xref: /linux/drivers/pci/host-bridge.c (revision 459f58ce51e2e11235b7bb4b1732ebf3c17d86f7)
1610929e1SYinghai Lu /*
2610929e1SYinghai Lu  * host bridge related code
3610929e1SYinghai Lu  */
4610929e1SYinghai Lu 
5610929e1SYinghai Lu #include <linux/kernel.h>
6610929e1SYinghai Lu #include <linux/init.h>
7610929e1SYinghai Lu #include <linux/pci.h>
8610929e1SYinghai Lu #include <linux/module.h>
9610929e1SYinghai Lu 
10610929e1SYinghai Lu #include "pci.h"
11610929e1SYinghai Lu 
12610929e1SYinghai Lu static LIST_HEAD(pci_host_bridges);
13610929e1SYinghai Lu 
14610929e1SYinghai Lu void add_to_pci_host_bridges(struct pci_host_bridge *bridge)
15610929e1SYinghai Lu {
16610929e1SYinghai Lu 	list_add_tail(&bridge->list, &pci_host_bridges);
17610929e1SYinghai Lu }
18610929e1SYinghai Lu 
19*459f58ceSYinghai Lu static struct pci_bus *find_pci_root_bus(struct pci_dev *dev)
20610929e1SYinghai Lu {
21610929e1SYinghai Lu 	struct pci_bus *bus;
22610929e1SYinghai Lu 
23610929e1SYinghai Lu 	bus = dev->bus;
24610929e1SYinghai Lu 	while (bus->parent)
25610929e1SYinghai Lu 		bus = bus->parent;
26610929e1SYinghai Lu 
27*459f58ceSYinghai Lu 	return bus;
28*459f58ceSYinghai Lu }
29*459f58ceSYinghai Lu 
30*459f58ceSYinghai Lu static struct pci_host_bridge *find_pci_host_bridge(struct pci_dev *dev)
31*459f58ceSYinghai Lu {
32*459f58ceSYinghai Lu 	struct pci_bus *bus = find_pci_root_bus(dev);
33*459f58ceSYinghai Lu 	struct pci_host_bridge *bridge;
34*459f58ceSYinghai Lu 
35610929e1SYinghai Lu 	list_for_each_entry(bridge, &pci_host_bridges, list) {
36610929e1SYinghai Lu 		if (bridge->bus == bus)
37610929e1SYinghai Lu 			return bridge;
38610929e1SYinghai Lu 	}
39610929e1SYinghai Lu 
40610929e1SYinghai Lu 	return NULL;
41610929e1SYinghai Lu }
42610929e1SYinghai Lu 
43610929e1SYinghai Lu static bool resource_contains(struct resource *res1, struct resource *res2)
44610929e1SYinghai Lu {
45610929e1SYinghai Lu 	return res1->start <= res2->start && res1->end >= res2->end;
46610929e1SYinghai Lu }
47610929e1SYinghai Lu 
48610929e1SYinghai Lu void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
49610929e1SYinghai Lu 			     struct resource *res)
50610929e1SYinghai Lu {
51*459f58ceSYinghai Lu 	struct pci_host_bridge *bridge = find_pci_host_bridge(dev);
52610929e1SYinghai Lu 	struct pci_host_bridge_window *window;
53610929e1SYinghai Lu 	resource_size_t offset = 0;
54610929e1SYinghai Lu 
55610929e1SYinghai Lu 	list_for_each_entry(window, &bridge->windows, list) {
56610929e1SYinghai Lu 		if (resource_type(res) != resource_type(window->res))
57610929e1SYinghai Lu 			continue;
58610929e1SYinghai Lu 
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 
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 
76610929e1SYinghai Lu void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
77610929e1SYinghai Lu 			     struct pci_bus_region *region)
78610929e1SYinghai Lu {
79*459f58ceSYinghai Lu 	struct pci_host_bridge *bridge = find_pci_host_bridge(dev);
80610929e1SYinghai Lu 	struct pci_host_bridge_window *window;
81610929e1SYinghai Lu 	resource_size_t offset = 0;
82610929e1SYinghai Lu 
83610929e1SYinghai Lu 	list_for_each_entry(window, &bridge->windows, list) {
84*459f58ceSYinghai Lu 		struct pci_bus_region bus_region;
85*459f58ceSYinghai 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