]> Git Repo - qemu.git/blob - tests/libqos/pci.c
Merge remote-tracking branch 'remotes/maxreitz/tags/pull-block-2019-05-07' into staging
[qemu.git] / tests / libqos / pci.c
1 /*
2  * libqos PCI bindings
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
13 #include "qemu/osdep.h"
14 #include "libqos/pci.h"
15
16 #include "hw/pci/pci_regs.h"
17 #include "qemu/host-utils.h"
18 #include "libqos/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 uint8_t qpci_find_capability(QPCIDevice *dev, uint8_t id)
119 {
120     uint8_t cap;
121     uint8_t addr = qpci_config_readb(dev, PCI_CAPABILITY_LIST);
122
123     do {
124         cap = qpci_config_readb(dev, addr);
125         if (cap != id) {
126             addr = qpci_config_readb(dev, addr + PCI_CAP_LIST_NEXT);
127         }
128     } while (cap != id && addr != 0);
129
130     return addr;
131 }
132
133 void qpci_msix_enable(QPCIDevice *dev)
134 {
135     uint8_t addr;
136     uint16_t val;
137     uint32_t table;
138     uint8_t bir_table;
139     uint8_t bir_pba;
140
141     addr = qpci_find_capability(dev, PCI_CAP_ID_MSIX);
142     g_assert_cmphex(addr, !=, 0);
143
144     val = qpci_config_readw(dev, addr + PCI_MSIX_FLAGS);
145     qpci_config_writew(dev, addr + PCI_MSIX_FLAGS, val | PCI_MSIX_FLAGS_ENABLE);
146
147     table = qpci_config_readl(dev, addr + PCI_MSIX_TABLE);
148     bir_table = table & PCI_MSIX_FLAGS_BIRMASK;
149     dev->msix_table_bar = qpci_iomap(dev, bir_table, NULL);
150     dev->msix_table_off = table & ~PCI_MSIX_FLAGS_BIRMASK;
151
152     table = qpci_config_readl(dev, addr + PCI_MSIX_PBA);
153     bir_pba = table & PCI_MSIX_FLAGS_BIRMASK;
154     if (bir_pba != bir_table) {
155         dev->msix_pba_bar = qpci_iomap(dev, bir_pba, NULL);
156     } else {
157         dev->msix_pba_bar = dev->msix_table_bar;
158     }
159     dev->msix_pba_off = table & ~PCI_MSIX_FLAGS_BIRMASK;
160
161     dev->msix_enabled = true;
162 }
163
164 void qpci_msix_disable(QPCIDevice *dev)
165 {
166     uint8_t addr;
167     uint16_t val;
168
169     g_assert(dev->msix_enabled);
170     addr = qpci_find_capability(dev, PCI_CAP_ID_MSIX);
171     g_assert_cmphex(addr, !=, 0);
172     val = qpci_config_readw(dev, addr + PCI_MSIX_FLAGS);
173     qpci_config_writew(dev, addr + PCI_MSIX_FLAGS,
174                                                 val & ~PCI_MSIX_FLAGS_ENABLE);
175
176     if (dev->msix_pba_bar.addr != dev->msix_table_bar.addr) {
177         qpci_iounmap(dev, dev->msix_pba_bar);
178     }
179     qpci_iounmap(dev, dev->msix_table_bar);
180
181     dev->msix_enabled = 0;
182     dev->msix_table_off = 0;
183     dev->msix_pba_off = 0;
184 }
185
186 bool qpci_msix_pending(QPCIDevice *dev, uint16_t entry)
187 {
188     uint32_t pba_entry;
189     uint8_t bit_n = entry % 32;
190     uint64_t  off = (entry / 32) * PCI_MSIX_ENTRY_SIZE / 4;
191
192     g_assert(dev->msix_enabled);
193     pba_entry = qpci_io_readl(dev, dev->msix_pba_bar, dev->msix_pba_off + off);
194     qpci_io_writel(dev, dev->msix_pba_bar, dev->msix_pba_off + off,
195                    pba_entry & ~(1 << bit_n));
196     return (pba_entry & (1 << bit_n)) != 0;
197 }
198
199 bool qpci_msix_masked(QPCIDevice *dev, uint16_t entry)
200 {
201     uint8_t addr;
202     uint16_t val;
203     uint64_t vector_off = dev->msix_table_off + entry * PCI_MSIX_ENTRY_SIZE;
204
205     g_assert(dev->msix_enabled);
206     addr = qpci_find_capability(dev, PCI_CAP_ID_MSIX);
207     g_assert_cmphex(addr, !=, 0);
208     val = qpci_config_readw(dev, addr + PCI_MSIX_FLAGS);
209
210     if (val & PCI_MSIX_FLAGS_MASKALL) {
211         return true;
212     } else {
213         return (qpci_io_readl(dev, dev->msix_table_bar,
214                               vector_off + PCI_MSIX_ENTRY_VECTOR_CTRL)
215                 & PCI_MSIX_ENTRY_CTRL_MASKBIT) != 0;
216     }
217 }
218
219 uint16_t qpci_msix_table_size(QPCIDevice *dev)
220 {
221     uint8_t addr;
222     uint16_t control;
223
224     addr = qpci_find_capability(dev, PCI_CAP_ID_MSIX);
225     g_assert_cmphex(addr, !=, 0);
226
227     control = qpci_config_readw(dev, addr + PCI_MSIX_FLAGS);
228     return (control & PCI_MSIX_FLAGS_QSIZE) + 1;
229 }
230
231 uint8_t qpci_config_readb(QPCIDevice *dev, uint8_t offset)
232 {
233     return dev->bus->config_readb(dev->bus, dev->devfn, offset);
234 }
235
236 uint16_t qpci_config_readw(QPCIDevice *dev, uint8_t offset)
237 {
238     return dev->bus->config_readw(dev->bus, dev->devfn, offset);
239 }
240
241 uint32_t qpci_config_readl(QPCIDevice *dev, uint8_t offset)
242 {
243     return dev->bus->config_readl(dev->bus, dev->devfn, offset);
244 }
245
246
247 void qpci_config_writeb(QPCIDevice *dev, uint8_t offset, uint8_t value)
248 {
249     dev->bus->config_writeb(dev->bus, dev->devfn, offset, value);
250 }
251
252 void qpci_config_writew(QPCIDevice *dev, uint8_t offset, uint16_t value)
253 {
254     dev->bus->config_writew(dev->bus, dev->devfn, offset, value);
255 }
256
257 void qpci_config_writel(QPCIDevice *dev, uint8_t offset, uint32_t value)
258 {
259     dev->bus->config_writel(dev->bus, dev->devfn, offset, value);
260 }
261
262 uint8_t qpci_io_readb(QPCIDevice *dev, QPCIBar token, uint64_t off)
263 {
264     if (token.addr < QPCI_PIO_LIMIT) {
265         return dev->bus->pio_readb(dev->bus, token.addr + off);
266     } else {
267         uint8_t val;
268         dev->bus->memread(dev->bus, token.addr + off, &val, sizeof(val));
269         return val;
270     }
271 }
272
273 uint16_t qpci_io_readw(QPCIDevice *dev, QPCIBar token, uint64_t off)
274 {
275     if (token.addr < QPCI_PIO_LIMIT) {
276         return dev->bus->pio_readw(dev->bus, token.addr + off);
277     } else {
278         uint16_t val;
279         dev->bus->memread(dev->bus, token.addr + off, &val, sizeof(val));
280         return le16_to_cpu(val);
281     }
282 }
283
284 uint32_t qpci_io_readl(QPCIDevice *dev, QPCIBar token, uint64_t off)
285 {
286     if (token.addr < QPCI_PIO_LIMIT) {
287         return dev->bus->pio_readl(dev->bus, token.addr + off);
288     } else {
289         uint32_t val;
290         dev->bus->memread(dev->bus, token.addr + off, &val, sizeof(val));
291         return le32_to_cpu(val);
292     }
293 }
294
295 uint64_t qpci_io_readq(QPCIDevice *dev, QPCIBar token, uint64_t off)
296 {
297     if (token.addr < QPCI_PIO_LIMIT) {
298         return dev->bus->pio_readq(dev->bus, token.addr + off);
299     } else {
300         uint64_t val;
301         dev->bus->memread(dev->bus, token.addr + off, &val, sizeof(val));
302         return le64_to_cpu(val);
303     }
304 }
305
306 void qpci_io_writeb(QPCIDevice *dev, QPCIBar token, uint64_t off,
307                     uint8_t value)
308 {
309     if (token.addr < QPCI_PIO_LIMIT) {
310         dev->bus->pio_writeb(dev->bus, token.addr + off, value);
311     } else {
312         dev->bus->memwrite(dev->bus, token.addr + off, &value, sizeof(value));
313     }
314 }
315
316 void qpci_io_writew(QPCIDevice *dev, QPCIBar token, uint64_t off,
317                     uint16_t value)
318 {
319     if (token.addr < QPCI_PIO_LIMIT) {
320         dev->bus->pio_writew(dev->bus, token.addr + off, value);
321     } else {
322         value = cpu_to_le16(value);
323         dev->bus->memwrite(dev->bus, token.addr + off, &value, sizeof(value));
324     }
325 }
326
327 void qpci_io_writel(QPCIDevice *dev, QPCIBar token, uint64_t off,
328                     uint32_t value)
329 {
330     if (token.addr < QPCI_PIO_LIMIT) {
331         dev->bus->pio_writel(dev->bus, token.addr + off, value);
332     } else {
333         value = cpu_to_le32(value);
334         dev->bus->memwrite(dev->bus, token.addr + off, &value, sizeof(value));
335     }
336 }
337
338 void qpci_io_writeq(QPCIDevice *dev, QPCIBar token, uint64_t off,
339                     uint64_t value)
340 {
341     if (token.addr < QPCI_PIO_LIMIT) {
342         dev->bus->pio_writeq(dev->bus, token.addr + off, value);
343     } else {
344         value = cpu_to_le64(value);
345         dev->bus->memwrite(dev->bus, token.addr + off, &value, sizeof(value));
346     }
347 }
348
349 void qpci_memread(QPCIDevice *dev, QPCIBar token, uint64_t off,
350                   void *buf, size_t len)
351 {
352     g_assert(token.addr >= QPCI_PIO_LIMIT);
353     dev->bus->memread(dev->bus, token.addr + off, buf, len);
354 }
355
356 void qpci_memwrite(QPCIDevice *dev, QPCIBar token, uint64_t off,
357                    const void *buf, size_t len)
358 {
359     g_assert(token.addr >= QPCI_PIO_LIMIT);
360     dev->bus->memwrite(dev->bus, token.addr + off, buf, len);
361 }
362
363 QPCIBar qpci_iomap(QPCIDevice *dev, int barno, uint64_t *sizeptr)
364 {
365     QPCIBus *bus = dev->bus;
366     static const int bar_reg_map[] = {
367         PCI_BASE_ADDRESS_0, PCI_BASE_ADDRESS_1, PCI_BASE_ADDRESS_2,
368         PCI_BASE_ADDRESS_3, PCI_BASE_ADDRESS_4, PCI_BASE_ADDRESS_5,
369     };
370     QPCIBar bar;
371     int bar_reg;
372     uint32_t addr, size;
373     uint32_t io_type;
374     uint64_t loc;
375
376     g_assert(barno >= 0 && barno <= 5);
377     bar_reg = bar_reg_map[barno];
378
379     qpci_config_writel(dev, bar_reg, 0xFFFFFFFF);
380     addr = qpci_config_readl(dev, bar_reg);
381
382     io_type = addr & PCI_BASE_ADDRESS_SPACE;
383     if (io_type == PCI_BASE_ADDRESS_SPACE_IO) {
384         addr &= PCI_BASE_ADDRESS_IO_MASK;
385     } else {
386         addr &= PCI_BASE_ADDRESS_MEM_MASK;
387     }
388
389     g_assert(addr); /* Must have *some* size bits */
390
391     size = 1U << ctz32(addr);
392     if (sizeptr) {
393         *sizeptr = size;
394     }
395
396     if (io_type == PCI_BASE_ADDRESS_SPACE_IO) {
397         loc = QEMU_ALIGN_UP(bus->pio_alloc_ptr, size);
398
399         g_assert(loc >= bus->pio_alloc_ptr);
400         g_assert(loc + size <= QPCI_PIO_LIMIT); /* Keep PIO below 64kiB */
401
402         bus->pio_alloc_ptr = loc + size;
403
404         qpci_config_writel(dev, bar_reg, loc | PCI_BASE_ADDRESS_SPACE_IO);
405     } else {
406         loc = QEMU_ALIGN_UP(bus->mmio_alloc_ptr, size);
407
408         /* Check for space */
409         g_assert(loc >= bus->mmio_alloc_ptr);
410         g_assert(loc + size <= bus->mmio_limit);
411
412         bus->mmio_alloc_ptr = loc + size;
413
414         qpci_config_writel(dev, bar_reg, loc);
415     }
416
417     bar.addr = loc;
418     return bar;
419 }
420
421 void qpci_iounmap(QPCIDevice *dev, QPCIBar bar)
422 {
423     /* FIXME */
424 }
425
426 QPCIBar qpci_legacy_iomap(QPCIDevice *dev, uint16_t addr)
427 {
428     QPCIBar bar = { .addr = addr };
429     return bar;
430 }
431
432 void add_qpci_address(QOSGraphEdgeOptions *opts, QPCIAddress *addr)
433 {
434     g_assert(addr);
435     g_assert(opts);
436
437     opts->arg = addr;
438     opts->size_arg = sizeof(QPCIAddress);
439 }
This page took 0.048234 seconds and 4 git commands to generate.