aboutsummaryrefslogtreecommitdiff
path: root/hw/msix.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/msix.c')
-rw-r--r--hw/msix.c47
1 files changed, 47 insertions, 0 deletions
diff --git a/hw/msix.c b/hw/msix.c
index b64f109326..bafea94084 100644
--- a/hw/msix.c
+++ b/hw/msix.c
@@ -299,6 +299,45 @@ err_config:
return ret;
}
+int msix_init_exclusive_bar(PCIDevice *dev, unsigned short nentries,
+ uint8_t bar_nr)
+{
+ int ret;
+ char *name;
+
+ /*
+ * Migration compatibility dictates that this remains a 4k
+ * BAR with the vector table in the lower half and PBA in
+ * the upper half. Do not use these elsewhere!
+ */
+#define MSIX_EXCLUSIVE_BAR_SIZE 4096
+#define MSIX_EXCLUSIVE_BAR_PBA_OFFSET (MSIX_EXCLUSIVE_BAR_SIZE / 2)
+
+ if (nentries * PCI_MSIX_ENTRY_SIZE > MSIX_EXCLUSIVE_BAR_PBA_OFFSET) {
+ return -EINVAL;
+ }
+
+ if (asprintf(&name, "%s-msix", dev->name) == -1) {
+ return -ENOMEM;
+ }
+
+ memory_region_init(&dev->msix_exclusive_bar, name, MSIX_EXCLUSIVE_BAR_SIZE);
+
+ free(name);
+
+ ret = msix_init(dev, nentries, &dev->msix_exclusive_bar, bar_nr,
+ MSIX_EXCLUSIVE_BAR_SIZE);
+ if (ret) {
+ memory_region_destroy(&dev->msix_exclusive_bar);
+ return ret;
+ }
+
+ pci_register_bar(dev, bar_nr, PCI_BASE_ADDRESS_SPACE_MEMORY,
+ &dev->msix_exclusive_bar);
+
+ return 0;
+}
+
static void msix_free_irq_entries(PCIDevice *dev)
{
int vector;
@@ -329,6 +368,14 @@ int msix_uninit(PCIDevice *dev, MemoryRegion *bar)
return 0;
}
+void msix_uninit_exclusive_bar(PCIDevice *dev)
+{
+ if (msix_present(dev)) {
+ msix_uninit(dev, &dev->msix_exclusive_bar);
+ memory_region_destroy(&dev->msix_exclusive_bar);
+ }
+}
+
void msix_save(PCIDevice *dev, QEMUFile *f)
{
unsigned n = dev->msix_entries_nr;