svn commit: r347089 - in head/sys: compat/linuxkpi/common/include/linux compat/linuxkpi/common/src sys
Hans Petter Selasky
hselasky at FreeBSD.org
Sat May 4 09:47:03 UTC 2019
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,
More information about the svn-src-all
mailing list