Skip to content

Commit 234c56a

Browse files
committed
Merge branch 'at91-4.14-trunk/dma' into linux-4.14-at91
2 parents ad5acd5 + a902f6f commit 234c56a

File tree

1 file changed

+61
-14
lines changed

1 file changed

+61
-14
lines changed

drivers/dma/at_xdmac.c

Lines changed: 61 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,7 @@ struct at_xdmac_chan {
203203
u32 save_cim;
204204
u32 save_cnda;
205205
u32 save_cndc;
206+
u32 irq_status;
206207
unsigned long status;
207208
struct tasklet_struct tasklet;
208209
struct dma_slave_config sconfig;
@@ -307,6 +308,11 @@ static inline int at_xdmac_csize(u32 maxburst)
307308
return csize;
308309
};
309310

311+
static inline bool at_xdmac_chan_is_peripheral_xfer(u32 cfg)
312+
{
313+
return cfg & AT_XDMAC_CC_TYPE_PER_TRAN;
314+
}
315+
310316
static inline u8 at_xdmac_get_dwidth(u32 cfg)
311317
{
312318
return (cfg & AT_XDMAC_CC_DWIDTH_MASK) >> AT_XDMAC_CC_DWIDTH_OFFSET;
@@ -388,7 +394,13 @@ static void at_xdmac_start_xfer(struct at_xdmac_chan *atchan,
388394
at_xdmac_chan_read(atchan, AT_XDMAC_CUBC));
389395

390396
at_xdmac_chan_write(atchan, AT_XDMAC_CID, 0xffffffff);
391-
reg = AT_XDMAC_CIE_RBEIE | AT_XDMAC_CIE_WBEIE | AT_XDMAC_CIE_ROIE;
397+
reg = AT_XDMAC_CIE_RBEIE | AT_XDMAC_CIE_WBEIE;
398+
/*
399+
* Request Overflow Error is only for peripheral synchronized transfers
400+
*/
401+
if (at_xdmac_chan_is_peripheral_xfer(first->lld.mbr_cfg))
402+
reg |= AT_XDMAC_CIE_ROIE;
403+
392404
/*
393405
* There is no end of list when doing cyclic dma, we need to get
394406
* an interrupt after each periods.
@@ -1574,38 +1586,73 @@ static void at_xdmac_handle_cyclic(struct at_xdmac_chan *atchan)
15741586
dmaengine_desc_get_callback_invoke(txd, NULL);
15751587
}
15761588

1589+
static void at_xdmac_handle_error(struct at_xdmac_chan *atchan)
1590+
{
1591+
struct at_xdmac *atxdmac = to_at_xdmac(atchan->chan.device);
1592+
struct at_xdmac_desc *bad_desc;
1593+
1594+
/*
1595+
* The descriptor currently at the head of the active list is
1596+
* broked. Since we don't have any way to report errors, we'll
1597+
* just have to scream loudly and try to carry on.
1598+
*/
1599+
if (atchan->irq_status & AT_XDMAC_CIS_RBEIS)
1600+
dev_err(chan2dev(&atchan->chan), "read bus error!!!");
1601+
if (atchan->irq_status & AT_XDMAC_CIS_WBEIS)
1602+
dev_err(chan2dev(&atchan->chan), "write bus error!!!");
1603+
if (atchan->irq_status & AT_XDMAC_CIS_ROIS)
1604+
dev_err(chan2dev(&atchan->chan), "request overflow error!!!");
1605+
1606+
spin_lock_bh(&atchan->lock);
1607+
/* Channel must be disabled first as it's not done automatically */
1608+
at_xdmac_write(atxdmac, AT_XDMAC_GD, atchan->mask);
1609+
while (at_xdmac_read(atxdmac, AT_XDMAC_GS) & atchan->mask)
1610+
cpu_relax();
1611+
bad_desc = list_first_entry(&atchan->xfers_list,
1612+
struct at_xdmac_desc,
1613+
xfer_node);
1614+
spin_unlock_bh(&atchan->lock);
1615+
/* Print bad descriptor's details if needed */
1616+
dev_dbg(chan2dev(&atchan->chan),
1617+
"%s: lld: mbr_sa=%pad, mbr_da=%pad, mbr_ubc=0x%08x\n",
1618+
__func__, &bad_desc->lld.mbr_sa, &bad_desc->lld.mbr_da,
1619+
bad_desc->lld.mbr_ubc);
1620+
1621+
/* Then continue with usual descriptor management */
1622+
}
1623+
15771624
static void at_xdmac_tasklet(unsigned long data)
15781625
{
15791626
struct at_xdmac_chan *atchan = (struct at_xdmac_chan *)data;
15801627
struct at_xdmac_desc *desc;
15811628
u32 error_mask;
15821629

1583-
dev_dbg(chan2dev(&atchan->chan), "%s: status=0x%08lx\n",
1584-
__func__, atchan->status);
1630+
dev_dbg(chan2dev(&atchan->chan), "%s: status=0x%08x\n",
1631+
__func__, atchan->irq_status);
15851632

15861633
error_mask = AT_XDMAC_CIS_RBEIS
15871634
| AT_XDMAC_CIS_WBEIS
15881635
| AT_XDMAC_CIS_ROIS;
15891636

15901637
if (at_xdmac_chan_is_cyclic(atchan)) {
15911638
at_xdmac_handle_cyclic(atchan);
1592-
} else if ((atchan->status & AT_XDMAC_CIS_LIS)
1593-
|| (atchan->status & error_mask)) {
1639+
} else if ((atchan->irq_status & AT_XDMAC_CIS_LIS)
1640+
|| (atchan->irq_status & error_mask)) {
15941641
struct dma_async_tx_descriptor *txd;
15951642

1596-
if (atchan->status & AT_XDMAC_CIS_RBEIS)
1597-
dev_err(chan2dev(&atchan->chan), "read bus error!!!");
1598-
if (atchan->status & AT_XDMAC_CIS_WBEIS)
1599-
dev_err(chan2dev(&atchan->chan), "write bus error!!!");
1600-
if (atchan->status & AT_XDMAC_CIS_ROIS)
1601-
dev_err(chan2dev(&atchan->chan), "request overflow error!!!");
1643+
if (atchan->irq_status & error_mask)
1644+
at_xdmac_handle_error(atchan);
16021645

16031646
spin_lock_bh(&atchan->lock);
16041647
desc = list_first_entry(&atchan->xfers_list,
16051648
struct at_xdmac_desc,
16061649
xfer_node);
16071650
dev_vdbg(chan2dev(&atchan->chan), "%s: desc 0x%p\n", __func__, desc);
1608-
BUG_ON(!desc->active_xfer);
1651+
if (!desc->active_xfer) {
1652+
dev_err(chan2dev(&atchan->chan), "Xfer not active: exiting");
1653+
spin_unlock_bh(&atchan->lock);
1654+
return;
1655+
}
16091656

16101657
txd = &desc->tx_dma_desc;
16111658

@@ -1652,7 +1699,7 @@ static irqreturn_t at_xdmac_interrupt(int irq, void *dev_id)
16521699
atchan = &atxdmac->chan[i];
16531700
chan_imr = at_xdmac_chan_read(atchan, AT_XDMAC_CIM);
16541701
chan_status = at_xdmac_chan_read(atchan, AT_XDMAC_CIS);
1655-
atchan->status = chan_status & chan_imr;
1702+
atchan->irq_status = chan_status & chan_imr;
16561703
dev_vdbg(atxdmac->dma.dev,
16571704
"%s: chan%d: imr=0x%x, status=0x%x\n",
16581705
__func__, i, chan_imr, chan_status);
@@ -1666,7 +1713,7 @@ static irqreturn_t at_xdmac_interrupt(int irq, void *dev_id)
16661713
at_xdmac_chan_read(atchan, AT_XDMAC_CDA),
16671714
at_xdmac_chan_read(atchan, AT_XDMAC_CUBC));
16681715

1669-
if (atchan->status & (AT_XDMAC_CIS_RBEIS | AT_XDMAC_CIS_WBEIS))
1716+
if (atchan->irq_status & (AT_XDMAC_CIS_RBEIS | AT_XDMAC_CIS_WBEIS))
16701717
at_xdmac_write(atxdmac, AT_XDMAC_GD, atchan->mask);
16711718

16721719
tasklet_schedule(&atchan->tasklet);

0 commit comments

Comments
 (0)