Author: hselasky
Date: Sat May  4 09:47:01 2019
New Revision: 347089
URL: https://svnweb.freebsd.org/changeset/base/347089

Log:
  Fix regression issue after r346645 in the LinuxKPI.
  
  The S/G list must be mapped AS-IS without any optimisations.
  This also implies that sg_dma_len() must be equal to sg->length.
  Many Linux drivers assume this and this fixes some DRM issues.
  
  Put the BUS DMA map pointer into the scatter-gather list to
  allow multiple mappings on the same physical memory address.
  
  The FreeBSD version has been bumped to force recompilation of
  external kernel modules.
  
  Sponsored by:         Mellanox Technologies

Modified:
  head/sys/compat/linuxkpi/common/include/linux/scatterlist.h
  head/sys/compat/linuxkpi/common/src/linux_pci.c
  head/sys/sys/param.h

Modified: head/sys/compat/linuxkpi/common/include/linux/scatterlist.h
==============================================================================
--- head/sys/compat/linuxkpi/common/include/linux/scatterlist.h Sat May  4 
09:30:03 2019        (r347088)
+++ head/sys/compat/linuxkpi/common/include/linux/scatterlist.h Sat May  4 
09:47:01 2019        (r347089)
@@ -36,6 +36,7 @@
 #include <linux/slab.h>
 #include <linux/mm.h>
 
+struct bus_dmamap;
 struct scatterlist {
        unsigned long page_link;
 #define        SG_PAGE_LINK_CHAIN      0x1UL
@@ -44,7 +45,7 @@ struct scatterlist {
        unsigned int offset;
        unsigned int length;
        dma_addr_t dma_address;
-       unsigned int dma_length;
+       struct bus_dmamap *dma_map;     /* FreeBSD specific */
 };
 
 CTASSERT((sizeof(struct scatterlist) & SG_PAGE_LINK_MASK) == 0);
@@ -79,7 +80,7 @@ struct sg_page_iter {
        ((struct scatterlist *) ((sg)->page_link & ~SG_PAGE_LINK_MASK))
 
 #define        sg_dma_address(sg)      (sg)->dma_address
-#define        sg_dma_len(sg)          (sg)->dma_length
+#define        sg_dma_len(sg)          (sg)->length
 
 #define        for_each_sg_page(sgl, iter, nents, pgoffset)                    
\
        for (_sg_iter_init(sgl, iter, nents, pgoffset);                 \

Modified: head/sys/compat/linuxkpi/common/src/linux_pci.c
==============================================================================
--- head/sys/compat/linuxkpi/common/src/linux_pci.c     Sat May  4 09:30:03 
2019        (r347088)
+++ head/sys/compat/linuxkpi/common/src/linux_pci.c     Sat May  4 09:47:01 
2019        (r347089)
@@ -562,70 +562,39 @@ linux_dma_map_sg_attrs(struct device *dev, struct scat
     enum dma_data_direction dir, struct dma_attrs *attrs)
 {
        struct linux_dma_priv *priv;
-       struct linux_dma_obj *obj;
-       struct scatterlist *dma_sg, *sg;
-       int dma_nents, error, nseg;
-       size_t seg_len;
-       vm_paddr_t seg_phys, prev_phys_end;
+       struct scatterlist *sg;
+       int i, nseg;
        bus_dma_segment_t seg;
 
        priv = dev->dma_priv;
 
-       obj = uma_zalloc(linux_dma_obj_zone, 0);
-
        DMA_PRIV_LOCK(priv);
-       if (bus_dmamap_create(priv->dmat, 0, &obj->dmamap) != 0) {
+
+       /* create common DMA map in the first S/G entry */
+       if (bus_dmamap_create(priv->dmat, 0, &sgl->dma_map) != 0) {
                DMA_PRIV_UNLOCK(priv);
-               uma_zfree(linux_dma_obj_zone, obj);
                return (0);
        }
 
-       sg = sgl;
-       dma_sg = sg;
-       dma_nents = 0;
-
-       while (nents > 0) {
-               seg_phys = sg_phys(sg);
-               seg_len = sg->length;
-               while (--nents > 0) {
-                       prev_phys_end = sg_phys(sg) + sg->length;
-                       sg = sg_next(sg);
-                       if (prev_phys_end != sg_phys(sg))
-                               break;
-                       seg_len += sg->length;
-               }
-
+       /* load all S/G list entries */
+       for_each_sg(sgl, sg, nents, i) {
                nseg = -1;
-               if (_bus_dmamap_load_phys(priv->dmat, obj->dmamap,
-                   seg_phys, seg_len, BUS_DMA_NOWAIT,
+               if (_bus_dmamap_load_phys(priv->dmat, sgl->dma_map,
+                   sg_phys(sg), sg->length, BUS_DMA_NOWAIT,
                    &seg, &nseg) != 0) {
-                       bus_dmamap_unload(priv->dmat, obj->dmamap);
-                       bus_dmamap_destroy(priv->dmat, obj->dmamap);
+                       bus_dmamap_unload(priv->dmat, sgl->dma_map);
+                       bus_dmamap_destroy(priv->dmat, sgl->dma_map);
                        DMA_PRIV_UNLOCK(priv);
-                       uma_zfree(linux_dma_obj_zone, obj);
                        return (0);
                }
-               KASSERT(++nseg == 1, ("More than one segment (nseg=%d)", nseg));
+               KASSERT(nseg == 0,
+                   ("More than one segment (nseg=%d)", nseg + 1));
 
-               sg_dma_address(dma_sg) = seg.ds_addr;
-               sg_dma_len(dma_sg) = seg.ds_len;
-
-               dma_sg = sg_next(dma_sg);
-               dma_nents++;
-        }
-
-       obj->dma_addr = sg_dma_address(sgl);
-
-       error = LINUX_DMA_PCTRIE_INSERT(&priv->ptree, obj);
-       if (error != 0) {
-               bus_dmamap_unload(priv->dmat, obj->dmamap);
-               bus_dmamap_destroy(priv->dmat, obj->dmamap);
-               DMA_PRIV_UNLOCK(priv);
-               uma_zfree(linux_dma_obj_zone, obj);
-               return (0);
+               sg_dma_address(sg) = seg.ds_addr;
        }
        DMA_PRIV_UNLOCK(priv);
-       return (dma_nents);
+
+       return (nents);
 }
 
 void
@@ -633,22 +602,13 @@ linux_dma_unmap_sg_attrs(struct device *dev, struct sc
     int nents, enum dma_data_direction dir, struct dma_attrs *attrs)
 {
        struct linux_dma_priv *priv;
-       struct linux_dma_obj *obj;
 
        priv = dev->dma_priv;
 
        DMA_PRIV_LOCK(priv);
-       obj = LINUX_DMA_PCTRIE_LOOKUP(&priv->ptree, sg_dma_address(sgl));
-       if (obj == NULL) {
-               DMA_PRIV_UNLOCK(priv);
-               return;
-       }
-       LINUX_DMA_PCTRIE_REMOVE(&priv->ptree, sg_dma_address(sgl));
-       bus_dmamap_unload(priv->dmat, obj->dmamap);
-       bus_dmamap_destroy(priv->dmat, obj->dmamap);
+       bus_dmamap_unload(priv->dmat, sgl->dma_map);
+       bus_dmamap_destroy(priv->dmat, sgl->dma_map);
        DMA_PRIV_UNLOCK(priv);
-
-       uma_zfree(linux_dma_obj_zone, obj);
 }
 
 struct dma_pool {

Modified: head/sys/sys/param.h
==============================================================================
--- head/sys/sys/param.h        Sat May  4 09:30:03 2019        (r347088)
+++ head/sys/sys/param.h        Sat May  4 09:47:01 2019        (r347089)
@@ -60,7 +60,7 @@
  *             in the range 5 to 9.
  */
 #undef __FreeBSD_version
-#define __FreeBSD_version 1300021      /* Master, propagated to newvers */
+#define __FreeBSD_version 1300022      /* Master, propagated to newvers */
 
 /*
  * __FreeBSD_kernel__ indicates that this system uses the kernel of FreeBSD,
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to