Scan bus 0 and function 0 only for now
Cc: Andrew Jones <[email protected]>
Signed-off-by: Alexander Gordeev <[email protected]>
---
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
[email protected]
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm