xen-devel.lists.xenproject.org archive mirror
 help / color / mirror / Atom feed
From: Paul Durrant <Paul.Durrant@citrix.com>
To: "xen-devel@lists.xenproject.org" <xen-devel@lists.xenproject.org>
Cc: Andrew Cooper <Andrew.Cooper3@citrix.com>,
	"julien.grall@arm.com" <julien.grall@arm.com>,
	Jan Beulich <jbeulich@suse.com>,
	"boris.ostrovsky@oracle.com" <boris.ostrovsky@oracle.com>,
	Roger Pau Monne <roger.pau@citrix.com>
Subject: Re: [PATCH v4 7/9] vpci/msi: add MSI handlers
Date: Tue, 18 Jul 2017 08:56:44 +0000	[thread overview]
Message-ID: <7dd7fdb9eac4441dafd0b03763c42c8d@AMSPEX02CL01.citrite.net> (raw)
In-Reply-To: <20170630150117.88489-8-roger.pau@citrix.com>

> -----Original Message-----
> From: Roger Pau Monne [mailto:roger.pau@citrix.com]
> Sent: 30 June 2017 16:01
> To: xen-devel@lists.xenproject.org
> Cc: boris.ostrovsky@oracle.com; julien.grall@arm.com;
> konrad.wilk@oracle.com; Roger Pau Monne <roger.pau@citrix.com>; Jan
> Beulich <jbeulich@suse.com>; Andrew Cooper
> <Andrew.Cooper3@citrix.com>; Paul Durrant <Paul.Durrant@citrix.com>
> 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@citrix.com>
> ---
> Cc: Jan Beulich <jbeulich@suse.com>
> Cc: Andrew Cooper <andrew.cooper3@citrix.com>
> Cc: Paul Durrant <paul.durrant@citrix.com>
> ---
> 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@lists.xen.org
https://lists.xen.org/xen-devel

  reply	other threads:[~2017-07-18  8:56 UTC|newest]

Thread overview: 44+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-06-30 15:01 [PATCH v4 0/9] vpci: PCI config space emulation Roger Pau Monne
2017-06-30 15:01 ` [PATCH v4 2/9] x86/mmcfg: add handlers for the PVH Dom0 MMCFG areas Roger Pau Monne
2017-07-10 13:34   ` Paul Durrant
2017-07-13 20:15   ` Jan Beulich
2017-07-14 16:33     ` Roger Pau Monné
2017-07-28 12:22       ` Jan Beulich
2017-06-30 15:01 ` [PATCH v4 3/9] x86/physdev: enable PHYSDEVOP_pci_mmcfg_reserved for PVH Dom0 Roger Pau Monne
2017-07-14 10:32   ` Jan Beulich
2017-07-20 10:23     ` Roger Pau Monne
2017-07-28 12:31       ` Jan Beulich
2017-06-30 15:01 ` [PATCH v4 4/9] xen/mm: move modify_identity_mmio to global file and drop __init Roger Pau Monne
2017-07-14 10:32   ` Jan Beulich
2017-06-30 15:01 ` [PATCH v4 5/9] xen/pci: split code to size BARs from pci_add_device Roger Pau Monne
2017-07-14 10:33   ` Jan Beulich
2017-07-20 14:00     ` Roger Pau Monne
2017-07-20 14:05       ` Roger Pau Monne
2017-07-29 16:32       ` Jan Beulich
2017-06-30 15:01 ` [PATCH v4 6/9] xen/vpci: add handlers to map the BARs Roger Pau Monne
2017-07-14 15:11   ` Jan Beulich
2017-07-24 14:58     ` Roger Pau Monne
2017-07-29 16:44       ` Jan Beulich
2017-08-08 12:35         ` Roger Pau Monné
2017-08-09  8:17           ` Jan Beulich
2017-08-09  8:22             ` Roger Pau Monné
2017-06-30 15:01 ` [PATCH v4 7/9] vpci/msi: add MSI handlers Roger Pau Monne
2017-07-18  8:56   ` Paul Durrant [this message]
2017-08-02 13:34   ` Jan Beulich
2017-08-08 15:44     ` Roger Pau Monné
2017-08-09  8:21       ` Jan Beulich
2017-08-09  8:39         ` Roger Pau Monné
2017-06-30 15:01 ` [PATCH v4 8/9] vpci: add a priority parameter to the vPCI register initializer Roger Pau Monne
2017-08-02 14:13   ` Jan Beulich
2017-06-30 15:01 ` [PATCH v4 9/9] vpci/msix: add MSI-X handlers Roger Pau Monne
2017-08-02 15:07   ` Jan Beulich
2017-08-10 17:04     ` Roger Pau Monné
2017-08-11 10:01       ` Jan Beulich
2017-08-11 10:11         ` Roger Pau Monné
2017-08-11 10:20           ` Jan Beulich
     [not found] ` <20170630150117.88489-2-roger.pau@citrix.com>
2017-07-10 13:27   ` [PATCH v4 1/9] xen/vpci: introduce basic handlers to trap accesses to the PCI config space Paul Durrant
2017-07-13 14:36   ` Jan Beulich
2017-07-14 15:33     ` Roger Pau Monné
2017-07-14 16:01       ` Jan Beulich
2017-07-14 16:41         ` Roger Pau Monné
2017-07-28 12:25           ` Jan Beulich

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=7dd7fdb9eac4441dafd0b03763c42c8d@AMSPEX02CL01.citrite.net \
    --to=paul.durrant@citrix.com \
    --cc=Andrew.Cooper3@citrix.com \
    --cc=boris.ostrovsky@oracle.com \
    --cc=jbeulich@suse.com \
    --cc=julien.grall@arm.com \
    --cc=roger.pau@citrix.com \
    --cc=xen-devel@lists.xenproject.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).