Scan bus 0 and function 0 only for now Cc: Andrew Jones <drjones@xxxxxxxxxx> Signed-off-by: Alexander Gordeev <agordeev@xxxxxxxxxx> --- arm/pci-test.c | 4 +++ lib/pci-host-generic.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++ lib/pci-host-generic.h | 1 + lib/pci.h | 1 + 4 files changed, 73 insertions(+) diff --git a/arm/pci-test.c b/arm/pci-test.c index 8629c89..1539d3e 100644 --- a/arm/pci-test.c +++ b/arm/pci-test.c @@ -11,6 +11,7 @@ int main(void) { struct pci *pci; + int ret; pci = pci_dt_probe(); @@ -18,6 +19,9 @@ int main(void) if (!pci) goto done; + ret = pci_bus_scan(pci); + report("PCI bus scanning detected %d devices", true, ret); + pci_shutdown(pci); done: diff --git a/lib/pci-host-generic.c b/lib/pci-host-generic.c index 62b5662..e479989 100644 --- a/lib/pci-host-generic.c +++ b/lib/pci-host-generic.c @@ -14,6 +14,49 @@ #include "pci-host-generic.h" #include <linux/pci_regs.h> +#define for_each_pci_dev(pci, dev, conf) \ + for (dev = find_next_dev(pci, -1, &conf); \ + dev >= 0; \ + dev = find_next_dev(pci, dev, &conf)) + +static u8 pci_config_readb(const void *conf, int off) +{ + return readb(conf + off); +} + +static u32 pci_config_readl(const void *conf, int off) +{ + return readl(conf + off); +} + +static void pci_config_writel(u32 val, void *conf, int off) +{ + writel(val, conf + off); +} + +static void* dev_conf(struct pci *pci, int dev) +{ + struct pci_host_bridge *host = pci->sysdata; + return (void*)host->cpu_range.start + (dev * 8) * PCI_ECAM_CONFIG_SIZE; +} + +/* We scan bus 0 only for now */ +static int find_next_dev(struct pci *pci, int dev, void **pconf) +{ + struct pci_host_bridge *host = pci->sysdata; + int limit = MIN(32u, host->cpu_range.size / PCI_ECAM_CONFIG_SIZE); + + for (dev++; dev < limit; dev++) { + void *conf = dev_conf(pci, dev); + if (pci_config_readl(conf, PCI_VENDOR_ID) != ((u32)~0)) { + *pconf = conf; + return dev; + } + } + + return -1; +} + static void pci_host_addr_space_init(struct pci_addr_space as[], int nr_as, u32 cells[], int nr_range_cells) { @@ -133,6 +176,24 @@ static struct pci_host_bridge *pci_host_bridge_probe(void) return host; } +int pci_bus_scan(struct pci *pci) +{ + void *conf; + int dev; + int nr_dev = 0; + + for_each_pci_dev(pci, dev, conf) { + /* We are only interested in normal PCI devices */ + if (pci_config_readb(conf, PCI_HEADER_TYPE) != + PCI_HEADER_TYPE_NORMAL) + continue; + pci_config_writel(PCI_COMMAND_SERR, conf, PCI_COMMAND); + nr_dev++; + } + + return nr_dev; +} + struct pci *pci_dt_probe(void) { struct pci_host_bridge *host; @@ -150,6 +211,12 @@ struct pci *pci_dt_probe(void) void pci_shutdown(struct pci *pci) { + void *conf; + int dev; + + for_each_pci_dev(pci, dev, conf) + pci_config_writel(PCI_COMMAND_INTX_DISABLE, conf, PCI_COMMAND); + free(pci->sysdata); free(pci); } diff --git a/lib/pci-host-generic.h b/lib/pci-host-generic.h index 097ac2d..c14d32d 100644 --- a/lib/pci-host-generic.h +++ b/lib/pci-host-generic.h @@ -22,5 +22,6 @@ struct pci_host_bridge { }; #define PCI_ECAM_BUS_SIZE (1 << 20) +#define PCI_ECAM_CONFIG_SIZE (1 << 12) #endif diff --git a/lib/pci.h b/lib/pci.h index 22b8e31..bc4f2d2 100644 --- a/lib/pci.h +++ b/lib/pci.h @@ -8,6 +8,7 @@ struct pci { }; extern struct pci *pci_dt_probe(void); +extern int pci_bus_scan(struct pci *pci); extern void pci_shutdown(struct pci *pci); #endif -- 1.8.3.1 _______________________________________________ kvmarm mailing list kvmarm@xxxxxxxxxxxxxxxxxxxxx https://lists.cs.columbia.edu/mailman/listinfo/kvmarm