lkml.org 
[lkml]   [2011]   [Nov]   [2]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
/
SubjectRe: [PATCH RFC] virtio-pci: flexible configuration layout
From
Date
Hi Michael,

On Thu, 2011-11-03 at 01:31 +0200, Michael S. Tsirkin wrote:
> Add a flexible mechanism to specify virtio configuration layout, using
> pci vendor-specific capability. A separate capability is used for each
> of common, device specific and data-path accesses.
>
> Warning: compiled only.
> This patch also needs to be split up, pci_iomap changes
> also need arch updates for non-x86.
>
> We also will need to update the spec.
>
> See the first chunk for layout documentation.
>
> Posting here for early feedback.
>
> In particular:
>
> Do we need to require offset to be aligned?
> Does iowrite16 work with unaligned accesses on all architectures?
> Does using ioread/write as we do add overhead as compared to
> plain PIO accesses?
>
> Jesse - are you OK with the pci_iomap_range API proposed here
> (see last chunks)?
> I noticed lots of architectures duplicate the implementation
> of pci_iomap - makes sense to clean that up?
>
> Thanks,
>
> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
>
> ---
>
> diff --git a/include/linux/virtio_pci.h b/include/linux/virtio_pci.h
> index ea66f3f..b8a9de2 100644
> --- a/include/linux/virtio_pci.h
> +++ b/include/linux/virtio_pci.h
> @@ -92,4 +92,38 @@
> /* The alignment to use between consumer and producer parts of vring.
> * x86 pagesize again. */
> #define VIRTIO_PCI_VRING_ALIGN 4096
> +
> +/*
> + * Layout for Virtio PCI vendor specific capability (little-endian):
> + * 5 bit virtio capability id.
> + * 3 bit BAR index register, specifying which BAR to use.
> + * 4 byte cfg offset within the BAR.

Why not make the 3 bits of the BIR as the lower 3 bits of the offset
like its done in the PCI spec?

This way you also get 'free' 32bit alignment and simpler masking.

> + * 4 byte cfg size.
> + */
> +
> +/* A single virtio device has multiple vendor specific capabilities, we use the
> + * 5 bit ID field to distinguish between these. */
> +#define VIRTIO_PCI_CAP_ID 3
> +#define VIRTIO_PCI_CAP_ID_MASK 0x1f
> +#define VIRTIO_PCI_CAP_ID_SHIFT 0
> +
> +/* IDs for different capabilities. If a specific configuration
> + * is missing, legacy PIO path is used. */
> +/* Common configuration */
> +#define VIRTIO_PCI_CAP_COMMON_CFG 0
> +/* Device specific confiuration */
> +#define VIRTIO_PCI_CAP_DEVICE_CFG 1
> +/* Notifications and ISR access */
> +#define VIRTIO_PCI_CAP_NOTIFY_CFG 2

I think that separating notification here is very kvm specific. Maybe it
could be replaced by allowing virtio to signal eventfds or something
similar?

> +
> +/* Index of the BAR including this configuration */
> +#define VIRTIO_PCI_CAP_CFG_BIR 3
> +#define VIRTIO_PCI_CAP_CFG_BIR_MASK (0x7)
> +#define VIRTIO_PCI_CAP_CFG_BIR_SHIFT 5
> +
> +/* Offset within the BAR */
> +#define VIRTIO_PCI_CAP_CFG_OFF 4
> +/* Size of the configuration space */
> +#define VIRTIO_PCI_CAP_CFG_SIZE 8
> +
> #endif
> diff --git a/drivers/virtio/virtio_pci.c b/drivers/virtio/virtio_pci.c
> index 4bcc8b8..d4ed130 100644
> --- a/drivers/virtio/virtio_pci.c
> +++ b/drivers/virtio/virtio_pci.c
> @@ -37,8 +37,12 @@ struct virtio_pci_device
> struct virtio_device vdev;
> struct pci_dev *pci_dev;
>
> - /* the IO mapping for the PCI config space */
> + /* the IO address for the common PCI config space */
> void __iomem *ioaddr;
> + /* the IO address for device specific config */
> + void __iomem *ioaddr_device;
> + /* the IO address to use for notifications operations */
> + void __iomem *ioaddr_notify;
>
> /* a list of queues so we can dispatch IRQs */
> spinlock_t lock;
> @@ -57,8 +61,142 @@ struct virtio_pci_device
> unsigned msix_used_vectors;
> /* Whether we have vector per vq */
> bool per_vq_vectors;
> +
> + /* Various IO mappings: used for resource tracking only. */
> +
> + /* Legacy BAR0: typically PIO. */
> + void __iomem *legacy_map;
> +
> + /* Mappings specified by device capabilities: typically in MMIO */
> + void __iomem *notify_map;
> + void __iomem *common_map;
> + void __iomem *device_map;
> };
>
> +/*
> + * With PIO, device-specific config moves as MSI-X is enabled/disabled.
> + * Use this accessor to keep pointer to that config in sync.
> + */
> +static void virtio_pci_set_msix_enabled(struct virtio_pci_device *vp_dev, int enabled)
> +{
> + vp_dev->msix_enabled = enabled;
> + if (vp_dev->device_map)
> + vp_dev->ioaddr_device = vp_dev->device_map;
> + else
> + vp_dev->ioaddr_device = vp_dev->legacy_map +
> + VIRTIO_PCI_CONFIG(vp_dev);
> +}
> +
> +static void __iomem *virtio_pci_map_cfg(struct virtio_pci_device *vp_dev, u8 cap_id)
> +{
> + u32 size;
> + u32 offset;
> + u8 bir;
> + u8 cap_len;
> + int pos;
> + struct pci_dev *dev = vp_dev->pci_dev;
> + void __iomem *p;
> +
> + for (pos = pci_find_capability(dev, PCI_CAP_ID_VNDR);
> + pos > 0;
> + pos = pci_find_next_capability(dev, pos, PCI_CAP_ID_VNDR)) {
> + u8 id;
> + pci_read_config_byte(dev, pos + PCI_VNDR_CAP_LEN, &cap_len);
> + if (cap_len < VIRTIO_PCI_CAP_ID + 1)
> + continue;
> + pci_read_config_byte(dev, pos + VIRTIO_PCI_CAP_ID, &id);
> + id >>= VIRTIO_PCI_CAP_ID_SHIFT;
> + id &= VIRTIO_PCI_CAP_ID_MASK;
> + if (id == cap_id)
> + break;
> + }
> +
> + if (pos <= 0)
> + return NULL;
> +
> + if (cap_len < VIRTIO_PCI_CAP_CFG_BIR + 1)
> + goto err;
> + pci_read_config_byte(dev, pos + VIRTIO_PCI_CAP_CFG_BIR, &bir);
> + if (cap_len < VIRTIO_PCI_CAP_CFG_OFF + 4)
> + goto err;
> + pci_read_config_dword(dev, pos + VIRTIO_PCI_CAP_CFG_OFF, &offset);
> + if (cap_len < VIRTIO_PCI_CAP_CFG_SIZE + 4)
> + goto err;
> + pci_read_config_dword(dev, pos + VIRTIO_PCI_CAP_CFG_SIZE, &size);
> + bir >>= VIRTIO_PCI_CAP_CFG_BIR_SHIFT;
> + bir &= VIRTIO_PCI_CAP_CFG_BIR_MASK;
> +
> + /* It's possible for a device to supply a huge config space,
> + * but we'll never need to map more than a page ATM. */
> + p = pci_iomap_range(dev, bir, offset, size, PAGE_SIZE);
> + if (!p)
> + dev_err(&vp_dev->vdev.dev, "Unable to map virtio pci memory");
> + return p;
> +err:
> + dev_err(&vp_dev->vdev.dev, "Unable to parse virtio pci capability");
> + return NULL;
> +}
> +
> +static void virtio_pci_iounmap(struct virtio_pci_device *vp_dev)
> +{
> + if (vp_dev->legacy_map)
> + pci_iounmap(vp_dev->pci_dev, vp_dev->legacy_map);
> + if (vp_dev->notify_map)
> + pci_iounmap(vp_dev->pci_dev, vp_dev->notify_map);
> + if (vp_dev->common_map)
> + pci_iounmap(vp_dev->pci_dev, vp_dev->common_map);
> + if (vp_dev->device_map)
> + pci_iounmap(vp_dev->pci_dev, vp_dev->device_map);
> +}
> +
> +static int virtio_pci_iomap(struct virtio_pci_device *vp_dev)
> +{
> + vp_dev->notify_map = virtio_pci_map_cfg(vp_dev,
> + VIRTIO_PCI_CAP_NOTIFY_CFG);
> + vp_dev->common_map = virtio_pci_map_cfg(vp_dev,
> + VIRTIO_PCI_CAP_COMMON_CFG);
> + vp_dev->device_map = virtio_pci_map_cfg(vp_dev,
> + VIRTIO_PCI_CAP_DEVICE_CFG);
> +
> + if (!vp_dev->notify_map || !vp_dev->common_map ||
> + !vp_dev->device_map) {
> + /*
> + * If not all capabilities present, map legacy PIO.
> + * Legacy access is at BAR 0. We never need to map
> + * more than 256 bytes there, since legacy config space
> + * used PIO which has this size limit.
> + * */

Whats the point of putting each of those new configs into a separate cap
structure if you must have all 3 of them for the new config layout to
work anyway?

Also, why not use this change to simplify the config space? The attempts
to squeeze it into the limited PIO space made it quite messy, and this
can be a good chance to fix some things like the MSI-X and offsets
issue.

--

Sasha.



\
 
 \ /
  Last update: 2011-11-03 01:23    [W:0.128 / U:11.748 seconds]
©2003-2018 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site