Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mmc: dw_mmc: add quirk for broken data transfer over scheme

This patch add a new quirk to add a s/w timer to notify the driver
to terminate current transfer and report a data timeout to the core,
if DTO interrupt does NOT come within the given time.

dw_mmc call mmc_request_done func to finish transfer depends on
DTO interrupt. If DTO interrupt does not come in sending data state,
the current transfer will be blocked.

We got the reply from synopsys:
There are two counters but both use the same value of [31:8] bits.
Data timeout counter doesn't wait for stop clock and you should get
DRTO even when the clock is not stopped.
Host Starvation timeout counter is triggered with stop clock condition.

This means that host should get DRTO and DTO interrupt.

But this case really exists, when driver reads tuning data from
card on RK3288-pink2 board. I measured waveforms by oscilloscope
and found that card clock was always on and data lines were always
holded high level in sending data state.

There are two possibility that data over interrupt doesn't come in
reading data state on RK3X SoCs:
- get command done interrupt, but doesn't get any data-related interrupt.
- get data error interrupt, but doesn't get data over interrupt.

Signed-off-by: Addy Ke <addy.ke@rock-chips.com>
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
Signed-off-by: Jaehoon Chung <jh80.chung@samsung.com>

authored by

Addy Ke and committed by
Ulf Hansson
57e10486 40a7a463

+69 -2
+3
drivers/mmc/host/dw_mmc-rockchip.c
··· 73 73 /* It is slot 8 on Rockchip SoCs */ 74 74 host->sdio_id0 = 8; 75 75 76 + /* It needs this quirk on all Rockchip SoCs */ 77 + host->pdata->quirks |= DW_MCI_QUIRK_BROKEN_DTO; 78 + 76 79 return 0; 77 80 } 78 81
+62 -2
drivers/mmc/host/dw_mmc.c
··· 1574 1574 return data->error; 1575 1575 } 1576 1576 1577 + static void dw_mci_set_drto(struct dw_mci *host) 1578 + { 1579 + unsigned int drto_clks; 1580 + unsigned int drto_ms; 1581 + 1582 + drto_clks = mci_readl(host, TMOUT) >> 8; 1583 + drto_ms = DIV_ROUND_UP(drto_clks, host->bus_hz / 1000); 1584 + 1585 + /* add a bit spare time */ 1586 + drto_ms += 10; 1587 + 1588 + mod_timer(&host->dto_timer, jiffies + msecs_to_jiffies(drto_ms)); 1589 + } 1590 + 1577 1591 static void dw_mci_tasklet_func(unsigned long priv) 1578 1592 { 1579 1593 struct dw_mci *host = (struct dw_mci *)priv; ··· 1665 1651 } 1666 1652 1667 1653 if (!test_and_clear_bit(EVENT_XFER_COMPLETE, 1668 - &host->pending_events)) 1654 + &host->pending_events)) { 1655 + /* 1656 + * If all data-related interrupts don't come 1657 + * within the given time in reading data state. 1658 + */ 1659 + if ((host->quirks & DW_MCI_QUIRK_BROKEN_DTO) && 1660 + (host->dir_status == DW_MCI_RECV_STATUS)) 1661 + dw_mci_set_drto(host); 1669 1662 break; 1663 + } 1670 1664 1671 1665 set_bit(EVENT_XFER_COMPLETE, &host->completed_events); 1672 1666 ··· 1707 1685 1708 1686 case STATE_DATA_BUSY: 1709 1687 if (!test_and_clear_bit(EVENT_DATA_COMPLETE, 1710 - &host->pending_events)) 1688 + &host->pending_events)) { 1689 + /* 1690 + * If data error interrupt comes but data over 1691 + * interrupt doesn't come within the given time. 1692 + * in reading data state. 1693 + */ 1694 + if ((host->quirks & DW_MCI_QUIRK_BROKEN_DTO) && 1695 + (host->dir_status == DW_MCI_RECV_STATUS)) 1696 + dw_mci_set_drto(host); 1711 1697 break; 1698 + } 1712 1699 1713 1700 host->data = NULL; 1714 1701 set_bit(EVENT_DATA_COMPLETE, &host->completed_events); ··· 2290 2259 } 2291 2260 2292 2261 if (pending & SDMMC_INT_DATA_OVER) { 2262 + if (host->quirks & DW_MCI_QUIRK_BROKEN_DTO) 2263 + del_timer(&host->dto_timer); 2264 + 2293 2265 mci_writel(host, RINTSTS, SDMMC_INT_DATA_OVER); 2294 2266 if (!host->data_status) 2295 2267 host->data_status = pending; ··· 2678 2644 tasklet_schedule(&host->tasklet); 2679 2645 } 2680 2646 2647 + static void dw_mci_dto_timer(unsigned long arg) 2648 + { 2649 + struct dw_mci *host = (struct dw_mci *)arg; 2650 + 2651 + switch (host->state) { 2652 + case STATE_SENDING_DATA: 2653 + case STATE_DATA_BUSY: 2654 + /* 2655 + * If DTO interrupt does NOT come in sending data state, 2656 + * we should notify the driver to terminate current transfer 2657 + * and report a data timeout to the core. 2658 + */ 2659 + host->data_status = SDMMC_INT_DRTO; 2660 + set_bit(EVENT_DATA_ERROR, &host->pending_events); 2661 + set_bit(EVENT_DATA_COMPLETE, &host->pending_events); 2662 + tasklet_schedule(&host->tasklet); 2663 + break; 2664 + default: 2665 + break; 2666 + } 2667 + } 2668 + 2681 2669 #ifdef CONFIG_OF 2682 2670 static struct dw_mci_of_quirks { 2683 2671 char *quirk; ··· 2877 2821 dw_mci_cmd11_timer, (unsigned long)host); 2878 2822 2879 2823 host->quirks = host->pdata->quirks; 2824 + 2825 + if (host->quirks & DW_MCI_QUIRK_BROKEN_DTO) 2826 + setup_timer(&host->dto_timer, 2827 + dw_mci_dto_timer, (unsigned long)host); 2880 2828 2881 2829 spin_lock_init(&host->lock); 2882 2830 spin_lock_init(&host->irq_lock);
+4
include/linux/mmc/dw_mmc.h
··· 98 98 * @irq_flags: The flags to be passed to request_irq. 99 99 * @irq: The irq value to be passed to request_irq. 100 100 * @sdio_id0: Number of slot0 in the SDIO interrupt registers. 101 + * @dto_timer: Timer for broken data transfer over scheme. 101 102 * 102 103 * Locking 103 104 * ======= ··· 201 200 int sdio_id0; 202 201 203 202 struct timer_list cmd11_timer; 203 + struct timer_list dto_timer; 204 204 }; 205 205 206 206 /* DMA ops for Internal/External DMAC interface */ ··· 224 222 #define DW_MCI_QUIRK_HIGHSPEED BIT(2) 225 223 /* Unreliable card detection */ 226 224 #define DW_MCI_QUIRK_BROKEN_CARD_DETECTION BIT(3) 225 + /* Timer for broken data transfer over scheme */ 226 + #define DW_MCI_QUIRK_BROKEN_DTO BIT(4) 227 227 228 228 struct dma_pdata; 229 229