123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194 |
- /*
- * QEMU "pci-testdev" PCI test device
- *
- * Copyright (C) 2016, Red Hat Inc, Alexander Gordeev <agordeev@redhat.com>
- *
- * 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 (*io_readb)(const volatile void *addr);
- u16 (*io_readw)(const volatile void *addr);
- u32 (*io_readl)(const volatile void *addr);
- void (*io_writeb)(u8 value, volatile void *addr);
- void (*io_writew)(u16 value, volatile void *addr);
- void (*io_writel)(u32 value, volatile void *addr);
- };
- static u8 pio_readb(const volatile void *addr)
- {
- return inb((unsigned long)addr);
- }
- static u16 pio_readw(const volatile void *addr)
- {
- return inw((unsigned long)addr);
- }
- static u32 pio_readl(const volatile void *addr)
- {
- return inl((unsigned long)addr);
- }
- static void pio_writeb(u8 value, volatile void *addr)
- {
- outb(value, (unsigned long)addr);
- }
- static void pio_writew(u16 value, volatile void *addr)
- {
- outw(value, (unsigned long)addr);
- }
- static void pio_writel(u32 value, volatile void *addr)
- {
- outl(value, (unsigned long)addr);
- }
- static struct pci_testdev_ops pci_testdev_io_ops = {
- .io_readb = pio_readb,
- .io_readw = pio_readw,
- .io_readl = pio_readl,
- .io_writeb = pio_writeb,
- .io_writew = pio_writew,
- .io_writel = pio_writel
- };
- static u8 mmio_readb(const volatile void *addr)
- {
- return *(const volatile u8 __force *)addr;
- }
- static u16 mmio_readw(const volatile void *addr)
- {
- return *(const volatile u16 __force *)addr;
- }
- static u32 mmio_readl(const volatile void *addr)
- {
- return *(const volatile u32 __force *)addr;
- }
- static void mmio_writeb(u8 value, volatile void *addr)
- {
- *(volatile u8 __force *)addr = value;
- }
- static void mmio_writew(u16 value, volatile void *addr)
- {
- *(volatile u16 __force *)addr = value;
- }
- static void mmio_writel(u32 value, volatile void *addr)
- {
- *(volatile u32 __force *)addr = value;
- }
- static struct pci_testdev_ops pci_testdev_mem_ops = {
- .io_readb = mmio_readb,
- .io_readw = mmio_readw,
- .io_readl = mmio_readl,
- .io_writeb = mmio_writeb,
- .io_writew = mmio_writew,
- .io_writel = mmio_writel
- };
- 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->io_writeb(test_nr, &test->test);
- count = ops->io_readl(&test->count);
- if (count != 0)
- return false;
- width = ops->io_readb(&test->width);
- if (width != 1 && width != 2 && width != 4)
- return false;
- sig = ops->io_readl(&test->data);
- off = ops->io_readl(&test->offset);
- for (i = 0; i < nr_writes; i++) {
- switch (width) {
- case 1: ops->io_writeb(sig, (void *)test + off); break;
- case 2: ops->io_writew(sig, (void *)test + off); break;
- case 4: ops->io_writel(sig, (void *)test + off); break;
- }
- }
- count = ops->io_readl(&test->count);
- if (!count)
- return true;
- return (int)count == nr_writes;
- }
- static 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->io_readb(&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)
- {
- struct pci_dev pci_dev;
- pcidevaddr_t dev;
- phys_addr_t addr;
- void __iomem *mem, *io;
- int nr_tests = 0;
- bool ret;
- dev = pci_find_dev(PCI_VENDOR_ID_REDHAT, PCI_DEVICE_ID_REDHAT_TEST);
- if (dev == PCIDEVADDR_INVALID) {
- printf("'pci-testdev' device is not found, "
- "check QEMU '-device pci-testdev' parameter\n");
- return -1;
- }
- pci_dev_init(&pci_dev, dev);
- ret = pci_bar_is_valid(&pci_dev, 0) && pci_bar_is_valid(&pci_dev, 1);
- assert(ret);
- addr = pci_bar_get_addr(&pci_dev, 0);
- mem = ioremap(addr, PAGE_SIZE);
- addr = pci_bar_get_addr(&pci_dev, 1);
- io = (void *)(unsigned long)addr;
- nr_tests += pci_testdev_all(mem, &pci_testdev_mem_ops);
- nr_tests += pci_testdev_all(io, &pci_testdev_io_ops);
- return nr_tests;
- }
|