diff options
Diffstat (limited to 'drivers/pci/pci.c')
-rw-r--r-- | drivers/pci/pci.c | 102 |
1 files changed, 78 insertions, 24 deletions
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index e2b05d8..06b56b0 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -218,67 +218,121 @@ pci_dev_t pci_find_device(unsigned int vendor, unsigned int device, int index) * */ -pci_addr_t pci_hose_phys_to_bus (struct pci_controller *hose, - phys_addr_t phys_addr, - unsigned long flags) +int __pci_hose_phys_to_bus (struct pci_controller *hose, + phys_addr_t phys_addr, + unsigned long flags, + unsigned long skip_mask, + pci_addr_t *ba) { struct pci_region *res; pci_addr_t bus_addr; int i; - if (!hose) { - printf ("pci_hose_phys_to_bus: %s\n", "invalid hose"); - goto Done; - } - for (i = 0; i < hose->region_count; i++) { res = &hose->regions[i]; if (((res->flags ^ flags) & PCI_REGION_TYPE) != 0) continue; + if (res->flags & skip_mask) + continue; + bus_addr = phys_addr - res->phys_start + res->bus_start; if (bus_addr >= res->bus_start && bus_addr < res->bus_start + res->size) { - return bus_addr; + *ba = bus_addr; + return 0; } } - printf ("pci_hose_phys_to_bus: %s\n", "invalid physical address"); - -Done: - return 0; + return 1; } -phys_addr_t pci_hose_bus_to_phys(struct pci_controller* hose, - pci_addr_t bus_addr, - unsigned long flags) +pci_addr_t pci_hose_phys_to_bus (struct pci_controller *hose, + phys_addr_t phys_addr, + unsigned long flags) { - struct pci_region *res; - int i; + pci_addr_t bus_addr = 0; + int ret; if (!hose) { - printf ("pci_hose_bus_to_phys: %s\n", "invalid hose"); - goto Done; + puts ("pci_hose_phys_to_bus: invalid hose\n"); + return bus_addr; + } + + /* if PCI_REGION_MEM is set we do a two pass search with preference + * on matches that don't have PCI_REGION_SYS_MEMORY set */ + if ((flags & PCI_REGION_MEM) == PCI_REGION_MEM) { + ret = __pci_hose_phys_to_bus(hose, phys_addr, + flags, PCI_REGION_SYS_MEMORY, &bus_addr); + if (!ret) + return bus_addr; } + ret = __pci_hose_phys_to_bus(hose, phys_addr, flags, 0, &bus_addr); + + if (ret) + puts ("pci_hose_phys_to_bus: invalid physical address\n"); + + return bus_addr; +} + +int __pci_hose_bus_to_phys (struct pci_controller *hose, + pci_addr_t bus_addr, + unsigned long flags, + unsigned long skip_mask, + phys_addr_t *pa) +{ + struct pci_region *res; + int i; + for (i = 0; i < hose->region_count; i++) { res = &hose->regions[i]; if (((res->flags ^ flags) & PCI_REGION_TYPE) != 0) continue; + if (res->flags & skip_mask) + continue; + if (bus_addr >= res->bus_start && bus_addr < res->bus_start + res->size) { - return bus_addr - res->bus_start + res->phys_start; + *pa = (bus_addr - res->bus_start + res->phys_start); + return 0; } } - printf ("pci_hose_bus_to_phys: %s\n", "invalid physical address"); + return 1; +} -Done: - return 0; +phys_addr_t pci_hose_bus_to_phys(struct pci_controller* hose, + pci_addr_t bus_addr, + unsigned long flags) +{ + phys_addr_t phys_addr = 0; + int ret; + + if (!hose) { + puts ("pci_hose_bus_to_phys: invalid hose\n"); + return phys_addr; + } + + /* if PCI_REGION_MEM is set we do a two pass search with preference + * on matches that don't have PCI_REGION_SYS_MEMORY set */ + if ((flags & PCI_REGION_MEM) == PCI_REGION_MEM) { + ret = __pci_hose_bus_to_phys(hose, bus_addr, + flags, PCI_REGION_SYS_MEMORY, &phys_addr); + if (!ret) + return phys_addr; + } + + ret = __pci_hose_bus_to_phys(hose, bus_addr, flags, 0, &phys_addr); + + if (ret) + puts ("pci_hose_bus_to_phys: invalid physical address\n"); + + return phys_addr; } /* |