blob: bafea94084c59a6af6fe92f54c6621531697ea78 [file] [log] [blame]
Michael S. Tsirkin02eb84d2009-06-21 19:49:54 +03001/*
2 * MSI-X device support
3 *
4 * This module includes support for MSI-X in pci devices.
5 *
6 * Author: Michael S. Tsirkin <mst@redhat.com>
7 *
8 * Copyright (c) 2009, Red Hat Inc, Michael S. Tsirkin (mst@redhat.com)
9 *
10 * This work is licensed under the terms of the GNU GPL, version 2. See
11 * the COPYING file in the top-level directory.
Paolo Bonzini6b620ca2012-01-13 17:44:23 +010012 *
13 * Contributions after 2012-01-13 are licensed under the terms of the
14 * GNU GPL, version 2 or (at your option) any later version.
Michael S. Tsirkin02eb84d2009-06-21 19:49:54 +030015 */
16
17#include "hw.h"
Jan Kiszka60ba3cc2011-10-15 14:33:17 +020018#include "msi.h"
Michael S. Tsirkin02eb84d2009-06-21 19:49:54 +030019#include "msix.h"
20#include "pci.h"
Blue Swirlbf1b0072010-09-18 05:53:14 +000021#include "range.h"
Michael S. Tsirkin02eb84d2009-06-21 19:49:54 +030022
Michael S. Tsirkin02eb84d2009-06-21 19:49:54 +030023#define MSIX_CAP_LENGTH 12
24
Michael S. Tsirkin27609522009-11-25 12:18:00 +020025/* MSI enable bit and maskall bit are in byte 1 in FLAGS register */
26#define MSIX_CONTROL_OFFSET (PCI_MSIX_FLAGS + 1)
Michael S. Tsirkin02eb84d2009-06-21 19:49:54 +030027#define MSIX_ENABLE_MASK (PCI_MSIX_FLAGS_ENABLE >> 8)
Michael S. Tsirkin5b5cb082009-11-25 12:19:32 +020028#define MSIX_MASKALL_MASK (PCI_MSIX_FLAGS_MASKALL >> 8)
Michael S. Tsirkin02eb84d2009-06-21 19:49:54 +030029
Michael S. Tsirkin5a1fc5e2009-09-29 18:53:26 +020030/* How much space does an MSIX table need. */
31/* The spec requires giving the table structure
32 * a 4K aligned region all by itself. */
33#define MSIX_PAGE_SIZE 0x1000
34/* Reserve second half of the page for pending bits */
35#define MSIX_PAGE_PENDING (MSIX_PAGE_SIZE / 2)
Michael S. Tsirkin02eb84d2009-06-21 19:49:54 +030036#define MSIX_MAX_ENTRIES 32
37
Jan Kiszkabc4caf42012-05-17 10:32:29 -030038static MSIMessage msix_get_message(PCIDevice *dev, unsigned vector)
39{
40 uint8_t *table_entry = dev->msix_table_page + vector * PCI_MSIX_ENTRY_SIZE;
41 MSIMessage msg;
42
43 msg.address = pci_get_quad(table_entry + PCI_MSIX_ENTRY_LOWER_ADDR);
44 msg.data = pci_get_long(table_entry + PCI_MSIX_ENTRY_DATA);
45 return msg;
46}
Michael S. Tsirkin02eb84d2009-06-21 19:49:54 +030047
Michael S. Tsirkin02eb84d2009-06-21 19:49:54 +030048/* Add MSI-X capability to the config space for the device. */
49/* Given a bar and its size, add MSI-X table on top of it
50 * and fill MSI-X capability in the config space.
51 * Original bar size must be a power of 2 or 0.
52 * New bar size is returned. */
53static int msix_add_config(struct PCIDevice *pdev, unsigned short nentries,
54 unsigned bar_nr, unsigned bar_size)
55{
56 int config_offset;
57 uint8_t *config;
Michael S. Tsirkin02eb84d2009-06-21 19:49:54 +030058
59 if (nentries < 1 || nentries > PCI_MSIX_FLAGS_QSIZE + 1)
60 return -EINVAL;
61 if (bar_size > 0x80000000)
62 return -ENOSPC;
63
Jan Kiszka393a9892012-06-04 16:56:01 +020064 /* Require aligned offset for MSI-X structures */
65 if (bar_size & ~(MSIX_PAGE_SIZE - 1)) {
66 return -EINVAL;
Michael S. Tsirkin5a1fc5e2009-09-29 18:53:26 +020067 }
Michael S. Tsirkin02eb84d2009-06-21 19:49:54 +030068
Isaku Yamahataca770892010-09-06 16:46:16 +090069 config_offset = pci_add_capability(pdev, PCI_CAP_ID_MSIX,
70 0, MSIX_CAP_LENGTH);
Michael S. Tsirkin02eb84d2009-06-21 19:49:54 +030071 if (config_offset < 0)
72 return config_offset;
73 config = pdev->config + config_offset;
74
75 pci_set_word(config + PCI_MSIX_FLAGS, nentries - 1);
76 /* Table on top of BAR */
Jan Kiszka01731cf2011-06-09 09:39:56 +020077 pci_set_long(config + PCI_MSIX_TABLE, bar_size | bar_nr);
Michael S. Tsirkin02eb84d2009-06-21 19:49:54 +030078 /* Pending bits on top of that */
Jan Kiszka01731cf2011-06-09 09:39:56 +020079 pci_set_long(config + PCI_MSIX_PBA, (bar_size + MSIX_PAGE_PENDING) |
Michael S. Tsirkin5a1fc5e2009-09-29 18:53:26 +020080 bar_nr);
Michael S. Tsirkin02eb84d2009-06-21 19:49:54 +030081 pdev->msix_cap = config_offset;
Stefan Weilebabb672011-04-26 10:29:36 +020082 /* Make flags bit writable. */
Michael S. Tsirkin5b5cb082009-11-25 12:19:32 +020083 pdev->wmask[config_offset + MSIX_CONTROL_OFFSET] |= MSIX_ENABLE_MASK |
84 MSIX_MASKALL_MASK;
Michael S. Tsirkin50322242011-11-21 18:57:21 +020085 pdev->msix_function_masked = true;
Michael S. Tsirkin02eb84d2009-06-21 19:49:54 +030086 return 0;
87}
88
Avi Kivity95524ae2011-08-08 16:09:26 +030089static uint64_t msix_mmio_read(void *opaque, target_phys_addr_t addr,
90 unsigned size)
Michael S. Tsirkin02eb84d2009-06-21 19:49:54 +030091{
92 PCIDevice *dev = opaque;
Michael S. Tsirkin76f51592009-10-26 16:22:44 +020093 unsigned int offset = addr & (MSIX_PAGE_SIZE - 1) & ~0x3;
Michael S. Tsirkin02eb84d2009-06-21 19:49:54 +030094 void *page = dev->msix_table_page;
Michael S. Tsirkin02eb84d2009-06-21 19:49:54 +030095
Michael S. Tsirkin76f51592009-10-26 16:22:44 +020096 return pci_get_long(page + offset);
Michael S. Tsirkin02eb84d2009-06-21 19:49:54 +030097}
98
Michael S. Tsirkin02eb84d2009-06-21 19:49:54 +030099static uint8_t msix_pending_mask(int vector)
100{
101 return 1 << (vector % 8);
102}
103
104static uint8_t *msix_pending_byte(PCIDevice *dev, int vector)
105{
Michael S. Tsirkin5a1fc5e2009-09-29 18:53:26 +0200106 return dev->msix_table_page + MSIX_PAGE_PENDING + vector / 8;
Michael S. Tsirkin02eb84d2009-06-21 19:49:54 +0300107}
108
109static int msix_is_pending(PCIDevice *dev, int vector)
110{
111 return *msix_pending_byte(dev, vector) & msix_pending_mask(vector);
112}
113
114static void msix_set_pending(PCIDevice *dev, int vector)
115{
116 *msix_pending_byte(dev, vector) |= msix_pending_mask(vector);
117}
118
119static void msix_clr_pending(PCIDevice *dev, int vector)
120{
121 *msix_pending_byte(dev, vector) &= ~msix_pending_mask(vector);
122}
123
Michael S. Tsirkinae392c42011-11-21 18:57:50 +0200124static bool msix_vector_masked(PCIDevice *dev, int vector, bool fmask)
Michael S. Tsirkin02eb84d2009-06-21 19:49:54 +0300125{
Michael S. Tsirkinae392c42011-11-21 18:57:50 +0200126 unsigned offset = vector * PCI_MSIX_ENTRY_SIZE + PCI_MSIX_ENTRY_VECTOR_CTRL;
127 return fmask || dev->msix_table_page[offset] & PCI_MSIX_ENTRY_CTRL_MASKBIT;
Michael S. Tsirkin5b5cb082009-11-25 12:19:32 +0200128}
129
Michael S. Tsirkinae392c42011-11-21 18:57:50 +0200130static bool msix_is_masked(PCIDevice *dev, int vector)
Michael S. Tsirkin5b5cb082009-11-25 12:19:32 +0200131{
Michael S. Tsirkinae392c42011-11-21 18:57:50 +0200132 return msix_vector_masked(dev, vector, dev->msix_function_masked);
133}
134
Jan Kiszka2cdfe532012-05-17 10:32:31 -0300135static void msix_fire_vector_notifier(PCIDevice *dev,
136 unsigned int vector, bool is_masked)
137{
138 MSIMessage msg;
139 int ret;
140
141 if (!dev->msix_vector_use_notifier) {
142 return;
143 }
144 if (is_masked) {
145 dev->msix_vector_release_notifier(dev, vector);
146 } else {
147 msg = msix_get_message(dev, vector);
148 ret = dev->msix_vector_use_notifier(dev, vector, msg);
149 assert(ret >= 0);
150 }
151}
152
Michael S. Tsirkinae392c42011-11-21 18:57:50 +0200153static void msix_handle_mask_update(PCIDevice *dev, int vector, bool was_masked)
154{
155 bool is_masked = msix_is_masked(dev, vector);
Jan Kiszka2cdfe532012-05-17 10:32:31 -0300156
Michael S. Tsirkinae392c42011-11-21 18:57:50 +0200157 if (is_masked == was_masked) {
158 return;
159 }
160
Jan Kiszka2cdfe532012-05-17 10:32:31 -0300161 msix_fire_vector_notifier(dev, vector, is_masked);
162
Michael S. Tsirkinae392c42011-11-21 18:57:50 +0200163 if (!is_masked && msix_is_pending(dev, vector)) {
Michael S. Tsirkin5b5cb082009-11-25 12:19:32 +0200164 msix_clr_pending(dev, vector);
165 msix_notify(dev, vector);
166 }
167}
168
Michael S. Tsirkin50322242011-11-21 18:57:21 +0200169static void msix_update_function_masked(PCIDevice *dev)
170{
171 dev->msix_function_masked = !msix_enabled(dev) ||
172 (dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] & MSIX_MASKALL_MASK);
173}
174
Michael S. Tsirkin5b5cb082009-11-25 12:19:32 +0200175/* Handle MSI-X capability config write. */
176void msix_write_config(PCIDevice *dev, uint32_t addr,
177 uint32_t val, int len)
178{
179 unsigned enable_pos = dev->msix_cap + MSIX_CONTROL_OFFSET;
180 int vector;
Michael S. Tsirkin50322242011-11-21 18:57:21 +0200181 bool was_masked;
Michael S. Tsirkin5b5cb082009-11-25 12:19:32 +0200182
Jan Kiszka7c9958b2012-05-11 11:42:39 -0300183 if (!msix_present(dev) || !range_covers_byte(addr, len, enable_pos)) {
Michael S. Tsirkin5b5cb082009-11-25 12:19:32 +0200184 return;
185 }
186
Michael S. Tsirkin50322242011-11-21 18:57:21 +0200187 was_masked = dev->msix_function_masked;
188 msix_update_function_masked(dev);
189
Michael S. Tsirkin5b5cb082009-11-25 12:19:32 +0200190 if (!msix_enabled(dev)) {
191 return;
192 }
193
Isaku Yamahatae407bf12011-01-20 16:21:40 +0900194 pci_device_deassert_intx(dev);
Michael S. Tsirkin5b5cb082009-11-25 12:19:32 +0200195
Michael S. Tsirkin50322242011-11-21 18:57:21 +0200196 if (dev->msix_function_masked == was_masked) {
Michael S. Tsirkin5b5cb082009-11-25 12:19:32 +0200197 return;
198 }
199
200 for (vector = 0; vector < dev->msix_entries_nr; ++vector) {
Michael S. Tsirkinae392c42011-11-21 18:57:50 +0200201 msix_handle_mask_update(dev, vector,
202 msix_vector_masked(dev, vector, was_masked));
Michael S. Tsirkin5b5cb082009-11-25 12:19:32 +0200203 }
Michael S. Tsirkin02eb84d2009-06-21 19:49:54 +0300204}
205
Avi Kivity95524ae2011-08-08 16:09:26 +0300206static void msix_mmio_write(void *opaque, target_phys_addr_t addr,
207 uint64_t val, unsigned size)
Michael S. Tsirkin02eb84d2009-06-21 19:49:54 +0300208{
209 PCIDevice *dev = opaque;
Michael S. Tsirkin76f51592009-10-26 16:22:44 +0200210 unsigned int offset = addr & (MSIX_PAGE_SIZE - 1) & ~0x3;
Jan Kiszka01731cf2011-06-09 09:39:56 +0200211 int vector = offset / PCI_MSIX_ENTRY_SIZE;
Michael S. Tsirkinae392c42011-11-21 18:57:50 +0200212 bool was_masked;
Michael S. Tsirkin9a93b612011-11-21 18:57:31 +0200213
214 /* MSI-X page includes a read-only PBA and a writeable Vector Control. */
215 if (vector >= dev->msix_entries_nr) {
216 return;
217 }
218
Michael S. Tsirkinae392c42011-11-21 18:57:50 +0200219 was_masked = msix_is_masked(dev, vector);
Michael S. Tsirkin76f51592009-10-26 16:22:44 +0200220 pci_set_long(dev->msix_table_page + offset, val);
Michael S. Tsirkinae392c42011-11-21 18:57:50 +0200221 msix_handle_mask_update(dev, vector, was_masked);
Michael S. Tsirkin02eb84d2009-06-21 19:49:54 +0300222}
223
Avi Kivity95524ae2011-08-08 16:09:26 +0300224static const MemoryRegionOps msix_mmio_ops = {
225 .read = msix_mmio_read,
226 .write = msix_mmio_write,
227 .endianness = DEVICE_NATIVE_ENDIAN,
228 .valid = {
229 .min_access_size = 4,
230 .max_access_size = 4,
231 },
Michael S. Tsirkin02eb84d2009-06-21 19:49:54 +0300232};
233
Avi Kivity95524ae2011-08-08 16:09:26 +0300234static void msix_mmio_setup(PCIDevice *d, MemoryRegion *bar)
Michael S. Tsirkin02eb84d2009-06-21 19:49:54 +0300235{
236 uint8_t *config = d->config + d->msix_cap;
Jan Kiszka01731cf2011-06-09 09:39:56 +0200237 uint32_t table = pci_get_long(config + PCI_MSIX_TABLE);
Michael S. Tsirkin5a1fc5e2009-09-29 18:53:26 +0200238 uint32_t offset = table & ~(MSIX_PAGE_SIZE - 1);
Michael S. Tsirkin02eb84d2009-06-21 19:49:54 +0300239 /* TODO: for assigned devices, we'll want to make it possible to map
240 * pending bits separately in case they are in a separate bar. */
Michael S. Tsirkin02eb84d2009-06-21 19:49:54 +0300241
Avi Kivity95524ae2011-08-08 16:09:26 +0300242 memory_region_add_subregion(bar, offset, &d->msix_mmio);
Michael S. Tsirkin02eb84d2009-06-21 19:49:54 +0300243}
244
Michael S. Tsirkinae1be0b2009-11-25 11:41:48 +0200245static void msix_mask_all(struct PCIDevice *dev, unsigned nentries)
246{
247 int vector;
Jan Kiszka5b5f1332012-05-17 10:32:30 -0300248
Michael S. Tsirkinae1be0b2009-11-25 11:41:48 +0200249 for (vector = 0; vector < nentries; ++vector) {
Jan Kiszka01731cf2011-06-09 09:39:56 +0200250 unsigned offset =
251 vector * PCI_MSIX_ENTRY_SIZE + PCI_MSIX_ENTRY_VECTOR_CTRL;
Jan Kiszka5b5f1332012-05-17 10:32:30 -0300252 bool was_masked = msix_is_masked(dev, vector);
253
Jan Kiszka01731cf2011-06-09 09:39:56 +0200254 dev->msix_table_page[offset] |= PCI_MSIX_ENTRY_CTRL_MASKBIT;
Jan Kiszka5b5f1332012-05-17 10:32:30 -0300255 msix_handle_mask_update(dev, vector, was_masked);
Michael S. Tsirkinae1be0b2009-11-25 11:41:48 +0200256 }
257}
258
Michael S. Tsirkin02eb84d2009-06-21 19:49:54 +0300259/* Initialize the MSI-X structures. Note: if MSI-X is supported, BAR size is
260 * modified, it should be retrieved with msix_bar_size. */
261int msix_init(struct PCIDevice *dev, unsigned short nentries,
Avi Kivity95524ae2011-08-08 16:09:26 +0300262 MemoryRegion *bar,
Michael S. Tsirkin5a1fc5e2009-09-29 18:53:26 +0200263 unsigned bar_nr, unsigned bar_size)
Michael S. Tsirkin02eb84d2009-06-21 19:49:54 +0300264{
265 int ret;
Michael S. Tsirkin02eb84d2009-06-21 19:49:54 +0300266
Jan Kiszka60ba3cc2011-10-15 14:33:17 +0200267 /* Nothing to do if MSI is not supported by interrupt controller */
268 if (!msi_supported) {
269 return -ENOTSUP;
270 }
Michael S. Tsirkin02eb84d2009-06-21 19:49:54 +0300271 if (nentries > MSIX_MAX_ENTRIES)
272 return -EINVAL;
273
Anthony Liguori7267c092011-08-20 22:09:37 -0500274 dev->msix_entry_used = g_malloc0(MSIX_MAX_ENTRIES *
Michael S. Tsirkin02eb84d2009-06-21 19:49:54 +0300275 sizeof *dev->msix_entry_used);
276
Anthony Liguori7267c092011-08-20 22:09:37 -0500277 dev->msix_table_page = g_malloc0(MSIX_PAGE_SIZE);
Michael S. Tsirkinae1be0b2009-11-25 11:41:48 +0200278 msix_mask_all(dev, nentries);
Michael S. Tsirkin02eb84d2009-06-21 19:49:54 +0300279
Avi Kivity95524ae2011-08-08 16:09:26 +0300280 memory_region_init_io(&dev->msix_mmio, &msix_mmio_ops, dev,
281 "msix", MSIX_PAGE_SIZE);
Michael S. Tsirkin02eb84d2009-06-21 19:49:54 +0300282
283 dev->msix_entries_nr = nentries;
284 ret = msix_add_config(dev, nentries, bar_nr, bar_size);
285 if (ret)
286 goto err_config;
287
288 dev->cap_present |= QEMU_PCI_CAP_MSIX;
Avi Kivity95524ae2011-08-08 16:09:26 +0300289 msix_mmio_setup(dev, bar);
Michael S. Tsirkin02eb84d2009-06-21 19:49:54 +0300290 return 0;
291
292err_config:
Michael S. Tsirkin3174ecd2009-07-22 18:51:14 +0300293 dev->msix_entries_nr = 0;
Avi Kivity95524ae2011-08-08 16:09:26 +0300294 memory_region_destroy(&dev->msix_mmio);
Anthony Liguori7267c092011-08-20 22:09:37 -0500295 g_free(dev->msix_table_page);
Michael S. Tsirkin02eb84d2009-06-21 19:49:54 +0300296 dev->msix_table_page = NULL;
Anthony Liguori7267c092011-08-20 22:09:37 -0500297 g_free(dev->msix_entry_used);
Michael S. Tsirkin02eb84d2009-06-21 19:49:54 +0300298 dev->msix_entry_used = NULL;
299 return ret;
300}
301
Alex Williamson53f94922012-06-14 12:15:51 -0600302int msix_init_exclusive_bar(PCIDevice *dev, unsigned short nentries,
303 uint8_t bar_nr)
304{
305 int ret;
306 char *name;
307
308 /*
309 * Migration compatibility dictates that this remains a 4k
310 * BAR with the vector table in the lower half and PBA in
311 * the upper half. Do not use these elsewhere!
312 */
313#define MSIX_EXCLUSIVE_BAR_SIZE 4096
314#define MSIX_EXCLUSIVE_BAR_PBA_OFFSET (MSIX_EXCLUSIVE_BAR_SIZE / 2)
315
316 if (nentries * PCI_MSIX_ENTRY_SIZE > MSIX_EXCLUSIVE_BAR_PBA_OFFSET) {
317 return -EINVAL;
318 }
319
320 if (asprintf(&name, "%s-msix", dev->name) == -1) {
321 return -ENOMEM;
322 }
323
324 memory_region_init(&dev->msix_exclusive_bar, name, MSIX_EXCLUSIVE_BAR_SIZE);
325
326 free(name);
327
328 ret = msix_init(dev, nentries, &dev->msix_exclusive_bar, bar_nr,
329 MSIX_EXCLUSIVE_BAR_SIZE);
330 if (ret) {
331 memory_region_destroy(&dev->msix_exclusive_bar);
332 return ret;
333 }
334
335 pci_register_bar(dev, bar_nr, PCI_BASE_ADDRESS_SPACE_MEMORY,
336 &dev->msix_exclusive_bar);
337
338 return 0;
339}
340
Michael S. Tsirkin98304c82009-11-25 12:24:14 +0200341static void msix_free_irq_entries(PCIDevice *dev)
342{
343 int vector;
344
345 for (vector = 0; vector < dev->msix_entries_nr; ++vector) {
346 dev->msix_entry_used[vector] = 0;
347 msix_clr_pending(dev, vector);
348 }
349}
350
Michael S. Tsirkin02eb84d2009-06-21 19:49:54 +0300351/* Clean up resources for the device. */
Avi Kivity95524ae2011-08-08 16:09:26 +0300352int msix_uninit(PCIDevice *dev, MemoryRegion *bar)
Michael S. Tsirkin02eb84d2009-06-21 19:49:54 +0300353{
Jan Kiszka44701ab2012-06-04 16:53:48 +0200354 if (!msix_present(dev)) {
Michael S. Tsirkin02eb84d2009-06-21 19:49:54 +0300355 return 0;
Jan Kiszka44701ab2012-06-04 16:53:48 +0200356 }
Michael S. Tsirkin02eb84d2009-06-21 19:49:54 +0300357 pci_del_capability(dev, PCI_CAP_ID_MSIX, MSIX_CAP_LENGTH);
358 dev->msix_cap = 0;
359 msix_free_irq_entries(dev);
360 dev->msix_entries_nr = 0;
Avi Kivity95524ae2011-08-08 16:09:26 +0300361 memory_region_del_subregion(bar, &dev->msix_mmio);
362 memory_region_destroy(&dev->msix_mmio);
Anthony Liguori7267c092011-08-20 22:09:37 -0500363 g_free(dev->msix_table_page);
Michael S. Tsirkin02eb84d2009-06-21 19:49:54 +0300364 dev->msix_table_page = NULL;
Anthony Liguori7267c092011-08-20 22:09:37 -0500365 g_free(dev->msix_entry_used);
Michael S. Tsirkin02eb84d2009-06-21 19:49:54 +0300366 dev->msix_entry_used = NULL;
367 dev->cap_present &= ~QEMU_PCI_CAP_MSIX;
368 return 0;
369}
370
Alex Williamson53f94922012-06-14 12:15:51 -0600371void msix_uninit_exclusive_bar(PCIDevice *dev)
372{
373 if (msix_present(dev)) {
374 msix_uninit(dev, &dev->msix_exclusive_bar);
375 memory_region_destroy(&dev->msix_exclusive_bar);
376 }
377}
378
Michael S. Tsirkin02eb84d2009-06-21 19:49:54 +0300379void msix_save(PCIDevice *dev, QEMUFile *f)
380{
Michael S. Tsirkin9a3e12c2009-07-01 16:28:00 +0300381 unsigned n = dev->msix_entries_nr;
382
Jan Kiszka44701ab2012-06-04 16:53:48 +0200383 if (!msix_present(dev)) {
Michael S. Tsirkin9a3e12c2009-07-01 16:28:00 +0300384 return;
Michael S. Tsirkin72755a72009-07-05 15:58:52 +0300385 }
Michael S. Tsirkin9a3e12c2009-07-01 16:28:00 +0300386
Jan Kiszka01731cf2011-06-09 09:39:56 +0200387 qemu_put_buffer(f, dev->msix_table_page, n * PCI_MSIX_ENTRY_SIZE);
Michael S. Tsirkin5a1fc5e2009-09-29 18:53:26 +0200388 qemu_put_buffer(f, dev->msix_table_page + MSIX_PAGE_PENDING, (n + 7) / 8);
Michael S. Tsirkin02eb84d2009-06-21 19:49:54 +0300389}
390
391/* Should be called after restoring the config space. */
392void msix_load(PCIDevice *dev, QEMUFile *f)
393{
394 unsigned n = dev->msix_entries_nr;
Jan Kiszka2cdfe532012-05-17 10:32:31 -0300395 unsigned int vector;
Michael S. Tsirkin02eb84d2009-06-21 19:49:54 +0300396
Jan Kiszka44701ab2012-06-04 16:53:48 +0200397 if (!msix_present(dev)) {
Michael S. Tsirkin02eb84d2009-06-21 19:49:54 +0300398 return;
Blue Swirl98846d72009-07-05 08:11:39 +0000399 }
Michael S. Tsirkin02eb84d2009-06-21 19:49:54 +0300400
Michael S. Tsirkin4bfd1712009-07-05 15:58:44 +0300401 msix_free_irq_entries(dev);
Jan Kiszka01731cf2011-06-09 09:39:56 +0200402 qemu_get_buffer(f, dev->msix_table_page, n * PCI_MSIX_ENTRY_SIZE);
Michael S. Tsirkin5a1fc5e2009-09-29 18:53:26 +0200403 qemu_get_buffer(f, dev->msix_table_page + MSIX_PAGE_PENDING, (n + 7) / 8);
Michael S. Tsirkin50322242011-11-21 18:57:21 +0200404 msix_update_function_masked(dev);
Jan Kiszka2cdfe532012-05-17 10:32:31 -0300405
406 for (vector = 0; vector < n; vector++) {
407 msix_handle_mask_update(dev, vector, true);
408 }
Michael S. Tsirkin02eb84d2009-06-21 19:49:54 +0300409}
410
411/* Does device support MSI-X? */
412int msix_present(PCIDevice *dev)
413{
414 return dev->cap_present & QEMU_PCI_CAP_MSIX;
415}
416
417/* Is MSI-X enabled? */
418int msix_enabled(PCIDevice *dev)
419{
420 return (dev->cap_present & QEMU_PCI_CAP_MSIX) &&
Michael S. Tsirkin27609522009-11-25 12:18:00 +0200421 (dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] &
Michael S. Tsirkin02eb84d2009-06-21 19:49:54 +0300422 MSIX_ENABLE_MASK);
423}
424
Michael S. Tsirkin02eb84d2009-06-21 19:49:54 +0300425/* Send an MSI-X message */
426void msix_notify(PCIDevice *dev, unsigned vector)
427{
Jan Kiszkabc4caf42012-05-17 10:32:29 -0300428 MSIMessage msg;
Michael S. Tsirkin02eb84d2009-06-21 19:49:54 +0300429
430 if (vector >= dev->msix_entries_nr || !dev->msix_entry_used[vector])
431 return;
432 if (msix_is_masked(dev, vector)) {
433 msix_set_pending(dev, vector);
434 return;
435 }
436
Jan Kiszkabc4caf42012-05-17 10:32:29 -0300437 msg = msix_get_message(dev, vector);
438
439 stl_le_phys(msg.address, msg.data);
Michael S. Tsirkin02eb84d2009-06-21 19:49:54 +0300440}
441
442void msix_reset(PCIDevice *dev)
443{
Jan Kiszka44701ab2012-06-04 16:53:48 +0200444 if (!msix_present(dev)) {
Michael S. Tsirkin02eb84d2009-06-21 19:49:54 +0300445 return;
Jan Kiszka44701ab2012-06-04 16:53:48 +0200446 }
Michael S. Tsirkin02eb84d2009-06-21 19:49:54 +0300447 msix_free_irq_entries(dev);
Michael S. Tsirkin27609522009-11-25 12:18:00 +0200448 dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] &=
449 ~dev->wmask[dev->msix_cap + MSIX_CONTROL_OFFSET];
Michael S. Tsirkin5a1fc5e2009-09-29 18:53:26 +0200450 memset(dev->msix_table_page, 0, MSIX_PAGE_SIZE);
Michael S. Tsirkinae1be0b2009-11-25 11:41:48 +0200451 msix_mask_all(dev, dev->msix_entries_nr);
Michael S. Tsirkin02eb84d2009-06-21 19:49:54 +0300452}
453
454/* PCI spec suggests that devices make it possible for software to configure
455 * less vectors than supported by the device, but does not specify a standard
456 * mechanism for devices to do so.
457 *
458 * We support this by asking devices to declare vectors software is going to
459 * actually use, and checking this on the notification path. Devices that
460 * don't want to follow the spec suggestion can declare all vectors as used. */
461
462/* Mark vector as used. */
463int msix_vector_use(PCIDevice *dev, unsigned vector)
464{
465 if (vector >= dev->msix_entries_nr)
466 return -EINVAL;
467 dev->msix_entry_used[vector]++;
468 return 0;
469}
470
471/* Mark vector as unused. */
472void msix_vector_unuse(PCIDevice *dev, unsigned vector)
473{
Michael S. Tsirkin98304c82009-11-25 12:24:14 +0200474 if (vector >= dev->msix_entries_nr || !dev->msix_entry_used[vector]) {
475 return;
476 }
477 if (--dev->msix_entry_used[vector]) {
478 return;
479 }
480 msix_clr_pending(dev, vector);
Michael S. Tsirkin02eb84d2009-06-21 19:49:54 +0300481}
Michael S. Tsirkinb5f28bc2009-11-24 16:44:15 +0200482
483void msix_unuse_all_vectors(PCIDevice *dev)
484{
Jan Kiszka44701ab2012-06-04 16:53:48 +0200485 if (!msix_present(dev)) {
Michael S. Tsirkinb5f28bc2009-11-24 16:44:15 +0200486 return;
Jan Kiszka44701ab2012-06-04 16:53:48 +0200487 }
Michael S. Tsirkinb5f28bc2009-11-24 16:44:15 +0200488 msix_free_irq_entries(dev);
489}
Jan Kiszka2cdfe532012-05-17 10:32:31 -0300490
Jan Kiszkacb697aa2012-05-17 10:32:38 -0300491unsigned int msix_nr_vectors_allocated(const PCIDevice *dev)
492{
493 return dev->msix_entries_nr;
494}
495
Jan Kiszka2cdfe532012-05-17 10:32:31 -0300496static int msix_set_notifier_for_vector(PCIDevice *dev, unsigned int vector)
497{
498 MSIMessage msg;
499
500 if (msix_is_masked(dev, vector)) {
501 return 0;
502 }
503 msg = msix_get_message(dev, vector);
504 return dev->msix_vector_use_notifier(dev, vector, msg);
505}
506
507static void msix_unset_notifier_for_vector(PCIDevice *dev, unsigned int vector)
508{
509 if (msix_is_masked(dev, vector)) {
510 return;
511 }
512 dev->msix_vector_release_notifier(dev, vector);
513}
514
515int msix_set_vector_notifiers(PCIDevice *dev,
516 MSIVectorUseNotifier use_notifier,
517 MSIVectorReleaseNotifier release_notifier)
518{
519 int vector, ret;
520
521 assert(use_notifier && release_notifier);
522
523 dev->msix_vector_use_notifier = use_notifier;
524 dev->msix_vector_release_notifier = release_notifier;
525
526 if ((dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] &
527 (MSIX_ENABLE_MASK | MSIX_MASKALL_MASK)) == MSIX_ENABLE_MASK) {
528 for (vector = 0; vector < dev->msix_entries_nr; vector++) {
529 ret = msix_set_notifier_for_vector(dev, vector);
530 if (ret < 0) {
531 goto undo;
532 }
533 }
534 }
535 return 0;
536
537undo:
538 while (--vector >= 0) {
539 msix_unset_notifier_for_vector(dev, vector);
540 }
541 dev->msix_vector_use_notifier = NULL;
542 dev->msix_vector_release_notifier = NULL;
543 return ret;
544}
545
546void msix_unset_vector_notifiers(PCIDevice *dev)
547{
548 int vector;
549
550 assert(dev->msix_vector_use_notifier &&
551 dev->msix_vector_release_notifier);
552
553 if ((dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] &
554 (MSIX_ENABLE_MASK | MSIX_MASKALL_MASK)) == MSIX_ENABLE_MASK) {
555 for (vector = 0; vector < dev->msix_entries_nr; vector++) {
556 msix_unset_notifier_for_vector(dev, vector);
557 }
558 }
559 dev->msix_vector_use_notifier = NULL;
560 dev->msix_vector_release_notifier = NULL;
561}