11cf4323eSThomas Huth /* 21cf4323eSThomas Huth * libqos PCI bindings for PC 31cf4323eSThomas Huth * 41cf4323eSThomas Huth * Copyright IBM, Corp. 2012-2013 51cf4323eSThomas Huth * 61cf4323eSThomas Huth * Authors: 71cf4323eSThomas Huth * Anthony Liguori <aliguori@us.ibm.com> 81cf4323eSThomas Huth * 91cf4323eSThomas Huth * This work is licensed under the terms of the GNU GPL, version 2 or later. 101cf4323eSThomas Huth * See the COPYING file in the top-level directory. 111cf4323eSThomas Huth */ 121cf4323eSThomas Huth 131cf4323eSThomas Huth #include "qemu/osdep.h" 141cf4323eSThomas Huth #include "libqtest.h" 151cf4323eSThomas Huth #include "libqos/pci-pc.h" 161cf4323eSThomas Huth #include "qapi/qmp/qdict.h" 171cf4323eSThomas Huth #include "hw/pci/pci_regs.h" 181cf4323eSThomas Huth 191cf4323eSThomas Huth #include "qemu/module.h" 201cf4323eSThomas Huth 211cf4323eSThomas Huth #define ACPI_PCIHP_ADDR 0xae00 221cf4323eSThomas Huth #define PCI_EJ_BASE 0x0008 231cf4323eSThomas Huth 241cf4323eSThomas Huth static uint8_t qpci_pc_pio_readb(QPCIBus *bus, uint32_t addr) 251cf4323eSThomas Huth { 261cf4323eSThomas Huth return qtest_inb(bus->qts, addr); 271cf4323eSThomas Huth } 281cf4323eSThomas Huth 291cf4323eSThomas Huth static void qpci_pc_pio_writeb(QPCIBus *bus, uint32_t addr, uint8_t val) 301cf4323eSThomas Huth { 311cf4323eSThomas Huth qtest_outb(bus->qts, addr, val); 321cf4323eSThomas Huth } 331cf4323eSThomas Huth 341cf4323eSThomas Huth static uint16_t qpci_pc_pio_readw(QPCIBus *bus, uint32_t addr) 351cf4323eSThomas Huth { 361cf4323eSThomas Huth return qtest_inw(bus->qts, addr); 371cf4323eSThomas Huth } 381cf4323eSThomas Huth 391cf4323eSThomas Huth static void qpci_pc_pio_writew(QPCIBus *bus, uint32_t addr, uint16_t val) 401cf4323eSThomas Huth { 411cf4323eSThomas Huth qtest_outw(bus->qts, addr, val); 421cf4323eSThomas Huth } 431cf4323eSThomas Huth 441cf4323eSThomas Huth static uint32_t qpci_pc_pio_readl(QPCIBus *bus, uint32_t addr) 451cf4323eSThomas Huth { 461cf4323eSThomas Huth return qtest_inl(bus->qts, addr); 471cf4323eSThomas Huth } 481cf4323eSThomas Huth 491cf4323eSThomas Huth static void qpci_pc_pio_writel(QPCIBus *bus, uint32_t addr, uint32_t val) 501cf4323eSThomas Huth { 511cf4323eSThomas Huth qtest_outl(bus->qts, addr, val); 521cf4323eSThomas Huth } 531cf4323eSThomas Huth 541cf4323eSThomas Huth static uint64_t qpci_pc_pio_readq(QPCIBus *bus, uint32_t addr) 551cf4323eSThomas Huth { 561cf4323eSThomas Huth return (uint64_t)qtest_inl(bus->qts, addr) + 571cf4323eSThomas Huth ((uint64_t)qtest_inl(bus->qts, addr + 4) << 32); 581cf4323eSThomas Huth } 591cf4323eSThomas Huth 601cf4323eSThomas Huth static void qpci_pc_pio_writeq(QPCIBus *bus, uint32_t addr, uint64_t val) 611cf4323eSThomas Huth { 621cf4323eSThomas Huth qtest_outl(bus->qts, addr, val & 0xffffffff); 631cf4323eSThomas Huth qtest_outl(bus->qts, addr + 4, val >> 32); 641cf4323eSThomas Huth } 651cf4323eSThomas Huth 661cf4323eSThomas Huth static void qpci_pc_memread(QPCIBus *bus, uint32_t addr, void *buf, size_t len) 671cf4323eSThomas Huth { 681cf4323eSThomas Huth qtest_memread(bus->qts, addr, buf, len); 691cf4323eSThomas Huth } 701cf4323eSThomas Huth 711cf4323eSThomas Huth static void qpci_pc_memwrite(QPCIBus *bus, uint32_t addr, 721cf4323eSThomas Huth const void *buf, size_t len) 731cf4323eSThomas Huth { 741cf4323eSThomas Huth qtest_memwrite(bus->qts, addr, buf, len); 751cf4323eSThomas Huth } 761cf4323eSThomas Huth 771cf4323eSThomas Huth static uint8_t qpci_pc_config_readb(QPCIBus *bus, int devfn, uint8_t offset) 781cf4323eSThomas Huth { 791cf4323eSThomas Huth qtest_outl(bus->qts, 0xcf8, (1U << 31) | (devfn << 8) | offset); 801cf4323eSThomas Huth return qtest_inb(bus->qts, 0xcfc); 811cf4323eSThomas Huth } 821cf4323eSThomas Huth 831cf4323eSThomas Huth static uint16_t qpci_pc_config_readw(QPCIBus *bus, int devfn, uint8_t offset) 841cf4323eSThomas Huth { 851cf4323eSThomas Huth qtest_outl(bus->qts, 0xcf8, (1U << 31) | (devfn << 8) | offset); 861cf4323eSThomas Huth return qtest_inw(bus->qts, 0xcfc); 871cf4323eSThomas Huth } 881cf4323eSThomas Huth 891cf4323eSThomas Huth static uint32_t qpci_pc_config_readl(QPCIBus *bus, int devfn, uint8_t offset) 901cf4323eSThomas Huth { 911cf4323eSThomas Huth qtest_outl(bus->qts, 0xcf8, (1U << 31) | (devfn << 8) | offset); 921cf4323eSThomas Huth return qtest_inl(bus->qts, 0xcfc); 931cf4323eSThomas Huth } 941cf4323eSThomas Huth 951cf4323eSThomas Huth static void qpci_pc_config_writeb(QPCIBus *bus, int devfn, uint8_t offset, uint8_t value) 961cf4323eSThomas Huth { 971cf4323eSThomas Huth qtest_outl(bus->qts, 0xcf8, (1U << 31) | (devfn << 8) | offset); 981cf4323eSThomas Huth qtest_outb(bus->qts, 0xcfc, value); 991cf4323eSThomas Huth } 1001cf4323eSThomas Huth 1011cf4323eSThomas Huth static void qpci_pc_config_writew(QPCIBus *bus, int devfn, uint8_t offset, uint16_t value) 1021cf4323eSThomas Huth { 1031cf4323eSThomas Huth qtest_outl(bus->qts, 0xcf8, (1U << 31) | (devfn << 8) | offset); 1041cf4323eSThomas Huth qtest_outw(bus->qts, 0xcfc, value); 1051cf4323eSThomas Huth } 1061cf4323eSThomas Huth 1071cf4323eSThomas Huth static void qpci_pc_config_writel(QPCIBus *bus, int devfn, uint8_t offset, uint32_t value) 1081cf4323eSThomas Huth { 1091cf4323eSThomas Huth qtest_outl(bus->qts, 0xcf8, (1U << 31) | (devfn << 8) | offset); 1101cf4323eSThomas Huth qtest_outl(bus->qts, 0xcfc, value); 1111cf4323eSThomas Huth } 1121cf4323eSThomas Huth 1131cf4323eSThomas Huth static void *qpci_pc_get_driver(void *obj, const char *interface) 1141cf4323eSThomas Huth { 1151cf4323eSThomas Huth QPCIBusPC *qpci = obj; 1161cf4323eSThomas Huth if (!g_strcmp0(interface, "pci-bus")) { 1171cf4323eSThomas Huth return &qpci->bus; 1181cf4323eSThomas Huth } 1191cf4323eSThomas Huth fprintf(stderr, "%s not present in pci-bus-pc\n", interface); 1201cf4323eSThomas Huth g_assert_not_reached(); 1211cf4323eSThomas Huth } 1221cf4323eSThomas Huth 1231cf4323eSThomas Huth void qpci_init_pc(QPCIBusPC *qpci, QTestState *qts, QGuestAllocator *alloc) 1241cf4323eSThomas Huth { 1251cf4323eSThomas Huth assert(qts); 1261cf4323eSThomas Huth 1271cf4323eSThomas Huth /* tests can use pci-bus */ 1281cf4323eSThomas Huth qpci->bus.has_buggy_msi = false; 1291cf4323eSThomas Huth 1301cf4323eSThomas Huth qpci->bus.pio_readb = qpci_pc_pio_readb; 1311cf4323eSThomas Huth qpci->bus.pio_readw = qpci_pc_pio_readw; 1321cf4323eSThomas Huth qpci->bus.pio_readl = qpci_pc_pio_readl; 1331cf4323eSThomas Huth qpci->bus.pio_readq = qpci_pc_pio_readq; 1341cf4323eSThomas Huth 1351cf4323eSThomas Huth qpci->bus.pio_writeb = qpci_pc_pio_writeb; 1361cf4323eSThomas Huth qpci->bus.pio_writew = qpci_pc_pio_writew; 1371cf4323eSThomas Huth qpci->bus.pio_writel = qpci_pc_pio_writel; 1381cf4323eSThomas Huth qpci->bus.pio_writeq = qpci_pc_pio_writeq; 1391cf4323eSThomas Huth 1401cf4323eSThomas Huth qpci->bus.memread = qpci_pc_memread; 1411cf4323eSThomas Huth qpci->bus.memwrite = qpci_pc_memwrite; 1421cf4323eSThomas Huth 1431cf4323eSThomas Huth qpci->bus.config_readb = qpci_pc_config_readb; 1441cf4323eSThomas Huth qpci->bus.config_readw = qpci_pc_config_readw; 1451cf4323eSThomas Huth qpci->bus.config_readl = qpci_pc_config_readl; 1461cf4323eSThomas Huth 1471cf4323eSThomas Huth qpci->bus.config_writeb = qpci_pc_config_writeb; 1481cf4323eSThomas Huth qpci->bus.config_writew = qpci_pc_config_writew; 1491cf4323eSThomas Huth qpci->bus.config_writel = qpci_pc_config_writel; 1501cf4323eSThomas Huth 1511cf4323eSThomas Huth qpci->bus.qts = qts; 1521cf4323eSThomas Huth qpci->bus.pio_alloc_ptr = 0xc000; 1531cf4323eSThomas Huth qpci->bus.mmio_alloc_ptr = 0xE0000000; 1541cf4323eSThomas Huth qpci->bus.mmio_limit = 0x100000000ULL; 1551cf4323eSThomas Huth 1561cf4323eSThomas Huth qpci->obj.get_driver = qpci_pc_get_driver; 1571cf4323eSThomas Huth } 1581cf4323eSThomas Huth 1591cf4323eSThomas Huth QPCIBus *qpci_new_pc(QTestState *qts, QGuestAllocator *alloc) 1601cf4323eSThomas Huth { 1611cf4323eSThomas Huth QPCIBusPC *qpci = g_new0(QPCIBusPC, 1); 1621cf4323eSThomas Huth qpci_init_pc(qpci, qts, alloc); 1631cf4323eSThomas Huth 1641cf4323eSThomas Huth return &qpci->bus; 1651cf4323eSThomas Huth } 1661cf4323eSThomas Huth 1671cf4323eSThomas Huth void qpci_free_pc(QPCIBus *bus) 1681cf4323eSThomas Huth { 1691cf4323eSThomas Huth QPCIBusPC *s; 1701cf4323eSThomas Huth 1711cf4323eSThomas Huth if (!bus) { 1721cf4323eSThomas Huth return; 1731cf4323eSThomas Huth } 1741cf4323eSThomas Huth s = container_of(bus, QPCIBusPC, bus); 1751cf4323eSThomas Huth 1761cf4323eSThomas Huth g_free(s); 1771cf4323eSThomas Huth } 1781cf4323eSThomas Huth 1791cf4323eSThomas Huth void qpci_unplug_acpi_device_test(QTestState *qts, const char *id, uint8_t slot) 1801cf4323eSThomas Huth { 1811cf4323eSThomas Huth QDict *response; 1821cf4323eSThomas Huth 1831cf4323eSThomas Huth response = qtest_qmp(qts, "{'execute': 'device_del'," 1841cf4323eSThomas Huth " 'arguments': {'id': %s}}", id); 1851cf4323eSThomas Huth g_assert(response); 1861cf4323eSThomas Huth g_assert(!qdict_haskey(response, "error")); 1871cf4323eSThomas Huth qobject_unref(response); 1881cf4323eSThomas Huth 189*4b7c0683SPaolo Bonzini qtest_outl(qts, ACPI_PCIHP_ADDR + PCI_EJ_BASE, 1 << slot); 1901cf4323eSThomas Huth 1911cf4323eSThomas Huth qtest_qmp_eventwait(qts, "DEVICE_DELETED"); 1921cf4323eSThomas Huth } 1931cf4323eSThomas Huth 1941cf4323eSThomas Huth static void qpci_pc_register_nodes(void) 1951cf4323eSThomas Huth { 1961cf4323eSThomas Huth qos_node_create_driver("pci-bus-pc", NULL); 1971cf4323eSThomas Huth qos_node_produces("pci-bus-pc", "pci-bus"); 1981cf4323eSThomas Huth } 1991cf4323eSThomas Huth 2001cf4323eSThomas Huth libqos_init(qpci_pc_register_nodes); 201