Spaces:
Runtime error
Runtime error
File size: 4,232 Bytes
8df6da4 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 |
/*
* 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;
}
|