aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/block/nvme.c
diff options
context:
space:
mode:
authorMatthew Wilcox <matthew.r.wilcox@intel.com>2011-01-26 17:05:50 -0500
committerMatthew Wilcox <matthew.r.wilcox@intel.com>2011-11-04 15:52:52 -0400
commit7fc3cdabba75c2516b8b645eb0ca7907aea70415 (patch)
tree67cf9f491410121bbf8c2418dcb05148258ad5cb /drivers/block/nvme.c
parentbd38c5557cf482fc195e2264b32ea62eed60730a (diff)
NVMe: Create nvme_map_user_pages() and nvme_unmap_user_pages()
These are generalisations of the code that was in nvme_submit_user_admin_command(). Signed-off-by: Matthew Wilcox <matthew.r.wilcox@intel.com>
Diffstat (limited to 'drivers/block/nvme.c')
-rw-r--r--drivers/block/nvme.c68
1 files changed, 53 insertions, 15 deletions
diff --git a/drivers/block/nvme.c b/drivers/block/nvme.c
index b28d188d10f8..f44d6cd87ea2 100644
--- a/drivers/block/nvme.c
+++ b/drivers/block/nvme.c
@@ -677,17 +677,22 @@ static int __devinit nvme_configure_admin_queue(struct nvme_dev *dev)
677 return result; 677 return result;
678} 678}
679 679
680static int nvme_submit_user_admin_command(struct nvme_dev *dev, unsigned long addr, 680static int nvme_map_user_pages(struct nvme_dev *dev, int write,
681 unsigned length, struct nvme_command *cmd) 681 unsigned long addr, unsigned length,
682 struct scatterlist **sgp)
682{ 683{
683 int i, err, count, nents, offset; 684 int i, err, count, nents, offset;
684 struct scatterlist sg[2]; 685 struct scatterlist *sg;
685 struct page *pages[2]; 686 struct page **pages;
686 687
687 if (addr & 3) 688 if (addr & 3)
688 return -EINVAL; 689 return -EINVAL;
690 if (!length)
691 return -EINVAL;
692
689 offset = offset_in_page(addr); 693 offset = offset_in_page(addr);
690 count = ((offset + length) > PAGE_SIZE) ? 2 : 1; 694 count = DIV_ROUND_UP(offset + length, PAGE_SIZE);
695 pages = kcalloc(count, sizeof(*pages), GFP_KERNEL);
691 696
692 err = get_user_pages_fast(addr, count, 1, pages); 697 err = get_user_pages_fast(addr, count, 1, pages);
693 if (err < count) { 698 if (err < count) {
@@ -695,27 +700,60 @@ static int nvme_submit_user_admin_command(struct nvme_dev *dev, unsigned long ad
695 err = -EFAULT; 700 err = -EFAULT;
696 goto put_pages; 701 goto put_pages;
697 } 702 }
703
704 sg = kcalloc(count, sizeof(*sg), GFP_KERNEL);
698 sg_init_table(sg, count); 705 sg_init_table(sg, count);
699 sg_set_page(&sg[0], pages[0], PAGE_SIZE - offset, offset); 706 sg_set_page(&sg[0], pages[0], PAGE_SIZE - offset, offset);
700 if (count > 1) 707 length -= (PAGE_SIZE - offset);
701 sg_set_page(&sg[1], pages[1], offset, 0); 708 for (i = 1; i < count; i++) {
702 nents = dma_map_sg(&dev->pci_dev->dev, sg, count, DMA_FROM_DEVICE); 709 sg_set_page(&sg[i], pages[i], min_t(int, length, PAGE_SIZE), 0);
710 length -= PAGE_SIZE;
711 }
712
713 err = -ENOMEM;
714 nents = dma_map_sg(&dev->pci_dev->dev, sg, count,
715 write ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
703 if (!nents) 716 if (!nents)
704 goto put_pages; 717 goto put_pages;
705 718
706 nvme_setup_prps(&cmd->common, sg, length); 719 kfree(pages);
720 *sgp = sg;
721 return nents;
707 722
708 err = nvme_submit_admin_cmd(dev, cmd, NULL); 723 put_pages:
724 for (i = 0; i < count; i++)
725 put_page(pages[i]);
726 kfree(pages);
727 return err;
728}
709 729
710 if (err) 730static void nvme_unmap_user_pages(struct nvme_dev *dev, int write,
711 err = -EIO; 731 unsigned long addr, int length,
732 struct scatterlist *sg, int nents)
733{
734 int i, count;
712 735
736 count = DIV_ROUND_UP(offset_in_page(addr) + length, PAGE_SIZE);
713 dma_unmap_sg(&dev->pci_dev->dev, sg, nents, DMA_FROM_DEVICE); 737 dma_unmap_sg(&dev->pci_dev->dev, sg, nents, DMA_FROM_DEVICE);
714 put_pages: 738
715 for (i = 0; i < count; i++) 739 for (i = 0; i < count; i++)
716 put_page(pages[i]); 740 put_page(sg_page(&sg[i]));
741}
717 742
718 return err; 743static int nvme_submit_user_admin_command(struct nvme_dev *dev,
744 unsigned long addr, unsigned length,
745 struct nvme_command *cmd)
746{
747 int err, nents;
748 struct scatterlist *sg;
749
750 nents = nvme_map_user_pages(dev, 0, addr, length, &sg);
751 if (nents < 0)
752 return nents;
753 nvme_setup_prps(&cmd->common, sg, length);
754 err = nvme_submit_admin_cmd(dev, cmd, NULL);
755 nvme_unmap_user_pages(dev, 0, addr, length, sg, nents);
756 return err ? -EIO : 0;
719} 757}
720 758
721static int nvme_identify(struct nvme_ns *ns, unsigned long addr, int cns) 759static int nvme_identify(struct nvme_ns *ns, unsigned long addr, int cns)