Message ID | 1588122633-1552-1-git-send-email-alan.mikhak@sifive.com (mailing list archive) |
---|---|
State | Not Applicable, archived |
Headers | show |
Series | [next] dmaengine: dw-edma: support local dma device transfer semantics | expand |
On 28-04-20, 18:10, Alan Mikhak wrote: > From: Alan Mikhak <alan.mikhak@sifive.com> > > Modify dw_edma_device_transfer() to also support the semantics of dma > device transfer for additional use cases involving pcitest utility as a > local initiator. > > For its original use case, dw-edma supported the semantics of dma device > transfer from the perspective of a remote initiator who is located across > the PCIe bus from dma channel hardware. > > To a remote initiator, DMA_DEV_TO_MEM means using a remote dma WRITE > channel to transfer from remote memory to local memory. A WRITE channel > would be employed on the remote device in order to move the contents of > remote memory to the bus destined for local memory. > > To a remote initiator, DMA_MEM_TO_DEV means using a remote dma READ > channel to transfer from local memory to remote memory. A READ channel > would be employed on the remote device in order to move the contents of > local memory to the bus destined for remote memory. > > >From the perspective of a local dma initiator who is co-located on the > same side of the PCIe bus as the dma channel hardware, the semantics of > dma device transfer are flipped. > > To a local initiator, DMA_DEV_TO_MEM means using a local dma READ channel > to transfer from remote memory to local memory. A READ channel would be > employed on the local device in order to move the contents of remote > memory to the bus destined for local memory. > > To a local initiator, DMA_MEM_TO_DEV means using a local dma WRITE channel > to transfer from local memory to remote memory. A WRITE channel would be > employed on the local device in order to move the contents of local memory > to the bus destined for remote memory. > > To support local dma initiators, dw_edma_device_transfer() is modified to > now examine the direction field of struct dma_slave_config for the channel > which initiators can configure by calling dmaengine_slave_config(). > > If direction is configured as either DMA_DEV_TO_MEM or DMA_MEM_TO_DEV, > local initiator semantics are used. If direction is a value other than > DMA_DEV_TO_MEM nor DMA_MEM_TO_DEV, then remote initiator semantics are > used. This should maintain backward compatibility with the original use > case of dw-edma. > > The dw-edma-test utility is an example of a remote initiator. From reading > its patch, dw-edma-test does not specifically set the direction field of > struct dma_slave_config. Since dw_edma_device_transfer() also does not > check the direction field of struct dma_slave_config, it seems safe to use > this convention in dw-edma to support both local and remote initiator > semantics. Applied, thanks
diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c index 306ab50462be..ed430ad9b3dd 100644 --- a/drivers/dma/dw-edma/dw-edma-core.c +++ b/drivers/dma/dw-edma/dw-edma-core.c @@ -323,7 +323,7 @@ static struct dma_async_tx_descriptor * dw_edma_device_transfer(struct dw_edma_transfer *xfer) { struct dw_edma_chan *chan = dchan2dw_edma_chan(xfer->dchan); - enum dma_transfer_direction direction = xfer->direction; + enum dma_transfer_direction dir = xfer->direction; phys_addr_t src_addr, dst_addr; struct scatterlist *sg = NULL; struct dw_edma_chunk *chunk; @@ -332,10 +332,26 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer) u32 cnt; int i; - if ((direction == DMA_MEM_TO_DEV && chan->dir == EDMA_DIR_WRITE) || - (direction == DMA_DEV_TO_MEM && chan->dir == EDMA_DIR_READ)) + if (!chan->configured) return NULL; + switch (chan->config.direction) { + case DMA_DEV_TO_MEM: /* local dma */ + if (dir == DMA_DEV_TO_MEM && chan->dir == EDMA_DIR_READ) + break; + return NULL; + case DMA_MEM_TO_DEV: /* local dma */ + if (dir == DMA_MEM_TO_DEV && chan->dir == EDMA_DIR_WRITE) + break; + return NULL; + default: /* remote dma */ + if (dir == DMA_MEM_TO_DEV && chan->dir == EDMA_DIR_READ) + break; + if (dir == DMA_DEV_TO_MEM && chan->dir == EDMA_DIR_WRITE) + break; + return NULL; + } + if (xfer->cyclic) { if (!xfer->xfer.cyclic.len || !xfer->xfer.cyclic.cnt) return NULL; @@ -344,9 +360,6 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer) return NULL; } - if (!chan->configured) - return NULL; - desc = dw_edma_alloc_desc(chan); if (unlikely(!desc)) goto err_alloc; @@ -387,7 +400,7 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer) chunk->ll_region.sz += burst->sz; desc->alloc_sz += burst->sz; - if (direction == DMA_DEV_TO_MEM) { + if (chan->dir == EDMA_DIR_WRITE) { burst->sar = src_addr; if (xfer->cyclic) { burst->dar = xfer->xfer.cyclic.paddr;