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