xref: /openbmc/linux/drivers/pci/host-bridge.c (revision 59dc3325)
17328c8f4SBjorn Helgaas // SPDX-License-Identifier: GPL-2.0
2610929e1SYinghai Lu /*
3df62ab5eSBjorn 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 
find_pci_root_bus(struct pci_bus * bus)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 
pci_find_host_bridge(struct pci_bus * bus)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 }
26*59dc3325SRafael J. Wysocki EXPORT_SYMBOL_GPL(pci_find_host_bridge);
27610929e1SYinghai Lu 
pci_get_host_bridge_device(struct pci_dev * dev)286675a601SMurali Karicheri struct device *pci_get_host_bridge_device(struct pci_dev *dev)
296675a601SMurali Karicheri {
306675a601SMurali Karicheri 	struct pci_bus *root_bus = find_pci_root_bus(dev->bus);
316675a601SMurali Karicheri 	struct device *bridge = root_bus->bridge;
326675a601SMurali Karicheri 
336675a601SMurali Karicheri 	kobject_get(&bridge->kobj);
346675a601SMurali Karicheri 	return bridge;
356675a601SMurali Karicheri }
366675a601SMurali Karicheri 
pci_put_host_bridge_device(struct device * dev)376675a601SMurali Karicheri void  pci_put_host_bridge_device(struct device *dev)
386675a601SMurali Karicheri {
396675a601SMurali Karicheri 	kobject_put(&dev->kobj);
406675a601SMurali Karicheri }
416675a601SMurali Karicheri 
pci_set_host_bridge_release(struct pci_host_bridge * bridge,void (* release_fn)(struct pci_host_bridge *),void * release_data)424fa2649aSYinghai Lu void pci_set_host_bridge_release(struct pci_host_bridge *bridge,
434fa2649aSYinghai Lu 				 void (*release_fn)(struct pci_host_bridge *),
444fa2649aSYinghai Lu 				 void *release_data)
454fa2649aSYinghai Lu {
464fa2649aSYinghai Lu 	bridge->release_fn = release_fn;
474fa2649aSYinghai Lu 	bridge->release_data = release_data;
484fa2649aSYinghai Lu }
496f38a8b9SAndrew Donnellan EXPORT_SYMBOL_GPL(pci_set_host_bridge_release);
504fa2649aSYinghai Lu 
pcibios_resource_to_bus(struct pci_bus * bus,struct pci_bus_region * region,struct resource * res)51fc279850SYinghai Lu void pcibios_resource_to_bus(struct pci_bus *bus, struct pci_bus_region *region,
52610929e1SYinghai Lu 			     struct resource *res)
53610929e1SYinghai Lu {
543390e085SAaron Lu 	struct pci_host_bridge *bridge = pci_find_host_bridge(bus);
5514d76b68SJiang Liu 	struct resource_entry *window;
56610929e1SYinghai Lu 	resource_size_t offset = 0;
57610929e1SYinghai Lu 
5814d76b68SJiang Liu 	resource_list_for_each_entry(window, &bridge->windows) {
59610929e1SYinghai Lu 		if (resource_contains(window->res, res)) {
60610929e1SYinghai Lu 			offset = window->offset;
61610929e1SYinghai Lu 			break;
62610929e1SYinghai Lu 		}
63610929e1SYinghai Lu 	}
64610929e1SYinghai Lu 
65610929e1SYinghai Lu 	region->start = res->start - offset;
66610929e1SYinghai Lu 	region->end = res->end - offset;
67610929e1SYinghai Lu }
68610929e1SYinghai Lu EXPORT_SYMBOL(pcibios_resource_to_bus);
69610929e1SYinghai Lu 
region_contains(struct pci_bus_region * region1,struct pci_bus_region * region2)70610929e1SYinghai Lu static bool region_contains(struct pci_bus_region *region1,
71610929e1SYinghai Lu 			    struct pci_bus_region *region2)
72610929e1SYinghai Lu {
73610929e1SYinghai Lu 	return region1->start <= region2->start && region1->end >= region2->end;
74610929e1SYinghai Lu }
75610929e1SYinghai Lu 
pcibios_bus_to_resource(struct pci_bus * bus,struct resource * res,struct pci_bus_region * region)76fc279850SYinghai Lu void pcibios_bus_to_resource(struct pci_bus *bus, struct resource *res,
77610929e1SYinghai Lu 			     struct pci_bus_region *region)
78610929e1SYinghai Lu {
793390e085SAaron Lu 	struct pci_host_bridge *bridge = pci_find_host_bridge(bus);
8014d76b68SJiang Liu 	struct resource_entry *window;
81610929e1SYinghai Lu 	resource_size_t offset = 0;
82610929e1SYinghai Lu 
8314d76b68SJiang Liu 	resource_list_for_each_entry(window, &bridge->windows) {
84459f58ceSYinghai Lu 		struct pci_bus_region bus_region;
85459f58ceSYinghai Lu 
86610929e1SYinghai Lu 		if (resource_type(res) != resource_type(window->res))
87610929e1SYinghai Lu 			continue;
88610929e1SYinghai Lu 
89610929e1SYinghai Lu 		bus_region.start = window->res->start - window->offset;
90610929e1SYinghai Lu 		bus_region.end = window->res->end - window->offset;
91610929e1SYinghai Lu 
92610929e1SYinghai Lu 		if (region_contains(&bus_region, region)) {
93610929e1SYinghai Lu 			offset = window->offset;
94610929e1SYinghai Lu 			break;
95610929e1SYinghai Lu 		}
96610929e1SYinghai Lu 	}
97610929e1SYinghai Lu 
98610929e1SYinghai Lu 	res->start = region->start + offset;
99610929e1SYinghai Lu 	res->end = region->end + offset;
100610929e1SYinghai Lu }
101610929e1SYinghai Lu EXPORT_SYMBOL(pcibios_bus_to_resource);
102