Loading Documentation/dmaengine/provider.txt +55 −42 Original line number Diff line number Diff line Loading @@ -113,6 +113,31 @@ need to initialize a few fields in there: * channels: should be initialized as a list using the INIT_LIST_HEAD macro for example * src_addr_widths: - should contain a bitmask of the supported source transfer width * dst_addr_widths: - should contain a bitmask of the supported destination transfer width * directions: - should contain a bitmask of the supported slave directions (i.e. excluding mem2mem transfers) * residue_granularity: - Granularity of the transfer residue reported to dma_set_residue. - This can be either: + Descriptor -> Your device doesn't support any kind of residue reporting. The framework will only know that a particular transaction descriptor is done. + Segment -> Your device is able to report which chunks have been transferred + Burst -> Your device is able to report which burst have been transferred * dev: should hold the pointer to the struct device associated to your current driver instance. Loading Loading @@ -274,48 +299,36 @@ supported. account the current period. - This function can be called in an interrupt context. * device_control - Used by client drivers to control and configure the channel it has a handle on. - Called with a command and an argument + The command is one of the values listed by the enum dma_ctrl_cmd. The valid commands are: + DMA_PAUSE + Pauses a transfer on the channel + This command should operate synchronously on the channel, * device_config - Reconfigures the channel with the configuration given as argument - This command should NOT perform synchronously, or on any currently queued transfers, but only on subsequent ones - In this case, the function will receive a dma_slave_config structure pointer as an argument, that will detail which configuration to use. - Even though that structure contains a direction field, this field is deprecated in favor of the direction argument given to the prep_* functions - This call is mandatory for slave operations only. This should NOT be set or expected to be set for memcpy operations. If a driver support both, it should use this call for slave operations only and not for memcpy ones. * device_pause - Pauses a transfer on the channel - This command should operate synchronously on the channel, pausing right away the work of the given channel * device_resume - Resumes a transfer on the channel - This command should operate synchronously on the channel, pausing right away the work of the given channel + DMA_RESUME + Restarts a transfer on the channel + This command should operate synchronously on the channel, resuming right away the work of the given channel + DMA_TERMINATE_ALL + Aborts all the pending and ongoing transfers on the channel + This command should operate synchronously on the channel, * device_terminate_all - Aborts all the pending and ongoing transfers on the channel - This command should operate synchronously on the channel, terminating right away all the channels + DMA_SLAVE_CONFIG + Reconfigures the channel with passed configuration + This command should NOT perform synchronously, or on any currently queued transfers, but only on subsequent ones + In this case, the function will receive a dma_slave_config structure pointer as an argument, that will detail which configuration to use. + Even though that structure contains a direction field, this field is deprecated in favor of the direction argument given to the prep_* functions + FSLDMA_EXTERNAL_START + TODO: Why does that even exist? + The argument is an opaque unsigned long. This actually is a pointer to a struct dma_slave_config that should be used only in the DMA_SLAVE_CONFIG. * device_slave_caps - Called through the framework by client drivers in order to have an idea of what are the properties of the channel allocated to them. - Such properties are the buswidth, available directions, etc. - Required for every generic layer doing DMA transfers, such as ASoC. Misc notes (stuff that should be documented, but don't really know where to put them) Loading drivers/crypto/ux500/cryp/cryp_core.c +2 −2 Original line number Diff line number Diff line Loading @@ -606,12 +606,12 @@ static void cryp_dma_done(struct cryp_ctx *ctx) dev_dbg(ctx->device->dev, "[%s]: ", __func__); chan = ctx->device->dma.chan_mem2cryp; dmaengine_device_control(chan, DMA_TERMINATE_ALL, 0); dmaengine_terminate_all(chan); dma_unmap_sg(chan->device->dev, ctx->device->dma.sg_src, ctx->device->dma.sg_src_len, DMA_TO_DEVICE); chan = ctx->device->dma.chan_cryp2mem; dmaengine_device_control(chan, DMA_TERMINATE_ALL, 0); dmaengine_terminate_all(chan); dma_unmap_sg(chan->device->dev, ctx->device->dma.sg_dst, ctx->device->dma.sg_dst_len, DMA_FROM_DEVICE); } Loading drivers/crypto/ux500/hash/hash_core.c +1 −1 Original line number Diff line number Diff line Loading @@ -202,7 +202,7 @@ static void hash_dma_done(struct hash_ctx *ctx) struct dma_chan *chan; chan = ctx->device->dma.chan_mem2hash; dmaengine_device_control(chan, DMA_TERMINATE_ALL, 0); dmaengine_terminate_all(chan); dma_unmap_sg(chan->device->dev, ctx->device->dma.sg, ctx->device->dma.sg_len, DMA_TO_DEVICE); } Loading drivers/dma/amba-pl08x.c +90 −66 Original line number Diff line number Diff line Loading @@ -1386,32 +1386,6 @@ static u32 pl08x_get_cctl(struct pl08x_dma_chan *plchan, return pl08x_cctl(cctl); } static int dma_set_runtime_config(struct dma_chan *chan, struct dma_slave_config *config) { struct pl08x_dma_chan *plchan = to_pl08x_chan(chan); struct pl08x_driver_data *pl08x = plchan->host; if (!plchan->slave) return -EINVAL; /* Reject definitely invalid configurations */ if (config->src_addr_width == DMA_SLAVE_BUSWIDTH_8_BYTES || config->dst_addr_width == DMA_SLAVE_BUSWIDTH_8_BYTES) return -EINVAL; if (config->device_fc && pl08x->vd->pl080s) { dev_err(&pl08x->adev->dev, "%s: PL080S does not support peripheral flow control\n", __func__); return -EINVAL; } plchan->cfg = *config; return 0; } /* * Slave transactions callback to the slave device to allow * synchronization of slave DMA signals with the DMAC enable Loading Loading @@ -1693,32 +1667,44 @@ static struct dma_async_tx_descriptor *pl08x_prep_dma_cyclic( return vchan_tx_prep(&plchan->vc, &txd->vd, flags); } static int pl08x_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, unsigned long arg) static int pl08x_config(struct dma_chan *chan, struct dma_slave_config *config) { struct pl08x_dma_chan *plchan = to_pl08x_chan(chan); struct pl08x_driver_data *pl08x = plchan->host; unsigned long flags; int ret = 0; /* Controls applicable to inactive channels */ if (cmd == DMA_SLAVE_CONFIG) { return dma_set_runtime_config(chan, (struct dma_slave_config *)arg); if (!plchan->slave) return -EINVAL; /* Reject definitely invalid configurations */ if (config->src_addr_width == DMA_SLAVE_BUSWIDTH_8_BYTES || config->dst_addr_width == DMA_SLAVE_BUSWIDTH_8_BYTES) return -EINVAL; if (config->device_fc && pl08x->vd->pl080s) { dev_err(&pl08x->adev->dev, "%s: PL080S does not support peripheral flow control\n", __func__); return -EINVAL; } plchan->cfg = *config; return 0; } /* * Anything succeeds on channels with no physical allocation and * no queued transfers. */ static int pl08x_terminate_all(struct dma_chan *chan) { struct pl08x_dma_chan *plchan = to_pl08x_chan(chan); struct pl08x_driver_data *pl08x = plchan->host; unsigned long flags; spin_lock_irqsave(&plchan->vc.lock, flags); if (!plchan->phychan && !plchan->at) { spin_unlock_irqrestore(&plchan->vc.lock, flags); return 0; } switch (cmd) { case DMA_TERMINATE_ALL: plchan->state = PL08X_CHAN_IDLE; if (plchan->phychan) { Loading @@ -1735,24 +1721,56 @@ static int pl08x_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, } /* Dequeue jobs not yet fired as well */ pl08x_free_txd_list(pl08x, plchan); break; case DMA_PAUSE: spin_unlock_irqrestore(&plchan->vc.lock, flags); return 0; } static int pl08x_pause(struct dma_chan *chan) { struct pl08x_dma_chan *plchan = to_pl08x_chan(chan); unsigned long flags; /* * Anything succeeds on channels with no physical allocation and * no queued transfers. */ spin_lock_irqsave(&plchan->vc.lock, flags); if (!plchan->phychan && !plchan->at) { spin_unlock_irqrestore(&plchan->vc.lock, flags); return 0; } pl08x_pause_phy_chan(plchan->phychan); plchan->state = PL08X_CHAN_PAUSED; break; case DMA_RESUME: spin_unlock_irqrestore(&plchan->vc.lock, flags); return 0; } static int pl08x_resume(struct dma_chan *chan) { struct pl08x_dma_chan *plchan = to_pl08x_chan(chan); unsigned long flags; /* * Anything succeeds on channels with no physical allocation and * no queued transfers. */ spin_lock_irqsave(&plchan->vc.lock, flags); if (!plchan->phychan && !plchan->at) { spin_unlock_irqrestore(&plchan->vc.lock, flags); return 0; } pl08x_resume_phy_chan(plchan->phychan); plchan->state = PL08X_CHAN_RUNNING; break; default: /* Unknown command */ ret = -ENXIO; break; } spin_unlock_irqrestore(&plchan->vc.lock, flags); return ret; return 0; } bool pl08x_filter_id(struct dma_chan *chan, void *chan_id) Loading Loading @@ -2048,7 +2066,10 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id) pl08x->memcpy.device_prep_dma_interrupt = pl08x_prep_dma_interrupt; pl08x->memcpy.device_tx_status = pl08x_dma_tx_status; pl08x->memcpy.device_issue_pending = pl08x_issue_pending; pl08x->memcpy.device_control = pl08x_control; pl08x->memcpy.device_config = pl08x_config; pl08x->memcpy.device_pause = pl08x_pause; pl08x->memcpy.device_resume = pl08x_resume; pl08x->memcpy.device_terminate_all = pl08x_terminate_all; /* Initialize slave engine */ dma_cap_set(DMA_SLAVE, pl08x->slave.cap_mask); Loading @@ -2061,7 +2082,10 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id) pl08x->slave.device_issue_pending = pl08x_issue_pending; pl08x->slave.device_prep_slave_sg = pl08x_prep_slave_sg; pl08x->slave.device_prep_dma_cyclic = pl08x_prep_dma_cyclic; pl08x->slave.device_control = pl08x_control; pl08x->slave.device_config = pl08x_config; pl08x->slave.device_pause = pl08x_pause; pl08x->slave.device_resume = pl08x_resume; pl08x->slave.device_terminate_all = pl08x_terminate_all; /* Get the platform data */ pl08x->pd = dev_get_platdata(&adev->dev); Loading drivers/dma/at_hdmac.c +82 −48 Original line number Diff line number Diff line Loading @@ -42,6 +42,11 @@ #define ATC_DEFAULT_CFG (ATC_FIFOCFG_HALFFIFO) #define ATC_DEFAULT_CTRLB (ATC_SIF(AT_DMA_MEM_IF) \ |ATC_DIF(AT_DMA_MEM_IF)) #define ATC_DMA_BUSWIDTHS\ (BIT(DMA_SLAVE_BUSWIDTH_UNDEFINED) |\ BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |\ BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |\ BIT(DMA_SLAVE_BUSWIDTH_4_BYTES)) /* * Initial number of descriptors to allocate for each channel. This could Loading Loading @@ -972,11 +977,13 @@ atc_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len, return NULL; } static int set_runtime_config(struct dma_chan *chan, static int atc_config(struct dma_chan *chan, struct dma_slave_config *sconfig) { struct at_dma_chan *atchan = to_at_dma_chan(chan); dev_vdbg(chan2dev(chan), "%s\n", __func__); /* Check if it is chan is configured for slave transfers */ if (!chan->private) return -EINVAL; Loading @@ -989,9 +996,7 @@ static int set_runtime_config(struct dma_chan *chan, return 0; } static int atc_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, unsigned long arg) static int atc_pause(struct dma_chan *chan) { struct at_dma_chan *atchan = to_at_dma_chan(chan); struct at_dma *atdma = to_at_dma(chan->device); Loading @@ -1000,16 +1005,29 @@ static int atc_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, LIST_HEAD(list); dev_vdbg(chan2dev(chan), "atc_control (%d)\n", cmd); dev_vdbg(chan2dev(chan), "%s\n", __func__); if (cmd == DMA_PAUSE) { spin_lock_irqsave(&atchan->lock, flags); dma_writel(atdma, CHER, AT_DMA_SUSP(chan_id)); set_bit(ATC_IS_PAUSED, &atchan->status); spin_unlock_irqrestore(&atchan->lock, flags); } else if (cmd == DMA_RESUME) { return 0; } static int atc_resume(struct dma_chan *chan) { struct at_dma_chan *atchan = to_at_dma_chan(chan); struct at_dma *atdma = to_at_dma(chan->device); int chan_id = atchan->chan_common.chan_id; unsigned long flags; LIST_HEAD(list); dev_vdbg(chan2dev(chan), "%s\n", __func__); if (!atc_chan_is_paused(atchan)) return 0; Loading @@ -1019,8 +1037,22 @@ static int atc_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, clear_bit(ATC_IS_PAUSED, &atchan->status); spin_unlock_irqrestore(&atchan->lock, flags); } else if (cmd == DMA_TERMINATE_ALL) { return 0; } static int atc_terminate_all(struct dma_chan *chan) { struct at_dma_chan *atchan = to_at_dma_chan(chan); struct at_dma *atdma = to_at_dma(chan->device); int chan_id = atchan->chan_common.chan_id; struct at_desc *desc, *_desc; unsigned long flags; LIST_HEAD(list); dev_vdbg(chan2dev(chan), "%s\n", __func__); /* * This is only called when something went wrong elsewhere, so * we don't really care about the data. Just disable the Loading Loading @@ -1049,11 +1081,6 @@ static int atc_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, clear_bit(ATC_IS_CYCLIC, &atchan->status); spin_unlock_irqrestore(&atchan->lock, flags); } else if (cmd == DMA_SLAVE_CONFIG) { return set_runtime_config(chan, (struct dma_slave_config *)arg); } else { return -ENXIO; } return 0; } Loading Loading @@ -1505,7 +1532,14 @@ static int __init at_dma_probe(struct platform_device *pdev) /* controller can do slave DMA: can trigger cyclic transfers */ dma_cap_set(DMA_CYCLIC, atdma->dma_common.cap_mask); atdma->dma_common.device_prep_dma_cyclic = atc_prep_dma_cyclic; atdma->dma_common.device_control = atc_control; atdma->dma_common.device_config = atc_config; atdma->dma_common.device_pause = atc_pause; atdma->dma_common.device_resume = atc_resume; atdma->dma_common.device_terminate_all = atc_terminate_all; atdma->dma_common.src_addr_widths = ATC_DMA_BUSWIDTHS; atdma->dma_common.dst_addr_widths = ATC_DMA_BUSWIDTHS; atdma->dma_common.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV); atdma->dma_common.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST; } dma_writel(atdma, EN, AT_DMA_ENABLE); Loading Loading @@ -1622,7 +1656,7 @@ static void atc_suspend_cyclic(struct at_dma_chan *atchan) if (!atc_chan_is_paused(atchan)) { dev_warn(chan2dev(chan), "cyclic channel not paused, should be done by channel user\n"); atc_control(chan, DMA_PAUSE, 0); atc_pause(chan); } /* now preserve additional data for cyclic operations */ Loading Loading
Documentation/dmaengine/provider.txt +55 −42 Original line number Diff line number Diff line Loading @@ -113,6 +113,31 @@ need to initialize a few fields in there: * channels: should be initialized as a list using the INIT_LIST_HEAD macro for example * src_addr_widths: - should contain a bitmask of the supported source transfer width * dst_addr_widths: - should contain a bitmask of the supported destination transfer width * directions: - should contain a bitmask of the supported slave directions (i.e. excluding mem2mem transfers) * residue_granularity: - Granularity of the transfer residue reported to dma_set_residue. - This can be either: + Descriptor -> Your device doesn't support any kind of residue reporting. The framework will only know that a particular transaction descriptor is done. + Segment -> Your device is able to report which chunks have been transferred + Burst -> Your device is able to report which burst have been transferred * dev: should hold the pointer to the struct device associated to your current driver instance. Loading Loading @@ -274,48 +299,36 @@ supported. account the current period. - This function can be called in an interrupt context. * device_control - Used by client drivers to control and configure the channel it has a handle on. - Called with a command and an argument + The command is one of the values listed by the enum dma_ctrl_cmd. The valid commands are: + DMA_PAUSE + Pauses a transfer on the channel + This command should operate synchronously on the channel, * device_config - Reconfigures the channel with the configuration given as argument - This command should NOT perform synchronously, or on any currently queued transfers, but only on subsequent ones - In this case, the function will receive a dma_slave_config structure pointer as an argument, that will detail which configuration to use. - Even though that structure contains a direction field, this field is deprecated in favor of the direction argument given to the prep_* functions - This call is mandatory for slave operations only. This should NOT be set or expected to be set for memcpy operations. If a driver support both, it should use this call for slave operations only and not for memcpy ones. * device_pause - Pauses a transfer on the channel - This command should operate synchronously on the channel, pausing right away the work of the given channel * device_resume - Resumes a transfer on the channel - This command should operate synchronously on the channel, pausing right away the work of the given channel + DMA_RESUME + Restarts a transfer on the channel + This command should operate synchronously on the channel, resuming right away the work of the given channel + DMA_TERMINATE_ALL + Aborts all the pending and ongoing transfers on the channel + This command should operate synchronously on the channel, * device_terminate_all - Aborts all the pending and ongoing transfers on the channel - This command should operate synchronously on the channel, terminating right away all the channels + DMA_SLAVE_CONFIG + Reconfigures the channel with passed configuration + This command should NOT perform synchronously, or on any currently queued transfers, but only on subsequent ones + In this case, the function will receive a dma_slave_config structure pointer as an argument, that will detail which configuration to use. + Even though that structure contains a direction field, this field is deprecated in favor of the direction argument given to the prep_* functions + FSLDMA_EXTERNAL_START + TODO: Why does that even exist? + The argument is an opaque unsigned long. This actually is a pointer to a struct dma_slave_config that should be used only in the DMA_SLAVE_CONFIG. * device_slave_caps - Called through the framework by client drivers in order to have an idea of what are the properties of the channel allocated to them. - Such properties are the buswidth, available directions, etc. - Required for every generic layer doing DMA transfers, such as ASoC. Misc notes (stuff that should be documented, but don't really know where to put them) Loading
drivers/crypto/ux500/cryp/cryp_core.c +2 −2 Original line number Diff line number Diff line Loading @@ -606,12 +606,12 @@ static void cryp_dma_done(struct cryp_ctx *ctx) dev_dbg(ctx->device->dev, "[%s]: ", __func__); chan = ctx->device->dma.chan_mem2cryp; dmaengine_device_control(chan, DMA_TERMINATE_ALL, 0); dmaengine_terminate_all(chan); dma_unmap_sg(chan->device->dev, ctx->device->dma.sg_src, ctx->device->dma.sg_src_len, DMA_TO_DEVICE); chan = ctx->device->dma.chan_cryp2mem; dmaengine_device_control(chan, DMA_TERMINATE_ALL, 0); dmaengine_terminate_all(chan); dma_unmap_sg(chan->device->dev, ctx->device->dma.sg_dst, ctx->device->dma.sg_dst_len, DMA_FROM_DEVICE); } Loading
drivers/crypto/ux500/hash/hash_core.c +1 −1 Original line number Diff line number Diff line Loading @@ -202,7 +202,7 @@ static void hash_dma_done(struct hash_ctx *ctx) struct dma_chan *chan; chan = ctx->device->dma.chan_mem2hash; dmaengine_device_control(chan, DMA_TERMINATE_ALL, 0); dmaengine_terminate_all(chan); dma_unmap_sg(chan->device->dev, ctx->device->dma.sg, ctx->device->dma.sg_len, DMA_TO_DEVICE); } Loading
drivers/dma/amba-pl08x.c +90 −66 Original line number Diff line number Diff line Loading @@ -1386,32 +1386,6 @@ static u32 pl08x_get_cctl(struct pl08x_dma_chan *plchan, return pl08x_cctl(cctl); } static int dma_set_runtime_config(struct dma_chan *chan, struct dma_slave_config *config) { struct pl08x_dma_chan *plchan = to_pl08x_chan(chan); struct pl08x_driver_data *pl08x = plchan->host; if (!plchan->slave) return -EINVAL; /* Reject definitely invalid configurations */ if (config->src_addr_width == DMA_SLAVE_BUSWIDTH_8_BYTES || config->dst_addr_width == DMA_SLAVE_BUSWIDTH_8_BYTES) return -EINVAL; if (config->device_fc && pl08x->vd->pl080s) { dev_err(&pl08x->adev->dev, "%s: PL080S does not support peripheral flow control\n", __func__); return -EINVAL; } plchan->cfg = *config; return 0; } /* * Slave transactions callback to the slave device to allow * synchronization of slave DMA signals with the DMAC enable Loading Loading @@ -1693,32 +1667,44 @@ static struct dma_async_tx_descriptor *pl08x_prep_dma_cyclic( return vchan_tx_prep(&plchan->vc, &txd->vd, flags); } static int pl08x_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, unsigned long arg) static int pl08x_config(struct dma_chan *chan, struct dma_slave_config *config) { struct pl08x_dma_chan *plchan = to_pl08x_chan(chan); struct pl08x_driver_data *pl08x = plchan->host; unsigned long flags; int ret = 0; /* Controls applicable to inactive channels */ if (cmd == DMA_SLAVE_CONFIG) { return dma_set_runtime_config(chan, (struct dma_slave_config *)arg); if (!plchan->slave) return -EINVAL; /* Reject definitely invalid configurations */ if (config->src_addr_width == DMA_SLAVE_BUSWIDTH_8_BYTES || config->dst_addr_width == DMA_SLAVE_BUSWIDTH_8_BYTES) return -EINVAL; if (config->device_fc && pl08x->vd->pl080s) { dev_err(&pl08x->adev->dev, "%s: PL080S does not support peripheral flow control\n", __func__); return -EINVAL; } plchan->cfg = *config; return 0; } /* * Anything succeeds on channels with no physical allocation and * no queued transfers. */ static int pl08x_terminate_all(struct dma_chan *chan) { struct pl08x_dma_chan *plchan = to_pl08x_chan(chan); struct pl08x_driver_data *pl08x = plchan->host; unsigned long flags; spin_lock_irqsave(&plchan->vc.lock, flags); if (!plchan->phychan && !plchan->at) { spin_unlock_irqrestore(&plchan->vc.lock, flags); return 0; } switch (cmd) { case DMA_TERMINATE_ALL: plchan->state = PL08X_CHAN_IDLE; if (plchan->phychan) { Loading @@ -1735,24 +1721,56 @@ static int pl08x_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, } /* Dequeue jobs not yet fired as well */ pl08x_free_txd_list(pl08x, plchan); break; case DMA_PAUSE: spin_unlock_irqrestore(&plchan->vc.lock, flags); return 0; } static int pl08x_pause(struct dma_chan *chan) { struct pl08x_dma_chan *plchan = to_pl08x_chan(chan); unsigned long flags; /* * Anything succeeds on channels with no physical allocation and * no queued transfers. */ spin_lock_irqsave(&plchan->vc.lock, flags); if (!plchan->phychan && !plchan->at) { spin_unlock_irqrestore(&plchan->vc.lock, flags); return 0; } pl08x_pause_phy_chan(plchan->phychan); plchan->state = PL08X_CHAN_PAUSED; break; case DMA_RESUME: spin_unlock_irqrestore(&plchan->vc.lock, flags); return 0; } static int pl08x_resume(struct dma_chan *chan) { struct pl08x_dma_chan *plchan = to_pl08x_chan(chan); unsigned long flags; /* * Anything succeeds on channels with no physical allocation and * no queued transfers. */ spin_lock_irqsave(&plchan->vc.lock, flags); if (!plchan->phychan && !plchan->at) { spin_unlock_irqrestore(&plchan->vc.lock, flags); return 0; } pl08x_resume_phy_chan(plchan->phychan); plchan->state = PL08X_CHAN_RUNNING; break; default: /* Unknown command */ ret = -ENXIO; break; } spin_unlock_irqrestore(&plchan->vc.lock, flags); return ret; return 0; } bool pl08x_filter_id(struct dma_chan *chan, void *chan_id) Loading Loading @@ -2048,7 +2066,10 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id) pl08x->memcpy.device_prep_dma_interrupt = pl08x_prep_dma_interrupt; pl08x->memcpy.device_tx_status = pl08x_dma_tx_status; pl08x->memcpy.device_issue_pending = pl08x_issue_pending; pl08x->memcpy.device_control = pl08x_control; pl08x->memcpy.device_config = pl08x_config; pl08x->memcpy.device_pause = pl08x_pause; pl08x->memcpy.device_resume = pl08x_resume; pl08x->memcpy.device_terminate_all = pl08x_terminate_all; /* Initialize slave engine */ dma_cap_set(DMA_SLAVE, pl08x->slave.cap_mask); Loading @@ -2061,7 +2082,10 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id) pl08x->slave.device_issue_pending = pl08x_issue_pending; pl08x->slave.device_prep_slave_sg = pl08x_prep_slave_sg; pl08x->slave.device_prep_dma_cyclic = pl08x_prep_dma_cyclic; pl08x->slave.device_control = pl08x_control; pl08x->slave.device_config = pl08x_config; pl08x->slave.device_pause = pl08x_pause; pl08x->slave.device_resume = pl08x_resume; pl08x->slave.device_terminate_all = pl08x_terminate_all; /* Get the platform data */ pl08x->pd = dev_get_platdata(&adev->dev); Loading
drivers/dma/at_hdmac.c +82 −48 Original line number Diff line number Diff line Loading @@ -42,6 +42,11 @@ #define ATC_DEFAULT_CFG (ATC_FIFOCFG_HALFFIFO) #define ATC_DEFAULT_CTRLB (ATC_SIF(AT_DMA_MEM_IF) \ |ATC_DIF(AT_DMA_MEM_IF)) #define ATC_DMA_BUSWIDTHS\ (BIT(DMA_SLAVE_BUSWIDTH_UNDEFINED) |\ BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |\ BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |\ BIT(DMA_SLAVE_BUSWIDTH_4_BYTES)) /* * Initial number of descriptors to allocate for each channel. This could Loading Loading @@ -972,11 +977,13 @@ atc_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len, return NULL; } static int set_runtime_config(struct dma_chan *chan, static int atc_config(struct dma_chan *chan, struct dma_slave_config *sconfig) { struct at_dma_chan *atchan = to_at_dma_chan(chan); dev_vdbg(chan2dev(chan), "%s\n", __func__); /* Check if it is chan is configured for slave transfers */ if (!chan->private) return -EINVAL; Loading @@ -989,9 +996,7 @@ static int set_runtime_config(struct dma_chan *chan, return 0; } static int atc_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, unsigned long arg) static int atc_pause(struct dma_chan *chan) { struct at_dma_chan *atchan = to_at_dma_chan(chan); struct at_dma *atdma = to_at_dma(chan->device); Loading @@ -1000,16 +1005,29 @@ static int atc_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, LIST_HEAD(list); dev_vdbg(chan2dev(chan), "atc_control (%d)\n", cmd); dev_vdbg(chan2dev(chan), "%s\n", __func__); if (cmd == DMA_PAUSE) { spin_lock_irqsave(&atchan->lock, flags); dma_writel(atdma, CHER, AT_DMA_SUSP(chan_id)); set_bit(ATC_IS_PAUSED, &atchan->status); spin_unlock_irqrestore(&atchan->lock, flags); } else if (cmd == DMA_RESUME) { return 0; } static int atc_resume(struct dma_chan *chan) { struct at_dma_chan *atchan = to_at_dma_chan(chan); struct at_dma *atdma = to_at_dma(chan->device); int chan_id = atchan->chan_common.chan_id; unsigned long flags; LIST_HEAD(list); dev_vdbg(chan2dev(chan), "%s\n", __func__); if (!atc_chan_is_paused(atchan)) return 0; Loading @@ -1019,8 +1037,22 @@ static int atc_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, clear_bit(ATC_IS_PAUSED, &atchan->status); spin_unlock_irqrestore(&atchan->lock, flags); } else if (cmd == DMA_TERMINATE_ALL) { return 0; } static int atc_terminate_all(struct dma_chan *chan) { struct at_dma_chan *atchan = to_at_dma_chan(chan); struct at_dma *atdma = to_at_dma(chan->device); int chan_id = atchan->chan_common.chan_id; struct at_desc *desc, *_desc; unsigned long flags; LIST_HEAD(list); dev_vdbg(chan2dev(chan), "%s\n", __func__); /* * This is only called when something went wrong elsewhere, so * we don't really care about the data. Just disable the Loading Loading @@ -1049,11 +1081,6 @@ static int atc_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, clear_bit(ATC_IS_CYCLIC, &atchan->status); spin_unlock_irqrestore(&atchan->lock, flags); } else if (cmd == DMA_SLAVE_CONFIG) { return set_runtime_config(chan, (struct dma_slave_config *)arg); } else { return -ENXIO; } return 0; } Loading Loading @@ -1505,7 +1532,14 @@ static int __init at_dma_probe(struct platform_device *pdev) /* controller can do slave DMA: can trigger cyclic transfers */ dma_cap_set(DMA_CYCLIC, atdma->dma_common.cap_mask); atdma->dma_common.device_prep_dma_cyclic = atc_prep_dma_cyclic; atdma->dma_common.device_control = atc_control; atdma->dma_common.device_config = atc_config; atdma->dma_common.device_pause = atc_pause; atdma->dma_common.device_resume = atc_resume; atdma->dma_common.device_terminate_all = atc_terminate_all; atdma->dma_common.src_addr_widths = ATC_DMA_BUSWIDTHS; atdma->dma_common.dst_addr_widths = ATC_DMA_BUSWIDTHS; atdma->dma_common.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV); atdma->dma_common.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST; } dma_writel(atdma, EN, AT_DMA_ENABLE); Loading Loading @@ -1622,7 +1656,7 @@ static void atc_suspend_cyclic(struct at_dma_chan *atchan) if (!atc_chan_is_paused(atchan)) { dev_warn(chan2dev(chan), "cyclic channel not paused, should be done by channel user\n"); atc_control(chan, DMA_PAUSE, 0); atc_pause(chan); } /* now preserve additional data for cyclic operations */ Loading