xref: /linux/drivers/pci/host-bridge.c (revision 4fa2649a01a4357a82dcc60ef8fb7b8c441e64ed)
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 
277b543663SYinghai Lu 	return to_pci_host_bridge(bus->bridge);
28610929e1SYinghai Lu }
29610929e1SYinghai Lu 
30*4fa2649aSYinghai Lu void pci_set_host_bridge_release(struct pci_host_bridge *bridge,
31*4fa2649aSYinghai Lu 				 void (*release_fn)(struct pci_host_bridge *),
32*4fa2649aSYinghai Lu 				 void *release_data)
33*4fa2649aSYinghai Lu {
34*4fa2649aSYinghai Lu 	bridge->release_fn = release_fn;
35*4fa2649aSYinghai Lu 	bridge->release_data = release_data;
36*4fa2649aSYinghai Lu }
37*4fa2649aSYinghai Lu 
38610929e1SYinghai Lu static bool resource_contains(struct resource *res1, struct resource *res2)
39610929e1SYinghai Lu {
40610929e1SYinghai Lu 	return res1->start <= res2->start && res1->end >= res2->end;
41610929e1SYinghai Lu }
42610929e1SYinghai Lu 
43610929e1SYinghai Lu void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
44610929e1SYinghai Lu 			     struct resource *res)
45610929e1SYinghai Lu {
46459f58ceSYinghai Lu 	struct pci_host_bridge *bridge = find_pci_host_bridge(dev);
47610929e1SYinghai Lu 	struct pci_host_bridge_window *window;
48610929e1SYinghai Lu 	resource_size_t offset = 0;
49610929e1SYinghai Lu 
50610929e1SYinghai Lu 	list_for_each_entry(window, &bridge->windows, list) {
51610929e1SYinghai Lu 		if (resource_type(res) != resource_type(window->res))
52610929e1SYinghai Lu 			continue;
53610929e1SYinghai Lu 
54610929e1SYinghai Lu 		if (resource_contains(window->res, res)) {
55610929e1SYinghai Lu 			offset = window->offset;
56610929e1SYinghai Lu 			break;
57610929e1SYinghai Lu 		}
58610929e1SYinghai Lu 	}
59610929e1SYinghai Lu 
60610929e1SYinghai Lu 	region->start = res->start - offset;
61610929e1SYinghai Lu 	region->end = res->end - offset;
62610929e1SYinghai Lu }
63610929e1SYinghai Lu EXPORT_SYMBOL(pcibios_resource_to_bus);
64610929e1SYinghai Lu 
65610929e1SYinghai Lu static bool region_contains(struct pci_bus_region *region1,
66610929e1SYinghai Lu 			    struct pci_bus_region *region2)
67610929e1SYinghai Lu {
68610929e1SYinghai Lu 	return region1->start <= region2->start && region1->end >= region2->end;
69610929e1SYinghai Lu }
70610929e1SYinghai Lu 
71610929e1SYinghai Lu void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
72610929e1SYinghai Lu 			     struct pci_bus_region *region)
73610929e1SYinghai Lu {
74459f58ceSYinghai Lu 	struct pci_host_bridge *bridge = find_pci_host_bridge(dev);
75610929e1SYinghai Lu 	struct pci_host_bridge_window *window;
76610929e1SYinghai Lu 	resource_size_t offset = 0;
77610929e1SYinghai Lu 
78610929e1SYinghai Lu 	list_for_each_entry(window, &bridge->windows, list) {
79459f58ceSYinghai Lu 		struct pci_bus_region bus_region;
80459f58ceSYinghai Lu 
81610929e1SYinghai Lu 		if (resource_type(res) != resource_type(window->res))
82610929e1SYinghai Lu 			continue;
83610929e1SYinghai Lu 
84610929e1SYinghai Lu 		bus_region.start = window->res->start - window->offset;
85610929e1SYinghai Lu 		bus_region.end = window->res->end - window->offset;
86610929e1SYinghai Lu 
87610929e1SYinghai Lu 		if (region_contains(&bus_region, region)) {
88610929e1SYinghai Lu 			offset = window->offset;
89610929e1SYinghai Lu 			break;
90610929e1SYinghai Lu 		}
91610929e1SYinghai Lu 	}
92610929e1SYinghai Lu 
93610929e1SYinghai Lu 	res->start = region->start + offset;
94610929e1SYinghai Lu 	res->end = region->end + offset;
95610929e1SYinghai Lu }
96610929e1SYinghai Lu EXPORT_SYMBOL(pcibios_bus_to_resource);
97