aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc/host/atmel-mci.c
diff options
context:
space:
mode:
authorLudovic Desroches <ludovic.desroches@atmel.com>2011-08-11 11:25:48 -0400
committerChris Ball <cjb@laptop.org>2011-10-26 15:43:26 -0400
commit7e8ba228d9f43a4e4b3ed0e6aa3399e8f30d7bc1 (patch)
treee6f437eef48a83bf36a8201dc803ab763193f574 /drivers/mmc/host/atmel-mci.c
parent341fa4c3affe1171005597847a86e4c26dea8bb1 (diff)
mmc: atmel-mci: fix a potential issue about pending PDC interrupts
This patch fixes a potential issue about PDC interrupts. For example we have a ENDRX pending interrupt and a RXBUFF pending interrupt. We have received the RXBUFF interrupt but the transfer is not finished (so we didn't have time to give a new buffer to the PDC controller). Then we will compute ENDRX interrupt and we will give a new buffer to the PDC controller, just after we will compute the RXBUFF interrupt and give one or two new buffers to the PDC controller but we are not sure that the first buffer given has been filled. So in this situation we may have "lost" one sg buffer. It's the same for transmission. Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com> Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> Signed-off-by: Chris Ball <cjb@laptop.org>
Diffstat (limited to 'drivers/mmc/host/atmel-mci.c')
-rw-r--r--drivers/mmc/host/atmel-mci.c32
1 files changed, 17 insertions, 15 deletions
diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
index 96004c9fe3a5..a7ee50271465 100644
--- a/drivers/mmc/host/atmel-mci.c
+++ b/drivers/mmc/host/atmel-mci.c
@@ -1729,17 +1729,9 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id)
1729 tasklet_schedule(&host->tasklet); 1729 tasklet_schedule(&host->tasklet);
1730 } 1730 }
1731 1731
1732 if (pending & ATMCI_ENDTX) {
1733 atmci_writel(host, ATMCI_IDR, ATMCI_ENDTX);
1734 if (host->data_size) {
1735 atmci_pdc_set_single_buf(host,
1736 XFER_TRANSMIT, PDC_SECOND_BUF);
1737 atmci_writel(host, ATMCI_IER, ATMCI_ENDTX);
1738 }
1739 }
1740
1741 if (pending & ATMCI_TXBUFE) { 1732 if (pending & ATMCI_TXBUFE) {
1742 atmci_writel(host, ATMCI_IDR, ATMCI_TXBUFE); 1733 atmci_writel(host, ATMCI_IDR, ATMCI_TXBUFE);
1734 atmci_writel(host, ATMCI_IDR, ATMCI_ENDTX);
1743 /* 1735 /*
1744 * We can receive this interruption before having configured 1736 * We can receive this interruption before having configured
1745 * the second pdc buffer, so we need to reconfigure first and 1737 * the second pdc buffer, so we need to reconfigure first and
@@ -1747,24 +1739,24 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id)
1747 */ 1739 */
1748 if (host->data_size) { 1740 if (host->data_size) {
1749 atmci_pdc_set_both_buf(host, XFER_TRANSMIT); 1741 atmci_pdc_set_both_buf(host, XFER_TRANSMIT);
1742 atmci_writel(host, ATMCI_IER, ATMCI_ENDTX);
1750 atmci_writel(host, ATMCI_IER, ATMCI_TXBUFE); 1743 atmci_writel(host, ATMCI_IER, ATMCI_TXBUFE);
1751 } else { 1744 } else {
1752 atmci_pdc_complete(host); 1745 atmci_pdc_complete(host);
1753 } 1746 }
1754 } 1747 } else if (pending & ATMCI_ENDTX) {
1755 1748 atmci_writel(host, ATMCI_IDR, ATMCI_ENDTX);
1756 if (pending & ATMCI_ENDRX) {
1757 atmci_writel(host, ATMCI_IDR, ATMCI_ENDRX);
1758 1749
1759 if (host->data_size) { 1750 if (host->data_size) {
1760 atmci_pdc_set_single_buf(host, 1751 atmci_pdc_set_single_buf(host,
1761 XFER_RECEIVE, PDC_SECOND_BUF); 1752 XFER_TRANSMIT, PDC_SECOND_BUF);
1762 atmci_writel(host, ATMCI_IER, ATMCI_ENDRX); 1753 atmci_writel(host, ATMCI_IER, ATMCI_ENDTX);
1763 } 1754 }
1764 } 1755 }
1765 1756
1766 if (pending & ATMCI_RXBUFF) { 1757 if (pending & ATMCI_RXBUFF) {
1767 atmci_writel(host, ATMCI_IDR, ATMCI_RXBUFF); 1758 atmci_writel(host, ATMCI_IDR, ATMCI_RXBUFF);
1759 atmci_writel(host, ATMCI_IDR, ATMCI_ENDRX);
1768 /* 1760 /*
1769 * We can receive this interruption before having configured 1761 * We can receive this interruption before having configured
1770 * the second pdc buffer, so we need to reconfigure first and 1762 * the second pdc buffer, so we need to reconfigure first and
@@ -1772,12 +1764,22 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id)
1772 */ 1764 */
1773 if (host->data_size) { 1765 if (host->data_size) {
1774 atmci_pdc_set_both_buf(host, XFER_RECEIVE); 1766 atmci_pdc_set_both_buf(host, XFER_RECEIVE);
1767 atmci_writel(host, ATMCI_IER, ATMCI_ENDRX);
1775 atmci_writel(host, ATMCI_IER, ATMCI_RXBUFF); 1768 atmci_writel(host, ATMCI_IER, ATMCI_RXBUFF);
1776 } else { 1769 } else {
1777 atmci_pdc_complete(host); 1770 atmci_pdc_complete(host);
1778 } 1771 }
1772 } else if (pending & ATMCI_ENDRX) {
1773 atmci_writel(host, ATMCI_IDR, ATMCI_ENDRX);
1774
1775 if (host->data_size) {
1776 atmci_pdc_set_single_buf(host,
1777 XFER_RECEIVE, PDC_SECOND_BUF);
1778 atmci_writel(host, ATMCI_IER, ATMCI_ENDRX);
1779 }
1779 } 1780 }
1780 1781
1782
1781 if (pending & ATMCI_NOTBUSY) { 1783 if (pending & ATMCI_NOTBUSY) {
1782 atmci_writel(host, ATMCI_IDR, 1784 atmci_writel(host, ATMCI_IDR,
1783 ATMCI_DATA_ERROR_FLAGS | ATMCI_NOTBUSY); 1785 ATMCI_DATA_ERROR_FLAGS | ATMCI_NOTBUSY);