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"
15 #include "libqos/pci-pc.h"
17 #include "hw/pci/pci_regs.h"
19 #include "qemu-common.h"
20 #include "qemu/host-utils.h"
23 #define ACPI_PCIHP_ADDR 0xae00
24 #define PCI_EJ_BASE 0x0008
26 typedef struct QPCIBusPC
30 uint32_t pci_hole_start
;
31 uint32_t pci_hole_size
;
32 uint32_t pci_hole_alloc
;
34 uint16_t pci_iohole_start
;
35 uint16_t pci_iohole_size
;
36 uint16_t pci_iohole_alloc
;
39 static uint8_t qpci_pc_io_readb(QPCIBus
*bus
, void *addr
)
41 uintptr_t port
= (uintptr_t)addr
;
53 static uint16_t qpci_pc_io_readw(QPCIBus
*bus
, void *addr
)
55 uintptr_t port
= (uintptr_t)addr
;
67 static uint32_t qpci_pc_io_readl(QPCIBus
*bus
, void *addr
)
69 uintptr_t port
= (uintptr_t)addr
;
81 static void qpci_pc_io_writeb(QPCIBus
*bus
, void *addr
, uint8_t value
)
83 uintptr_t port
= (uintptr_t)addr
;
92 static void qpci_pc_io_writew(QPCIBus
*bus
, void *addr
, uint16_t value
)
94 uintptr_t port
= (uintptr_t)addr
;
103 static void qpci_pc_io_writel(QPCIBus
*bus
, void *addr
, uint32_t value
)
105 uintptr_t port
= (uintptr_t)addr
;
107 if (port
< 0x10000) {
114 static uint8_t qpci_pc_config_readb(QPCIBus
*bus
, int devfn
, uint8_t offset
)
116 outl(0xcf8, (1U << 31) | (devfn
<< 8) | offset
);
120 static uint16_t qpci_pc_config_readw(QPCIBus
*bus
, int devfn
, uint8_t offset
)
122 outl(0xcf8, (1U << 31) | (devfn
<< 8) | offset
);
126 static uint32_t qpci_pc_config_readl(QPCIBus
*bus
, int devfn
, uint8_t offset
)
128 outl(0xcf8, (1U << 31) | (devfn
<< 8) | offset
);
132 static void qpci_pc_config_writeb(QPCIBus
*bus
, int devfn
, uint8_t offset
, uint8_t value
)
134 outl(0xcf8, (1U << 31) | (devfn
<< 8) | offset
);
138 static void qpci_pc_config_writew(QPCIBus
*bus
, int devfn
, uint8_t offset
, uint16_t value
)
140 outl(0xcf8, (1U << 31) | (devfn
<< 8) | offset
);
144 static void qpci_pc_config_writel(QPCIBus
*bus
, int devfn
, uint8_t offset
, uint32_t value
)
146 outl(0xcf8, (1U << 31) | (devfn
<< 8) | offset
);
150 static void *qpci_pc_iomap(QPCIBus
*bus
, QPCIDevice
*dev
, int barno
, uint64_t *sizeptr
)
152 QPCIBusPC
*s
= container_of(bus
, QPCIBusPC
, bus
);
153 static const int bar_reg_map
[] = {
154 PCI_BASE_ADDRESS_0
, PCI_BASE_ADDRESS_1
, PCI_BASE_ADDRESS_2
,
155 PCI_BASE_ADDRESS_3
, PCI_BASE_ADDRESS_4
, PCI_BASE_ADDRESS_5
,
162 g_assert(barno
>= 0 && barno
<= 5);
163 bar_reg
= bar_reg_map
[barno
];
165 qpci_config_writel(dev
, bar_reg
, 0xFFFFFFFF);
166 addr
= qpci_config_readl(dev
, bar_reg
);
168 io_type
= addr
& PCI_BASE_ADDRESS_SPACE
;
169 if (io_type
== PCI_BASE_ADDRESS_SPACE_IO
) {
170 addr
&= PCI_BASE_ADDRESS_IO_MASK
;
172 addr
&= PCI_BASE_ADDRESS_MEM_MASK
;
175 size
= (1ULL << ctzl(addr
));
183 if (io_type
== PCI_BASE_ADDRESS_SPACE_IO
) {
186 g_assert(QEMU_ALIGN_UP(s
->pci_iohole_alloc
, size
) + size
187 <= s
->pci_iohole_size
);
188 s
->pci_iohole_alloc
= QEMU_ALIGN_UP(s
->pci_iohole_alloc
, size
);
189 loc
= s
->pci_iohole_start
+ s
->pci_iohole_alloc
;
190 s
->pci_iohole_alloc
+= size
;
192 qpci_config_writel(dev
, bar_reg
, loc
| PCI_BASE_ADDRESS_SPACE_IO
);
194 return (void *)(intptr_t)loc
;
198 g_assert(QEMU_ALIGN_UP(s
->pci_hole_alloc
, size
) + size
199 <= s
->pci_hole_size
);
200 s
->pci_hole_alloc
= QEMU_ALIGN_UP(s
->pci_hole_alloc
, size
);
201 loc
= s
->pci_hole_start
+ s
->pci_hole_alloc
;
202 s
->pci_hole_alloc
+= size
;
204 qpci_config_writel(dev
, bar_reg
, loc
);
206 return (void *)(intptr_t)loc
;
210 static void qpci_pc_iounmap(QPCIBus
*bus
, void *data
)
215 QPCIBus
*qpci_init_pc(void)
219 ret
= g_malloc(sizeof(*ret
));
221 ret
->bus
.io_readb
= qpci_pc_io_readb
;
222 ret
->bus
.io_readw
= qpci_pc_io_readw
;
223 ret
->bus
.io_readl
= qpci_pc_io_readl
;
225 ret
->bus
.io_writeb
= qpci_pc_io_writeb
;
226 ret
->bus
.io_writew
= qpci_pc_io_writew
;
227 ret
->bus
.io_writel
= qpci_pc_io_writel
;
229 ret
->bus
.config_readb
= qpci_pc_config_readb
;
230 ret
->bus
.config_readw
= qpci_pc_config_readw
;
231 ret
->bus
.config_readl
= qpci_pc_config_readl
;
233 ret
->bus
.config_writeb
= qpci_pc_config_writeb
;
234 ret
->bus
.config_writew
= qpci_pc_config_writew
;
235 ret
->bus
.config_writel
= qpci_pc_config_writel
;
237 ret
->bus
.iomap
= qpci_pc_iomap
;
238 ret
->bus
.iounmap
= qpci_pc_iounmap
;
240 ret
->pci_hole_start
= 0xE0000000;
241 ret
->pci_hole_size
= 0x20000000;
242 ret
->pci_hole_alloc
= 0;
244 ret
->pci_iohole_start
= 0xc000;
245 ret
->pci_iohole_size
= 0x4000;
246 ret
->pci_iohole_alloc
= 0;
251 void qpci_free_pc(QPCIBus
*bus
)
253 QPCIBusPC
*s
= container_of(bus
, QPCIBusPC
, bus
);
258 void qpci_plug_device_test(const char *driver
, const char *id
,
259 uint8_t slot
, const char *opts
)
264 cmd
= g_strdup_printf("{'execute': 'device_add',"
271 opts
? opts
: "", opts
? "," : "",
276 g_assert(!qdict_haskey(response
, "error"));
280 void qpci_unplug_acpi_device_test(const char *id
, uint8_t slot
)
285 cmd
= g_strdup_printf("{'execute': 'device_del',"
292 g_assert(!qdict_haskey(response
, "error"));
295 outb(ACPI_PCIHP_ADDR
+ PCI_EJ_BASE
, 1 << slot
);
299 g_assert(qdict_haskey(response
, "event"));
300 g_assert(!strcmp(qdict_get_str(response
, "event"), "DEVICE_DELETED"));