From 7febd88f815cadf0cb2f73b4aa9ad78e8cf79e04 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Thu, 11 Feb 2016 16:51:01 +0000
Subject: [PATCH] bcm2835-sdhost: Major revision

This is a significant revision of the bcm2835-sdhost driver. It
improves on the original in a number of ways:

1) Through the use of CMD23 for reads it appears to avoid problems
   reading some sectors on certain high speed cards.
2) Better atomicity to prevent crashes.
3) Higher performance.
4) Activity logging included, for easier diagnosis in the event
   of a problem.

Signed-off-by: Phil Elwell <phil@raspberrypi.org>
---
 drivers/mmc/host/bcm2835-sdhost.c | 1284 ++++++++++++++++++++-----------------
 1 file changed, 686 insertions(+), 598 deletions(-)

--- a/drivers/mmc/host/bcm2835-sdhost.c
+++ b/drivers/mmc/host/bcm2835-sdhost.c
@@ -2,7 +2,7 @@
  * BCM2835 SD host driver.
  *
  * Author:      Phil Elwell <phil@raspberrypi.org>
- *              Copyright 2015
+ *              Copyright (C) 2015-2016 Raspberry Pi (Trading) Ltd.
  *
  * Based on
  *  mmc-bcm2835.c by Gellert Weisz
@@ -24,12 +24,13 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#define SAFE_READ_THRESHOLD     4
-#define SAFE_WRITE_THRESHOLD    4
-#define ALLOW_DMA               1
-#define ALLOW_CMD23             0
-#define ALLOW_FAST              1
-#define USE_BLOCK_IRQ           1
+#define FIFO_READ_THRESHOLD     4
+#define FIFO_WRITE_THRESHOLD    4
+#define ALLOW_CMD23_READ        1
+#define ALLOW_CMD23_WRITE       0
+#define ENABLE_LOG              1
+#define SDDATA_FIFO_PIO_BURST   8
+#define CMD_DALLY_US            1
 
 #include <linux/delay.h>
 #include <linux/module.h>
@@ -48,6 +49,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/of_dma.h>
 #include <linux/time.h>
+#include <linux/workqueue.h>
 
 #define DRIVER_NAME "sdhost-bcm2835"
 
@@ -110,6 +112,28 @@
 #define SDEDM_READ_THRESHOLD_SHIFT 14
 #define SDEDM_THRESHOLD_MASK     0x1f
 
+#define SDEDM_FSM_MASK           0xf
+#define SDEDM_FSM_IDENTMODE      0x0
+#define SDEDM_FSM_DATAMODE       0x1
+#define SDEDM_FSM_READDATA       0x2
+#define SDEDM_FSM_WRITEDATA      0x3
+#define SDEDM_FSM_READWAIT       0x4
+#define SDEDM_FSM_READCRC        0x5
+#define SDEDM_FSM_WRITECRC       0x6
+#define SDEDM_FSM_WRITEWAIT1     0x7
+#define SDEDM_FSM_POWERDOWN      0x8
+#define SDEDM_FSM_POWERUP        0x9
+#define SDEDM_FSM_WRITESTART1    0xa
+#define SDEDM_FSM_WRITESTART2    0xb
+#define SDEDM_FSM_GENPULSES      0xc
+#define SDEDM_FSM_WRITEWAIT2     0xd
+#define SDEDM_FSM_STARTPOWDOWN   0xf
+
+#define SDDATA_FIFO_WORDS        16
+
+#define USE_CMD23_FLAGS          ((ALLOW_CMD23_READ * MMC_DATA_READ) | \
+				  (ALLOW_CMD23_WRITE * MMC_DATA_WRITE))
+
 #define MHZ 1000000
 
 
@@ -131,15 +155,17 @@ struct bcm2835_host {
 
 	struct tasklet_struct	finish_tasklet;	/* Tasklet structures */
 
-	struct timer_list	timer;		/* Timer for timeouts */
+	struct work_struct	cmd_wait_wq;	/* Workqueue function */
 
-	struct timer_list	pio_timer;	/* PIO error detection timer */
+	struct timer_list	timer;		/* Timer for timeouts */
 
 	struct sg_mapping_iter	sg_miter;	/* SG state for PIO */
 	unsigned int		blocks;		/* remaining PIO blocks */
 
 	int			irq;		/* Device IRQ */
 
+	u32			cmd_quick_poll_retries;
+	u32			ns_per_fifo_word;
 
 	/* cached registers */
 	u32			hcfg;
@@ -154,16 +180,21 @@ struct bcm2835_host {
 
 	unsigned int			use_busy:1;		/* Wait for busy interrupt */
 
-	unsigned int			debug:1;		/* Enable debug output */
+	unsigned int			use_sbc:1;		/* Send CMD23 */
 
-	u32				thread_isr;
+	unsigned int			debug:1;		/* Enable debug output */
 
 	/*DMA part*/
 	struct dma_chan			*dma_chan_rx;		/* DMA channel for reads */
 	struct dma_chan			*dma_chan_tx;		/* DMA channel for writes */
+	struct dma_chan			*dma_chan;		/* Channel in used */
+	struct dma_async_tx_descriptor	*dma_desc;
+	u32				dma_dir;
+	u32				drain_words;
+	struct page 			*drain_page;
+	u32				drain_offset;
 
 	bool				allow_dma;
-	bool				have_dma;
 	bool				use_dma;
 	/*end of DMA part*/
 
@@ -173,13 +204,98 @@ struct bcm2835_host {
 	u32				overclock_50;	/* frequency to use when 50MHz is requested (in MHz) */
 	u32				overclock;	/* Current frequency if overclocked, else zero */
 	u32				pio_limit;	/* Maximum block count for PIO (0 = always DMA) */
+};
 
-	u32				debug_flags;
+#if ENABLE_LOG
 
-	u32				sectors;	/* Cached card size in sectors */
-	u32				single_read_sectors[8];
+struct log_entry_struct {
+	char event[4];
+	u32 timestamp;
+	u32 param1;
+	u32 param2;
 };
 
+typedef struct log_entry_struct LOG_ENTRY_T;
+
+LOG_ENTRY_T *sdhost_log_buf;
+dma_addr_t sdhost_log_addr;
+static u32 sdhost_log_idx;
+static spinlock_t log_lock;
+static void __iomem *timer_base;
+
+#define LOG_ENTRIES (256*1)
+#define LOG_SIZE (sizeof(LOG_ENTRY_T)*LOG_ENTRIES)
+
+static void log_init(u32 bus_to_phys)
+{
+	spin_lock_init(&log_lock);
+	sdhost_log_buf = dma_zalloc_coherent(NULL, LOG_SIZE, &sdhost_log_addr,
+					     GFP_KERNEL);
+	if (sdhost_log_buf) {
+		pr_err("sdhost: log_buf @ %p (%x)\n",
+		       sdhost_log_buf, sdhost_log_addr);
+		timer_base = ioremap_nocache(bus_to_phys + 0x7e003000, SZ_4K);
+		if (!timer_base)
+			pr_err("sdhost: failed to remap timer\n");
+	}
+	else
+		pr_err("sdhost: failed to allocate log buf\n");
+}
+
+static void log_event_impl(const char *event, u32 param1, u32 param2)
+{
+	if (sdhost_log_buf) {
+		LOG_ENTRY_T *entry;
+		unsigned long flags;
+
+		spin_lock_irqsave(&log_lock, flags);
+
+		entry = sdhost_log_buf + sdhost_log_idx;
+		memcpy(entry->event, event, 4);
+		entry->timestamp = (readl(timer_base + 4) & 0x3fffffff) +
+			(smp_processor_id()<<30);
+		entry->param1 = param1;
+		entry->param2 = param2;
+		sdhost_log_idx = (sdhost_log_idx + 1) % LOG_ENTRIES;
+
+		spin_unlock_irqrestore(&log_lock, flags);
+	}
+}
+
+static void log_dump(void)
+{
+	if (sdhost_log_buf) {
+		LOG_ENTRY_T *entry;
+		unsigned long flags;
+		int idx;
+
+		spin_lock_irqsave(&log_lock, flags);
+
+		idx = sdhost_log_idx;
+		do {
+			entry = sdhost_log_buf + idx;
+			if (entry->event[0] != '\0')
+				pr_err("[%08x] %.4s %x %x\n",
+				       entry->timestamp,
+				       entry->event,
+				       entry->param1,
+				       entry->param2);
+			idx = (idx + 1) % LOG_ENTRIES;
+		} while (idx != sdhost_log_idx);
+
+		spin_unlock_irqrestore(&log_lock, flags);
+	}
+}
+
+#define log_event(event, param1, param2) log_event_impl(event, param1, param2)
+
+#else
+
+#define log_init(x) (void)0
+#define log_event(event, param1, param2) (void)0
+#define log_dump() (void)0
+
+#endif
 
 static inline void bcm2835_sdhost_write(struct bcm2835_host *host, u32 val, int reg)
 {
@@ -201,7 +317,7 @@ static void bcm2835_sdhost_dumpcmd(struc
 				   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",
+		pr_err("%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,
@@ -211,73 +327,74 @@ static void bcm2835_sdhost_dumpcmd(struc
 
 static void bcm2835_sdhost_dumpregs(struct bcm2835_host *host)
 {
-	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");
+	if (host->mrq)
+	{
+		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",
+	pr_err("%s: =========== REGISTER DUMP ===========\n",
 		mmc_hostname(host->mmc));
 
-	pr_info("%s: SDCMD  0x%08x\n",
+	pr_err("%s: SDCMD  0x%08x\n",
 		mmc_hostname(host->mmc),
 		bcm2835_sdhost_read(host, SDCMD));
-	pr_info("%s: SDARG  0x%08x\n",
+	pr_err("%s: SDARG  0x%08x\n",
 		mmc_hostname(host->mmc),
 		bcm2835_sdhost_read(host, SDARG));
-	pr_info("%s: SDTOUT 0x%08x\n",
+	pr_err("%s: SDTOUT 0x%08x\n",
 		mmc_hostname(host->mmc),
 		bcm2835_sdhost_read(host, SDTOUT));
-	pr_info("%s: SDCDIV 0x%08x\n",
+	pr_err("%s: SDCDIV 0x%08x\n",
 		mmc_hostname(host->mmc),
 		bcm2835_sdhost_read(host, SDCDIV));
-	pr_info("%s: SDRSP0 0x%08x\n",
+	pr_err("%s: SDRSP0 0x%08x\n",
 		mmc_hostname(host->mmc),
 		bcm2835_sdhost_read(host, SDRSP0));
-	pr_info("%s: SDRSP1 0x%08x\n",
+	pr_err("%s: SDRSP1 0x%08x\n",
 		mmc_hostname(host->mmc),
 		bcm2835_sdhost_read(host, SDRSP1));
-	pr_info("%s: SDRSP2 0x%08x\n",
+	pr_err("%s: SDRSP2 0x%08x\n",
 		mmc_hostname(host->mmc),
 		bcm2835_sdhost_read(host, SDRSP2));
-	pr_info("%s: SDRSP3 0x%08x\n",
+	pr_err("%s: SDRSP3 0x%08x\n",
 		mmc_hostname(host->mmc),
 		bcm2835_sdhost_read(host, SDRSP3));
-	pr_info("%s: SDHSTS 0x%08x\n",
+	pr_err("%s: SDHSTS 0x%08x\n",
 		mmc_hostname(host->mmc),
 		bcm2835_sdhost_read(host, SDHSTS));
-	pr_info("%s: SDVDD  0x%08x\n",
+	pr_err("%s: SDVDD  0x%08x\n",
 		mmc_hostname(host->mmc),
 		bcm2835_sdhost_read(host, SDVDD));
-	pr_info("%s: SDEDM  0x%08x\n",
+	pr_err("%s: SDEDM  0x%08x\n",
 		mmc_hostname(host->mmc),
 		bcm2835_sdhost_read(host, SDEDM));
-	pr_info("%s: SDHCFG 0x%08x\n",
+	pr_err("%s: SDHCFG 0x%08x\n",
 		mmc_hostname(host->mmc),
 		bcm2835_sdhost_read(host, SDHCFG));
-	pr_info("%s: SDHBCT 0x%08x\n",
+	pr_err("%s: SDHBCT 0x%08x\n",
 		mmc_hostname(host->mmc),
 		bcm2835_sdhost_read(host, SDHBCT));
-	pr_info("%s: SDHBLC 0x%08x\n",
+	pr_err("%s: SDHBLC 0x%08x\n",
 		mmc_hostname(host->mmc),
 		bcm2835_sdhost_read(host, SDHBLC));
 
-	pr_info("%s: ===========================================\n",
+	pr_err("%s: ===========================================\n",
 		mmc_hostname(host->mmc));
 }
 
-
 static void bcm2835_sdhost_set_power(struct bcm2835_host *host, bool on)
 {
 	bcm2835_sdhost_write(host, on ? 1 : 0, SDVDD);
 }
 
-
 static void bcm2835_sdhost_reset_internal(struct bcm2835_host *host)
 {
 	u32 temp;
@@ -300,26 +417,24 @@ static void bcm2835_sdhost_reset_interna
 	temp = bcm2835_sdhost_read(host, SDEDM);
 	temp &= ~((SDEDM_THRESHOLD_MASK<<SDEDM_READ_THRESHOLD_SHIFT) |
 		  (SDEDM_THRESHOLD_MASK<<SDEDM_WRITE_THRESHOLD_SHIFT));
-	temp |= (SAFE_READ_THRESHOLD << SDEDM_READ_THRESHOLD_SHIFT) |
-		(SAFE_WRITE_THRESHOLD << SDEDM_WRITE_THRESHOLD_SHIFT);
+	temp |= (FIFO_READ_THRESHOLD << SDEDM_READ_THRESHOLD_SHIFT) |
+		(FIFO_WRITE_THRESHOLD << SDEDM_WRITE_THRESHOLD_SHIFT);
 	bcm2835_sdhost_write(host, temp, SDEDM);
 	mdelay(10);
 	bcm2835_sdhost_set_power(host, true);
 	mdelay(10);
 	host->clock = 0;
-	host->sectors = 0;
-	host->single_read_sectors[0] = ~0;
 	bcm2835_sdhost_write(host, host->hcfg, SDHCFG);
 	bcm2835_sdhost_write(host, host->cdiv, SDCDIV);
 	mmiowb();
 }
 
-
 static void bcm2835_sdhost_reset(struct mmc_host *mmc)
 {
 	struct bcm2835_host *host = mmc_priv(mmc);
 	unsigned long flags;
 	spin_lock_irqsave(&host->lock, flags);
+	log_event("RST<", 0, 0);
 
 	bcm2835_sdhost_reset_internal(host);
 
@@ -344,82 +459,48 @@ static void bcm2835_sdhost_init(struct b
 	}
 }
 
-static bool bcm2835_sdhost_is_write_complete(struct bcm2835_host *host)
+static void bcm2835_sdhost_wait_transfer_complete(struct bcm2835_host *host)
 {
-	bool write_complete = ((bcm2835_sdhost_read(host, SDEDM) & 0xf) == 1);
+	int timediff;
+	u32 alternate_idle;
+	u32 edm;
 
-	if (!write_complete) {
-		/* Request an IRQ for the last block */
-		host->hcfg |= SDHCFG_BLOCK_IRPT_EN;
-		bcm2835_sdhost_write(host, host->hcfg, SDHCFG);
-		if ((bcm2835_sdhost_read(host, SDEDM) & 0xf) == 1) {
-			/* The write has now completed. Disable the interrupt
-			   and clear the status flag */
-			host->hcfg &= ~SDHCFG_BLOCK_IRPT_EN;
-			bcm2835_sdhost_write(host, host->hcfg, SDHCFG);
-			bcm2835_sdhost_write(host, SDHSTS_BLOCK_IRPT, SDHSTS);
-			write_complete = true;
-		}
-	}
+	alternate_idle = (host->mrq->data->flags & MMC_DATA_READ) ?
+		SDEDM_FSM_READWAIT : SDEDM_FSM_WRITESTART1;
 
-	return write_complete;
-}
+	edm = bcm2835_sdhost_read(host, SDEDM);
 
-static void bcm2835_sdhost_wait_write_complete(struct bcm2835_host *host)
-{
-	int timediff;
-#ifdef DEBUG
-	static struct timeval start_time;
-	static int max_stall_time = 0;
-	static int total_stall_time = 0;
-	struct timeval before, after;
-
-	do_gettimeofday(&before);
-	if (max_stall_time == 0)
-		start_time = before;
-#endif
+	log_event("WTC<", edm, 0);
 
 	timediff = 0;
 
 	while (1) {
-		u32 edm = bcm2835_sdhost_read(host, SDEDM);
-		if ((edm & 0xf) == 1)
+		u32 fsm = edm & SDEDM_FSM_MASK;
+		if ((fsm == SDEDM_FSM_IDENTMODE) ||
+		    (fsm == SDEDM_FSM_DATAMODE))
 			break;
-		timediff++;
-		if (timediff > 5000000) {
-#ifdef DEBUG
-			do_gettimeofday(&after);
-			timediff = (after.tv_sec - before.tv_sec)*1000000 +
-				(after.tv_usec - before.tv_usec);
+		if (fsm == alternate_idle) {
+			bcm2835_sdhost_write(host,
+					     edm | SDEDM_FORCE_DATA_MODE,
+					     SDEDM);
+			break;
+		}
 
-			pr_err(" wait_write_complete - still waiting after %dus\n",
-			       timediff);
-#else
-			pr_err(" wait_write_complete - still waiting after %d retries\n",
+		timediff++;
+		if (timediff == 100000) {
+			pr_err("%s: wait_transfer_complete - still waiting after %d retries\n",
+			       mmc_hostname(host->mmc),
 			       timediff);
-#endif
+			log_dump();
 			bcm2835_sdhost_dumpregs(host);
-			host->data->error = -ETIMEDOUT;
+			host->mrq->data->error = -ETIMEDOUT;
+			log_event("WTC!", edm, 0);
 			return;
 		}
+		cpu_relax();
+		edm = bcm2835_sdhost_read(host, SDEDM);
 	}
-
-#ifdef DEBUG
-	do_gettimeofday(&after);
-	timediff = (after.tv_sec - before.tv_sec)*1000000 + (after.tv_usec - before.tv_usec);
-
-	total_stall_time += timediff;
-	if (timediff > max_stall_time)
-		max_stall_time = timediff;
-
-	if ((after.tv_sec - start_time.tv_sec) > 10) {
-		pr_debug(" wait_write_complete - max wait %dus, total %dus\n",
-			 max_stall_time, total_stall_time);
-		start_time = after;
-		max_stall_time = 0;
-		total_stall_time = 0;
-	}
-#endif
+	log_event("WTC>", edm, 0);
 }
 
 static void bcm2835_sdhost_finish_data(struct bcm2835_host *host);
@@ -427,65 +508,44 @@ static void bcm2835_sdhost_finish_data(s
 static void bcm2835_sdhost_dma_complete(void *param)
 {
 	struct bcm2835_host *host = param;
-	struct dma_chan *dma_chan;
+	struct mmc_data *data = host->data;
 	unsigned long flags;
-	u32 dir_data;
 
 	spin_lock_irqsave(&host->lock, flags);
+	log_event("DMA<", (u32)host->data, bcm2835_sdhost_read(host, SDHSTS));
+	log_event("DMA ", bcm2835_sdhost_read(host, SDCMD),
+		  bcm2835_sdhost_read(host, SDEDM));
 
-	if (host->data) {
-		bool write_complete;
-		if (USE_BLOCK_IRQ)
-			write_complete = bcm2835_sdhost_is_write_complete(host);
-		else {
-			bcm2835_sdhost_wait_write_complete(host);
-			write_complete = true;
-		}
-		pr_debug("dma_complete() - write_complete=%d\n",
-			 write_complete);
-
-		if (write_complete || (host->data->flags & MMC_DATA_READ))
-		{
-			if (write_complete) {
-				dma_chan = host->dma_chan_tx;
-				dir_data = DMA_TO_DEVICE;
-			} else {
-				dma_chan = host->dma_chan_rx;
-				dir_data = DMA_FROM_DEVICE;
-			}
-
-			dma_unmap_sg(dma_chan->device->dev,
-				     host->data->sg, host->data->sg_len,
-				     dir_data);
+	if (host->dma_chan) {
+		dma_unmap_sg(host->dma_chan->device->dev,
+			     data->sg, data->sg_len,
+			     host->dma_dir);
 
-			bcm2835_sdhost_finish_data(host);
-		}
+		host->dma_chan = NULL;
 	}
 
-	spin_unlock_irqrestore(&host->lock, flags);
-}
+	if (host->drain_words) {
+		void *page;
+		u32 *buf;
 
-static bool data_transfer_wait(struct bcm2835_host *host)
-{
-	unsigned long timeout = 1000000;
-	while (timeout)
-	{
-		u32 sdhsts = bcm2835_sdhost_read(host, SDHSTS);
-		if (sdhsts & SDHSTS_DATA_FLAG) {
-			bcm2835_sdhost_write(host, SDHSTS_DATA_FLAG, SDHSTS);
-			break;
+		page = kmap_atomic(host->drain_page);
+		buf = page + host->drain_offset;
+
+		while (host->drain_words) {
+			u32 edm = bcm2835_sdhost_read(host, SDEDM);
+			if ((edm >> 4) & 0x1f)
+				*(buf++) = bcm2835_sdhost_read(host,
+							       SDDATA);
+			host->drain_words--;
 		}
-		timeout--;
-	}
-	if (timeout == 0) {
-	    pr_err("%s: Data %s timeout\n",
-		   mmc_hostname(host->mmc),
-		   (host->data->flags & MMC_DATA_READ) ? "read" : "write");
-	    bcm2835_sdhost_dumpregs(host);
-	    host->data->error = -ETIMEDOUT;
-	    return false;
+
+		kunmap_atomic(page);
 	}
-	return true;
+
+	bcm2835_sdhost_finish_data(host);
+
+	log_event("DMA>", (u32)host->data, 0);
+	spin_unlock_irqrestore(&host->lock, flags);
 }
 
 static void bcm2835_sdhost_read_block_pio(struct bcm2835_host *host)
@@ -493,32 +553,83 @@ static void bcm2835_sdhost_read_block_pi
 	unsigned long flags;
 	size_t blksize, len;
 	u32 *buf;
+	unsigned long wait_max;
 
 	blksize = host->data->blksz;
 
+	wait_max = jiffies + msecs_to_jiffies(host->pio_timeout);
+
 	local_irq_save(flags);
 
 	while (blksize) {
-		if (!sg_miter_next(&host->sg_miter))
-			BUG();
+		int copy_words;
+		u32 hsts = 0;
+
+		if (!sg_miter_next(&host->sg_miter)) {
+			host->data->error = -EINVAL;
+			break;
+		}
 
 		len = min(host->sg_miter.length, blksize);
-		BUG_ON(len % 4);
+		if (len % 4) {
+			host->data->error = -EINVAL;
+			break;
+		}
 
 		blksize -= len;
 		host->sg_miter.consumed = len;
 
 		buf = (u32 *)host->sg_miter.addr;
 
-		while (len) {
-			if (!data_transfer_wait(host))
-				break;
+		copy_words = len/4;
+
+		while (copy_words) {
+			int burst_words, words;
+			u32 edm;
+
+			burst_words = SDDATA_FIFO_PIO_BURST;
+			if (burst_words > copy_words)
+				burst_words = copy_words;
+			edm = bcm2835_sdhost_read(host, SDEDM);
+			words = ((edm >> 4) & 0x1f);
+
+			if (words < burst_words) {
+				int fsm_state = (edm & SDEDM_FSM_MASK);
+				if ((fsm_state != SDEDM_FSM_READDATA) &&
+				    (fsm_state != SDEDM_FSM_READWAIT) &&
+				    (fsm_state != SDEDM_FSM_READCRC)) {
+					hsts = bcm2835_sdhost_read(host,
+								   SDHSTS);
+					pr_err("%s: fsm %x, hsts %x\n",
+					       mmc_hostname(host->mmc),
+					       fsm_state, hsts);
+					if (hsts & SDHSTS_ERROR_MASK)
+						break;
+				}
+
+				if (time_after(jiffies, wait_max)) {
+					pr_err("%s: PIO read timeout - EDM %x\n",
+					       mmc_hostname(host->mmc),
+					       edm);
+					hsts = SDHSTS_REW_TIME_OUT;
+					break;
+				}
+				ndelay((burst_words - words) *
+				       host->ns_per_fifo_word);
+				continue;
+			} else if (words > copy_words) {
+				words = copy_words;
+			}
+
+			copy_words -= words;
 
-			*(buf++) = bcm2835_sdhost_read(host, SDDATA);
-			len -= 4;
+			while (words) {
+				*(buf++) = bcm2835_sdhost_read(host, SDDATA);
+				words--;
+			}
 		}
 
-		if (host->data->error)
+		if (hsts & SDHSTS_ERROR_MASK)
 			break;
 	}
 
@@ -532,32 +643,83 @@ static void bcm2835_sdhost_write_block_p
 	unsigned long flags;
 	size_t blksize, len;
 	u32 *buf;
+	unsigned long wait_max;
 
 	blksize = host->data->blksz;
 
+	wait_max = jiffies + msecs_to_jiffies(host->pio_timeout);
+
 	local_irq_save(flags);
 
 	while (blksize) {
-		if (!sg_miter_next(&host->sg_miter))
-			BUG();
+		int copy_words;
+		u32 hsts = 0;
+
+		if (!sg_miter_next(&host->sg_miter)) {
+			host->data->error = -EINVAL;
+			break;
+		}
 
 		len = min(host->sg_miter.length, blksize);
-		BUG_ON(len % 4);
+		if (len % 4) {
+			host->data->error = -EINVAL;
+			break;
+		}
 
 		blksize -= len;
 		host->sg_miter.consumed = len;
 
-		buf = host->sg_miter.addr;
+		buf = (u32 *)host->sg_miter.addr;
 
-		while (len) {
-			if (!data_transfer_wait(host))
-				break;
+		copy_words = len/4;
+
+		while (copy_words) {
+			int burst_words, words;
+			u32 edm;
+
+			burst_words = SDDATA_FIFO_PIO_BURST;
+			if (burst_words > copy_words)
+				burst_words = copy_words;
+			edm = bcm2835_sdhost_read(host, SDEDM);
+			words = SDDATA_FIFO_WORDS - ((edm >> 4) & 0x1f);
+
+			if (words < burst_words) {
+				int fsm_state = (edm & SDEDM_FSM_MASK);
+				if ((fsm_state != SDEDM_FSM_WRITEDATA) &&
+				    (fsm_state != SDEDM_FSM_WRITESTART1) &&
+				    (fsm_state != SDEDM_FSM_WRITESTART2)) {
+					hsts = bcm2835_sdhost_read(host,
+								   SDHSTS);
+					pr_err("%s: fsm %x, hsts %x\n",
+					       mmc_hostname(host->mmc),
+					       fsm_state, hsts);
+					if (hsts & SDHSTS_ERROR_MASK)
+						break;
+				}
 
-			bcm2835_sdhost_write(host, *(buf++), SDDATA);
-			len -= 4;
+				if (time_after(jiffies, wait_max)) {
+					pr_err("%s: PIO write timeout - EDM %x\n",
+					       mmc_hostname(host->mmc),
+					       edm);
+					hsts = SDHSTS_REW_TIME_OUT;
+					break;
+				}
+				ndelay((burst_words - words) *
+				       host->ns_per_fifo_word);
+				continue;
+			} else if (words > copy_words) {
+				words = copy_words;
+			}
+
+			copy_words -= words;
+
+			while (words) {
+				bcm2835_sdhost_write(host, *(buf++), SDDATA);
+				words--;
+			}
 		}
 
-		if (host->data->error)
+		if (hsts & SDHSTS_ERROR_MASK)
 			break;
 	}
 
@@ -566,12 +728,12 @@ static void bcm2835_sdhost_write_block_p
 	local_irq_restore(flags);
 }
 
-
 static void bcm2835_sdhost_transfer_pio(struct bcm2835_host *host)
 {
 	u32 sdhsts;
 	bool is_read;
 	BUG_ON(!host->data);
+	log_event("XFP<", (u32)host->data, host->blocks);
 
 	is_read = (host->data->flags & MMC_DATA_READ) != 0;
 	if (is_read)
@@ -595,28 +757,21 @@ static void bcm2835_sdhost_transfer_pio(
 		       is_read ? "read" : "write",
 		       sdhsts);
 		host->data->error = -ETIMEDOUT;
-	} else if (!is_read && !host->data->error) {
-		/* Start a timer in case a transfer error occurs because
-		   there is no error interrupt */
-		mod_timer(&host->pio_timer, jiffies + host->pio_timeout);
 	}
+	log_event("XFP>", (u32)host->data, host->blocks);
 }
 
-
-static void bcm2835_sdhost_transfer_dma(struct bcm2835_host *host)
+static void bcm2835_sdhost_prepare_dma(struct bcm2835_host *host,
+	struct mmc_data *data)
 {
-	u32 len, dir_data, dir_slave;
+	int len, dir_data, dir_slave;
 	struct dma_async_tx_descriptor *desc = NULL;
 	struct dma_chan *dma_chan;
 
-	pr_debug("bcm2835_sdhost_transfer_dma()\n");
-
-	WARN_ON(!host->data);
+	log_event("PRD<", (u32)data, 0);
+	pr_debug("bcm2835_sdhost_prepare_dma()\n");
 
-	if (!host->data)
-		return;
-
-	if (host->data->flags & MMC_DATA_READ) {
+	if (data->flags & MMC_DATA_READ) {
 		dma_chan = host->dma_chan_rx;
 		dir_data = DMA_FROM_DEVICE;
 		dir_slave = DMA_DEV_TO_MEM;
@@ -625,35 +780,71 @@ static void bcm2835_sdhost_transfer_dma(
 		dir_data = DMA_TO_DEVICE;
 		dir_slave = DMA_MEM_TO_DEV;
 	}
+	log_event("PRD1", (u32)dma_chan, 0);
 
 	BUG_ON(!dma_chan->device);
 	BUG_ON(!dma_chan->device->dev);
-	BUG_ON(!host->data->sg);
+	BUG_ON(!data->sg);
 
-	len = dma_map_sg(dma_chan->device->dev, host->data->sg,
-			 host->data->sg_len, dir_data);
-	if (len > 0) {
-		desc = dmaengine_prep_slave_sg(dma_chan, host->data->sg,
+	/* The block doesn't manage the FIFO DREQs properly for multi-block
+	   transfers, so don't attempt to DMA the final few words.
+	   Unfortunately this requires the final sg entry to be trimmed.
+	   N.B. This code demands that the overspill is contained in
+	   a single sg entry.
+	*/
+
+	host->drain_words = 0;
+	if ((data->blocks > 1) && (dir_data == DMA_FROM_DEVICE)) {
+		struct scatterlist *sg;
+		u32 len;
+		int i;
+
+		len = min((u32)(FIFO_READ_THRESHOLD - 1) * 4,
+			  (u32)data->blocks * data->blksz);
+
+		for_each_sg(data->sg, sg, data->sg_len, i) {
+			if (sg_is_last(sg)) {
+				BUG_ON(sg->length < len);
+				sg->length -= len;
+				host->drain_page = (struct page *)sg->page_link;
+				host->drain_offset = sg->offset + sg->length;
+			}
+		}
+		host->drain_words = len/4;
+	}
+
+	len = dma_map_sg(dma_chan->device->dev, data->sg, data->sg_len,
+			 dir_data);
+
+	log_event("PRD2", len, 0);
+	if (len > 0)
+		desc = dmaengine_prep_slave_sg(dma_chan, data->sg,
 					       len, dir_slave,
 					       DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
-	} else {
-		dev_err(mmc_dev(host->mmc), "dma_map_sg returned zero length\n");
-	}
+	log_event("PRD3", (u32)desc, 0);
+
 	if (desc) {
 		desc->callback = bcm2835_sdhost_dma_complete;
 		desc->callback_param = host;
-		dmaengine_submit(desc);
-		dma_async_issue_pending(dma_chan);
+		host->dma_desc = desc;
+		host->dma_chan = dma_chan;
+		host->dma_dir = dir_data;
 	}
-
+	log_event("PDM>", (u32)data, 0);
 }
 
+static void bcm2835_sdhost_start_dma(struct bcm2835_host *host)
+{
+	log_event("SDMA", (u32)host->data, (u32)host->dma_chan);
+	dmaengine_submit(host->dma_desc);
+	dma_async_issue_pending(host->dma_chan);
+}
 
 static void bcm2835_sdhost_set_transfer_irqs(struct bcm2835_host *host)
 {
 	u32 all_irqs = SDHCFG_DATA_IRPT_EN | SDHCFG_BLOCK_IRPT_EN |
 		SDHCFG_BUSY_IRPT_EN;
-	if (host->use_dma)
+	if (host->dma_desc)
 		host->hcfg = (host->hcfg & ~all_irqs) |
 			SDHCFG_BUSY_IRPT_EN;
 	else
@@ -664,13 +855,13 @@ static void bcm2835_sdhost_set_transfer_
 	bcm2835_sdhost_write(host, host->hcfg, SDHCFG);
 }
 
-
 static void bcm2835_sdhost_prepare_data(struct bcm2835_host *host, struct mmc_command *cmd)
 {
 	struct mmc_data *data = cmd->data;
 
 	WARN_ON(host->data);
 
+	host->data = data;
 	if (!data)
 		return;
 
@@ -679,46 +870,19 @@ static void bcm2835_sdhost_prepare_data(
 	BUG_ON(data->blksz > host->mmc->max_blk_size);
 	BUG_ON(data->blocks > 65535);
 
-	host->data = data;
 	host->data_complete = 0;
 	host->flush_fifo = 0;
 	host->data->bytes_xfered = 0;
 
-	if (!host->sectors && host->mmc->card && !(host->debug_flags & 1))
-	{
-		struct mmc_card *card = host->mmc->card;
-		if (!mmc_card_sd(card) && mmc_card_blockaddr(card)) {
-			/*
-			 * The EXT_CSD sector count is in number of 512 byte
-			 * sectors.
-			 */
-			host->sectors = card->ext_csd.sectors;
-			pr_err("%s: using ext_csd!\n", mmc_hostname(host->mmc));
-		} else {
-			/*
-			 * The CSD capacity field is in units of read_blkbits.
-			 * set_capacity takes units of 512 bytes.
-			 */
-			host->sectors = card->csd.capacity <<
-				(card->csd.read_blkbits - 9);
-		}
-		host->single_read_sectors[0] = host->sectors - 65;
-		host->single_read_sectors[1] = host->sectors - 64;
-		host->single_read_sectors[2] = host->sectors - 33;
-		host->single_read_sectors[3] = host->sectors - 32;
-		host->single_read_sectors[4] = host->sectors - 1;
-		host->single_read_sectors[5] = ~0; /* Safety net */
-	}
 
-	host->use_dma = host->have_dma && (data->blocks > host->pio_limit);
-	if (!host->use_dma) {
+	if (!host->dma_desc) {
+		/* Use PIO */
 		int flags;
 
-		flags = SG_MITER_ATOMIC;
 		if (data->flags & MMC_DATA_READ)
-			flags |= SG_MITER_TO_SG;
+			flags = SG_MITER_TO_SG;
 		else
-			flags |= SG_MITER_FROM_SG;
+			flags = SG_MITER_FROM_SG;
 		sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags);
 		host->blocks = data->blocks;
 	}
@@ -726,19 +890,20 @@ static void bcm2835_sdhost_prepare_data(
 	bcm2835_sdhost_set_transfer_irqs(host);
 
 	bcm2835_sdhost_write(host, data->blksz, SDHBCT);
-	bcm2835_sdhost_write(host, host->use_dma ? data->blocks : 0, SDHBLC);
+	bcm2835_sdhost_write(host, data->blocks, SDHBLC);
 
 	BUG_ON(!host->data);
 }
 
-
-void bcm2835_sdhost_send_command(struct bcm2835_host *host, struct mmc_command *cmd)
+bool bcm2835_sdhost_send_command(struct bcm2835_host *host,
+				 struct mmc_command *cmd)
 {
 	u32 sdcmd, sdhsts;
 	unsigned long timeout;
 	int delay;
 
 	WARN_ON(host->cmd);
+	log_event("CMD<", cmd->opcode, cmd->arg);
 
 	if (cmd->data)
 		pr_debug("%s: send_command %d 0x%x "
@@ -761,9 +926,9 @@ void bcm2835_sdhost_send_command(struct
 			pr_err("%s: previous command never completed.\n",
 				mmc_hostname(host->mmc));
 			bcm2835_sdhost_dumpregs(host);
-			cmd->error = -EIO;
+			cmd->error = -EILSEQ;
 			tasklet_schedule(&host->finish_tasklet);
-			return;
+			return false;
 		}
 		timeout--;
 		udelay(10);
@@ -791,23 +956,24 @@ void bcm2835_sdhost_send_command(struct
 	if (sdhsts & SDHSTS_ERROR_MASK)
 		bcm2835_sdhost_write(host, sdhsts, SDHSTS);
 
-	bcm2835_sdhost_prepare_data(host, cmd);
-
-	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",
 			mmc_hostname(host->mmc));
 		cmd->error = -EINVAL;
 		tasklet_schedule(&host->finish_tasklet);
-		return;
+		return false;
 	}
 
+	bcm2835_sdhost_prepare_data(host, cmd);
+
+	bcm2835_sdhost_write(host, cmd->arg, SDARG);
+
 	sdcmd = cmd->opcode & SDCMD_CMD_MASK;
 
-	if (!(cmd->flags & MMC_RSP_PRESENT))
+	host->use_busy = 0;
+	if (!(cmd->flags & MMC_RSP_PRESENT)) {
 		sdcmd |= SDCMD_NO_RESPONSE;
-	else {
+	} else {
 		if (cmd->flags & MMC_RSP_136)
 			sdcmd |= SDCMD_LONG_RESPONSE;
 		if (cmd->flags & MMC_RSP_BUSY) {
@@ -817,6 +983,7 @@ void bcm2835_sdhost_send_command(struct
 	}
 
 	if (cmd->data) {
+		log_event("CMDD", cmd->data->blocks, cmd->data->blksz);
 		if (host->delay_after_stop) {
 			struct timeval now;
 			int time_since_stop;
@@ -839,10 +1006,12 @@ void bcm2835_sdhost_send_command(struct
 	}
 
 	bcm2835_sdhost_write(host, sdcmd | SDCMD_NEW_FLAG, SDCMD);
-}
 
+	return true;
+}
 
-static void bcm2835_sdhost_finish_command(struct bcm2835_host *host);
+static void bcm2835_sdhost_finish_command(struct bcm2835_host *host,
+					  unsigned long *irq_flags);
 static void bcm2835_sdhost_transfer_complete(struct bcm2835_host *host);
 
 static void bcm2835_sdhost_finish_data(struct bcm2835_host *host)
@@ -852,6 +1021,7 @@ static void bcm2835_sdhost_finish_data(s
 	data = host->data;
 	BUG_ON(!data);
 
+	log_event("FDA<", (u32)host->mrq, (u32)host->cmd);
 	pr_debug("finish_data(error %d, stop %d, sbc %d)\n",
 	       data->error, data->stop ? 1 : 0,
 	       host->mrq->sbc ? 1 : 0);
@@ -859,10 +1029,7 @@ static void bcm2835_sdhost_finish_data(s
 	host->hcfg &= ~(SDHCFG_DATA_IRPT_EN | SDHCFG_BLOCK_IRPT_EN);
 	bcm2835_sdhost_write(host, host->hcfg, SDHCFG);
 
-	if (data->error) {
-		data->bytes_xfered = 0;
-	} else
-		data->bytes_xfered = data->blksz * data->blocks;
+	data->bytes_xfered = data->error ? 0 : (data->blksz * data->blocks);
 
 	host->data_complete = 1;
 
@@ -877,9 +1044,9 @@ static void bcm2835_sdhost_finish_data(s
 	}
 	else
 		bcm2835_sdhost_transfer_complete(host);
+	log_event("FDA>", (u32)host->mrq, (u32)host->cmd);
 }
 
-
 static void bcm2835_sdhost_transfer_complete(struct bcm2835_host *host)
 {
 	struct mmc_data *data;
@@ -891,6 +1058,7 @@ static void bcm2835_sdhost_transfer_comp
 	data = host->data;
 	host->data = NULL;
 
+	log_event("TCM<", (u32)data, data->error);
 	pr_debug("transfer_complete(error %d, stop %d)\n",
 	       data->error, data->stop ? 1 : 0);
 
@@ -899,88 +1067,114 @@ static void bcm2835_sdhost_transfer_comp
 	 * a) open-ended multiblock transfer (no CMD23)
 	 * b) error in multiblock transfer
 	 */
-	if (data->stop &&
-	    (data->error ||
-	     !host->mrq->sbc)) {
-		host->flush_fifo = 1;
-		bcm2835_sdhost_send_command(host, data->stop);
-		if (host->delay_after_stop)
-			do_gettimeofday(&host->stop_time);
-		if (!host->use_busy)
-			bcm2835_sdhost_finish_command(host);
+	if (host->mrq->stop && (data->error || !host->use_sbc)) {
+		if (bcm2835_sdhost_send_command(host, host->mrq->stop)) {
+			/* No busy, so poll for completion */
+			if (!host->use_busy)
+				bcm2835_sdhost_finish_command(host, NULL);
+
+			if (host->delay_after_stop)
+				do_gettimeofday(&host->stop_time);
+		}
 	} else {
+		bcm2835_sdhost_wait_transfer_complete(host);
 		tasklet_schedule(&host->finish_tasklet);
 	}
+	log_event("TCM>", (u32)data, 0);
 }
 
-static void bcm2835_sdhost_finish_command(struct bcm2835_host *host)
+/* If irq_flags is valid, the caller is in a thread context and is allowed
+   to sleep */
+static void bcm2835_sdhost_finish_command(struct bcm2835_host *host,
+					  unsigned long *irq_flags)
 {
 	u32 sdcmd;
-	unsigned long timeout;
+	u32 retries;
 #ifdef DEBUG
 	struct timeval before, after;
 	int timediff = 0;
 #endif
 
+	log_event("FCM<", (u32)host->mrq, (u32)host->cmd);
 	pr_debug("finish_command(%x)\n", bcm2835_sdhost_read(host, SDCMD));
 
 	BUG_ON(!host->cmd || !host->mrq);
 
-#ifdef DEBUG
-	do_gettimeofday(&before);
-#endif
-	/* Wait max 100 ms */
-	timeout = 10000;
+	/* Poll quickly at first */
+
+	retries = host->cmd_quick_poll_retries;
+	if (!retries) {
+		/* Work out how many polls take 1us by timing 10us */
+		struct timeval start, now;
+		int us_diff;
+
+		retries = 1;
+		do {
+			int i;
+
+			retries *= 2;
+
+			do_gettimeofday(&start);
+
+			for (i = 0; i < retries; i++) {
+				cpu_relax();
+				sdcmd = bcm2835_sdhost_read(host, SDCMD);
+			}
+
+			do_gettimeofday(&now);
+			us_diff = (now.tv_sec - start.tv_sec) * 1000000 +
+				(now.tv_usec - start.tv_usec);
+		} while (us_diff < 10);
+
+		host->cmd_quick_poll_retries = ((retries * us_diff + 9)*CMD_DALLY_US)/10 + 1;
+		retries = 1; // We've already waited long enough this time
+	}
+
+	retries = host->cmd_quick_poll_retries;
 	for (sdcmd = bcm2835_sdhost_read(host, SDCMD);
-	     (sdcmd & SDCMD_NEW_FLAG) && timeout;
-	     timeout--) {
-		if (host->flush_fifo) {
-			while (bcm2835_sdhost_read(host, SDHSTS) &
-			       SDHSTS_DATA_FLAG)
-				(void)bcm2835_sdhost_read(host, SDDATA);
-		}
-		udelay(10);
+	     (sdcmd & SDCMD_NEW_FLAG) && !(sdcmd & SDCMD_FAIL_FLAG) && retries;
+	     retries--) {
+		cpu_relax();
 		sdcmd = bcm2835_sdhost_read(host, SDCMD);
 	}
-#ifdef DEBUG
-	do_gettimeofday(&after);
-	timediff = (after.tv_sec - before.tv_sec)*1000000 +
-		(after.tv_usec - before.tv_usec);
 
-	pr_debug(" finish_command - waited %dus\n", timediff);
-#endif
+	if (!retries) {
+		unsigned long wait_max;
+
+		if (!irq_flags) {
+			/* Schedule the work */
+			log_event("CWWQ", 0, 0);
+			schedule_work(&host->cmd_wait_wq);
+			return;
+		}
+
+		/* Wait max 100 ms */
+		wait_max = jiffies + msecs_to_jiffies(100);
+		while (time_before(jiffies, wait_max)) {
+			spin_unlock_irqrestore(&host->lock, *irq_flags);
+			usleep_range(1, 10);
+			spin_lock_irqsave(&host->lock, *irq_flags);
+			sdcmd = bcm2835_sdhost_read(host, SDCMD);
+			if (!(sdcmd & SDCMD_NEW_FLAG) ||
+			    (sdcmd & SDCMD_FAIL_FLAG))
+				break;
+		}
+	}
 
-	if (timeout == 0) {
+	/* Check for errors */
+	if (sdcmd & SDCMD_NEW_FLAG) {
 		pr_err("%s: command never completed.\n",
 		       mmc_hostname(host->mmc));
 		bcm2835_sdhost_dumpregs(host);
 		host->cmd->error = -EIO;
 		tasklet_schedule(&host->finish_tasklet);
 		return;
-	}
-
-	if (host->flush_fifo) {
-		for (timeout = 100;
-		     (bcm2835_sdhost_read(host, SDHSTS) & SDHSTS_DATA_FLAG) && timeout;
-		     timeout--) {
-			(void)bcm2835_sdhost_read(host, SDDATA);
-		}
-		host->flush_fifo = 0;
-		if (timeout == 0) {
-			pr_err("%s: FIFO never drained.\n",
-			       mmc_hostname(host->mmc));
-			bcm2835_sdhost_dumpregs(host);
-			host->cmd->error = -EIO;
-			tasklet_schedule(&host->finish_tasklet);
-			return;
-		}
-	}
-
-	/* Check for errors */
-	if (sdcmd & SDCMD_FAIL_FLAG)
-	{
+	} else if (sdcmd & SDCMD_FAIL_FLAG) {
 		u32 sdhsts = bcm2835_sdhost_read(host, SDHSTS);
 
+		/* Clear the errors */
+		bcm2835_sdhost_write(host, SDHSTS_ERROR_MASK, SDHSTS);
+
 		if (host->debug)
 			pr_info("%s: error detected - CMD %x, HSTS %03x, EDM %x\n",
 				mmc_hostname(host->mmc), sdcmd, sdhsts,
@@ -1003,7 +1197,7 @@ static void bcm2835_sdhost_finish_comman
 				       mmc_hostname(host->mmc),
 				       host->cmd->opcode);
 				bcm2835_sdhost_dumpregs(host);
-				host->cmd->error = -EIO;
+				host->cmd->error = -EILSEQ;
 			}
 			tasklet_schedule(&host->finish_tasklet);
 			return;
@@ -1018,31 +1212,31 @@ static void bcm2835_sdhost_finish_comman
 			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]);
+			log_event("RSP ", host->cmd->resp[0], host->cmd->resp[1]);
 		} else {
 			host->cmd->resp[0] = bcm2835_sdhost_read(host, SDRSP0);
 			pr_debug("%s: finish_command %08x\n",
 				 mmc_hostname(host->mmc),
 				 host->cmd->resp[0]);
+			log_event("RSP ", host->cmd->resp[0], 0);
 		}
 	}
 
-	host->cmd->error = 0;
-
 	if (host->cmd == host->mrq->sbc) {
 		/* Finished CMD23, now send actual command. */
 		host->cmd = NULL;
-		bcm2835_sdhost_send_command(host, host->mrq->cmd);
+		if (bcm2835_sdhost_send_command(host, host->mrq->cmd)) {
+			if (host->data && host->dma_desc)
+				/* DMA transfer starts now, PIO starts after irq */
+				bcm2835_sdhost_start_dma(host);
 
-		if (host->cmd->data && host->use_dma)
-			/* DMA transfer starts now, PIO starts after irq */
-			bcm2835_sdhost_transfer_dma(host);
-
-		if (!host->use_busy)
-			bcm2835_sdhost_finish_command(host);
-	} else if (host->cmd == host->mrq->stop)
+			if (!host->use_busy)
+				bcm2835_sdhost_finish_command(host, NULL);
+		}
+	} else if (host->cmd == host->mrq->stop) {
 		/* Finished CMD12 */
 		tasklet_schedule(&host->finish_tasklet);
-	else {
+	} else {
 		/* Processed actual command. */
 		host->cmd = NULL;
 		if (!host->data)
@@ -1050,6 +1244,7 @@ static void bcm2835_sdhost_finish_comman
 		else if (host->data_complete)
 			bcm2835_sdhost_transfer_complete(host);
 	}
+	log_event("FCM>", (u32)host->mrq, (u32)host->cmd);
 }
 
 static void bcm2835_sdhost_timeout(unsigned long data)
@@ -1060,10 +1255,12 @@ static void bcm2835_sdhost_timeout(unsig
 	host = (struct bcm2835_host *)data;
 
 	spin_lock_irqsave(&host->lock, flags);
+	log_event("TIM<", 0, 0);
 
 	if (host->mrq) {
 		pr_err("%s: timeout waiting for hardware interrupt.\n",
 			mmc_hostname(host->mmc));
+		log_dump();
 		bcm2835_sdhost_dumpregs(host);
 
 		if (host->data) {
@@ -1084,74 +1281,15 @@ static void bcm2835_sdhost_timeout(unsig
 	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 sdhsts = bcm2835_sdhost_read(host, SDHSTS);
-
-		if (sdhsts & 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)
-		host->hcfg |= SDHCFG_SDIO_IRPT_EN;
-	else
-		host->hcfg &= ~SDHCFG_SDIO_IRPT_EN;
-	bcm2835_sdhost_write(host, host->hcfg, SDHCFG);
-	mmiowb();
-}
-
-static void bcm2835_sdhost_enable_sdio_irq(struct mmc_host *mmc, int enable)
-{
-	struct bcm2835_host *host = mmc_priv(mmc);
-	unsigned long flags;
-
-	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);
-}
-
-static u32 bcm2835_sdhost_busy_irq(struct bcm2835_host *host, u32 intmask)
+static void bcm2835_sdhost_busy_irq(struct bcm2835_host *host, u32 intmask)
 {
-	const u32 handled = (SDHSTS_REW_TIME_OUT | SDHSTS_CMD_TIME_OUT |
-			     SDHSTS_CRC16_ERROR | SDHSTS_CRC7_ERROR |
-			     SDHSTS_FIFO_ERROR);
-
+	log_event("IRQB", (u32)host->cmd, intmask);
 	if (!host->cmd) {
 		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);
-		return 0;
+		return;
 	}
 
 	if (!host->use_busy) {
@@ -1159,7 +1297,7 @@ static u32 bcm2835_sdhost_busy_irq(struc
 			"though not expecting one.\n",
 			mmc_hostname(host->mmc), (unsigned)intmask);
 		bcm2835_sdhost_dumpregs(host);
-		return 0;
+		return;
 	}
 	host->use_busy = 0;
 
@@ -1182,28 +1320,23 @@ static u32 bcm2835_sdhost_busy_irq(struc
 		} else if (intmask & SDHSTS_CMD_TIME_OUT)
 			host->cmd->error = -ETIMEDOUT;
 
+		log_dump();
 		bcm2835_sdhost_dumpregs(host);
-		tasklet_schedule(&host->finish_tasklet);
 	}
 	else
-		bcm2835_sdhost_finish_command(host);
-
-	return handled;
+		bcm2835_sdhost_finish_command(host, NULL);
 }
 
-static u32 bcm2835_sdhost_data_irq(struct bcm2835_host *host, u32 intmask)
+static void bcm2835_sdhost_data_irq(struct bcm2835_host *host, u32 intmask)
 {
-	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
 	   data/space available FIFO status bits. It is therefore not
 	   an error to get here when there is no data transfer in
 	   progress. */
+	log_event("IRQD", (u32)host->data, intmask);
 	if (!host->data)
-		return 0;
+		return;
 
 	if (intmask & (SDHSTS_CRC16_ERROR |
 		       SDHSTS_FIFO_ERROR |
@@ -1214,46 +1347,37 @@ static u32 bcm2835_sdhost_data_irq(struc
 		else
 			host->data->error = -ETIMEDOUT;
 
-		bcm2835_sdhost_dumpregs(host);
-		tasklet_schedule(&host->finish_tasklet);
-		return handled;
+		if (host->debug) {
+			log_dump();
+			bcm2835_sdhost_dumpregs(host);
+		}
 	}
 
-	/* Use the block interrupt for writes after the first block */
-	if (host->data->flags & MMC_DATA_WRITE) {
+	if (host->data->error) {
+		bcm2835_sdhost_finish_data(host);
+	} else if (host->data->flags & MMC_DATA_WRITE) {
+		/* Use the block interrupt for writes after the first block */
 		host->hcfg &= ~(SDHCFG_DATA_IRPT_EN);
 		host->hcfg |= SDHCFG_BLOCK_IRPT_EN;
 		bcm2835_sdhost_write(host, host->hcfg, SDHCFG);
-		if (host->data->error)
-			bcm2835_sdhost_finish_data(host);
-		else
-			bcm2835_sdhost_transfer_pio(host);
+		bcm2835_sdhost_transfer_pio(host);
 	} else {
-		if (!host->data->error) {
-			bcm2835_sdhost_transfer_pio(host);
-			host->blocks--;
-		}
+		bcm2835_sdhost_transfer_pio(host);
+		host->blocks--;
 		if ((host->blocks == 0) || host->data->error)
 			bcm2835_sdhost_finish_data(host);
 	}
-
-	return handled;
 }
 
-static u32 bcm2835_sdhost_block_irq(struct bcm2835_host *host, u32 intmask)
+static void bcm2835_sdhost_block_irq(struct bcm2835_host *host, u32 intmask)
 {
-	struct dma_chan *dma_chan;
-	u32 dir_data;
-	const u32 handled = (SDHSTS_REW_TIME_OUT |
-			     SDHSTS_CRC16_ERROR |
-			     SDHSTS_FIFO_ERROR);
-
+	log_event("IRQK", (u32)host->data, intmask);
 	if (!host->data) {
 		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;
+		return;
 	}
 
 	if (intmask & (SDHSTS_CRC16_ERROR |
@@ -1265,149 +1389,69 @@ static u32 bcm2835_sdhost_block_irq(stru
 		else
 			host->data->error = -ETIMEDOUT;
 
-		if (host->debug)
+		if (host->debug) {
+			log_dump();
 			bcm2835_sdhost_dumpregs(host);
-		tasklet_schedule(&host->finish_tasklet);
-		return handled;
+		}
 	}
 
-	if (!host->use_dma) {
+	if (!host->dma_desc) {
 		BUG_ON(!host->blocks);
-		host->blocks--;
-		if ((host->blocks == 0) || host->data->error) {
-			/* Cancel the timer */
-			del_timer(&host->pio_timer);
-
+		if (host->data->error || (--host->blocks == 0)) {
 			bcm2835_sdhost_finish_data(host);
 		} else {
-			/* Reset the timer */
-			mod_timer(&host->pio_timer,
-				  jiffies + host->pio_timeout);
-
 			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;
-		dma_unmap_sg(dma_chan->device->dev,
-			     host->data->sg, host->data->sg_len,
-			     dir_data);
-
 		bcm2835_sdhost_finish_data(host);
 	}
-
-	return handled;
 }
 
-
 static irqreturn_t bcm2835_sdhost_irq(int irq, void *dev_id)
 {
 	irqreturn_t result = IRQ_NONE;
 	struct bcm2835_host *host = dev_id;
-	u32 unexpected = 0, early = 0;
-	int loops = 0;
+	u32 intmask;
 
 	spin_lock(&host->lock);
 
-	for (loops = 0; loops < 1; loops++) {
-		u32 intmask, handled;
-
-		intmask = bcm2835_sdhost_read(host, SDHSTS);
-		handled = intmask & (SDHSTS_BUSY_IRPT |
-				     SDHSTS_BLOCK_IRPT |
-				     SDHSTS_SDIO_IRPT |
-				     SDHSTS_DATA_FLAG);
-		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",
-			       mmc_hostname(host->mmc),
-			       (unsigned)intmask);
-
-			bcm2835_sdhost_dumpregs(host);
-		}
-
-		if (!handled)
-			break;
+	intmask = bcm2835_sdhost_read(host, SDHSTS);
+	log_event("IRQ<", intmask, 0);
 
-		if (loops)
-			early |= handled;
+	bcm2835_sdhost_write(host,
+			     SDHSTS_BUSY_IRPT |
+			     SDHSTS_BLOCK_IRPT |
+			     SDHSTS_SDIO_IRPT |
+			     SDHSTS_DATA_FLAG,
+			     SDHSTS);
 
+	if (intmask & SDHSTS_BLOCK_IRPT) {
+		bcm2835_sdhost_block_irq(host, intmask);
 		result = IRQ_HANDLED;
+	}
 
-		/* Clear all interrupts and notifications */
-		bcm2835_sdhost_write(host, intmask, SDHSTS);
-
-		if (intmask & SDHSTS_BUSY_IRPT)
-			handled |= bcm2835_sdhost_busy_irq(host, intmask);
-
-		/* There is no true data interrupt status bit, so it is
-		   necessary to qualify the data flag with the interrupt
-		   enable bit */
-		if ((intmask & SDHSTS_DATA_FLAG) &&
-		    (host->hcfg & SDHCFG_DATA_IRPT_EN))
-			handled |= bcm2835_sdhost_data_irq(host, intmask);
-
-		if (intmask & SDHSTS_BLOCK_IRPT)
-			handled |= bcm2835_sdhost_block_irq(host, intmask);
-
-		if (intmask & SDHSTS_SDIO_IRPT) {
-			bcm2835_sdhost_enable_sdio_irq_nolock(host, false);
-			host->thread_isr |= SDHSTS_SDIO_IRPT;
-			result = IRQ_WAKE_THREAD;
-		}
+	if (intmask & SDHSTS_BUSY_IRPT) {
+		bcm2835_sdhost_busy_irq(host, intmask);
+		result = IRQ_HANDLED;
+	}
 
-		unexpected |= (intmask & ~handled);
+	/* There is no true data interrupt status bit, so it is
+	   necessary to qualify the data flag with the interrupt
+	   enable bit */
+	if ((intmask & SDHSTS_DATA_FLAG) &&
+	    (host->hcfg & SDHCFG_DATA_IRPT_EN)) {
+		bcm2835_sdhost_data_irq(host, intmask);
+		result = IRQ_HANDLED;
 	}
 
 	mmiowb();
 
+	log_event("IRQ>", bcm2835_sdhost_read(host, SDHSTS), 0);
 	spin_unlock(&host->lock);
 
-	if (early)
-		pr_debug("%s: early %x (loops %d)\n",
-			 mmc_hostname(host->mmc), early, loops);
-
-	if (unexpected) {
-		pr_err("%s: unexpected interrupt 0x%08x.\n",
-			   mmc_hostname(host->mmc), unexpected);
-		bcm2835_sdhost_dumpregs(host);
-	}
-
 	return result;
 }
 
-static irqreturn_t bcm2835_sdhost_thread_irq(int irq, void *dev_id)
-{
-	struct bcm2835_host *host = dev_id;
-	unsigned long flags;
-	u32 isr;
-
-	spin_lock_irqsave(&host->lock, flags);
-	isr = host->thread_isr;
-	host->thread_isr = 0;
-	spin_unlock_irqrestore(&host->lock, flags);
-
-	if (isr & SDHSTS_SDIO_IRPT) {
-		sdio_run_irqs(host->mmc);
-
-/* Is this necessary? Why re-enable an interrupt which is enabled?
-		spin_lock_irqsave(&host->lock, flags);
-		if (host->flags & SDHSTS_SDIO_IRPT_ENABLED)
-			bcm2835_sdhost_enable_sdio_irq_nolock(host, true);
-		spin_unlock_irqrestore(&host->lock, flags);
-*/
-	}
-
-	return isr ? IRQ_HANDLED : IRQ_NONE;
-}
-
-
-
 void bcm2835_sdhost_set_clock(struct bcm2835_host *host, unsigned int clock)
 {
 	int div = 0; /* Initialized for compiler warning */
@@ -1417,9 +1461,8 @@ void bcm2835_sdhost_set_clock(struct bcm
 		pr_info("%s: set_clock(%d)\n", mmc_hostname(host->mmc), clock);
 
 	if ((host->overclock_50 > 50) &&
-	    (clock == 50*MHZ)) {
+	    (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
@@ -1466,6 +1509,11 @@ void bcm2835_sdhost_set_clock(struct bcm
 	clock = host->max_clk / (div + 2);
 	host->mmc->actual_clock = clock;
 
+	/* Calibrate some delays */
+
+	host->ns_per_fifo_word = (1000000000/clock) *
+		((host->mmc->caps & MMC_CAP_4_BIT_DATA) ? 8 : 32);
+
 	if (clock > input_clock) {
 		/* Save the closest value, to make it easier
 		   to reduce in the event of error */
@@ -1501,6 +1549,7 @@ static void bcm2835_sdhost_request(struc
 {
 	struct bcm2835_host *host;
 	unsigned long flags;
+	u32 edm, fsm;
 
 	host = mmc_priv(mmc);
 
@@ -1521,6 +1570,8 @@ static void bcm2835_sdhost_request(struc
 	}
 
 	/* Reset the error statuses in case this is a retry */
+	if (mrq->sbc)
+		mrq->sbc->error = 0;
 	if (mrq->cmd)
 		mrq->cmd->error = 0;
 	if (mrq->data)
@@ -1536,28 +1587,58 @@ static void bcm2835_sdhost_request(struc
 		return;
 	}
 
+	if (host->use_dma && mrq->data &&
+	    (mrq->data->blocks > host->pio_limit))
+		bcm2835_sdhost_prepare_dma(host, mrq->data);
+
 	spin_lock_irqsave(&host->lock, flags);
 
 	WARN_ON(host->mrq != NULL);
-
 	host->mrq = mrq;
 
-	if (mrq->sbc)
-		bcm2835_sdhost_send_command(host, mrq->sbc);
-	else
-		bcm2835_sdhost_send_command(host, mrq->cmd);
+	edm = bcm2835_sdhost_read(host, SDEDM);
+	fsm = edm & SDEDM_FSM_MASK;
 
-	mmiowb();
-	spin_unlock_irqrestore(&host->lock, flags);
+	log_event("REQ<", (u32)mrq, edm);
+	if ((fsm != SDEDM_FSM_IDENTMODE) &&
+	    (fsm != SDEDM_FSM_DATAMODE)) {
+		pr_err("%s: previous command (%d) not complete (EDM %x)\n",
+		       mmc_hostname(host->mmc),
+		       bcm2835_sdhost_read(host, SDCMD) & SDCMD_CMD_MASK,
+		       edm);
+		log_event("REQ!", (u32)mrq, edm);
+		log_dump();
+		bcm2835_sdhost_dumpregs(host);
+		mrq->cmd->error = -EILSEQ;
+		tasklet_schedule(&host->finish_tasklet);
+		mmiowb();
+		spin_unlock_irqrestore(&host->lock, flags);
+		return;
+	}
+
+	host->use_sbc = !!mrq->sbc &&
+		(host->mrq->data->flags & USE_CMD23_FLAGS);
+	if (host->use_sbc) {
+		if (bcm2835_sdhost_send_command(host, mrq->sbc)) {
+			if (!host->use_busy)
+				bcm2835_sdhost_finish_command(host, &flags);
+		}
+	} else if (bcm2835_sdhost_send_command(host, mrq->cmd)) {
+		if (host->data && host->dma_desc)
+			/* DMA transfer starts now, PIO starts after irq */
+			bcm2835_sdhost_start_dma(host);
 
-	if (!mrq->sbc && mrq->cmd->data && host->use_dma)
-		/* DMA transfer starts now, PIO starts after irq */
-		bcm2835_sdhost_transfer_dma(host);
+		if (!host->use_busy)
+			bcm2835_sdhost_finish_command(host, &flags);
+	}
 
-	if (!host->use_busy)
-		bcm2835_sdhost_finish_command(host);
-}
+	log_event("CMD ", (u32)mrq->cmd->opcode,
+		   mrq->data ? (u32)mrq->data->blksz : 0);
+	mmiowb();
 
+	log_event("REQ>", (u32)mrq, 0);
+	spin_unlock_irqrestore(&host->lock, flags);
+}
 
 static void bcm2835_sdhost_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 {
@@ -1574,6 +1655,8 @@ static void bcm2835_sdhost_set_ios(struc
 
 	spin_lock_irqsave(&host->lock, flags);
 
+	log_event("IOS<", ios->clock, 0);
+
 	if (!ios->clock || ios->clock != host->clock) {
 		bcm2835_sdhost_set_clock(host, ios->clock);
 		host->clock = ios->clock;
@@ -1596,59 +1679,53 @@ static void bcm2835_sdhost_set_ios(struc
 	spin_unlock_irqrestore(&host->lock, flags);
 }
 
-static int bcm2835_sdhost_multi_io_quirk(struct mmc_card *card,
-					 unsigned int direction,
-					 u32 blk_pos, int blk_size)
-{
-	/* There is a bug in the host controller hardware that makes
-	   reading the final sector of the card as part of a multiple read
-	   problematic. Detect that case and shorten the read accordingly.
-	*/
+static struct mmc_host_ops bcm2835_sdhost_ops = {
+	.request = bcm2835_sdhost_request,
+	.set_ios = bcm2835_sdhost_set_ios,
+	.hw_reset = bcm2835_sdhost_reset,
+};
+
+static void bcm2835_sdhost_cmd_wait_work(struct work_struct *work)
+{
 	struct bcm2835_host *host;
+	unsigned long flags;
 
-	host = mmc_priv(card->host);
+	host = container_of(work, struct bcm2835_host, cmd_wait_wq);
 
-	if (!host->sectors) {
-		/* csd.capacity is in weird units - convert to sectors */
-		u32 card_sectors = (card->csd.capacity << (card->csd.read_blkbits - 9));
-		if ((direction == MMC_DATA_READ) &&
-		    ((blk_pos + blk_size) == card_sectors))
-			blk_size--;
-		return blk_size;
-	}
+	spin_lock_irqsave(&host->lock, flags);
 
-	if (direction == MMC_DATA_READ) {
-		int i;
-		int sector;
-		for (i = 0; blk_pos > (sector = host->single_read_sectors[i]); i++)
-			continue;
+	log_event("CWK<", (u32)host->cmd, (u32)host->mrq);
 
-		if ((blk_pos + blk_size) > sector)
-			blk_size = (blk_pos == sector) ? 1 : (sector - blk_pos);
+	/*
+	 * If this tasklet gets rescheduled while running, it will
+	 * be run again afterwards but without any active request.
+	 */
+	if (!host->mrq) {
+		spin_unlock_irqrestore(&host->lock, flags);
+		return;
 	}
-	return blk_size;
-}
 
+	bcm2835_sdhost_finish_command(host, &flags);
 
-static struct mmc_host_ops bcm2835_sdhost_ops = {
-	.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,
-};
+	mmiowb();
+
+	log_event("CWK>", (u32)host->cmd, 0);
 
+	spin_unlock_irqrestore(&host->lock, flags);
+}
 
 static void bcm2835_sdhost_tasklet_finish(unsigned long param)
 {
 	struct bcm2835_host *host;
 	unsigned long flags;
 	struct mmc_request *mrq;
+	struct dma_chan *terminate_chan = NULL;
 
 	host = (struct bcm2835_host *)param;
 
 	spin_lock_irqsave(&host->lock, flags);
 
+	log_event("TSK<", (u32)host->mrq, 0);
 	/*
 	 * If this tasklet gets rescheduled while running, it will
 	 * be run again afterwards but without any active request.
@@ -1683,11 +1760,23 @@ static void bcm2835_sdhost_tasklet_finis
 
 	mmiowb();
 
+	host->dma_desc = NULL;
+	terminate_chan = host->dma_chan;
+	host->dma_chan = NULL;
+
 	spin_unlock_irqrestore(&host->lock, flags);
-	mmc_request_done(host->mmc, mrq);
-}
 
+	if (terminate_chan)
+	{
+		int err = dmaengine_terminate_all(terminate_chan);
+		if (err)
+			pr_err("%s: failed to terminate DMA (%d)\n",
+			       mmc_hostname(host->mmc), err);
+	}
 
+	mmc_request_done(host->mmc, mrq);
+	log_event("TSK>", (u32)mrq, 0);
+}
 
 int bcm2835_sdhost_add_host(struct bcm2835_host *host)
 {
@@ -1709,10 +1798,10 @@ int bcm2835_sdhost_add_host(struct bcm28
 		 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->caps |=
 		MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED |
 		MMC_CAP_NEEDS_POLL | MMC_CAP_HW_RESET | MMC_CAP_ERASE |
-		(ALLOW_CMD23 * MMC_CAP_CMD23);
+		((ALLOW_CMD23_READ|ALLOW_CMD23_WRITE) * MMC_CAP_CMD23);
 
 	spin_lock_init(&host->lock);
 
@@ -1722,9 +1811,9 @@ int bcm2835_sdhost_add_host(struct bcm28
 			pr_err("%s: unable to initialise DMA channels. "
 			       "Falling back to PIO\n",
 			       mmc_hostname(mmc));
-			host->have_dma = false;
+			host->use_dma = false;
 		} else {
-			host->have_dma = true;
+			host->use_dma = true;
 
 			cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
 			cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
@@ -1741,7 +1830,7 @@ int bcm2835_sdhost_add_host(struct bcm28
 			ret = dmaengine_slave_config(host->dma_chan_rx, &cfg);
 		}
 	} else {
-		host->have_dma = false;
+		host->use_dma = false;
 	}
 
 	mmc->max_segs = 128;
@@ -1756,16 +1845,15 @@ 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,
-		    (unsigned long)host);
+	INIT_WORK(&host->cmd_wait_wq, bcm2835_sdhost_cmd_wait_work);
 
-	setup_timer(&host->pio_timer, bcm2835_sdhost_pio_timeout,
+	setup_timer(&host->timer, bcm2835_sdhost_timeout,
 		    (unsigned long)host);
 
 	bcm2835_sdhost_init(host, 0);
-	ret = request_threaded_irq(host->irq, bcm2835_sdhost_irq,
-				   bcm2835_sdhost_thread_irq,
-				   IRQF_SHARED,	mmc_hostname(mmc), host);
+
+	ret = request_irq(host->irq, bcm2835_sdhost_irq, 0 /*IRQF_SHARED*/,
+				  mmc_hostname(mmc), host);
 	if (ret) {
 		pr_err("%s: failed to request IRQ %d: %d\n",
 		       mmc_hostname(mmc), host->irq, ret);
@@ -1776,11 +1864,11 @@ int bcm2835_sdhost_add_host(struct bcm28
 	mmc_add_host(mmc);
 
 	pio_limit_string[0] = '\0';
-	if (host->have_dma && (host->pio_limit > 0))
+	if (host->use_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",
+		host->use_dma ? "enabled" : "disabled",
 		pio_limit_string);
 
 	return 0;
@@ -1810,8 +1898,11 @@ static int bcm2835_sdhost_probe(struct p
 	mmc->ops = &bcm2835_sdhost_ops;
 	host = mmc_priv(mmc);
 	host->mmc = mmc;
+	host->cmd_quick_poll_retries = 0;
 	host->pio_timeout = msecs_to_jiffies(500);
+	host->pio_limit = 1;
 	host->max_delay = 1; /* Warn if over 1ms */
+	host->allow_dma = 1;
 	spin_lock_init(&host->lock);
 
 	iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -1827,13 +1918,12 @@ static int bcm2835_sdhost_probe(struct p
 		return -ENODEV;
 	}
 	host->bus_addr = be32_to_cpup(addr);
+	log_init(iomem->start - host->bus_addr);
 	pr_debug(" - ioaddr %lx, iomem->start %lx, bus_addr %lx\n",
 		 (unsigned long)host->ioaddr,
 		 (unsigned long)iomem->start,
 		 (unsigned long)host->bus_addr);
 
-	host->allow_dma = ALLOW_DMA;
-
 	if (node) {
 		/* Read any custom properties */
 		of_property_read_u32(node,
@@ -1845,16 +1935,17 @@ static int bcm2835_sdhost_probe(struct p
 		of_property_read_u32(node,
 				     "brcm,pio-limit",
 				     &host->pio_limit);
-		host->allow_dma = ALLOW_DMA &&
+		host->allow_dma =
 			!of_property_read_bool(node, "brcm,force-pio");
 		host->debug = of_property_read_bool(node, "brcm,debug");
-		of_property_read_u32(node,
-				     "brcm,debug-flags",
-				     &host->debug_flags);
 	}
 
-	if (host->debug_flags)
-		dev_err(dev, "debug_flags=%x\n", host->debug_flags);
+	host->dma_chan = NULL;
+	host->dma_desc = NULL;
+
+	/* Formally recognise the other way of disabling DMA */
+	if (host->pio_limit == 0x7fffffff)
+		host->allow_dma = false;
 
 	if (host->allow_dma) {
 		if (node) {
@@ -1940,15 +2031,12 @@ static int bcm2835_sdhost_remove(struct
 	return 0;
 }
 
-
 static const struct of_device_id bcm2835_sdhost_match[] = {
 	{ .compatible = "brcm,bcm2835-sdhost" },
 	{ }
 };
 MODULE_DEVICE_TABLE(of, bcm2835_sdhost_match);
 
-
-
 static struct platform_driver bcm2835_sdhost_driver = {
 	.probe      = bcm2835_sdhost_probe,
 	.remove     = bcm2835_sdhost_remove,
