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"
24 #define ACPI_PCIHP_ADDR 0xae00
25 #define PCI_EJ_BASE 0x0008
27 typedef struct QPCIBusPC
31 uint32_t pci_hole_start
;
32 uint32_t pci_hole_size
;
33 uint32_t pci_hole_alloc
;
35 uint16_t pci_iohole_start
;
36 uint16_t pci_iohole_size
;
37 uint16_t pci_iohole_alloc
;
40 static uint8_t qpci_pc_io_readb(QPCIBus
*bus
, void *addr
)
42 uintptr_t port
= (uintptr_t)addr
;
54 static uint16_t qpci_pc_io_readw(QPCIBus
*bus
, void *addr
)
56 uintptr_t port
= (uintptr_t)addr
;
68 static uint32_t qpci_pc_io_readl(QPCIBus
*bus
, void *addr
)
70 uintptr_t port
= (uintptr_t)addr
;
82 static void qpci_pc_io_writeb(QPCIBus
*bus
, void *addr
, uint8_t value
)
84 uintptr_t port
= (uintptr_t)addr
;
93 static void qpci_pc_io_writew(QPCIBus
*bus
, void *addr
, uint16_t value
)
95 uintptr_t port
= (uintptr_t)addr
;
104 static void qpci_pc_io_writel(QPCIBus
*bus
, void *addr
, uint32_t value
)
106 uintptr_t port
= (uintptr_t)addr
;
108 if (port
< 0x10000) {
115 static uint8_t qpci_pc_config_readb(QPCIBus
*bus
, int devfn
, uint8_t offset
)
117 outl(0xcf8, (1U << 31) | (devfn
<< 8) | offset
);
121 static uint16_t qpci_pc_config_readw(QPCIBus
*bus
, int devfn
, uint8_t offset
)
123 outl(0xcf8, (1U << 31) | (devfn
<< 8) | offset
);
127 static uint32_t qpci_pc_config_readl(QPCIBus
*bus
, int devfn
, uint8_t offset
)
129 outl(0xcf8, (1U << 31) | (devfn
<< 8) | offset
);
133 static void qpci_pc_config_writeb(QPCIBus
*bus
, int devfn
, uint8_t offset
, uint8_t value
)
135 outl(0xcf8, (1U << 31) | (devfn
<< 8) | offset
);
139 static void qpci_pc_config_writew(QPCIBus
*bus
, int devfn
, uint8_t offset
, uint16_t value
)
141 outl(0xcf8, (1U << 31) | (devfn
<< 8) | offset
);
145 static void qpci_pc_config_writel(QPCIBus
*bus
, int devfn
, uint8_t offset
, uint32_t value
)
147 outl(0xcf8, (1U << 31) | (devfn
<< 8) | offset
);
151 static void *qpci_pc_iomap(QPCIBus
*bus
, QPCIDevice
*dev
, int barno
, uint64_t *sizeptr
)
153 QPCIBusPC
*s
= container_of(bus
, QPCIBusPC
, bus
);
154 static const int bar_reg_map
[] = {
155 PCI_BASE_ADDRESS_0
, PCI_BASE_ADDRESS_1
, PCI_BASE_ADDRESS_2
,
156 PCI_BASE_ADDRESS_3
, PCI_BASE_ADDRESS_4
, PCI_BASE_ADDRESS_5
,
163 g_assert(barno
>= 0 && barno
<= 5);
164 bar_reg
= bar_reg_map
[barno
];
166 qpci_config_writel(dev
, bar_reg
, 0xFFFFFFFF);
167 addr
= qpci_config_readl(dev
, bar_reg
);
169 io_type
= addr
& PCI_BASE_ADDRESS_SPACE
;
170 if (io_type
== PCI_BASE_ADDRESS_SPACE_IO
) {
171 addr
&= PCI_BASE_ADDRESS_IO_MASK
;
173 addr
&= PCI_BASE_ADDRESS_MEM_MASK
;
176 size
= (1ULL << ctzl(addr
));
184 if (io_type
== PCI_BASE_ADDRESS_SPACE_IO
) {
187 g_assert(QEMU_ALIGN_UP(s
->pci_iohole_alloc
, size
) + size
188 <= s
->pci_iohole_size
);
189 s
->pci_iohole_alloc
= QEMU_ALIGN_UP(s
->pci_iohole_alloc
, size
);
190 loc
= s
->pci_iohole_start
+ s
->pci_iohole_alloc
;
191 s
->pci_iohole_alloc
+= size
;
193 qpci_config_writel(dev
, bar_reg
, loc
| PCI_BASE_ADDRESS_SPACE_IO
);
195 return (void *)(intptr_t)loc
;
199 g_assert(QEMU_ALIGN_UP(s
->pci_hole_alloc
, size
) + size
200 <= s
->pci_hole_size
);
201 s
->pci_hole_alloc
= QEMU_ALIGN_UP(s
->pci_hole_alloc
, size
);
202 loc
= s
->pci_hole_start
+ s
->pci_hole_alloc
;
203 s
->pci_hole_alloc
+= size
;
205 qpci_config_writel(dev
, bar_reg
, loc
);
207 return (void *)(intptr_t)loc
;
211 static void qpci_pc_iounmap(QPCIBus
*bus
, void *data
)
216 QPCIBus
*qpci_init_pc(void)
220 ret
= g_malloc(sizeof(*ret
));
222 ret
->bus
.io_readb
= qpci_pc_io_readb
;
223 ret
->bus
.io_readw
= qpci_pc_io_readw
;
224 ret
->bus
.io_readl
= qpci_pc_io_readl
;
226 ret
->bus
.io_writeb
= qpci_pc_io_writeb
;
227 ret
->bus
.io_writew
= qpci_pc_io_writew
;
228 ret
->bus
.io_writel
= qpci_pc_io_writel
;
230 ret
->bus
.config_readb
= qpci_pc_config_readb
;
231 ret
->bus
.config_readw
= qpci_pc_config_readw
;
232 ret
->bus
.config_readl
= qpci_pc_config_readl
;
234 ret
->bus
.config_writeb
= qpci_pc_config_writeb
;
235 ret
->bus
.config_writew
= qpci_pc_config_writew
;
236 ret
->bus
.config_writel
= qpci_pc_config_writel
;
238 ret
->bus
.iomap
= qpci_pc_iomap
;
239 ret
->bus
.iounmap
= qpci_pc_iounmap
;
241 ret
->pci_hole_start
= 0xE0000000;
242 ret
->pci_hole_size
= 0x20000000;
243 ret
->pci_hole_alloc
= 0;
245 ret
->pci_iohole_start
= 0xc000;
246 ret
->pci_iohole_size
= 0x4000;
247 ret
->pci_iohole_alloc
= 0;
252 void qpci_free_pc(QPCIBus
*bus
)
254 QPCIBusPC
*s
= container_of(bus
, QPCIBusPC
, bus
);
259 void qpci_plug_device_test(const char *driver
, const char *id
,
260 uint8_t slot
, const char *opts
)
265 cmd
= g_strdup_printf("{'execute': 'device_add',"
272 opts
? opts
: "", opts
? "," : "",
277 g_assert(!qdict_haskey(response
, "error"));
281 void qpci_unplug_acpi_device_test(const char *id
, uint8_t slot
)
286 cmd
= g_strdup_printf("{'execute': 'device_del',"
293 g_assert(!qdict_haskey(response
, "error"));
296 outb(ACPI_PCIHP_ADDR
+ PCI_EJ_BASE
, 1 << slot
);
300 g_assert(qdict_haskey(response
, "event"));
301 g_assert(!strcmp(qdict_get_str(response
, "event"), "DEVICE_DELETED"));