On Tue, May 12, 2015 at 01:39:00AM +1000, Alexey Kardashevskiy wrote:
>This is a pretty mechanical patch to make next patches simpler.
>
>New tce_iommu_unuse_page() helper does put_page() now but it might skip
>that after the memory registering patch applied.
>
>As we are here, this removes unnecessary checks for a value returned
>by pfn_to_page() as it cannot possibly return NULL.
>
>This moves tce_iommu_disable() later to let tce_iommu_clear() know if
>the container has been enabled because if it has not been, then
>put_page() must not be called on TCEs from the TCE table. This situation
>is not yet possible but it will after KVM acceleration patchset is
>applied.
>
>This changes code to work with physical addresses rather than linear
>mapping addresses for better code readability. Following patches will
>add an xchg() callback for an IOMMU table which will accept/return
>physical addresses (unlike current tce_build()) which will eliminate
>redundant conversions.
>
>Signed-off-by: Alexey Kardashevskiy <a...@ozlabs.ru>
>[aw: for the vfio related changes]
>Acked-by: Alex Williamson <alex.william...@redhat.com>
>Reviewed-by: David Gibson <da...@gibson.dropbear.id.au>

Reviewed-by: Gavin Shan <gws...@linux.vnet.ibm.com>

>---
>Changes:
>v9:
>* changed helpers to work with physical addresses rather than linear
>(for simplicity - later ::xchg() will receive physical and avoid
>additional convertions)
>
>v6:
>* tce_get_hva() returns hva via a pointer
>---
> drivers/vfio/vfio_iommu_spapr_tce.c | 61 +++++++++++++++++++++++++------------
> 1 file changed, 41 insertions(+), 20 deletions(-)
>
>diff --git a/drivers/vfio/vfio_iommu_spapr_tce.c 
>b/drivers/vfio/vfio_iommu_spapr_tce.c
>index e21479c..115d5e6 100644
>--- a/drivers/vfio/vfio_iommu_spapr_tce.c
>+++ b/drivers/vfio/vfio_iommu_spapr_tce.c
>@@ -191,69 +191,90 @@ static void tce_iommu_release(void *iommu_data)
>       struct tce_container *container = iommu_data;
>
>       WARN_ON(container->tbl && !container->tbl->it_group);
>-      tce_iommu_disable(container);
>
>       if (container->tbl && container->tbl->it_group)
>               tce_iommu_detach_group(iommu_data, container->tbl->it_group);
>
>+      tce_iommu_disable(container);
>       mutex_destroy(&container->lock);
>
>       kfree(container);
> }
>
>+static void tce_iommu_unuse_page(struct tce_container *container,
>+              unsigned long oldtce)
>+{
>+      struct page *page;
>+
>+      if (!(oldtce & (TCE_PCI_READ | TCE_PCI_WRITE)))
>+              return;
>+

It might be worthy to have a global helper function in iommu.h to check
if the given TCE entry is empty or not, for better readability. I would
think the helper function is used here and there :-)

Thanks,
Gavin

>+      page = pfn_to_page(oldtce >> PAGE_SHIFT);
>+
>+      if (oldtce & TCE_PCI_WRITE)
>+              SetPageDirty(page);
>+
>+      put_page(page);
>+}
>+
> static int tce_iommu_clear(struct tce_container *container,
>               struct iommu_table *tbl,
>               unsigned long entry, unsigned long pages)
> {
>       unsigned long oldtce;
>-      struct page *page;
>
>       for ( ; pages; --pages, ++entry) {
>               oldtce = iommu_clear_tce(tbl, entry);
>               if (!oldtce)
>                       continue;
>
>-              page = pfn_to_page(oldtce >> PAGE_SHIFT);
>-              WARN_ON(!page);
>-              if (page) {
>-                      if (oldtce & TCE_PCI_WRITE)
>-                              SetPageDirty(page);
>-                      put_page(page);
>-              }
>+              tce_iommu_unuse_page(container, oldtce);
>       }
>
>       return 0;
> }
>
>+static int tce_iommu_use_page(unsigned long tce, unsigned long *hpa)
>+{
>+      struct page *page = NULL;
>+      enum dma_data_direction direction = iommu_tce_direction(tce);
>+
>+      if (get_user_pages_fast(tce & PAGE_MASK, 1,
>+                      direction != DMA_TO_DEVICE, &page) != 1)
>+              return -EFAULT;
>+
>+      *hpa = __pa((unsigned long) page_address(page));
>+
>+      return 0;
>+}
>+
> static long tce_iommu_build(struct tce_container *container,
>               struct iommu_table *tbl,
>               unsigned long entry, unsigned long tce, unsigned long pages)
> {
>       long i, ret = 0;
>-      struct page *page = NULL;
>-      unsigned long hva;
>+      struct page *page;
>+      unsigned long hpa;
>       enum dma_data_direction direction = iommu_tce_direction(tce);
>
>       for (i = 0; i < pages; ++i) {
>               unsigned long offset = tce & IOMMU_PAGE_MASK(tbl) & ~PAGE_MASK;
>
>-              ret = get_user_pages_fast(tce & PAGE_MASK, 1,
>-                              direction != DMA_TO_DEVICE, &page);
>-              if (unlikely(ret != 1)) {
>-                      ret = -EFAULT;
>+              ret = tce_iommu_use_page(tce, &hpa);
>+              if (ret)
>                       break;
>-              }
>
>+              page = pfn_to_page(hpa >> PAGE_SHIFT);
>               if (!tce_page_is_contained(page, tbl->it_page_shift)) {
>                       ret = -EPERM;
>                       break;
>               }
>
>-              hva = (unsigned long) page_address(page) + offset;
>-
>-              ret = iommu_tce_build(tbl, entry + i, hva, direction);
>+              hpa |= offset;
>+              ret = iommu_tce_build(tbl, entry + i, (unsigned long) __va(hpa),
>+                              direction);
>               if (ret) {
>-                      put_page(page);
>+                      tce_iommu_unuse_page(container, hpa);
>                       pr_err("iommu_tce: %s failed ioba=%lx, tce=%lx, 
> ret=%ld\n",
>                                       __func__, entry << tbl->it_page_shift,
>                                       tce, ret);
>-- 
>2.4.0.rc3.8.gfb3e7d5
>

_______________________________________________
Linuxppc-dev mailing list
Linuxppc-dev@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/linuxppc-dev

Reply via email to