xref: /openbmc/qemu/tests/qtest/libqos/pci.c (revision ad1a706f)
1 /*
2  * libqos PCI bindings
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 
13 #include "qemu/osdep.h"
14 #include "pci.h"
15 
16 #include "hw/pci/pci_regs.h"
17 #include "qemu/host-utils.h"
18 #include "qgraph.h"
19 
20 void qpci_device_foreach(QPCIBus *bus, int vendor_id, int device_id,
21                          void (*func)(QPCIDevice *dev, int devfn, void *data),
22                          void *data)
23 {
24     int slot;
25 
26     for (slot = 0; slot < 32; slot++) {
27         int fn;
28 
29         for (fn = 0; fn < 8; fn++) {
30             QPCIDevice *dev;
31 
32             dev = qpci_device_find(bus, QPCI_DEVFN(slot, fn));
33             if (!dev) {
34                 continue;
35             }
36 
37             if (vendor_id != -1 &&
38                 qpci_config_readw(dev, PCI_VENDOR_ID) != vendor_id) {
39                 g_free(dev);
40                 continue;
41             }
42 
43             if (device_id != -1 &&
44                 qpci_config_readw(dev, PCI_DEVICE_ID) != device_id) {
45                 g_free(dev);
46                 continue;
47             }
48 
49             func(dev, QPCI_DEVFN(slot, fn), data);
50         }
51     }
52 }
53 
54 bool qpci_has_buggy_msi(QPCIDevice *dev)
55 {
56     return dev->bus->has_buggy_msi;
57 }
58 
59 bool qpci_check_buggy_msi(QPCIDevice *dev)
60 {
61     if (qpci_has_buggy_msi(dev)) {
62         g_test_skip("Skipping due to incomplete support for MSI");
63         return true;
64     }
65     return false;
66 }
67 
68 static void qpci_device_set(QPCIDevice *dev, QPCIBus *bus, int devfn)
69 {
70     g_assert(dev);
71 
72     dev->bus = bus;
73     dev->devfn = devfn;
74 }
75 
76 QPCIDevice *qpci_device_find(QPCIBus *bus, int devfn)
77 {
78     QPCIDevice *dev;
79 
80     dev = g_malloc0(sizeof(*dev));
81     qpci_device_set(dev, bus, devfn);
82 
83     if (qpci_config_readw(dev, PCI_VENDOR_ID) == 0xFFFF) {
84         g_free(dev);
85         return NULL;
86     }
87 
88     return dev;
89 }
90 
91 void qpci_device_init(QPCIDevice *dev, QPCIBus *bus, QPCIAddress *addr)
92 {
93     uint16_t vendor_id, device_id;
94 
95     qpci_device_set(dev, bus, addr->devfn);
96     vendor_id = qpci_config_readw(dev, PCI_VENDOR_ID);
97     device_id = qpci_config_readw(dev, PCI_DEVICE_ID);
98     g_assert(!addr->vendor_id || vendor_id == addr->vendor_id);
99     g_assert(!addr->device_id || device_id == addr->device_id);
100 }
101 
102 void qpci_device_enable(QPCIDevice *dev)
103 {
104     uint16_t cmd;
105 
106     /* FIXME -- does this need to be a bus callout? */
107     cmd = qpci_config_readw(dev, PCI_COMMAND);
108     cmd |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
109     qpci_config_writew(dev, PCI_COMMAND, cmd);
110 
111     /* Verify the bits are now set. */
112     cmd = qpci_config_readw(dev, PCI_COMMAND);
113     g_assert_cmphex(cmd & PCI_COMMAND_IO, ==, PCI_COMMAND_IO);
114     g_assert_cmphex(cmd & PCI_COMMAND_MEMORY, ==, PCI_COMMAND_MEMORY);
115     g_assert_cmphex(cmd & PCI_COMMAND_MASTER, ==, PCI_COMMAND_MASTER);
116 }
117 
118 /**
119  * qpci_find_capability:
120  * @dev: the PCI device
121  * @id: the PCI Capability ID (PCI_CAP_ID_*)
122  * @start_addr: 0 to begin iteration or the last return value to continue
123  *              iteration
124  *
125  * Iterate over the PCI Capabilities List.
126  *
127  * Returns: PCI Configuration Space offset of the capabililty structure or
128  *          0 if no further matching capability is found
129  */
130 uint8_t qpci_find_capability(QPCIDevice *dev, uint8_t id, uint8_t start_addr)
131 {
132     uint8_t cap;
133     uint8_t addr;
134 
135     if (start_addr) {
136         addr = qpci_config_readb(dev, start_addr + PCI_CAP_LIST_NEXT);
137     } else {
138         addr = qpci_config_readb(dev, PCI_CAPABILITY_LIST);
139     }
140 
141     do {
142         cap = qpci_config_readb(dev, addr);
143         if (cap != id) {
144             addr = qpci_config_readb(dev, addr + PCI_CAP_LIST_NEXT);
145         }
146     } while (cap != id && addr != 0);
147 
148     return addr;
149 }
150 
151 void qpci_msix_enable(QPCIDevice *dev)
152 {
153     uint8_t addr;
154     uint16_t val;
155     uint32_t table;
156     uint8_t bir_table;
157     uint8_t bir_pba;
158 
159     addr = qpci_find_capability(dev, PCI_CAP_ID_MSIX, 0);
160     g_assert_cmphex(addr, !=, 0);
161 
162     val = qpci_config_readw(dev, addr + PCI_MSIX_FLAGS);
163     qpci_config_writew(dev, addr + PCI_MSIX_FLAGS, val | PCI_MSIX_FLAGS_ENABLE);
164 
165     table = qpci_config_readl(dev, addr + PCI_MSIX_TABLE);
166     bir_table = table & PCI_MSIX_FLAGS_BIRMASK;
167     dev->msix_table_bar = qpci_iomap(dev, bir_table, NULL);
168     dev->msix_table_off = table & ~PCI_MSIX_FLAGS_BIRMASK;
169 
170     table = qpci_config_readl(dev, addr + PCI_MSIX_PBA);
171     bir_pba = table & PCI_MSIX_FLAGS_BIRMASK;
172     if (bir_pba != bir_table) {
173         dev->msix_pba_bar = qpci_iomap(dev, bir_pba, NULL);
174     } else {
175         dev->msix_pba_bar = dev->msix_table_bar;
176     }
177     dev->msix_pba_off = table & ~PCI_MSIX_FLAGS_BIRMASK;
178 
179     dev->msix_enabled = true;
180 }
181 
182 void qpci_msix_disable(QPCIDevice *dev)
183 {
184     uint8_t addr;
185     uint16_t val;
186 
187     g_assert(dev->msix_enabled);
188     addr = qpci_find_capability(dev, PCI_CAP_ID_MSIX, 0);
189     g_assert_cmphex(addr, !=, 0);
190     val = qpci_config_readw(dev, addr + PCI_MSIX_FLAGS);
191     qpci_config_writew(dev, addr + PCI_MSIX_FLAGS,
192                                                 val & ~PCI_MSIX_FLAGS_ENABLE);
193 
194     if (dev->msix_pba_bar.addr != dev->msix_table_bar.addr) {
195         qpci_iounmap(dev, dev->msix_pba_bar);
196     }
197     qpci_iounmap(dev, dev->msix_table_bar);
198 
199     dev->msix_enabled = 0;
200     dev->msix_table_off = 0;
201     dev->msix_pba_off = 0;
202 }
203 
204 bool qpci_msix_pending(QPCIDevice *dev, uint16_t entry)
205 {
206     uint32_t pba_entry;
207     uint8_t bit_n = entry % 32;
208     uint64_t  off = (entry / 32) * PCI_MSIX_ENTRY_SIZE / 4;
209 
210     g_assert(dev->msix_enabled);
211     pba_entry = qpci_io_readl(dev, dev->msix_pba_bar, dev->msix_pba_off + off);
212     qpci_io_writel(dev, dev->msix_pba_bar, dev->msix_pba_off + off,
213                    pba_entry & ~(1 << bit_n));
214     return (pba_entry & (1 << bit_n)) != 0;
215 }
216 
217 bool qpci_msix_masked(QPCIDevice *dev, uint16_t entry)
218 {
219     uint8_t addr;
220     uint16_t val;
221     uint64_t vector_off = dev->msix_table_off + entry * PCI_MSIX_ENTRY_SIZE;
222 
223     g_assert(dev->msix_enabled);
224     addr = qpci_find_capability(dev, PCI_CAP_ID_MSIX, 0);
225     g_assert_cmphex(addr, !=, 0);
226     val = qpci_config_readw(dev, addr + PCI_MSIX_FLAGS);
227 
228     if (val & PCI_MSIX_FLAGS_MASKALL) {
229         return true;
230     } else {
231         return (qpci_io_readl(dev, dev->msix_table_bar,
232                               vector_off + PCI_MSIX_ENTRY_VECTOR_CTRL)
233                 & PCI_MSIX_ENTRY_CTRL_MASKBIT) != 0;
234     }
235 }
236 
237 uint16_t qpci_msix_table_size(QPCIDevice *dev)
238 {
239     uint8_t addr;
240     uint16_t control;
241 
242     addr = qpci_find_capability(dev, PCI_CAP_ID_MSIX, 0);
243     g_assert_cmphex(addr, !=, 0);
244 
245     control = qpci_config_readw(dev, addr + PCI_MSIX_FLAGS);
246     return (control & PCI_MSIX_FLAGS_QSIZE) + 1;
247 }
248 
249 uint8_t qpci_config_readb(QPCIDevice *dev, uint8_t offset)
250 {
251     return dev->bus->config_readb(dev->bus, dev->devfn, offset);
252 }
253 
254 uint16_t qpci_config_readw(QPCIDevice *dev, uint8_t offset)
255 {
256     return dev->bus->config_readw(dev->bus, dev->devfn, offset);
257 }
258 
259 uint32_t qpci_config_readl(QPCIDevice *dev, uint8_t offset)
260 {
261     return dev->bus->config_readl(dev->bus, dev->devfn, offset);
262 }
263 
264 
265 void qpci_config_writeb(QPCIDevice *dev, uint8_t offset, uint8_t value)
266 {
267     dev->bus->config_writeb(dev->bus, dev->devfn, offset, value);
268 }
269 
270 void qpci_config_writew(QPCIDevice *dev, uint8_t offset, uint16_t value)
271 {
272     dev->bus->config_writew(dev->bus, dev->devfn, offset, value);
273 }
274 
275 void qpci_config_writel(QPCIDevice *dev, uint8_t offset, uint32_t value)
276 {
277     dev->bus->config_writel(dev->bus, dev->devfn, offset, value);
278 }
279 
280 uint8_t qpci_io_readb(QPCIDevice *dev, QPCIBar token, uint64_t off)
281 {
282     if (token.addr < QPCI_PIO_LIMIT) {
283         return dev->bus->pio_readb(dev->bus, token.addr + off);
284     } else {
285         uint8_t val;
286         dev->bus->memread(dev->bus, token.addr + off, &val, sizeof(val));
287         return val;
288     }
289 }
290 
291 uint16_t qpci_io_readw(QPCIDevice *dev, QPCIBar token, uint64_t off)
292 {
293     if (token.addr < QPCI_PIO_LIMIT) {
294         return dev->bus->pio_readw(dev->bus, token.addr + off);
295     } else {
296         uint16_t val;
297         dev->bus->memread(dev->bus, token.addr + off, &val, sizeof(val));
298         return le16_to_cpu(val);
299     }
300 }
301 
302 uint32_t qpci_io_readl(QPCIDevice *dev, QPCIBar token, uint64_t off)
303 {
304     if (token.addr < QPCI_PIO_LIMIT) {
305         return dev->bus->pio_readl(dev->bus, token.addr + off);
306     } else {
307         uint32_t val;
308         dev->bus->memread(dev->bus, token.addr + off, &val, sizeof(val));
309         return le32_to_cpu(val);
310     }
311 }
312 
313 uint64_t qpci_io_readq(QPCIDevice *dev, QPCIBar token, uint64_t off)
314 {
315     if (token.addr < QPCI_PIO_LIMIT) {
316         return dev->bus->pio_readq(dev->bus, token.addr + off);
317     } else {
318         uint64_t val;
319         dev->bus->memread(dev->bus, token.addr + off, &val, sizeof(val));
320         return le64_to_cpu(val);
321     }
322 }
323 
324 void qpci_io_writeb(QPCIDevice *dev, QPCIBar token, uint64_t off,
325                     uint8_t value)
326 {
327     if (token.addr < QPCI_PIO_LIMIT) {
328         dev->bus->pio_writeb(dev->bus, token.addr + off, value);
329     } else {
330         dev->bus->memwrite(dev->bus, token.addr + off, &value, sizeof(value));
331     }
332 }
333 
334 void qpci_io_writew(QPCIDevice *dev, QPCIBar token, uint64_t off,
335                     uint16_t value)
336 {
337     if (token.addr < QPCI_PIO_LIMIT) {
338         dev->bus->pio_writew(dev->bus, token.addr + off, value);
339     } else {
340         value = cpu_to_le16(value);
341         dev->bus->memwrite(dev->bus, token.addr + off, &value, sizeof(value));
342     }
343 }
344 
345 void qpci_io_writel(QPCIDevice *dev, QPCIBar token, uint64_t off,
346                     uint32_t value)
347 {
348     if (token.addr < QPCI_PIO_LIMIT) {
349         dev->bus->pio_writel(dev->bus, token.addr + off, value);
350     } else {
351         value = cpu_to_le32(value);
352         dev->bus->memwrite(dev->bus, token.addr + off, &value, sizeof(value));
353     }
354 }
355 
356 void qpci_io_writeq(QPCIDevice *dev, QPCIBar token, uint64_t off,
357                     uint64_t value)
358 {
359     if (token.addr < QPCI_PIO_LIMIT) {
360         dev->bus->pio_writeq(dev->bus, token.addr + off, value);
361     } else {
362         value = cpu_to_le64(value);
363         dev->bus->memwrite(dev->bus, token.addr + off, &value, sizeof(value));
364     }
365 }
366 
367 void qpci_memread(QPCIDevice *dev, QPCIBar token, uint64_t off,
368                   void *buf, size_t len)
369 {
370     g_assert(token.addr >= QPCI_PIO_LIMIT);
371     dev->bus->memread(dev->bus, token.addr + off, buf, len);
372 }
373 
374 void qpci_memwrite(QPCIDevice *dev, QPCIBar token, uint64_t off,
375                    const void *buf, size_t len)
376 {
377     g_assert(token.addr >= QPCI_PIO_LIMIT);
378     dev->bus->memwrite(dev->bus, token.addr + off, buf, len);
379 }
380 
381 QPCIBar qpci_iomap(QPCIDevice *dev, int barno, uint64_t *sizeptr)
382 {
383     QPCIBus *bus = dev->bus;
384     static const int bar_reg_map[] = {
385         PCI_BASE_ADDRESS_0, PCI_BASE_ADDRESS_1, PCI_BASE_ADDRESS_2,
386         PCI_BASE_ADDRESS_3, PCI_BASE_ADDRESS_4, PCI_BASE_ADDRESS_5,
387     };
388     QPCIBar bar;
389     int bar_reg;
390     uint32_t addr, size;
391     uint32_t io_type;
392     uint64_t loc;
393 
394     g_assert(barno >= 0 && barno <= 5);
395     bar_reg = bar_reg_map[barno];
396 
397     qpci_config_writel(dev, bar_reg, 0xFFFFFFFF);
398     addr = qpci_config_readl(dev, bar_reg);
399 
400     io_type = addr & PCI_BASE_ADDRESS_SPACE;
401     if (io_type == PCI_BASE_ADDRESS_SPACE_IO) {
402         addr &= PCI_BASE_ADDRESS_IO_MASK;
403     } else {
404         addr &= PCI_BASE_ADDRESS_MEM_MASK;
405     }
406 
407     g_assert(addr); /* Must have *some* size bits */
408 
409     size = 1U << ctz32(addr);
410     if (sizeptr) {
411         *sizeptr = size;
412     }
413 
414     if (io_type == PCI_BASE_ADDRESS_SPACE_IO) {
415         loc = QEMU_ALIGN_UP(bus->pio_alloc_ptr, size);
416 
417         g_assert(loc >= bus->pio_alloc_ptr);
418         g_assert(loc + size <= QPCI_PIO_LIMIT); /* Keep PIO below 64kiB */
419 
420         bus->pio_alloc_ptr = loc + size;
421 
422         qpci_config_writel(dev, bar_reg, loc | PCI_BASE_ADDRESS_SPACE_IO);
423     } else {
424         loc = QEMU_ALIGN_UP(bus->mmio_alloc_ptr, size);
425 
426         /* Check for space */
427         g_assert(loc >= bus->mmio_alloc_ptr);
428         g_assert(loc + size <= bus->mmio_limit);
429 
430         bus->mmio_alloc_ptr = loc + size;
431 
432         qpci_config_writel(dev, bar_reg, loc);
433     }
434 
435     bar.addr = loc;
436     return bar;
437 }
438 
439 void qpci_iounmap(QPCIDevice *dev, QPCIBar bar)
440 {
441     /* FIXME */
442 }
443 
444 QPCIBar qpci_legacy_iomap(QPCIDevice *dev, uint16_t addr)
445 {
446     QPCIBar bar = { .addr = addr };
447     return bar;
448 }
449 
450 void add_qpci_address(QOSGraphEdgeOptions *opts, QPCIAddress *addr)
451 {
452     g_assert(addr);
453     g_assert(opts);
454 
455     opts->arg = addr;
456     opts->size_arg = sizeof(QPCIAddress);
457 }
458