[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Xen-devel] [PATCH v4 7/9] vpci/msi: add MSI handlers



> -----Original Message-----
> From: Roger Pau Monne [mailto:roger.pau@xxxxxxxxxx]
> Sent: 30 June 2017 16:01
> To: xen-devel@xxxxxxxxxxxxxxxxxxxx
> Cc: boris.ostrovsky@xxxxxxxxxx; julien.grall@xxxxxxx;
> konrad.wilk@xxxxxxxxxx; Roger Pau Monne <roger.pau@xxxxxxxxxx>; Jan
> Beulich <jbeulich@xxxxxxxx>; Andrew Cooper
> <Andrew.Cooper3@xxxxxxxxxx>; Paul Durrant <Paul.Durrant@xxxxxxxxxx>
> Subject: [PATCH v4 7/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 v3:
>  - Propagate changes from previous versions: drop xen_ prefix, drop
>    return value from handlers, use the new vpci_val fields.
>  - Use MASK_EXTR.
>  - Remove the usage of GENMASK.
>  - Add GFLAGS_SHIFT_DEST_ID and use it in msi_flags.
>  - Add "arch" to the MSI arch specific functions.
>  - Move the dumping of vPCI MSI information to dump_msi (key 'M').
>  - Remove the guest_vectors field.
>  - Allow the guest to change the number of active vectors without
>    having to disable and enable MSI.
>  - Check the number of active vectors when parsing the disable
>    mask.
>  - Remove the debug messages from vpci_init_msi.
>  - Move the arch-specific part of the dump handler to x86/hvm/vmsi.c.
>  - Use trylock in the dump handler to get the vpci lock.
> 
> 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.
> ---
>  xen/arch/x86/hvm/vmsi.c      | 149 ++++++++++++++++++
>  xen/arch/x86/msi.c           |   3 +
>  xen/drivers/vpci/Makefile    |   2 +-
>  xen/drivers/vpci/msi.c       | 348
> +++++++++++++++++++++++++++++++++++++++++++
>  xen/include/asm-x86/hvm/io.h |  18 +++
>  xen/include/asm-x86/msi.h    |   1 +
>  xen/include/xen/hvm/irq.h    |   2 +
>  xen/include/xen/vpci.h       |  26 ++++
>  8 files changed, 548 insertions(+), 1 deletion(-)
>  create mode 100644 xen/drivers/vpci/msi.c
> 
> diff --git a/xen/arch/x86/hvm/vmsi.c b/xen/arch/x86/hvm/vmsi.c
> index a36692c313..5732c70b5c 100644
> --- a/xen/arch/x86/hvm/vmsi.c
> +++ b/xen/arch/x86/hvm/vmsi.c
> @@ -622,3 +622,152 @@ 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 MASK_EXTR(data, MSI_DATA_VECTOR_MASK);
> +}
> +
> +static unsigned int msi_flags(uint16_t data, uint64_t addr)
> +{
> +    unsigned int rh, dm, dest_id, deliv_mode, trig_mode;
> +
> +    rh = MASK_EXTR(addr, MSI_ADDR_REDIRECTION_MASK);
> +    dm = MASK_EXTR(addr, MSI_ADDR_DESTMODE_MASK);
> +    dest_id = MASK_EXTR(addr, MSI_ADDR_DEST_ID_MASK);
> +    deliv_mode = MASK_EXTR(data, MSI_DATA_DELIVERY_MODE_MASK);
> +    trig_mode = MASK_EXTR(data, MSI_DATA_TRIGGER_MASK);
> +
> +    return (dest_id << GFLAGS_SHIFT_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_arch_mask(struct vpci_arch_msi *arch, struct pci_dev *pdev,
> +                        unsigned int entry, bool mask)
> +{
> +    struct domain *d = pdev->domain;
> +    const struct pirq *pinfo;
> +    struct irq_desc *desc;
> +    unsigned long flags;
> +    int irq;
> +
> +    ASSERT(arch->pirq >= 0);
> +    pinfo = pirq_info(d, arch->pirq + entry);
> +    ASSERT(pinfo);
> +
> +    irq = pinfo->arch.irq;
> +    ASSERT(irq < nr_irqs && irq >= 0);
> +
> +    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_arch_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,
> +    };
> +    unsigned int i;
> +    int rc;
> +
> +    ASSERT(arch->pirq == -1);
> +
> +    /* Get a PIRQ. */
> +    rc = allocate_and_map_msi_pirq(pdev->domain, -1, &arch->pirq,
> +                                   MAP_PIRQ_TYPE_MULTI_MSI, &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 = {
> +            .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_arch_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 = {
> +            .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, uint16_t data,
> +                         uint64_t addr)
> +{
> +    printk("vec=%#02x%7s%6s%3sassert%5s%7s dest_id=%lu pirq: %d\n",
> +           MASK_EXTR(data, MSI_DATA_VECTOR_MASK),
> +           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",
> +           MASK_EXTR(addr, MSI_ADDR_DEST_ID_MASK),
> +           arch->pirq);
> +}
> diff --git a/xen/arch/x86/msi.c b/xen/arch/x86/msi.c
> index d98f400699..573378d6c3 100644
> --- a/xen/arch/x86/msi.c
> +++ b/xen/arch/x86/msi.c
> @@ -30,6 +30,7 @@
>  #include <public/physdev.h>
>  #include <xen/iommu.h>
>  #include <xsm/xsm.h>
> +#include <xen/vpci.h>
> 
>  static s8 __read_mostly use_msi = -1;
>  boolean_param("msi", use_msi);
> @@ -1536,6 +1537,8 @@ static void dump_msi(unsigned char key)
>                 attr.guest_masked ? 'G' : ' ',
>                 mask);
>      }
> +
> +    vpci_dump_msi();
>  }
> 
>  static int __init msi_setup_keyhandler(void)
> diff --git a/xen/drivers/vpci/Makefile b/xen/drivers/vpci/Makefile
> index 241467212f..62cec9e82b 100644
> --- a/xen/drivers/vpci/Makefile
> +++ b/xen/drivers/vpci/Makefile
> @@ -1 +1 @@
> -obj-y += vpci.o header.o
> +obj-y += vpci.o header.o msi.o
> diff --git a/xen/drivers/vpci/msi.c b/xen/drivers/vpci/msi.c
> new file mode 100644
> index 0000000000..d8f3418616
> --- /dev/null
> +++ b/xen/drivers/vpci/msi.c
> @@ -0,0 +1,348 @@
> +/*
> + * 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 void vpci_msi_control_read(struct pci_dev *pdev, unsigned int reg,
> +                                  union vpci_val *val, void *data)
> +{
> +    const struct vpci_msi *msi = data;
> +
> +    /* Set multiple message capable. */
> +    val->u16 = MASK_INSR(fls(msi->max_vectors) - 1,
> PCI_MSI_FLAGS_QMASK);
> +
> +    if ( msi->enabled ) {
> +        val->u16 |= PCI_MSI_FLAGS_ENABLE;
> +        val->u16 |= MASK_INSR(fls(msi->vectors) - 1, PCI_MSI_FLAGS_QSIZE);
> +    }
> +    val->u16 |= msi->masking ? PCI_MSI_FLAGS_MASKBIT : 0;
> +    val->u16 |= msi->address64 ? PCI_MSI_FLAGS_64BIT : 0;
> +}
> +
> +static void vpci_msi_enable(struct pci_dev *pdev, struct vpci_msi *msi,
> +                            unsigned int vectors)
> +{
> +    int ret;
> +
> +    ASSERT(!msi->vectors);
> +
> +    ret = vpci_msi_arch_enable(&msi->arch, pdev, msi->address, msi->data,
> +                               vectors);
> +    if ( ret )
> +        return;
> +
> +    /* Apply the mask bits. */
> +    if ( msi->masking )
> +    {
> +        unsigned int i;
> +        uint32_t mask = msi->mask;
> +
> +        for ( i = ffs(mask) - 1; mask && i < vectors; i = ffs(mask) - 1 )
> +        {
> +            vpci_msi_arch_mask(&msi->arch, pdev, i, true);
> +            __clear_bit(i, &mask);
> +        }
> +    }
> +
> +    __msi_set_enable(pdev->seg, pdev->bus, PCI_SLOT(pdev->devfn),
> +                     PCI_FUNC(pdev->devfn), msi->pos, 1);
> +
> +    msi->vectors = vectors;
> +    msi->enabled = true;
> +}
> +
> +static int vpci_msi_disable(struct pci_dev *pdev, struct vpci_msi *msi)
> +{
> +    int ret;
> +
> +    ASSERT(msi->vectors);
> +
> +    __msi_set_enable(pdev->seg, pdev->bus, PCI_SLOT(pdev->devfn),
> +                     PCI_FUNC(pdev->devfn), msi->pos, 0);
> +
> +    ret = vpci_msi_arch_disable(&msi->arch, pdev, msi->vectors);
> +    if ( ret )
> +        return ret;
> +
> +    msi->vectors = 0;
> +    msi->enabled = false;
> +
> +    return 0;
> +}
> +
> +static void 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 << MASK_EXTR(val.u16, PCI_MSI_FLAGS_QSIZE);
> +    int ret;
> +
> +    if ( vectors > msi->max_vectors )
> +        vectors = msi->max_vectors;
> +
> +    if ( !!(val.u16 & PCI_MSI_FLAGS_ENABLE) == msi->enabled &&
> +         (vectors == msi->vectors || !msi->enabled) )
> +        return;

Personally I find the above logic a little tricky to follow. Would it be 
clearer to fold it into the logic below? (I only understood the reason for the 
logic above after reading the logic below).

> +
> +    if ( val.u16 & PCI_MSI_FLAGS_ENABLE )
> +    {
> +        if ( msi->enabled )
> +        {
> +            /*
> +             * Change to the number of enabled vectors, disable and
> +             * enable MSI in order to apply it.
> +             */
> +            ret = vpci_msi_disable(pdev, msi);
> +            if ( ret )
> +                return;
> +        }
> +        vpci_msi_enable(pdev, msi, vectors);
> +    }
> +    else
> +        vpci_msi_disable(pdev, msi);
> +}
> +
> +/* Handlers for the address field (32bit or low part of a 64bit address). */
> +static void vpci_msi_address_read(struct pci_dev *pdev, unsigned int reg,
> +                                  union vpci_val *val, void *data)
> +{
> +    const struct vpci_msi *msi = data;
> +
> +    val->u32 = msi->address;
> +}
> +
> +static void 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 &= ~(uint64_t)0xffffffff;
> +    msi->address |= val.u32;
> +}
> +
> +/* Handlers for the high part of a 64bit address field. */
> +static void vpci_msi_address_upper_read(struct pci_dev *pdev, unsigned
> int reg,
> +                                        union vpci_val *val, void *data)
> +{
> +    const struct vpci_msi *msi = data;
> +
> +    val->u32 = msi->address >> 32;
> +}
> +
> +static void 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 &= ~((uint64_t)0xffffffff << 32);
> +    msi->address |= (uint64_t)val.u32 << 32;
> +}
> +
> +/* Handlers for the data field. */
> +static void vpci_msi_data_read(struct pci_dev *pdev, unsigned int reg,
> +                               union vpci_val *val, void *data)
> +{
> +    const struct vpci_msi *msi = data;
> +
> +    val->u16 = msi->data;
> +}
> +
> +static void 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.u16;
> +}
> +
> +static void vpci_msi_mask_read(struct pci_dev *pdev, unsigned int reg,
> +                               union vpci_val *val, void *data)
> +{
> +    const struct vpci_msi *msi = data;
> +
> +    val->u32 = msi->mask;
> +}
> +
> +static void 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.u32;
> +
> +    if ( !dmask )
> +        return;
> +
> +    if ( msi->enabled )
> +    {
> +        unsigned int i;
> +
> +        for ( i = ffs(dmask) - 1; dmask && i < msi->vectors;
> +              i = ffs(dmask) - 1 )
> +        {
> +            vpci_msi_arch_mask(&msi->arch, pdev, i, MASK_EXTR(val.u32, 1 <<
> i));
> +            __clear_bit(i, &dmask);
> +        }
> +    }
> +
> +    msi->mask = val.u32;
> +}
> +
> +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;
> +    unsigned int msi_offset;
> +    uint16_t control;
> +    int ret;
> +
> +    msi_offset = pci_find_cap_offset(seg, bus, slot, func, PCI_CAP_ID_MSI);
> +    if ( !msi_offset )
> +        return 0;
> +
> +    msi = xzalloc(struct vpci_msi);
> +    if ( !msi )
> +        return -ENOMEM;
> +
> +    msi->pos = msi_offset;
> +
> +    control = pci_conf_read16(seg, bus, slot, func,
> +                              msi_control_reg(msi_offset));
> +
> +    ret = vpci_add_register(pdev, vpci_msi_control_read,
> +                            vpci_msi_control_write,
> +                            msi_control_reg(msi_offset), 2, msi);
> +    if ( ret )
> +        goto error;
> +
> +    /* Get the maximum number of vectors the device supports. */
> +    msi->max_vectors = multi_msi_capable(control);
> +    ASSERT(msi->max_vectors <= 32);
> +
> +    /* 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;
> +
> +    ret = vpci_add_register(pdev, vpci_msi_address_read,
> +                            vpci_msi_address_write,
> +                            msi_lower_address_reg(msi_offset), 4, msi);
> +    if ( ret )
> +        goto error;
> +
> +    ret = vpci_add_register(pdev, vpci_msi_data_read, vpci_msi_data_write,
> +                            msi_data_reg(msi_offset, msi->address64), 2,
> +                            msi);
> +    if ( ret )
> +        goto error;
> +
> +    if ( msi->address64 )
> +    {
> +        ret = vpci_add_register(pdev, vpci_msi_address_upper_read,
> +                                vpci_msi_address_upper_write,
> +                                msi_upper_address_reg(msi_offset), 4, msi);
> +        if ( ret )
> +            goto error;
> +    }
> +
> +    if ( msi->masking )
> +    {
> +        ret = vpci_add_register(pdev, vpci_msi_mask_read,
> vpci_msi_mask_write,
> +                                msi_mask_bits_reg(msi_offset,
> +                                                  msi->address64), 4, msi);
> +        if ( ret )
> +            goto error;
> +    }
> +
> +    pdev->vpci->msi = msi;
> +
> +    return 0;
> +
> + error:

Do you not need to clean up any added register handlers here? They have been 
given a context value which you're about to xfree().

  Paul

> +    ASSERT(ret);
> +    xfree(msi);
> +    return ret;
> +}
> +
> +REGISTER_VPCI_INIT(vpci_init_msi);
> +
> +void vpci_dump_msi(void)
> +{
> +    struct domain *d;
> +
> +    for_each_domain ( d )
> +    {
> +        const struct pci_dev *pdev;
> +
> +        if ( !has_vpci(d) )
> +            continue;
> +
> +        printk("vPCI MSI information for guest %u\n", d->domain_id);
> +
> +        if ( !vpci_trylock(d) )
> +        {
> +            printk("Unable to get vPCI lock, skipping\n");
> +            continue;
> +        }
> +
> +        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;
> +
> +            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 enabled vectors: %u\n",
> +                   msi->max_vectors, msi->vectors);
> +
> +            vpci_msi_arch_print(&msi->arch, msi->data, msi->address);
> +
> +            if ( msi->masking )
> +                printk("mask=%#032x\n", msi->mask);
> +        }
> +        vpci_unlock(d);
> +    }
> +}
> +
> +/*
> + * 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 4fe996fe49..55ed094734 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,23 @@ void hvm_dpci_eoi(struct domain *d, unsigned int
> guest_irq,
>  void msix_write_completion(struct vcpu *);
>  void msixtbl_init(struct domain *d);
> 
> +/* Arch-specific MSI data for vPCI. */
> +struct vpci_arch_msi {
> +    int pirq;
> +};
> +
> +/* Arch-specific vPCI MSI helpers. */
> +void vpci_msi_arch_mask(struct vpci_arch_msi *arch, struct pci_dev *pdev,
> +                        unsigned int entry, bool mask);
> +int vpci_msi_arch_enable(struct vpci_arch_msi *arch, struct pci_dev *pdev,
> +                         uint64_t address, uint32_t data,
> +                         unsigned int vectors);
> +int vpci_msi_arch_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, uint16_t data,
> +                         uint64_t addr);
> +
>  enum stdvga_cache_state {
>      STDVGA_CACHE_UNINITIALIZED,
>      STDVGA_CACHE_ENABLED,
> diff --git a/xen/include/asm-x86/msi.h b/xen/include/asm-x86/msi.h
> index 213ee53f72..9c36c34372 100644
> --- a/xen/include/asm-x86/msi.h
> +++ b/xen/include/asm-x86/msi.h
> @@ -48,6 +48,7 @@
>  #define MSI_ADDR_REDIRECTION_SHIFT  3
>  #define MSI_ADDR_REDIRECTION_CPU    (0 <<
> MSI_ADDR_REDIRECTION_SHIFT)
>  #define MSI_ADDR_REDIRECTION_LOWPRI (1 <<
> MSI_ADDR_REDIRECTION_SHIFT)
> +#define MSI_ADDR_REDIRECTION_MASK   0x8
> 
>  #define MSI_ADDR_DEST_ID_SHIFT               12
>  #define       MSI_ADDR_DEST_ID_MASK          0x00ff000
> diff --git a/xen/include/xen/hvm/irq.h b/xen/include/xen/hvm/irq.h
> index 0d2c72c109..d07185a479 100644
> --- a/xen/include/xen/hvm/irq.h
> +++ b/xen/include/xen/hvm/irq.h
> @@ -57,7 +57,9 @@ struct dev_intx_gsi_link {
>  #define VMSI_DELIV_MASK   0x7000
>  #define VMSI_TRIG_MODE    0x8000
> 
> +#define GFLAGS_SHIFT_DEST_ID        0
>  #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 452ee482e8..2a7d7557b3 100644
> --- a/xen/include/xen/vpci.h
> +++ b/xen/include/xen/vpci.h
> @@ -13,6 +13,7 @@
>   * of just returning whether the lock is hold by any CPU).
>   */
>  #define vpci_lock(d) spin_lock_recursive(&(d)-
> >arch.hvm_domain.vpci_lock)
> +#define vpci_trylock(d) spin_trylock_recursive(&(d)-
> >arch.hvm_domain.vpci_lock)
>  #define vpci_unlock(d) spin_unlock_recursive(&(d)-
> >arch.hvm_domain.vpci_lock)
>  #define vpci_locked(d) spin_is_locked(&(d)->arch.hvm_domain.vpci_lock)
> 
> @@ -85,9 +86,34 @@ struct vpci {
>          } bars[7]; /* At most 6 BARS + 1 expansion ROM BAR. */
>          /* FIXME: currently there's no support for SR-IOV. */
>      } header;
> +
> +    /* MSI data. */
> +    struct vpci_msi {
> +        /* Offset of the capability in the config space. */
> +        unsigned int pos;
> +        /* Maximum number of vectors supported by the device. */
> +        unsigned int max_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
>  };
> 
> +void vpci_dump_msi(void);
> +
>  #endif
> 
>  /*
> --
> 2.11.0 (Apple Git-81)

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
https://lists.xen.org/xen-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.