Cc: Andrew Jones <drjones@xxxxxxxxxx> Signed-off-by: Alexander Gordeev <agordeev@xxxxxxxxxx> --- lib/pci-host-generic.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 69 insertions(+), 2 deletions(-) diff --git a/lib/pci-host-generic.c b/lib/pci-host-generic.c index b783d29..f3161f8 100644 --- a/lib/pci-host-generic.c +++ b/lib/pci-host-generic.c @@ -19,6 +19,11 @@ dev >= 0; \ dev = find_next_dev(pci, dev, &conf)) +static pci_res_type_t flags_to_type(u32 of_flags) +{ + return ((of_flags & 0x40000000) >> 28) | ((of_flags >> 24) & 0x03); +} + static u8 pci_config_readb(const void *conf, int off) { return readb(conf + off); @@ -255,11 +260,66 @@ static bool pci_get_bar(void *conf, int bar, pci_res_type_t *type, return true; } +static void pci_set_bar(void *conf, int bar, phys_addr_t addr, bool is64) +{ + int off = PCI_BASE_ADDRESS_0 + (bar * 4); + + pci_config_writel(addr, conf, off); + if (is64) + pci_config_writel(addr >> 32, conf, off + 4); +} + +static struct pci_addr_space *pci_find_res(struct pci_host_bridge *host, + pci_res_type_t type) +{ + struct pci_addr_space *as = &host->addr_space[0]; + int i; + + for (i = 0; i < host->nr_addr_spaces; i++, as++) { + if (flags_to_type(as->of_flags) == type) + return as; + } + + return NULL; +} + +static phys_addr_t pci_align_res_size(phys_addr_t size, pci_res_type_t type) +{ + phys_addr_t mask; + + if (type == PCI_RES_TYPE_IO) + mask = PCI_BASE_ADDRESS_IO_MASK; + else + mask = PCI_BASE_ADDRESS_MEM_MASK; + + return (size + ~mask) & mask; +} + +static phys_addr_t pci_alloc_res(struct pci_host_bridge *host, + pci_res_type_t type, u64 size) +{ + struct pci_addr_space *res; + phys_addr_t addr; + + assert(res = pci_find_res(host, type)); + + size = pci_align_res_size(size, type); + assert(res->alloc + size <= res->pci_range.size); + + addr = res->pci_range.start + res->alloc; + res->alloc += size; + + return addr; +} + int pci_bus_scan(struct pci *pci) { void *conf; + phys_addr_t addr; + u64 size; pci_res_type_t type; bool is64; + u32 cmd = PCI_COMMAND_SERR; int bar; int dev; int nr_dev = 0; @@ -271,13 +331,20 @@ int pci_bus_scan(struct pci *pci) continue; for (bar = 0; bar < PCI_HEADER_TYPE_NORMAL_NUM_BARS; bar++) { - if (!pci_get_bar(conf, bar, &type, NULL, NULL, &is64)) + if (!pci_get_bar(conf, bar, &type, NULL, &size, &is64)) break; + addr = pci_alloc_res(pci->sysdata, type, size); + pci_set_bar(conf, bar, addr, is64); if (is64) bar++; + + if (type == PCI_RES_TYPE_IO) + cmd |= PCI_COMMAND_IO; + else + cmd |= PCI_COMMAND_MEMORY; } - pci_config_writel(PCI_COMMAND_SERR, conf, PCI_COMMAND); + pci_config_writel(cmd, conf, PCI_COMMAND); nr_dev++; } -- 1.8.3.1 _______________________________________________ kvmarm mailing list kvmarm@xxxxxxxxxxxxxxxxxxxxx https://lists.cs.columbia.edu/mailman/listinfo/kvmarm