Index: sys/compat/linuxkpi/common/include/linux/scatterlist.h =================================================================== --- sys/compat/linuxkpi/common/include/linux/scatterlist.h +++ sys/compat/linuxkpi/common/include/linux/scatterlist.h @@ -44,7 +44,6 @@ unsigned int offset; unsigned int length; dma_addr_t dma_address; - unsigned int dma_length; }; CTASSERT((sizeof(struct scatterlist) & SG_PAGE_LINK_MASK) == 0); @@ -79,7 +78,7 @@ ((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); \ Index: sys/compat/linuxkpi/common/src/linux_pci.c =================================================================== --- sys/compat/linuxkpi/common/src/linux_pci.c +++ sys/compat/linuxkpi/common/src/linux_pci.c @@ -492,6 +492,7 @@ { struct linux_dma_priv *priv; struct linux_dma_obj *obj; + struct linux_dma_obj *old; int error, nseg; bus_dma_segment_t seg; @@ -518,6 +519,16 @@ KASSERT(++nseg == 1, ("More than one segment (nseg=%d)", nseg)); obj->dma_addr = seg.ds_addr; + /* check if there is an existing mapping and remove it */ + old = LINUX_DMA_PCTRIE_LOOKUP(&priv->ptree, obj->dma_addr); + if (old != NULL) { + LINUX_DMA_PCTRIE_REMOVE(&priv->ptree, obj->dma_addr); + bus_dmamap_unload(priv->dmat, old->dmamap); + bus_dmamap_destroy(priv->dmat, old->dmamap); + uma_zfree(linux_dma_obj_zone, old); + } + + /* insert new mapping */ error = LINUX_DMA_PCTRIE_INSERT(&priv->ptree, obj); if (error != 0) { bus_dmamap_unload(priv->dmat, obj->dmamap); @@ -558,10 +569,9 @@ { 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 linux_dma_obj *old; + struct scatterlist *sg; + int error, i, nseg; bus_dma_segment_t seg; priv = dev->dma_priv; @@ -575,24 +585,10 @@ 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; - } - + 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, + 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); @@ -601,16 +597,21 @@ return (0); } KASSERT(++nseg == 1, ("More than one segment (nseg=%d)", nseg)); + sg_dma_address(sg) = seg.ds_addr; + } - sg_dma_address(dma_sg) = seg.ds_addr; - sg_dma_len(dma_sg) = seg.ds_len; + obj->dma_addr = sg_dma_address(sgl); - dma_sg = sg_next(dma_sg); - dma_nents++; - } + /* check if there is an existing mapping and remove it */ + old = LINUX_DMA_PCTRIE_LOOKUP(&priv->ptree, obj->dma_addr); + if (old != NULL) { + LINUX_DMA_PCTRIE_REMOVE(&priv->ptree, obj->dma_addr); + bus_dmamap_unload(priv->dmat, old->dmamap); + bus_dmamap_destroy(priv->dmat, old->dmamap); + uma_zfree(linux_dma_obj_zone, old); + } - obj->dma_addr = sg_dma_address(sgl); - + /* insert new mapping */ error = LINUX_DMA_PCTRIE_INSERT(&priv->ptree, obj); if (error != 0) { bus_dmamap_unload(priv->dmat, obj->dmamap); @@ -620,7 +621,7 @@ return (0); } DMA_PRIV_UNLOCK(priv); - return (dma_nents); + return (nents); } void