This patch changes virtio_pci to use a shared memory area for virtio config info instead of using the PCI configuration space. This is closer semantically to what the virtio API exposes and is it a lot easier to implement on both ends. Signed-off-by: Anthony Liguori <aliguori@xxxxxxxxxx> diff --git a/drivers/virtio/virtio_pci.c b/drivers/virtio/virtio_pci.c index eb9a8e0..7e6e453 100644 --- a/drivers/virtio/virtio_pci.c +++ b/drivers/virtio/virtio_pci.c @@ -39,6 +39,12 @@ struct virtio_pci_device /* the IO mapping for the PCI config space */ void *ioaddr; + /* the shared device configuration */ + void *config; + + /* the size of the shared device configuration */ + u32 config_len; + /* a list of queues so we can dispatch IRQs */ spinlock_t lock; struct list_head virtqueues; @@ -111,47 +117,12 @@ static void vp_get(struct virtio_device *vdev, unsigned offset, void *buf, unsigned len) { struct virtio_pci_device *vp_dev = to_vp_device(vdev); - void *ioaddr = vp_dev->ioaddr + VIRTIO_PCI_CONFIG + offset; - - /* We translate appropriately sized get requests into more natural - * IO operations. These functions also take care of endianness - * conversion. */ - switch (len) { - case 1: { - u8 val; - val = ioread8(ioaddr); - memcpy(buf, &val, sizeof(val)); - break; - } - case 2: { - u16 val; - val = ioread16(ioaddr); - memcpy(buf, &val, sizeof(val)); - break; - } - case 4: { - u32 val; - val = ioread32(ioaddr); - memcpy(buf, &val, sizeof(val)); - break; - } - case 8: { - u64 val; - val = (u64)ioread32(ioaddr) << 32; - val |= ioread32(ioaddr + 4); - memcpy(buf, &val, sizeof(val)); - break; - } - default: { - uint8_t *ptr = buf; - int i; + BUG_ON(vp_dev->config == NULL); - for (i = 0; i < len; i++) - ptr[i] = ioread8(ioaddr + i); - break; - } - } + BUG_ON(vp_dev->config_len < (offset + len)); + + memcpy(buf, vp_dev->config + offset, len); } /* the config->set() implementation. it's symmetric to the config->get() @@ -160,43 +131,10 @@ static void vp_set(struct virtio_device *vdev, unsigned offset, const void *buf, unsigned len) { struct virtio_pci_device *vp_dev = to_vp_device(vdev); - void *ioaddr = vp_dev->ioaddr + VIRTIO_PCI_CONFIG + offset; - - switch (len) { - case 1: { - u8 val; - memcpy(&val, buf, sizeof(val)); - iowrite8(val, ioaddr); - break; - } - case 2: { - u16 val; - memcpy(&val, buf, sizeof(val)); - iowrite16(val, ioaddr); - break; - } - case 4: { - u32 val; - memcpy(&val, buf, sizeof(val)); - iowrite32(val, ioaddr); - break; - } - case 8: { - u64 val; - memcpy(&val, buf, sizeof(val)); - iowrite32(val >> 32, ioaddr); - iowrite32(val, ioaddr + 4); - break; - } - default: { - const uint8_t *ptr = buf; - int i; - for (i = 0; i < len; i++) - iowrite8(ptr[i], ioaddr + i); - break; - } - } + BUG_ON(vp_dev->config_len < (offset + len)); + + memcpy(vp_dev->config + offset, buf, len); } /* config->{get,set}_status() implementations */ @@ -281,7 +219,7 @@ static struct virtqueue *vp_find_vq(struct virtio_device *vdev, unsigned index, info->queue_index = index; info->num = num; - info->queue = kmalloc(vring_size(num), GFP_KERNEL | __GFP_ZERO); + info->queue = kzalloc(PAGE_ALIGN(vring_size(num)), GFP_KERNEL); if (info->queue == NULL) { err = -ENOMEM; goto out_info; @@ -390,11 +328,25 @@ static int __devinit virtio_pci_probe(struct pci_dev *pci_dev, vp_dev->vdev.id.vendor = pci_dev->subsystem_vendor; vp_dev->vdev.id.device = pci_dev->subsystem_device; + vp_dev->config_len = ioread32(vp_dev->ioaddr + VIRTIO_PCI_CONFIG_LEN); + if (vp_dev->config_len) { + /* round up to nearest page size to ensure proper alignment */ + vp_dev->config = kzalloc(PAGE_ALIGN(vp_dev->config_len), + GFP_KERNEL); + if (vp_dev->config == NULL) + goto out_set_drvdata; + + /* tell the host about our config space */ + iowrite32(virt_to_phys(vp_dev->config) >> PAGE_SHIFT, + vp_dev->ioaddr + VIRTIO_PCI_CONFIG_PFN); + } else + vp_dev->config = NULL; + /* register a handler for the queue with the PCI device's interrupt */ err = request_irq(vp_dev->pci_dev->irq, vp_interrupt, IRQF_SHARED, vp_dev->vdev.dev.bus_id, vp_dev); if (err) - goto out_set_drvdata; + goto out_alloc_config; /* finally register the virtio device */ err = register_virtio_device(&vp_dev->vdev); @@ -405,6 +357,8 @@ static int __devinit virtio_pci_probe(struct pci_dev *pci_dev, out_req_irq: free_irq(pci_dev->irq, vp_dev); +out_alloc_config: + kfree(vp_dev->config); out_set_drvdata: pci_set_drvdata(pci_dev, NULL); pci_iounmap(pci_dev, vp_dev->ioaddr); @@ -422,6 +376,7 @@ static void __devexit virtio_pci_remove(struct pci_dev *pci_dev) struct virtio_pci_device *vp_dev = pci_get_drvdata(pci_dev); free_irq(pci_dev->irq, vp_dev); + kfree(vp_dev->config); pci_set_drvdata(pci_dev, NULL); pci_iounmap(pci_dev, vp_dev->ioaddr); pci_release_regions(pci_dev); diff --git a/include/linux/virtio_pci.h b/include/linux/virtio_pci.h index 4b28409..79e6641 100644 --- a/include/linux/virtio_pci.h +++ b/include/linux/virtio_pci.h @@ -45,8 +45,12 @@ * a read-and-acknowledge. */ #define VIRTIO_PCI_ISR 19 -/* The remaining space is defined by each driver as the per-driver - * configuration space */ -#define VIRTIO_PCI_CONFIG 20 +/* A 32-bit r/o configuration size. This is the amount of memory required + * to be allocated for VIRTIO_PCI_CONFIG_PFN. */ +#define VIRTIO_PCI_CONFIG_LEN 20 + +/* A 32-bit r/w PFN for the shared configuration information. The PA written + * by the host must point to at least VIRTIO_PCI_CONFIG_LEN bytes */ +#define VIRTIO_PCI_CONFIG_PFN 24 #endif _______________________________________________ Virtualization mailing list Virtualization@xxxxxxxxxxxxxxxxxxxxxxxxxx https://lists.linux-foundation.org/mailman/listinfo/virtualization