]>
Commit | Line | Data |
---|---|---|
c4efe1ca AL |
1 | /* |
2 | * libqos PCI bindings for PC | |
3 | * | |
4 | * Copyright IBM, Corp. 2012-2013 | |
5 | * | |
6 | * Authors: | |
7 | * Anthony Liguori <[email protected]> | |
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" | |
c4efe1ca | 20 | |
c4efe1ca | 21 | |
2f8b2767 IM |
22 | #define ACPI_PCIHP_ADDR 0xae00 |
23 | #define PCI_EJ_BASE 0x0008 | |
24 | ||
c4efe1ca AL |
25 | typedef struct QPCIBusPC |
26 | { | |
27 | QPCIBus bus; | |
c4efe1ca AL |
28 | } QPCIBusPC; |
29 | ||
a795fc08 | 30 | static uint8_t qpci_pc_pio_readb(QPCIBus *bus, uint32_t addr) |
c4efe1ca | 31 | { |
a795fc08 | 32 | return inb(addr); |
c4efe1ca AL |
33 | } |
34 | ||
a795fc08 DG |
35 | static void qpci_pc_pio_writeb(QPCIBus *bus, uint32_t addr, uint8_t val) |
36 | { | |
37 | outb(addr, val); | |
c4efe1ca AL |
38 | } |
39 | ||
a795fc08 DG |
40 | static uint16_t qpci_pc_pio_readw(QPCIBus *bus, uint32_t addr) |
41 | { | |
42 | return inw(addr); | |
43 | } | |
c4efe1ca | 44 | |
a795fc08 | 45 | static void qpci_pc_pio_writew(QPCIBus *bus, uint32_t addr, uint16_t val) |
c4efe1ca | 46 | { |
a795fc08 DG |
47 | outw(addr, val); |
48 | } | |
c4efe1ca | 49 | |
a795fc08 | 50 | static uint32_t qpci_pc_pio_readl(QPCIBus *bus, uint32_t addr) |
c4efe1ca | 51 | { |
a795fc08 DG |
52 | return inl(addr); |
53 | } | |
c4efe1ca | 54 | |
a795fc08 | 55 | static void qpci_pc_pio_writel(QPCIBus *bus, uint32_t addr, uint32_t val) |
c4efe1ca | 56 | { |
a795fc08 DG |
57 | outl(addr, val); |
58 | } | |
c4efe1ca | 59 | |
f775f45a DG |
60 | static uint64_t qpci_pc_pio_readq(QPCIBus *bus, uint32_t addr) |
61 | { | |
62 | return (uint64_t)inl(addr) + ((uint64_t)inl(addr + 4) << 32); | |
63 | } | |
64 | ||
65 | static void qpci_pc_pio_writeq(QPCIBus *bus, uint32_t addr, uint64_t val) | |
66 | { | |
67 | outl(addr, val & 0xffffffff); | |
68 | outl(addr + 4, val >> 32); | |
69 | } | |
70 | ||
9a84f889 DG |
71 | static void qpci_pc_memread(QPCIBus *bus, uint32_t addr, void *buf, size_t len) |
72 | { | |
73 | memread(addr, buf, len); | |
74 | } | |
75 | ||
76 | static void qpci_pc_memwrite(QPCIBus *bus, uint32_t addr, | |
77 | const void *buf, size_t len) | |
78 | { | |
79 | memwrite(addr, buf, len); | |
80 | } | |
81 | ||
c4efe1ca AL |
82 | static uint8_t qpci_pc_config_readb(QPCIBus *bus, int devfn, uint8_t offset) |
83 | { | |
a879125b | 84 | outl(0xcf8, (1U << 31) | (devfn << 8) | offset); |
c4efe1ca AL |
85 | return inb(0xcfc); |
86 | } | |
87 | ||
88 | static uint16_t qpci_pc_config_readw(QPCIBus *bus, int devfn, uint8_t offset) | |
89 | { | |
a879125b | 90 | outl(0xcf8, (1U << 31) | (devfn << 8) | offset); |
c4efe1ca AL |
91 | return inw(0xcfc); |
92 | } | |
93 | ||
94 | static uint32_t qpci_pc_config_readl(QPCIBus *bus, int devfn, uint8_t offset) | |
95 | { | |
a879125b | 96 | outl(0xcf8, (1U << 31) | (devfn << 8) | offset); |
c4efe1ca AL |
97 | return inl(0xcfc); |
98 | } | |
99 | ||
100 | static void qpci_pc_config_writeb(QPCIBus *bus, int devfn, uint8_t offset, uint8_t value) | |
101 | { | |
a879125b | 102 | outl(0xcf8, (1U << 31) | (devfn << 8) | offset); |
c4efe1ca AL |
103 | outb(0xcfc, value); |
104 | } | |
105 | ||
106 | static void qpci_pc_config_writew(QPCIBus *bus, int devfn, uint8_t offset, uint16_t value) | |
107 | { | |
a879125b | 108 | outl(0xcf8, (1U << 31) | (devfn << 8) | offset); |
c4efe1ca AL |
109 | outw(0xcfc, value); |
110 | } | |
111 | ||
112 | static void qpci_pc_config_writel(QPCIBus *bus, int devfn, uint8_t offset, uint32_t value) | |
113 | { | |
a879125b | 114 | outl(0xcf8, (1U << 31) | (devfn << 8) | offset); |
c4efe1ca AL |
115 | outl(0xcfc, value); |
116 | } | |
117 | ||
2ecd7e2f | 118 | QPCIBus *qpci_init_pc(QGuestAllocator *alloc) |
c4efe1ca AL |
119 | { |
120 | QPCIBusPC *ret; | |
121 | ||
122 | ret = g_malloc(sizeof(*ret)); | |
123 | ||
a795fc08 DG |
124 | ret->bus.pio_readb = qpci_pc_pio_readb; |
125 | ret->bus.pio_readw = qpci_pc_pio_readw; | |
126 | ret->bus.pio_readl = qpci_pc_pio_readl; | |
f775f45a | 127 | ret->bus.pio_readq = qpci_pc_pio_readq; |
a795fc08 DG |
128 | |
129 | ret->bus.pio_writeb = qpci_pc_pio_writeb; | |
130 | ret->bus.pio_writew = qpci_pc_pio_writew; | |
131 | ret->bus.pio_writel = qpci_pc_pio_writel; | |
f775f45a | 132 | ret->bus.pio_writeq = qpci_pc_pio_writeq; |
a795fc08 | 133 | |
9a84f889 DG |
134 | ret->bus.memread = qpci_pc_memread; |
135 | ret->bus.memwrite = qpci_pc_memwrite; | |
136 | ||
c4efe1ca AL |
137 | ret->bus.config_readb = qpci_pc_config_readb; |
138 | ret->bus.config_readw = qpci_pc_config_readw; | |
139 | ret->bus.config_readl = qpci_pc_config_readl; | |
140 | ||
141 | ret->bus.config_writeb = qpci_pc_config_writeb; | |
142 | ret->bus.config_writew = qpci_pc_config_writew; | |
143 | ret->bus.config_writel = qpci_pc_config_writel; | |
144 | ||
b8cc4d02 DG |
145 | ret->bus.pio_alloc_ptr = 0xc000; |
146 | ret->bus.mmio_alloc_ptr = 0xE0000000; | |
147 | ret->bus.mmio_limit = 0x100000000ULL; | |
c4efe1ca AL |
148 | |
149 | return &ret->bus; | |
150 | } | |
7f2a5ae6 JS |
151 | |
152 | void qpci_free_pc(QPCIBus *bus) | |
153 | { | |
154 | QPCIBusPC *s = container_of(bus, QPCIBusPC, bus); | |
155 | ||
156 | g_free(s); | |
157 | } | |
2f8b2767 | 158 | |
2f8b2767 IM |
159 | void qpci_unplug_acpi_device_test(const char *id, uint8_t slot) |
160 | { | |
161 | QDict *response; | |
162 | char *cmd; | |
163 | ||
164 | cmd = g_strdup_printf("{'execute': 'device_del'," | |
165 | " 'arguments': {" | |
166 | " 'id': '%s'" | |
167 | "}}", id); | |
168 | response = qmp(cmd); | |
169 | g_free(cmd); | |
170 | g_assert(response); | |
171 | g_assert(!qdict_haskey(response, "error")); | |
172 | QDECREF(response); | |
173 | ||
174 | outb(ACPI_PCIHP_ADDR + PCI_EJ_BASE, 1 << slot); | |
175 | ||
176 | response = qmp(""); | |
177 | g_assert(response); | |
178 | g_assert(qdict_haskey(response, "event")); | |
179 | g_assert(!strcmp(qdict_get_str(response, "event"), "DEVICE_DELETED")); | |
180 | QDECREF(response); | |
181 | } |