summaryrefslogtreecommitdiff
path: root/drivers/parisc/iommu-helpers.h
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/parisc/iommu-helpers.h')
-rw-r--r--drivers/parisc/iommu-helpers.h54
1 files changed, 29 insertions, 25 deletions
diff --git a/drivers/parisc/iommu-helpers.h b/drivers/parisc/iommu-helpers.h
index 8c33491b21fe..0691884f5095 100644
--- a/drivers/parisc/iommu-helpers.h
+++ b/drivers/parisc/iommu-helpers.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0 */
#include <linux/prefetch.h>
/**
@@ -13,13 +14,13 @@
static inline unsigned int
iommu_fill_pdir(struct ioc *ioc, struct scatterlist *startsg, int nents,
unsigned long hint,
- void (*iommu_io_pdir_entry)(u64 *, space_t, unsigned long,
+ void (*iommu_io_pdir_entry)(__le64 *, space_t, phys_addr_t,
unsigned long))
{
struct scatterlist *dma_sg = startsg; /* pointer to current DMA */
unsigned int n_mappings = 0;
unsigned long dma_offset = 0, dma_len = 0;
- u64 *pdirp = NULL;
+ __le64 *pdirp = NULL;
/* Horrible hack. For efficiency's sake, dma_sg starts one
* entry below the true start (it is immediately incremented
@@ -27,12 +28,12 @@ iommu_fill_pdir(struct ioc *ioc, struct scatterlist *startsg, int nents,
dma_sg--;
while (nents-- > 0) {
- unsigned long vaddr;
+ phys_addr_t paddr;
long size;
- DBG_RUN_SG(" %d : %08lx/%05x %08lx/%05x\n", nents,
- (unsigned long)sg_dma_address(startsg), cnt,
- sg_virt_addr(startsg), startsg->length
+ DBG_RUN_SG(" %d : %08lx %p/%05x\n", nents,
+ (unsigned long)sg_dma_address(startsg),
+ sg_virt(startsg), startsg->length
);
@@ -66,7 +67,7 @@ iommu_fill_pdir(struct ioc *ioc, struct scatterlist *startsg, int nents,
BUG_ON(pdirp == NULL);
- vaddr = sg_virt_addr(startsg);
+ paddr = sg_phys(startsg);
sg_dma_len(dma_sg) += startsg->length;
size = startsg->length + dma_offset;
dma_offset = 0;
@@ -75,8 +76,8 @@ iommu_fill_pdir(struct ioc *ioc, struct scatterlist *startsg, int nents,
#endif
do {
iommu_io_pdir_entry(pdirp, KERNEL_SPACE,
- vaddr, hint);
- vaddr += IOVP_SIZE;
+ paddr, hint);
+ paddr += IOVP_SIZE;
size -= IOVP_SIZE;
pdirp++;
} while(unlikely(size > 0));
@@ -104,7 +105,11 @@ iommu_coalesce_chunks(struct ioc *ioc, struct device *dev,
struct scatterlist *contig_sg; /* contig chunk head */
unsigned long dma_offset, dma_len; /* start/len of DMA stream */
unsigned int n_mappings = 0;
- unsigned int max_seg_size = dma_get_max_seg_size(dev);
+ unsigned int max_seg_size = min(dma_get_max_seg_size(dev),
+ (unsigned)DMA_CHUNK_SIZE);
+ unsigned int max_seg_boundary = dma_get_seg_boundary(dev) + 1;
+ if (max_seg_boundary) /* check if the addition above didn't overflow */
+ max_seg_size = min(max_seg_size, max_seg_boundary);
while (nents > 0) {
@@ -113,7 +118,7 @@ iommu_coalesce_chunks(struct ioc *ioc, struct device *dev,
*/
contig_sg = startsg;
dma_len = startsg->length;
- dma_offset = sg_virt_addr(startsg) & ~IOVP_MASK;
+ dma_offset = startsg->offset;
/* PARANOID: clear entries */
sg_dma_address(startsg) = 0;
@@ -124,14 +129,13 @@ iommu_coalesce_chunks(struct ioc *ioc, struct device *dev,
** it's always looking one "ahead".
*/
while(--nents > 0) {
- unsigned long prevstartsg_end, startsg_end;
+ unsigned long prev_end, sg_start;
- prevstartsg_end = sg_virt_addr(startsg) +
- startsg->length;
+ prev_end = (unsigned long)sg_virt(startsg) +
+ startsg->length;
startsg++;
- startsg_end = sg_virt_addr(startsg) +
- startsg->length;
+ sg_start = (unsigned long)sg_virt(startsg);
/* PARANOID: clear entries */
sg_dma_address(startsg) = 0;
@@ -139,21 +143,21 @@ iommu_coalesce_chunks(struct ioc *ioc, struct device *dev,
/*
** First make sure current dma stream won't
- ** exceed DMA_CHUNK_SIZE if we coalesce the
+ ** exceed max_seg_size if we coalesce the
** next entry.
*/
- if(unlikely(ALIGN(dma_len + dma_offset + startsg->length,
- IOVP_SIZE) > DMA_CHUNK_SIZE))
- break;
-
- if (startsg->length + dma_len > max_seg_size)
+ if (unlikely(ALIGN(dma_len + dma_offset + startsg->length, IOVP_SIZE) >
+ max_seg_size))
break;
/*
- ** Next see if we can append the next chunk (i.e.
- ** it must end on one page and begin on another
+ * Next see if we can append the next chunk (i.e.
+ * it must end on one page and begin on another, or
+ * it must start on the same address as the previous
+ * entry ended.
*/
- if (unlikely(((prevstartsg_end | sg_virt_addr(startsg)) & ~PAGE_MASK) != 0))
+ if (unlikely((prev_end != sg_start) ||
+ ((prev_end | sg_start) & ~PAGE_MASK)))
break;
dma_len += startsg->length;