17328c8f4SBjorn Helgaas // SPDX-License-Identifier: GPL-2.0 2610929e1SYinghai Lu /* 3*df62ab5eSBjorn Helgaas * Host bridge related code 4610929e1SYinghai Lu */ 5610929e1SYinghai Lu 6610929e1SYinghai Lu #include <linux/kernel.h> 7610929e1SYinghai Lu #include <linux/pci.h> 8610929e1SYinghai Lu #include <linux/module.h> 9610929e1SYinghai Lu 10610929e1SYinghai Lu #include "pci.h" 11610929e1SYinghai Lu 12fc279850SYinghai Lu static struct pci_bus *find_pci_root_bus(struct pci_bus *bus) 13610929e1SYinghai Lu { 14610929e1SYinghai Lu while (bus->parent) 15610929e1SYinghai Lu bus = bus->parent; 16610929e1SYinghai Lu 17459f58ceSYinghai Lu return bus; 18459f58ceSYinghai Lu } 19459f58ceSYinghai Lu 203390e085SAaron Lu struct pci_host_bridge *pci_find_host_bridge(struct pci_bus *bus) 21459f58ceSYinghai Lu { 22fc279850SYinghai Lu struct pci_bus *root_bus = find_pci_root_bus(bus); 23459f58ceSYinghai Lu 24fc279850SYinghai Lu return to_pci_host_bridge(root_bus->bridge); 25610929e1SYinghai Lu } 26610929e1SYinghai Lu 276675a601SMurali Karicheri struct device *pci_get_host_bridge_device(struct pci_dev *dev) 286675a601SMurali Karicheri { 296675a601SMurali Karicheri struct pci_bus *root_bus = find_pci_root_bus(dev->bus); 306675a601SMurali Karicheri struct device *bridge = root_bus->bridge; 316675a601SMurali Karicheri 326675a601SMurali Karicheri kobject_get(&bridge->kobj); 336675a601SMurali Karicheri return bridge; 346675a601SMurali Karicheri } 356675a601SMurali Karicheri 366675a601SMurali Karicheri void pci_put_host_bridge_device(struct device *dev) 376675a601SMurali Karicheri { 386675a601SMurali Karicheri kobject_put(&dev->kobj); 396675a601SMurali Karicheri } 406675a601SMurali Karicheri 414fa2649aSYinghai Lu void pci_set_host_bridge_release(struct pci_host_bridge *bridge, 424fa2649aSYinghai Lu void (*release_fn)(struct pci_host_bridge *), 434fa2649aSYinghai Lu void *release_data) 444fa2649aSYinghai Lu { 454fa2649aSYinghai Lu bridge->release_fn = release_fn; 464fa2649aSYinghai Lu bridge->release_data = release_data; 474fa2649aSYinghai Lu } 486f38a8b9SAndrew Donnellan EXPORT_SYMBOL_GPL(pci_set_host_bridge_release); 494fa2649aSYinghai Lu 50fc279850SYinghai Lu void pcibios_resource_to_bus(struct pci_bus *bus, struct pci_bus_region *region, 51610929e1SYinghai Lu struct resource *res) 52610929e1SYinghai Lu { 533390e085SAaron Lu struct pci_host_bridge *bridge = pci_find_host_bridge(bus); 5414d76b68SJiang Liu struct resource_entry *window; 55610929e1SYinghai Lu resource_size_t offset = 0; 56610929e1SYinghai Lu 5714d76b68SJiang Liu resource_list_for_each_entry(window, &bridge->windows) { 58610929e1SYinghai Lu if (resource_contains(window->res, res)) { 59610929e1SYinghai Lu offset = window->offset; 60610929e1SYinghai Lu break; 61610929e1SYinghai Lu } 62610929e1SYinghai Lu } 63610929e1SYinghai Lu 64610929e1SYinghai Lu region->start = res->start - offset; 65610929e1SYinghai Lu region->end = res->end - offset; 66610929e1SYinghai Lu } 67610929e1SYinghai Lu EXPORT_SYMBOL(pcibios_resource_to_bus); 68610929e1SYinghai Lu 69610929e1SYinghai Lu static bool region_contains(struct pci_bus_region *region1, 70610929e1SYinghai Lu struct pci_bus_region *region2) 71610929e1SYinghai Lu { 72610929e1SYinghai Lu return region1->start <= region2->start && region1->end >= region2->end; 73610929e1SYinghai Lu } 74610929e1SYinghai Lu 75fc279850SYinghai Lu void pcibios_bus_to_resource(struct pci_bus *bus, struct resource *res, 76610929e1SYinghai Lu struct pci_bus_region *region) 77610929e1SYinghai Lu { 783390e085SAaron Lu struct pci_host_bridge *bridge = pci_find_host_bridge(bus); 7914d76b68SJiang Liu struct resource_entry *window; 80610929e1SYinghai Lu resource_size_t offset = 0; 81610929e1SYinghai Lu 8214d76b68SJiang Liu resource_list_for_each_entry(window, &bridge->windows) { 83459f58ceSYinghai Lu struct pci_bus_region bus_region; 84459f58ceSYinghai Lu 85610929e1SYinghai Lu if (resource_type(res) != resource_type(window->res)) 86610929e1SYinghai Lu continue; 87610929e1SYinghai Lu 88610929e1SYinghai Lu bus_region.start = window->res->start - window->offset; 89610929e1SYinghai Lu bus_region.end = window->res->end - window->offset; 90610929e1SYinghai Lu 91610929e1SYinghai Lu if (region_contains(&bus_region, region)) { 92610929e1SYinghai Lu offset = window->offset; 93610929e1SYinghai Lu break; 94610929e1SYinghai Lu } 95610929e1SYinghai Lu } 96610929e1SYinghai Lu 97610929e1SYinghai Lu res->start = region->start + offset; 98610929e1SYinghai Lu res->end = region->end + offset; 99610929e1SYinghai Lu } 100610929e1SYinghai Lu EXPORT_SYMBOL(pcibios_bus_to_resource); 101