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>