Skip to content

Commit

Permalink
dmaengine: dma-jz4780: Break descriptor chains on JZ4740
Browse files Browse the repository at this point in the history
The current driver works perfectly fine on every generation of the
JZ47xx SoCs, except on the JZ4740.

There, when hardware descriptors are chained together (with the LINK
bit set), the next descriptor isn't automatically fetched as it should -
instead, an interrupt is raised, even if the TIE bit (Transfer Interrupt
Enable) bit is cleared. When it happens, the DMA transfer seems to be
stopped (it doesn't chain), and it's uncertain how many bytes have
actually been transferred.

Until somebody smarter than me can figure out how to make chained
descriptors work on the JZ4740, we now disable chained descriptors on
that particular SoC.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
Link: https://lore.kernel.org/r/20190714215504.10877-1-paul@crapouillou.net
Signed-off-by: Vinod Koul <vkoul@kernel.org>
  • Loading branch information
Paul Cercueil authored and Vinod Koul committed Jul 25, 2019
1 parent 156a599 commit f4c255f
Showing 1 changed file with 12 additions and 3 deletions.
15 changes: 12 additions & 3 deletions drivers/dma/dma-jz4780.c
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@
#define JZ_SOC_DATA_PROGRAMMABLE_DMA BIT(1)
#define JZ_SOC_DATA_PER_CHAN_PM BIT(2)
#define JZ_SOC_DATA_NO_DCKES_DCKEC BIT(3)
#define JZ_SOC_DATA_BREAK_LINKS BIT(4)

/**
* struct jz4780_dma_hwdesc - descriptor structure read by the DMA controller.
Expand Down Expand Up @@ -355,6 +356,7 @@ static struct dma_async_tx_descriptor *jz4780_dma_prep_slave_sg(
void *context)
{
struct jz4780_dma_chan *jzchan = to_jz4780_dma_chan(chan);
struct jz4780_dma_dev *jzdma = jz4780_dma_chan_parent(jzchan);
struct jz4780_dma_desc *desc;
unsigned int i;
int err;
Expand All @@ -375,7 +377,8 @@ static struct dma_async_tx_descriptor *jz4780_dma_prep_slave_sg(

desc->desc[i].dcm |= JZ_DMA_DCM_TIE;

if (i != (sg_len - 1)) {
if (i != (sg_len - 1) &&
!(jzdma->soc_data->flags & JZ_SOC_DATA_BREAK_LINKS)) {
/* Automatically proceeed to the next descriptor. */
desc->desc[i].dcm |= JZ_DMA_DCM_LINK;

Expand Down Expand Up @@ -664,6 +667,8 @@ static enum dma_status jz4780_dma_tx_status(struct dma_chan *chan,
static bool jz4780_dma_chan_irq(struct jz4780_dma_dev *jzdma,
struct jz4780_dma_chan *jzchan)
{
const unsigned int soc_flags = jzdma->soc_data->flags;
struct jz4780_dma_desc *desc = jzchan->desc;
uint32_t dcs;
bool ack = true;

Expand Down Expand Up @@ -691,8 +696,11 @@ static bool jz4780_dma_chan_irq(struct jz4780_dma_dev *jzdma,

jz4780_dma_begin(jzchan);
} else if (dcs & JZ_DMA_DCS_TT) {
vchan_cookie_complete(&jzchan->desc->vdesc);
jzchan->desc = NULL;
if (!(soc_flags & JZ_SOC_DATA_BREAK_LINKS) ||
(jzchan->curr_hwdesc + 1 == desc->count)) {
vchan_cookie_complete(&desc->vdesc);
jzchan->desc = NULL;
}

jz4780_dma_begin(jzchan);
} else {
Expand Down Expand Up @@ -992,6 +1000,7 @@ static int jz4780_dma_remove(struct platform_device *pdev)
static const struct jz4780_dma_soc_data jz4740_dma_soc_data = {
.nb_channels = 6,
.transfer_ord_max = 5,
.flags = JZ_SOC_DATA_BREAK_LINKS,
};

static const struct jz4780_dma_soc_data jz4725b_dma_soc_data = {
Expand Down

0 comments on commit f4c255f

Please sign in to comment.