xref: /qemu/tests/qtest/libqos/pci-pc.c (revision ea42a6c4)
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"
14907b5105SMarc-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 
qpci_pc_pio_readb(QPCIBus * bus,uint32_t addr)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 
qpci_pc_pio_writeb(QPCIBus * bus,uint32_t addr,uint8_t val)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 
qpci_pc_pio_readw(QPCIBus * bus,uint32_t addr)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 
qpci_pc_pio_writew(QPCIBus * bus,uint32_t addr,uint16_t val)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 
qpci_pc_pio_readl(QPCIBus * bus,uint32_t addr)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 
qpci_pc_pio_writel(QPCIBus * bus,uint32_t addr,uint32_t val)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 
qpci_pc_pio_readq(QPCIBus * bus,uint32_t addr)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 
qpci_pc_pio_writeq(QPCIBus * bus,uint32_t addr,uint64_t val)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 
qpci_pc_memread(QPCIBus * bus,uint32_t addr,void * buf,size_t len)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 
qpci_pc_memwrite(QPCIBus * bus,uint32_t addr,const void * buf,size_t len)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 
qpci_pc_config_readb(QPCIBus * bus,int devfn,uint8_t offset)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 
qpci_pc_config_readw(QPCIBus * bus,int devfn,uint8_t offset)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 
qpci_pc_config_readl(QPCIBus * bus,int devfn,uint8_t offset)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 
qpci_pc_config_writeb(QPCIBus * bus,int devfn,uint8_t offset,uint8_t value)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 
qpci_pc_config_writew(QPCIBus * bus,int devfn,uint8_t offset,uint16_t value)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 
qpci_pc_config_writel(QPCIBus * bus,int devfn,uint8_t offset,uint32_t value)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 
qpci_pc_get_driver(void * obj,const char * interface)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 
qpci_init_pc(QPCIBusPC * qpci,QTestState * qts,QGuestAllocator * alloc)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;
1533df72d1cSEric Auger     qpci->bus.pio_limit = 0x10000;
1541cf4323eSThomas Huth     qpci->bus.mmio_alloc_ptr = 0xE0000000;
1551cf4323eSThomas Huth     qpci->bus.mmio_limit = 0x100000000ULL;
1561cf4323eSThomas Huth 
1571cf4323eSThomas Huth     qpci->obj.get_driver = qpci_pc_get_driver;
1581cf4323eSThomas Huth }
1591cf4323eSThomas Huth 
qpci_new_pc(QTestState * qts,QGuestAllocator * alloc)1601cf4323eSThomas Huth QPCIBus *qpci_new_pc(QTestState *qts, QGuestAllocator *alloc)
1611cf4323eSThomas Huth {
1621cf4323eSThomas Huth     QPCIBusPC *qpci = g_new0(QPCIBusPC, 1);
1631cf4323eSThomas Huth     qpci_init_pc(qpci, qts, alloc);
1641cf4323eSThomas Huth 
1651cf4323eSThomas Huth     return &qpci->bus;
1661cf4323eSThomas Huth }
1671cf4323eSThomas Huth 
qpci_free_pc(QPCIBus * bus)1681cf4323eSThomas Huth void qpci_free_pc(QPCIBus *bus)
1691cf4323eSThomas Huth {
1701cf4323eSThomas Huth     QPCIBusPC *s;
1711cf4323eSThomas Huth 
1721cf4323eSThomas Huth     if (!bus) {
1731cf4323eSThomas Huth         return;
1741cf4323eSThomas Huth     }
1751cf4323eSThomas Huth     s = container_of(bus, QPCIBusPC, bus);
1761cf4323eSThomas Huth 
1771cf4323eSThomas Huth     g_free(s);
1781cf4323eSThomas Huth }
1791cf4323eSThomas Huth 
qpci_unplug_acpi_device_test(QTestState * qts,const char * id,uint8_t slot)1801cf4323eSThomas Huth void qpci_unplug_acpi_device_test(QTestState *qts, const char *id, uint8_t slot)
1811cf4323eSThomas Huth {
182ea42a6c4SMichael Labiuk     qtest_qmp_device_del_send(qts, id);
1831cf4323eSThomas Huth 
1844b7c0683SPaolo Bonzini     qtest_outl(qts, ACPI_PCIHP_ADDR + PCI_EJ_BASE, 1 << slot);
1851cf4323eSThomas Huth 
1861cf4323eSThomas Huth     qtest_qmp_eventwait(qts, "DEVICE_DELETED");
1871cf4323eSThomas Huth }
1881cf4323eSThomas Huth 
qpci_pc_register_nodes(void)1891cf4323eSThomas Huth static void qpci_pc_register_nodes(void)
1901cf4323eSThomas Huth {
1911cf4323eSThomas Huth     qos_node_create_driver("pci-bus-pc", NULL);
1921cf4323eSThomas Huth     qos_node_produces("pci-bus-pc", "pci-bus");
1931cf4323eSThomas Huth }
1941cf4323eSThomas Huth 
1951cf4323eSThomas Huth libqos_init(qpci_pc_register_nodes);
196