]> git.proxmox.com Git - mirror_qemu.git/blob - tests/libqos/pci-spapr.c
virtio-balloon: convert VMSTATE_VIRTIO_DEVICE
[mirror_qemu.git] / tests / libqos / pci-spapr.c
1 /*
2 * libqos PCI bindings for SPAPR
3 *
4 * This work is licensed under the terms of the GNU GPL, version 2 or later.
5 * See the COPYING file in the top-level directory.
6 */
7
8 #include "qemu/osdep.h"
9 #include "libqtest.h"
10 #include "libqos/pci-spapr.h"
11 #include "libqos/rtas.h"
12
13 #include "hw/pci/pci_regs.h"
14
15 #include "qemu-common.h"
16 #include "qemu/host-utils.h"
17
18
19 /* From include/hw/pci-host/spapr.h */
20
21 #define SPAPR_PCI_BASE_BUID 0x800000020000000ULL
22
23 #define SPAPR_PCI_MEM_WIN_BUS_OFFSET 0x80000000ULL
24
25 #define SPAPR_PCI_WINDOW_BASE 0x10000000000ULL
26 #define SPAPR_PCI_WINDOW_SPACING 0x1000000000ULL
27 #define SPAPR_PCI_MMIO_WIN_OFF 0xA0000000
28 #define SPAPR_PCI_MMIO_WIN_SIZE (SPAPR_PCI_WINDOW_SPACING - \
29 SPAPR_PCI_MEM_WIN_BUS_OFFSET)
30 #define SPAPR_PCI_IO_WIN_OFF 0x80000000
31 #define SPAPR_PCI_IO_WIN_SIZE 0x10000
32
33 /* index is the phb index */
34
35 #define BUIDBASE(index) (SPAPR_PCI_BASE_BUID + (index))
36 #define PCIBASE(index) (SPAPR_PCI_WINDOW_BASE + \
37 (index) * SPAPR_PCI_WINDOW_SPACING)
38 #define IOBASE(index) (PCIBASE(index) + SPAPR_PCI_IO_WIN_OFF)
39 #define MMIOBASE(index) (PCIBASE(index) + SPAPR_PCI_MMIO_WIN_OFF)
40
41 typedef struct QPCIBusSPAPR {
42 QPCIBus bus;
43 QGuestAllocator *alloc;
44
45 uint64_t pci_hole_start;
46 uint64_t pci_hole_size;
47 uint64_t pci_hole_alloc;
48
49 uint32_t pci_iohole_start;
50 uint32_t pci_iohole_size;
51 uint32_t pci_iohole_alloc;
52 } QPCIBusSPAPR;
53
54 /*
55 * PCI devices are always little-endian
56 * SPAPR by default is big-endian
57 * so PCI accessors need to swap data endianness
58 */
59
60 static uint8_t qpci_spapr_io_readb(QPCIBus *bus, void *addr)
61 {
62 uint64_t port = (uintptr_t)addr;
63 uint8_t v;
64 if (port < SPAPR_PCI_IO_WIN_SIZE) {
65 v = readb(IOBASE(0) + port);
66 } else {
67 v = readb(MMIOBASE(0) + port);
68 }
69 return v;
70 }
71
72 static uint16_t qpci_spapr_io_readw(QPCIBus *bus, void *addr)
73 {
74 uint64_t port = (uintptr_t)addr;
75 uint16_t v;
76 if (port < SPAPR_PCI_IO_WIN_SIZE) {
77 v = readw(IOBASE(0) + port);
78 } else {
79 v = readw(MMIOBASE(0) + port);
80 }
81 return bswap16(v);
82 }
83
84 static uint32_t qpci_spapr_io_readl(QPCIBus *bus, void *addr)
85 {
86 uint64_t port = (uintptr_t)addr;
87 uint32_t v;
88 if (port < SPAPR_PCI_IO_WIN_SIZE) {
89 v = readl(IOBASE(0) + port);
90 } else {
91 v = readl(MMIOBASE(0) + port);
92 }
93 return bswap32(v);
94 }
95
96 static void qpci_spapr_io_writeb(QPCIBus *bus, void *addr, uint8_t value)
97 {
98 uint64_t port = (uintptr_t)addr;
99 if (port < SPAPR_PCI_IO_WIN_SIZE) {
100 writeb(IOBASE(0) + port, value);
101 } else {
102 writeb(MMIOBASE(0) + port, value);
103 }
104 }
105
106 static void qpci_spapr_io_writew(QPCIBus *bus, void *addr, uint16_t value)
107 {
108 uint64_t port = (uintptr_t)addr;
109 value = bswap16(value);
110 if (port < SPAPR_PCI_IO_WIN_SIZE) {
111 writew(IOBASE(0) + port, value);
112 } else {
113 writew(MMIOBASE(0) + port, value);
114 }
115 }
116
117 static void qpci_spapr_io_writel(QPCIBus *bus, void *addr, uint32_t value)
118 {
119 uint64_t port = (uintptr_t)addr;
120 value = bswap32(value);
121 if (port < SPAPR_PCI_IO_WIN_SIZE) {
122 writel(IOBASE(0) + port, value);
123 } else {
124 writel(MMIOBASE(0) + port, value);
125 }
126 }
127
128 static uint8_t qpci_spapr_config_readb(QPCIBus *bus, int devfn, uint8_t offset)
129 {
130 QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus);
131 uint32_t config_addr = (devfn << 8) | offset;
132 return qrtas_ibm_read_pci_config(s->alloc, BUIDBASE(0),
133 config_addr, 1);
134 }
135
136 static uint16_t qpci_spapr_config_readw(QPCIBus *bus, int devfn, uint8_t offset)
137 {
138 QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus);
139 uint32_t config_addr = (devfn << 8) | offset;
140 return qrtas_ibm_read_pci_config(s->alloc, BUIDBASE(0),
141 config_addr, 2);
142 }
143
144 static uint32_t qpci_spapr_config_readl(QPCIBus *bus, int devfn, uint8_t offset)
145 {
146 QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus);
147 uint32_t config_addr = (devfn << 8) | offset;
148 return qrtas_ibm_read_pci_config(s->alloc, BUIDBASE(0),
149 config_addr, 4);
150 }
151
152 static void qpci_spapr_config_writeb(QPCIBus *bus, int devfn, uint8_t offset,
153 uint8_t value)
154 {
155 QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus);
156 uint32_t config_addr = (devfn << 8) | offset;
157 qrtas_ibm_write_pci_config(s->alloc, BUIDBASE(0),
158 config_addr, 1, value);
159 }
160
161 static void qpci_spapr_config_writew(QPCIBus *bus, int devfn, uint8_t offset,
162 uint16_t value)
163 {
164 QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus);
165 uint32_t config_addr = (devfn << 8) | offset;
166 qrtas_ibm_write_pci_config(s->alloc, BUIDBASE(0),
167 config_addr, 2, value);
168 }
169
170 static void qpci_spapr_config_writel(QPCIBus *bus, int devfn, uint8_t offset,
171 uint32_t value)
172 {
173 QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus);
174 uint32_t config_addr = (devfn << 8) | offset;
175 qrtas_ibm_write_pci_config(s->alloc, BUIDBASE(0),
176 config_addr, 4, value);
177 }
178
179 static void *qpci_spapr_iomap(QPCIBus *bus, QPCIDevice *dev, int barno,
180 uint64_t *sizeptr)
181 {
182 QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus);
183 static const int bar_reg_map[] = {
184 PCI_BASE_ADDRESS_0, PCI_BASE_ADDRESS_1, PCI_BASE_ADDRESS_2,
185 PCI_BASE_ADDRESS_3, PCI_BASE_ADDRESS_4, PCI_BASE_ADDRESS_5,
186 };
187 int bar_reg;
188 uint32_t addr;
189 uint64_t size;
190 uint32_t io_type;
191
192 g_assert(barno >= 0 && barno <= 5);
193 bar_reg = bar_reg_map[barno];
194
195 qpci_config_writel(dev, bar_reg, 0xFFFFFFFF);
196 addr = qpci_config_readl(dev, bar_reg);
197
198 io_type = addr & PCI_BASE_ADDRESS_SPACE;
199 if (io_type == PCI_BASE_ADDRESS_SPACE_IO) {
200 addr &= PCI_BASE_ADDRESS_IO_MASK;
201 } else {
202 addr &= PCI_BASE_ADDRESS_MEM_MASK;
203 }
204
205 size = (1ULL << ctzl(addr));
206 if (size == 0) {
207 return NULL;
208 }
209 if (sizeptr) {
210 *sizeptr = size;
211 }
212
213 if (io_type == PCI_BASE_ADDRESS_SPACE_IO) {
214 uint16_t loc;
215
216 g_assert(QEMU_ALIGN_UP(s->pci_iohole_alloc, size) + size
217 <= s->pci_iohole_size);
218 s->pci_iohole_alloc = QEMU_ALIGN_UP(s->pci_iohole_alloc, size);
219 loc = s->pci_iohole_start + s->pci_iohole_alloc;
220 s->pci_iohole_alloc += size;
221
222 qpci_config_writel(dev, bar_reg, loc | PCI_BASE_ADDRESS_SPACE_IO);
223
224 return (void *)(unsigned long)loc;
225 } else {
226 uint64_t loc;
227
228 g_assert(QEMU_ALIGN_UP(s->pci_hole_alloc, size) + size
229 <= s->pci_hole_size);
230 s->pci_hole_alloc = QEMU_ALIGN_UP(s->pci_hole_alloc, size);
231 loc = s->pci_hole_start + s->pci_hole_alloc;
232 s->pci_hole_alloc += size;
233
234 qpci_config_writel(dev, bar_reg, loc);
235
236 return (void *)(unsigned long)loc;
237 }
238 }
239
240 static void qpci_spapr_iounmap(QPCIBus *bus, void *data)
241 {
242 /* FIXME */
243 }
244
245 QPCIBus *qpci_init_spapr(QGuestAllocator *alloc)
246 {
247 QPCIBusSPAPR *ret;
248
249 ret = g_malloc(sizeof(*ret));
250
251 ret->alloc = alloc;
252
253 ret->bus.io_readb = qpci_spapr_io_readb;
254 ret->bus.io_readw = qpci_spapr_io_readw;
255 ret->bus.io_readl = qpci_spapr_io_readl;
256
257 ret->bus.io_writeb = qpci_spapr_io_writeb;
258 ret->bus.io_writew = qpci_spapr_io_writew;
259 ret->bus.io_writel = qpci_spapr_io_writel;
260
261 ret->bus.config_readb = qpci_spapr_config_readb;
262 ret->bus.config_readw = qpci_spapr_config_readw;
263 ret->bus.config_readl = qpci_spapr_config_readl;
264
265 ret->bus.config_writeb = qpci_spapr_config_writeb;
266 ret->bus.config_writew = qpci_spapr_config_writew;
267 ret->bus.config_writel = qpci_spapr_config_writel;
268
269 ret->bus.iomap = qpci_spapr_iomap;
270 ret->bus.iounmap = qpci_spapr_iounmap;
271
272 ret->pci_hole_start = 0xC0000000;
273 ret->pci_hole_size = SPAPR_PCI_MMIO_WIN_SIZE;
274 ret->pci_hole_alloc = 0;
275
276 ret->pci_iohole_start = 0xc000;
277 ret->pci_iohole_size = SPAPR_PCI_IO_WIN_SIZE;
278 ret->pci_iohole_alloc = 0;
279
280 return &ret->bus;
281 }
282
283 void qpci_free_spapr(QPCIBus *bus)
284 {
285 QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus);
286
287 g_free(s);
288 }