Loading drivers/dma/pl330.c +66 −76 Original line number Diff line number Diff line Loading @@ -443,7 +443,10 @@ struct dma_pl330_chan { /* For D-to-M and M-to-D channels */ int burst_sz; /* the peripheral fifo width */ int burst_len; /* the number of burst */ dma_addr_t fifo_addr; phys_addr_t fifo_addr; /* DMA-mapped view of the FIFO; may differ if an IOMMU is present */ dma_addr_t fifo_dma; enum dma_data_direction dir; /* for cyclic capability */ bool cyclic; Loading Loading @@ -538,11 +541,6 @@ struct _xfer_spec { struct dma_pl330_desc *desc; }; static inline bool _queue_empty(struct pl330_thread *thrd) { return thrd->req[0].desc == NULL && thrd->req[1].desc == NULL; } static inline bool _queue_full(struct pl330_thread *thrd) { return thrd->req[0].desc != NULL && thrd->req[1].desc != NULL; Loading @@ -564,23 +562,6 @@ static inline u32 get_revision(u32 periph_id) return (periph_id >> PERIPH_REV_SHIFT) & PERIPH_REV_MASK; } static inline u32 _emit_ADDH(unsigned dry_run, u8 buf[], enum pl330_dst da, u16 val) { if (dry_run) return SZ_DMAADDH; buf[0] = CMD_DMAADDH; buf[0] |= (da << 1); buf[1] = val; buf[2] = val >> 8; PL330_DBGCMD_DUMP(SZ_DMAADDH, "\tDMAADDH %s %u\n", da == 1 ? "DA" : "SA", val); return SZ_DMAADDH; } static inline u32 _emit_END(unsigned dry_run, u8 buf[]) { if (dry_run) Loading Loading @@ -738,18 +719,6 @@ static inline u32 _emit_MOV(unsigned dry_run, u8 buf[], return SZ_DMAMOV; } static inline u32 _emit_NOP(unsigned dry_run, u8 buf[]) { if (dry_run) return SZ_DMANOP; buf[0] = CMD_DMANOP; PL330_DBGCMD_DUMP(SZ_DMANOP, "\tDMANOP\n"); return SZ_DMANOP; } static inline u32 _emit_RMB(unsigned dry_run, u8 buf[]) { if (dry_run) Loading Loading @@ -817,39 +786,6 @@ static inline u32 _emit_STP(unsigned dry_run, u8 buf[], return SZ_DMASTP; } static inline u32 _emit_STZ(unsigned dry_run, u8 buf[]) { if (dry_run) return SZ_DMASTZ; buf[0] = CMD_DMASTZ; PL330_DBGCMD_DUMP(SZ_DMASTZ, "\tDMASTZ\n"); return SZ_DMASTZ; } static inline u32 _emit_WFE(unsigned dry_run, u8 buf[], u8 ev, unsigned invalidate) { if (dry_run) return SZ_DMAWFE; buf[0] = CMD_DMAWFE; ev &= 0x1f; ev <<= 3; buf[1] = ev; if (invalidate) buf[1] |= (1 << 1); PL330_DBGCMD_DUMP(SZ_DMAWFE, "\tDMAWFE %u%s\n", ev >> 3, invalidate ? ", I" : ""); return SZ_DMAWFE; } static inline u32 _emit_WFP(unsigned dry_run, u8 buf[], enum pl330_cond cond, u8 peri) { Loading Loading @@ -2120,11 +2056,60 @@ static int pl330_alloc_chan_resources(struct dma_chan *chan) return 1; } /* * We need the data direction between the DMAC (the dma-mapping "device") and * the FIFO (the dmaengine "dev"), from the FIFO's point of view. Confusing! */ static enum dma_data_direction pl330_dma_slave_map_dir(enum dma_transfer_direction dir) { switch (dir) { case DMA_MEM_TO_DEV: return DMA_FROM_DEVICE; case DMA_DEV_TO_MEM: return DMA_TO_DEVICE; case DMA_DEV_TO_DEV: return DMA_BIDIRECTIONAL; default: return DMA_NONE; } } static void pl330_unprep_slave_fifo(struct dma_pl330_chan *pch) { if (pch->dir != DMA_NONE) dma_unmap_resource(pch->chan.device->dev, pch->fifo_dma, 1 << pch->burst_sz, pch->dir, 0); pch->dir = DMA_NONE; } static bool pl330_prep_slave_fifo(struct dma_pl330_chan *pch, enum dma_transfer_direction dir) { struct device *dev = pch->chan.device->dev; enum dma_data_direction dma_dir = pl330_dma_slave_map_dir(dir); /* Already mapped for this config? */ if (pch->dir == dma_dir) return true; pl330_unprep_slave_fifo(pch); pch->fifo_dma = dma_map_resource(dev, pch->fifo_addr, 1 << pch->burst_sz, dma_dir, 0); if (dma_mapping_error(dev, pch->fifo_dma)) return false; pch->dir = dma_dir; return true; } static int pl330_config(struct dma_chan *chan, struct dma_slave_config *slave_config) { struct dma_pl330_chan *pch = to_pchan(chan); pl330_unprep_slave_fifo(pch); if (slave_config->direction == DMA_MEM_TO_DEV) { if (slave_config->dst_addr) pch->fifo_addr = slave_config->dst_addr; Loading Loading @@ -2235,6 +2220,7 @@ static void pl330_free_chan_resources(struct dma_chan *chan) spin_unlock_irqrestore(&pl330->lock, flags); pm_runtime_mark_last_busy(pch->dmac->ddma.dev); pm_runtime_put_autosuspend(pch->dmac->ddma.dev); pl330_unprep_slave_fifo(pch); } static int pl330_get_current_xferred_count(struct dma_pl330_chan *pch, Loading Loading @@ -2564,6 +2550,9 @@ static struct dma_async_tx_descriptor *pl330_prep_dma_cyclic( return NULL; } if (!pl330_prep_slave_fifo(pch, direction)) return NULL; for (i = 0; i < len / period_len; i++) { desc = pl330_get_desc(pch); if (!desc) { Loading Loading @@ -2593,12 +2582,12 @@ static struct dma_async_tx_descriptor *pl330_prep_dma_cyclic( desc->rqcfg.src_inc = 1; desc->rqcfg.dst_inc = 0; src = dma_addr; dst = pch->fifo_addr; dst = pch->fifo_dma; break; case DMA_DEV_TO_MEM: desc->rqcfg.src_inc = 0; desc->rqcfg.dst_inc = 1; src = pch->fifo_addr; src = pch->fifo_dma; dst = dma_addr; break; default: Loading Loading @@ -2711,12 +2700,12 @@ pl330_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, struct dma_pl330_chan *pch = to_pchan(chan); struct scatterlist *sg; int i; dma_addr_t addr; if (unlikely(!pch || !sgl || !sg_len)) return NULL; addr = pch->fifo_addr; if (!pl330_prep_slave_fifo(pch, direction)) return NULL; first = NULL; Loading @@ -2742,13 +2731,13 @@ pl330_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, if (direction == DMA_MEM_TO_DEV) { desc->rqcfg.src_inc = 1; desc->rqcfg.dst_inc = 0; fill_px(&desc->px, addr, sg_dma_address(sg), sg_dma_len(sg)); fill_px(&desc->px, pch->fifo_dma, sg_dma_address(sg), sg_dma_len(sg)); } else { desc->rqcfg.src_inc = 0; desc->rqcfg.dst_inc = 1; fill_px(&desc->px, sg_dma_address(sg), addr, sg_dma_len(sg)); fill_px(&desc->px, sg_dma_address(sg), pch->fifo_dma, sg_dma_len(sg)); } desc->rqcfg.brst_size = pch->burst_sz; Loading Loading @@ -2906,6 +2895,7 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id) pch->thread = NULL; pch->chan.device = pd; pch->dmac = pl330; pch->dir = DMA_NONE; /* Add the channel to the DMAC list */ list_add_tail(&pch->chan.device_node, &pd->channels); Loading Loading
drivers/dma/pl330.c +66 −76 Original line number Diff line number Diff line Loading @@ -443,7 +443,10 @@ struct dma_pl330_chan { /* For D-to-M and M-to-D channels */ int burst_sz; /* the peripheral fifo width */ int burst_len; /* the number of burst */ dma_addr_t fifo_addr; phys_addr_t fifo_addr; /* DMA-mapped view of the FIFO; may differ if an IOMMU is present */ dma_addr_t fifo_dma; enum dma_data_direction dir; /* for cyclic capability */ bool cyclic; Loading Loading @@ -538,11 +541,6 @@ struct _xfer_spec { struct dma_pl330_desc *desc; }; static inline bool _queue_empty(struct pl330_thread *thrd) { return thrd->req[0].desc == NULL && thrd->req[1].desc == NULL; } static inline bool _queue_full(struct pl330_thread *thrd) { return thrd->req[0].desc != NULL && thrd->req[1].desc != NULL; Loading @@ -564,23 +562,6 @@ static inline u32 get_revision(u32 periph_id) return (periph_id >> PERIPH_REV_SHIFT) & PERIPH_REV_MASK; } static inline u32 _emit_ADDH(unsigned dry_run, u8 buf[], enum pl330_dst da, u16 val) { if (dry_run) return SZ_DMAADDH; buf[0] = CMD_DMAADDH; buf[0] |= (da << 1); buf[1] = val; buf[2] = val >> 8; PL330_DBGCMD_DUMP(SZ_DMAADDH, "\tDMAADDH %s %u\n", da == 1 ? "DA" : "SA", val); return SZ_DMAADDH; } static inline u32 _emit_END(unsigned dry_run, u8 buf[]) { if (dry_run) Loading Loading @@ -738,18 +719,6 @@ static inline u32 _emit_MOV(unsigned dry_run, u8 buf[], return SZ_DMAMOV; } static inline u32 _emit_NOP(unsigned dry_run, u8 buf[]) { if (dry_run) return SZ_DMANOP; buf[0] = CMD_DMANOP; PL330_DBGCMD_DUMP(SZ_DMANOP, "\tDMANOP\n"); return SZ_DMANOP; } static inline u32 _emit_RMB(unsigned dry_run, u8 buf[]) { if (dry_run) Loading Loading @@ -817,39 +786,6 @@ static inline u32 _emit_STP(unsigned dry_run, u8 buf[], return SZ_DMASTP; } static inline u32 _emit_STZ(unsigned dry_run, u8 buf[]) { if (dry_run) return SZ_DMASTZ; buf[0] = CMD_DMASTZ; PL330_DBGCMD_DUMP(SZ_DMASTZ, "\tDMASTZ\n"); return SZ_DMASTZ; } static inline u32 _emit_WFE(unsigned dry_run, u8 buf[], u8 ev, unsigned invalidate) { if (dry_run) return SZ_DMAWFE; buf[0] = CMD_DMAWFE; ev &= 0x1f; ev <<= 3; buf[1] = ev; if (invalidate) buf[1] |= (1 << 1); PL330_DBGCMD_DUMP(SZ_DMAWFE, "\tDMAWFE %u%s\n", ev >> 3, invalidate ? ", I" : ""); return SZ_DMAWFE; } static inline u32 _emit_WFP(unsigned dry_run, u8 buf[], enum pl330_cond cond, u8 peri) { Loading Loading @@ -2120,11 +2056,60 @@ static int pl330_alloc_chan_resources(struct dma_chan *chan) return 1; } /* * We need the data direction between the DMAC (the dma-mapping "device") and * the FIFO (the dmaengine "dev"), from the FIFO's point of view. Confusing! */ static enum dma_data_direction pl330_dma_slave_map_dir(enum dma_transfer_direction dir) { switch (dir) { case DMA_MEM_TO_DEV: return DMA_FROM_DEVICE; case DMA_DEV_TO_MEM: return DMA_TO_DEVICE; case DMA_DEV_TO_DEV: return DMA_BIDIRECTIONAL; default: return DMA_NONE; } } static void pl330_unprep_slave_fifo(struct dma_pl330_chan *pch) { if (pch->dir != DMA_NONE) dma_unmap_resource(pch->chan.device->dev, pch->fifo_dma, 1 << pch->burst_sz, pch->dir, 0); pch->dir = DMA_NONE; } static bool pl330_prep_slave_fifo(struct dma_pl330_chan *pch, enum dma_transfer_direction dir) { struct device *dev = pch->chan.device->dev; enum dma_data_direction dma_dir = pl330_dma_slave_map_dir(dir); /* Already mapped for this config? */ if (pch->dir == dma_dir) return true; pl330_unprep_slave_fifo(pch); pch->fifo_dma = dma_map_resource(dev, pch->fifo_addr, 1 << pch->burst_sz, dma_dir, 0); if (dma_mapping_error(dev, pch->fifo_dma)) return false; pch->dir = dma_dir; return true; } static int pl330_config(struct dma_chan *chan, struct dma_slave_config *slave_config) { struct dma_pl330_chan *pch = to_pchan(chan); pl330_unprep_slave_fifo(pch); if (slave_config->direction == DMA_MEM_TO_DEV) { if (slave_config->dst_addr) pch->fifo_addr = slave_config->dst_addr; Loading Loading @@ -2235,6 +2220,7 @@ static void pl330_free_chan_resources(struct dma_chan *chan) spin_unlock_irqrestore(&pl330->lock, flags); pm_runtime_mark_last_busy(pch->dmac->ddma.dev); pm_runtime_put_autosuspend(pch->dmac->ddma.dev); pl330_unprep_slave_fifo(pch); } static int pl330_get_current_xferred_count(struct dma_pl330_chan *pch, Loading Loading @@ -2564,6 +2550,9 @@ static struct dma_async_tx_descriptor *pl330_prep_dma_cyclic( return NULL; } if (!pl330_prep_slave_fifo(pch, direction)) return NULL; for (i = 0; i < len / period_len; i++) { desc = pl330_get_desc(pch); if (!desc) { Loading Loading @@ -2593,12 +2582,12 @@ static struct dma_async_tx_descriptor *pl330_prep_dma_cyclic( desc->rqcfg.src_inc = 1; desc->rqcfg.dst_inc = 0; src = dma_addr; dst = pch->fifo_addr; dst = pch->fifo_dma; break; case DMA_DEV_TO_MEM: desc->rqcfg.src_inc = 0; desc->rqcfg.dst_inc = 1; src = pch->fifo_addr; src = pch->fifo_dma; dst = dma_addr; break; default: Loading Loading @@ -2711,12 +2700,12 @@ pl330_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, struct dma_pl330_chan *pch = to_pchan(chan); struct scatterlist *sg; int i; dma_addr_t addr; if (unlikely(!pch || !sgl || !sg_len)) return NULL; addr = pch->fifo_addr; if (!pl330_prep_slave_fifo(pch, direction)) return NULL; first = NULL; Loading @@ -2742,13 +2731,13 @@ pl330_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, if (direction == DMA_MEM_TO_DEV) { desc->rqcfg.src_inc = 1; desc->rqcfg.dst_inc = 0; fill_px(&desc->px, addr, sg_dma_address(sg), sg_dma_len(sg)); fill_px(&desc->px, pch->fifo_dma, sg_dma_address(sg), sg_dma_len(sg)); } else { desc->rqcfg.src_inc = 0; desc->rqcfg.dst_inc = 1; fill_px(&desc->px, sg_dma_address(sg), addr, sg_dma_len(sg)); fill_px(&desc->px, sg_dma_address(sg), pch->fifo_dma, sg_dma_len(sg)); } desc->rqcfg.brst_size = pch->burst_sz; Loading Loading @@ -2906,6 +2895,7 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id) pch->thread = NULL; pch->chan.device = pd; pch->dmac = pl330; pch->dir = DMA_NONE; /* Add the channel to the DMAC list */ list_add_tail(&pch->chan.device_node, &pd->channels); Loading