xref: /qemu/tests/qtest/libqos/pci-pc.c (revision 907b5105)
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"
14*907b5105SMarc-André Lureau #include "../libqtest.h"
15a2ce7dbdSPaolo Bonzini #include "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 
1894b7c0683SPaolo 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