[PATCH v2 5/5] arm/pci: pci-testdev PCI device operation test

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

 



Cc: Thomas Huth <thuth@xxxxxxxxxx>
Cc: Andrew Jones <drjones@xxxxxxxxxx>
Signed-off-by: Alexander Gordeev <agordeev@xxxxxxxxxx>
---
 arm/pci-test.c               |   4 +
 config/config-arm-common.mak |   1 +
 lib/pci-testdev.c            | 189 +++++++++++++++++++++++++++++++++++++++++++
 lib/pci.h                    |   6 ++
 4 files changed, 200 insertions(+)
 create mode 100644 lib/pci-testdev.c

diff --git a/arm/pci-test.c b/arm/pci-test.c
index db7d048..2ec6156 100644
--- a/arm/pci-test.c
+++ b/arm/pci-test.c
@@ -15,6 +15,10 @@ int main(void)
 	ret = pci_probe();
 	report("PCI device tree probing", ret);
 
+	ret = pci_testdev();
+	report("PCI test device passed %d tests",
+	       ret >= PCI_TESTDEV_NUM_BARS * PCI_TESTDEV_NUM_TESTS, ret);
+
 	pci_shutdown();
 
 	return report_summary();
diff --git a/config/config-arm-common.mak b/config/config-arm-common.mak
index 06ad346..f2e0ad1 100644
--- a/config/config-arm-common.mak
+++ b/config/config-arm-common.mak
@@ -31,6 +31,7 @@ include config/asm-offsets.mak
 cflatobjs += lib/alloc.o
 cflatobjs += lib/devicetree.o
 cflatobjs += lib/pci-host-generic.o
+cflatobjs += lib/pci-testdev.o
 cflatobjs += lib/virtio.o
 cflatobjs += lib/virtio-mmio.o
 cflatobjs += lib/chr-testdev.o
diff --git a/lib/pci-testdev.c b/lib/pci-testdev.c
new file mode 100644
index 0000000..1567228
--- /dev/null
+++ b/lib/pci-testdev.c
@@ -0,0 +1,189 @@
+/*
+ * QEMU "pci-testdev" PCI test device
+ *
+ * Copyright (C) 2016, Red Hat Inc, Alexander Gordeev <agordeev@xxxxxxxxxx>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.
+ */
+#include "pci.h"
+#include "asm/io.h"
+
+struct pci_testdev_ops {
+	u8 (*read_byte)(const volatile void *addr);
+	u16 (*read_word)(const volatile void *addr);
+	u32 (*read_long)(const volatile void *addr);
+	void (*write_byte)(u8 value, volatile void *addr);
+	void (*write_word)(u16 value, volatile void *addr);
+	void (*write_long)(u32 value, volatile void *addr);
+};
+
+static u8 ioreadb(const volatile void *addr)
+{
+	return readb(addr);
+}
+
+static u16 ioreadw(const volatile void *addr)
+{
+	return readw(addr);
+}
+
+static u32 ioreadl(const volatile void *addr)
+{
+	return readl(addr);
+}
+
+static void iowriteb(u8 value, volatile void *addr)
+{
+	writeb(value, addr);
+}
+
+static void iowritew(u16 value, volatile void *addr)
+{
+	writew(value, addr);
+}
+
+static void iowritel(u32 value, volatile void *addr)
+{
+	writel(value, addr);
+}
+
+static struct pci_testdev_ops pci_testdev_io_ops = {
+	.read_byte	= ioreadb,
+	.read_word	= ioreadw,
+	.read_long	= ioreadl,
+	.write_byte	= iowriteb,
+	.write_word	= iowritew,
+	.write_long	= iowritel
+};
+
+static u8 memreadb(const volatile void *addr)
+{
+	return *(const volatile u8 __force *)addr;
+}
+
+static u16 memreadw(const volatile void *addr)
+{
+	return *(const volatile u16 __force *)addr;
+}
+
+static u32 memreadl(const volatile void *addr)
+{
+	return *(const volatile u32 __force *)addr;
+}
+
+static void memwriteb(u8 value, volatile void *addr)
+{
+	*(volatile u8 __force *)addr = value;
+}
+
+static void memwritew(u16 value, volatile void *addr)
+{
+	*(volatile u16 __force *)addr = value;
+}
+
+static void memwritel(u32 value, volatile void *addr)
+{
+	*(volatile u32 __force *)addr = value;
+}
+
+static struct pci_testdev_ops pci_testdev_mem_ops = {
+	.read_byte	= memreadb,
+	.read_word	= memreadw,
+	.read_long	= memreadl,
+	.write_byte	= memwriteb,
+	.write_word	= memwritew,
+	.write_long	= memwritel
+};
+
+static bool pci_testdev_one(struct pci_test_dev_hdr *test,
+			    int test_nr,
+			    struct pci_testdev_ops *ops)
+{
+	u8 width;
+	u32 count, sig, off;
+	const int nr_writes = 16;
+	int i;
+
+	ops->write_byte(test_nr, &test->test);
+	count = ops->read_long(&test->count);
+	if (count != 0)
+		return false;
+
+	width = ops->read_byte(&test->width);
+	if ((width != 1) && (width != 2) && (width != 4))
+		return false;
+
+	sig = ops->read_long(&test->data);
+	off = ops->read_long(&test->offset);
+
+	for (i = 0; i < nr_writes; i++) {
+		switch (width) {
+			case 1: ops->write_byte(sig, (void*)test + off); break;
+			case 2: ops->write_word(sig, (void*)test + off); break;
+			case 4: ops->write_long(sig, (void*)test + off); break;
+		}
+	}
+
+	if ((int)ops->read_long(&test->count) != nr_writes)
+		return false;
+
+	return true;
+}
+
+void pci_testdev_print(struct pci_test_dev_hdr *test,
+		       struct pci_testdev_ops *ops)
+{
+	bool io = (ops == &pci_testdev_io_ops);
+	int i;
+
+	printf("pci-testdev %3s: ", io ? "io" : "mem");
+	for (i = 0;; ++i) {
+		char c = ops->read_byte(&test->name[i]);
+		if (!c)
+			break;
+		printf("%c", c);
+	}
+	printf("\n");
+
+}
+
+static int pci_testdev_all(struct pci_test_dev_hdr *test,
+			   struct pci_testdev_ops *ops)
+{
+	int i;
+
+	for (i = 0;; i++) {
+		if (!pci_testdev_one(test, i, ops))
+			break;
+		pci_testdev_print(test, ops);
+	}
+
+	return i;
+}
+
+int pci_testdev(void)
+{
+	unsigned long addr;
+	void __iomem *mem, *io;
+	pcidevaddr_t dev;
+	int nr_tests = 0;
+
+	dev = pci_find_dev(PCI_VENDOR_ID_REDHAT, PCI_DEVICE_ID_REDHAT_TEST);
+	if (dev == PCIDEVADDR_INVALID)
+		return -1;
+
+	addr = pci_bar_addr(dev, 1);
+	if (addr == ~0ul)
+		return -1;
+	io = (void*)addr;
+
+	addr = pci_bar_addr(dev, 0);
+	if (addr == ~0ul)
+		return -1;
+	mem = ioremap(addr, 0);
+
+	nr_tests += pci_testdev_all(mem, &pci_testdev_mem_ops);
+	nr_tests += pci_testdev_all(io, &pci_testdev_io_ops);
+
+	return nr_tests;
+}
diff --git a/lib/pci.h b/lib/pci.h
index 80d0d04..4a0d305 100644
--- a/lib/pci.h
+++ b/lib/pci.h
@@ -27,7 +27,12 @@ bool pci_bar_is_valid(pcidevaddr_t dev, int bar_num);
 #define PCI_VENDOR_ID_REDHAT		0x1b36
 #define PCI_DEVICE_ID_REDHAT_TEST	0x0005
 
+/*
+ * pci-testdev supports at least three types of tests (via mmio and
+ * portio BARs): no-eventfd, wildcard-eventfd and datamatch-eventfd
+ */
 #define PCI_TESTDEV_NUM_BARS		2
+#define PCI_TESTDEV_NUM_TESTS		3
 
 struct pci_test_dev_hdr {
 	uint8_t  test;
@@ -41,5 +46,6 @@ struct pci_test_dev_hdr {
 
 extern bool pci_probe(void);
 extern void pci_shutdown(void);
+extern int pci_testdev(void);
 
 #endif /* PCI_H */
-- 
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