Merge tag 'dma-mapping-5.15' of git://git.infradead.org/users/hch/dma-mapping
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 2 Sep 2021 17:32:06 +0000 (10:32 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 2 Sep 2021 17:32:06 +0000 (10:32 -0700)
Pull dma-mapping updates from Christoph Hellwig:

 - fix debugfs initialization order (Anthony Iliopoulos)

 - use memory_intersects() directly (Kefeng Wang)

 - allow to return specific errors from ->map_sg (Logan Gunthorpe,
   Martin Oliveira)

 - turn the dma_map_sg return value into an unsigned int (me)

 - provide a common global coherent pool Ń–mplementation (me)

* tag 'dma-mapping-5.15' of git://git.infradead.org/users/hch/dma-mapping: (31 commits)
  hexagon: use the generic global coherent pool
  dma-mapping: make the global coherent pool conditional
  dma-mapping: add a dma_init_global_coherent helper
  dma-mapping: simplify dma_init_coherent_memory
  dma-mapping: allow using the global coherent pool for !ARM
  ARM/nommu: use the generic dma-direct code for non-coherent devices
  dma-direct: add support for dma_coherent_default_memory
  dma-mapping: return an unsigned int from dma_map_sg{,_attrs}
  dma-mapping: disallow .map_sg operations from returning zero on error
  dma-mapping: return error code from dma_dummy_map_sg()
  x86/amd_gart: don't set failed sg dma_address to DMA_MAPPING_ERROR
  x86/amd_gart: return error code from gart_map_sg()
  xen: swiotlb: return error code from xen_swiotlb_map_sg()
  parisc: return error code from .map_sg() ops
  sparc/iommu: don't set failed sg dma_address to DMA_MAPPING_ERROR
  sparc/iommu: return error codes from .map_sg() ops
  s390/pci: don't set failed sg dma_address to DMA_MAPPING_ERROR
  s390/pci: return error code from s390_dma_map_sg()
  powerpc/iommu: don't set failed sg dma_address to DMA_MAPPING_ERROR
  powerpc/iommu: return error code from .map_sg() ops
  ...

1  2 
arch/arm/Kconfig
arch/powerpc/platforms/ps3/system-bus.c
arch/powerpc/platforms/pseries/vio.c
arch/s390/pci/pci_dma.c
drivers/iommu/dma-iommu.c
drivers/iommu/iommu.c

diff --combined arch/arm/Kconfig
@@@ -18,8 -18,8 +18,8 @@@ config AR
        select ARCH_HAS_SET_MEMORY
        select ARCH_HAS_STRICT_KERNEL_RWX if MMU && !XIP_KERNEL
        select ARCH_HAS_STRICT_MODULE_RWX if MMU
-       select ARCH_HAS_SYNC_DMA_FOR_DEVICE if SWIOTLB
-       select ARCH_HAS_SYNC_DMA_FOR_CPU if SWIOTLB
+       select ARCH_HAS_SYNC_DMA_FOR_DEVICE if SWIOTLB || !MMU
+       select ARCH_HAS_SYNC_DMA_FOR_CPU if SWIOTLB || !MMU
        select ARCH_HAS_TEARDOWN_DMA_OPS if MMU
        select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
        select ARCH_HAVE_CUSTOM_GPIO_H
@@@ -44,6 -44,7 +44,7 @@@
        select CPU_PM if SUSPEND || CPU_IDLE
        select DCACHE_WORD_ACCESS if HAVE_EFFICIENT_UNALIGNED_ACCESS
        select DMA_DECLARE_COHERENT
+       select DMA_GLOBAL_POOL if !MMU
        select DMA_OPS
        select DMA_REMAP if MMU
        select EDAC_SUPPORT
@@@ -63,6 -64,8 +64,6 @@@
        select GENERIC_PCI_IOMAP
        select GENERIC_SCHED_CLOCK
        select GENERIC_SMP_IDLE_THREAD
 -      select GENERIC_STRNCPY_FROM_USER
 -      select GENERIC_STRNLEN_USER
        select HANDLE_DOMAIN_IRQ
        select HARDIRQS_SW_RESEND
        select HAVE_ARCH_AUDITSYSCALL if AEABI && !OABI_COMPAT
@@@ -381,7 -381,7 +381,7 @@@ static int ps3_system_bus_probe(struct 
        return result;
  }
  
 -static int ps3_system_bus_remove(struct device *_dev)
 +static void ps3_system_bus_remove(struct device *_dev)
  {
        struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev);
        struct ps3_system_bus_driver *drv;
                        __func__, __LINE__, drv->core.name);
  
        pr_debug(" <- %s:%d: %s\n", __func__, __LINE__, dev_name(&dev->core));
 -      return 0;
  }
  
  static void ps3_system_bus_shutdown(struct device *_dev)
@@@ -662,7 -663,7 +662,7 @@@ static int ps3_ioc0_map_sg(struct devic
                           unsigned long attrs)
  {
        BUG();
-       return 0;
+       return -EINVAL;
  }
  
  static void ps3_sb_unmap_sg(struct device *_dev, struct scatterlist *sg,
@@@ -560,7 -560,8 +560,8 @@@ static int vio_dma_iommu_map_sg(struct 
        for_each_sg(sglist, sgl, nelems, count)
                alloc_size += roundup(sgl->length, IOMMU_PAGE_SIZE(tbl));
  
-       if (vio_cmo_alloc(viodev, alloc_size))
+       ret = vio_cmo_alloc(viodev, alloc_size);
+       if (ret)
                goto out_fail;
        ret = ppc_iommu_map_sg(dev, tbl, sglist, nelems, dma_get_mask(dev),
                        direction, attrs);
@@@ -577,7 -578,7 +578,7 @@@ out_deallocate
        vio_cmo_dealloc(viodev, alloc_size);
  out_fail:
        atomic_inc(&viodev->cmo.allocs_failed);
-       return 0;
+       return ret;
  }
  
  static void vio_dma_iommu_unmap_sg(struct device *dev,
@@@ -1257,7 -1258,7 +1258,7 @@@ static int vio_bus_probe(struct device 
  }
  
  /* convert from struct device to struct vio_dev and pass to driver. */
 -static int vio_bus_remove(struct device *dev)
 +static void vio_bus_remove(struct device *dev)
  {
        struct vio_dev *viodev = to_vio_dev(dev);
        struct vio_driver *viodrv = to_vio_driver(dev->driver);
                vio_cmo_bus_remove(viodev);
  
        put_device(devptr);
 -      return 0;
  }
  
  static void vio_bus_shutdown(struct device *dev)
diff --combined arch/s390/pci/pci_dma.c
@@@ -487,18 -487,18 +487,18 @@@ static int s390_dma_map_sg(struct devic
        unsigned int max = dma_get_max_seg_size(dev);
        unsigned int size = s->offset + s->length;
        unsigned int offset = s->offset;
-       int count = 0, i;
+       int count = 0, i, ret;
  
        for (i = 1; i < nr_elements; i++) {
                s = sg_next(s);
  
-               s->dma_address = DMA_MAPPING_ERROR;
                s->dma_length = 0;
  
                if (s->offset || (size & ~PAGE_MASK) ||
                    size + s->length > max) {
-                       if (__s390_dma_map_sg(dev, start, size,
-                                             &dma->dma_address, dir))
+                       ret = __s390_dma_map_sg(dev, start, size,
+                                               &dma->dma_address, dir);
+                       if (ret)
                                goto unmap;
  
                        dma->dma_address += offset;
                }
                size += s->length;
        }
-       if (__s390_dma_map_sg(dev, start, size, &dma->dma_address, dir))
+       ret = __s390_dma_map_sg(dev, start, size, &dma->dma_address, dir);
+       if (ret)
                goto unmap;
  
        dma->dma_address += offset;
@@@ -523,7 -524,7 +524,7 @@@ unmap
                s390_dma_unmap_pages(dev, sg_dma_address(s), sg_dma_len(s),
                                     dir, attrs);
  
-       return 0;
+       return ret;
  }
  
  static void s390_dma_unmap_sg(struct device *dev, struct scatterlist *sg,
@@@ -590,11 -591,10 +591,11 @@@ int zpci_dma_init_device(struct zpci_de
                }
  
        }
 -      rc = zpci_register_ioat(zdev, 0, zdev->start_dma, zdev->end_dma,
 -                              (u64) zdev->dma_table);
 -      if (rc)
 +      if (zpci_register_ioat(zdev, 0, zdev->start_dma, zdev->end_dma,
 +                             (u64)zdev->dma_table)) {
 +              rc = -EIO;
                goto free_bitmap;
 +      }
  
        return 0;
  free_bitmap:
@@@ -609,25 -609,17 +610,25 @@@ out
        return rc;
  }
  
 -void zpci_dma_exit_device(struct zpci_dev *zdev)
 +int zpci_dma_exit_device(struct zpci_dev *zdev)
  {
 +      int cc = 0;
 +
        /*
         * At this point, if the device is part of an IOMMU domain, this would
         * be a strong hint towards a bug in the IOMMU API (common) code and/or
         * simultaneous access via IOMMU and DMA API. So let's issue a warning.
         */
        WARN_ON(zdev->s390_domain);
 -
 -      if (zpci_unregister_ioat(zdev, 0))
 -              return;
 +      if (zdev_enabled(zdev))
 +              cc = zpci_unregister_ioat(zdev, 0);
 +      /*
 +       * cc == 3 indicates the function is gone already. This can happen
 +       * if the function was deconfigured/disabled suddenly and we have not
 +       * received a new handle yet.
 +       */
 +      if (cc && cc != 3)
 +              return -EIO;
  
        dma_cleanup_tables(zdev->dma_table);
        zdev->dma_table = NULL;
        zdev->iommu_bitmap = NULL;
        vfree(zdev->lazy_bitmap);
        zdev->lazy_bitmap = NULL;
 -
        zdev->next_bit = 0;
 +      return 0;
  }
  
  static int __init dma_alloc_cpu_table_caches(void)
@@@ -768,7 -768,6 +768,7 @@@ static void iommu_dma_free_noncontiguou
        __iommu_dma_unmap(dev, sgt->sgl->dma_address, size);
        __iommu_dma_free_pages(sh->pages, PAGE_ALIGN(size) >> PAGE_SHIFT);
        sg_free_table(&sh->sgt);
 +      kfree(sh);
  }
  #endif /* CONFIG_DMA_REMAP */
  
@@@ -973,7 -972,7 +973,7 @@@ static int iommu_dma_map_sg_swiotlb(str
  
  out_unmap:
        iommu_dma_unmap_sg_swiotlb(dev, sg, i, dir, attrs | DMA_ATTR_SKIP_CPU_SYNC);
-       return 0;
+       return -EIO;
  }
  
  /*
@@@ -994,11 -993,13 +994,13 @@@ static int iommu_dma_map_sg(struct devi
        dma_addr_t iova;
        size_t iova_len = 0;
        unsigned long mask = dma_get_seg_boundary(dev);
+       ssize_t ret;
        int i;
  
-       if (static_branch_unlikely(&iommu_deferred_attach_enabled) &&
-           iommu_deferred_attach(dev, domain))
-               return 0;
+       if (static_branch_unlikely(&iommu_deferred_attach_enabled)) {
+               ret = iommu_deferred_attach(dev, domain);
+               goto out;
+       }
  
        if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC))
                iommu_dma_sync_sg_for_device(dev, sg, nents, dir);
        }
  
        iova = iommu_dma_alloc_iova(domain, iova_len, dma_get_mask(dev), dev);
-       if (!iova)
+       if (!iova) {
+               ret = -ENOMEM;
                goto out_restore_sg;
+       }
  
        /*
         * We'll leave any physical concatenation to the IOMMU driver's
         * implementation - it knows better than we do.
         */
-       if (iommu_map_sg_atomic(domain, iova, sg, nents, prot) < iova_len)
+       ret = iommu_map_sg_atomic(domain, iova, sg, nents, prot);
+       if (ret < iova_len)
                goto out_free_iova;
  
        return __finalise_sg(dev, sg, nents, iova);
@@@ -1062,7 -1066,10 +1067,10 @@@ out_free_iova
        iommu_dma_free_iova(cookie, iova, iova_len, NULL);
  out_restore_sg:
        __invalidate_sg(sg, nents);
-       return 0;
+ out:
+       if (ret != -ENOMEM)
+               return -EINVAL;
+       return ret;
  }
  
  static void iommu_dma_unmap_sg(struct device *dev, struct scatterlist *sg,
diff --combined drivers/iommu/iommu.c
@@@ -924,9 -924,6 +924,9 @@@ void iommu_group_remove_device(struct d
        struct iommu_group *group = dev->iommu_group;
        struct group_device *tmp_device, *device = NULL;
  
 +      if (!group)
 +              return;
 +
        dev_info(dev, "Removing from iommu group %d\n", group->id);
  
        /* Pre-notify listeners that a device is being removed. */
@@@ -2570,9 -2567,9 +2570,9 @@@ size_t iommu_unmap_fast(struct iommu_do
  }
  EXPORT_SYMBOL_GPL(iommu_unmap_fast);
  
- static size_t __iommu_map_sg(struct iommu_domain *domain, unsigned long iova,
-                            struct scatterlist *sg, unsigned int nents, int prot,
-                            gfp_t gfp)
+ static ssize_t __iommu_map_sg(struct iommu_domain *domain, unsigned long iova,
+               struct scatterlist *sg, unsigned int nents, int prot,
+               gfp_t gfp)
  {
        const struct iommu_ops *ops = domain->ops;
        size_t len = 0, mapped = 0;
@@@ -2613,19 -2610,18 +2613,18 @@@ out_err
        /* undo mappings already done */
        iommu_unmap(domain, iova, mapped);
  
-       return 0;
+       return ret;
  }
  
- size_t iommu_map_sg(struct iommu_domain *domain, unsigned long iova,
-                   struct scatterlist *sg, unsigned int nents, int prot)
+ ssize_t iommu_map_sg(struct iommu_domain *domain, unsigned long iova,
+                    struct scatterlist *sg, unsigned int nents, int prot)
  {
        might_sleep();
        return __iommu_map_sg(domain, iova, sg, nents, prot, GFP_KERNEL);
  }
  EXPORT_SYMBOL_GPL(iommu_map_sg);
  
- size_t iommu_map_sg_atomic(struct iommu_domain *domain, unsigned long iova,
+ ssize_t iommu_map_sg_atomic(struct iommu_domain *domain, unsigned long iova,
                    struct scatterlist *sg, unsigned int nents, int prot)
  {
        return __iommu_map_sg(domain, iova, sg, nents, prot, GFP_ATOMIC);