180b4ecc8SPaolo Bonzini /*
280b4ecc8SPaolo Bonzini * Copyright (c) 2007, Intel Corporation.
380b4ecc8SPaolo Bonzini *
480b4ecc8SPaolo Bonzini * This work is licensed under the terms of the GNU GPL, version 2. See
580b4ecc8SPaolo Bonzini * the COPYING file in the top-level directory.
680b4ecc8SPaolo Bonzini *
780b4ecc8SPaolo Bonzini * Jiang Yunhong <yunhong.jiang@intel.com>
880b4ecc8SPaolo Bonzini *
980b4ecc8SPaolo Bonzini * This file implements direct PCI assignment to a HVM guest
1080b4ecc8SPaolo Bonzini */
1180b4ecc8SPaolo Bonzini
1221cbfe5fSPeter Maydell #include "qemu/osdep.h"
1380b4ecc8SPaolo Bonzini
1480b4ecc8SPaolo Bonzini #include "hw/i386/apic-msidef.h"
15*e2abfe5eSDavid Woodhouse #include "xen_pt.h"
16*e2abfe5eSDavid Woodhouse #include "hw/xen/xen-legacy-backend.h"
1780b4ecc8SPaolo Bonzini
1880b4ecc8SPaolo Bonzini
1980b4ecc8SPaolo Bonzini #define XEN_PT_AUTO_ASSIGN -1
2080b4ecc8SPaolo Bonzini
2180b4ecc8SPaolo Bonzini /* shift count for gflags */
2280b4ecc8SPaolo Bonzini #define XEN_PT_GFLAGS_SHIFT_DEST_ID 0
2380b4ecc8SPaolo Bonzini #define XEN_PT_GFLAGS_SHIFT_RH 8
2480b4ecc8SPaolo Bonzini #define XEN_PT_GFLAGS_SHIFT_DM 9
2580b4ecc8SPaolo Bonzini #define XEN_PT_GFLAGSSHIFT_DELIV_MODE 12
2680b4ecc8SPaolo Bonzini #define XEN_PT_GFLAGSSHIFT_TRG_MODE 15
27a8036336SRoger Pau Monne #define XEN_PT_GFLAGSSHIFT_UNMASKED 16
2880b4ecc8SPaolo Bonzini
29f0ada360SJan Beulich #define latch(fld) latch[PCI_MSIX_ENTRY_##fld / sizeof(uint32_t)]
3080b4ecc8SPaolo Bonzini
3180b4ecc8SPaolo Bonzini /*
3280b4ecc8SPaolo Bonzini * Helpers
3380b4ecc8SPaolo Bonzini */
3480b4ecc8SPaolo Bonzini
msi_vector(uint32_t data)3580b4ecc8SPaolo Bonzini static inline uint8_t msi_vector(uint32_t data)
3680b4ecc8SPaolo Bonzini {
3780b4ecc8SPaolo Bonzini return (data & MSI_DATA_VECTOR_MASK) >> MSI_DATA_VECTOR_SHIFT;
3880b4ecc8SPaolo Bonzini }
3980b4ecc8SPaolo Bonzini
msi_dest_id(uint32_t addr)4080b4ecc8SPaolo Bonzini static inline uint8_t msi_dest_id(uint32_t addr)
4180b4ecc8SPaolo Bonzini {
4280b4ecc8SPaolo Bonzini return (addr & MSI_ADDR_DEST_ID_MASK) >> MSI_ADDR_DEST_ID_SHIFT;
4380b4ecc8SPaolo Bonzini }
4480b4ecc8SPaolo Bonzini
msi_ext_dest_id(uint32_t addr_hi)4580b4ecc8SPaolo Bonzini static inline uint32_t msi_ext_dest_id(uint32_t addr_hi)
4680b4ecc8SPaolo Bonzini {
4780b4ecc8SPaolo Bonzini return addr_hi & 0xffffff00;
4880b4ecc8SPaolo Bonzini }
4980b4ecc8SPaolo Bonzini
msi_gflags(uint32_t data,uint64_t addr)5080b4ecc8SPaolo Bonzini static uint32_t msi_gflags(uint32_t data, uint64_t addr)
5180b4ecc8SPaolo Bonzini {
5280b4ecc8SPaolo Bonzini uint32_t result = 0;
5380b4ecc8SPaolo Bonzini int rh, dm, dest_id, deliv_mode, trig_mode;
5480b4ecc8SPaolo Bonzini
5580b4ecc8SPaolo Bonzini rh = (addr >> MSI_ADDR_REDIRECTION_SHIFT) & 0x1;
5680b4ecc8SPaolo Bonzini dm = (addr >> MSI_ADDR_DEST_MODE_SHIFT) & 0x1;
5780b4ecc8SPaolo Bonzini dest_id = msi_dest_id(addr);
5880b4ecc8SPaolo Bonzini deliv_mode = (data >> MSI_DATA_DELIVERY_MODE_SHIFT) & 0x7;
5980b4ecc8SPaolo Bonzini trig_mode = (data >> MSI_DATA_TRIGGER_SHIFT) & 0x1;
6080b4ecc8SPaolo Bonzini
6180b4ecc8SPaolo Bonzini result = dest_id | (rh << XEN_PT_GFLAGS_SHIFT_RH)
6280b4ecc8SPaolo Bonzini | (dm << XEN_PT_GFLAGS_SHIFT_DM)
6380b4ecc8SPaolo Bonzini | (deliv_mode << XEN_PT_GFLAGSSHIFT_DELIV_MODE)
6480b4ecc8SPaolo Bonzini | (trig_mode << XEN_PT_GFLAGSSHIFT_TRG_MODE);
6580b4ecc8SPaolo Bonzini
6680b4ecc8SPaolo Bonzini return result;
6780b4ecc8SPaolo Bonzini }
6880b4ecc8SPaolo Bonzini
msi_addr64(XenPTMSI * msi)6980b4ecc8SPaolo Bonzini static inline uint64_t msi_addr64(XenPTMSI *msi)
7080b4ecc8SPaolo Bonzini {
7180b4ecc8SPaolo Bonzini return (uint64_t)msi->addr_hi << 32 | msi->addr_lo;
7280b4ecc8SPaolo Bonzini }
7380b4ecc8SPaolo Bonzini
msi_msix_enable(XenPCIPassthroughState * s,uint32_t address,uint16_t flag,bool enable)7480b4ecc8SPaolo Bonzini static int msi_msix_enable(XenPCIPassthroughState *s,
7580b4ecc8SPaolo Bonzini uint32_t address,
7680b4ecc8SPaolo Bonzini uint16_t flag,
7780b4ecc8SPaolo Bonzini bool enable)
7880b4ecc8SPaolo Bonzini {
7980b4ecc8SPaolo Bonzini uint16_t val = 0;
80fe2da64cSKonrad Rzeszutek Wilk int rc;
8180b4ecc8SPaolo Bonzini
8280b4ecc8SPaolo Bonzini if (!address) {
8380b4ecc8SPaolo Bonzini return -1;
8480b4ecc8SPaolo Bonzini }
8580b4ecc8SPaolo Bonzini
86fe2da64cSKonrad Rzeszutek Wilk rc = xen_host_pci_get_word(&s->real_device, address, &val);
87fe2da64cSKonrad Rzeszutek Wilk if (rc) {
88fe2da64cSKonrad Rzeszutek Wilk XEN_PT_ERR(&s->dev, "Failed to read MSI/MSI-X register (0x%x), rc:%d\n",
89fe2da64cSKonrad Rzeszutek Wilk address, rc);
90fe2da64cSKonrad Rzeszutek Wilk return rc;
91fe2da64cSKonrad Rzeszutek Wilk }
9280b4ecc8SPaolo Bonzini if (enable) {
9380b4ecc8SPaolo Bonzini val |= flag;
9480b4ecc8SPaolo Bonzini } else {
9580b4ecc8SPaolo Bonzini val &= ~flag;
9680b4ecc8SPaolo Bonzini }
97fe2da64cSKonrad Rzeszutek Wilk rc = xen_host_pci_set_word(&s->real_device, address, val);
98fe2da64cSKonrad Rzeszutek Wilk if (rc) {
99fe2da64cSKonrad Rzeszutek Wilk XEN_PT_ERR(&s->dev, "Failed to write MSI/MSI-X register (0x%x), rc:%d\n",
100fe2da64cSKonrad Rzeszutek Wilk address, rc);
101fe2da64cSKonrad Rzeszutek Wilk }
102fe2da64cSKonrad Rzeszutek Wilk return rc;
10380b4ecc8SPaolo Bonzini }
10480b4ecc8SPaolo Bonzini
msi_msix_setup(XenPCIPassthroughState * s,uint64_t addr,uint32_t data,int * ppirq,bool is_msix,int msix_entry,bool is_not_mapped)10580b4ecc8SPaolo Bonzini static int msi_msix_setup(XenPCIPassthroughState *s,
10680b4ecc8SPaolo Bonzini uint64_t addr,
10780b4ecc8SPaolo Bonzini uint32_t data,
10880b4ecc8SPaolo Bonzini int *ppirq,
10980b4ecc8SPaolo Bonzini bool is_msix,
11080b4ecc8SPaolo Bonzini int msix_entry,
11180b4ecc8SPaolo Bonzini bool is_not_mapped)
11280b4ecc8SPaolo Bonzini {
11380b4ecc8SPaolo Bonzini uint8_t gvec = msi_vector(data);
11480b4ecc8SPaolo Bonzini int rc = 0;
11580b4ecc8SPaolo Bonzini
11680b4ecc8SPaolo Bonzini assert((!is_msix && msix_entry == 0) || is_msix);
11780b4ecc8SPaolo Bonzini
118428c3eceSStefano Stabellini if (xen_is_pirq_msi(data)) {
11980b4ecc8SPaolo Bonzini *ppirq = msi_ext_dest_id(addr >> 32) | msi_dest_id(addr);
12080b4ecc8SPaolo Bonzini if (!*ppirq) {
12180b4ecc8SPaolo Bonzini /* this probably identifies an misconfiguration of the guest,
12280b4ecc8SPaolo Bonzini * try the emulated path */
12380b4ecc8SPaolo Bonzini *ppirq = XEN_PT_UNASSIGNED_PIRQ;
12480b4ecc8SPaolo Bonzini } else {
12580b4ecc8SPaolo Bonzini XEN_PT_LOG(&s->dev, "requested pirq %d for MSI%s"
12601d152c0SXinhao Zhang " (vec: 0x%x, entry: 0x%x)\n",
12780b4ecc8SPaolo Bonzini *ppirq, is_msix ? "-X" : "", gvec, msix_entry);
12880b4ecc8SPaolo Bonzini }
12980b4ecc8SPaolo Bonzini }
13080b4ecc8SPaolo Bonzini
13180b4ecc8SPaolo Bonzini if (is_not_mapped) {
13280b4ecc8SPaolo Bonzini uint64_t table_base = 0;
13380b4ecc8SPaolo Bonzini
13480b4ecc8SPaolo Bonzini if (is_msix) {
13580b4ecc8SPaolo Bonzini table_base = s->msix->table_base;
13680b4ecc8SPaolo Bonzini }
13780b4ecc8SPaolo Bonzini
13880b4ecc8SPaolo Bonzini rc = xc_physdev_map_pirq_msi(xen_xc, xen_domid, XEN_PT_AUTO_ASSIGN,
13980b4ecc8SPaolo Bonzini ppirq, PCI_DEVFN(s->real_device.dev,
14080b4ecc8SPaolo Bonzini s->real_device.func),
14180b4ecc8SPaolo Bonzini s->real_device.bus,
14280b4ecc8SPaolo Bonzini msix_entry, table_base);
14380b4ecc8SPaolo Bonzini if (rc) {
14480b4ecc8SPaolo Bonzini XEN_PT_ERR(&s->dev,
14501d152c0SXinhao Zhang "Mapping of MSI%s (err: %i, vec: 0x%x, entry 0x%x)\n",
1463782f60dSJan Beulich is_msix ? "-X" : "", errno, gvec, msix_entry);
14780b4ecc8SPaolo Bonzini return rc;
14880b4ecc8SPaolo Bonzini }
14980b4ecc8SPaolo Bonzini }
15080b4ecc8SPaolo Bonzini
15180b4ecc8SPaolo Bonzini return 0;
15280b4ecc8SPaolo Bonzini }
msi_msix_update(XenPCIPassthroughState * s,uint64_t addr,uint32_t data,int pirq,bool is_msix,int msix_entry,int * old_pirq,bool masked)15380b4ecc8SPaolo Bonzini static int msi_msix_update(XenPCIPassthroughState *s,
15480b4ecc8SPaolo Bonzini uint64_t addr,
15580b4ecc8SPaolo Bonzini uint32_t data,
15680b4ecc8SPaolo Bonzini int pirq,
15780b4ecc8SPaolo Bonzini bool is_msix,
15880b4ecc8SPaolo Bonzini int msix_entry,
159a8036336SRoger Pau Monne int *old_pirq,
160a8036336SRoger Pau Monne bool masked)
16180b4ecc8SPaolo Bonzini {
16280b4ecc8SPaolo Bonzini PCIDevice *d = &s->dev;
16380b4ecc8SPaolo Bonzini uint8_t gvec = msi_vector(data);
16480b4ecc8SPaolo Bonzini uint32_t gflags = msi_gflags(data, addr);
16580b4ecc8SPaolo Bonzini int rc = 0;
16680b4ecc8SPaolo Bonzini uint64_t table_addr = 0;
16780b4ecc8SPaolo Bonzini
16801d152c0SXinhao Zhang XEN_PT_LOG(d, "Updating MSI%s with pirq %d gvec 0x%x gflags 0x%x"
16901d152c0SXinhao Zhang " (entry: 0x%x)\n",
17080b4ecc8SPaolo Bonzini is_msix ? "-X" : "", pirq, gvec, gflags, msix_entry);
17180b4ecc8SPaolo Bonzini
17280b4ecc8SPaolo Bonzini if (is_msix) {
17380b4ecc8SPaolo Bonzini table_addr = s->msix->mmio_base_addr;
17480b4ecc8SPaolo Bonzini }
17580b4ecc8SPaolo Bonzini
176a8036336SRoger Pau Monne gflags |= masked ? 0 : (1u << XEN_PT_GFLAGSSHIFT_UNMASKED);
177a8036336SRoger Pau Monne
17880b4ecc8SPaolo Bonzini rc = xc_domain_update_msi_irq(xen_xc, xen_domid, gvec,
17980b4ecc8SPaolo Bonzini pirq, gflags, table_addr);
18080b4ecc8SPaolo Bonzini
18180b4ecc8SPaolo Bonzini if (rc) {
1823782f60dSJan Beulich XEN_PT_ERR(d, "Updating of MSI%s failed. (err: %d)\n",
1833782f60dSJan Beulich is_msix ? "-X" : "", errno);
18480b4ecc8SPaolo Bonzini
18580b4ecc8SPaolo Bonzini if (xc_physdev_unmap_pirq(xen_xc, xen_domid, *old_pirq)) {
1863782f60dSJan Beulich XEN_PT_ERR(d, "Unmapping of MSI%s pirq %d failed. (err: %d)\n",
1873782f60dSJan Beulich is_msix ? "-X" : "", *old_pirq, errno);
18880b4ecc8SPaolo Bonzini }
18980b4ecc8SPaolo Bonzini *old_pirq = XEN_PT_UNASSIGNED_PIRQ;
19080b4ecc8SPaolo Bonzini }
19180b4ecc8SPaolo Bonzini return rc;
19280b4ecc8SPaolo Bonzini }
19380b4ecc8SPaolo Bonzini
msi_msix_disable(XenPCIPassthroughState * s,uint64_t addr,uint32_t data,int pirq,bool is_msix,bool is_binded)19480b4ecc8SPaolo Bonzini static int msi_msix_disable(XenPCIPassthroughState *s,
19580b4ecc8SPaolo Bonzini uint64_t addr,
19680b4ecc8SPaolo Bonzini uint32_t data,
19780b4ecc8SPaolo Bonzini int pirq,
19880b4ecc8SPaolo Bonzini bool is_msix,
19980b4ecc8SPaolo Bonzini bool is_binded)
20080b4ecc8SPaolo Bonzini {
20180b4ecc8SPaolo Bonzini PCIDevice *d = &s->dev;
20280b4ecc8SPaolo Bonzini uint8_t gvec = msi_vector(data);
20380b4ecc8SPaolo Bonzini uint32_t gflags = msi_gflags(data, addr);
20480b4ecc8SPaolo Bonzini int rc = 0;
20580b4ecc8SPaolo Bonzini
20680b4ecc8SPaolo Bonzini if (pirq == XEN_PT_UNASSIGNED_PIRQ) {
20780b4ecc8SPaolo Bonzini return 0;
20880b4ecc8SPaolo Bonzini }
20980b4ecc8SPaolo Bonzini
21080b4ecc8SPaolo Bonzini if (is_binded) {
21101d152c0SXinhao Zhang XEN_PT_LOG(d, "Unbind MSI%s with pirq %d, gvec 0x%x\n",
21280b4ecc8SPaolo Bonzini is_msix ? "-X" : "", pirq, gvec);
21380b4ecc8SPaolo Bonzini rc = xc_domain_unbind_msi_irq(xen_xc, xen_domid, gvec, pirq, gflags);
21480b4ecc8SPaolo Bonzini if (rc) {
21501d152c0SXinhao Zhang XEN_PT_ERR(d, "Unbinding of MSI%s failed. (err: %d, pirq: %d, gvec: 0x%x)\n",
2163782f60dSJan Beulich is_msix ? "-X" : "", errno, pirq, gvec);
21780b4ecc8SPaolo Bonzini return rc;
21880b4ecc8SPaolo Bonzini }
21980b4ecc8SPaolo Bonzini }
22080b4ecc8SPaolo Bonzini
22180b4ecc8SPaolo Bonzini XEN_PT_LOG(d, "Unmap MSI%s pirq %d\n", is_msix ? "-X" : "", pirq);
22280b4ecc8SPaolo Bonzini rc = xc_physdev_unmap_pirq(xen_xc, xen_domid, pirq);
22380b4ecc8SPaolo Bonzini if (rc) {
2243782f60dSJan Beulich XEN_PT_ERR(d, "Unmapping of MSI%s pirq %d failed. (err: %i)\n",
2253782f60dSJan Beulich is_msix ? "-X" : "", pirq, errno);
22680b4ecc8SPaolo Bonzini return rc;
22780b4ecc8SPaolo Bonzini }
22880b4ecc8SPaolo Bonzini
22980b4ecc8SPaolo Bonzini return 0;
23080b4ecc8SPaolo Bonzini }
23180b4ecc8SPaolo Bonzini
23280b4ecc8SPaolo Bonzini /*
23380b4ecc8SPaolo Bonzini * MSI virtualization functions
23480b4ecc8SPaolo Bonzini */
23580b4ecc8SPaolo Bonzini
xen_pt_msi_set_enable(XenPCIPassthroughState * s,bool enable)236cf8124f0SKonrad Rzeszutek Wilk static int xen_pt_msi_set_enable(XenPCIPassthroughState *s, bool enable)
23780b4ecc8SPaolo Bonzini {
23880b4ecc8SPaolo Bonzini XEN_PT_LOG(&s->dev, "%s MSI.\n", enable ? "enabling" : "disabling");
23980b4ecc8SPaolo Bonzini
24080b4ecc8SPaolo Bonzini if (!s->msi) {
24180b4ecc8SPaolo Bonzini return -1;
24280b4ecc8SPaolo Bonzini }
24380b4ecc8SPaolo Bonzini
24480b4ecc8SPaolo Bonzini return msi_msix_enable(s, s->msi->ctrl_offset, PCI_MSI_FLAGS_ENABLE,
24580b4ecc8SPaolo Bonzini enable);
24680b4ecc8SPaolo Bonzini }
24780b4ecc8SPaolo Bonzini
24880b4ecc8SPaolo Bonzini /* setup physical msi, but don't enable it */
xen_pt_msi_setup(XenPCIPassthroughState * s)24980b4ecc8SPaolo Bonzini int xen_pt_msi_setup(XenPCIPassthroughState *s)
25080b4ecc8SPaolo Bonzini {
25180b4ecc8SPaolo Bonzini int pirq = XEN_PT_UNASSIGNED_PIRQ;
25280b4ecc8SPaolo Bonzini int rc = 0;
25380b4ecc8SPaolo Bonzini XenPTMSI *msi = s->msi;
25480b4ecc8SPaolo Bonzini
25580b4ecc8SPaolo Bonzini if (msi->initialized) {
25680b4ecc8SPaolo Bonzini XEN_PT_ERR(&s->dev,
25780b4ecc8SPaolo Bonzini "Setup physical MSI when it has been properly initialized.\n");
25880b4ecc8SPaolo Bonzini return -1;
25980b4ecc8SPaolo Bonzini }
26080b4ecc8SPaolo Bonzini
26180b4ecc8SPaolo Bonzini rc = msi_msix_setup(s, msi_addr64(msi), msi->data, &pirq, false, 0, true);
26280b4ecc8SPaolo Bonzini if (rc) {
26380b4ecc8SPaolo Bonzini return rc;
26480b4ecc8SPaolo Bonzini }
26580b4ecc8SPaolo Bonzini
26680b4ecc8SPaolo Bonzini if (pirq < 0) {
26780b4ecc8SPaolo Bonzini XEN_PT_ERR(&s->dev, "Invalid pirq number: %d.\n", pirq);
26880b4ecc8SPaolo Bonzini return -1;
26980b4ecc8SPaolo Bonzini }
27080b4ecc8SPaolo Bonzini
27180b4ecc8SPaolo Bonzini msi->pirq = pirq;
27280b4ecc8SPaolo Bonzini XEN_PT_LOG(&s->dev, "MSI mapped with pirq %d.\n", pirq);
27380b4ecc8SPaolo Bonzini
27480b4ecc8SPaolo Bonzini return 0;
27580b4ecc8SPaolo Bonzini }
27680b4ecc8SPaolo Bonzini
xen_pt_msi_update(XenPCIPassthroughState * s)27780b4ecc8SPaolo Bonzini int xen_pt_msi_update(XenPCIPassthroughState *s)
27880b4ecc8SPaolo Bonzini {
27980b4ecc8SPaolo Bonzini XenPTMSI *msi = s->msi;
280a8036336SRoger Pau Monne
281a8036336SRoger Pau Monne /* Current MSI emulation in QEMU only supports 1 vector */
28280b4ecc8SPaolo Bonzini return msi_msix_update(s, msi_addr64(msi), msi->data, msi->pirq,
283a8036336SRoger Pau Monne false, 0, &msi->pirq, msi->mask & 1);
28480b4ecc8SPaolo Bonzini }
28580b4ecc8SPaolo Bonzini
xen_pt_msi_disable(XenPCIPassthroughState * s)28680b4ecc8SPaolo Bonzini void xen_pt_msi_disable(XenPCIPassthroughState *s)
28780b4ecc8SPaolo Bonzini {
28880b4ecc8SPaolo Bonzini XenPTMSI *msi = s->msi;
28980b4ecc8SPaolo Bonzini
29080b4ecc8SPaolo Bonzini if (!msi) {
29180b4ecc8SPaolo Bonzini return;
29280b4ecc8SPaolo Bonzini }
29380b4ecc8SPaolo Bonzini
294fe2da64cSKonrad Rzeszutek Wilk (void)xen_pt_msi_set_enable(s, false);
29580b4ecc8SPaolo Bonzini
29680b4ecc8SPaolo Bonzini msi_msix_disable(s, msi_addr64(msi), msi->data, msi->pirq, false,
29780b4ecc8SPaolo Bonzini msi->initialized);
29880b4ecc8SPaolo Bonzini
29980b4ecc8SPaolo Bonzini /* clear msi info */
300c976437cSZhenzhong Duan msi->flags &= ~PCI_MSI_FLAGS_ENABLE;
301c976437cSZhenzhong Duan msi->initialized = false;
30280b4ecc8SPaolo Bonzini msi->mapped = false;
30380b4ecc8SPaolo Bonzini msi->pirq = XEN_PT_UNASSIGNED_PIRQ;
30480b4ecc8SPaolo Bonzini }
30580b4ecc8SPaolo Bonzini
30680b4ecc8SPaolo Bonzini /*
30780b4ecc8SPaolo Bonzini * MSI-X virtualization functions
30880b4ecc8SPaolo Bonzini */
30980b4ecc8SPaolo Bonzini
msix_set_enable(XenPCIPassthroughState * s,bool enabled)31080b4ecc8SPaolo Bonzini static int msix_set_enable(XenPCIPassthroughState *s, bool enabled)
31180b4ecc8SPaolo Bonzini {
31280b4ecc8SPaolo Bonzini XEN_PT_LOG(&s->dev, "%s MSI-X.\n", enabled ? "enabling" : "disabling");
31380b4ecc8SPaolo Bonzini
31480b4ecc8SPaolo Bonzini if (!s->msix) {
31580b4ecc8SPaolo Bonzini return -1;
31680b4ecc8SPaolo Bonzini }
31780b4ecc8SPaolo Bonzini
31880b4ecc8SPaolo Bonzini return msi_msix_enable(s, s->msix->ctrl_offset, PCI_MSIX_FLAGS_ENABLE,
31980b4ecc8SPaolo Bonzini enabled);
32080b4ecc8SPaolo Bonzini }
32180b4ecc8SPaolo Bonzini
xen_pt_msix_update_one(XenPCIPassthroughState * s,int entry_nr,uint32_t vec_ctrl)322f0ada360SJan Beulich static int xen_pt_msix_update_one(XenPCIPassthroughState *s, int entry_nr,
323f0ada360SJan Beulich uint32_t vec_ctrl)
32480b4ecc8SPaolo Bonzini {
32580b4ecc8SPaolo Bonzini XenPTMSIXEntry *entry = NULL;
32680b4ecc8SPaolo Bonzini int pirq;
32780b4ecc8SPaolo Bonzini int rc;
32880b4ecc8SPaolo Bonzini
32980b4ecc8SPaolo Bonzini if (entry_nr < 0 || entry_nr >= s->msix->total_entries) {
33080b4ecc8SPaolo Bonzini return -EINVAL;
33180b4ecc8SPaolo Bonzini }
33280b4ecc8SPaolo Bonzini
33380b4ecc8SPaolo Bonzini entry = &s->msix->msix_entry[entry_nr];
33480b4ecc8SPaolo Bonzini
33580b4ecc8SPaolo Bonzini if (!entry->updated) {
33680b4ecc8SPaolo Bonzini return 0;
33780b4ecc8SPaolo Bonzini }
33880b4ecc8SPaolo Bonzini
33980b4ecc8SPaolo Bonzini pirq = entry->pirq;
34080b4ecc8SPaolo Bonzini
341f0ada360SJan Beulich /*
342f0ada360SJan Beulich * Update the entry addr and data to the latest values only when the
343f0ada360SJan Beulich * entry is masked or they are all masked, as required by the spec.
344f0ada360SJan Beulich * Addr and data changes while the MSI-X entry is unmasked get deferred
345f0ada360SJan Beulich * until the next masked -> unmasked transition.
346f0ada360SJan Beulich */
347f0ada360SJan Beulich if (pirq == XEN_PT_UNASSIGNED_PIRQ || s->msix->maskall ||
348f0ada360SJan Beulich (vec_ctrl & PCI_MSIX_ENTRY_CTRL_MASKBIT)) {
349f0ada360SJan Beulich entry->addr = entry->latch(LOWER_ADDR) |
350f0ada360SJan Beulich ((uint64_t)entry->latch(UPPER_ADDR) << 32);
351f0ada360SJan Beulich entry->data = entry->latch(DATA);
352f0ada360SJan Beulich }
353f0ada360SJan Beulich
35480b4ecc8SPaolo Bonzini rc = msi_msix_setup(s, entry->addr, entry->data, &pirq, true, entry_nr,
35580b4ecc8SPaolo Bonzini entry->pirq == XEN_PT_UNASSIGNED_PIRQ);
35680b4ecc8SPaolo Bonzini if (rc) {
35780b4ecc8SPaolo Bonzini return rc;
35880b4ecc8SPaolo Bonzini }
35980b4ecc8SPaolo Bonzini if (entry->pirq == XEN_PT_UNASSIGNED_PIRQ) {
36080b4ecc8SPaolo Bonzini entry->pirq = pirq;
36180b4ecc8SPaolo Bonzini }
36280b4ecc8SPaolo Bonzini
36380b4ecc8SPaolo Bonzini rc = msi_msix_update(s, entry->addr, entry->data, pirq, true,
364a8036336SRoger Pau Monne entry_nr, &entry->pirq,
365a8036336SRoger Pau Monne vec_ctrl & PCI_MSIX_ENTRY_CTRL_MASKBIT);
36680b4ecc8SPaolo Bonzini
36780b4ecc8SPaolo Bonzini if (!rc) {
36880b4ecc8SPaolo Bonzini entry->updated = false;
36980b4ecc8SPaolo Bonzini }
37080b4ecc8SPaolo Bonzini
37180b4ecc8SPaolo Bonzini return rc;
37280b4ecc8SPaolo Bonzini }
37380b4ecc8SPaolo Bonzini
xen_pt_msix_update(XenPCIPassthroughState * s)37480b4ecc8SPaolo Bonzini int xen_pt_msix_update(XenPCIPassthroughState *s)
37580b4ecc8SPaolo Bonzini {
37680b4ecc8SPaolo Bonzini XenPTMSIX *msix = s->msix;
37780b4ecc8SPaolo Bonzini int i;
37880b4ecc8SPaolo Bonzini
37980b4ecc8SPaolo Bonzini for (i = 0; i < msix->total_entries; i++) {
380f0ada360SJan Beulich xen_pt_msix_update_one(s, i, msix->msix_entry[i].latch(VECTOR_CTRL));
38180b4ecc8SPaolo Bonzini }
38280b4ecc8SPaolo Bonzini
38380b4ecc8SPaolo Bonzini return 0;
38480b4ecc8SPaolo Bonzini }
38580b4ecc8SPaolo Bonzini
xen_pt_msix_disable(XenPCIPassthroughState * s)38680b4ecc8SPaolo Bonzini void xen_pt_msix_disable(XenPCIPassthroughState *s)
38780b4ecc8SPaolo Bonzini {
38880b4ecc8SPaolo Bonzini int i = 0;
38980b4ecc8SPaolo Bonzini
39080b4ecc8SPaolo Bonzini msix_set_enable(s, false);
39180b4ecc8SPaolo Bonzini
39280b4ecc8SPaolo Bonzini for (i = 0; i < s->msix->total_entries; i++) {
39380b4ecc8SPaolo Bonzini XenPTMSIXEntry *entry = &s->msix->msix_entry[i];
39480b4ecc8SPaolo Bonzini
39580b4ecc8SPaolo Bonzini msi_msix_disable(s, entry->addr, entry->data, entry->pirq, true, true);
39680b4ecc8SPaolo Bonzini
39780b4ecc8SPaolo Bonzini /* clear MSI-X info */
39880b4ecc8SPaolo Bonzini entry->pirq = XEN_PT_UNASSIGNED_PIRQ;
39980b4ecc8SPaolo Bonzini entry->updated = false;
40080b4ecc8SPaolo Bonzini }
40180b4ecc8SPaolo Bonzini }
40280b4ecc8SPaolo Bonzini
xen_pt_msix_update_remap(XenPCIPassthroughState * s,int bar_index)40380b4ecc8SPaolo Bonzini int xen_pt_msix_update_remap(XenPCIPassthroughState *s, int bar_index)
40480b4ecc8SPaolo Bonzini {
40580b4ecc8SPaolo Bonzini XenPTMSIXEntry *entry;
40680b4ecc8SPaolo Bonzini int i, ret;
40780b4ecc8SPaolo Bonzini
40880b4ecc8SPaolo Bonzini if (!(s->msix && s->msix->bar_index == bar_index)) {
40980b4ecc8SPaolo Bonzini return 0;
41080b4ecc8SPaolo Bonzini }
41180b4ecc8SPaolo Bonzini
41280b4ecc8SPaolo Bonzini for (i = 0; i < s->msix->total_entries; i++) {
41380b4ecc8SPaolo Bonzini entry = &s->msix->msix_entry[i];
41480b4ecc8SPaolo Bonzini if (entry->pirq != XEN_PT_UNASSIGNED_PIRQ) {
41580b4ecc8SPaolo Bonzini ret = xc_domain_unbind_pt_irq(xen_xc, xen_domid, entry->pirq,
41680b4ecc8SPaolo Bonzini PT_IRQ_TYPE_MSI, 0, 0, 0, 0);
41780b4ecc8SPaolo Bonzini if (ret) {
4183782f60dSJan Beulich XEN_PT_ERR(&s->dev, "unbind MSI-X entry %d failed (err: %d)\n",
4193782f60dSJan Beulich entry->pirq, errno);
42080b4ecc8SPaolo Bonzini }
42180b4ecc8SPaolo Bonzini entry->updated = true;
42280b4ecc8SPaolo Bonzini }
42380b4ecc8SPaolo Bonzini }
42480b4ecc8SPaolo Bonzini return xen_pt_msix_update(s);
42580b4ecc8SPaolo Bonzini }
42680b4ecc8SPaolo Bonzini
get_entry_value(XenPTMSIXEntry * e,int offset)42780b4ecc8SPaolo Bonzini static uint32_t get_entry_value(XenPTMSIXEntry *e, int offset)
42880b4ecc8SPaolo Bonzini {
429bdfe5159SJan Beulich assert(!(offset % sizeof(*e->latch)));
430bdfe5159SJan Beulich return e->latch[offset / sizeof(*e->latch)];
43180b4ecc8SPaolo Bonzini }
43280b4ecc8SPaolo Bonzini
set_entry_value(XenPTMSIXEntry * e,int offset,uint32_t val)43380b4ecc8SPaolo Bonzini static void set_entry_value(XenPTMSIXEntry *e, int offset, uint32_t val)
43480b4ecc8SPaolo Bonzini {
435bdfe5159SJan Beulich assert(!(offset % sizeof(*e->latch)));
436f0ada360SJan Beulich e->latch[offset / sizeof(*e->latch)] = val;
43780b4ecc8SPaolo Bonzini }
43880b4ecc8SPaolo Bonzini
pci_msix_write(void * opaque,hwaddr addr,uint64_t val,unsigned size)43980b4ecc8SPaolo Bonzini static void pci_msix_write(void *opaque, hwaddr addr,
44080b4ecc8SPaolo Bonzini uint64_t val, unsigned size)
44180b4ecc8SPaolo Bonzini {
44280b4ecc8SPaolo Bonzini XenPCIPassthroughState *s = opaque;
44380b4ecc8SPaolo Bonzini XenPTMSIX *msix = s->msix;
44480b4ecc8SPaolo Bonzini XenPTMSIXEntry *entry;
445b38ec5eeSJan Beulich unsigned int entry_nr, offset;
44680b4ecc8SPaolo Bonzini
44780b4ecc8SPaolo Bonzini entry_nr = addr / PCI_MSIX_ENTRY_SIZE;
448b38ec5eeSJan Beulich if (entry_nr >= msix->total_entries) {
44980b4ecc8SPaolo Bonzini return;
45080b4ecc8SPaolo Bonzini }
45180b4ecc8SPaolo Bonzini entry = &msix->msix_entry[entry_nr];
45280b4ecc8SPaolo Bonzini offset = addr % PCI_MSIX_ENTRY_SIZE;
45380b4ecc8SPaolo Bonzini
45480b4ecc8SPaolo Bonzini if (offset != PCI_MSIX_ENTRY_VECTOR_CTRL) {
455c976437cSZhenzhong Duan if (get_entry_value(entry, offset) == val
456c976437cSZhenzhong Duan && entry->pirq != XEN_PT_UNASSIGNED_PIRQ) {
45780b4ecc8SPaolo Bonzini return;
45880b4ecc8SPaolo Bonzini }
45980b4ecc8SPaolo Bonzini
460f0ada360SJan Beulich entry->updated = true;
461f0ada360SJan Beulich } else if (msix->enabled && entry->updated &&
462f0ada360SJan Beulich !(val & PCI_MSIX_ENTRY_CTRL_MASKBIT)) {
463f0ada360SJan Beulich const volatile uint32_t *vec_ctrl;
464f0ada360SJan Beulich
46580b4ecc8SPaolo Bonzini /*
46680b4ecc8SPaolo Bonzini * If Xen intercepts the mask bit access, entry->vec_ctrl may not be
46780b4ecc8SPaolo Bonzini * up-to-date. Read from hardware directly.
46880b4ecc8SPaolo Bonzini */
46980b4ecc8SPaolo Bonzini vec_ctrl = s->msix->phys_iomem_base + entry_nr * PCI_MSIX_ENTRY_SIZE
47080b4ecc8SPaolo Bonzini + PCI_MSIX_ENTRY_VECTOR_CTRL;
471f0ada360SJan Beulich xen_pt_msix_update_one(s, entry_nr, *vec_ctrl);
47280b4ecc8SPaolo Bonzini }
47380b4ecc8SPaolo Bonzini
47480b4ecc8SPaolo Bonzini set_entry_value(entry, offset, val);
47580b4ecc8SPaolo Bonzini }
47680b4ecc8SPaolo Bonzini
pci_msix_read(void * opaque,hwaddr addr,unsigned size)47780b4ecc8SPaolo Bonzini static uint64_t pci_msix_read(void *opaque, hwaddr addr,
47880b4ecc8SPaolo Bonzini unsigned size)
47980b4ecc8SPaolo Bonzini {
48080b4ecc8SPaolo Bonzini XenPCIPassthroughState *s = opaque;
48180b4ecc8SPaolo Bonzini XenPTMSIX *msix = s->msix;
48280b4ecc8SPaolo Bonzini int entry_nr, offset;
48380b4ecc8SPaolo Bonzini
48480b4ecc8SPaolo Bonzini entry_nr = addr / PCI_MSIX_ENTRY_SIZE;
48580b4ecc8SPaolo Bonzini if (entry_nr < 0) {
48680b4ecc8SPaolo Bonzini XEN_PT_ERR(&s->dev, "asked MSI-X entry '%i' invalid!\n", entry_nr);
48780b4ecc8SPaolo Bonzini return 0;
48880b4ecc8SPaolo Bonzini }
48980b4ecc8SPaolo Bonzini
49080b4ecc8SPaolo Bonzini offset = addr % PCI_MSIX_ENTRY_SIZE;
49180b4ecc8SPaolo Bonzini
49280b4ecc8SPaolo Bonzini if (addr < msix->total_entries * PCI_MSIX_ENTRY_SIZE) {
49380b4ecc8SPaolo Bonzini return get_entry_value(&msix->msix_entry[entry_nr], offset);
49480b4ecc8SPaolo Bonzini } else {
49580b4ecc8SPaolo Bonzini /* Pending Bit Array (PBA) */
49680b4ecc8SPaolo Bonzini return *(uint32_t *)(msix->phys_iomem_base + addr);
49780b4ecc8SPaolo Bonzini }
49880b4ecc8SPaolo Bonzini }
49980b4ecc8SPaolo Bonzini
pci_msix_accepts(void * opaque,hwaddr addr,unsigned size,bool is_write,MemTxAttrs attrs)500bdfe5159SJan Beulich static bool pci_msix_accepts(void *opaque, hwaddr addr,
5018372d383SPeter Maydell unsigned size, bool is_write,
5028372d383SPeter Maydell MemTxAttrs attrs)
503bdfe5159SJan Beulich {
504bdfe5159SJan Beulich return !(addr & (size - 1));
505bdfe5159SJan Beulich }
506bdfe5159SJan Beulich
50780b4ecc8SPaolo Bonzini static const MemoryRegionOps pci_msix_ops = {
50880b4ecc8SPaolo Bonzini .read = pci_msix_read,
50980b4ecc8SPaolo Bonzini .write = pci_msix_write,
51080b4ecc8SPaolo Bonzini .endianness = DEVICE_NATIVE_ENDIAN,
51180b4ecc8SPaolo Bonzini .valid = {
51280b4ecc8SPaolo Bonzini .min_access_size = 4,
51380b4ecc8SPaolo Bonzini .max_access_size = 4,
51480b4ecc8SPaolo Bonzini .unaligned = false,
515bdfe5159SJan Beulich .accepts = pci_msix_accepts
51680b4ecc8SPaolo Bonzini },
517bdfe5159SJan Beulich .impl = {
518bdfe5159SJan Beulich .min_access_size = 4,
519bdfe5159SJan Beulich .max_access_size = 4,
520bdfe5159SJan Beulich .unaligned = false
521bdfe5159SJan Beulich }
52280b4ecc8SPaolo Bonzini };
52380b4ecc8SPaolo Bonzini
xen_pt_msix_init(XenPCIPassthroughState * s,uint32_t base)52480b4ecc8SPaolo Bonzini int xen_pt_msix_init(XenPCIPassthroughState *s, uint32_t base)
52580b4ecc8SPaolo Bonzini {
52680b4ecc8SPaolo Bonzini uint8_t id = 0;
52780b4ecc8SPaolo Bonzini uint16_t control = 0;
52880b4ecc8SPaolo Bonzini uint32_t table_off = 0;
52980b4ecc8SPaolo Bonzini int i, total_entries, bar_index;
53080b4ecc8SPaolo Bonzini XenHostPCIDevice *hd = &s->real_device;
53180b4ecc8SPaolo Bonzini PCIDevice *d = &s->dev;
53280b4ecc8SPaolo Bonzini int fd = -1;
53380b4ecc8SPaolo Bonzini XenPTMSIX *msix = NULL;
53480b4ecc8SPaolo Bonzini int rc = 0;
53580b4ecc8SPaolo Bonzini
53680b4ecc8SPaolo Bonzini rc = xen_host_pci_get_byte(hd, base + PCI_CAP_LIST_ID, &id);
53780b4ecc8SPaolo Bonzini if (rc) {
53880b4ecc8SPaolo Bonzini return rc;
53980b4ecc8SPaolo Bonzini }
54080b4ecc8SPaolo Bonzini
54180b4ecc8SPaolo Bonzini if (id != PCI_CAP_ID_MSIX) {
54201d152c0SXinhao Zhang XEN_PT_ERR(d, "Invalid id 0x%x base 0x%x\n", id, base);
54380b4ecc8SPaolo Bonzini return -1;
54480b4ecc8SPaolo Bonzini }
54580b4ecc8SPaolo Bonzini
54664c7c117SPeter Maydell rc = xen_host_pci_get_word(hd, base + PCI_MSIX_FLAGS, &control);
54764c7c117SPeter Maydell if (rc) {
54864c7c117SPeter Maydell XEN_PT_ERR(d, "Failed to read PCI_MSIX_FLAGS field\n");
54964c7c117SPeter Maydell return rc;
55064c7c117SPeter Maydell }
55180b4ecc8SPaolo Bonzini total_entries = control & PCI_MSIX_FLAGS_QSIZE;
55280b4ecc8SPaolo Bonzini total_entries += 1;
55380b4ecc8SPaolo Bonzini
55480b4ecc8SPaolo Bonzini s->msix = g_malloc0(sizeof (XenPTMSIX)
55580b4ecc8SPaolo Bonzini + total_entries * sizeof (XenPTMSIXEntry));
55680b4ecc8SPaolo Bonzini msix = s->msix;
55780b4ecc8SPaolo Bonzini
55880b4ecc8SPaolo Bonzini msix->total_entries = total_entries;
55980b4ecc8SPaolo Bonzini for (i = 0; i < total_entries; i++) {
56080b4ecc8SPaolo Bonzini msix->msix_entry[i].pirq = XEN_PT_UNASSIGNED_PIRQ;
56180b4ecc8SPaolo Bonzini }
56280b4ecc8SPaolo Bonzini
56322fc860bSPaolo Bonzini memory_region_init_io(&msix->mmio, OBJECT(s), &pci_msix_ops,
56422fc860bSPaolo Bonzini s, "xen-pci-pt-msix",
56580b4ecc8SPaolo Bonzini (total_entries * PCI_MSIX_ENTRY_SIZE
56680b4ecc8SPaolo Bonzini + XC_PAGE_SIZE - 1)
56780b4ecc8SPaolo Bonzini & XC_PAGE_MASK);
56880b4ecc8SPaolo Bonzini
56964c7c117SPeter Maydell rc = xen_host_pci_get_long(hd, base + PCI_MSIX_TABLE, &table_off);
57064c7c117SPeter Maydell if (rc) {
57164c7c117SPeter Maydell XEN_PT_ERR(d, "Failed to read PCI_MSIX_TABLE field\n");
57264c7c117SPeter Maydell goto error_out;
57364c7c117SPeter Maydell }
57480b4ecc8SPaolo Bonzini bar_index = msix->bar_index = table_off & PCI_MSIX_FLAGS_BIRMASK;
57580b4ecc8SPaolo Bonzini table_off = table_off & ~PCI_MSIX_FLAGS_BIRMASK;
57680b4ecc8SPaolo Bonzini msix->table_base = s->real_device.io_regions[bar_index].base_addr;
57780b4ecc8SPaolo Bonzini XEN_PT_LOG(d, "get MSI-X table BAR base 0x%"PRIx64"\n", msix->table_base);
57880b4ecc8SPaolo Bonzini
57980b4ecc8SPaolo Bonzini fd = open("/dev/mem", O_RDWR);
58080b4ecc8SPaolo Bonzini if (fd == -1) {
58180b4ecc8SPaolo Bonzini rc = -errno;
58280b4ecc8SPaolo Bonzini XEN_PT_ERR(d, "Can't open /dev/mem: %s\n", strerror(errno));
58380b4ecc8SPaolo Bonzini goto error_out;
58480b4ecc8SPaolo Bonzini }
58501d152c0SXinhao Zhang XEN_PT_LOG(d, "table_off = 0x%x, total_entries = %d\n",
58680b4ecc8SPaolo Bonzini table_off, total_entries);
58780b4ecc8SPaolo Bonzini msix->table_offset_adjust = table_off & 0x0fff;
58880b4ecc8SPaolo Bonzini msix->phys_iomem_base =
58980b4ecc8SPaolo Bonzini mmap(NULL,
59080b4ecc8SPaolo Bonzini total_entries * PCI_MSIX_ENTRY_SIZE + msix->table_offset_adjust,
59180b4ecc8SPaolo Bonzini PROT_READ,
59280b4ecc8SPaolo Bonzini MAP_SHARED | MAP_LOCKED,
59380b4ecc8SPaolo Bonzini fd,
59480b4ecc8SPaolo Bonzini msix->table_base + table_off - msix->table_offset_adjust);
59580b4ecc8SPaolo Bonzini close(fd);
59680b4ecc8SPaolo Bonzini if (msix->phys_iomem_base == MAP_FAILED) {
59780b4ecc8SPaolo Bonzini rc = -errno;
59880b4ecc8SPaolo Bonzini XEN_PT_ERR(d, "Can't map physical MSI-X table: %s\n", strerror(errno));
59980b4ecc8SPaolo Bonzini goto error_out;
60080b4ecc8SPaolo Bonzini }
60180b4ecc8SPaolo Bonzini msix->phys_iomem_base = (char *)msix->phys_iomem_base
60280b4ecc8SPaolo Bonzini + msix->table_offset_adjust;
60380b4ecc8SPaolo Bonzini
60480b4ecc8SPaolo Bonzini XEN_PT_LOG(d, "mapping physical MSI-X table to %p\n",
60580b4ecc8SPaolo Bonzini msix->phys_iomem_base);
60680b4ecc8SPaolo Bonzini
60780b4ecc8SPaolo Bonzini memory_region_add_subregion_overlap(&s->bar[bar_index], table_off,
60880b4ecc8SPaolo Bonzini &msix->mmio,
60980b4ecc8SPaolo Bonzini 2); /* Priority: pci default + 1 */
61080b4ecc8SPaolo Bonzini
61180b4ecc8SPaolo Bonzini return 0;
61280b4ecc8SPaolo Bonzini
61380b4ecc8SPaolo Bonzini error_out:
61480b4ecc8SPaolo Bonzini g_free(s->msix);
61580b4ecc8SPaolo Bonzini s->msix = NULL;
61680b4ecc8SPaolo Bonzini return rc;
61780b4ecc8SPaolo Bonzini }
61880b4ecc8SPaolo Bonzini
xen_pt_msix_unmap(XenPCIPassthroughState * s)6194e494de6SLan Tianyu void xen_pt_msix_unmap(XenPCIPassthroughState *s)
62080b4ecc8SPaolo Bonzini {
62180b4ecc8SPaolo Bonzini XenPTMSIX *msix = s->msix;
62280b4ecc8SPaolo Bonzini
62380b4ecc8SPaolo Bonzini if (!msix) {
62480b4ecc8SPaolo Bonzini return;
62580b4ecc8SPaolo Bonzini }
62680b4ecc8SPaolo Bonzini
62780b4ecc8SPaolo Bonzini /* unmap the MSI-X memory mapped register area */
62880b4ecc8SPaolo Bonzini if (msix->phys_iomem_base) {
62980b4ecc8SPaolo Bonzini XEN_PT_LOG(&s->dev, "unmapping physical MSI-X table from %p\n",
63080b4ecc8SPaolo Bonzini msix->phys_iomem_base);
63180b4ecc8SPaolo Bonzini munmap(msix->phys_iomem_base, msix->total_entries * PCI_MSIX_ENTRY_SIZE
63280b4ecc8SPaolo Bonzini + msix->table_offset_adjust);
63380b4ecc8SPaolo Bonzini }
63480b4ecc8SPaolo Bonzini
63580b4ecc8SPaolo Bonzini memory_region_del_subregion(&s->bar[msix->bar_index], &msix->mmio);
6364e494de6SLan Tianyu }
6374e494de6SLan Tianyu
xen_pt_msix_delete(XenPCIPassthroughState * s)6384e494de6SLan Tianyu void xen_pt_msix_delete(XenPCIPassthroughState *s)
6394e494de6SLan Tianyu {
6404e494de6SLan Tianyu XenPTMSIX *msix = s->msix;
6414e494de6SLan Tianyu
6424e494de6SLan Tianyu if (!msix) {
6434e494de6SLan Tianyu return;
6444e494de6SLan Tianyu }
6454e494de6SLan Tianyu
6464e494de6SLan Tianyu object_unparent(OBJECT(&msix->mmio));
64780b4ecc8SPaolo Bonzini
64880b4ecc8SPaolo Bonzini g_free(s->msix);
64980b4ecc8SPaolo Bonzini s->msix = NULL;
65080b4ecc8SPaolo Bonzini }
651