| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Driver for the Atmel Extensible DMA Controller (aka XDMAC on AT91 systems) |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Copyright (C) 2014 Atmel Corporation |
|---|
| 5 | 6 | * |
|---|
| 6 | 7 | * Author: Ludovic Desroches <ludovic.desroches@atmel.com> |
|---|
| 7 | | - * |
|---|
| 8 | | - * This program is free software; you can redistribute it and/or modify it |
|---|
| 9 | | - * under the terms of the GNU General Public License version 2 as published by |
|---|
| 10 | | - * the Free Software Foundation. |
|---|
| 11 | | - * |
|---|
| 12 | | - * This program is distributed in the hope that it will be useful, but WITHOUT |
|---|
| 13 | | - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|---|
| 14 | | - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
|---|
| 15 | | - * more details. |
|---|
| 16 | | - * |
|---|
| 17 | | - * You should have received a copy of the GNU General Public License along with |
|---|
| 18 | | - * this program. If not, see <http://www.gnu.org/licenses/>. |
|---|
| 19 | 8 | */ |
|---|
| 20 | 9 | |
|---|
| 21 | 10 | #include <asm/barrier.h> |
|---|
| .. | .. |
|---|
| 223 | 212 | int irq; |
|---|
| 224 | 213 | struct clk *clk; |
|---|
| 225 | 214 | u32 save_gim; |
|---|
| 215 | + u32 save_gs; |
|---|
| 226 | 216 | struct dma_pool *at_xdmac_desc_pool; |
|---|
| 227 | | - struct at_xdmac_chan chan[0]; |
|---|
| 217 | + struct at_xdmac_chan chan[]; |
|---|
| 228 | 218 | }; |
|---|
| 229 | 219 | |
|---|
| 230 | 220 | |
|---|
| .. | .. |
|---|
| 309 | 299 | return csize; |
|---|
| 310 | 300 | }; |
|---|
| 311 | 301 | |
|---|
| 302 | +static inline bool at_xdmac_chan_is_peripheral_xfer(u32 cfg) |
|---|
| 303 | +{ |
|---|
| 304 | + return cfg & AT_XDMAC_CC_TYPE_PER_TRAN; |
|---|
| 305 | +} |
|---|
| 306 | + |
|---|
| 312 | 307 | static inline u8 at_xdmac_get_dwidth(u32 cfg) |
|---|
| 313 | 308 | { |
|---|
| 314 | 309 | return (cfg & AT_XDMAC_CC_DWIDTH_MASK) >> AT_XDMAC_CC_DWIDTH_OFFSET; |
|---|
| .. | .. |
|---|
| 388 | 383 | at_xdmac_chan_read(atchan, AT_XDMAC_CUBC)); |
|---|
| 389 | 384 | |
|---|
| 390 | 385 | at_xdmac_chan_write(atchan, AT_XDMAC_CID, 0xffffffff); |
|---|
| 391 | | - reg = AT_XDMAC_CIE_RBEIE | AT_XDMAC_CIE_WBEIE | AT_XDMAC_CIE_ROIE; |
|---|
| 386 | + reg = AT_XDMAC_CIE_RBEIE | AT_XDMAC_CIE_WBEIE; |
|---|
| 387 | + /* |
|---|
| 388 | + * Request Overflow Error is only for peripheral synchronized transfers |
|---|
| 389 | + */ |
|---|
| 390 | + if (at_xdmac_chan_is_peripheral_xfer(first->lld.mbr_cfg)) |
|---|
| 391 | + reg |= AT_XDMAC_CIE_ROIE; |
|---|
| 392 | + |
|---|
| 392 | 393 | /* |
|---|
| 393 | 394 | * There is no end of list when doing cyclic dma, we need to get |
|---|
| 394 | 395 | * an interrupt after each periods. |
|---|
| .. | .. |
|---|
| 677 | 678 | if (!desc) { |
|---|
| 678 | 679 | dev_err(chan2dev(chan), "can't get descriptor\n"); |
|---|
| 679 | 680 | if (first) |
|---|
| 680 | | - list_splice_init(&first->descs_list, &atchan->free_descs_list); |
|---|
| 681 | + list_splice_tail_init(&first->descs_list, |
|---|
| 682 | + &atchan->free_descs_list); |
|---|
| 681 | 683 | goto spin_unlock; |
|---|
| 682 | 684 | } |
|---|
| 683 | 685 | |
|---|
| .. | .. |
|---|
| 765 | 767 | if (!desc) { |
|---|
| 766 | 768 | dev_err(chan2dev(chan), "can't get descriptor\n"); |
|---|
| 767 | 769 | if (first) |
|---|
| 768 | | - list_splice_init(&first->descs_list, &atchan->free_descs_list); |
|---|
| 770 | + list_splice_tail_init(&first->descs_list, |
|---|
| 771 | + &atchan->free_descs_list); |
|---|
| 769 | 772 | spin_unlock_irqrestore(&atchan->lock, irqflags); |
|---|
| 770 | 773 | return NULL; |
|---|
| 771 | 774 | } |
|---|
| .. | .. |
|---|
| 967 | 970 | NULL, |
|---|
| 968 | 971 | src_addr, dst_addr, |
|---|
| 969 | 972 | xt, xt->sgl); |
|---|
| 973 | + if (!first) |
|---|
| 974 | + return NULL; |
|---|
| 970 | 975 | |
|---|
| 971 | 976 | /* Length of the block is (BLEN+1) microblocks. */ |
|---|
| 972 | 977 | for (i = 0; i < xt->numf - 1; i++) |
|---|
| .. | .. |
|---|
| 997 | 1002 | src_addr, dst_addr, |
|---|
| 998 | 1003 | xt, chunk); |
|---|
| 999 | 1004 | if (!desc) { |
|---|
| 1000 | | - list_splice_init(&first->descs_list, |
|---|
| 1001 | | - &atchan->free_descs_list); |
|---|
| 1005 | + if (first) |
|---|
| 1006 | + list_splice_tail_init(&first->descs_list, |
|---|
| 1007 | + &atchan->free_descs_list); |
|---|
| 1002 | 1008 | return NULL; |
|---|
| 1003 | 1009 | } |
|---|
| 1004 | 1010 | |
|---|
| .. | .. |
|---|
| 1076 | 1082 | if (!desc) { |
|---|
| 1077 | 1083 | dev_err(chan2dev(chan), "can't get descriptor\n"); |
|---|
| 1078 | 1084 | if (first) |
|---|
| 1079 | | - list_splice_init(&first->descs_list, &atchan->free_descs_list); |
|---|
| 1085 | + list_splice_tail_init(&first->descs_list, |
|---|
| 1086 | + &atchan->free_descs_list); |
|---|
| 1080 | 1087 | return NULL; |
|---|
| 1081 | 1088 | } |
|---|
| 1082 | 1089 | |
|---|
| .. | .. |
|---|
| 1250 | 1257 | sg_dma_len(sg), |
|---|
| 1251 | 1258 | value); |
|---|
| 1252 | 1259 | if (!desc && first) |
|---|
| 1253 | | - list_splice_init(&first->descs_list, |
|---|
| 1254 | | - &atchan->free_descs_list); |
|---|
| 1260 | + list_splice_tail_init(&first->descs_list, |
|---|
| 1261 | + &atchan->free_descs_list); |
|---|
| 1255 | 1262 | |
|---|
| 1256 | 1263 | if (!first) |
|---|
| 1257 | 1264 | first = desc; |
|---|
| .. | .. |
|---|
| 1390 | 1397 | { |
|---|
| 1391 | 1398 | struct at_xdmac_chan *atchan = to_at_xdmac_chan(chan); |
|---|
| 1392 | 1399 | struct at_xdmac *atxdmac = to_at_xdmac(atchan->chan.device); |
|---|
| 1393 | | - struct at_xdmac_desc *desc, *_desc; |
|---|
| 1400 | + struct at_xdmac_desc *desc, *_desc, *iter; |
|---|
| 1394 | 1401 | struct list_head *descs_list; |
|---|
| 1395 | 1402 | enum dma_status ret; |
|---|
| 1396 | 1403 | int residue, retry; |
|---|
| .. | .. |
|---|
| 1505 | 1512 | * microblock. |
|---|
| 1506 | 1513 | */ |
|---|
| 1507 | 1514 | descs_list = &desc->descs_list; |
|---|
| 1508 | | - list_for_each_entry_safe(desc, _desc, descs_list, desc_node) { |
|---|
| 1509 | | - dwidth = at_xdmac_get_dwidth(desc->lld.mbr_cfg); |
|---|
| 1510 | | - residue -= (desc->lld.mbr_ubc & 0xffffff) << dwidth; |
|---|
| 1511 | | - if ((desc->lld.mbr_nda & 0xfffffffc) == cur_nda) |
|---|
| 1515 | + list_for_each_entry_safe(iter, _desc, descs_list, desc_node) { |
|---|
| 1516 | + dwidth = at_xdmac_get_dwidth(iter->lld.mbr_cfg); |
|---|
| 1517 | + residue -= (iter->lld.mbr_ubc & 0xffffff) << dwidth; |
|---|
| 1518 | + if ((iter->lld.mbr_nda & 0xfffffffc) == cur_nda) { |
|---|
| 1519 | + desc = iter; |
|---|
| 1512 | 1520 | break; |
|---|
| 1521 | + } |
|---|
| 1513 | 1522 | } |
|---|
| 1514 | 1523 | residue += cur_ubc << dwidth; |
|---|
| 1515 | 1524 | |
|---|
| .. | .. |
|---|
| 1524 | 1533 | return ret; |
|---|
| 1525 | 1534 | } |
|---|
| 1526 | 1535 | |
|---|
| 1527 | | -/* Call must be protected by lock. */ |
|---|
| 1528 | | -static void at_xdmac_remove_xfer(struct at_xdmac_chan *atchan, |
|---|
| 1529 | | - struct at_xdmac_desc *desc) |
|---|
| 1530 | | -{ |
|---|
| 1531 | | - dev_dbg(chan2dev(&atchan->chan), "%s: desc 0x%p\n", __func__, desc); |
|---|
| 1532 | | - |
|---|
| 1533 | | - /* |
|---|
| 1534 | | - * Remove the transfer from the transfer list then move the transfer |
|---|
| 1535 | | - * descriptors into the free descriptors list. |
|---|
| 1536 | | - */ |
|---|
| 1537 | | - list_del(&desc->xfer_node); |
|---|
| 1538 | | - list_splice_init(&desc->descs_list, &atchan->free_descs_list); |
|---|
| 1539 | | -} |
|---|
| 1540 | | - |
|---|
| 1541 | 1536 | static void at_xdmac_advance_work(struct at_xdmac_chan *atchan) |
|---|
| 1542 | 1537 | { |
|---|
| 1543 | 1538 | struct at_xdmac_desc *desc; |
|---|
| 1544 | | - unsigned long flags; |
|---|
| 1545 | | - |
|---|
| 1546 | | - spin_lock_irqsave(&atchan->lock, flags); |
|---|
| 1547 | 1539 | |
|---|
| 1548 | 1540 | /* |
|---|
| 1549 | 1541 | * If channel is enabled, do nothing, advance_work will be triggered |
|---|
| .. | .. |
|---|
| 1557 | 1549 | if (!desc->active_xfer) |
|---|
| 1558 | 1550 | at_xdmac_start_xfer(atchan, desc); |
|---|
| 1559 | 1551 | } |
|---|
| 1560 | | - |
|---|
| 1561 | | - spin_unlock_irqrestore(&atchan->lock, flags); |
|---|
| 1562 | 1552 | } |
|---|
| 1563 | 1553 | |
|---|
| 1564 | 1554 | static void at_xdmac_handle_cyclic(struct at_xdmac_chan *atchan) |
|---|
| .. | .. |
|---|
| 1566 | 1556 | struct at_xdmac_desc *desc; |
|---|
| 1567 | 1557 | struct dma_async_tx_descriptor *txd; |
|---|
| 1568 | 1558 | |
|---|
| 1569 | | - desc = list_first_entry(&atchan->xfers_list, struct at_xdmac_desc, xfer_node); |
|---|
| 1559 | + spin_lock_irq(&atchan->lock); |
|---|
| 1560 | + if (list_empty(&atchan->xfers_list)) { |
|---|
| 1561 | + spin_unlock_irq(&atchan->lock); |
|---|
| 1562 | + return; |
|---|
| 1563 | + } |
|---|
| 1564 | + desc = list_first_entry(&atchan->xfers_list, struct at_xdmac_desc, |
|---|
| 1565 | + xfer_node); |
|---|
| 1566 | + spin_unlock_irq(&atchan->lock); |
|---|
| 1570 | 1567 | txd = &desc->tx_dma_desc; |
|---|
| 1571 | | - |
|---|
| 1572 | 1568 | if (txd->flags & DMA_PREP_INTERRUPT) |
|---|
| 1573 | 1569 | dmaengine_desc_get_callback_invoke(txd, NULL); |
|---|
| 1574 | 1570 | } |
|---|
| 1575 | 1571 | |
|---|
| 1576 | | -static void at_xdmac_tasklet(unsigned long data) |
|---|
| 1572 | +static void at_xdmac_handle_error(struct at_xdmac_chan *atchan) |
|---|
| 1577 | 1573 | { |
|---|
| 1578 | | - struct at_xdmac_chan *atchan = (struct at_xdmac_chan *)data; |
|---|
| 1574 | + struct at_xdmac *atxdmac = to_at_xdmac(atchan->chan.device); |
|---|
| 1575 | + struct at_xdmac_desc *bad_desc; |
|---|
| 1576 | + |
|---|
| 1577 | + /* |
|---|
| 1578 | + * The descriptor currently at the head of the active list is |
|---|
| 1579 | + * broken. Since we don't have any way to report errors, we'll |
|---|
| 1580 | + * just have to scream loudly and try to continue with other |
|---|
| 1581 | + * descriptors queued (if any). |
|---|
| 1582 | + */ |
|---|
| 1583 | + if (atchan->irq_status & AT_XDMAC_CIS_RBEIS) |
|---|
| 1584 | + dev_err(chan2dev(&atchan->chan), "read bus error!!!"); |
|---|
| 1585 | + if (atchan->irq_status & AT_XDMAC_CIS_WBEIS) |
|---|
| 1586 | + dev_err(chan2dev(&atchan->chan), "write bus error!!!"); |
|---|
| 1587 | + if (atchan->irq_status & AT_XDMAC_CIS_ROIS) |
|---|
| 1588 | + dev_err(chan2dev(&atchan->chan), "request overflow error!!!"); |
|---|
| 1589 | + |
|---|
| 1590 | + spin_lock_irq(&atchan->lock); |
|---|
| 1591 | + |
|---|
| 1592 | + /* Channel must be disabled first as it's not done automatically */ |
|---|
| 1593 | + at_xdmac_write(atxdmac, AT_XDMAC_GD, atchan->mask); |
|---|
| 1594 | + while (at_xdmac_read(atxdmac, AT_XDMAC_GS) & atchan->mask) |
|---|
| 1595 | + cpu_relax(); |
|---|
| 1596 | + |
|---|
| 1597 | + bad_desc = list_first_entry(&atchan->xfers_list, |
|---|
| 1598 | + struct at_xdmac_desc, |
|---|
| 1599 | + xfer_node); |
|---|
| 1600 | + |
|---|
| 1601 | + spin_unlock_irq(&atchan->lock); |
|---|
| 1602 | + |
|---|
| 1603 | + /* Print bad descriptor's details if needed */ |
|---|
| 1604 | + dev_dbg(chan2dev(&atchan->chan), |
|---|
| 1605 | + "%s: lld: mbr_sa=%pad, mbr_da=%pad, mbr_ubc=0x%08x\n", |
|---|
| 1606 | + __func__, &bad_desc->lld.mbr_sa, &bad_desc->lld.mbr_da, |
|---|
| 1607 | + bad_desc->lld.mbr_ubc); |
|---|
| 1608 | + |
|---|
| 1609 | + /* Then continue with usual descriptor management */ |
|---|
| 1610 | +} |
|---|
| 1611 | + |
|---|
| 1612 | +static void at_xdmac_tasklet(struct tasklet_struct *t) |
|---|
| 1613 | +{ |
|---|
| 1614 | + struct at_xdmac_chan *atchan = from_tasklet(atchan, t, tasklet); |
|---|
| 1579 | 1615 | struct at_xdmac_desc *desc; |
|---|
| 1580 | 1616 | u32 error_mask; |
|---|
| 1581 | 1617 | |
|---|
| .. | .. |
|---|
| 1592 | 1628 | || (atchan->irq_status & error_mask)) { |
|---|
| 1593 | 1629 | struct dma_async_tx_descriptor *txd; |
|---|
| 1594 | 1630 | |
|---|
| 1595 | | - if (atchan->irq_status & AT_XDMAC_CIS_RBEIS) |
|---|
| 1596 | | - dev_err(chan2dev(&atchan->chan), "read bus error!!!"); |
|---|
| 1597 | | - if (atchan->irq_status & AT_XDMAC_CIS_WBEIS) |
|---|
| 1598 | | - dev_err(chan2dev(&atchan->chan), "write bus error!!!"); |
|---|
| 1599 | | - if (atchan->irq_status & AT_XDMAC_CIS_ROIS) |
|---|
| 1600 | | - dev_err(chan2dev(&atchan->chan), "request overflow error!!!"); |
|---|
| 1631 | + if (atchan->irq_status & error_mask) |
|---|
| 1632 | + at_xdmac_handle_error(atchan); |
|---|
| 1601 | 1633 | |
|---|
| 1602 | | - spin_lock_bh(&atchan->lock); |
|---|
| 1634 | + spin_lock_irq(&atchan->lock); |
|---|
| 1603 | 1635 | desc = list_first_entry(&atchan->xfers_list, |
|---|
| 1604 | 1636 | struct at_xdmac_desc, |
|---|
| 1605 | 1637 | xfer_node); |
|---|
| 1606 | 1638 | dev_vdbg(chan2dev(&atchan->chan), "%s: desc 0x%p\n", __func__, desc); |
|---|
| 1607 | 1639 | if (!desc->active_xfer) { |
|---|
| 1608 | 1640 | dev_err(chan2dev(&atchan->chan), "Xfer not active: exiting"); |
|---|
| 1609 | | - spin_unlock(&atchan->lock); |
|---|
| 1641 | + spin_unlock_irq(&atchan->lock); |
|---|
| 1610 | 1642 | return; |
|---|
| 1611 | 1643 | } |
|---|
| 1612 | 1644 | |
|---|
| 1613 | 1645 | txd = &desc->tx_dma_desc; |
|---|
| 1646 | + dma_cookie_complete(txd); |
|---|
| 1647 | + /* Remove the transfer from the transfer list. */ |
|---|
| 1648 | + list_del(&desc->xfer_node); |
|---|
| 1649 | + spin_unlock_irq(&atchan->lock); |
|---|
| 1614 | 1650 | |
|---|
| 1615 | | - at_xdmac_remove_xfer(atchan, desc); |
|---|
| 1616 | | - spin_unlock_bh(&atchan->lock); |
|---|
| 1617 | | - |
|---|
| 1618 | | - if (!at_xdmac_chan_is_cyclic(atchan)) { |
|---|
| 1619 | | - dma_cookie_complete(txd); |
|---|
| 1620 | | - if (txd->flags & DMA_PREP_INTERRUPT) |
|---|
| 1621 | | - dmaengine_desc_get_callback_invoke(txd, NULL); |
|---|
| 1622 | | - } |
|---|
| 1651 | + if (txd->flags & DMA_PREP_INTERRUPT) |
|---|
| 1652 | + dmaengine_desc_get_callback_invoke(txd, NULL); |
|---|
| 1623 | 1653 | |
|---|
| 1624 | 1654 | dma_run_dependencies(txd); |
|---|
| 1625 | 1655 | |
|---|
| 1656 | + spin_lock_irq(&atchan->lock); |
|---|
| 1657 | + /* Move the xfer descriptors into the free descriptors list. */ |
|---|
| 1658 | + list_splice_tail_init(&desc->descs_list, |
|---|
| 1659 | + &atchan->free_descs_list); |
|---|
| 1626 | 1660 | at_xdmac_advance_work(atchan); |
|---|
| 1661 | + spin_unlock_irq(&atchan->lock); |
|---|
| 1627 | 1662 | } |
|---|
| 1628 | 1663 | } |
|---|
| 1629 | 1664 | |
|---|
| .. | .. |
|---|
| 1684 | 1719 | static void at_xdmac_issue_pending(struct dma_chan *chan) |
|---|
| 1685 | 1720 | { |
|---|
| 1686 | 1721 | struct at_xdmac_chan *atchan = to_at_xdmac_chan(chan); |
|---|
| 1722 | + unsigned long flags; |
|---|
| 1687 | 1723 | |
|---|
| 1688 | 1724 | dev_dbg(chan2dev(&atchan->chan), "%s\n", __func__); |
|---|
| 1689 | 1725 | |
|---|
| 1690 | | - if (!at_xdmac_chan_is_cyclic(atchan)) |
|---|
| 1691 | | - at_xdmac_advance_work(atchan); |
|---|
| 1726 | + spin_lock_irqsave(&atchan->lock, flags); |
|---|
| 1727 | + at_xdmac_advance_work(atchan); |
|---|
| 1728 | + spin_unlock_irqrestore(&atchan->lock, flags); |
|---|
| 1692 | 1729 | |
|---|
| 1693 | 1730 | return; |
|---|
| 1694 | 1731 | } |
|---|
| .. | .. |
|---|
| 1766 | 1803 | cpu_relax(); |
|---|
| 1767 | 1804 | |
|---|
| 1768 | 1805 | /* Cancel all pending transfers. */ |
|---|
| 1769 | | - list_for_each_entry_safe(desc, _desc, &atchan->xfers_list, xfer_node) |
|---|
| 1770 | | - at_xdmac_remove_xfer(atchan, desc); |
|---|
| 1806 | + list_for_each_entry_safe(desc, _desc, &atchan->xfers_list, xfer_node) { |
|---|
| 1807 | + list_del(&desc->xfer_node); |
|---|
| 1808 | + list_splice_tail_init(&desc->descs_list, |
|---|
| 1809 | + &atchan->free_descs_list); |
|---|
| 1810 | + } |
|---|
| 1771 | 1811 | |
|---|
| 1772 | 1812 | clear_bit(AT_XDMAC_CHAN_IS_PAUSED, &atchan->status); |
|---|
| 1773 | 1813 | clear_bit(AT_XDMAC_CHAN_IS_CYCLIC, &atchan->status); |
|---|
| .. | .. |
|---|
| 1781 | 1821 | struct at_xdmac_chan *atchan = to_at_xdmac_chan(chan); |
|---|
| 1782 | 1822 | struct at_xdmac_desc *desc; |
|---|
| 1783 | 1823 | int i; |
|---|
| 1784 | | - unsigned long flags; |
|---|
| 1785 | | - |
|---|
| 1786 | | - spin_lock_irqsave(&atchan->lock, flags); |
|---|
| 1787 | 1824 | |
|---|
| 1788 | 1825 | if (at_xdmac_chan_is_enabled(atchan)) { |
|---|
| 1789 | 1826 | dev_err(chan2dev(chan), |
|---|
| 1790 | 1827 | "can't allocate channel resources (channel enabled)\n"); |
|---|
| 1791 | | - i = -EIO; |
|---|
| 1792 | | - goto spin_unlock; |
|---|
| 1828 | + return -EIO; |
|---|
| 1793 | 1829 | } |
|---|
| 1794 | 1830 | |
|---|
| 1795 | 1831 | if (!list_empty(&atchan->free_descs_list)) { |
|---|
| 1796 | 1832 | dev_err(chan2dev(chan), |
|---|
| 1797 | 1833 | "can't allocate channel resources (channel not free from a previous use)\n"); |
|---|
| 1798 | | - i = -EIO; |
|---|
| 1799 | | - goto spin_unlock; |
|---|
| 1834 | + return -EIO; |
|---|
| 1800 | 1835 | } |
|---|
| 1801 | 1836 | |
|---|
| 1802 | 1837 | for (i = 0; i < init_nr_desc_per_channel; i++) { |
|---|
| 1803 | | - desc = at_xdmac_alloc_desc(chan, GFP_ATOMIC); |
|---|
| 1838 | + desc = at_xdmac_alloc_desc(chan, GFP_KERNEL); |
|---|
| 1804 | 1839 | if (!desc) { |
|---|
| 1840 | + if (i == 0) { |
|---|
| 1841 | + dev_warn(chan2dev(chan), |
|---|
| 1842 | + "can't allocate any descriptors\n"); |
|---|
| 1843 | + return -EIO; |
|---|
| 1844 | + } |
|---|
| 1805 | 1845 | dev_warn(chan2dev(chan), |
|---|
| 1806 | 1846 | "only %d descriptors have been allocated\n", i); |
|---|
| 1807 | 1847 | break; |
|---|
| .. | .. |
|---|
| 1813 | 1853 | |
|---|
| 1814 | 1854 | dev_dbg(chan2dev(chan), "%s: allocated %d descriptors\n", __func__, i); |
|---|
| 1815 | 1855 | |
|---|
| 1816 | | -spin_unlock: |
|---|
| 1817 | | - spin_unlock_irqrestore(&atchan->lock, flags); |
|---|
| 1818 | 1856 | return i; |
|---|
| 1819 | 1857 | } |
|---|
| 1820 | 1858 | |
|---|
| .. | .. |
|---|
| 1871 | 1909 | } |
|---|
| 1872 | 1910 | } |
|---|
| 1873 | 1911 | atxdmac->save_gim = at_xdmac_read(atxdmac, AT_XDMAC_GIM); |
|---|
| 1912 | + atxdmac->save_gs = at_xdmac_read(atxdmac, AT_XDMAC_GS); |
|---|
| 1874 | 1913 | |
|---|
| 1875 | 1914 | at_xdmac_off(atxdmac); |
|---|
| 1876 | 1915 | clk_disable_unprepare(atxdmac->clk); |
|---|
| .. | .. |
|---|
| 1907 | 1946 | at_xdmac_chan_write(atchan, AT_XDMAC_CNDC, atchan->save_cndc); |
|---|
| 1908 | 1947 | at_xdmac_chan_write(atchan, AT_XDMAC_CIE, atchan->save_cim); |
|---|
| 1909 | 1948 | wmb(); |
|---|
| 1910 | | - at_xdmac_write(atxdmac, AT_XDMAC_GE, atchan->mask); |
|---|
| 1949 | + if (atxdmac->save_gs & atchan->mask) |
|---|
| 1950 | + at_xdmac_write(atxdmac, AT_XDMAC_GE, atchan->mask); |
|---|
| 1911 | 1951 | } |
|---|
| 1912 | 1952 | } |
|---|
| 1913 | 1953 | return 0; |
|---|
| .. | .. |
|---|
| 1916 | 1956 | |
|---|
| 1917 | 1957 | static int at_xdmac_probe(struct platform_device *pdev) |
|---|
| 1918 | 1958 | { |
|---|
| 1919 | | - struct resource *res; |
|---|
| 1920 | 1959 | struct at_xdmac *atxdmac; |
|---|
| 1921 | 1960 | int irq, size, nr_channels, i, ret; |
|---|
| 1922 | 1961 | void __iomem *base; |
|---|
| 1923 | 1962 | u32 reg; |
|---|
| 1924 | 1963 | |
|---|
| 1925 | | - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
|---|
| 1926 | | - if (!res) |
|---|
| 1927 | | - return -EINVAL; |
|---|
| 1928 | | - |
|---|
| 1929 | 1964 | irq = platform_get_irq(pdev, 0); |
|---|
| 1930 | 1965 | if (irq < 0) |
|---|
| 1931 | 1966 | return irq; |
|---|
| 1932 | 1967 | |
|---|
| 1933 | | - base = devm_ioremap_resource(&pdev->dev, res); |
|---|
| 1968 | + base = devm_platform_ioremap_resource(pdev, 0); |
|---|
| 1934 | 1969 | if (IS_ERR(base)) |
|---|
| 1935 | 1970 | return PTR_ERR(base); |
|---|
| 1936 | 1971 | |
|---|
| .. | .. |
|---|
| 2035 | 2070 | spin_lock_init(&atchan->lock); |
|---|
| 2036 | 2071 | INIT_LIST_HEAD(&atchan->xfers_list); |
|---|
| 2037 | 2072 | INIT_LIST_HEAD(&atchan->free_descs_list); |
|---|
| 2038 | | - tasklet_init(&atchan->tasklet, at_xdmac_tasklet, |
|---|
| 2039 | | - (unsigned long)atchan); |
|---|
| 2073 | + tasklet_setup(&atchan->tasklet, at_xdmac_tasklet); |
|---|
| 2040 | 2074 | |
|---|
| 2041 | 2075 | /* Clear pending interrupts. */ |
|---|
| 2042 | 2076 | while (at_xdmac_chan_read(atchan, AT_XDMAC_CIS)) |
|---|