Source
/* SPDX-License-Identifier: GPL-2.0 */
/**
* iommu_fill_pdir - Insert coalesced scatter/gather chunks into the I/O Pdir.
* @ioc: The I/O Controller.
* @startsg: The scatter/gather list of coalesced chunks.
* @nents: The number of entries in the scatter/gather list.
* @hint: The DMA Hint.
*
* This function inserts the coalesced scatter/gather list chunks into the
* I/O Controller's I/O Pdir.
*/
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,
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;
/* Horrible hack. For efficiency's sake, dma_sg starts one
* entry below the true start (it is immediately incremented
* in the loop) */
dma_sg--;
while (nents-- > 0) {
unsigned long vaddr;
long size;
DBG_RUN_SG(" %d : %08lx/%05x %p/%05x\n", nents,
(unsigned long)sg_dma_address(startsg), cnt,
sg_virt(startsg), startsg->length
);
/*
** Look for the start of a new DMA stream
*/
if (sg_dma_address(startsg) & PIDE_FLAG) {
u32 pide = sg_dma_address(startsg) & ~PIDE_FLAG;
BUG_ON(pdirp && (dma_len != sg_dma_len(dma_sg)));
dma_sg++;
dma_len = sg_dma_len(startsg);
sg_dma_len(startsg) = 0;
dma_offset = (unsigned long) pide & ~IOVP_MASK;
n_mappings++;
/* Pluto IOMMU IO Virt Address is not zero based */
sg_dma_address(dma_sg) = pide | ioc->ibase;
/* SBA, ccio, and dino are zero based.
* Trying to save a few CPU cycles for most users.
*/
sg_dma_address(dma_sg) = pide;