Cc: Andrew Jones <[email protected]>
Signed-off-by: Alexander Gordeev <[email protected]>
---
 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
[email protected]
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

Reply via email to