diff options
-rw-r--r-- | drivers/virtio/virtio_pci.c | 69 |
1 files changed, 46 insertions, 23 deletions
diff --git a/drivers/virtio/virtio_pci.c b/drivers/virtio/virtio_pci.c index 133978c6bd85..68023e509fcc 100644 --- a/drivers/virtio/virtio_pci.c +++ b/drivers/virtio/virtio_pci.c | |||
@@ -82,6 +82,12 @@ struct virtio_pci_device { | |||
82 | /* Whether we have vector per vq */ | 82 | /* Whether we have vector per vq */ |
83 | bool per_vq_vectors; | 83 | bool per_vq_vectors; |
84 | 84 | ||
85 | struct virtqueue *(*setup_vq)(struct virtio_pci_device *vp_dev, | ||
86 | struct virtio_pci_vq_info *info, | ||
87 | unsigned idx, | ||
88 | void (*callback)(struct virtqueue *vq), | ||
89 | const char *name, | ||
90 | u16 msix_vec); | ||
85 | void (*del_vq)(struct virtio_pci_vq_info *info); | 91 | void (*del_vq)(struct virtio_pci_vq_info *info); |
86 | }; | 92 | }; |
87 | 93 | ||
@@ -389,15 +395,15 @@ static int vp_request_intx(struct virtio_device *vdev) | |||
389 | return err; | 395 | return err; |
390 | } | 396 | } |
391 | 397 | ||
392 | static struct virtqueue *setup_vq(struct virtio_device *vdev, unsigned index, | 398 | static struct virtqueue *setup_vq(struct virtio_pci_device *vp_dev, |
399 | struct virtio_pci_vq_info *info, | ||
400 | unsigned index, | ||
393 | void (*callback)(struct virtqueue *vq), | 401 | void (*callback)(struct virtqueue *vq), |
394 | const char *name, | 402 | const char *name, |
395 | u16 msix_vec) | 403 | u16 msix_vec) |
396 | { | 404 | { |
397 | struct virtio_pci_device *vp_dev = to_vp_device(vdev); | ||
398 | struct virtio_pci_vq_info *info; | ||
399 | struct virtqueue *vq; | 405 | struct virtqueue *vq; |
400 | unsigned long flags, size; | 406 | unsigned long size; |
401 | u16 num; | 407 | u16 num; |
402 | int err; | 408 | int err; |
403 | 409 | ||
@@ -409,28 +415,21 @@ static struct virtqueue *setup_vq(struct virtio_device *vdev, unsigned index, | |||
409 | if (!num || ioread32(vp_dev->ioaddr + VIRTIO_PCI_QUEUE_PFN)) | 415 | if (!num || ioread32(vp_dev->ioaddr + VIRTIO_PCI_QUEUE_PFN)) |
410 | return ERR_PTR(-ENOENT); | 416 | return ERR_PTR(-ENOENT); |
411 | 417 | ||
412 | /* allocate and fill out our structure the represents an active | ||
413 | * queue */ | ||
414 | info = kmalloc(sizeof(struct virtio_pci_vq_info), GFP_KERNEL); | ||
415 | if (!info) | ||
416 | return ERR_PTR(-ENOMEM); | ||
417 | |||
418 | info->num = num; | 418 | info->num = num; |
419 | info->msix_vector = msix_vec; | 419 | info->msix_vector = msix_vec; |
420 | 420 | ||
421 | size = PAGE_ALIGN(vring_size(num, VIRTIO_PCI_VRING_ALIGN)); | 421 | size = PAGE_ALIGN(vring_size(num, VIRTIO_PCI_VRING_ALIGN)); |
422 | info->queue = alloc_pages_exact(size, GFP_KERNEL|__GFP_ZERO); | 422 | info->queue = alloc_pages_exact(size, GFP_KERNEL|__GFP_ZERO); |
423 | if (info->queue == NULL) { | 423 | if (info->queue == NULL) |
424 | err = -ENOMEM; | 424 | return ERR_PTR(-ENOMEM); |
425 | goto out_info; | ||
426 | } | ||
427 | 425 | ||
428 | /* activate the queue */ | 426 | /* activate the queue */ |
429 | iowrite32(virt_to_phys(info->queue) >> VIRTIO_PCI_QUEUE_ADDR_SHIFT, | 427 | iowrite32(virt_to_phys(info->queue) >> VIRTIO_PCI_QUEUE_ADDR_SHIFT, |
430 | vp_dev->ioaddr + VIRTIO_PCI_QUEUE_PFN); | 428 | vp_dev->ioaddr + VIRTIO_PCI_QUEUE_PFN); |
431 | 429 | ||
432 | /* create the vring */ | 430 | /* create the vring */ |
433 | vq = vring_new_virtqueue(index, info->num, VIRTIO_PCI_VRING_ALIGN, vdev, | 431 | vq = vring_new_virtqueue(index, info->num, |
432 | VIRTIO_PCI_VRING_ALIGN, &vp_dev->vdev, | ||
434 | true, info->queue, vp_notify, callback, name); | 433 | true, info->queue, vp_notify, callback, name); |
435 | if (!vq) { | 434 | if (!vq) { |
436 | err = -ENOMEM; | 435 | err = -ENOMEM; |
@@ -438,7 +437,6 @@ static struct virtqueue *setup_vq(struct virtio_device *vdev, unsigned index, | |||
438 | } | 437 | } |
439 | 438 | ||
440 | vq->priv = (void __force *)vp_dev->ioaddr + VIRTIO_PCI_QUEUE_NOTIFY; | 439 | vq->priv = (void __force *)vp_dev->ioaddr + VIRTIO_PCI_QUEUE_NOTIFY; |
441 | info->vq = vq; | ||
442 | 440 | ||
443 | if (msix_vec != VIRTIO_MSI_NO_VECTOR) { | 441 | if (msix_vec != VIRTIO_MSI_NO_VECTOR) { |
444 | iowrite16(msix_vec, vp_dev->ioaddr + VIRTIO_MSI_QUEUE_VECTOR); | 442 | iowrite16(msix_vec, vp_dev->ioaddr + VIRTIO_MSI_QUEUE_VECTOR); |
@@ -449,6 +447,35 @@ static struct virtqueue *setup_vq(struct virtio_device *vdev, unsigned index, | |||
449 | } | 447 | } |
450 | } | 448 | } |
451 | 449 | ||
450 | return vq; | ||
451 | |||
452 | out_assign: | ||
453 | vring_del_virtqueue(vq); | ||
454 | out_activate_queue: | ||
455 | iowrite32(0, vp_dev->ioaddr + VIRTIO_PCI_QUEUE_PFN); | ||
456 | free_pages_exact(info->queue, size); | ||
457 | return ERR_PTR(err); | ||
458 | } | ||
459 | |||
460 | static struct virtqueue *vp_setup_vq(struct virtio_device *vdev, unsigned index, | ||
461 | void (*callback)(struct virtqueue *vq), | ||
462 | const char *name, | ||
463 | u16 msix_vec) | ||
464 | { | ||
465 | struct virtio_pci_device *vp_dev = to_vp_device(vdev); | ||
466 | struct virtio_pci_vq_info *info = kmalloc(sizeof *info, GFP_KERNEL); | ||
467 | struct virtqueue *vq; | ||
468 | unsigned long flags; | ||
469 | |||
470 | /* fill out our structure that represents an active queue */ | ||
471 | if (!info) | ||
472 | return ERR_PTR(-ENOMEM); | ||
473 | |||
474 | vq = vp_dev->setup_vq(vp_dev, info, index, callback, name, msix_vec); | ||
475 | if (IS_ERR(vq)) | ||
476 | goto out_info; | ||
477 | |||
478 | info->vq = vq; | ||
452 | if (callback) { | 479 | if (callback) { |
453 | spin_lock_irqsave(&vp_dev->lock, flags); | 480 | spin_lock_irqsave(&vp_dev->lock, flags); |
454 | list_add(&info->node, &vp_dev->virtqueues); | 481 | list_add(&info->node, &vp_dev->virtqueues); |
@@ -460,14 +487,9 @@ static struct virtqueue *setup_vq(struct virtio_device *vdev, unsigned index, | |||
460 | vp_dev->vqs[index] = info; | 487 | vp_dev->vqs[index] = info; |
461 | return vq; | 488 | return vq; |
462 | 489 | ||
463 | out_assign: | ||
464 | vring_del_virtqueue(vq); | ||
465 | out_activate_queue: | ||
466 | iowrite32(0, vp_dev->ioaddr + VIRTIO_PCI_QUEUE_PFN); | ||
467 | free_pages_exact(info->queue, size); | ||
468 | out_info: | 490 | out_info: |
469 | kfree(info); | 491 | kfree(info); |
470 | return ERR_PTR(err); | 492 | return vq; |
471 | } | 493 | } |
472 | 494 | ||
473 | static void del_vq(struct virtio_pci_vq_info *info) | 495 | static void del_vq(struct virtio_pci_vq_info *info) |
@@ -578,7 +600,7 @@ static int vp_try_to_find_vqs(struct virtio_device *vdev, unsigned nvqs, | |||
578 | msix_vec = allocated_vectors++; | 600 | msix_vec = allocated_vectors++; |
579 | else | 601 | else |
580 | msix_vec = VP_MSIX_VQ_VECTOR; | 602 | msix_vec = VP_MSIX_VQ_VECTOR; |
581 | vqs[i] = setup_vq(vdev, i, callbacks[i], names[i], msix_vec); | 603 | vqs[i] = vp_setup_vq(vdev, i, callbacks[i], names[i], msix_vec); |
582 | if (IS_ERR(vqs[i])) { | 604 | if (IS_ERR(vqs[i])) { |
583 | err = PTR_ERR(vqs[i]); | 605 | err = PTR_ERR(vqs[i]); |
584 | goto error_find; | 606 | goto error_find; |
@@ -748,6 +770,7 @@ static int virtio_pci_probe(struct pci_dev *pci_dev, | |||
748 | vp_dev->vdev.id.vendor = pci_dev->subsystem_vendor; | 770 | vp_dev->vdev.id.vendor = pci_dev->subsystem_vendor; |
749 | vp_dev->vdev.id.device = pci_dev->subsystem_device; | 771 | vp_dev->vdev.id.device = pci_dev->subsystem_device; |
750 | 772 | ||
773 | vp_dev->setup_vq = setup_vq; | ||
751 | vp_dev->del_vq = del_vq; | 774 | vp_dev->del_vq = del_vq; |
752 | 775 | ||
753 | /* finally register the virtio device */ | 776 | /* finally register the virtio device */ |