pci-pc.c (5343B)
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 "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 24static uint8_t qpci_pc_pio_readb(QPCIBus *bus, uint32_t addr) 25{ 26 return qtest_inb(bus->qts, addr); 27} 28 29static void qpci_pc_pio_writeb(QPCIBus *bus, uint32_t addr, uint8_t val) 30{ 31 qtest_outb(bus->qts, addr, val); 32} 33 34static uint16_t qpci_pc_pio_readw(QPCIBus *bus, uint32_t addr) 35{ 36 return qtest_inw(bus->qts, addr); 37} 38 39static void qpci_pc_pio_writew(QPCIBus *bus, uint32_t addr, uint16_t val) 40{ 41 qtest_outw(bus->qts, addr, val); 42} 43 44static uint32_t qpci_pc_pio_readl(QPCIBus *bus, uint32_t addr) 45{ 46 return qtest_inl(bus->qts, addr); 47} 48 49static void qpci_pc_pio_writel(QPCIBus *bus, uint32_t addr, uint32_t val) 50{ 51 qtest_outl(bus->qts, addr, val); 52} 53 54static 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 60static 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 66static 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 71static 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 77static 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 83static 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 89static 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 95static 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 101static 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 107static 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 113static 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 123void 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 159QPCIBus *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 167void 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 179void 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_outl(qts, ACPI_PCIHP_ADDR + PCI_EJ_BASE, 1 << slot); 190 191 qtest_qmp_eventwait(qts, "DEVICE_DELETED"); 192} 193 194static 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 200libqos_init(qpci_pc_register_nodes);