diff options
author | Matthew Wilcox <matthew.r.wilcox@intel.com> | 2011-01-24 07:52:07 -0500 |
---|---|---|
committer | Matthew Wilcox <matthew.r.wilcox@intel.com> | 2011-11-04 15:52:52 -0400 |
commit | 36c14ed9caa957c686d4a48fd598a5ec2aa0331b (patch) | |
tree | 73d550e0795add691a849c2dcc8977762fcbdf2c /drivers/block/nvme.c | |
parent | 53c9577e9ca68a633c6e9df2b54eaecacfa77f62 (diff) |
NVMe: Use PRP2 for the nvme_identify ioctl
DMA the result straight to userspace instead of bounce-buffering in the
kernel.
Signed-off-by: Matthew Wilcox <matthew.r.wilcox@intel.com>
Diffstat (limited to 'drivers/block/nvme.c')
-rw-r--r-- | drivers/block/nvme.c | 58 |
1 files changed, 41 insertions, 17 deletions
diff --git a/drivers/block/nvme.c b/drivers/block/nvme.c index 44a9d5edd8db..c0ef1dd1cc90 100644 --- a/drivers/block/nvme.c +++ b/drivers/block/nvme.c | |||
@@ -647,33 +647,57 @@ static int __devinit nvme_configure_admin_queue(struct nvme_dev *dev) | |||
647 | return result; | 647 | return result; |
648 | } | 648 | } |
649 | 649 | ||
650 | static int nvme_identify(struct nvme_ns *ns, void __user *addr, int cns) | 650 | static int nvme_identify(struct nvme_ns *ns, unsigned long addr, int cns) |
651 | { | 651 | { |
652 | struct nvme_dev *dev = ns->dev; | 652 | struct nvme_dev *dev = ns->dev; |
653 | int status; | 653 | int i, err, count, nents, offset; |
654 | struct nvme_command c; | 654 | struct nvme_command c; |
655 | void *page; | 655 | struct scatterlist sg[2]; |
656 | dma_addr_t dma_addr; | 656 | struct page *pages[2]; |
657 | 657 | ||
658 | page = dma_alloc_coherent(&dev->pci_dev->dev, 4096, &dma_addr, | 658 | if (addr & 3) |
659 | GFP_KERNEL); | 659 | return -EINVAL; |
660 | offset = offset_in_page(addr); | ||
661 | count = offset ? 2 : 1; | ||
662 | |||
663 | err = get_user_pages_fast(addr, count, 1, pages); | ||
664 | if (err < count) { | ||
665 | count = err; | ||
666 | err = -EFAULT; | ||
667 | goto put_pages; | ||
668 | } | ||
669 | sg_init_table(sg, count); | ||
670 | for (i = 0; i < count; i++) | ||
671 | sg_set_page(&sg[i], pages[i], PAGE_SIZE, 0); | ||
672 | nents = dma_map_sg(&dev->pci_dev->dev, sg, count, DMA_FROM_DEVICE); | ||
673 | if (!nents) | ||
674 | goto put_pages; | ||
660 | 675 | ||
661 | memset(&c, 0, sizeof(c)); | 676 | memset(&c, 0, sizeof(c)); |
662 | c.identify.opcode = nvme_admin_identify; | 677 | c.identify.opcode = nvme_admin_identify; |
663 | c.identify.nsid = cns ? 0 : cpu_to_le32(ns->ns_id); | 678 | c.identify.nsid = cns ? 0 : cpu_to_le32(ns->ns_id); |
664 | c.identify.prp1 = cpu_to_le64(dma_addr); | 679 | c.identify.prp1 = cpu_to_le64(sg_dma_address(&sg[0]) + offset); |
680 | if (count > 1) { | ||
681 | u64 dma_addr; | ||
682 | if (nents > 1) | ||
683 | dma_addr = sg_dma_address(&sg[1]); | ||
684 | else | ||
685 | dma_addr = sg_dma_address(&sg[0]) + PAGE_SIZE; | ||
686 | c.identify.prp2 = cpu_to_le64(dma_addr); | ||
687 | } | ||
665 | c.identify.cns = cpu_to_le32(cns); | 688 | c.identify.cns = cpu_to_le32(cns); |
666 | 689 | ||
667 | status = nvme_submit_admin_cmd(dev, &c, NULL); | 690 | err = nvme_submit_admin_cmd(dev, &c, NULL); |
668 | 691 | ||
669 | if (status) | 692 | if (err) |
670 | status = -EIO; | 693 | err = -EIO; |
671 | else if (copy_to_user(addr, page, 4096)) | ||
672 | status = -EFAULT; | ||
673 | 694 | ||
674 | dma_free_coherent(&dev->pci_dev->dev, 4096, page, dma_addr); | 695 | dma_unmap_sg(&dev->pci_dev->dev, sg, nents, DMA_FROM_DEVICE); |
696 | put_pages: | ||
697 | for (i = 0; i < count; i++) | ||
698 | put_page(pages[i]); | ||
675 | 699 | ||
676 | return status; | 700 | return err; |
677 | } | 701 | } |
678 | 702 | ||
679 | static int nvme_get_range_type(struct nvme_ns *ns, void __user *addr) | 703 | static int nvme_get_range_type(struct nvme_ns *ns, void __user *addr) |
@@ -713,9 +737,9 @@ static int nvme_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, | |||
713 | 737 | ||
714 | switch (cmd) { | 738 | switch (cmd) { |
715 | case NVME_IOCTL_IDENTIFY_NS: | 739 | case NVME_IOCTL_IDENTIFY_NS: |
716 | return nvme_identify(ns, (void __user *)arg, 0); | 740 | return nvme_identify(ns, arg, 0); |
717 | case NVME_IOCTL_IDENTIFY_CTRL: | 741 | case NVME_IOCTL_IDENTIFY_CTRL: |
718 | return nvme_identify(ns, (void __user *)arg, 1); | 742 | return nvme_identify(ns, arg, 1); |
719 | case NVME_IOCTL_GET_RANGE_TYPE: | 743 | case NVME_IOCTL_GET_RANGE_TYPE: |
720 | return nvme_get_range_type(ns, (void __user *)arg); | 744 | return nvme_get_range_type(ns, (void __user *)arg); |
721 | default: | 745 | default: |