[PATCH v2 2/5] arm/pci: Scan PCI root bus for devices

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Scan bus 0 only and function 0 only on each device.

Operations pci_config_read*/pci_config_write* are just
wrappers over read*/write* accessors and only needed
to emphasize PCI configuration space access.

Cc: Thomas Huth <thuth@xxxxxxxxxx>
Cc: Andrew Jones <drjones@xxxxxxxxxx>
Signed-off-by: Alexander Gordeev <agordeev@xxxxxxxxxx>
---
 lib/pci-host-generic.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++++-
 lib/pci-host-generic.h | 34 +++++++++++++++++++++++
 2 files changed, 107 insertions(+), 1 deletion(-)

diff --git a/lib/pci-host-generic.c b/lib/pci-host-generic.c
index 9bc6642..fd3bb34 100644
--- a/lib/pci-host-generic.c
+++ b/lib/pci-host-generic.c
@@ -38,6 +38,18 @@ static pci_res_type_t flags_to_type(u32 of_flags)
 	return ((of_flags & 0x40000000) >> 28) | ((of_flags >> 24) & 0x03);
 }
 
+int find_next_dev(struct gen_pci *pci, int dev)
+{
+	for (dev++; dev < PCI_NUM_DEVICES; dev++) {
+		void *conf = dev_conf(pci, dev);
+
+		if (pci_config_readl(conf, PCI_VENDOR_ID) != ((u32)~0))
+			return dev;
+	}
+
+	return -1;
+}
+
 static u32 from_fdt32(fdt32_t val)
 {
 	return fdt32_to_cpu(val);
@@ -199,20 +211,80 @@ static struct gen_pci *gen_pci_probe(void)
 	return pci;
 }
 
+static void pci_dev_print(void *conf)
+{
+	u16 vendor_id = pci_config_readw(conf, PCI_VENDOR_ID);
+	u16 device_id = pci_config_readw(conf, PCI_DEVICE_ID);
+	u8 header = pci_config_readb(conf, PCI_HEADER_TYPE);
+	u8 progif = pci_config_readb(conf, PCI_CLASS_PROG);
+	u8 subcl = pci_config_readb(conf, PCI_CLASS_DEVICE);
+	u8 class = pci_config_readb(conf, PCI_CLASS_DEVICE + 1);
+
+	printf("conf %p vendor_id %04x device_id %04x type %d "
+	       "progif %02x class %02x subcl %02x\n",
+	       conf, vendor_id, device_id, header,
+	       progif, class, subcl);
+}
+
+static int pci_bus_scan(struct gen_pci *pci)
+{
+	int dev;
+	int nr_dev = 0;
+
+	if (!pci)
+		return -1;
+
+	for_each_pci_dev(pci, dev) {
+		void *conf = dev_conf(pci, dev);
+		pci_dev_print(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;
+}
+
 bool pci_probe(void)
 {
 	struct gen_pci *pci = get_pci();
 
 	assert(pci == NULL);
 	pci = gen_pci_probe();
+	if (!pci)
+		goto probe;
 	set_pci(pci);
 
-	return (pci != NULL);
+	if (pci_bus_scan(pci) < 0)
+		goto scan;
+
+	return true;
+
+scan:
+	pci_shutdown();
+
+probe:
+	return false;
 }
 
 void pci_shutdown(void)
 {
 	struct gen_pci *pci = get_pci();
+	int dev;
+
+	if (!pci)
+		return;
+
+	for_each_pci_dev(pci, dev) {
+		void *conf = dev_conf(pci, dev);
+
+		pci_config_writel(PCI_COMMAND_INTX_DISABLE, conf, PCI_COMMAND);
+	}
 
 	set_pci(NULL);
 	free(pci);
diff --git a/lib/pci-host-generic.h b/lib/pci-host-generic.h
index f4ae3e4..1d86b43 100644
--- a/lib/pci-host-generic.h
+++ b/lib/pci-host-generic.h
@@ -69,5 +69,39 @@ typedef enum pci_res_type {
  *
  */
 #define PCI_ECAM_BUS_SIZE	(1 << 20)
+#define PCI_NUM_DEVICES		(PCI_ECAM_BUS_SIZE / (1 << 15))
+#define PCI_ECAM_CONFIG_SIZE	(1 << 12)
+
+#define for_each_pci_dev(pci, dev)		\
+	for (dev = find_next_dev(pci, -1);	\
+	     dev >= 0;				\
+	     dev = find_next_dev(pci, dev))
+
+static void* dev_conf(struct gen_pci *pci, int dev)
+{
+	return (void*)pci->cpu_range.start + (dev * 8) * PCI_ECAM_CONFIG_SIZE;
+}
+
+static u8 pci_config_readb(const void *conf, int off)
+{
+	return readb(conf + off);
+}
+
+static u16 pci_config_readw(const void *conf, int off)
+{
+	return readw(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);
+}
+
+extern int find_next_dev(struct gen_pci *pci, int dev);
 
 #endif
-- 
1.8.3.1

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]
  Powered by Linux