xref: /linux/drivers/pci/host-bridge.c (revision 7b54366358008241f88228f02cc80ab352265eac)
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 
12459f58ceSYinghai Lu static struct pci_bus *find_pci_root_bus(struct pci_dev *dev)
13610929e1SYinghai Lu {
14610929e1SYinghai Lu 	struct pci_bus *bus;
15610929e1SYinghai Lu 
16610929e1SYinghai Lu 	bus = dev->bus;
17610929e1SYinghai Lu 	while (bus->parent)
18610929e1SYinghai Lu 		bus = bus->parent;
19610929e1SYinghai Lu 
20459f58ceSYinghai Lu 	return bus;
21459f58ceSYinghai Lu }
22459f58ceSYinghai Lu 
23459f58ceSYinghai Lu static struct pci_host_bridge *find_pci_host_bridge(struct pci_dev *dev)
24459f58ceSYinghai Lu {
25459f58ceSYinghai Lu 	struct pci_bus *bus = find_pci_root_bus(dev);
26459f58ceSYinghai Lu 
27*7b543663SYinghai Lu 	return to_pci_host_bridge(bus->bridge);
28610929e1SYinghai Lu }
29610929e1SYinghai Lu 
30610929e1SYinghai Lu static bool resource_contains(struct resource *res1, struct resource *res2)
31610929e1SYinghai Lu {
32610929e1SYinghai Lu 	return res1->start <= res2->start && res1->end >= res2->end;
33610929e1SYinghai Lu }
34610929e1SYinghai Lu 
35610929e1SYinghai Lu void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
36610929e1SYinghai Lu 			     struct resource *res)
37610929e1SYinghai Lu {
38459f58ceSYinghai Lu 	struct pci_host_bridge *bridge = find_pci_host_bridge(dev);
39610929e1SYinghai Lu 	struct pci_host_bridge_window *window;
40610929e1SYinghai Lu 	resource_size_t offset = 0;
41610929e1SYinghai Lu 
42610929e1SYinghai Lu 	list_for_each_entry(window, &bridge->windows, list) {
43610929e1SYinghai Lu 		if (resource_type(res) != resource_type(window->res))
44610929e1SYinghai Lu 			continue;
45610929e1SYinghai Lu 
46610929e1SYinghai Lu 		if (resource_contains(window->res, res)) {
47610929e1SYinghai Lu 			offset = window->offset;
48610929e1SYinghai Lu 			break;
49610929e1SYinghai Lu 		}
50610929e1SYinghai Lu 	}
51610929e1SYinghai Lu 
52610929e1SYinghai Lu 	region->start = res->start - offset;
53610929e1SYinghai Lu 	region->end = res->end - offset;
54610929e1SYinghai Lu }
55610929e1SYinghai Lu EXPORT_SYMBOL(pcibios_resource_to_bus);
56610929e1SYinghai Lu 
57610929e1SYinghai Lu static bool region_contains(struct pci_bus_region *region1,
58610929e1SYinghai Lu 			    struct pci_bus_region *region2)
59610929e1SYinghai Lu {
60610929e1SYinghai Lu 	return region1->start <= region2->start && region1->end >= region2->end;
61610929e1SYinghai Lu }
62610929e1SYinghai Lu 
63610929e1SYinghai Lu void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
64610929e1SYinghai Lu 			     struct pci_bus_region *region)
65610929e1SYinghai Lu {
66459f58ceSYinghai Lu 	struct pci_host_bridge *bridge = find_pci_host_bridge(dev);
67610929e1SYinghai Lu 	struct pci_host_bridge_window *window;
68610929e1SYinghai Lu 	resource_size_t offset = 0;
69610929e1SYinghai Lu 
70610929e1SYinghai Lu 	list_for_each_entry(window, &bridge->windows, list) {
71459f58ceSYinghai Lu 		struct pci_bus_region bus_region;
72459f58ceSYinghai Lu 
73610929e1SYinghai Lu 		if (resource_type(res) != resource_type(window->res))
74610929e1SYinghai Lu 			continue;
75610929e1SYinghai Lu 
76610929e1SYinghai Lu 		bus_region.start = window->res->start - window->offset;
77610929e1SYinghai Lu 		bus_region.end = window->res->end - window->offset;
78610929e1SYinghai Lu 
79610929e1SYinghai Lu 		if (region_contains(&bus_region, region)) {
80610929e1SYinghai Lu 			offset = window->offset;
81610929e1SYinghai Lu 			break;
82610929e1SYinghai Lu 		}
83610929e1SYinghai Lu 	}
84610929e1SYinghai Lu 
85610929e1SYinghai Lu 	res->start = region->start + offset;
86610929e1SYinghai Lu 	res->end = region->end + offset;
87610929e1SYinghai Lu }
88610929e1SYinghai Lu EXPORT_SYMBOL(pcibios_bus_to_resource);
89