Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 4 May 2019 09:47:01 +0000 (UTC)
From:      Hans Petter Selasky <hselasky@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r347089 - in head/sys: compat/linuxkpi/common/include/linux compat/linuxkpi/common/src sys
Message-ID:  <201905040947.x449l1j9087033@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
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,



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201905040947.x449l1j9087033>