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