xref: /linux/drivers/pci/host-bridge.c (revision df62ab5e0f75608919df7442654b0fab78246b7b)
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