qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

xen_pt_msi.c (18418B)


      1 /*
      2  * Copyright (c) 2007, Intel Corporation.
      3  *
      4  * This work is licensed under the terms of the GNU GPL, version 2.  See
      5  * the COPYING file in the top-level directory.
      6  *
      7  * Jiang Yunhong <yunhong.jiang@intel.com>
      8  *
      9  * This file implements direct PCI assignment to a HVM guest
     10  */
     11 
     12 #include "qemu/osdep.h"
     13 
     14 #include "hw/xen/xen-legacy-backend.h"
     15 #include "xen_pt.h"
     16 #include "hw/i386/apic-msidef.h"
     17 
     18 
     19 #define XEN_PT_AUTO_ASSIGN -1
     20 
     21 /* shift count for gflags */
     22 #define XEN_PT_GFLAGS_SHIFT_DEST_ID        0
     23 #define XEN_PT_GFLAGS_SHIFT_RH             8
     24 #define XEN_PT_GFLAGS_SHIFT_DM             9
     25 #define XEN_PT_GFLAGSSHIFT_DELIV_MODE     12
     26 #define XEN_PT_GFLAGSSHIFT_TRG_MODE       15
     27 #define XEN_PT_GFLAGSSHIFT_UNMASKED       16
     28 
     29 #define latch(fld) latch[PCI_MSIX_ENTRY_##fld / sizeof(uint32_t)]
     30 
     31 /*
     32  * Helpers
     33  */
     34 
     35 static inline uint8_t msi_vector(uint32_t data)
     36 {
     37     return (data & MSI_DATA_VECTOR_MASK) >> MSI_DATA_VECTOR_SHIFT;
     38 }
     39 
     40 static inline uint8_t msi_dest_id(uint32_t addr)
     41 {
     42     return (addr & MSI_ADDR_DEST_ID_MASK) >> MSI_ADDR_DEST_ID_SHIFT;
     43 }
     44 
     45 static inline uint32_t msi_ext_dest_id(uint32_t addr_hi)
     46 {
     47     return addr_hi & 0xffffff00;
     48 }
     49 
     50 static uint32_t msi_gflags(uint32_t data, uint64_t addr)
     51 {
     52     uint32_t result = 0;
     53     int rh, dm, dest_id, deliv_mode, trig_mode;
     54 
     55     rh = (addr >> MSI_ADDR_REDIRECTION_SHIFT) & 0x1;
     56     dm = (addr >> MSI_ADDR_DEST_MODE_SHIFT) & 0x1;
     57     dest_id = msi_dest_id(addr);
     58     deliv_mode = (data >> MSI_DATA_DELIVERY_MODE_SHIFT) & 0x7;
     59     trig_mode = (data >> MSI_DATA_TRIGGER_SHIFT) & 0x1;
     60 
     61     result = dest_id | (rh << XEN_PT_GFLAGS_SHIFT_RH)
     62         | (dm << XEN_PT_GFLAGS_SHIFT_DM)
     63         | (deliv_mode << XEN_PT_GFLAGSSHIFT_DELIV_MODE)
     64         | (trig_mode << XEN_PT_GFLAGSSHIFT_TRG_MODE);
     65 
     66     return result;
     67 }
     68 
     69 static inline uint64_t msi_addr64(XenPTMSI *msi)
     70 {
     71     return (uint64_t)msi->addr_hi << 32 | msi->addr_lo;
     72 }
     73 
     74 static int msi_msix_enable(XenPCIPassthroughState *s,
     75                            uint32_t address,
     76                            uint16_t flag,
     77                            bool enable)
     78 {
     79     uint16_t val = 0;
     80     int rc;
     81 
     82     if (!address) {
     83         return -1;
     84     }
     85 
     86     rc = xen_host_pci_get_word(&s->real_device, address, &val);
     87     if (rc) {
     88         XEN_PT_ERR(&s->dev, "Failed to read MSI/MSI-X register (0x%x), rc:%d\n",
     89                    address, rc);
     90         return rc;
     91     }
     92     if (enable) {
     93         val |= flag;
     94     } else {
     95         val &= ~flag;
     96     }
     97     rc = xen_host_pci_set_word(&s->real_device, address, val);
     98     if (rc) {
     99         XEN_PT_ERR(&s->dev, "Failed to write MSI/MSI-X register (0x%x), rc:%d\n",
    100                    address, rc);
    101     }
    102     return rc;
    103 }
    104 
    105 static int msi_msix_setup(XenPCIPassthroughState *s,
    106                           uint64_t addr,
    107                           uint32_t data,
    108                           int *ppirq,
    109                           bool is_msix,
    110                           int msix_entry,
    111                           bool is_not_mapped)
    112 {
    113     uint8_t gvec = msi_vector(data);
    114     int rc = 0;
    115 
    116     assert((!is_msix && msix_entry == 0) || is_msix);
    117 
    118     if (xen_is_pirq_msi(data)) {
    119         *ppirq = msi_ext_dest_id(addr >> 32) | msi_dest_id(addr);
    120         if (!*ppirq) {
    121             /* this probably identifies an misconfiguration of the guest,
    122              * try the emulated path */
    123             *ppirq = XEN_PT_UNASSIGNED_PIRQ;
    124         } else {
    125             XEN_PT_LOG(&s->dev, "requested pirq %d for MSI%s"
    126                        " (vec: 0x%x, entry: 0x%x)\n",
    127                        *ppirq, is_msix ? "-X" : "", gvec, msix_entry);
    128         }
    129     }
    130 
    131     if (is_not_mapped) {
    132         uint64_t table_base = 0;
    133 
    134         if (is_msix) {
    135             table_base = s->msix->table_base;
    136         }
    137 
    138         rc = xc_physdev_map_pirq_msi(xen_xc, xen_domid, XEN_PT_AUTO_ASSIGN,
    139                                      ppirq, PCI_DEVFN(s->real_device.dev,
    140                                                       s->real_device.func),
    141                                      s->real_device.bus,
    142                                      msix_entry, table_base);
    143         if (rc) {
    144             XEN_PT_ERR(&s->dev,
    145                        "Mapping of MSI%s (err: %i, vec: 0x%x, entry 0x%x)\n",
    146                        is_msix ? "-X" : "", errno, gvec, msix_entry);
    147             return rc;
    148         }
    149     }
    150 
    151     return 0;
    152 }
    153 static int msi_msix_update(XenPCIPassthroughState *s,
    154                            uint64_t addr,
    155                            uint32_t data,
    156                            int pirq,
    157                            bool is_msix,
    158                            int msix_entry,
    159                            int *old_pirq,
    160                            bool masked)
    161 {
    162     PCIDevice *d = &s->dev;
    163     uint8_t gvec = msi_vector(data);
    164     uint32_t gflags = msi_gflags(data, addr);
    165     int rc = 0;
    166     uint64_t table_addr = 0;
    167 
    168     XEN_PT_LOG(d, "Updating MSI%s with pirq %d gvec 0x%x gflags 0x%x"
    169                " (entry: 0x%x)\n",
    170                is_msix ? "-X" : "", pirq, gvec, gflags, msix_entry);
    171 
    172     if (is_msix) {
    173         table_addr = s->msix->mmio_base_addr;
    174     }
    175 
    176     gflags |= masked ? 0 : (1u << XEN_PT_GFLAGSSHIFT_UNMASKED);
    177 
    178     rc = xc_domain_update_msi_irq(xen_xc, xen_domid, gvec,
    179                                   pirq, gflags, table_addr);
    180 
    181     if (rc) {
    182         XEN_PT_ERR(d, "Updating of MSI%s failed. (err: %d)\n",
    183                    is_msix ? "-X" : "", errno);
    184 
    185         if (xc_physdev_unmap_pirq(xen_xc, xen_domid, *old_pirq)) {
    186             XEN_PT_ERR(d, "Unmapping of MSI%s pirq %d failed. (err: %d)\n",
    187                        is_msix ? "-X" : "", *old_pirq, errno);
    188         }
    189         *old_pirq = XEN_PT_UNASSIGNED_PIRQ;
    190     }
    191     return rc;
    192 }
    193 
    194 static int msi_msix_disable(XenPCIPassthroughState *s,
    195                             uint64_t addr,
    196                             uint32_t data,
    197                             int pirq,
    198                             bool is_msix,
    199                             bool is_binded)
    200 {
    201     PCIDevice *d = &s->dev;
    202     uint8_t gvec = msi_vector(data);
    203     uint32_t gflags = msi_gflags(data, addr);
    204     int rc = 0;
    205 
    206     if (pirq == XEN_PT_UNASSIGNED_PIRQ) {
    207         return 0;
    208     }
    209 
    210     if (is_binded) {
    211         XEN_PT_LOG(d, "Unbind MSI%s with pirq %d, gvec 0x%x\n",
    212                    is_msix ? "-X" : "", pirq, gvec);
    213         rc = xc_domain_unbind_msi_irq(xen_xc, xen_domid, gvec, pirq, gflags);
    214         if (rc) {
    215             XEN_PT_ERR(d, "Unbinding of MSI%s failed. (err: %d, pirq: %d, gvec: 0x%x)\n",
    216                        is_msix ? "-X" : "", errno, pirq, gvec);
    217             return rc;
    218         }
    219     }
    220 
    221     XEN_PT_LOG(d, "Unmap MSI%s pirq %d\n", is_msix ? "-X" : "", pirq);
    222     rc = xc_physdev_unmap_pirq(xen_xc, xen_domid, pirq);
    223     if (rc) {
    224         XEN_PT_ERR(d, "Unmapping of MSI%s pirq %d failed. (err: %i)\n",
    225                    is_msix ? "-X" : "", pirq, errno);
    226         return rc;
    227     }
    228 
    229     return 0;
    230 }
    231 
    232 /*
    233  * MSI virtualization functions
    234  */
    235 
    236 static int xen_pt_msi_set_enable(XenPCIPassthroughState *s, bool enable)
    237 {
    238     XEN_PT_LOG(&s->dev, "%s MSI.\n", enable ? "enabling" : "disabling");
    239 
    240     if (!s->msi) {
    241         return -1;
    242     }
    243 
    244     return msi_msix_enable(s, s->msi->ctrl_offset, PCI_MSI_FLAGS_ENABLE,
    245                            enable);
    246 }
    247 
    248 /* setup physical msi, but don't enable it */
    249 int xen_pt_msi_setup(XenPCIPassthroughState *s)
    250 {
    251     int pirq = XEN_PT_UNASSIGNED_PIRQ;
    252     int rc = 0;
    253     XenPTMSI *msi = s->msi;
    254 
    255     if (msi->initialized) {
    256         XEN_PT_ERR(&s->dev,
    257                    "Setup physical MSI when it has been properly initialized.\n");
    258         return -1;
    259     }
    260 
    261     rc = msi_msix_setup(s, msi_addr64(msi), msi->data, &pirq, false, 0, true);
    262     if (rc) {
    263         return rc;
    264     }
    265 
    266     if (pirq < 0) {
    267         XEN_PT_ERR(&s->dev, "Invalid pirq number: %d.\n", pirq);
    268         return -1;
    269     }
    270 
    271     msi->pirq = pirq;
    272     XEN_PT_LOG(&s->dev, "MSI mapped with pirq %d.\n", pirq);
    273 
    274     return 0;
    275 }
    276 
    277 int xen_pt_msi_update(XenPCIPassthroughState *s)
    278 {
    279     XenPTMSI *msi = s->msi;
    280 
    281     /* Current MSI emulation in QEMU only supports 1 vector */
    282     return msi_msix_update(s, msi_addr64(msi), msi->data, msi->pirq,
    283                            false, 0, &msi->pirq, msi->mask & 1);
    284 }
    285 
    286 void xen_pt_msi_disable(XenPCIPassthroughState *s)
    287 {
    288     XenPTMSI *msi = s->msi;
    289 
    290     if (!msi) {
    291         return;
    292     }
    293 
    294     (void)xen_pt_msi_set_enable(s, false);
    295 
    296     msi_msix_disable(s, msi_addr64(msi), msi->data, msi->pirq, false,
    297                      msi->initialized);
    298 
    299     /* clear msi info */
    300     msi->flags &= ~PCI_MSI_FLAGS_ENABLE;
    301     msi->initialized = false;
    302     msi->mapped = false;
    303     msi->pirq = XEN_PT_UNASSIGNED_PIRQ;
    304 }
    305 
    306 /*
    307  * MSI-X virtualization functions
    308  */
    309 
    310 static int msix_set_enable(XenPCIPassthroughState *s, bool enabled)
    311 {
    312     XEN_PT_LOG(&s->dev, "%s MSI-X.\n", enabled ? "enabling" : "disabling");
    313 
    314     if (!s->msix) {
    315         return -1;
    316     }
    317 
    318     return msi_msix_enable(s, s->msix->ctrl_offset, PCI_MSIX_FLAGS_ENABLE,
    319                            enabled);
    320 }
    321 
    322 static int xen_pt_msix_update_one(XenPCIPassthroughState *s, int entry_nr,
    323                                   uint32_t vec_ctrl)
    324 {
    325     XenPTMSIXEntry *entry = NULL;
    326     int pirq;
    327     int rc;
    328 
    329     if (entry_nr < 0 || entry_nr >= s->msix->total_entries) {
    330         return -EINVAL;
    331     }
    332 
    333     entry = &s->msix->msix_entry[entry_nr];
    334 
    335     if (!entry->updated) {
    336         return 0;
    337     }
    338 
    339     pirq = entry->pirq;
    340 
    341     /*
    342      * Update the entry addr and data to the latest values only when the
    343      * entry is masked or they are all masked, as required by the spec.
    344      * Addr and data changes while the MSI-X entry is unmasked get deferred
    345      * until the next masked -> unmasked transition.
    346      */
    347     if (pirq == XEN_PT_UNASSIGNED_PIRQ || s->msix->maskall ||
    348         (vec_ctrl & PCI_MSIX_ENTRY_CTRL_MASKBIT)) {
    349         entry->addr = entry->latch(LOWER_ADDR) |
    350                       ((uint64_t)entry->latch(UPPER_ADDR) << 32);
    351         entry->data = entry->latch(DATA);
    352     }
    353 
    354     rc = msi_msix_setup(s, entry->addr, entry->data, &pirq, true, entry_nr,
    355                         entry->pirq == XEN_PT_UNASSIGNED_PIRQ);
    356     if (rc) {
    357         return rc;
    358     }
    359     if (entry->pirq == XEN_PT_UNASSIGNED_PIRQ) {
    360         entry->pirq = pirq;
    361     }
    362 
    363     rc = msi_msix_update(s, entry->addr, entry->data, pirq, true,
    364                          entry_nr, &entry->pirq,
    365                          vec_ctrl & PCI_MSIX_ENTRY_CTRL_MASKBIT);
    366 
    367     if (!rc) {
    368         entry->updated = false;
    369     }
    370 
    371     return rc;
    372 }
    373 
    374 int xen_pt_msix_update(XenPCIPassthroughState *s)
    375 {
    376     XenPTMSIX *msix = s->msix;
    377     int i;
    378 
    379     for (i = 0; i < msix->total_entries; i++) {
    380         xen_pt_msix_update_one(s, i, msix->msix_entry[i].latch(VECTOR_CTRL));
    381     }
    382 
    383     return 0;
    384 }
    385 
    386 void xen_pt_msix_disable(XenPCIPassthroughState *s)
    387 {
    388     int i = 0;
    389 
    390     msix_set_enable(s, false);
    391 
    392     for (i = 0; i < s->msix->total_entries; i++) {
    393         XenPTMSIXEntry *entry = &s->msix->msix_entry[i];
    394 
    395         msi_msix_disable(s, entry->addr, entry->data, entry->pirq, true, true);
    396 
    397         /* clear MSI-X info */
    398         entry->pirq = XEN_PT_UNASSIGNED_PIRQ;
    399         entry->updated = false;
    400     }
    401 }
    402 
    403 int xen_pt_msix_update_remap(XenPCIPassthroughState *s, int bar_index)
    404 {
    405     XenPTMSIXEntry *entry;
    406     int i, ret;
    407 
    408     if (!(s->msix && s->msix->bar_index == bar_index)) {
    409         return 0;
    410     }
    411 
    412     for (i = 0; i < s->msix->total_entries; i++) {
    413         entry = &s->msix->msix_entry[i];
    414         if (entry->pirq != XEN_PT_UNASSIGNED_PIRQ) {
    415             ret = xc_domain_unbind_pt_irq(xen_xc, xen_domid, entry->pirq,
    416                                           PT_IRQ_TYPE_MSI, 0, 0, 0, 0);
    417             if (ret) {
    418                 XEN_PT_ERR(&s->dev, "unbind MSI-X entry %d failed (err: %d)\n",
    419                            entry->pirq, errno);
    420             }
    421             entry->updated = true;
    422         }
    423     }
    424     return xen_pt_msix_update(s);
    425 }
    426 
    427 static uint32_t get_entry_value(XenPTMSIXEntry *e, int offset)
    428 {
    429     assert(!(offset % sizeof(*e->latch)));
    430     return e->latch[offset / sizeof(*e->latch)];
    431 }
    432 
    433 static void set_entry_value(XenPTMSIXEntry *e, int offset, uint32_t val)
    434 {
    435     assert(!(offset % sizeof(*e->latch)));
    436     e->latch[offset / sizeof(*e->latch)] = val;
    437 }
    438 
    439 static void pci_msix_write(void *opaque, hwaddr addr,
    440                            uint64_t val, unsigned size)
    441 {
    442     XenPCIPassthroughState *s = opaque;
    443     XenPTMSIX *msix = s->msix;
    444     XenPTMSIXEntry *entry;
    445     unsigned int entry_nr, offset;
    446 
    447     entry_nr = addr / PCI_MSIX_ENTRY_SIZE;
    448     if (entry_nr >= msix->total_entries) {
    449         return;
    450     }
    451     entry = &msix->msix_entry[entry_nr];
    452     offset = addr % PCI_MSIX_ENTRY_SIZE;
    453 
    454     if (offset != PCI_MSIX_ENTRY_VECTOR_CTRL) {
    455         if (get_entry_value(entry, offset) == val
    456             && entry->pirq != XEN_PT_UNASSIGNED_PIRQ) {
    457             return;
    458         }
    459 
    460         entry->updated = true;
    461     } else if (msix->enabled && entry->updated &&
    462                !(val & PCI_MSIX_ENTRY_CTRL_MASKBIT)) {
    463         const volatile uint32_t *vec_ctrl;
    464 
    465         /*
    466          * If Xen intercepts the mask bit access, entry->vec_ctrl may not be
    467          * up-to-date. Read from hardware directly.
    468          */
    469         vec_ctrl = s->msix->phys_iomem_base + entry_nr * PCI_MSIX_ENTRY_SIZE
    470             + PCI_MSIX_ENTRY_VECTOR_CTRL;
    471         xen_pt_msix_update_one(s, entry_nr, *vec_ctrl);
    472     }
    473 
    474     set_entry_value(entry, offset, val);
    475 }
    476 
    477 static uint64_t pci_msix_read(void *opaque, hwaddr addr,
    478                               unsigned size)
    479 {
    480     XenPCIPassthroughState *s = opaque;
    481     XenPTMSIX *msix = s->msix;
    482     int entry_nr, offset;
    483 
    484     entry_nr = addr / PCI_MSIX_ENTRY_SIZE;
    485     if (entry_nr < 0) {
    486         XEN_PT_ERR(&s->dev, "asked MSI-X entry '%i' invalid!\n", entry_nr);
    487         return 0;
    488     }
    489 
    490     offset = addr % PCI_MSIX_ENTRY_SIZE;
    491 
    492     if (addr < msix->total_entries * PCI_MSIX_ENTRY_SIZE) {
    493         return get_entry_value(&msix->msix_entry[entry_nr], offset);
    494     } else {
    495         /* Pending Bit Array (PBA) */
    496         return *(uint32_t *)(msix->phys_iomem_base + addr);
    497     }
    498 }
    499 
    500 static bool pci_msix_accepts(void *opaque, hwaddr addr,
    501                              unsigned size, bool is_write,
    502                              MemTxAttrs attrs)
    503 {
    504     return !(addr & (size - 1));
    505 }
    506 
    507 static const MemoryRegionOps pci_msix_ops = {
    508     .read = pci_msix_read,
    509     .write = pci_msix_write,
    510     .endianness = DEVICE_NATIVE_ENDIAN,
    511     .valid = {
    512         .min_access_size = 4,
    513         .max_access_size = 4,
    514         .unaligned = false,
    515         .accepts = pci_msix_accepts
    516     },
    517     .impl = {
    518         .min_access_size = 4,
    519         .max_access_size = 4,
    520         .unaligned = false
    521     }
    522 };
    523 
    524 int xen_pt_msix_init(XenPCIPassthroughState *s, uint32_t base)
    525 {
    526     uint8_t id = 0;
    527     uint16_t control = 0;
    528     uint32_t table_off = 0;
    529     int i, total_entries, bar_index;
    530     XenHostPCIDevice *hd = &s->real_device;
    531     PCIDevice *d = &s->dev;
    532     int fd = -1;
    533     XenPTMSIX *msix = NULL;
    534     int rc = 0;
    535 
    536     rc = xen_host_pci_get_byte(hd, base + PCI_CAP_LIST_ID, &id);
    537     if (rc) {
    538         return rc;
    539     }
    540 
    541     if (id != PCI_CAP_ID_MSIX) {
    542         XEN_PT_ERR(d, "Invalid id 0x%x base 0x%x\n", id, base);
    543         return -1;
    544     }
    545 
    546     rc = xen_host_pci_get_word(hd, base + PCI_MSIX_FLAGS, &control);
    547     if (rc) {
    548         XEN_PT_ERR(d, "Failed to read PCI_MSIX_FLAGS field\n");
    549         return rc;
    550     }
    551     total_entries = control & PCI_MSIX_FLAGS_QSIZE;
    552     total_entries += 1;
    553 
    554     s->msix = g_malloc0(sizeof (XenPTMSIX)
    555                         + total_entries * sizeof (XenPTMSIXEntry));
    556     msix = s->msix;
    557 
    558     msix->total_entries = total_entries;
    559     for (i = 0; i < total_entries; i++) {
    560         msix->msix_entry[i].pirq = XEN_PT_UNASSIGNED_PIRQ;
    561     }
    562 
    563     memory_region_init_io(&msix->mmio, OBJECT(s), &pci_msix_ops,
    564                           s, "xen-pci-pt-msix",
    565                           (total_entries * PCI_MSIX_ENTRY_SIZE
    566                            + XC_PAGE_SIZE - 1)
    567                           & XC_PAGE_MASK);
    568 
    569     rc = xen_host_pci_get_long(hd, base + PCI_MSIX_TABLE, &table_off);
    570     if (rc) {
    571         XEN_PT_ERR(d, "Failed to read PCI_MSIX_TABLE field\n");
    572         goto error_out;
    573     }
    574     bar_index = msix->bar_index = table_off & PCI_MSIX_FLAGS_BIRMASK;
    575     table_off = table_off & ~PCI_MSIX_FLAGS_BIRMASK;
    576     msix->table_base = s->real_device.io_regions[bar_index].base_addr;
    577     XEN_PT_LOG(d, "get MSI-X table BAR base 0x%"PRIx64"\n", msix->table_base);
    578 
    579     fd = open("/dev/mem", O_RDWR);
    580     if (fd == -1) {
    581         rc = -errno;
    582         XEN_PT_ERR(d, "Can't open /dev/mem: %s\n", strerror(errno));
    583         goto error_out;
    584     }
    585     XEN_PT_LOG(d, "table_off = 0x%x, total_entries = %d\n",
    586                table_off, total_entries);
    587     msix->table_offset_adjust = table_off & 0x0fff;
    588     msix->phys_iomem_base =
    589         mmap(NULL,
    590              total_entries * PCI_MSIX_ENTRY_SIZE + msix->table_offset_adjust,
    591              PROT_READ,
    592              MAP_SHARED | MAP_LOCKED,
    593              fd,
    594              msix->table_base + table_off - msix->table_offset_adjust);
    595     close(fd);
    596     if (msix->phys_iomem_base == MAP_FAILED) {
    597         rc = -errno;
    598         XEN_PT_ERR(d, "Can't map physical MSI-X table: %s\n", strerror(errno));
    599         goto error_out;
    600     }
    601     msix->phys_iomem_base = (char *)msix->phys_iomem_base
    602         + msix->table_offset_adjust;
    603 
    604     XEN_PT_LOG(d, "mapping physical MSI-X table to %p\n",
    605                msix->phys_iomem_base);
    606 
    607     memory_region_add_subregion_overlap(&s->bar[bar_index], table_off,
    608                                         &msix->mmio,
    609                                         2); /* Priority: pci default + 1 */
    610 
    611     return 0;
    612 
    613 error_out:
    614     g_free(s->msix);
    615     s->msix = NULL;
    616     return rc;
    617 }
    618 
    619 void xen_pt_msix_unmap(XenPCIPassthroughState *s)
    620 {
    621     XenPTMSIX *msix = s->msix;
    622 
    623     if (!msix) {
    624         return;
    625     }
    626 
    627     /* unmap the MSI-X memory mapped register area */
    628     if (msix->phys_iomem_base) {
    629         XEN_PT_LOG(&s->dev, "unmapping physical MSI-X table from %p\n",
    630                    msix->phys_iomem_base);
    631         munmap(msix->phys_iomem_base, msix->total_entries * PCI_MSIX_ENTRY_SIZE
    632                + msix->table_offset_adjust);
    633     }
    634 
    635     memory_region_del_subregion(&s->bar[msix->bar_index], &msix->mmio);
    636 }
    637 
    638 void xen_pt_msix_delete(XenPCIPassthroughState *s)
    639 {
    640     XenPTMSIX *msix = s->msix;
    641 
    642     if (!msix) {
    643         return;
    644     }
    645 
    646     object_unparent(OBJECT(&msix->mmio));
    647 
    648     g_free(s->msix);
    649     s->msix = NULL;
    650 }