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

Re: [Xen-devel] [PATCH v7 for-next 09/12] vpci/bars: add handlers to map the BARs



>>> On 18.10.17 at 13:40, <roger.pau@xxxxxxxxxx> wrote:
> --- /dev/null
> +++ b/xen/drivers/vpci/header.c
> @@ -0,0 +1,518 @@
> +/*
> + * Generic functionality for handling accesses to the PCI header from the
> + * configuration space.
> + *
> + * 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 <xen/p2m-common.h>
> +#include <xen/softirq.h>

Unless there's a reason for this ordering, please sort #include-s in
new files.

> +static void modify_decoding(const struct pci_dev *pdev, bool map, bool rom)
> +{
> +    struct vpci_header *header = &pdev->vpci->header;
> +    uint8_t slot = PCI_SLOT(pdev->devfn), func = PCI_FUNC(pdev->devfn);
> +    unsigned int i;
> +
> +    for ( i = 0; i < ARRAY_SIZE(header->bars); i++ )
> +    {
> +        if ( rom && header->bars[i].type == VPCI_BAR_ROM )
> +        {
> +            unsigned int rom_pos = (i == 6) ? PCI_ROM_ADDRESS
> +                                            : PCI_ROM_ADDRESS1;
> +            uint32_t val = pci_conf_read32(pdev->seg, pdev->bus, slot, func,
> +                                           rom_pos);
> +
> +            header->bars[i].enabled = header->bars[i].rom_enabled = map;
> +
> +            val &= ~PCI_ROM_ADDRESS_ENABLE;
> +            val |= map ? PCI_ROM_ADDRESS_ENABLE : 0;
> +            pci_conf_write32(pdev->seg, pdev->bus, slot, func, rom_pos, val);
> +            break;
> +        }
> +        if ( !rom && (header->bars[i].type != VPCI_BAR_ROM ||
> +                      header->bars[i].rom_enabled) )
> +            header->bars[i].enabled = map;
> +    }

Looking at all of this, it would clearly be more logical for
rom_enabled to be a per-header instead of a per-BAR flag.

> +    if ( !rom )
> +    {
> +        uint16_t cmd = pci_conf_read16(pdev->seg, pdev->bus, slot,
> +                                       func, PCI_COMMAND);
> +
> +        cmd &= ~PCI_COMMAND_MEMORY;
> +        cmd |= map ? PCI_COMMAND_MEMORY : 0;
> +        pci_conf_write16(pdev->seg, pdev->bus, slot, func, PCI_COMMAND,
> +                         cmd);
> +    }

For both writes, wouldn't it be worthwhile to avoid them when the
flag is already in the intended state?

> +bool vpci_process_pending(struct vcpu *v)
> +{
> +    while ( v->vpci.mem )
> +    {
> +        struct map_data data = {
> +            .d = v->domain,
> +            .map = v->vpci.map,
> +        };
> +
> +        switch ( rangeset_consume_ranges(v->vpci.mem, map_range, &data) )
> +        {
> +        case -ERESTART:
> +            return true;
> +        case 0:

Blank line between non-fall-through case blocks please.

> +            if ( v->vpci.map )
> +            {
> +                spin_lock(&v->vpci.pdev->vpci->lock);
> +                modify_decoding(v->vpci.pdev, v->vpci.map, v->vpci.rom);
> +                spin_unlock(&v->vpci.pdev->vpci->lock);
> +            }
> +            /* fallthrough. */
> +        case -ENOMEM:
> +            /*
> +             * Other errors are ignored, hopping that at least some regions

hoping

I also don't really understand your intentions here: If other errors
are being ignored, wouldn't that lead to the rangeset being leaked?
Or is "other" here meant to include -ENOMEM, in which case you
really mean "default:" above?

> +static void modify_bars(const struct pci_dev *pdev, bool map, bool rom)
> +{
> +    struct vpci_header *header = &pdev->vpci->header;
> +    struct rangeset *mem = rangeset_new(NULL, NULL, 0);
> +    const struct pci_dev *tmp;
> +    unsigned int i;
> +    int rc;
> +
> +    if ( !map )
> +        modify_decoding(pdev, false, rom);
> +
> +    if ( !mem )
> +        return;
> +
> +    /*
> +     * Create a rangeset that represents the current device BARs memory 
> region
> +     * and compare it against all the currently active BAR memory regions. If
> +     * an overlap is found, subtract it from the region to be
> +     * mapped/unmapped.
> +     *
> +     * NB: the rangeset uses inclusive frame numbers.
> +     */
> +
> +    /*
> +     * First fill the rangeset with all the BARs of this device or with the 
> ROM
> +     * BAR only, depending on whether the guest is toggling the memory decode
> +     * bit of the command register, or the enable bit of the ROM BAR 
> register.
> +     */
> +    for ( i = 0; i < ARRAY_SIZE(header->bars); i++ )
> +    {
> +        const struct vpci_bar *bar = &header->bars[i];
> +
> +        if ( !MAPPABLE_BAR(bar) ||
> +             rom ? bar->type != VPCI_BAR_ROM
> +                 : (bar->type == VPCI_BAR_ROM && !bar->rom_enabled) )
> +            continue;

Logically as well as from the indentation used I think this is again
lacking parentheses around the conditional expression.

> --- a/xen/drivers/vpci/vpci.c
> +++ b/xen/drivers/vpci/vpci.c
> @@ -102,6 +102,21 @@ static void vpci_ignored_write(const struct pci_dev 
> *pdev, unsigned int reg,
>  {
>  }
>  
> +uint32_t vpci_hw_read16(const struct pci_dev *pdev, unsigned int reg,
> +                        void *data)
> +{
> +    return pci_conf_read16(pdev->seg, pdev->bus, PCI_SLOT(pdev->devfn),
> +                           PCI_FUNC(pdev->devfn), reg);
> +}
> +
> +uint32_t vpci_hw_read32(const struct pci_dev *pdev, unsigned int reg,
> +                        void *data)
> +{
> +    return pci_conf_read32(pdev->seg, pdev->bus, PCI_SLOT(pdev->devfn),
> +                           PCI_FUNC(pdev->devfn), reg);
> +}
> +
> +
>  int vpci_add_register(struct vpci *vpci, vpci_read_t *read_handler,

No double blank lines please.

> @@ -264,6 +265,11 @@ struct vcpu
>  
>      struct evtchn_fifo_vcpu *evtchn_fifo;
>  
> +#ifdef CONFIG_HAS_PCI
> +    /* vPCI per-vCPU area, used to store data for long running operations. */
> +    struct vpci_vcpu vpci;
> +#endif

Wasn't the #ifdef here supposed to be dropped with the dummy
structure you now have?

>  struct vpci {
>      /* List of vPCI handlers for a device. */
>      struct list_head handlers;
>      spinlock_t lock;
> +
> +#ifdef __XEN__
> +    /* Hide the rest of the vpci struct from the user-space test harness. */
> +    struct vpci_header {
> +        /* Information about the PCI BARs of this device. */
> +        struct vpci_bar {
> +            uint64_t addr;
> +            uint64_t size;
> +            enum {
> +                VPCI_BAR_EMPTY,
> +                VPCI_BAR_IO,
> +                VPCI_BAR_MEM32,
> +                VPCI_BAR_MEM64_LO,
> +                VPCI_BAR_MEM64_HI,
> +                VPCI_BAR_ROM,
> +            } type;
> +            bool prefetchable : 1;
> +            /* Store whether the BAR is mapped into guest p2m. */
> +            bool enabled      : 1;
> +            /*
> +             * Store whether the ROM enable bit is set (doesn't imply ROM BAR
> +             * is mapped into guest p2m). Only used for type VPCI_BAR_ROM.
> +             */
> +            bool rom_enabled  : 1;
> +        } bars[7]; /* At most 6 BARS + 1 expansion ROM BAR. */
> +        /* FIXME: currently there's no support for SR-IOV. */
> +    } header;
> +#endif
>  };
>  
> +#ifdef __XEN__
> +struct vpci_vcpu {
> +    struct rangeset *mem;
> +    const struct pci_dev *pdev;
> +    bool map : 1;
> +    bool rom : 1;
> +};
> +#endif

This structure could do with a comment briefly noting it purpose.
Also - if the #ifdef really needed here?

Jan

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/xen-devel

 


Rackspace

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