Revision 01731cfb hw/msix.c
b/hw/msix.c | ||
---|---|---|
16 | 16 |
#include "pci.h" |
17 | 17 |
#include "range.h" |
18 | 18 |
|
19 |
/* MSI-X capability structure */ |
|
20 |
#define MSIX_TABLE_OFFSET 4 |
|
21 |
#define MSIX_PBA_OFFSET 8 |
|
22 | 19 |
#define MSIX_CAP_LENGTH 12 |
23 | 20 |
|
24 | 21 |
/* MSI enable bit and maskall bit are in byte 1 in FLAGS register */ |
... | ... | |
26 | 23 |
#define MSIX_ENABLE_MASK (PCI_MSIX_FLAGS_ENABLE >> 8) |
27 | 24 |
#define MSIX_MASKALL_MASK (PCI_MSIX_FLAGS_MASKALL >> 8) |
28 | 25 |
|
29 |
/* MSI-X table format */ |
|
30 |
#define MSIX_MSG_ADDR 0 |
|
31 |
#define MSIX_MSG_UPPER_ADDR 4 |
|
32 |
#define MSIX_MSG_DATA 8 |
|
33 |
#define MSIX_VECTOR_CTRL 12 |
|
34 |
#define MSIX_ENTRY_SIZE 16 |
|
35 |
#define MSIX_VECTOR_MASK 0x1 |
|
36 |
|
|
37 | 26 |
/* How much space does an MSIX table need. */ |
38 | 27 |
/* The spec requires giving the table structure |
39 | 28 |
* a 4K aligned region all by itself. */ |
... | ... | |
82 | 71 |
|
83 | 72 |
pci_set_word(config + PCI_MSIX_FLAGS, nentries - 1); |
84 | 73 |
/* Table on top of BAR */ |
85 |
pci_set_long(config + MSIX_TABLE_OFFSET, bar_size | bar_nr);
|
|
74 |
pci_set_long(config + PCI_MSIX_TABLE, bar_size | bar_nr);
|
|
86 | 75 |
/* Pending bits on top of that */ |
87 |
pci_set_long(config + MSIX_PBA_OFFSET, (bar_size + MSIX_PAGE_PENDING) |
|
|
76 |
pci_set_long(config + PCI_MSIX_PBA, (bar_size + MSIX_PAGE_PENDING) |
|
|
88 | 77 |
bar_nr); |
89 | 78 |
pdev->msix_cap = config_offset; |
90 | 79 |
/* Make flags bit writeable. */ |
... | ... | |
140 | 129 |
|
141 | 130 |
static int msix_is_masked(PCIDevice *dev, int vector) |
142 | 131 |
{ |
143 |
unsigned offset = vector * MSIX_ENTRY_SIZE + MSIX_VECTOR_CTRL; |
|
132 |
unsigned offset = |
|
133 |
vector * PCI_MSIX_ENTRY_SIZE + PCI_MSIX_ENTRY_VECTOR_CTRL; |
|
144 | 134 |
return msix_function_masked(dev) || |
145 |
dev->msix_table_page[offset] & MSIX_VECTOR_MASK;
|
|
135 |
dev->msix_table_page[offset] & PCI_MSIX_ENTRY_CTRL_MASKBIT;
|
|
146 | 136 |
} |
147 | 137 |
|
148 | 138 |
static void msix_handle_mask_update(PCIDevice *dev, int vector) |
... | ... | |
184 | 174 |
{ |
185 | 175 |
PCIDevice *dev = opaque; |
186 | 176 |
unsigned int offset = addr & (MSIX_PAGE_SIZE - 1) & ~0x3; |
187 |
int vector = offset / MSIX_ENTRY_SIZE; |
|
177 |
int vector = offset / PCI_MSIX_ENTRY_SIZE;
|
|
188 | 178 |
pci_set_long(dev->msix_table_page + offset, val); |
189 | 179 |
msix_handle_mask_update(dev, vector); |
190 | 180 |
} |
... | ... | |
208 | 198 |
pcibus_t addr, pcibus_t size, int type) |
209 | 199 |
{ |
210 | 200 |
uint8_t *config = d->config + d->msix_cap; |
211 |
uint32_t table = pci_get_long(config + MSIX_TABLE_OFFSET);
|
|
201 |
uint32_t table = pci_get_long(config + PCI_MSIX_TABLE);
|
|
212 | 202 |
uint32_t offset = table & ~(MSIX_PAGE_SIZE - 1); |
213 | 203 |
/* TODO: for assigned devices, we'll want to make it possible to map |
214 | 204 |
* pending bits separately in case they are in a separate bar. */ |
... | ... | |
226 | 216 |
{ |
227 | 217 |
int vector; |
228 | 218 |
for (vector = 0; vector < nentries; ++vector) { |
229 |
unsigned offset = vector * MSIX_ENTRY_SIZE + MSIX_VECTOR_CTRL; |
|
230 |
dev->msix_table_page[offset] |= MSIX_VECTOR_MASK; |
|
219 |
unsigned offset = |
|
220 |
vector * PCI_MSIX_ENTRY_SIZE + PCI_MSIX_ENTRY_VECTOR_CTRL; |
|
221 |
dev->msix_table_page[offset] |= PCI_MSIX_ENTRY_CTRL_MASKBIT; |
|
231 | 222 |
} |
232 | 223 |
} |
233 | 224 |
|
... | ... | |
313 | 304 |
return; |
314 | 305 |
} |
315 | 306 |
|
316 |
qemu_put_buffer(f, dev->msix_table_page, n * MSIX_ENTRY_SIZE); |
|
307 |
qemu_put_buffer(f, dev->msix_table_page, n * PCI_MSIX_ENTRY_SIZE);
|
|
317 | 308 |
qemu_put_buffer(f, dev->msix_table_page + MSIX_PAGE_PENDING, (n + 7) / 8); |
318 | 309 |
} |
319 | 310 |
|
... | ... | |
327 | 318 |
} |
328 | 319 |
|
329 | 320 |
msix_free_irq_entries(dev); |
330 |
qemu_get_buffer(f, dev->msix_table_page, n * MSIX_ENTRY_SIZE); |
|
321 |
qemu_get_buffer(f, dev->msix_table_page, n * PCI_MSIX_ENTRY_SIZE);
|
|
331 | 322 |
qemu_get_buffer(f, dev->msix_table_page + MSIX_PAGE_PENDING, (n + 7) / 8); |
332 | 323 |
} |
333 | 324 |
|
... | ... | |
355 | 346 |
/* Send an MSI-X message */ |
356 | 347 |
void msix_notify(PCIDevice *dev, unsigned vector) |
357 | 348 |
{ |
358 |
uint8_t *table_entry = dev->msix_table_page + vector * MSIX_ENTRY_SIZE; |
|
349 |
uint8_t *table_entry = dev->msix_table_page + vector * PCI_MSIX_ENTRY_SIZE;
|
|
359 | 350 |
uint64_t address; |
360 | 351 |
uint32_t data; |
361 | 352 |
|
... | ... | |
366 | 357 |
return; |
367 | 358 |
} |
368 | 359 |
|
369 |
address = pci_get_long(table_entry + MSIX_MSG_UPPER_ADDR); |
|
370 |
address = (address << 32) | pci_get_long(table_entry + MSIX_MSG_ADDR); |
|
371 |
data = pci_get_long(table_entry + MSIX_MSG_DATA); |
|
360 |
address = pci_get_quad(table_entry + PCI_MSIX_ENTRY_LOWER_ADDR); |
|
361 |
data = pci_get_long(table_entry + PCI_MSIX_ENTRY_DATA); |
|
372 | 362 |
stl_phys(address, data); |
373 | 363 |
} |
374 | 364 |
|
Also available in: Unified diff