pci-testdev.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  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. struct pci_testdev_ops {
  11. u8 (*io_readb)(const volatile void *addr);
  12. u16 (*io_readw)(const volatile void *addr);
  13. u32 (*io_readl)(const volatile void *addr);
  14. void (*io_writeb)(u8 value, volatile void *addr);
  15. void (*io_writew)(u16 value, volatile void *addr);
  16. void (*io_writel)(u32 value, volatile void *addr);
  17. };
  18. static u8 pio_readb(const volatile void *addr)
  19. {
  20. return inb((unsigned long)addr);
  21. }
  22. static u16 pio_readw(const volatile void *addr)
  23. {
  24. return inw((unsigned long)addr);
  25. }
  26. static u32 pio_readl(const volatile void *addr)
  27. {
  28. return inl((unsigned long)addr);
  29. }
  30. static void pio_writeb(u8 value, volatile void *addr)
  31. {
  32. outb(value, (unsigned long)addr);
  33. }
  34. static void pio_writew(u16 value, volatile void *addr)
  35. {
  36. outw(value, (unsigned long)addr);
  37. }
  38. static void pio_writel(u32 value, volatile void *addr)
  39. {
  40. outl(value, (unsigned long)addr);
  41. }
  42. static struct pci_testdev_ops pci_testdev_io_ops = {
  43. .io_readb = pio_readb,
  44. .io_readw = pio_readw,
  45. .io_readl = pio_readl,
  46. .io_writeb = pio_writeb,
  47. .io_writew = pio_writew,
  48. .io_writel = pio_writel
  49. };
  50. static u8 mmio_readb(const volatile void *addr)
  51. {
  52. return *(const volatile u8 __force *)addr;
  53. }
  54. static u16 mmio_readw(const volatile void *addr)
  55. {
  56. return *(const volatile u16 __force *)addr;
  57. }
  58. static u32 mmio_readl(const volatile void *addr)
  59. {
  60. return *(const volatile u32 __force *)addr;
  61. }
  62. static void mmio_writeb(u8 value, volatile void *addr)
  63. {
  64. *(volatile u8 __force *)addr = value;
  65. }
  66. static void mmio_writew(u16 value, volatile void *addr)
  67. {
  68. *(volatile u16 __force *)addr = value;
  69. }
  70. static void mmio_writel(u32 value, volatile void *addr)
  71. {
  72. *(volatile u32 __force *)addr = value;
  73. }
  74. static struct pci_testdev_ops pci_testdev_mem_ops = {
  75. .io_readb = mmio_readb,
  76. .io_readw = mmio_readw,
  77. .io_readl = mmio_readl,
  78. .io_writeb = mmio_writeb,
  79. .io_writew = mmio_writew,
  80. .io_writel = mmio_writel
  81. };
  82. static bool pci_testdev_one(struct pci_test_dev_hdr *test,
  83. int test_nr,
  84. struct pci_testdev_ops *ops)
  85. {
  86. u8 width;
  87. u32 count, sig, off;
  88. const int nr_writes = 16;
  89. int i;
  90. ops->io_writeb(test_nr, &test->test);
  91. count = ops->io_readl(&test->count);
  92. if (count != 0)
  93. return false;
  94. width = ops->io_readb(&test->width);
  95. if (width != 1 && width != 2 && width != 4)
  96. return false;
  97. sig = ops->io_readl(&test->data);
  98. off = ops->io_readl(&test->offset);
  99. for (i = 0; i < nr_writes; i++) {
  100. switch (width) {
  101. case 1: ops->io_writeb(sig, (void *)test + off); break;
  102. case 2: ops->io_writew(sig, (void *)test + off); break;
  103. case 4: ops->io_writel(sig, (void *)test + off); break;
  104. }
  105. }
  106. count = ops->io_readl(&test->count);
  107. if (!count)
  108. return true;
  109. return (int)count == nr_writes;
  110. }
  111. static void pci_testdev_print(struct pci_test_dev_hdr *test,
  112. struct pci_testdev_ops *ops)
  113. {
  114. bool io = (ops == &pci_testdev_io_ops);
  115. int i;
  116. printf("pci-testdev %3s: ", io ? "io" : "mem");
  117. for (i = 0;; ++i) {
  118. char c = ops->io_readb(&test->name[i]);
  119. if (!c)
  120. break;
  121. printf("%c", c);
  122. }
  123. printf("\n");
  124. }
  125. static int pci_testdev_all(struct pci_test_dev_hdr *test,
  126. struct pci_testdev_ops *ops)
  127. {
  128. int i;
  129. for (i = 0;; i++) {
  130. if (!pci_testdev_one(test, i, ops))
  131. break;
  132. pci_testdev_print(test, ops);
  133. }
  134. return i;
  135. }
  136. int pci_testdev(void)
  137. {
  138. struct pci_dev pci_dev;
  139. pcidevaddr_t dev;
  140. phys_addr_t addr;
  141. void __iomem *mem, *io;
  142. int nr_tests = 0;
  143. bool ret;
  144. dev = pci_find_dev(PCI_VENDOR_ID_REDHAT, PCI_DEVICE_ID_REDHAT_TEST);
  145. if (dev == PCIDEVADDR_INVALID) {
  146. printf("'pci-testdev' device is not found, "
  147. "check QEMU '-device pci-testdev' parameter\n");
  148. return -1;
  149. }
  150. pci_dev_init(&pci_dev, dev);
  151. ret = pci_bar_is_valid(&pci_dev, 0) && pci_bar_is_valid(&pci_dev, 1);
  152. assert(ret);
  153. addr = pci_bar_get_addr(&pci_dev, 0);
  154. mem = ioremap(addr, PAGE_SIZE);
  155. addr = pci_bar_get_addr(&pci_dev, 1);
  156. io = (void *)(unsigned long)addr;
  157. nr_tests += pci_testdev_all(mem, &pci_testdev_mem_ops);
  158. nr_tests += pci_testdev_all(io, &pci_testdev_io_ops);
  159. return nr_tests;
  160. }