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