[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH v3 8/9] vpci/msi: add MSI handlers
Add handlers for the MSI control, address, data and mask fields in order to detect accesses to them and setup the interrupts as requested by the guest. Note that the pending register is not trapped, and the guest can freely read/write to it. Whether Xen is going to provide this functionality to Dom0 (MSI emulation) is controlled by the "msi" option in the dom0 field. When disabling this option Xen will hide the MSI capability structure from Dom0. Signed-off-by: Roger Pau Monné <roger.pau@xxxxxxxxxx> --- Cc: Jan Beulich <jbeulich@xxxxxxxx> Cc: Andrew Cooper <andrew.cooper3@xxxxxxxxxx> Cc: Paul Durrant <paul.durrant@xxxxxxxxxx> --- Changes since v2: - Add an arch-specific abstraction layer. Note that this is only implemented for x86 currently. - Add a wrapper to detect MSI enabling for vPCI. NB: I've only been able to test this with devices using a single MSI interrupt and no mask register. I will try to find hardware that supports the mask register and more than one vector, but I cannot make any promises. If there are doubts about the untested parts we could always force Xen to report no per-vector masking support and only 1 available vector, but I would rather avoid doing it. --- docs/misc/xen-command-line.markdown | 9 +- xen/arch/x86/dom0_build.c | 12 +- xen/arch/x86/hvm/vmsi.c | 141 +++++++++++++ xen/drivers/vpci/Makefile | 2 +- xen/drivers/vpci/capabilities.c | 7 +- xen/drivers/vpci/msi.c | 392 ++++++++++++++++++++++++++++++++++++ xen/include/asm-x86/hvm/io.h | 19 ++ xen/include/xen/hvm/irq.h | 1 + xen/include/xen/vpci.h | 26 +++ 9 files changed, 601 insertions(+), 8 deletions(-) create mode 100644 xen/drivers/vpci/msi.c diff --git a/docs/misc/xen-command-line.markdown b/docs/misc/xen-command-line.markdown index 44d99852aa..73013aea14 100644 --- a/docs/misc/xen-command-line.markdown +++ b/docs/misc/xen-command-line.markdown @@ -660,7 +660,7 @@ affinities to prefer but be not limited to the specified node(s). Pin dom0 vcpus to their respective pcpus ### dom0 -> `= List of [ pvh | shadow ]` +> `= List of [ pvh | shadow | msi ]` > Sub-options: @@ -677,6 +677,13 @@ Flag that makes a dom0 boot in PVHv2 mode. Flag that makes a dom0 use shadow paging. Only works when "pvh" is enabled. +> `msi` + +> Default: `true` + +Enable or disable (using the `no-` prefix) the MSI emulation inside of +Xen for a PVH Dom0. Note that this option has no effect on a PV Dom0. + ### dtuart (ARM) > `= path [:options]` diff --git a/xen/arch/x86/dom0_build.c b/xen/arch/x86/dom0_build.c index cc8acad688..01afcf6215 100644 --- a/xen/arch/x86/dom0_build.c +++ b/xen/arch/x86/dom0_build.c @@ -176,29 +176,37 @@ struct vcpu *__init alloc_dom0_vcpu0(struct domain *dom0) bool __initdata opt_dom0_shadow; #endif bool __initdata dom0_pvh; +bool __initdata dom0_msi = true; /* * List of parameters that affect Dom0 creation: * * - pvh Create a PVHv2 Dom0. * - shadow Use shadow paging for Dom0. + * - msi MSI functionality. */ static void __init parse_dom0_param(char *s) { char *ss; + bool enabled; do { + enabled = !!strncmp(s, "no-", 3); + if ( !enabled ) + s += 3; ss = strchr(s, ','); if ( ss ) *ss = '\0'; if ( !strcmp(s, "pvh") ) - dom0_pvh = true; + dom0_pvh = enabled; #ifdef CONFIG_SHADOW_PAGING else if ( !strcmp(s, "shadow") ) - opt_dom0_shadow = true; + opt_dom0_shadow = enabled; #endif + else if ( !strcmp(s, "msi") ) + dom0_msi = enabled; s = ss + 1; } while ( ss ); diff --git a/xen/arch/x86/hvm/vmsi.c b/xen/arch/x86/hvm/vmsi.c index a36692c313..f23b2f43d6 100644 --- a/xen/arch/x86/hvm/vmsi.c +++ b/xen/arch/x86/hvm/vmsi.c @@ -622,3 +622,144 @@ void msix_write_completion(struct vcpu *v) if ( msixtbl_write(v, ctrl_address, 4, 0) != X86EMUL_OKAY ) gdprintk(XENLOG_WARNING, "MSI-X write completion failure\n"); } + +static unsigned int msi_vector(uint16_t data) +{ + return (data & MSI_DATA_VECTOR_MASK) >> MSI_DATA_VECTOR_SHIFT; +} + +static unsigned int msi_flags(uint16_t data, uint64_t addr) +{ + unsigned int rh, dm, dest_id, deliv_mode, trig_mode; + + rh = (addr >> MSI_ADDR_REDIRECTION_SHIFT) & 0x1; + dm = (addr >> MSI_ADDR_DESTMODE_SHIFT) & 0x1; + dest_id = (addr & MSI_ADDR_DEST_ID_MASK) >> MSI_ADDR_DEST_ID_SHIFT; + deliv_mode = (data >> MSI_DATA_DELIVERY_MODE_SHIFT) & 0x7; + trig_mode = (data >> MSI_DATA_TRIGGER_SHIFT) & 0x1; + + return dest_id | (rh << GFLAGS_SHIFT_RH) | (dm << GFLAGS_SHIFT_DM) | + (deliv_mode << GFLAGS_SHIFT_DELIV_MODE) | + (trig_mode << GFLAGS_SHIFT_TRG_MODE); +} + +void vpci_msi_mask(struct vpci_arch_msi *arch, unsigned int entry, bool mask) +{ + struct pirq *pinfo; + struct irq_desc *desc; + unsigned long flags; + int irq; + + ASSERT(arch->pirq != -1); + pinfo = pirq_info(current->domain, arch->pirq + entry); + ASSERT(pinfo); + + irq = pinfo->arch.irq; + ASSERT(irq < nr_irqs); + + desc = irq_to_desc(irq); + ASSERT(desc); + + spin_lock_irqsave(&desc->lock, flags); + guest_mask_msi_irq(desc, mask); + spin_unlock_irqrestore(&desc->lock, flags); +} + +int vpci_msi_enable(struct vpci_arch_msi *arch, struct pci_dev *pdev, + uint64_t address, uint32_t data, unsigned int vectors) +{ + struct msi_info msi_info = { + .seg = pdev->seg, + .bus = pdev->bus, + .devfn = pdev->devfn, + .entry_nr = vectors, + }; + int index = -1, rc; + unsigned int i; + + ASSERT(arch->pirq == -1); + + /* Get a PIRQ. */ + rc = allocate_and_map_msi_pirq(pdev->domain, &index, &arch->pirq, + &msi_info); + if ( rc ) + { + dprintk(XENLOG_ERR, "%04x:%02x:%02x.%u: failed to map PIRQ: %d\n", + pdev->seg, pdev->bus, PCI_SLOT(pdev->devfn), + PCI_FUNC(pdev->devfn), rc); + return rc; + } + + for ( i = 0; i < vectors; i++ ) + { + xen_domctl_bind_pt_irq_t bind = { + .hvm_domid = DOMID_SELF, + .machine_irq = arch->pirq + i, + .irq_type = PT_IRQ_TYPE_MSI, + .u.msi.gvec = msi_vector(data) + i, + .u.msi.gflags = msi_flags(data, address), + }; + + pcidevs_lock(); + rc = pt_irq_create_bind(pdev->domain, &bind); + if ( rc ) + { + dprintk(XENLOG_ERR, + "%04x:%02x:%02x.%u: failed to bind PIRQ %u: %d\n", + pdev->seg, pdev->bus, PCI_SLOT(pdev->devfn), + PCI_FUNC(pdev->devfn), arch->pirq + i, rc); + spin_lock(&pdev->domain->event_lock); + unmap_domain_pirq(pdev->domain, arch->pirq); + spin_unlock(&pdev->domain->event_lock); + pcidevs_unlock(); + arch->pirq = -1; + return rc; + } + pcidevs_unlock(); + } + + return 0; +} + +int vpci_msi_disable(struct vpci_arch_msi *arch, struct pci_dev *pdev, + unsigned int vectors) +{ + unsigned int i; + + ASSERT(arch->pirq != -1); + + for ( i = 0; i < vectors; i++ ) + { + xen_domctl_bind_pt_irq_t bind = { + .hvm_domid = DOMID_SELF, + .machine_irq = arch->pirq + i, + .irq_type = PT_IRQ_TYPE_MSI, + }; + + pcidevs_lock(); + pt_irq_destroy_bind(pdev->domain, &bind); + pcidevs_unlock(); + } + + pcidevs_lock(); + spin_lock(&pdev->domain->event_lock); + unmap_domain_pirq(pdev->domain, arch->pirq); + spin_unlock(&pdev->domain->event_lock); + pcidevs_unlock(); + + arch->pirq = -1; + + return 0; +} + +int vpci_msi_arch_init(struct vpci_arch_msi *arch) +{ + arch->pirq = -1; + return 0; +} + +void vpci_msi_arch_print(struct vpci_arch_msi *arch) +{ + printk("PIRQ: %d\n", arch->pirq); +} + diff --git a/xen/drivers/vpci/Makefile b/xen/drivers/vpci/Makefile index c3f3085c93..ef4fc6caf3 100644 --- a/xen/drivers/vpci/Makefile +++ b/xen/drivers/vpci/Makefile @@ -1 +1 @@ -obj-y += vpci.o header.o capabilities.o +obj-y += vpci.o header.o capabilities.o msi.o diff --git a/xen/drivers/vpci/capabilities.c b/xen/drivers/vpci/capabilities.c index 204355e673..ad9f45c2e1 100644 --- a/xen/drivers/vpci/capabilities.c +++ b/xen/drivers/vpci/capabilities.c @@ -109,7 +109,7 @@ static int vpci_index_capabilities(struct pci_dev *pdev) return 0; } -static void vpci_mask_capability(struct pci_dev *pdev, uint8_t cap_id) +void xen_vpci_mask_capability(struct pci_dev *pdev, uint8_t cap_id) { struct vpci_capability *cap; uint8_t cap_offset; @@ -138,9 +138,8 @@ static int vpci_capabilities_init(struct pci_dev *pdev) if ( rc ) return rc; - /* Mask MSI and MSI-X capabilities until Xen handles them. */ - vpci_mask_capability(pdev, PCI_CAP_ID_MSI); - vpci_mask_capability(pdev, PCI_CAP_ID_MSIX); + /* Mask MSI-X capability until Xen handles it. */ + xen_vpci_mask_capability(pdev, PCI_CAP_ID_MSIX); return 0; } diff --git a/xen/drivers/vpci/msi.c b/xen/drivers/vpci/msi.c new file mode 100644 index 0000000000..318dc0e626 --- /dev/null +++ b/xen/drivers/vpci/msi.c @@ -0,0 +1,392 @@ +/* + * Handlers for accesses to the MSI capability structure. + * + * Copyright (C) 2017 Citrix Systems R&D + * + * This program is free software; you can redistribute it and/or + * modify it under the terms and conditions of the GNU General Public + * License, version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; If not, see <http://www.gnu.org/licenses/>. + */ + +#include <xen/sched.h> +#include <xen/vpci.h> +#include <asm/msi.h> +#include <xen/keyhandler.h> + +/* Handlers for the MSI control field (PCI_MSI_FLAGS). */ +static int vpci_msi_control_read(struct pci_dev *pdev, unsigned int reg, + union vpci_val *val, void *data) +{ + struct vpci_msi *msi = data; + + if ( msi->enabled ) + val->word |= PCI_MSI_FLAGS_ENABLE; + if ( msi->masking ) + val->word |= PCI_MSI_FLAGS_MASKBIT; + if ( msi->address64 ) + val->word |= PCI_MSI_FLAGS_64BIT; + + /* Set multiple message capable. */ + val->word |= ((fls(msi->max_vectors) - 1) << 1) & PCI_MSI_FLAGS_QMASK; + + /* Set current number of configured vectors. */ + val->word |= ((fls(msi->guest_vectors) - 1) << 4) & PCI_MSI_FLAGS_QSIZE; + + return 0; +} + +static int vpci_msi_control_write(struct pci_dev *pdev, unsigned int reg, + union vpci_val val, void *data) +{ + struct vpci_msi *msi = data; + unsigned int vectors = 1 << ((val.word & PCI_MSI_FLAGS_QSIZE) >> 4); + int rc; + + if ( vectors > msi->max_vectors ) + return -EINVAL; + + msi->guest_vectors = vectors; + + if ( !!(val.word & PCI_MSI_FLAGS_ENABLE) == msi->enabled ) + return 0; + + if ( val.word & PCI_MSI_FLAGS_ENABLE ) + { + ASSERT(!msi->enabled && !msi->vectors); + + rc = vpci_msi_enable(&msi->arch, pdev, msi->address, msi->data, + vectors); + if ( rc ) + return rc; + + /* Apply the mask bits. */ + if ( msi->masking ) + { + uint32_t mask = msi->mask; + + while ( mask ) + { + unsigned int i = ffs(mask); + + vpci_msi_mask(&msi->arch, i, true); + __clear_bit(i, &mask); + } + } + + __msi_set_enable(pdev->seg, pdev->bus, PCI_SLOT(pdev->devfn), + PCI_FUNC(pdev->devfn), reg - PCI_MSI_FLAGS, 1); + + msi->vectors = vectors; + msi->enabled = true; + } + else + { + ASSERT(msi->enabled && msi->vectors); + + __msi_set_enable(pdev->seg, pdev->bus, PCI_SLOT(pdev->devfn), + PCI_FUNC(pdev->devfn), reg - PCI_MSI_FLAGS, 0); + + + rc = vpci_msi_disable(&msi->arch, pdev, msi->vectors); + if ( rc ) + return rc; + + msi->vectors = 0; + msi->enabled = false; + } + + return rc; +} + +/* Handlers for the address field (32bit or low part of a 64bit address). */ +static int vpci_msi_address_read(struct pci_dev *pdev, unsigned int reg, + union vpci_val *val, void *data) +{ + struct vpci_msi *msi = data; + + val->double_word = msi->address; + + return 0; +} + +static int vpci_msi_address_write(struct pci_dev *pdev, unsigned int reg, + union vpci_val val, void *data) +{ + struct vpci_msi *msi = data; + + /* Clear low part. */ + msi->address &= ~GENMASK(31, 0); + msi->address |= val.double_word; + + return 0; +} + +/* Handlers for the high part of a 64bit address field. */ +static int vpci_msi_address_upper_read(struct pci_dev *pdev, unsigned int reg, + union vpci_val *val, void *data) +{ + struct vpci_msi *msi = data; + + val->double_word = msi->address >> 32; + + return 0; +} + +static int vpci_msi_address_upper_write(struct pci_dev *pdev, unsigned int reg, + union vpci_val val, void *data) +{ + struct vpci_msi *msi = data; + + /* Clear high part. */ + msi->address &= ~GENMASK(63, 32); + msi->address |= (uint64_t)val.double_word << 32; + + return 0; +} + +/* Handlers for the data field. */ +static int vpci_msi_data_read(struct pci_dev *pdev, unsigned int reg, + union vpci_val *val, void *data) +{ + struct vpci_msi *msi = data; + + val->word = msi->data; + + return 0; +} + +static int vpci_msi_data_write(struct pci_dev *pdev, unsigned int reg, + union vpci_val val, void *data) +{ + struct vpci_msi *msi = data; + + msi->data = val.word; + + return 0; +} + +static int vpci_msi_mask_read(struct pci_dev *pdev, unsigned int reg, + union vpci_val *val, void *data) +{ + struct vpci_msi *msi = data; + + val->double_word = msi->mask; + + return 0; +} + +static int vpci_msi_mask_write(struct pci_dev *pdev, unsigned int reg, + union vpci_val val, void *data) +{ + struct vpci_msi *msi = data; + uint32_t dmask; + + dmask = msi->mask ^ val.double_word; + + if ( !dmask ) + return 0; + + while ( dmask && msi->enabled ) + { + unsigned int i = ffs(dmask); + + vpci_msi_mask(&msi->arch, i, !test_bit(i, &msi->mask)); + __clear_bit(i, &dmask); + } + + msi->mask = val.double_word; + return 0; +} + +static int vpci_init_msi(struct pci_dev *pdev) +{ + uint8_t seg = pdev->seg, bus = pdev->bus; + uint8_t slot = PCI_SLOT(pdev->devfn), func = PCI_FUNC(pdev->devfn); + struct vpci_msi *msi = NULL; + unsigned int msi_offset; + uint16_t control; + int rc; + + msi_offset = pci_find_cap_offset(seg, bus, slot, func, PCI_CAP_ID_MSI); + if ( !msi_offset ) + return 0; + + if ( !vpci_msi_enabled(pdev->domain) ) + { + xen_vpci_mask_capability(pdev, PCI_CAP_ID_MSI); + return 0; + } + + msi = xzalloc(struct vpci_msi); + if ( !msi ) + return -ENOMEM; + + control = pci_conf_read16(seg, bus, slot, func, + msi_control_reg(msi_offset)); + + rc = xen_vpci_add_register(pdev, vpci_msi_control_read, + vpci_msi_control_write, + msi_control_reg(msi_offset), 2, msi); + if ( rc ) + { + dprintk(XENLOG_ERR, + "%04x:%02x:%02x.%u: failed to add handler for MSI control: %d\n", + seg, bus, slot, func, rc); + goto error; + } + + /* Get the maximum number of vectors the device supports. */ + msi->max_vectors = multi_msi_capable(control); + ASSERT(msi->max_vectors <= 32); + + /* Initial value after reset. */ + msi->guest_vectors = 1; + + /* No PIRQ bind yet. */ + vpci_msi_arch_init(&msi->arch); + + if ( is_64bit_address(control) ) + msi->address64 = true; + if ( is_mask_bit_support(control) ) + msi->masking = true; + + rc = xen_vpci_add_register(pdev, vpci_msi_address_read, + vpci_msi_address_write, + msi_lower_address_reg(msi_offset), 4, msi); + if ( rc ) + { + dprintk(XENLOG_ERR, + "%04x:%02x:%02x.%u: failed to add handler for MSI address: %d\n", + seg, bus, slot, func, rc); + goto error; + } + + rc = xen_vpci_add_register(pdev, vpci_msi_data_read, vpci_msi_data_write, + msi_data_reg(msi_offset, msi->address64), 2, + msi); + if ( rc ) + { + dprintk(XENLOG_ERR, + "%04x:%02x:%02x.%u: failed to add handler for MSI address: %d\n", + seg, bus, slot, func, rc); + goto error; + } + + if ( msi->address64 ) + { + rc = xen_vpci_add_register(pdev, vpci_msi_address_upper_read, + vpci_msi_address_upper_write, + msi_upper_address_reg(msi_offset), 4, msi); + if ( rc ) + { + dprintk(XENLOG_ERR, + "%04x:%02x:%02x.%u: failed to add handler for MSI address: %d\n", + seg, bus, slot, func, rc); + goto error; + } + } + + if ( msi->masking ) + { + rc = xen_vpci_add_register(pdev, vpci_msi_mask_read, + vpci_msi_mask_write, + msi_mask_bits_reg(msi_offset, + msi->address64), 4, msi); + if ( rc ) + { + dprintk(XENLOG_ERR, + "%04x:%02x:%02x.%u: failed to add handler for MSI mask: %d\n", + seg, bus, slot, func, rc); + goto error; + } + } + + pdev->vpci->msi = msi; + + return 0; + + error: + ASSERT(rc); + xfree(msi); + return rc; +} + +REGISTER_VPCI_INIT(vpci_init_msi, false); + +static void vpci_dump_msi(unsigned char key) +{ + struct domain *d; + struct pci_dev *pdev; + + printk("Guest MSI information:\n"); + + for_each_domain ( d ) + { + if ( !has_vpci(d) ) + continue; + + vpci_lock(d); + list_for_each_entry ( pdev, &d->arch.pdev_list, domain_list) + { + uint8_t seg = pdev->seg, bus = pdev->bus; + uint8_t slot = PCI_SLOT(pdev->devfn), func = PCI_FUNC(pdev->devfn); + struct vpci_msi *msi = pdev->vpci->msi; + uint16_t data; + uint64_t addr; + + if ( !msi ) + continue; + + printk("Device %04x:%02x:%02x.%u\n", seg, bus, slot, func); + + printk("Enabled: %u Supports masking: %u 64-bit addresses: %u\n", + msi->enabled, msi->masking, msi->address64); + printk("Max vectors: %u guest vectors: %u enabled vectors: %u\n", + msi->max_vectors, msi->guest_vectors, msi->vectors); + + vpci_msi_arch_print(&msi->arch); + + data = msi->data; + addr = msi->address; + printk("vec=%#02x%7s%6s%3sassert%5s%7s dest_id=%lu\n", + (data & MSI_DATA_VECTOR_MASK) >> MSI_DATA_VECTOR_SHIFT, + data & MSI_DATA_DELIVERY_LOWPRI ? "lowest" : "fixed", + data & MSI_DATA_TRIGGER_LEVEL ? "level" : "edge", + data & MSI_DATA_LEVEL_ASSERT ? "" : "de", + addr & MSI_ADDR_DESTMODE_LOGIC ? "log" : "phys", + addr & MSI_ADDR_REDIRECTION_LOWPRI ? "lowest" : "cpu", + (addr & MSI_ADDR_DEST_ID_MASK) >> MSI_ADDR_DEST_ID_SHIFT); + + if ( msi->masking ) + printk("mask=%#032x\n", msi->mask); + printk("\n"); + } + vpci_unlock(d); + } +} + +static int __init vpci_msi_setup_keyhandler(void) +{ + register_keyhandler('Z', vpci_dump_msi, "dump guest MSI state", 1); + return 0; +} +__initcall(vpci_msi_setup_keyhandler); + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ + diff --git a/xen/include/asm-x86/hvm/io.h b/xen/include/asm-x86/hvm/io.h index f9b9829eaf..ae3af43749 100644 --- a/xen/include/asm-x86/hvm/io.h +++ b/xen/include/asm-x86/hvm/io.h @@ -20,6 +20,7 @@ #define __ASM_X86_HVM_IO_H__ #include <xen/mm.h> +#include <xen/pci.h> #include <asm/hvm/vpic.h> #include <asm/hvm/vioapic.h> #include <public/hvm/ioreq.h> @@ -126,6 +127,24 @@ void hvm_dpci_eoi(struct domain *d, unsigned int guest_irq, void msix_write_completion(struct vcpu *); void msixtbl_init(struct domain *d); +/* Is emulated MSI enabled? */ +extern bool dom0_msi; +#define vpci_msi_enabled(d) (!is_hardware_domain((d)) || dom0_msi) + +/* Arch-specific MSI data for vPCI. */ +struct vpci_arch_msi { + int pirq; +}; + +/* Arch-specific vPCI MSI helpers. */ +void vpci_msi_mask(struct vpci_arch_msi *arch, unsigned int entry, bool mask); +int vpci_msi_enable(struct vpci_arch_msi *arch, struct pci_dev *pdev, + uint64_t address, uint32_t data, unsigned int vectors); +int vpci_msi_disable(struct vpci_arch_msi *arch, struct pci_dev *pdev, + unsigned int vectors); +int vpci_msi_arch_init(struct vpci_arch_msi *arch); +void vpci_msi_arch_print(struct vpci_arch_msi *arch); + enum stdvga_cache_state { STDVGA_CACHE_UNINITIALIZED, STDVGA_CACHE_ENABLED, diff --git a/xen/include/xen/hvm/irq.h b/xen/include/xen/hvm/irq.h index 0d2c72c109..37dfb3b6c5 100644 --- a/xen/include/xen/hvm/irq.h +++ b/xen/include/xen/hvm/irq.h @@ -58,6 +58,7 @@ struct dev_intx_gsi_link { #define VMSI_TRIG_MODE 0x8000 #define GFLAGS_SHIFT_RH 8 +#define GFLAGS_SHIFT_DM 9 #define GFLAGS_SHIFT_DELIV_MODE 12 #define GFLAGS_SHIFT_TRG_MODE 15 diff --git a/xen/include/xen/vpci.h b/xen/include/xen/vpci.h index 2bf61d6c15..373b8d6505 100644 --- a/xen/include/xen/vpci.h +++ b/xen/include/xen/vpci.h @@ -89,9 +89,35 @@ struct vpci { /* List of capabilities supported by the device. */ struct list_head cap_list; + + /* MSI data. */ + struct vpci_msi { + /* Maximum number of vectors supported by the device. */ + unsigned int max_vectors; + /* Current guest-written number of vectors. */ + unsigned int guest_vectors; + /* Number of vectors configured. */ + unsigned int vectors; + /* Address and data fields. */ + uint64_t address; + uint16_t data; + /* Mask bitfield. */ + uint32_t mask; + /* Enabled? */ + bool enabled; + /* Supports per-vector masking? */ + bool masking; + /* 64-bit address capable? */ + bool address64; + /* Arch-specific data. */ + struct vpci_arch_msi arch; + } *msi; #endif }; +/* Mask a PCI capability. */ +void xen_vpci_mask_capability(struct pci_dev *pdev, uint8_t cap_id); + #endif /* -- 2.11.0 (Apple Git-81) _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx https://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |