]> git.proxmox.com Git - mirror_qemu.git/blame - tests/libqos/pci.c
Merge remote-tracking branch 'remotes/ehabkost/tags/machine-pull-request' into staging
[mirror_qemu.git] / tests / libqos / pci.c
CommitLineData
c4efe1ca
AL
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
681c28a3 13#include "qemu/osdep.h"
c4efe1ca
AL
14#include "libqos/pci.h"
15
16#include "hw/pci/pci_regs.h"
c4efe1ca 17
c4efe1ca
AL
18void qpci_device_foreach(QPCIBus *bus, int vendor_id, int device_id,
19 void (*func)(QPCIDevice *dev, int devfn, void *data),
20 void *data)
21{
22 int slot;
23
24 for (slot = 0; slot < 32; slot++) {
25 int fn;
26
27 for (fn = 0; fn < 8; fn++) {
28 QPCIDevice *dev;
29
30 dev = qpci_device_find(bus, QPCI_DEVFN(slot, fn));
31 if (!dev) {
32 continue;
33 }
34
35 if (vendor_id != -1 &&
36 qpci_config_readw(dev, PCI_VENDOR_ID) != vendor_id) {
ea53854a 37 g_free(dev);
c4efe1ca
AL
38 continue;
39 }
40
41 if (device_id != -1 &&
42 qpci_config_readw(dev, PCI_DEVICE_ID) != device_id) {
ea53854a 43 g_free(dev);
c4efe1ca
AL
44 continue;
45 }
46
47 func(dev, QPCI_DEVFN(slot, fn), data);
48 }
49 }
50}
51
52QPCIDevice *qpci_device_find(QPCIBus *bus, int devfn)
53{
54 QPCIDevice *dev;
55
56 dev = g_malloc0(sizeof(*dev));
57 dev->bus = bus;
58 dev->devfn = devfn;
59
60 if (qpci_config_readw(dev, PCI_VENDOR_ID) == 0xFFFF) {
61 g_free(dev);
62 return NULL;
63 }
64
65 return dev;
66}
67
68void qpci_device_enable(QPCIDevice *dev)
69{
70 uint16_t cmd;
71
72 /* FIXME -- does this need to be a bus callout? */
73 cmd = qpci_config_readw(dev, PCI_COMMAND);
9f0332b8 74 cmd |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
c4efe1ca 75 qpci_config_writew(dev, PCI_COMMAND, cmd);
96d6d3ba
JS
76
77 /* Verify the bits are now set. */
78 cmd = qpci_config_readw(dev, PCI_COMMAND);
79 g_assert_cmphex(cmd & PCI_COMMAND_IO, ==, PCI_COMMAND_IO);
80 g_assert_cmphex(cmd & PCI_COMMAND_MEMORY, ==, PCI_COMMAND_MEMORY);
81 g_assert_cmphex(cmd & PCI_COMMAND_MASTER, ==, PCI_COMMAND_MASTER);
c4efe1ca
AL
82}
83
58368113
MM
84uint8_t qpci_find_capability(QPCIDevice *dev, uint8_t id)
85{
86 uint8_t cap;
87 uint8_t addr = qpci_config_readb(dev, PCI_CAPABILITY_LIST);
88
89 do {
90 cap = qpci_config_readb(dev, addr);
91 if (cap != id) {
92 addr = qpci_config_readb(dev, addr + PCI_CAP_LIST_NEXT);
93 }
94 } while (cap != id && addr != 0);
95
96 return addr;
97}
98
99void qpci_msix_enable(QPCIDevice *dev)
100{
101 uint8_t addr;
102 uint16_t val;
103 uint32_t table;
104 uint8_t bir_table;
105 uint8_t bir_pba;
106 void *offset;
107
108 addr = qpci_find_capability(dev, PCI_CAP_ID_MSIX);
109 g_assert_cmphex(addr, !=, 0);
110
111 val = qpci_config_readw(dev, addr + PCI_MSIX_FLAGS);
112 qpci_config_writew(dev, addr + PCI_MSIX_FLAGS, val | PCI_MSIX_FLAGS_ENABLE);
113
114 table = qpci_config_readl(dev, addr + PCI_MSIX_TABLE);
115 bir_table = table & PCI_MSIX_FLAGS_BIRMASK;
116 offset = qpci_iomap(dev, bir_table, NULL);
117 dev->msix_table = offset + (table & ~PCI_MSIX_FLAGS_BIRMASK);
118
119 table = qpci_config_readl(dev, addr + PCI_MSIX_PBA);
120 bir_pba = table & PCI_MSIX_FLAGS_BIRMASK;
121 if (bir_pba != bir_table) {
122 offset = qpci_iomap(dev, bir_pba, NULL);
123 }
124 dev->msix_pba = offset + (table & ~PCI_MSIX_FLAGS_BIRMASK);
125
126 g_assert(dev->msix_table != NULL);
127 g_assert(dev->msix_pba != NULL);
128 dev->msix_enabled = true;
129}
130
131void qpci_msix_disable(QPCIDevice *dev)
132{
133 uint8_t addr;
134 uint16_t val;
135
136 g_assert(dev->msix_enabled);
137 addr = qpci_find_capability(dev, PCI_CAP_ID_MSIX);
138 g_assert_cmphex(addr, !=, 0);
139 val = qpci_config_readw(dev, addr + PCI_MSIX_FLAGS);
140 qpci_config_writew(dev, addr + PCI_MSIX_FLAGS,
141 val & ~PCI_MSIX_FLAGS_ENABLE);
142
143 qpci_iounmap(dev, dev->msix_table);
144 qpci_iounmap(dev, dev->msix_pba);
145 dev->msix_enabled = 0;
146 dev->msix_table = NULL;
147 dev->msix_pba = NULL;
148}
149
150bool qpci_msix_pending(QPCIDevice *dev, uint16_t entry)
151{
152 uint32_t pba_entry;
153 uint8_t bit_n = entry % 32;
154 void *addr = dev->msix_pba + (entry / 32) * PCI_MSIX_ENTRY_SIZE / 4;
155
156 g_assert(dev->msix_enabled);
157 pba_entry = qpci_io_readl(dev, addr);
158 qpci_io_writel(dev, addr, pba_entry & ~(1 << bit_n));
159 return (pba_entry & (1 << bit_n)) != 0;
160}
161
162bool qpci_msix_masked(QPCIDevice *dev, uint16_t entry)
163{
164 uint8_t addr;
165 uint16_t val;
166 void *vector_addr = dev->msix_table + (entry * PCI_MSIX_ENTRY_SIZE);
167
168 g_assert(dev->msix_enabled);
169 addr = qpci_find_capability(dev, PCI_CAP_ID_MSIX);
170 g_assert_cmphex(addr, !=, 0);
171 val = qpci_config_readw(dev, addr + PCI_MSIX_FLAGS);
172
173 if (val & PCI_MSIX_FLAGS_MASKALL) {
174 return true;
175 } else {
176 return (qpci_io_readl(dev, vector_addr + PCI_MSIX_ENTRY_VECTOR_CTRL)
177 & PCI_MSIX_ENTRY_CTRL_MASKBIT) != 0;
178 }
179}
180
181uint16_t qpci_msix_table_size(QPCIDevice *dev)
182{
183 uint8_t addr;
184 uint16_t control;
185
186 addr = qpci_find_capability(dev, PCI_CAP_ID_MSIX);
187 g_assert_cmphex(addr, !=, 0);
188
189 control = qpci_config_readw(dev, addr + PCI_MSIX_FLAGS);
190 return (control & PCI_MSIX_FLAGS_QSIZE) + 1;
191}
192
c4efe1ca
AL
193uint8_t qpci_config_readb(QPCIDevice *dev, uint8_t offset)
194{
195 return dev->bus->config_readb(dev->bus, dev->devfn, offset);
196}
197
198uint16_t qpci_config_readw(QPCIDevice *dev, uint8_t offset)
199{
200 return dev->bus->config_readw(dev->bus, dev->devfn, offset);
201}
202
203uint32_t qpci_config_readl(QPCIDevice *dev, uint8_t offset)
204{
205 return dev->bus->config_readl(dev->bus, dev->devfn, offset);
206}
207
208
209void qpci_config_writeb(QPCIDevice *dev, uint8_t offset, uint8_t value)
210{
211 dev->bus->config_writeb(dev->bus, dev->devfn, offset, value);
212}
213
214void qpci_config_writew(QPCIDevice *dev, uint8_t offset, uint16_t value)
215{
216 dev->bus->config_writew(dev->bus, dev->devfn, offset, value);
217}
218
219void qpci_config_writel(QPCIDevice *dev, uint8_t offset, uint32_t value)
220{
ad489e93 221 dev->bus->config_writel(dev->bus, dev->devfn, offset, value);
c4efe1ca
AL
222}
223
224
225uint8_t qpci_io_readb(QPCIDevice *dev, void *data)
226{
227 return dev->bus->io_readb(dev->bus, data);
228}
229
230uint16_t qpci_io_readw(QPCIDevice *dev, void *data)
231{
232 return dev->bus->io_readw(dev->bus, data);
233}
234
235uint32_t qpci_io_readl(QPCIDevice *dev, void *data)
236{
237 return dev->bus->io_readl(dev->bus, data);
238}
239
240
241void qpci_io_writeb(QPCIDevice *dev, void *data, uint8_t value)
242{
243 dev->bus->io_writeb(dev->bus, data, value);
244}
245
246void qpci_io_writew(QPCIDevice *dev, void *data, uint16_t value)
247{
248 dev->bus->io_writew(dev->bus, data, value);
249}
250
251void qpci_io_writel(QPCIDevice *dev, void *data, uint32_t value)
252{
253 dev->bus->io_writel(dev->bus, data, value);
254}
255
6ce7100e 256void *qpci_iomap(QPCIDevice *dev, int barno, uint64_t *sizeptr)
c4efe1ca 257{
6ce7100e 258 return dev->bus->iomap(dev->bus, dev, barno, sizeptr);
c4efe1ca
AL
259}
260
261void qpci_iounmap(QPCIDevice *dev, void *data)
262{
263 dev->bus->iounmap(dev->bus, data);
264}
265
cf716b31
LV
266void qpci_plug_device_test(const char *driver, const char *id,
267 uint8_t slot, const char *opts)
268{
269 QDict *response;
270 char *cmd;
271
272 cmd = g_strdup_printf("{'execute': 'device_add',"
273 " 'arguments': {"
274 " 'driver': '%s',"
275 " 'addr': '%d',"
276 " %s%s"
277 " 'id': '%s'"
278 "}}", driver, slot,
279 opts ? opts : "", opts ? "," : "",
280 id);
281 response = qmp(cmd);
282 g_free(cmd);
283 g_assert(response);
284 g_assert(!qdict_haskey(response, "error"));
285 QDECREF(response);
286}