diff options
author | John Crispin <john@openwrt.org> | 2016-02-25 10:14:05 +0000 |
---|---|---|
committer | John Crispin <john@openwrt.org> | 2016-02-25 10:14:05 +0000 |
commit | 0834f9f07631a8857a96614e37cb21e1dc84ffb4 (patch) | |
tree | c62e777de69d8397ed7870991bc46d5648a20046 /target/linux/brcm2708/patches-4.1/0076-bcm2835-sdhost-Improve-error-handling-and-recovery.patch | |
parent | b3dc9566a46efa67951ff6ae28e4397da9db92af (diff) | |
download | upstream-0834f9f07631a8857a96614e37cb21e1dc84ffb4.tar.gz upstream-0834f9f07631a8857a96614e37cb21e1dc84ffb4.tar.bz2 upstream-0834f9f07631a8857a96614e37cb21e1dc84ffb4.zip |
brcm2708: remove linux 4.1 support
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
SVN-Revision: 48766
Diffstat (limited to 'target/linux/brcm2708/patches-4.1/0076-bcm2835-sdhost-Improve-error-handling-and-recovery.patch')
-rw-r--r-- | target/linux/brcm2708/patches-4.1/0076-bcm2835-sdhost-Improve-error-handling-and-recovery.patch | 1088 |
1 files changed, 0 insertions, 1088 deletions
diff --git a/target/linux/brcm2708/patches-4.1/0076-bcm2835-sdhost-Improve-error-handling-and-recovery.patch b/target/linux/brcm2708/patches-4.1/0076-bcm2835-sdhost-Improve-error-handling-and-recovery.patch deleted file mode 100644 index 1c682f2e80..0000000000 --- a/target/linux/brcm2708/patches-4.1/0076-bcm2835-sdhost-Improve-error-handling-and-recovery.patch +++ /dev/null @@ -1,1088 +0,0 @@ -From aa9beb8d637dbe2509f9307cb5f7a809deb35e55 Mon Sep 17 00:00:00 2001 -From: Phil Elwell <phil@raspberrypi.org> -Date: Wed, 17 Jun 2015 11:36:53 +0100 -Subject: [PATCH 076/222] bcm2835-sdhost: Improve error handling and recovery - -1) Expose the hw_reset method to the MMC framework, removing many - internal calls by the driver. - -2) Reduce overclock setting on error. - -3) Increase timeout to cope with high capacity cards. - -4) Add properties and parameters to control pio_limit and debug. - -5) Reduce messages at probe time. ---- - arch/arm/boot/dts/overlays/README | 8 +- - arch/arm/boot/dts/overlays/sdhost-overlay.dts | 4 +- - drivers/mmc/host/bcm2835-sdhost.c | 578 ++++++++++++++++++-------- - 3 files changed, 404 insertions(+), 186 deletions(-) - ---- a/arch/arm/boot/dts/overlays/README -+++ b/arch/arm/boot/dts/overlays/README -@@ -408,7 +408,13 @@ Info: Selects the bcm2835-sdhost SD/MM - Load: dtoverlay=sdhost,<param>=<val> - Params: overclock_50 Clock (in MHz) to use when the MMC framework - requests 50MHz -- force_pio Disable DMA support -+ -+ force_pio Disable DMA support (default off) -+ -+ pio_limit Number of blocks above which to use DMA -+ (default 2) -+ -+ debug Enable debug output (default off) - - - Name: spi-bcm2708 ---- a/arch/arm/boot/dts/overlays/sdhost-overlay.dts -+++ b/arch/arm/boot/dts/overlays/sdhost-overlay.dts -@@ -22,6 +22,7 @@ - dma-names = "tx", "rx"; - brcm,delay-after-stop = <0>; - brcm,overclock-50 = <0>; -+ brcm,pio-limit = <2>; - status = "okay"; - }; - }; -@@ -70,9 +71,10 @@ - }; - - __overrides__ { -- delay_after_stop = <&sdhost>,"brcm,delay-after-stop:0"; - overclock_50 = <&sdhost>,"brcm,overclock-50:0"; - force_pio = <&sdhost>,"brcm,force-pio?"; -+ pio_limit = <&sdhost>,"brcm,pio-limit:0"; -+ debug = <&sdhost>,"brcm,debug?"; - sdhost_freq = <&clk_sdhost>,"clock-frequency:0"; - }; - }; ---- a/drivers/mmc/host/bcm2835-sdhost.c -+++ b/drivers/mmc/host/bcm2835-sdhost.c -@@ -90,9 +90,8 @@ - /* Reserved */ - #define SDHSTS_DATA_FLAG 0x01 - --#define SDHSTS_TRANSFER_ERROR_MASK (SDHSTS_CRC16_ERROR|SDHSTS_REW_TIME_OUT|SDHSTS_FIFO_ERROR) -+#define SDHSTS_TRANSFER_ERROR_MASK (SDHSTS_CRC7_ERROR|SDHSTS_CRC16_ERROR|SDHSTS_REW_TIME_OUT|SDHSTS_FIFO_ERROR) - #define SDHSTS_ERROR_MASK (SDHSTS_CMD_TIME_OUT|SDHSTS_TRANSFER_ERROR_MASK) --/* SDHSTS_CRC7_ERROR - ignore this as MMC cards generate this spuriously */ - - #define SDHCFG_BUSY_IRPT_EN (1<<10) - #define SDHCFG_BLOCK_IRPT_EN (1<<8) -@@ -111,16 +110,7 @@ - #define SDEDM_READ_THRESHOLD_SHIFT 14 - #define SDEDM_THRESHOLD_MASK 0x1f - --/* the inclusive limit in bytes under which PIO will be used instead of DMA */ --#ifdef CONFIG_MMC_BCM2835_SDHOST_PIO_DMA_BARRIER --#define PIO_DMA_BARRIER CONFIG_MMC_BCM2835_SDHOST_PIO_DMA_BARRIER --#else --#define PIO_DMA_BARRIER 0 --#endif -- --#define MIN_FREQ 400000 --#define TIMEOUT_VAL 0xE --#define BCM2835_SDHOST_WRITE_DELAY(f) (((2 * 1000000) / f) + 1) -+#define MHZ 1000000 - - #ifndef BCM2708_PERI_BASE - #define BCM2708_PERI_BASE 0x20000000 -@@ -138,19 +128,20 @@ struct bcm2835_host { - - struct mmc_host *mmc; - -- u32 timeout; -+ u32 pio_timeout; /* In jiffies */ - - int clock; /* Current clock speed */ - - bool slow_card; /* Force 11-bit divisor */ - - unsigned int max_clk; /* Max possible freq */ -- unsigned int timeout_clk; /* Timeout freq (KHz) */ - - struct tasklet_struct finish_tasklet; /* Tasklet structures */ - - struct timer_list timer; /* Timer for timeouts */ - -+ struct timer_list pio_timer; /* PIO error detection timer */ -+ - struct sg_mapping_iter sg_miter; /* SG state for PIO */ - unsigned int blocks; /* remaining PIO blocks */ - -@@ -170,6 +161,10 @@ struct bcm2835_host { - - unsigned int use_busy:1; /* Wait for busy interrupt */ - -+ unsigned int reduce_overclock:1; /* ...at the next opportunity */ -+ -+ unsigned int debug:1; /* Enable debug output */ -+ - u32 thread_isr; - - /*DMA part*/ -@@ -185,7 +180,8 @@ struct bcm2835_host { - struct timeval stop_time; /* when the last stop was issued */ - u32 delay_after_stop; /* minimum time between stop and subsequent data transfer */ - u32 overclock_50; /* frequency to use when 50MHz is requested (in MHz) */ -- u32 max_overclock; /* Highest reported */ -+ u32 overclock; /* Current frequency if overclocked, else zero */ -+ u32 pio_limit; /* Maximum block count for PIO (0 = always DMA) */ - }; - - -@@ -204,41 +200,79 @@ static inline u32 bcm2835_sdhost_read_re - return readl_relaxed(host->ioaddr + reg); - } - -+static void bcm2835_sdhost_dumpcmd(struct bcm2835_host *host, -+ struct mmc_command *cmd, -+ const char *label) -+{ -+ if (cmd) -+ pr_info("%s:%c%s op %d arg 0x%x flags 0x%x - resp %08x %08x %08x %08x, err %d\n", -+ mmc_hostname(host->mmc), -+ (cmd == host->cmd) ? '>' : ' ', -+ label, cmd->opcode, cmd->arg, cmd->flags, -+ cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3], -+ cmd->error); -+} -+ - static void bcm2835_sdhost_dumpregs(struct bcm2835_host *host) - { -- pr_info(DRIVER_NAME ": =========== REGISTER DUMP (%s)===========\n", -+ bcm2835_sdhost_dumpcmd(host, host->mrq->sbc, "sbc"); -+ bcm2835_sdhost_dumpcmd(host, host->mrq->cmd, "cmd"); -+ if (host->mrq->data) -+ pr_err("%s: data blocks %x blksz %x - err %d\n", -+ mmc_hostname(host->mmc), -+ host->mrq->data->blocks, -+ host->mrq->data->blksz, -+ host->mrq->data->error); -+ bcm2835_sdhost_dumpcmd(host, host->mrq->stop, "stop"); -+ -+ pr_info("%s: =========== REGISTER DUMP ===========\n", - mmc_hostname(host->mmc)); - -- pr_info(DRIVER_NAME ": SDCMD 0x%08x\n", -+ pr_info("%s: SDCMD 0x%08x\n", -+ mmc_hostname(host->mmc), - bcm2835_sdhost_read(host, SDCMD)); -- pr_info(DRIVER_NAME ": SDARG 0x%08x\n", -+ pr_info("%s: SDARG 0x%08x\n", -+ mmc_hostname(host->mmc), - bcm2835_sdhost_read(host, SDARG)); -- pr_info(DRIVER_NAME ": SDTOUT 0x%08x\n", -+ pr_info("%s: SDTOUT 0x%08x\n", -+ mmc_hostname(host->mmc), - bcm2835_sdhost_read(host, SDTOUT)); -- pr_info(DRIVER_NAME ": SDCDIV 0x%08x\n", -+ pr_info("%s: SDCDIV 0x%08x\n", -+ mmc_hostname(host->mmc), - bcm2835_sdhost_read(host, SDCDIV)); -- pr_info(DRIVER_NAME ": SDRSP0 0x%08x\n", -+ pr_info("%s: SDRSP0 0x%08x\n", -+ mmc_hostname(host->mmc), - bcm2835_sdhost_read(host, SDRSP0)); -- pr_info(DRIVER_NAME ": SDRSP1 0x%08x\n", -+ pr_info("%s: SDRSP1 0x%08x\n", -+ mmc_hostname(host->mmc), - bcm2835_sdhost_read(host, SDRSP1)); -- pr_info(DRIVER_NAME ": SDRSP2 0x%08x\n", -+ pr_info("%s: SDRSP2 0x%08x\n", -+ mmc_hostname(host->mmc), - bcm2835_sdhost_read(host, SDRSP2)); -- pr_info(DRIVER_NAME ": SDRSP3 0x%08x\n", -+ pr_info("%s: SDRSP3 0x%08x\n", -+ mmc_hostname(host->mmc), - bcm2835_sdhost_read(host, SDRSP3)); -- pr_info(DRIVER_NAME ": SDHSTS 0x%08x\n", -+ pr_info("%s: SDHSTS 0x%08x\n", -+ mmc_hostname(host->mmc), - bcm2835_sdhost_read(host, SDHSTS)); -- pr_info(DRIVER_NAME ": SDVDD 0x%08x\n", -+ pr_info("%s: SDVDD 0x%08x\n", -+ mmc_hostname(host->mmc), - bcm2835_sdhost_read(host, SDVDD)); -- pr_info(DRIVER_NAME ": SDEDM 0x%08x\n", -+ pr_info("%s: SDEDM 0x%08x\n", -+ mmc_hostname(host->mmc), - bcm2835_sdhost_read(host, SDEDM)); -- pr_info(DRIVER_NAME ": SDHCFG 0x%08x\n", -+ pr_info("%s: SDHCFG 0x%08x\n", -+ mmc_hostname(host->mmc), - bcm2835_sdhost_read(host, SDHCFG)); -- pr_info(DRIVER_NAME ": SDHBCT 0x%08x\n", -+ pr_info("%s: SDHBCT 0x%08x\n", -+ mmc_hostname(host->mmc), - bcm2835_sdhost_read(host, SDHBCT)); -- pr_info(DRIVER_NAME ": SDHBLC 0x%08x\n", -+ pr_info("%s: SDHBLC 0x%08x\n", -+ mmc_hostname(host->mmc), - bcm2835_sdhost_read(host, SDHBLC)); - -- pr_debug(DRIVER_NAME ": ===========================================\n"); -+ pr_info("%s: ===========================================\n", -+ mmc_hostname(host->mmc)); - } - - -@@ -248,12 +282,10 @@ static void bcm2835_sdhost_set_power(str - } - - --static void bcm2835_sdhost_reset(struct bcm2835_host *host) -+static void bcm2835_sdhost_reset_internal(struct bcm2835_host *host) - { - u32 temp; - -- pr_debug("bcm2835_sdhost_reset\n"); -- - bcm2835_sdhost_set_power(host, false); - - bcm2835_sdhost_write(host, 0, SDCMD); -@@ -281,6 +313,20 @@ static void bcm2835_sdhost_reset(struct - mmiowb(); - } - -+ -+static void bcm2835_sdhost_reset(struct mmc_host *mmc) -+{ -+ struct bcm2835_host *host = mmc_priv(mmc); -+ unsigned long flags; -+ if (host->debug) -+ pr_info("%s: reset\n", mmc_hostname(mmc)); -+ spin_lock_irqsave(&host->lock, flags); -+ -+ bcm2835_sdhost_reset_internal(host); -+ -+ spin_unlock_irqrestore(&host->lock, flags); -+} -+ - static void bcm2835_sdhost_set_ios(struct mmc_host *mmc, struct mmc_ios *ios); - - static void bcm2835_sdhost_init(struct bcm2835_host *host, int soft) -@@ -290,7 +336,7 @@ static void bcm2835_sdhost_init(struct b - /* Set interrupt enables */ - host->hcfg = SDHCFG_BUSY_IRPT_EN; - -- bcm2835_sdhost_reset(host); -+ bcm2835_sdhost_reset_internal(host); - - if (soft) { - /* force clock reconfiguration */ -@@ -420,6 +466,40 @@ static void bcm2835_sdhost_dma_complete( - spin_unlock_irqrestore(&host->lock, flags); - } - -+static bool data_transfer_wait(struct bcm2835_host *host, const char *caller) -+{ -+ unsigned long timeout = 1000000; -+ u32 hsts; -+ while (timeout) -+ { -+ hsts = bcm2835_sdhost_read(host, SDHSTS); -+ if (hsts & (SDHSTS_TRANSFER_ERROR_MASK | -+ SDHSTS_DATA_FLAG)) { -+ bcm2835_sdhost_write(host, SDHSTS_TRANSFER_ERROR_MASK, -+ SDHSTS); -+ break; -+ } -+ timeout--; -+ } -+ -+ if (hsts & (SDHSTS_CRC16_ERROR | -+ SDHSTS_CRC7_ERROR | -+ SDHSTS_FIFO_ERROR)) { -+ pr_err("%s: data error in %s - HSTS %x\n", -+ mmc_hostname(host->mmc), caller, hsts); -+ host->data->error = -EILSEQ; -+ return false; -+ } else if ((timeout == 0) || -+ (hsts & (SDHSTS_CMD_TIME_OUT | -+ SDHSTS_REW_TIME_OUT))) { -+ pr_err("%s: timeout in %s - HSTS %x\n", -+ mmc_hostname(host->mmc), caller, hsts); -+ host->data->error = -ETIMEDOUT; -+ return false; -+ } -+ return true; -+} -+ - static void bcm2835_sdhost_read_block_pio(struct bcm2835_host *host) - { - unsigned long flags; -@@ -443,35 +523,15 @@ static void bcm2835_sdhost_read_block_pi - buf = (u32 *)host->sg_miter.addr; - - while (len) { -- while (1) { -- u32 hsts; -- hsts = bcm2835_sdhost_read(host, SDHSTS); -- if (hsts & SDHSTS_DATA_FLAG) -- break; -- -- if (hsts & SDHSTS_ERROR_MASK) { -- pr_err("%s: Transfer error - HSTS %x, HBCT %x - %x left\n", -- mmc_hostname(host->mmc), -- hsts, -- bcm2835_sdhost_read(host, SDHBCT), -- blksize + len); -- if (hsts & SDHSTS_REW_TIME_OUT) -- host->data->error = -ETIMEDOUT; -- else if (hsts & (SDHSTS_CRC16_ERROR || -- SDHSTS_CRC7_ERROR)) -- host->data->error = -EILSEQ; -- else { -- pr_err("%s: unexpected data error\n", -- mmc_hostname(host->mmc)); -- bcm2835_sdhost_dumpregs(host); -- host->cmd->error = -EIO; -- } -- } -- } -+ if (!data_transfer_wait(host, "read_block_pio")) -+ break; - - *(buf++) = bcm2835_sdhost_read(host, SDDATA); - len -= 4; - } -+ -+ if (host->data->error) -+ break; - } - - sg_miter_stop(&host->sg_miter); -@@ -502,11 +562,15 @@ static void bcm2835_sdhost_write_block_p - buf = host->sg_miter.addr; - - while (len) { -- while (!(bcm2835_sdhost_read(host, SDHSTS) & SDHSTS_DATA_FLAG)) -- continue; -+ if (!data_transfer_wait(host, "write_block_pio")) -+ break; -+ - bcm2835_sdhost_write(host, *(buf++), SDDATA); - len -= 4; - } -+ -+ if (host->data->error) -+ break; - } - - sg_miter_stop(&host->sg_miter); -@@ -519,10 +583,15 @@ static void bcm2835_sdhost_transfer_pio( - { - BUG_ON(!host->data); - -- if (host->data->flags & MMC_DATA_READ) -+ if (host->data->flags & MMC_DATA_READ) { - bcm2835_sdhost_read_block_pio(host); -- else -+ } else { - bcm2835_sdhost_write_block_pio(host); -+ -+ /* Start a timer in case a transfer error occurs because -+ there is no error interrupt */ -+ mod_timer(&host->pio_timer, jiffies + host->pio_timeout); -+ } - } - - -@@ -607,6 +676,7 @@ static void bcm2835_sdhost_prepare_data( - host->flush_fifo = 0; - host->data->bytes_xfered = 0; - -+ host->use_dma = host->have_dma && (data->blocks > host->pio_limit); - if (!host->use_dma) { - int flags; - -@@ -619,8 +689,6 @@ static void bcm2835_sdhost_prepare_data( - host->blocks = data->blocks; - } - -- host->use_dma = host->have_dma && data->blocks > PIO_DMA_BARRIER; -- - bcm2835_sdhost_set_transfer_irqs(host); - - bcm2835_sdhost_write(host, data->blksz, SDHBCT); -@@ -638,22 +706,25 @@ void bcm2835_sdhost_send_command(struct - - WARN_ON(host->cmd); - -- if (1) { -- pr_debug("bcm2835_sdhost_send_command: %08x %08x (flags %x)\n", -- cmd->opcode, cmd->arg, (cmd->flags & 0xff) | (cmd->data ? cmd->data->flags : 0)); -- if (cmd->data) -- pr_debug("bcm2835_sdhost_send_command: %s %d*%x\n", -- (cmd->data->flags & MMC_DATA_READ) ? -- "read" : "write", cmd->data->blocks, -- cmd->data->blksz); -- } -+ if (cmd->data) -+ pr_debug("%s: send_command %d 0x%x " -+ "(flags 0x%x) - %s %d*%d\n", -+ mmc_hostname(host->mmc), -+ cmd->opcode, cmd->arg, cmd->flags, -+ (cmd->data->flags & MMC_DATA_READ) ? -+ "read" : "write", cmd->data->blocks, -+ cmd->data->blksz); -+ else -+ pr_debug("%s: send_command %d 0x%x (flags 0x%x)\n", -+ mmc_hostname(host->mmc), -+ cmd->opcode, cmd->arg, cmd->flags); - - /* Wait max 10 ms */ - timeout = 1000; - - while (bcm2835_sdhost_read(host, SDCMD) & SDCMD_NEW_FLAG) { - if (timeout == 0) { -- pr_err("%s: Previous command never completed.\n", -+ pr_err("%s: previous command never completed.\n", - mmc_hostname(host->mmc)); - bcm2835_sdhost_dumpregs(host); - cmd->error = -EIO; -@@ -666,16 +737,16 @@ void bcm2835_sdhost_send_command(struct - - if ((1000-timeout)/100 > 1 && (1000-timeout)/100 > host->max_delay) { - host->max_delay = (1000-timeout)/100; -- pr_warning("Warning: SDHost controller hung for %d ms\n", host->max_delay); -+ pr_warning("%s: controller hung for %d ms\n", -+ mmc_hostname(host->mmc), -+ host->max_delay); - } - - timeout = jiffies; --#ifdef CONFIG_ARCH_BCM2835 - if (!cmd->data && cmd->busy_timeout > 9000) - timeout += DIV_ROUND_UP(cmd->busy_timeout, 1000) * HZ + HZ; - else --#endif -- timeout += 10 * HZ; -+ timeout += 10 * HZ; - mod_timer(&host->timer, timeout); - - host->cmd = cmd; -@@ -685,7 +756,7 @@ void bcm2835_sdhost_send_command(struct - bcm2835_sdhost_write(host, cmd->arg, SDARG); - - if ((cmd->flags & MMC_RSP_136) && (cmd->flags & MMC_RSP_BUSY)) { -- pr_err("%s: Unsupported response type!\n", -+ pr_err("%s: unsupported response type!\n", - mmc_hostname(host->mmc)); - cmd->error = -EINVAL; - tasklet_schedule(&host->finish_tasklet); -@@ -783,13 +854,6 @@ static void bcm2835_sdhost_transfer_comp - pr_debug("transfer_complete(error %d, stop %d)\n", - data->error, data->stop ? 1 : 0); - -- if (data->error) -- /* -- * The controller needs a reset of internal state machines -- * upon error conditions. -- */ -- bcm2835_sdhost_reset(host); -- - /* - * Need to send CMD12 if - - * a) open-ended multiblock transfer (no CMD23) -@@ -845,7 +909,7 @@ static void bcm2835_sdhost_finish_comman - #endif - - if (timeout == 0) { -- pr_err("%s: Command never completed.\n", -+ pr_err("%s: command never completed.\n", - mmc_hostname(host->mmc)); - bcm2835_sdhost_dumpregs(host); - host->cmd->error = -EIO; -@@ -875,14 +939,23 @@ static void bcm2835_sdhost_finish_comman - { - u32 sdhsts = bcm2835_sdhost_read(host, SDHSTS); - -- pr_debug("%s: error detected - CMD %x, HSTS %03x, EDM %x\n", -- mmc_hostname(host->mmc), sdcmd, sdhsts, -- bcm2835_sdhost_read(host, SDEDM)); -- -- if (sdhsts & SDHSTS_CMD_TIME_OUT) -+ if (host->debug) -+ pr_info("%s: error detected - CMD %x, HSTS %03x, EDM %x\n", -+ mmc_hostname(host->mmc), sdcmd, sdhsts, -+ bcm2835_sdhost_read(host, SDEDM)); -+ -+ if (sdhsts & SDHSTS_CMD_TIME_OUT) { -+ switch (host->cmd->opcode) { -+ case 5: case 52: case 53: -+ /* Don't warn about SDIO commands */ -+ break; -+ default: -+ pr_err("%s: command timeout\n", -+ mmc_hostname(host->mmc)); -+ break; -+ } - host->cmd->error = -ETIMEDOUT; -- else -- { -+ } else { - pr_err("%s: unexpected command error\n", - mmc_hostname(host->mmc)); - bcm2835_sdhost_dumpregs(host); -@@ -897,11 +970,13 @@ static void bcm2835_sdhost_finish_comman - int i; - for (i = 0; i < 4; i++) - host->cmd->resp[3 - i] = bcm2835_sdhost_read(host, SDRSP0 + i*4); -- pr_debug("bcm2835_sdhost_finish_command: %08x %08x %08x %08x\n", -+ pr_debug("%s: finish_command %08x %08x %08x %08x\n", -+ mmc_hostname(host->mmc), - host->cmd->resp[0], host->cmd->resp[1], host->cmd->resp[2], host->cmd->resp[3]); - } else { - host->cmd->resp[0] = bcm2835_sdhost_read(host, SDRSP0); -- pr_debug("bcm2835_sdhost_finish_command: %08x\n", -+ pr_debug("%s: finish_command %08x\n", -+ mmc_hostname(host->mmc), - host->cmd->resp[0]); - } - } -@@ -932,7 +1007,7 @@ static void bcm2835_sdhost_finish_comman - } - } - --static void bcm2835_sdhost_timeout_timer(unsigned long data) -+static void bcm2835_sdhost_timeout(unsigned long data) - { - struct bcm2835_host *host; - unsigned long flags; -@@ -942,7 +1017,7 @@ static void bcm2835_sdhost_timeout_timer - spin_lock_irqsave(&host->lock, flags); - - if (host->mrq) { -- pr_err("%s: Timeout waiting for hardware interrupt.\n", -+ pr_err("%s: timeout waiting for hardware interrupt.\n", - mmc_hostname(host->mmc)); - bcm2835_sdhost_dumpregs(host); - -@@ -964,6 +1039,41 @@ static void bcm2835_sdhost_timeout_timer - spin_unlock_irqrestore(&host->lock, flags); - } - -+static void bcm2835_sdhost_pio_timeout(unsigned long data) -+{ -+ struct bcm2835_host *host; -+ unsigned long flags; -+ -+ host = (struct bcm2835_host *)data; -+ -+ spin_lock_irqsave(&host->lock, flags); -+ -+ if (host->data) { -+ u32 hsts = bcm2835_sdhost_read(host, SDHSTS); -+ -+ if (hsts & SDHSTS_REW_TIME_OUT) { -+ pr_err("%s: transfer timeout\n", -+ mmc_hostname(host->mmc)); -+ if (host->debug) -+ bcm2835_sdhost_dumpregs(host); -+ } else { -+ pr_err("%s: unexpected transfer timeout\n", -+ mmc_hostname(host->mmc)); -+ bcm2835_sdhost_dumpregs(host); -+ } -+ -+ bcm2835_sdhost_write(host, SDHSTS_TRANSFER_ERROR_MASK, -+ SDHSTS); -+ -+ host->data->error = -ETIMEDOUT; -+ -+ bcm2835_sdhost_finish_data(host); -+ } -+ -+ mmiowb(); -+ spin_unlock_irqrestore(&host->lock, flags); -+} -+ - static void bcm2835_sdhost_enable_sdio_irq_nolock(struct bcm2835_host *host, int enable) - { - if (enable) -@@ -979,7 +1089,7 @@ static void bcm2835_sdhost_enable_sdio_i - struct bcm2835_host *host = mmc_priv(mmc); - unsigned long flags; - -- pr_debug("bcm2835_sdhost_enable_sdio_irq(%d)\n", enable); -+ pr_debug("%s: enable_sdio_irq(%d)\n", mmc_hostname(mmc), enable); - spin_lock_irqsave(&host->lock, flags); - bcm2835_sdhost_enable_sdio_irq_nolock(host, enable); - spin_unlock_irqrestore(&host->lock, flags); -@@ -987,11 +1097,12 @@ static void bcm2835_sdhost_enable_sdio_i - - static u32 bcm2835_sdhost_busy_irq(struct bcm2835_host *host, u32 intmask) - { -- const u32 handled = (SDHSTS_CMD_TIME_OUT | SDHSTS_CRC16_ERROR | -- SDHSTS_CRC7_ERROR | SDHSTS_FIFO_ERROR); -+ const u32 handled = (SDHSTS_REW_TIME_OUT | SDHSTS_CMD_TIME_OUT | -+ SDHSTS_CRC16_ERROR | SDHSTS_CRC7_ERROR | -+ SDHSTS_FIFO_ERROR); - - if (!host->cmd) { -- pr_err("%s: Got command busy interrupt 0x%08x even " -+ pr_err("%s: got command busy interrupt 0x%08x even " - "though no command operation was in progress.\n", - mmc_hostname(host->mmc), (unsigned)intmask); - bcm2835_sdhost_dumpregs(host); -@@ -999,7 +1110,7 @@ static u32 bcm2835_sdhost_busy_irq(struc - } - - if (!host->use_busy) { -- pr_err("%s: Got command busy interrupt 0x%08x even " -+ pr_err("%s: got command busy interrupt 0x%08x even " - "though not expecting one.\n", - mmc_hostname(host->mmc), (unsigned)intmask); - bcm2835_sdhost_dumpregs(host); -@@ -1007,14 +1118,28 @@ static u32 bcm2835_sdhost_busy_irq(struc - } - host->use_busy = 0; - -- if (intmask & SDHSTS_CMD_TIME_OUT) -- host->cmd->error = -ETIMEDOUT; -- else if (intmask & (SDHSTS_CRC16_ERROR | SDHSTS_CRC7_ERROR | -- SDHSTS_FIFO_ERROR)) -- host->cmd->error = -EILSEQ; -+ if (intmask & SDHSTS_ERROR_MASK) -+ { -+ pr_err("sdhost_busy_irq: intmask %x, data %p\n", intmask, host->mrq->data); -+ if (intmask & SDHSTS_CRC7_ERROR) -+ host->cmd->error = -EILSEQ; -+ else if (intmask & (SDHSTS_CRC16_ERROR | -+ SDHSTS_FIFO_ERROR)) { -+ if (host->mrq->data) -+ host->mrq->data->error = -EILSEQ; -+ else -+ host->cmd->error = -EILSEQ; -+ } else if (intmask & SDHSTS_REW_TIME_OUT) { -+ if (host->mrq->data) -+ host->mrq->data->error = -ETIMEDOUT; -+ else -+ host->cmd->error = -ETIMEDOUT; -+ } else if (intmask & SDHSTS_CMD_TIME_OUT) -+ host->cmd->error = -ETIMEDOUT; - -- if (host->cmd->error) -+ bcm2835_sdhost_dumpregs(host); - tasklet_schedule(&host->finish_tasklet); -+ } - else - bcm2835_sdhost_finish_command(host); - -@@ -1023,8 +1148,9 @@ static u32 bcm2835_sdhost_busy_irq(struc - - static u32 bcm2835_sdhost_data_irq(struct bcm2835_host *host, u32 intmask) - { -- const u32 handled = (SDHSTS_CMD_TIME_OUT | SDHSTS_CRC16_ERROR | -- SDHSTS_CRC7_ERROR | SDHSTS_FIFO_ERROR); -+ const u32 handled = (SDHSTS_REW_TIME_OUT | -+ SDHSTS_CRC16_ERROR | -+ SDHSTS_FIFO_ERROR); - - /* There are no dedicated data/space available interrupt - status bits, so it is necessary to use the single shared -@@ -1034,13 +1160,19 @@ static u32 bcm2835_sdhost_data_irq(struc - if (!host->data) - return 0; - -- // XXX FIFO_ERROR -- if (intmask & SDHSTS_CMD_TIME_OUT) -- host->cmd->error = -ETIMEDOUT; -- else if ((intmask & (SDHSTS_CRC16_ERROR | SDHSTS_CRC7_ERROR)) && -- ((bcm2835_sdhost_read(host, SDCMD) & SDCMD_CMD_MASK) -- != MMC_BUS_TEST_R)) -- host->cmd->error = -EILSEQ; -+ if (intmask & (SDHSTS_CRC16_ERROR | -+ SDHSTS_FIFO_ERROR | -+ SDHSTS_REW_TIME_OUT)) { -+ if (intmask & (SDHSTS_CRC16_ERROR | -+ SDHSTS_FIFO_ERROR)) -+ host->data->error = -EILSEQ; -+ else -+ host->data->error = -ETIMEDOUT; -+ -+ bcm2835_sdhost_dumpregs(host); -+ tasklet_schedule(&host->finish_tasklet); -+ return handled; -+ } - - /* Use the block interrupt for writes after the first block */ - if (host->data->flags & MMC_DATA_WRITE) { -@@ -1067,31 +1199,48 @@ static u32 bcm2835_sdhost_block_irq(stru - { - struct dma_chan *dma_chan; - u32 dir_data; -- const u32 handled = (SDHSTS_CMD_TIME_OUT | SDHSTS_CRC16_ERROR | -- SDHSTS_CRC7_ERROR | SDHSTS_FIFO_ERROR); -+ const u32 handled = (SDHSTS_REW_TIME_OUT | -+ SDHSTS_CRC16_ERROR | -+ SDHSTS_FIFO_ERROR); - - if (!host->data) { -- pr_err("%s: Got block interrupt 0x%08x even " -+ pr_err("%s: got block interrupt 0x%08x even " - "though no data operation was in progress.\n", - mmc_hostname(host->mmc), (unsigned)intmask); - bcm2835_sdhost_dumpregs(host); - return handled; - } - -- if (intmask & SDHSTS_CMD_TIME_OUT) -- host->cmd->error = -ETIMEDOUT; -- else if ((intmask & (SDHSTS_CRC16_ERROR | SDHSTS_CRC7_ERROR)) && -- ((bcm2835_sdhost_read(host, SDCMD) & SDCMD_CMD_MASK) -- != MMC_BUS_TEST_R)) -- host->cmd->error = -EILSEQ; -+ if (intmask & (SDHSTS_CRC16_ERROR | -+ SDHSTS_FIFO_ERROR | -+ SDHSTS_REW_TIME_OUT)) { -+ if (intmask & (SDHSTS_CRC16_ERROR | -+ SDHSTS_FIFO_ERROR)) -+ host->data->error = -EILSEQ; -+ else -+ host->data->error = -ETIMEDOUT; -+ -+ if (host->debug) -+ bcm2835_sdhost_dumpregs(host); -+ tasklet_schedule(&host->finish_tasklet); -+ return handled; -+ } - - if (!host->use_dma) { - BUG_ON(!host->blocks); - host->blocks--; -- if ((host->blocks == 0) || host->data->error) -+ if ((host->blocks == 0) || host->data->error) { -+ /* Cancel the timer */ -+ del_timer(&host->pio_timer); -+ - bcm2835_sdhost_finish_data(host); -- else -+ } else { - bcm2835_sdhost_transfer_pio(host); -+ -+ /* Reset the timer */ -+ mod_timer(&host->pio_timer, -+ jiffies + host->pio_timeout); -+ } - } else if (host->data->flags & MMC_DATA_WRITE) { - dma_chan = host->dma_chan_tx; - dir_data = DMA_TO_DEVICE; -@@ -1125,7 +1274,7 @@ static irqreturn_t bcm2835_sdhost_irq(in - SDHSTS_BLOCK_IRPT | - SDHSTS_SDIO_IRPT | - SDHSTS_DATA_FLAG); -- if ((handled == SDHSTS_DATA_FLAG) && // XXX -+ if ((handled == SDHSTS_DATA_FLAG) && - (loops == 0) && !host->data) { - pr_err("%s: sdhost_irq data interrupt 0x%08x even " - "though no data operation was in progress.\n", -@@ -1177,10 +1326,11 @@ static irqreturn_t bcm2835_sdhost_irq(in - spin_unlock(&host->lock); - - if (early) -- pr_debug("%s: early %x (loops %d)\n", mmc_hostname(host->mmc), early, loops); -+ pr_debug("%s: early %x (loops %d)\n", -+ mmc_hostname(host->mmc), early, loops); - - if (unexpected) { -- pr_err("%s: Unexpected interrupt 0x%08x.\n", -+ pr_err("%s: unexpected interrupt 0x%08x.\n", - mmc_hostname(host->mmc), unexpected); - bcm2835_sdhost_dumpregs(host); - } -@@ -1227,8 +1377,22 @@ void bcm2835_sdhost_set_clock(struct bcm - int div = 0; /* Initialized for compiler warning */ - unsigned int input_clock = clock; - -- if (host->overclock_50 && (clock == 50000000)) -- clock = host->overclock_50 * 1000000 + 999999; -+ if (host->debug) -+ pr_info("%s: set_clock(%d)\n", mmc_hostname(host->mmc), clock); -+ -+ if ((clock == 0) && host->reduce_overclock) { -+ /* This is a reset following data corruption - reduce any -+ overclock */ -+ host->reduce_overclock = 0; -+ if (host->overclock_50 > 50) { -+ pr_warn("%s: reducing overclock due to errors\n", -+ mmc_hostname(host->mmc)); -+ host->overclock_50--; -+ } -+ } -+ -+ if (host->overclock_50 && (clock == 50*MHZ)) -+ clock = host->overclock_50 * MHZ + (MHZ - 1); - - /* The SDCDIV register has 11 bits, and holds (div - 2). - But in data mode the max is 50MHz wihout a minimum, and only the -@@ -1275,17 +1439,34 @@ void bcm2835_sdhost_set_clock(struct bcm - clock = host->max_clk / (div + 2); - host->mmc->actual_clock = clock; - -- if ((clock > input_clock) && (clock > host->max_overclock)) { -- pr_warn("%s: Overclocking to %dHz\n", -- mmc_hostname(host->mmc), clock); -- host->max_overclock = clock; -+ if (clock > input_clock) { -+ /* Save the closest value, to make it easier -+ to reduce in the event of error */ -+ host->overclock_50 = (clock/MHZ); -+ -+ if (clock != host->overclock) { -+ pr_warn("%s: overclocking to %dHz\n", -+ mmc_hostname(host->mmc), clock); -+ host->overclock = clock; -+ } -+ } -+ else if ((clock == 50 * MHZ) && host->overclock) -+ { -+ pr_warn("%s: cancelling overclock\n", -+ mmc_hostname(host->mmc)); -+ host->overclock = 0; - } - - host->cdiv = div; - bcm2835_sdhost_write(host, host->cdiv, SDCDIV); - -- pr_debug(DRIVER_NAME ": clock=%d -> max_clk=%d, cdiv=%x (actual clock %d)\n", -- input_clock, host->max_clk, host->cdiv, host->mmc->actual_clock); -+ /* Set the timeout to 500ms */ -+ bcm2835_sdhost_write(host, host->mmc->actual_clock/2, SDTOUT); -+ -+ if (host->debug) -+ pr_info("%s: clock=%d -> max_clk=%d, cdiv=%x (actual clock %d)\n", -+ mmc_hostname(host->mmc), input_clock, -+ host->max_clk, host->cdiv, host->mmc->actual_clock); - } - - static void bcm2835_sdhost_request(struct mmc_host *mmc, struct mmc_request *mrq) -@@ -1293,29 +1474,32 @@ static void bcm2835_sdhost_request(struc - struct bcm2835_host *host; - unsigned long flags; - -- if (1) { -+ host = mmc_priv(mmc); -+ -+ if (host->debug) { - struct mmc_command *cmd = mrq->cmd; -- const char *src = "cmd"; - BUG_ON(!cmd); -- pr_debug("bcm2835_sdhost_request: %s %08x %08x (flags %x)\n", -- src, cmd->opcode, cmd->arg, cmd->flags); - if (cmd->data) -- pr_debug("bcm2835_sdhost_request: %s %d*%d\n", -- (cmd->data->flags & MMC_DATA_READ) ? -- "read" : "write", cmd->data->blocks, -- cmd->data->blksz); -+ pr_info("%s: cmd %d 0x%x (flags 0x%x) - %s %d*%d\n", -+ mmc_hostname(mmc), -+ cmd->opcode, cmd->arg, cmd->flags, -+ (cmd->data->flags & MMC_DATA_READ) ? -+ "read" : "write", cmd->data->blocks, -+ cmd->data->blksz); -+ else -+ pr_info("%s: cmd %d 0x%x (flags 0x%x)\n", -+ mmc_hostname(mmc), -+ cmd->opcode, cmd->arg, cmd->flags); - } - - if (mrq->data && !is_power_of_2(mrq->data->blksz)) { -- pr_err("%s: Unsupported block size (%d bytes)\n", -+ pr_err("%s: unsupported block size (%d bytes)\n", - mmc_hostname(mmc), mrq->data->blksz); - mrq->cmd->error = -EINVAL; - mmc_request_done(mmc, mrq); - return; - } - -- host = mmc_priv(mmc); -- - spin_lock_irqsave(&host->lock, flags); - - WARN_ON(host->mrq != NULL); -@@ -1345,9 +1529,12 @@ static void bcm2835_sdhost_set_ios(struc - struct bcm2835_host *host = mmc_priv(mmc); - unsigned long flags; - -- pr_debug("bcm2835_sdhost_set_ios: clock %d, pwr %d, bus_width %d, timing %d, vdd %d, drv_type %d\n", -- ios->clock, ios->power_mode, ios->bus_width, -- ios->timing, ios->signal_voltage, ios->drv_type); -+ if (host->debug) -+ pr_info("%s: ios clock %d, pwr %d, bus_width %d, " -+ "timing %d, vdd %d, drv_type %d\n", -+ mmc_hostname(mmc), -+ ios->clock, ios->power_mode, ios->bus_width, -+ ios->timing, ios->signal_voltage, ios->drv_type); - - spin_lock_irqsave(&host->lock, flags); - -@@ -1396,6 +1583,7 @@ static struct mmc_host_ops bcm2835_sdhos - .request = bcm2835_sdhost_request, - .set_ios = bcm2835_sdhost_set_ios, - .enable_sdio_irq = bcm2835_sdhost_enable_sdio_irq, -+ .hw_reset = bcm2835_sdhost_reset, - .multi_io_quirk = bcm2835_sdhost_multi_io_quirk, - }; - -@@ -1423,15 +1611,24 @@ static void bcm2835_sdhost_tasklet_finis - - mrq = host->mrq; - -- /* -- * The controller needs a reset of internal state machines -- * upon error conditions. -- */ -- if (((mrq->cmd && mrq->cmd->error) || -- (mrq->data && (mrq->data->error || -- (mrq->data->stop && mrq->data->stop->error))))) { -+ /* Drop the overclock after any data corruption, or after any -+ error overclocked */ -+ if (mrq->data && (mrq->data->error == -EILSEQ)) -+ host->reduce_overclock = 1; -+ else if (host->overclock) { -+ /* Convert timeout errors while overclocked to data errors, -+ because the system recovers better. */ -+ if (mrq->cmd && mrq->cmd->error) { -+ host->reduce_overclock = 1; -+ if (mrq->cmd->error == -ETIMEDOUT) -+ mrq->cmd->error = -EILSEQ; -+ } - -- bcm2835_sdhost_reset(host); -+ if (mrq->data && mrq->data->error) { -+ host->reduce_overclock = 1; -+ if (mrq->data->error == -ETIMEDOUT) -+ mrq->data->error = -EILSEQ; -+ } - } - - host->mrq = NULL; -@@ -1450,35 +1647,37 @@ int bcm2835_sdhost_add_host(struct bcm28 - { - struct mmc_host *mmc; - struct dma_slave_config cfg; -+ char pio_limit_string[20]; - int ret; - - mmc = host->mmc; - -- bcm2835_sdhost_reset(host); -+ bcm2835_sdhost_reset_internal(host); - - mmc->f_max = host->max_clk; - mmc->f_min = host->max_clk / SDCDIV_MAX_CDIV; - -- /* SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK */ -- host->timeout_clk = mmc->f_max / 1000; --#ifdef CONFIG_ARCH_BCM2835 -- mmc->max_busy_timeout = (1 << 27) / host->timeout_clk; --#endif -+ mmc->max_busy_timeout = (~(unsigned int)0)/(mmc->f_max/1000); -+ -+ pr_debug("f_max %d, f_min %d, max_busy_timeout %d\n", -+ mmc->f_max, mmc->f_min, mmc->max_busy_timeout); -+ - /* host controller capabilities */ - mmc->caps |= /* MMC_CAP_SDIO_IRQ |*/ MMC_CAP_4_BIT_DATA | - MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED | -- MMC_CAP_NEEDS_POLL | -+ MMC_CAP_NEEDS_POLL | MMC_CAP_HW_RESET | - (ALLOW_CMD23 * MMC_CAP_CMD23); - - spin_lock_init(&host->lock); - - if (host->allow_dma) { -- if (!host->dma_chan_tx || !host->dma_chan_rx || -- IS_ERR(host->dma_chan_tx) || IS_ERR(host->dma_chan_rx)) { -- pr_err("%s: Unable to initialise DMA channels. Falling back to PIO\n", DRIVER_NAME); -+ if (IS_ERR_OR_NULL(host->dma_chan_tx) || -+ IS_ERR_OR_NULL(host->dma_chan_rx)) { -+ pr_err("%s: unable to initialise DMA channels. " -+ "Falling back to PIO\n", -+ mmc_hostname(mmc)); - host->have_dma = false; - } else { -- pr_info("DMA channels allocated for the SDHost driver"); - host->have_dma = true; - - cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; -@@ -1496,7 +1695,6 @@ int bcm2835_sdhost_add_host(struct bcm28 - ret = dmaengine_slave_config(host->dma_chan_rx, &cfg); - } - } else { -- pr_info("Forcing PIO mode\n"); - host->have_dma = false; - } - -@@ -1512,18 +1710,23 @@ int bcm2835_sdhost_add_host(struct bcm28 - tasklet_init(&host->finish_tasklet, - bcm2835_sdhost_tasklet_finish, (unsigned long)host); - -- setup_timer(&host->timer, bcm2835_sdhost_timeout_timer, (unsigned long)host); -+ setup_timer(&host->timer, bcm2835_sdhost_timeout, -+ (unsigned long)host); -+ -+ setup_timer(&host->pio_timer, bcm2835_sdhost_pio_timeout, -+ (unsigned long)host); - - bcm2835_sdhost_init(host, 0); - #ifndef CONFIG_ARCH_BCM2835 - ret = request_irq(host->irq, bcm2835_sdhost_irq, 0 /*IRQF_SHARED*/, - mmc_hostname(mmc), host); - #else -- ret = request_threaded_irq(host->irq, bcm2835_sdhost_irq, bcm2835_sdhost_thread_irq, -+ ret = request_threaded_irq(host->irq, bcm2835_sdhost_irq, -+ bcm2835_sdhost_thread_irq, - IRQF_SHARED, mmc_hostname(mmc), host); - #endif - if (ret) { -- pr_err("%s: Failed to request IRQ %d: %d\n", -+ pr_err("%s: failed to request IRQ %d: %d\n", - mmc_hostname(mmc), host->irq, ret); - goto untasklet; - } -@@ -1531,10 +1734,13 @@ int bcm2835_sdhost_add_host(struct bcm28 - mmiowb(); - mmc_add_host(mmc); - -- pr_info("Load BCM2835 SDHost driver\n"); -- if (host->delay_after_stop) -- pr_info("BCM2835 SDHost: delay_after_stop=%dus\n", -- host->delay_after_stop); -+ pio_limit_string[0] = '\0'; -+ if (host->have_dma && (host->pio_limit > 0)) -+ sprintf(pio_limit_string, " (>%d)", host->pio_limit); -+ pr_info("%s: %s loaded - DMA %s%s\n", -+ mmc_hostname(mmc), DRIVER_NAME, -+ host->have_dma ? "enabled" : "disabled", -+ pio_limit_string); - - return 0; - -@@ -1562,7 +1768,7 @@ static int bcm2835_sdhost_probe(struct p - mmc->ops = &bcm2835_sdhost_ops; - host = mmc_priv(mmc); - host->mmc = mmc; -- host->timeout = msecs_to_jiffies(1000); -+ host->pio_timeout = msecs_to_jiffies(500); - spin_lock_init(&host->lock); - - iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); -@@ -1588,8 +1794,12 @@ static int bcm2835_sdhost_probe(struct p - of_property_read_u32(node, - "brcm,overclock-50", - &host->overclock_50); -+ of_property_read_u32(node, -+ "brcm,pio-limit", -+ &host->pio_limit); - host->allow_dma = ALLOW_DMA && - !of_property_read_bool(node, "brcm,force-pio"); -+ host->debug = of_property_read_bool(node, "brcm,debug"); - } - - if (host->allow_dma) { |