2 * libqos PCI bindings for PC
4 * Copyright IBM, Corp. 2012-2013
7 * Anthony Liguori <aliguori@us.ibm.com>
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.
13 #include "qemu/osdep.h"
16 #include "qapi/qmp/qdict.h"
17 #include "hw/pci/pci_regs.h"
19 #include "qemu/module.h"
21 #define ACPI_PCIHP_ADDR 0xae00
22 #define PCI_EJ_BASE 0x0008
24 static uint8_t qpci_pc_pio_readb(QPCIBus
*bus
, uint32_t addr
)
26 return qtest_inb(bus
->qts
, addr
);
29 static void qpci_pc_pio_writeb(QPCIBus
*bus
, uint32_t addr
, uint8_t val
)
31 qtest_outb(bus
->qts
, addr
, val
);
34 static uint16_t qpci_pc_pio_readw(QPCIBus
*bus
, uint32_t addr
)
36 return qtest_inw(bus
->qts
, addr
);
39 static void qpci_pc_pio_writew(QPCIBus
*bus
, uint32_t addr
, uint16_t val
)
41 qtest_outw(bus
->qts
, addr
, val
);
44 static uint32_t qpci_pc_pio_readl(QPCIBus
*bus
, uint32_t addr
)
46 return qtest_inl(bus
->qts
, addr
);
49 static void qpci_pc_pio_writel(QPCIBus
*bus
, uint32_t addr
, uint32_t val
)
51 qtest_outl(bus
->qts
, addr
, val
);
54 static uint64_t qpci_pc_pio_readq(QPCIBus
*bus
, uint32_t addr
)
56 return (uint64_t)qtest_inl(bus
->qts
, addr
) +
57 ((uint64_t)qtest_inl(bus
->qts
, addr
+ 4) << 32);
60 static void qpci_pc_pio_writeq(QPCIBus
*bus
, uint32_t addr
, uint64_t val
)
62 qtest_outl(bus
->qts
, addr
, val
& 0xffffffff);
63 qtest_outl(bus
->qts
, addr
+ 4, val
>> 32);
66 static void qpci_pc_memread(QPCIBus
*bus
, uint32_t addr
, void *buf
, size_t len
)
68 qtest_memread(bus
->qts
, addr
, buf
, len
);
71 static void qpci_pc_memwrite(QPCIBus
*bus
, uint32_t addr
,
72 const void *buf
, size_t len
)
74 qtest_memwrite(bus
->qts
, addr
, buf
, len
);
77 static uint8_t qpci_pc_config_readb(QPCIBus
*bus
, int devfn
, uint8_t offset
)
79 qtest_outl(bus
->qts
, 0xcf8, (1U << 31) | (devfn
<< 8) | offset
);
80 return qtest_inb(bus
->qts
, 0xcfc);
83 static uint16_t qpci_pc_config_readw(QPCIBus
*bus
, int devfn
, uint8_t offset
)
85 qtest_outl(bus
->qts
, 0xcf8, (1U << 31) | (devfn
<< 8) | offset
);
86 return qtest_inw(bus
->qts
, 0xcfc);
89 static uint32_t qpci_pc_config_readl(QPCIBus
*bus
, int devfn
, uint8_t offset
)
91 qtest_outl(bus
->qts
, 0xcf8, (1U << 31) | (devfn
<< 8) | offset
);
92 return qtest_inl(bus
->qts
, 0xcfc);
95 static void qpci_pc_config_writeb(QPCIBus
*bus
, int devfn
, uint8_t offset
, uint8_t value
)
97 qtest_outl(bus
->qts
, 0xcf8, (1U << 31) | (devfn
<< 8) | offset
);
98 qtest_outb(bus
->qts
, 0xcfc, value
);
101 static void qpci_pc_config_writew(QPCIBus
*bus
, int devfn
, uint8_t offset
, uint16_t value
)
103 qtest_outl(bus
->qts
, 0xcf8, (1U << 31) | (devfn
<< 8) | offset
);
104 qtest_outw(bus
->qts
, 0xcfc, value
);
107 static void qpci_pc_config_writel(QPCIBus
*bus
, int devfn
, uint8_t offset
, uint32_t value
)
109 qtest_outl(bus
->qts
, 0xcf8, (1U << 31) | (devfn
<< 8) | offset
);
110 qtest_outl(bus
->qts
, 0xcfc, value
);
113 static void *qpci_pc_get_driver(void *obj
, const char *interface
)
115 QPCIBusPC
*qpci
= obj
;
116 if (!g_strcmp0(interface
, "pci-bus")) {
119 fprintf(stderr
, "%s not present in pci-bus-pc\n", interface
);
120 g_assert_not_reached();
123 void qpci_init_pc(QPCIBusPC
*qpci
, QTestState
*qts
, QGuestAllocator
*alloc
)
127 /* tests can use pci-bus */
128 qpci
->bus
.has_buggy_msi
= false;
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
;
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
;
140 qpci
->bus
.memread
= qpci_pc_memread
;
141 qpci
->bus
.memwrite
= qpci_pc_memwrite
;
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
;
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
;
152 qpci
->bus
.pio_alloc_ptr
= 0xc000;
153 qpci
->bus
.mmio_alloc_ptr
= 0xE0000000;
154 qpci
->bus
.mmio_limit
= 0x100000000ULL
;
156 qpci
->obj
.get_driver
= qpci_pc_get_driver
;
159 QPCIBus
*qpci_new_pc(QTestState
*qts
, QGuestAllocator
*alloc
)
161 QPCIBusPC
*qpci
= g_new0(QPCIBusPC
, 1);
162 qpci_init_pc(qpci
, qts
, alloc
);
167 void qpci_free_pc(QPCIBus
*bus
)
174 s
= container_of(bus
, QPCIBusPC
, bus
);
179 void qpci_unplug_acpi_device_test(QTestState
*qts
, const char *id
, uint8_t slot
)
183 response
= qtest_qmp(qts
, "{'execute': 'device_del',"
184 " 'arguments': {'id': %s}}", id
);
186 g_assert(!qdict_haskey(response
, "error"));
187 qobject_unref(response
);
189 qtest_outl(qts
, ACPI_PCIHP_ADDR
+ PCI_EJ_BASE
, 1 << slot
);
191 qtest_qmp_eventwait(qts
, "DEVICE_DELETED");
194 static void qpci_pc_register_nodes(void)
196 qos_node_create_driver("pci-bus-pc", NULL
);
197 qos_node_produces("pci-bus-pc", "pci-bus");
200 libqos_init(qpci_pc_register_nodes
);