提交 f8975224 编写于 作者: L Linus Torvalds

Merge branch 'fixes' of git://git.infradead.org/users/vkoul/slave-dma

Pull slave dmaengine fixes from Vinod Koul:
 "Four fixes for dw, pl08x, imx-sdma and at_hdmac driver.  Nothing
  unusual here, simple fixes to these drivers"

* 'fixes' of git://git.infradead.org/users/vkoul/slave-dma:
  dmaengine: pl08x: Define capabilities for generic capabilities reporting
  dmaengine: dw: append MODULE_ALIAS for platform driver
  dmaengine: imx-sdma: switch to dynamic context mode after script loaded
  dmaengine: at_hdmac: Fix calculation of the residual bytes
...@@ -97,6 +97,12 @@ ...@@ -97,6 +97,12 @@
#define DRIVER_NAME "pl08xdmac" #define DRIVER_NAME "pl08xdmac"
#define PL80X_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)
static struct amba_driver pl08x_amba_driver; static struct amba_driver pl08x_amba_driver;
struct pl08x_driver_data; struct pl08x_driver_data;
...@@ -2070,6 +2076,10 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id) ...@@ -2070,6 +2076,10 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id)
pl08x->memcpy.device_pause = pl08x_pause; pl08x->memcpy.device_pause = pl08x_pause;
pl08x->memcpy.device_resume = pl08x_resume; pl08x->memcpy.device_resume = pl08x_resume;
pl08x->memcpy.device_terminate_all = pl08x_terminate_all; pl08x->memcpy.device_terminate_all = pl08x_terminate_all;
pl08x->memcpy.src_addr_widths = PL80X_DMA_BUSWIDTHS;
pl08x->memcpy.dst_addr_widths = PL80X_DMA_BUSWIDTHS;
pl08x->memcpy.directions = BIT(DMA_MEM_TO_MEM);
pl08x->memcpy.residue_granularity = DMA_RESIDUE_GRANULARITY_SEGMENT;
/* Initialize slave engine */ /* Initialize slave engine */
dma_cap_set(DMA_SLAVE, pl08x->slave.cap_mask); dma_cap_set(DMA_SLAVE, pl08x->slave.cap_mask);
...@@ -2086,6 +2096,10 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id) ...@@ -2086,6 +2096,10 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id)
pl08x->slave.device_pause = pl08x_pause; pl08x->slave.device_pause = pl08x_pause;
pl08x->slave.device_resume = pl08x_resume; pl08x->slave.device_resume = pl08x_resume;
pl08x->slave.device_terminate_all = pl08x_terminate_all; pl08x->slave.device_terminate_all = pl08x_terminate_all;
pl08x->slave.src_addr_widths = PL80X_DMA_BUSWIDTHS;
pl08x->slave.dst_addr_widths = PL80X_DMA_BUSWIDTHS;
pl08x->slave.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
pl08x->slave.residue_granularity = DMA_RESIDUE_GRANULARITY_SEGMENT;
/* Get the platform data */ /* Get the platform data */
pl08x->pd = dev_get_platdata(&adev->dev); pl08x->pd = dev_get_platdata(&adev->dev);
......
...@@ -238,93 +238,126 @@ static void atc_dostart(struct at_dma_chan *atchan, struct at_desc *first) ...@@ -238,93 +238,126 @@ static void atc_dostart(struct at_dma_chan *atchan, struct at_desc *first)
} }
/* /*
* atc_get_current_descriptors - * atc_get_desc_by_cookie - get the descriptor of a cookie
* locate the descriptor which equal to physical address in DSCR * @atchan: the DMA channel
* @atchan: the channel we want to start * @cookie: the cookie to get the descriptor for
* @dscr_addr: physical descriptor address in DSCR
*/ */
static struct at_desc *atc_get_current_descriptors(struct at_dma_chan *atchan, static struct at_desc *atc_get_desc_by_cookie(struct at_dma_chan *atchan,
u32 dscr_addr) dma_cookie_t cookie)
{ {
struct at_desc *desc, *_desc, *child, *desc_cur = NULL; struct at_desc *desc, *_desc;
list_for_each_entry_safe(desc, _desc, &atchan->active_list, desc_node) { list_for_each_entry_safe(desc, _desc, &atchan->queue, desc_node) {
if (desc->lli.dscr == dscr_addr) { if (desc->txd.cookie == cookie)
desc_cur = desc; return desc;
break; }
}
list_for_each_entry(child, &desc->tx_list, desc_node) { list_for_each_entry_safe(desc, _desc, &atchan->active_list, desc_node) {
if (child->lli.dscr == dscr_addr) { if (desc->txd.cookie == cookie)
desc_cur = child; return desc;
break;
}
}
} }
return desc_cur; return NULL;
} }
/* /**
* atc_get_bytes_left - * atc_calc_bytes_left - calculates the number of bytes left according to the
* Get the number of bytes residue in dma buffer, * value read from CTRLA.
* @chan: the channel we want to start *
* @current_len: the number of bytes left before reading CTRLA
* @ctrla: the value of CTRLA
* @desc: the descriptor containing the transfer width
*/
static inline int atc_calc_bytes_left(int current_len, u32 ctrla,
struct at_desc *desc)
{
return current_len - ((ctrla & ATC_BTSIZE_MAX) << desc->tx_width);
}
/**
* atc_calc_bytes_left_from_reg - calculates the number of bytes left according
* to the current value of CTRLA.
*
* @current_len: the number of bytes left before reading CTRLA
* @atchan: the channel to read CTRLA for
* @desc: the descriptor containing the transfer width
*/
static inline int atc_calc_bytes_left_from_reg(int current_len,
struct at_dma_chan *atchan, struct at_desc *desc)
{
u32 ctrla = channel_readl(atchan, CTRLA);
return atc_calc_bytes_left(current_len, ctrla, desc);
}
/**
* atc_get_bytes_left - get the number of bytes residue for a cookie
* @chan: DMA channel
* @cookie: transaction identifier to check status of
*/ */
static int atc_get_bytes_left(struct dma_chan *chan) static int atc_get_bytes_left(struct dma_chan *chan, dma_cookie_t cookie)
{ {
struct at_dma_chan *atchan = to_at_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_first = atc_first_active(atchan); struct at_desc *desc_first = atc_first_active(atchan);
struct at_desc *desc_cur; struct at_desc *desc;
int ret = 0, count = 0; int ret;
u32 ctrla, dscr;
/* /*
* Initialize necessary values in the first time. * If the cookie doesn't match to the currently running transfer then
* remain_desc record remain desc length. * we can return the total length of the associated DMA transfer,
* because it is still queued.
*/ */
if (atchan->remain_desc == 0) desc = atc_get_desc_by_cookie(atchan, cookie);
/* First descriptor embedds the transaction length */ if (desc == NULL)
atchan->remain_desc = desc_first->len; return -EINVAL;
else if (desc != desc_first)
return desc->total_len;
/* /* cookie matches to the currently running transfer */
* This happens when current descriptor transfer complete. ret = desc_first->total_len;
* The residual buffer size should reduce current descriptor length.
*/
if (unlikely(test_bit(ATC_IS_BTC, &atchan->status))) {
clear_bit(ATC_IS_BTC, &atchan->status);
desc_cur = atc_get_current_descriptors(atchan,
channel_readl(atchan, DSCR));
if (!desc_cur) {
ret = -EINVAL;
goto out;
}
count = (desc_cur->lli.ctrla & ATC_BTSIZE_MAX) if (desc_first->lli.dscr) {
<< desc_first->tx_width; /* hardware linked list transfer */
if (atchan->remain_desc < count) {
ret = -EINVAL; /*
goto out; * Calculate the residue by removing the length of the child
* descriptors already transferred from the total length.
* To get the current child descriptor we can use the value of
* the channel's DSCR register and compare it against the value
* of the hardware linked list structure of each child
* descriptor.
*/
ctrla = channel_readl(atchan, CTRLA);
rmb(); /* ensure CTRLA is read before DSCR */
dscr = channel_readl(atchan, DSCR);
/* for the first descriptor we can be more accurate */
if (desc_first->lli.dscr == dscr)
return atc_calc_bytes_left(ret, ctrla, desc_first);
ret -= desc_first->len;
list_for_each_entry(desc, &desc_first->tx_list, desc_node) {
if (desc->lli.dscr == dscr)
break;
ret -= desc->len;
} }
atchan->remain_desc -= count;
ret = atchan->remain_desc;
} else {
/* /*
* Get residual bytes when current * For the last descriptor in the chain we can calculate
* descriptor transfer in progress. * the remaining bytes using the channel's register.
* Note that the transfer width of the first and last
* descriptor may differ.
*/ */
count = (channel_readl(atchan, CTRLA) & ATC_BTSIZE_MAX) if (!desc->lli.dscr)
<< (desc_first->tx_width); ret = atc_calc_bytes_left_from_reg(ret, atchan, desc);
ret = atchan->remain_desc - count; } else {
/* single transfer */
ret = atc_calc_bytes_left_from_reg(ret, atchan, desc_first);
} }
/*
* Check fifo empty.
*/
if (!(dma_readl(atdma, CHSR) & AT_DMA_EMPT(chan_id)))
atc_issue_pending(chan);
out:
return ret; return ret;
} }
...@@ -539,8 +572,6 @@ static irqreturn_t at_dma_interrupt(int irq, void *dev_id) ...@@ -539,8 +572,6 @@ static irqreturn_t at_dma_interrupt(int irq, void *dev_id)
/* Give information to tasklet */ /* Give information to tasklet */
set_bit(ATC_IS_ERROR, &atchan->status); set_bit(ATC_IS_ERROR, &atchan->status);
} }
if (pending & AT_DMA_BTC(i))
set_bit(ATC_IS_BTC, &atchan->status);
tasklet_schedule(&atchan->tasklet); tasklet_schedule(&atchan->tasklet);
ret = IRQ_HANDLED; ret = IRQ_HANDLED;
} }
...@@ -653,14 +684,18 @@ atc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, ...@@ -653,14 +684,18 @@ atc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
desc->lli.ctrlb = ctrlb; desc->lli.ctrlb = ctrlb;
desc->txd.cookie = 0; desc->txd.cookie = 0;
desc->len = xfer_count << src_width;
atc_desc_chain(&first, &prev, desc); atc_desc_chain(&first, &prev, desc);
} }
/* First descriptor of the chain embedds additional information */ /* First descriptor of the chain embedds additional information */
first->txd.cookie = -EBUSY; first->txd.cookie = -EBUSY;
first->len = len; first->total_len = len;
/* set transfer width for the calculation of the residue */
first->tx_width = src_width; first->tx_width = src_width;
prev->tx_width = src_width;
/* set end-of-link to the last link descriptor of list*/ /* set end-of-link to the last link descriptor of list*/
set_desc_eol(desc); set_desc_eol(desc);
...@@ -752,6 +787,7 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, ...@@ -752,6 +787,7 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
| ATC_SRC_WIDTH(mem_width) | ATC_SRC_WIDTH(mem_width)
| len >> mem_width; | len >> mem_width;
desc->lli.ctrlb = ctrlb; desc->lli.ctrlb = ctrlb;
desc->len = len;
atc_desc_chain(&first, &prev, desc); atc_desc_chain(&first, &prev, desc);
total_len += len; total_len += len;
...@@ -792,6 +828,7 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, ...@@ -792,6 +828,7 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
| ATC_DST_WIDTH(mem_width) | ATC_DST_WIDTH(mem_width)
| len >> reg_width; | len >> reg_width;
desc->lli.ctrlb = ctrlb; desc->lli.ctrlb = ctrlb;
desc->len = len;
atc_desc_chain(&first, &prev, desc); atc_desc_chain(&first, &prev, desc);
total_len += len; total_len += len;
...@@ -806,8 +843,11 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, ...@@ -806,8 +843,11 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
/* First descriptor of the chain embedds additional information */ /* First descriptor of the chain embedds additional information */
first->txd.cookie = -EBUSY; first->txd.cookie = -EBUSY;
first->len = total_len; first->total_len = total_len;
/* set transfer width for the calculation of the residue */
first->tx_width = reg_width; first->tx_width = reg_width;
prev->tx_width = reg_width;
/* first link descriptor of list is responsible of flags */ /* first link descriptor of list is responsible of flags */
first->txd.flags = flags; /* client is in control of this ack */ first->txd.flags = flags; /* client is in control of this ack */
...@@ -872,6 +912,7 @@ atc_dma_cyclic_fill_desc(struct dma_chan *chan, struct at_desc *desc, ...@@ -872,6 +912,7 @@ atc_dma_cyclic_fill_desc(struct dma_chan *chan, struct at_desc *desc,
| ATC_FC_MEM2PER | ATC_FC_MEM2PER
| ATC_SIF(atchan->mem_if) | ATC_SIF(atchan->mem_if)
| ATC_DIF(atchan->per_if); | ATC_DIF(atchan->per_if);
desc->len = period_len;
break; break;
case DMA_DEV_TO_MEM: case DMA_DEV_TO_MEM:
...@@ -883,6 +924,7 @@ atc_dma_cyclic_fill_desc(struct dma_chan *chan, struct at_desc *desc, ...@@ -883,6 +924,7 @@ atc_dma_cyclic_fill_desc(struct dma_chan *chan, struct at_desc *desc,
| ATC_FC_PER2MEM | ATC_FC_PER2MEM
| ATC_SIF(atchan->per_if) | ATC_SIF(atchan->per_if)
| ATC_DIF(atchan->mem_if); | ATC_DIF(atchan->mem_if);
desc->len = period_len;
break; break;
default: default:
...@@ -964,7 +1006,7 @@ atc_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len, ...@@ -964,7 +1006,7 @@ atc_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
/* First descriptor of the chain embedds additional information */ /* First descriptor of the chain embedds additional information */
first->txd.cookie = -EBUSY; first->txd.cookie = -EBUSY;
first->len = buf_len; first->total_len = buf_len;
first->tx_width = reg_width; first->tx_width = reg_width;
return &first->txd; return &first->txd;
...@@ -1118,7 +1160,7 @@ atc_tx_status(struct dma_chan *chan, ...@@ -1118,7 +1160,7 @@ atc_tx_status(struct dma_chan *chan,
spin_lock_irqsave(&atchan->lock, flags); spin_lock_irqsave(&atchan->lock, flags);
/* Get number of bytes left in the active transactions */ /* Get number of bytes left in the active transactions */
bytes = atc_get_bytes_left(chan); bytes = atc_get_bytes_left(chan, cookie);
spin_unlock_irqrestore(&atchan->lock, flags); spin_unlock_irqrestore(&atchan->lock, flags);
...@@ -1214,7 +1256,6 @@ static int atc_alloc_chan_resources(struct dma_chan *chan) ...@@ -1214,7 +1256,6 @@ static int atc_alloc_chan_resources(struct dma_chan *chan)
spin_lock_irqsave(&atchan->lock, flags); spin_lock_irqsave(&atchan->lock, flags);
atchan->descs_allocated = i; atchan->descs_allocated = i;
atchan->remain_desc = 0;
list_splice(&tmp_list, &atchan->free_list); list_splice(&tmp_list, &atchan->free_list);
dma_cookie_init(chan); dma_cookie_init(chan);
spin_unlock_irqrestore(&atchan->lock, flags); spin_unlock_irqrestore(&atchan->lock, flags);
...@@ -1257,7 +1298,6 @@ static void atc_free_chan_resources(struct dma_chan *chan) ...@@ -1257,7 +1298,6 @@ static void atc_free_chan_resources(struct dma_chan *chan)
list_splice_init(&atchan->free_list, &list); list_splice_init(&atchan->free_list, &list);
atchan->descs_allocated = 0; atchan->descs_allocated = 0;
atchan->status = 0; atchan->status = 0;
atchan->remain_desc = 0;
dev_vdbg(chan2dev(chan), "free_chan_resources: done\n"); dev_vdbg(chan2dev(chan), "free_chan_resources: done\n");
} }
......
...@@ -181,8 +181,9 @@ struct at_lli { ...@@ -181,8 +181,9 @@ struct at_lli {
* @at_lli: hardware lli structure * @at_lli: hardware lli structure
* @txd: support for the async_tx api * @txd: support for the async_tx api
* @desc_node: node on the channed descriptors list * @desc_node: node on the channed descriptors list
* @len: total transaction bytecount * @len: descriptor byte count
* @tx_width: transfer width * @tx_width: transfer width
* @total_len: total transaction byte count
*/ */
struct at_desc { struct at_desc {
/* FIRST values the hardware uses */ /* FIRST values the hardware uses */
...@@ -194,6 +195,7 @@ struct at_desc { ...@@ -194,6 +195,7 @@ struct at_desc {
struct list_head desc_node; struct list_head desc_node;
size_t len; size_t len;
u32 tx_width; u32 tx_width;
size_t total_len;
}; };
static inline struct at_desc * static inline struct at_desc *
...@@ -213,7 +215,6 @@ txd_to_at_desc(struct dma_async_tx_descriptor *txd) ...@@ -213,7 +215,6 @@ txd_to_at_desc(struct dma_async_tx_descriptor *txd)
enum atc_status { enum atc_status {
ATC_IS_ERROR = 0, ATC_IS_ERROR = 0,
ATC_IS_PAUSED = 1, ATC_IS_PAUSED = 1,
ATC_IS_BTC = 2,
ATC_IS_CYCLIC = 24, ATC_IS_CYCLIC = 24,
}; };
...@@ -231,7 +232,6 @@ enum atc_status { ...@@ -231,7 +232,6 @@ enum atc_status {
* @save_cfg: configuration register that is saved on suspend/resume cycle * @save_cfg: configuration register that is saved on suspend/resume cycle
* @save_dscr: for cyclic operations, preserve next descriptor address in * @save_dscr: for cyclic operations, preserve next descriptor address in
* the cyclic list on suspend/resume cycle * the cyclic list on suspend/resume cycle
* @remain_desc: to save remain desc length
* @dma_sconfig: configuration for slave transfers, passed via * @dma_sconfig: configuration for slave transfers, passed via
* .device_config * .device_config
* @lock: serializes enqueue/dequeue operations to descriptors lists * @lock: serializes enqueue/dequeue operations to descriptors lists
...@@ -251,7 +251,6 @@ struct at_dma_chan { ...@@ -251,7 +251,6 @@ struct at_dma_chan {
struct tasklet_struct tasklet; struct tasklet_struct tasklet;
u32 save_cfg; u32 save_cfg;
u32 save_dscr; u32 save_dscr;
u32 remain_desc;
struct dma_slave_config dma_sconfig; struct dma_slave_config dma_sconfig;
spinlock_t lock; spinlock_t lock;
......
...@@ -26,6 +26,8 @@ ...@@ -26,6 +26,8 @@
#include "internal.h" #include "internal.h"
#define DRV_NAME "dw_dmac"
static struct dma_chan *dw_dma_of_xlate(struct of_phandle_args *dma_spec, static struct dma_chan *dw_dma_of_xlate(struct of_phandle_args *dma_spec,
struct of_dma *ofdma) struct of_dma *ofdma)
{ {
...@@ -284,7 +286,7 @@ static struct platform_driver dw_driver = { ...@@ -284,7 +286,7 @@ static struct platform_driver dw_driver = {
.remove = dw_remove, .remove = dw_remove,
.shutdown = dw_shutdown, .shutdown = dw_shutdown,
.driver = { .driver = {
.name = "dw_dmac", .name = DRV_NAME,
.pm = &dw_dev_pm_ops, .pm = &dw_dev_pm_ops,
.of_match_table = of_match_ptr(dw_dma_of_id_table), .of_match_table = of_match_ptr(dw_dma_of_id_table),
.acpi_match_table = ACPI_PTR(dw_dma_acpi_id_table), .acpi_match_table = ACPI_PTR(dw_dma_acpi_id_table),
...@@ -305,3 +307,4 @@ module_exit(dw_exit); ...@@ -305,3 +307,4 @@ module_exit(dw_exit);
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("Synopsys DesignWare DMA Controller platform driver"); MODULE_DESCRIPTION("Synopsys DesignWare DMA Controller platform driver");
MODULE_ALIAS("platform:" DRV_NAME);
...@@ -531,6 +531,10 @@ static int sdma_run_channel0(struct sdma_engine *sdma) ...@@ -531,6 +531,10 @@ static int sdma_run_channel0(struct sdma_engine *sdma)
dev_err(sdma->dev, "Timeout waiting for CH0 ready\n"); dev_err(sdma->dev, "Timeout waiting for CH0 ready\n");
} }
/* Set bits of CONFIG register with dynamic context switching */
if (readl(sdma->regs + SDMA_H_CONFIG) == 0)
writel_relaxed(SDMA_H_CONFIG_CSM, sdma->regs + SDMA_H_CONFIG);
return ret ? 0 : -ETIMEDOUT; return ret ? 0 : -ETIMEDOUT;
} }
...@@ -1394,9 +1398,6 @@ static int sdma_init(struct sdma_engine *sdma) ...@@ -1394,9 +1398,6 @@ static int sdma_init(struct sdma_engine *sdma)
writel_relaxed(ccb_phys, sdma->regs + SDMA_H_C0PTR); writel_relaxed(ccb_phys, sdma->regs + SDMA_H_C0PTR);
/* Set bits of CONFIG register with given context switching mode */
writel_relaxed(SDMA_H_CONFIG_CSM, sdma->regs + SDMA_H_CONFIG);
/* Initializes channel's priorities */ /* Initializes channel's priorities */
sdma_set_channel_priority(&sdma->channel[0], 7); sdma_set_channel_priority(&sdma->channel[0], 7);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册