1 /* 2 * libqos PCI bindings for PC 3 * 4 * Copyright IBM, Corp. 2012-2013 5 * 6 * Authors: 7 * Anthony Liguori <aliguori@us.ibm.com> 8 * 9 * This work is licensed under the terms of the GNU GPL, version 2 or later. 10 * See the COPYING file in the top-level directory. 11 */ 12 13 #include "qemu/osdep.h" 14 #include "libqtest.h" 15 #include "libqos/pci-pc.h" 16 #include "qapi/qmp/qdict.h" 17 #include "hw/pci/pci_regs.h" 18 19 #include "qemu/module.h" 20 21 #define ACPI_PCIHP_ADDR 0xae00 22 #define PCI_EJ_BASE 0x0008 23 24 static uint8_t qpci_pc_pio_readb(QPCIBus *bus, uint32_t addr) 25 { 26 return qtest_inb(bus->qts, addr); 27 } 28 29 static void qpci_pc_pio_writeb(QPCIBus *bus, uint32_t addr, uint8_t val) 30 { 31 qtest_outb(bus->qts, addr, val); 32 } 33 34 static uint16_t qpci_pc_pio_readw(QPCIBus *bus, uint32_t addr) 35 { 36 return qtest_inw(bus->qts, addr); 37 } 38 39 static void qpci_pc_pio_writew(QPCIBus *bus, uint32_t addr, uint16_t val) 40 { 41 qtest_outw(bus->qts, addr, val); 42 } 43 44 static uint32_t qpci_pc_pio_readl(QPCIBus *bus, uint32_t addr) 45 { 46 return qtest_inl(bus->qts, addr); 47 } 48 49 static void qpci_pc_pio_writel(QPCIBus *bus, uint32_t addr, uint32_t val) 50 { 51 qtest_outl(bus->qts, addr, val); 52 } 53 54 static uint64_t qpci_pc_pio_readq(QPCIBus *bus, uint32_t addr) 55 { 56 return (uint64_t)qtest_inl(bus->qts, addr) + 57 ((uint64_t)qtest_inl(bus->qts, addr + 4) << 32); 58 } 59 60 static void qpci_pc_pio_writeq(QPCIBus *bus, uint32_t addr, uint64_t val) 61 { 62 qtest_outl(bus->qts, addr, val & 0xffffffff); 63 qtest_outl(bus->qts, addr + 4, val >> 32); 64 } 65 66 static void qpci_pc_memread(QPCIBus *bus, uint32_t addr, void *buf, size_t len) 67 { 68 qtest_memread(bus->qts, addr, buf, len); 69 } 70 71 static void qpci_pc_memwrite(QPCIBus *bus, uint32_t addr, 72 const void *buf, size_t len) 73 { 74 qtest_memwrite(bus->qts, addr, buf, len); 75 } 76 77 static uint8_t qpci_pc_config_readb(QPCIBus *bus, int devfn, uint8_t offset) 78 { 79 qtest_outl(bus->qts, 0xcf8, (1U << 31) | (devfn << 8) | offset); 80 return qtest_inb(bus->qts, 0xcfc); 81 } 82 83 static uint16_t qpci_pc_config_readw(QPCIBus *bus, int devfn, uint8_t offset) 84 { 85 qtest_outl(bus->qts, 0xcf8, (1U << 31) | (devfn << 8) | offset); 86 return qtest_inw(bus->qts, 0xcfc); 87 } 88 89 static uint32_t qpci_pc_config_readl(QPCIBus *bus, int devfn, uint8_t offset) 90 { 91 qtest_outl(bus->qts, 0xcf8, (1U << 31) | (devfn << 8) | offset); 92 return qtest_inl(bus->qts, 0xcfc); 93 } 94 95 static void qpci_pc_config_writeb(QPCIBus *bus, int devfn, uint8_t offset, uint8_t value) 96 { 97 qtest_outl(bus->qts, 0xcf8, (1U << 31) | (devfn << 8) | offset); 98 qtest_outb(bus->qts, 0xcfc, value); 99 } 100 101 static void qpci_pc_config_writew(QPCIBus *bus, int devfn, uint8_t offset, uint16_t value) 102 { 103 qtest_outl(bus->qts, 0xcf8, (1U << 31) | (devfn << 8) | offset); 104 qtest_outw(bus->qts, 0xcfc, value); 105 } 106 107 static void qpci_pc_config_writel(QPCIBus *bus, int devfn, uint8_t offset, uint32_t value) 108 { 109 qtest_outl(bus->qts, 0xcf8, (1U << 31) | (devfn << 8) | offset); 110 qtest_outl(bus->qts, 0xcfc, value); 111 } 112 113 static void *qpci_pc_get_driver(void *obj, const char *interface) 114 { 115 QPCIBusPC *qpci = obj; 116 if (!g_strcmp0(interface, "pci-bus")) { 117 return &qpci->bus; 118 } 119 fprintf(stderr, "%s not present in pci-bus-pc\n", interface); 120 g_assert_not_reached(); 121 } 122 123 void qpci_init_pc(QPCIBusPC *qpci, QTestState *qts, QGuestAllocator *alloc) 124 { 125 assert(qts); 126 127 /* tests can use pci-bus */ 128 qpci->bus.has_buggy_msi = false; 129 130 qpci->bus.pio_readb = qpci_pc_pio_readb; 131 qpci->bus.pio_readw = qpci_pc_pio_readw; 132 qpci->bus.pio_readl = qpci_pc_pio_readl; 133 qpci->bus.pio_readq = qpci_pc_pio_readq; 134 135 qpci->bus.pio_writeb = qpci_pc_pio_writeb; 136 qpci->bus.pio_writew = qpci_pc_pio_writew; 137 qpci->bus.pio_writel = qpci_pc_pio_writel; 138 qpci->bus.pio_writeq = qpci_pc_pio_writeq; 139 140 qpci->bus.memread = qpci_pc_memread; 141 qpci->bus.memwrite = qpci_pc_memwrite; 142 143 qpci->bus.config_readb = qpci_pc_config_readb; 144 qpci->bus.config_readw = qpci_pc_config_readw; 145 qpci->bus.config_readl = qpci_pc_config_readl; 146 147 qpci->bus.config_writeb = qpci_pc_config_writeb; 148 qpci->bus.config_writew = qpci_pc_config_writew; 149 qpci->bus.config_writel = qpci_pc_config_writel; 150 151 qpci->bus.qts = qts; 152 qpci->bus.pio_alloc_ptr = 0xc000; 153 qpci->bus.mmio_alloc_ptr = 0xE0000000; 154 qpci->bus.mmio_limit = 0x100000000ULL; 155 156 qpci->obj.get_driver = qpci_pc_get_driver; 157 } 158 159 QPCIBus *qpci_new_pc(QTestState *qts, QGuestAllocator *alloc) 160 { 161 QPCIBusPC *qpci = g_new0(QPCIBusPC, 1); 162 qpci_init_pc(qpci, qts, alloc); 163 164 return &qpci->bus; 165 } 166 167 void qpci_free_pc(QPCIBus *bus) 168 { 169 QPCIBusPC *s; 170 171 if (!bus) { 172 return; 173 } 174 s = container_of(bus, QPCIBusPC, bus); 175 176 g_free(s); 177 } 178 179 void qpci_unplug_acpi_device_test(QTestState *qts, const char *id, uint8_t slot) 180 { 181 QDict *response; 182 183 response = qtest_qmp(qts, "{'execute': 'device_del'," 184 " 'arguments': {'id': %s}}", id); 185 g_assert(response); 186 g_assert(!qdict_haskey(response, "error")); 187 qobject_unref(response); 188 189 qtest_outb(qts, ACPI_PCIHP_ADDR + PCI_EJ_BASE, 1 << slot); 190 191 qtest_qmp_eventwait(qts, "DEVICE_DELETED"); 192 } 193 194 static void qpci_pc_register_nodes(void) 195 { 196 qos_node_create_driver("pci-bus-pc", NULL); 197 qos_node_produces("pci-bus-pc", "pci-bus"); 198 } 199 200 libqos_init(qpci_pc_register_nodes); 201