aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael S. Tsirkin <mst@redhat.com>2015-01-14 11:50:55 -0500
committerRusty Russell <rusty@rustcorp.com.au>2015-01-21 00:58:55 -0500
commit3909213cfd9224cb1827d557fb6eb5ebdb8ddcbe (patch)
treef916c7f35438e2213640c3db90bac2caa4e31adc
parent89461c4a12faa643fd7564037440d626b777b033 (diff)
virtio_pci_modern: reduce number of mappings
We don't know the # of VQs that drivers are going to use so it's hard to predict how much memory we'll need to map. However, the relevant capability does give us an upper limit. If that's below a page, we can reduce the number of required mappings by mapping it all once ahead of the time. Signed-off-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
-rw-r--r--drivers/virtio/virtio_pci_common.h3
-rw-r--r--drivers/virtio/virtio_pci_modern.c57
2 files changed, 52 insertions, 8 deletions
diff --git a/drivers/virtio/virtio_pci_common.h b/drivers/virtio/virtio_pci_common.h
index 610c43f19230..d39180512761 100644
--- a/drivers/virtio/virtio_pci_common.h
+++ b/drivers/virtio/virtio_pci_common.h
@@ -62,8 +62,11 @@ struct virtio_pci_device {
62 struct virtio_pci_common_cfg __iomem *common; 62 struct virtio_pci_common_cfg __iomem *common;
63 /* Device-specific data (non-legacy mode) */ 63 /* Device-specific data (non-legacy mode) */
64 void __iomem *device; 64 void __iomem *device;
65 /* Base of vq notifications (non-legacy mode). */
66 void __iomem *notify_base;
65 67
66 /* So we can sanity-check accesses. */ 68 /* So we can sanity-check accesses. */
69 size_t notify_len;
67 size_t device_len; 70 size_t device_len;
68 71
69 /* Capability for when we need to map notifications per-vq. */ 72 /* Capability for when we need to map notifications per-vq. */
diff --git a/drivers/virtio/virtio_pci_modern.c b/drivers/virtio/virtio_pci_modern.c
index b2e707ad81cf..0e54cc88fdf5 100644
--- a/drivers/virtio/virtio_pci_modern.c
+++ b/drivers/virtio/virtio_pci_modern.c
@@ -330,10 +330,26 @@ static struct virtqueue *setup_vq(struct virtio_pci_device *vp_dev,
330 iowrite64_twopart(virt_to_phys(virtqueue_get_used(vq)), 330 iowrite64_twopart(virt_to_phys(virtqueue_get_used(vq)),
331 &cfg->queue_used_lo, &cfg->queue_used_hi); 331 &cfg->queue_used_lo, &cfg->queue_used_hi);
332 332
333 vq->priv = (void __force *)map_capability(vp_dev->pci_dev, 333 if (vp_dev->notify_base) {
334 vp_dev->notify_map_cap, 2, 2, 334 /* offset should not wrap */
335 off * vp_dev->notify_offset_multiplier, 2, 335 if ((u64)off * vp_dev->notify_offset_multiplier + 2
336 NULL); 336 > vp_dev->notify_len) {
337 dev_warn(&vp_dev->pci_dev->dev,
338 "bad notification offset %u (x %u) "
339 "for queue %u > %zd",
340 off, vp_dev->notify_offset_multiplier,
341 index, vp_dev->notify_len);
342 err = -EINVAL;
343 goto err_map_notify;
344 }
345 vq->priv = (void __force *)vp_dev->notify_base +
346 off * vp_dev->notify_offset_multiplier;
347 } else {
348 vq->priv = (void __force *)map_capability(vp_dev->pci_dev,
349 vp_dev->notify_map_cap, 2, 2,
350 off * vp_dev->notify_offset_multiplier, 2,
351 NULL);
352 }
337 353
338 if (!vq->priv) { 354 if (!vq->priv) {
339 err = -ENOMEM; 355 err = -ENOMEM;
@@ -352,7 +368,8 @@ static struct virtqueue *setup_vq(struct virtio_pci_device *vp_dev,
352 return vq; 368 return vq;
353 369
354err_assign_vector: 370err_assign_vector:
355 pci_iounmap(vp_dev->pci_dev, (void __iomem __force *)vq->priv); 371 if (!vp_dev->notify_base)
372 pci_iounmap(vp_dev->pci_dev, (void __iomem __force *)vq->priv);
356err_map_notify: 373err_map_notify:
357 vring_del_virtqueue(vq); 374 vring_del_virtqueue(vq);
358err_new_queue: 375err_new_queue:
@@ -397,7 +414,8 @@ static void del_vq(struct virtio_pci_vq_info *info)
397 ioread16(&vp_dev->common->queue_msix_vector); 414 ioread16(&vp_dev->common->queue_msix_vector);
398 } 415 }
399 416
400 pci_iounmap(vp_dev->pci_dev, (void __force __iomem *)vq->priv); 417 if (!vp_dev->notify_base)
418 pci_iounmap(vp_dev->pci_dev, (void __force __iomem *)vq->priv);
401 419
402 vring_del_virtqueue(vq); 420 vring_del_virtqueue(vq);
403 421
@@ -533,6 +551,7 @@ int virtio_pci_modern_probe(struct virtio_pci_device *vp_dev)
533 struct pci_dev *pci_dev = vp_dev->pci_dev; 551 struct pci_dev *pci_dev = vp_dev->pci_dev;
534 int err, common, isr, notify, device; 552 int err, common, isr, notify, device;
535 u32 notify_length; 553 u32 notify_length;
554 u32 notify_offset;
536 555
537 check_offsets(); 556 check_offsets();
538 557
@@ -599,13 +618,30 @@ int virtio_pci_modern_probe(struct virtio_pci_device *vp_dev)
599 notify + offsetof(struct virtio_pci_notify_cap, 618 notify + offsetof(struct virtio_pci_notify_cap,
600 notify_off_multiplier), 619 notify_off_multiplier),
601 &vp_dev->notify_offset_multiplier); 620 &vp_dev->notify_offset_multiplier);
602 /* Read notify length from config space. */ 621 /* Read notify length and offset from config space. */
603 pci_read_config_dword(pci_dev, 622 pci_read_config_dword(pci_dev,
604 notify + offsetof(struct virtio_pci_notify_cap, 623 notify + offsetof(struct virtio_pci_notify_cap,
605 cap.length), 624 cap.length),
606 &notify_length); 625 &notify_length);
607 626
608 vp_dev->notify_map_cap = notify; 627 pci_read_config_dword(pci_dev,
628 notify + offsetof(struct virtio_pci_notify_cap,
629 cap.length),
630 &notify_offset);
631
632 /* We don't know how many VQs we'll map, ahead of the time.
633 * If notify length is small, map it all now.
634 * Otherwise, map each VQ individually later.
635 */
636 if ((u64)notify_length + (notify_offset % PAGE_SIZE) <= PAGE_SIZE) {
637 vp_dev->notify_base = map_capability(pci_dev, notify, 2, 2,
638 0, notify_length,
639 &vp_dev->notify_len);
640 if (!vp_dev->notify_base)
641 goto err_map_notify;
642 } else {
643 vp_dev->notify_map_cap = notify;
644 }
609 645
610 /* Again, we don't know how much we should map, but PAGE_SIZE 646 /* Again, we don't know how much we should map, but PAGE_SIZE
611 * is more than enough for all existing devices. 647 * is more than enough for all existing devices.
@@ -627,6 +663,9 @@ int virtio_pci_modern_probe(struct virtio_pci_device *vp_dev)
627 return 0; 663 return 0;
628 664
629err_map_device: 665err_map_device:
666 if (vp_dev->notify_base)
667 pci_iounmap(pci_dev, vp_dev->notify_base);
668err_map_notify:
630 pci_iounmap(pci_dev, vp_dev->isr); 669 pci_iounmap(pci_dev, vp_dev->isr);
631err_map_isr: 670err_map_isr:
632 pci_iounmap(pci_dev, vp_dev->common); 671 pci_iounmap(pci_dev, vp_dev->common);
@@ -640,6 +679,8 @@ void virtio_pci_modern_remove(struct virtio_pci_device *vp_dev)
640 679
641 if (vp_dev->device) 680 if (vp_dev->device)
642 pci_iounmap(pci_dev, vp_dev->device); 681 pci_iounmap(pci_dev, vp_dev->device);
682 if (vp_dev->notify_base)
683 pci_iounmap(pci_dev, vp_dev->notify_base);
643 pci_iounmap(pci_dev, vp_dev->isr); 684 pci_iounmap(pci_dev, vp_dev->isr);
644 pci_iounmap(pci_dev, vp_dev->common); 685 pci_iounmap(pci_dev, vp_dev->common);
645} 686}