1 /* 2 * QEMU "pci-testdev" PCI test device 3 * 4 * Copyright (C) 2016, Red Hat Inc, Alexander Gordeev <agordeev@redhat.com> 5 * 6 * This work is licensed under the terms of the GNU LGPL, version 2. 7 */ 8 #include "pci.h" 9 #include "asm/io.h" 10 11 struct pci_testdev_ops { 12 u8 (*io_readb)(const volatile void *addr); 13 u16 (*io_readw)(const volatile void *addr); 14 u32 (*io_readl)(const volatile void *addr); 15 void (*io_writeb)(u8 value, volatile void *addr); 16 void (*io_writew)(u16 value, volatile void *addr); 17 void (*io_writel)(u32 value, volatile void *addr); 18 }; 19 20 static u8 pio_readb(const volatile void *addr) 21 { 22 return inb((unsigned long)addr); 23 } 24 25 static u16 pio_readw(const volatile void *addr) 26 { 27 return inw((unsigned long)addr); 28 } 29 30 static u32 pio_readl(const volatile void *addr) 31 { 32 return inl((unsigned long)addr); 33 } 34 35 static void pio_writeb(u8 value, volatile void *addr) 36 { 37 outb(value, (unsigned long)addr); 38 } 39 40 static void pio_writew(u16 value, volatile void *addr) 41 { 42 outw(value, (unsigned long)addr); 43 } 44 45 static void pio_writel(u32 value, volatile void *addr) 46 { 47 outl(value, (unsigned long)addr); 48 } 49 50 static struct pci_testdev_ops pci_testdev_io_ops = { 51 .io_readb = pio_readb, 52 .io_readw = pio_readw, 53 .io_readl = pio_readl, 54 .io_writeb = pio_writeb, 55 .io_writew = pio_writew, 56 .io_writel = pio_writel 57 }; 58 59 static u8 mmio_readb(const volatile void *addr) 60 { 61 return *(const volatile u8 __force *)addr; 62 } 63 64 static u16 mmio_readw(const volatile void *addr) 65 { 66 return *(const volatile u16 __force *)addr; 67 } 68 69 static u32 mmio_readl(const volatile void *addr) 70 { 71 return *(const volatile u32 __force *)addr; 72 } 73 74 static void mmio_writeb(u8 value, volatile void *addr) 75 { 76 *(volatile u8 __force *)addr = value; 77 } 78 79 static void mmio_writew(u16 value, volatile void *addr) 80 { 81 *(volatile u16 __force *)addr = value; 82 } 83 84 static void mmio_writel(u32 value, volatile void *addr) 85 { 86 *(volatile u32 __force *)addr = value; 87 } 88 89 static struct pci_testdev_ops pci_testdev_mem_ops = { 90 .io_readb = mmio_readb, 91 .io_readw = mmio_readw, 92 .io_readl = mmio_readl, 93 .io_writeb = mmio_writeb, 94 .io_writew = mmio_writew, 95 .io_writel = mmio_writel 96 }; 97 98 static bool pci_testdev_one(struct pci_test_dev_hdr *test, 99 int test_nr, 100 struct pci_testdev_ops *ops) 101 { 102 u8 width; 103 u32 count, sig, off; 104 const int nr_writes = 16; 105 int i; 106 107 ops->io_writeb(test_nr, &test->test); 108 count = ops->io_readl(&test->count); 109 if (count != 0) 110 return false; 111 112 width = ops->io_readb(&test->width); 113 if (width != 1 && width != 2 && width != 4) 114 return false; 115 116 sig = ops->io_readl(&test->data); 117 off = ops->io_readl(&test->offset); 118 119 for (i = 0; i < nr_writes; i++) { 120 switch (width) { 121 case 1: ops->io_writeb(sig, (void *)test + off); break; 122 case 2: ops->io_writew(sig, (void *)test + off); break; 123 case 4: ops->io_writel(sig, (void *)test + off); break; 124 } 125 } 126 127 count = ops->io_readl(&test->count); 128 if (!count) 129 return true; 130 131 return (int)count == nr_writes; 132 } 133 134 void pci_testdev_print(struct pci_test_dev_hdr *test, 135 struct pci_testdev_ops *ops) 136 { 137 bool io = (ops == &pci_testdev_io_ops); 138 int i; 139 140 printf("pci-testdev %3s: ", io ? "io" : "mem"); 141 for (i = 0;; ++i) { 142 char c = ops->io_readb(&test->name[i]); 143 if (!c) 144 break; 145 printf("%c", c); 146 } 147 printf("\n"); 148 } 149 150 static int pci_testdev_all(struct pci_test_dev_hdr *test, 151 struct pci_testdev_ops *ops) 152 { 153 int i; 154 155 for (i = 0;; i++) { 156 if (!pci_testdev_one(test, i, ops)) 157 break; 158 pci_testdev_print(test, ops); 159 } 160 161 return i; 162 } 163 164 int pci_testdev(void) 165 { 166 struct pci_dev pci_dev; 167 pcidevaddr_t dev; 168 phys_addr_t addr; 169 void __iomem *mem, *io; 170 int nr_tests = 0; 171 bool ret; 172 173 dev = pci_find_dev(PCI_VENDOR_ID_REDHAT, PCI_DEVICE_ID_REDHAT_TEST); 174 if (dev == PCIDEVADDR_INVALID) { 175 printf("'pci-testdev' device is not found, " 176 "check QEMU '-device pci-testdev' parameter\n"); 177 return -1; 178 } 179 pci_dev_init(&pci_dev, dev); 180 181 ret = pci_bar_is_valid(&pci_dev, 0) && pci_bar_is_valid(&pci_dev, 1); 182 assert(ret); 183 184 addr = pci_bar_get_addr(&pci_dev, 0); 185 mem = ioremap(addr, PAGE_SIZE); 186 187 addr = pci_bar_get_addr(&pci_dev, 1); 188 io = (void *)(unsigned long)addr; 189 190 nr_tests += pci_testdev_all(mem, &pci_testdev_mem_ops); 191 nr_tests += pci_testdev_all(io, &pci_testdev_io_ops); 192 193 return nr_tests; 194 } 195