]> git.proxmox.com Git - mirror_qemu.git/blame - tests/libqos/pci-pc.c
libqos: Handle PCI IO de-multiplexing in common code
[mirror_qemu.git] / tests / libqos / pci-pc.c
CommitLineData
c4efe1ca
AL
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
681c28a3 13#include "qemu/osdep.h"
c4efe1ca
AL
14#include "libqtest.h"
15#include "libqos/pci-pc.h"
16
17#include "hw/pci/pci_regs.h"
18
19#include "qemu-common.h"
20#include "qemu/host-utils.h"
21
c4efe1ca 22
2f8b2767
IM
23#define ACPI_PCIHP_ADDR 0xae00
24#define PCI_EJ_BASE 0x0008
25
c4efe1ca
AL
26typedef struct QPCIBusPC
27{
28 QPCIBus bus;
29
30 uint32_t pci_hole_start;
31 uint32_t pci_hole_size;
32 uint32_t pci_hole_alloc;
33
34 uint16_t pci_iohole_start;
35 uint16_t pci_iohole_size;
36 uint16_t pci_iohole_alloc;
37} QPCIBusPC;
38
a795fc08 39static uint8_t qpci_pc_pio_readb(QPCIBus *bus, uint32_t addr)
c4efe1ca 40{
a795fc08 41 return inb(addr);
c4efe1ca
AL
42}
43
a795fc08 44static uint8_t qpci_pc_mmio_readb(QPCIBus *bus, uint32_t addr)
c4efe1ca 45{
a795fc08
DG
46 return readb(addr);
47}
c4efe1ca 48
a795fc08
DG
49static void qpci_pc_pio_writeb(QPCIBus *bus, uint32_t addr, uint8_t val)
50{
51 outb(addr, val);
c4efe1ca
AL
52}
53
a795fc08 54static void qpci_pc_mmio_writeb(QPCIBus *bus, uint32_t addr, uint8_t val)
c4efe1ca 55{
a795fc08
DG
56 writeb(addr, val);
57}
c4efe1ca 58
a795fc08
DG
59static uint16_t qpci_pc_pio_readw(QPCIBus *bus, uint32_t addr)
60{
61 return inw(addr);
62}
c4efe1ca 63
a795fc08
DG
64static uint16_t qpci_pc_mmio_readw(QPCIBus *bus, uint32_t addr)
65{
66 return readw(addr);
c4efe1ca
AL
67}
68
a795fc08 69static void qpci_pc_pio_writew(QPCIBus *bus, uint32_t addr, uint16_t val)
c4efe1ca 70{
a795fc08
DG
71 outw(addr, val);
72}
c4efe1ca 73
a795fc08
DG
74static void qpci_pc_mmio_writew(QPCIBus *bus, uint32_t addr, uint16_t val)
75{
76 writew(addr, val);
c4efe1ca
AL
77}
78
a795fc08 79static uint32_t qpci_pc_pio_readl(QPCIBus *bus, uint32_t addr)
c4efe1ca 80{
a795fc08
DG
81 return inl(addr);
82}
c4efe1ca 83
a795fc08
DG
84static uint32_t qpci_pc_mmio_readl(QPCIBus *bus, uint32_t addr)
85{
86 return readl(addr);
c4efe1ca
AL
87}
88
a795fc08 89static void qpci_pc_pio_writel(QPCIBus *bus, uint32_t addr, uint32_t val)
c4efe1ca 90{
a795fc08
DG
91 outl(addr, val);
92}
c4efe1ca 93
a795fc08
DG
94static void qpci_pc_mmio_writel(QPCIBus *bus, uint32_t addr, uint32_t val)
95{
96 writel(addr, val);
c4efe1ca
AL
97}
98
99static uint8_t qpci_pc_config_readb(QPCIBus *bus, int devfn, uint8_t offset)
100{
a879125b 101 outl(0xcf8, (1U << 31) | (devfn << 8) | offset);
c4efe1ca
AL
102 return inb(0xcfc);
103}
104
105static uint16_t qpci_pc_config_readw(QPCIBus *bus, int devfn, uint8_t offset)
106{
a879125b 107 outl(0xcf8, (1U << 31) | (devfn << 8) | offset);
c4efe1ca
AL
108 return inw(0xcfc);
109}
110
111static uint32_t qpci_pc_config_readl(QPCIBus *bus, int devfn, uint8_t offset)
112{
a879125b 113 outl(0xcf8, (1U << 31) | (devfn << 8) | offset);
c4efe1ca
AL
114 return inl(0xcfc);
115}
116
117static void qpci_pc_config_writeb(QPCIBus *bus, int devfn, uint8_t offset, uint8_t value)
118{
a879125b 119 outl(0xcf8, (1U << 31) | (devfn << 8) | offset);
c4efe1ca
AL
120 outb(0xcfc, value);
121}
122
123static void qpci_pc_config_writew(QPCIBus *bus, int devfn, uint8_t offset, uint16_t value)
124{
a879125b 125 outl(0xcf8, (1U << 31) | (devfn << 8) | offset);
c4efe1ca
AL
126 outw(0xcfc, value);
127}
128
129static void qpci_pc_config_writel(QPCIBus *bus, int devfn, uint8_t offset, uint32_t value)
130{
a879125b 131 outl(0xcf8, (1U << 31) | (devfn << 8) | offset);
c4efe1ca
AL
132 outl(0xcfc, value);
133}
134
6ce7100e 135static void *qpci_pc_iomap(QPCIBus *bus, QPCIDevice *dev, int barno, uint64_t *sizeptr)
c4efe1ca
AL
136{
137 QPCIBusPC *s = container_of(bus, QPCIBusPC, bus);
138 static const int bar_reg_map[] = {
139 PCI_BASE_ADDRESS_0, PCI_BASE_ADDRESS_1, PCI_BASE_ADDRESS_2,
140 PCI_BASE_ADDRESS_3, PCI_BASE_ADDRESS_4, PCI_BASE_ADDRESS_5,
141 };
142 int bar_reg;
143 uint32_t addr;
144 uint64_t size;
145 uint32_t io_type;
146
147 g_assert(barno >= 0 && barno <= 5);
148 bar_reg = bar_reg_map[barno];
149
150 qpci_config_writel(dev, bar_reg, 0xFFFFFFFF);
151 addr = qpci_config_readl(dev, bar_reg);
152
153 io_type = addr & PCI_BASE_ADDRESS_SPACE;
154 if (io_type == PCI_BASE_ADDRESS_SPACE_IO) {
155 addr &= PCI_BASE_ADDRESS_IO_MASK;
156 } else {
157 addr &= PCI_BASE_ADDRESS_MEM_MASK;
158 }
159
160 size = (1ULL << ctzl(addr));
161 if (size == 0) {
162 return NULL;
163 }
6ce7100e
JS
164 if (sizeptr) {
165 *sizeptr = size;
166 }
c4efe1ca
AL
167
168 if (io_type == PCI_BASE_ADDRESS_SPACE_IO) {
169 uint16_t loc;
170
99826172
MA
171 g_assert(QEMU_ALIGN_UP(s->pci_iohole_alloc, size) + size
172 <= s->pci_iohole_size);
173 s->pci_iohole_alloc = QEMU_ALIGN_UP(s->pci_iohole_alloc, size);
c4efe1ca
AL
174 loc = s->pci_iohole_start + s->pci_iohole_alloc;
175 s->pci_iohole_alloc += size;
176
177 qpci_config_writel(dev, bar_reg, loc | PCI_BASE_ADDRESS_SPACE_IO);
178
179 return (void *)(intptr_t)loc;
180 } else {
181 uint64_t loc;
182
99826172
MA
183 g_assert(QEMU_ALIGN_UP(s->pci_hole_alloc, size) + size
184 <= s->pci_hole_size);
185 s->pci_hole_alloc = QEMU_ALIGN_UP(s->pci_hole_alloc, size);
c4efe1ca
AL
186 loc = s->pci_hole_start + s->pci_hole_alloc;
187 s->pci_hole_alloc += size;
188
189 qpci_config_writel(dev, bar_reg, loc);
190
191 return (void *)(intptr_t)loc;
192 }
193}
194
195static void qpci_pc_iounmap(QPCIBus *bus, void *data)
196{
197 /* FIXME */
198}
199
2ecd7e2f 200QPCIBus *qpci_init_pc(QGuestAllocator *alloc)
c4efe1ca
AL
201{
202 QPCIBusPC *ret;
203
204 ret = g_malloc(sizeof(*ret));
205
a795fc08
DG
206 ret->bus.pio_readb = qpci_pc_pio_readb;
207 ret->bus.pio_readw = qpci_pc_pio_readw;
208 ret->bus.pio_readl = qpci_pc_pio_readl;
209
210 ret->bus.pio_writeb = qpci_pc_pio_writeb;
211 ret->bus.pio_writew = qpci_pc_pio_writew;
212 ret->bus.pio_writel = qpci_pc_pio_writel;
213
214 ret->bus.mmio_readb = qpci_pc_mmio_readb;
215 ret->bus.mmio_readw = qpci_pc_mmio_readw;
216 ret->bus.mmio_readl = qpci_pc_mmio_readl;
c4efe1ca 217
a795fc08
DG
218 ret->bus.mmio_writeb = qpci_pc_mmio_writeb;
219 ret->bus.mmio_writew = qpci_pc_mmio_writew;
220 ret->bus.mmio_writel = qpci_pc_mmio_writel;
c4efe1ca
AL
221
222 ret->bus.config_readb = qpci_pc_config_readb;
223 ret->bus.config_readw = qpci_pc_config_readw;
224 ret->bus.config_readl = qpci_pc_config_readl;
225
226 ret->bus.config_writeb = qpci_pc_config_writeb;
227 ret->bus.config_writew = qpci_pc_config_writew;
228 ret->bus.config_writel = qpci_pc_config_writel;
229
230 ret->bus.iomap = qpci_pc_iomap;
231 ret->bus.iounmap = qpci_pc_iounmap;
232
233 ret->pci_hole_start = 0xE0000000;
234 ret->pci_hole_size = 0x20000000;
235 ret->pci_hole_alloc = 0;
236
237 ret->pci_iohole_start = 0xc000;
238 ret->pci_iohole_size = 0x4000;
239 ret->pci_iohole_alloc = 0;
240
241 return &ret->bus;
242}
7f2a5ae6
JS
243
244void qpci_free_pc(QPCIBus *bus)
245{
246 QPCIBusPC *s = container_of(bus, QPCIBusPC, bus);
247
248 g_free(s);
249}
2f8b2767 250
2f8b2767
IM
251void qpci_unplug_acpi_device_test(const char *id, uint8_t slot)
252{
253 QDict *response;
254 char *cmd;
255
256 cmd = g_strdup_printf("{'execute': 'device_del',"
257 " 'arguments': {"
258 " 'id': '%s'"
259 "}}", id);
260 response = qmp(cmd);
261 g_free(cmd);
262 g_assert(response);
263 g_assert(!qdict_haskey(response, "error"));
264 QDECREF(response);
265
266 outb(ACPI_PCIHP_ADDR + PCI_EJ_BASE, 1 << slot);
267
268 response = qmp("");
269 g_assert(response);
270 g_assert(qdict_haskey(response, "event"));
271 g_assert(!strcmp(qdict_get_str(response, "event"), "DEVICE_DELETED"));
272 QDECREF(response);
273}