xref: /linux/drivers/pci/host-bridge.c (revision 610929e119b2166167f4f8fce85408472e77a16a)
1*610929e1SYinghai Lu /*
2*610929e1SYinghai Lu  * host bridge related code
3*610929e1SYinghai Lu  */
4*610929e1SYinghai Lu 
5*610929e1SYinghai Lu #include <linux/kernel.h>
6*610929e1SYinghai Lu #include <linux/init.h>
7*610929e1SYinghai Lu #include <linux/pci.h>
8*610929e1SYinghai Lu #include <linux/module.h>
9*610929e1SYinghai Lu 
10*610929e1SYinghai Lu #include "pci.h"
11*610929e1SYinghai Lu 
12*610929e1SYinghai Lu static LIST_HEAD(pci_host_bridges);
13*610929e1SYinghai Lu 
14*610929e1SYinghai Lu void add_to_pci_host_bridges(struct pci_host_bridge *bridge)
15*610929e1SYinghai Lu {
16*610929e1SYinghai Lu 	list_add_tail(&bridge->list, &pci_host_bridges);
17*610929e1SYinghai Lu }
18*610929e1SYinghai Lu 
19*610929e1SYinghai Lu static struct pci_host_bridge *pci_host_bridge(struct pci_dev *dev)
20*610929e1SYinghai Lu {
21*610929e1SYinghai Lu 	struct pci_bus *bus;
22*610929e1SYinghai Lu 	struct pci_host_bridge *bridge;
23*610929e1SYinghai Lu 
24*610929e1SYinghai Lu 	bus = dev->bus;
25*610929e1SYinghai Lu 	while (bus->parent)
26*610929e1SYinghai Lu 		bus = bus->parent;
27*610929e1SYinghai Lu 
28*610929e1SYinghai Lu 	list_for_each_entry(bridge, &pci_host_bridges, list) {
29*610929e1SYinghai Lu 		if (bridge->bus == bus)
30*610929e1SYinghai Lu 			return bridge;
31*610929e1SYinghai Lu 	}
32*610929e1SYinghai Lu 
33*610929e1SYinghai Lu 	return NULL;
34*610929e1SYinghai Lu }
35*610929e1SYinghai Lu 
36*610929e1SYinghai Lu static bool resource_contains(struct resource *res1, struct resource *res2)
37*610929e1SYinghai Lu {
38*610929e1SYinghai Lu 	return res1->start <= res2->start && res1->end >= res2->end;
39*610929e1SYinghai Lu }
40*610929e1SYinghai Lu 
41*610929e1SYinghai Lu void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
42*610929e1SYinghai Lu 			     struct resource *res)
43*610929e1SYinghai Lu {
44*610929e1SYinghai Lu 	struct pci_host_bridge *bridge = pci_host_bridge(dev);
45*610929e1SYinghai Lu 	struct pci_host_bridge_window *window;
46*610929e1SYinghai Lu 	resource_size_t offset = 0;
47*610929e1SYinghai Lu 
48*610929e1SYinghai Lu 	list_for_each_entry(window, &bridge->windows, list) {
49*610929e1SYinghai Lu 		if (resource_type(res) != resource_type(window->res))
50*610929e1SYinghai Lu 			continue;
51*610929e1SYinghai Lu 
52*610929e1SYinghai Lu 		if (resource_contains(window->res, res)) {
53*610929e1SYinghai Lu 			offset = window->offset;
54*610929e1SYinghai Lu 			break;
55*610929e1SYinghai Lu 		}
56*610929e1SYinghai Lu 	}
57*610929e1SYinghai Lu 
58*610929e1SYinghai Lu 	region->start = res->start - offset;
59*610929e1SYinghai Lu 	region->end = res->end - offset;
60*610929e1SYinghai Lu }
61*610929e1SYinghai Lu EXPORT_SYMBOL(pcibios_resource_to_bus);
62*610929e1SYinghai Lu 
63*610929e1SYinghai Lu static bool region_contains(struct pci_bus_region *region1,
64*610929e1SYinghai Lu 			    struct pci_bus_region *region2)
65*610929e1SYinghai Lu {
66*610929e1SYinghai Lu 	return region1->start <= region2->start && region1->end >= region2->end;
67*610929e1SYinghai Lu }
68*610929e1SYinghai Lu 
69*610929e1SYinghai Lu void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
70*610929e1SYinghai Lu 			     struct pci_bus_region *region)
71*610929e1SYinghai Lu {
72*610929e1SYinghai Lu 	struct pci_host_bridge *bridge = pci_host_bridge(dev);
73*610929e1SYinghai Lu 	struct pci_host_bridge_window *window;
74*610929e1SYinghai Lu 	struct pci_bus_region bus_region;
75*610929e1SYinghai Lu 	resource_size_t offset = 0;
76*610929e1SYinghai Lu 
77*610929e1SYinghai Lu 	list_for_each_entry(window, &bridge->windows, list) {
78*610929e1SYinghai Lu 		if (resource_type(res) != resource_type(window->res))
79*610929e1SYinghai Lu 			continue;
80*610929e1SYinghai Lu 
81*610929e1SYinghai Lu 		bus_region.start = window->res->start - window->offset;
82*610929e1SYinghai Lu 		bus_region.end = window->res->end - window->offset;
83*610929e1SYinghai Lu 
84*610929e1SYinghai Lu 		if (region_contains(&bus_region, region)) {
85*610929e1SYinghai Lu 			offset = window->offset;
86*610929e1SYinghai Lu 			break;
87*610929e1SYinghai Lu 		}
88*610929e1SYinghai Lu 	}
89*610929e1SYinghai Lu 
90*610929e1SYinghai Lu 	res->start = region->start + offset;
91*610929e1SYinghai Lu 	res->end = region->end + offset;
92*610929e1SYinghai Lu }
93*610929e1SYinghai Lu EXPORT_SYMBOL(pcibios_bus_to_resource);
94