[FEISTY]: [PATCH 2/3] UBUNTU: Update tifm driver to 0.8d

Phillip lougher phillip at lougher.demon.co.uk
Wed May 2 00:28:56 UTC 2007


>From 6bec583645852716f3fee4a7d2534be1acf060d6 Mon Sep 17 00:00:00 2001
From: Phillip Lougher <phillip at ubuntu.com>
Date: Tue, 1 May 2007 19:39:09 +0100
Subject: [PATCH 2/3] UBUNTU: Update tifm driver to 0.8d
Bug: 53923

diff --git a/drivers/mmc/host/tifm_sd.c b/drivers/mmc/host/tifm_sd.c
index 31035a1..33c250b 100644
--- a/drivers/mmc/host/tifm_sd.c
+++ b/drivers/mmc/host/tifm_sd.c
@@ -7,6 +7,8 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  *
+ * Special thanks to Brad Campbell for extensive testing of this driver.
+ *
  */
 
 
@@ -16,7 +18,7 @@
 #include <asm/io.h>
 
 #define DRIVER_NAME "tifm_sd"
-#define DRIVER_VERSION "0.7"
+#define DRIVER_VERSION "0.8d"
 
 static int no_dma = 0;
 static int fixed_timeout = 0;
@@ -35,9 +37,9 @@ module_param(fixed_timeout, bool, 0644);
 #define TIFM_MMCSD_INAB       0x0080   /* abort / initialize command */
 #define TIFM_MMCSD_READ       0x8000
 
-#define TIFM_MMCSD_DATAMASK   0x401d   /* set bits: CERR, EOFB, BRS, CB, EOC */
 #define TIFM_MMCSD_ERRMASK    0x01e0   /* set bits: CCRC, CTO, DCRC, DTO */
 #define TIFM_MMCSD_EOC        0x0001   /* end of command phase  */
+#define TIFM_MMCSD_CD         0x0002   /* card detect           */
 #define TIFM_MMCSD_CB         0x0004   /* card enter busy state */
 #define TIFM_MMCSD_BRS        0x0008   /* block received/sent   */
 #define TIFM_MMCSD_EOFB       0x0010   /* card exit busy state  */
@@ -47,8 +49,13 @@ module_param(fixed_timeout, bool, 0644);
 #define TIFM_MMCSD_CCRC       0x0100   /* command crc error     */
 #define TIFM_MMCSD_AF         0x0400   /* fifo almost full      */
 #define TIFM_MMCSD_AE         0x0800   /* fifo almost empty     */
+#define TIFM_MMCSD_OCRB       0x1000   /* OCR busy              */
+#define TIFM_MMCSD_CIRQ       0x2000   /* card irq (cmd40/sdio) */
 #define TIFM_MMCSD_CERR       0x4000   /* card status error     */
 
+#define TIFM_MMCSD_ODTO       0x0040   /* open drain / extended timeout */
+#define TIFM_MMCSD_CARD_RO    0x0200   /* card is read-only     */
+
 #define TIFM_MMCSD_FIFO_SIZE  0x0020
 
 #define TIFM_MMCSD_RSP_R0     0x0000
@@ -66,97 +73,257 @@ module_param(fixed_timeout, bool, 0644);
 #define TIFM_MMCSD_CMD_AC     0x2000
 #define TIFM_MMCSD_CMD_ADTC   0x3000
 
-typedef enum {
-	IDLE = 0,
-	CMD,    /* main command ended                   */
-	BRS,    /* block transfer finished              */
-	SCMD,   /* stop command ended                   */
-	CARD,   /* card left busy state                 */
-	FIFO,   /* FIFO operation completed (uncertain) */
-	READY
-} card_state_t;
+#define TIFM_MMCSD_MAX_BLOCK_SIZE  0x0800
 
 enum {
-	FIFO_RDY   = 0x0001,     /* hardware dependent value */
-	EJECT      = 0x0004,
-	EJECT_DONE = 0x0008,
-	CARD_BUSY  = 0x0010,
-	OPENDRAIN  = 0x0040,     /* hardware dependent value */
-	CARD_EVENT = 0x0100,     /* hardware dependent value */
-	CARD_RO    = 0x0200,     /* hardware dependent value */
-	FIFO_EVENT = 0x10000 };  /* hardware dependent value */
+	CMD_READY    = 0x0001,
+	FIFO_READY   = 0x0002,
+	BRS_READY    = 0x0004,
+	SCMD_ACTIVE  = 0x0008,
+	SCMD_READY   = 0x0010,
+	CARD_BUSY    = 0x0020,
+	DATA_CARRY   = 0x0040
+};
 
 struct tifm_sd {
-	struct tifm_dev     *dev;
+	struct tifm_dev       *dev;
 
-	unsigned int        flags;
-	card_state_t        state;
-	unsigned int        clk_freq;
-	unsigned int        clk_div;
-	unsigned long       timeout_jiffies;
+	unsigned short        eject:1,
+			      open_drain:1,
+			      no_dma:1;
+	unsigned short        cmd_flags;
+
+	unsigned int          clk_freq;
+	unsigned int          clk_div;
+	unsigned long         timeout_jiffies;
 
 	struct tasklet_struct finish_tasklet;
 	struct timer_list     timer;
 	struct mmc_request    *req;
-	wait_queue_head_t     notify;
-
-	size_t                written_blocks;
-	size_t                buffer_size;
-	size_t                buffer_pos;
 
+	int                   sg_len;
+	int                   sg_pos;
+	unsigned int          block_pos;
+	struct scatterlist    bounce_buf;
+	unsigned char         bounce_buf_data[TIFM_MMCSD_MAX_BLOCK_SIZE];
 };
 
-static char* tifm_sd_data_buffer(struct mmc_data *data)
+/* for some reason, host won't respond correctly to readw/writew */
+static void tifm_sd_read_fifo(struct tifm_sd *host, struct page *pg,
+			      unsigned int off, unsigned int cnt)
 {
-	return page_address(data->sg->page) + data->sg->offset;
+	struct tifm_dev *sock = host->dev;
+	unsigned char *buf;
+	unsigned int pos = 0, val;
+
+	buf = kmap_atomic(pg, KM_BIO_DST_IRQ) + off;
+	if (host->cmd_flags & DATA_CARRY) {
+		buf[pos++] = host->bounce_buf_data[0];
+		host->cmd_flags &= ~DATA_CARRY;
+	}
+
+	while (pos < cnt) {
+		val = readl(sock->addr + SOCK_MMCSD_DATA);
+		buf[pos++] = val & 0xff;
+		if (pos == cnt) {
+			host->bounce_buf_data[0] = (val >> 8) & 0xff;
+			host->cmd_flags |= DATA_CARRY;
+			break;
+		}
+		buf[pos++] = (val >> 8) & 0xff;
+	}
+	kunmap_atomic(buf - off, KM_BIO_DST_IRQ);
 }
 
-static int tifm_sd_transfer_data(struct tifm_dev *sock, struct tifm_sd *host,
-				 unsigned int host_status)
+static void tifm_sd_write_fifo(struct tifm_sd *host, struct page *pg,
+			       unsigned int off, unsigned int cnt)
 {
-	struct mmc_command *cmd = host->req->cmd;
-	unsigned int t_val = 0, cnt = 0;
-	char *buffer;
-
-	if (host_status & TIFM_MMCSD_BRS) {
-		/* in non-dma rx mode BRS fires when fifo is still not empty */
-		if (no_dma && (cmd->data->flags & MMC_DATA_READ)) {
-			buffer = tifm_sd_data_buffer(host->req->data);
-			while (host->buffer_size > host->buffer_pos) {
-				t_val = readl(sock->addr + SOCK_MMCSD_DATA);
-				buffer[host->buffer_pos++] = t_val & 0xff;
-				buffer[host->buffer_pos++] =
-							(t_val >> 8) & 0xff;
-			}
+	struct tifm_dev *sock = host->dev;
+	unsigned char *buf;
+	unsigned int pos = 0, val;
+
+	buf = kmap_atomic(pg, KM_BIO_SRC_IRQ) + off;
+	if (host->cmd_flags & DATA_CARRY) {
+		val = host->bounce_buf_data[0] | ((buf[pos++] << 8) & 0xff00);
+		writel(val, sock->addr + SOCK_MMCSD_DATA);
+		host->cmd_flags &= ~DATA_CARRY;
+	}
+
+	while (pos < cnt) {
+		val = buf[pos++];
+		if (pos == cnt) {
+			host->bounce_buf_data[0] = val & 0xff;
+			host->cmd_flags |= DATA_CARRY;
+			break;
 		}
-		return 1;
-	} else if (no_dma) {
-		buffer = tifm_sd_data_buffer(host->req->data);
-		if ((cmd->data->flags & MMC_DATA_READ) &&
-				(host_status & TIFM_MMCSD_AF)) {
-			for (cnt = 0; cnt < TIFM_MMCSD_FIFO_SIZE; cnt++) {
-				t_val = readl(sock->addr + SOCK_MMCSD_DATA);
-				if (host->buffer_size > host->buffer_pos) {
-					buffer[host->buffer_pos++] =
-							t_val & 0xff;
-					buffer[host->buffer_pos++] =
-							(t_val >> 8) & 0xff;
-				}
-			}
-		} else if ((cmd->data->flags & MMC_DATA_WRITE)
-			   && (host_status & TIFM_MMCSD_AE)) {
-			for (cnt = 0; cnt < TIFM_MMCSD_FIFO_SIZE; cnt++) {
-				if (host->buffer_size > host->buffer_pos) {
-					t_val = buffer[host->buffer_pos++]
-						& 0x00ff;
-					t_val |= ((buffer[host->buffer_pos++])
-						  << 8) & 0xff00;
-					writel(t_val,
-					       sock->addr + SOCK_MMCSD_DATA);
-				}
+		val |= (buf[pos++] << 8) & 0xff00;
+		writel(val, sock->addr + SOCK_MMCSD_DATA);
+	}
+	kunmap_atomic(buf - off, KM_BIO_SRC_IRQ);
+}
+
+static void tifm_sd_transfer_data(struct tifm_sd *host)
+{
+	struct mmc_data *r_data = host->req->cmd->data;
+	struct scatterlist *sg = r_data->sg;
+	unsigned int off, cnt, t_size = TIFM_MMCSD_FIFO_SIZE * 2;
+	unsigned int p_off, p_cnt;
+	struct page *pg;
+
+	if (host->sg_pos == host->sg_len)
+		return;
+	while (t_size) {
+		cnt = sg[host->sg_pos].length - host->block_pos;
+		if (!cnt) {
+			host->block_pos = 0;
+			host->sg_pos++;
+			if (host->sg_pos == host->sg_len) {
+				if ((r_data->flags & MMC_DATA_WRITE)
+				    && DATA_CARRY)
+					writel(host->bounce_buf_data[0],
+					       host->dev->addr
+					       + SOCK_MMCSD_DATA);
+
+				return;
 			}
+			cnt = sg[host->sg_pos].length;
 		}
+		off = sg[host->sg_pos].offset + host->block_pos;
+
+		pg = nth_page(sg[host->sg_pos].page, off >> PAGE_SHIFT);
+		p_off = offset_in_page(off);
+		p_cnt = PAGE_SIZE - p_off;
+		p_cnt = min(p_cnt, cnt);
+		p_cnt = min(p_cnt, t_size);
+
+		if (r_data->flags & MMC_DATA_READ)
+			tifm_sd_read_fifo(host, pg, p_off, p_cnt);
+		else if (r_data->flags & MMC_DATA_WRITE)
+			tifm_sd_write_fifo(host, pg, p_off, p_cnt);
+
+		t_size -= p_cnt;
+		host->block_pos += p_cnt;
 	}
+}
+
+static void tifm_sd_copy_page(struct page *dst, unsigned int dst_off,
+			      struct page *src, unsigned int src_off,
+			      unsigned int count)
+{
+	unsigned char *src_buf = kmap_atomic(src, KM_BIO_SRC_IRQ) + src_off;
+	unsigned char *dst_buf = kmap_atomic(dst, KM_BIO_DST_IRQ) + dst_off;
+
+	memcpy(dst_buf, src_buf, count);
+
+	kunmap_atomic(dst_buf - dst_off, KM_BIO_DST_IRQ);
+	kunmap_atomic(src_buf - src_off, KM_BIO_SRC_IRQ);
+}
+
+static void tifm_sd_bounce_block(struct tifm_sd *host, struct mmc_data *r_data)
+{
+	struct scatterlist *sg = r_data->sg;
+	unsigned int t_size = r_data->blksz;
+	unsigned int off, cnt;
+	unsigned int p_off, p_cnt;
+	struct page *pg;
+
+	dev_dbg(&host->dev->dev, "bouncing block\n");
+	while (t_size) {
+		cnt = sg[host->sg_pos].length - host->block_pos;
+		if (!cnt) {
+			host->block_pos = 0;
+			host->sg_pos++;
+			if (host->sg_pos == host->sg_len)
+				return;
+			cnt = sg[host->sg_pos].length;
+		}
+		off = sg[host->sg_pos].offset + host->block_pos;
+
+		pg = nth_page(sg[host->sg_pos].page, off >> PAGE_SHIFT);
+		p_off = offset_in_page(off);
+		p_cnt = PAGE_SIZE - p_off;
+		p_cnt = min(p_cnt, cnt);
+		p_cnt = min(p_cnt, t_size);
+
+		if (r_data->flags & MMC_DATA_WRITE)
+			tifm_sd_copy_page(host->bounce_buf.page,
+					  r_data->blksz - t_size,
+					  pg, p_off, p_cnt);
+		else if (r_data->flags & MMC_DATA_READ)
+			tifm_sd_copy_page(pg, p_off, host->bounce_buf.page,
+					  r_data->blksz - t_size, p_cnt);
+
+		t_size -= p_cnt;
+		host->block_pos += p_cnt;
+	}
+}
+
+int tifm_sd_set_dma_data(struct tifm_sd *host, struct mmc_data *r_data)
+{
+	struct tifm_dev *sock = host->dev;
+	unsigned int t_size = TIFM_DMA_TSIZE * r_data->blksz;
+	unsigned int dma_len, dma_blk_cnt, dma_off;
+	struct scatterlist *sg = NULL;
+	unsigned long flags;
+
+	if (host->sg_pos == host->sg_len)
+		return 1;
+
+	if (host->cmd_flags & DATA_CARRY) {
+		host->cmd_flags &= ~DATA_CARRY;
+		local_irq_save(flags);
+		tifm_sd_bounce_block(host, r_data);
+		local_irq_restore(flags);
+		if (host->sg_pos == host->sg_len)
+			return 1;
+	}
+
+	while (1) {
+		dma_len = sg_dma_len(&r_data->sg[host->sg_pos])
+			  - host->block_pos;
+		if (dma_len)
+			break;
+		host->block_pos = 0;
+		host->sg_pos++;
+		if (host->sg_pos == host->sg_len)
+			return 1;
+	}
+
+	if (dma_len < t_size) {
+		dma_blk_cnt = dma_len / r_data->blksz;
+		dma_off = host->block_pos;
+		host->block_pos += dma_blk_cnt * r_data->blksz;
+	} else {
+		dma_blk_cnt = TIFM_DMA_TSIZE;
+		dma_off = host->block_pos;
+		host->block_pos += t_size;
+	}
+
+	if (dma_blk_cnt)
+		sg = &r_data->sg[host->sg_pos];
+	else if (dma_len) {
+		if (r_data->flags & MMC_DATA_WRITE) {
+			local_irq_save(flags);
+			tifm_sd_bounce_block(host, r_data);
+			local_irq_restore(flags);
+		} else
+			host->cmd_flags |= DATA_CARRY;
+
+		sg = &host->bounce_buf;
+		dma_off = 0;
+		dma_blk_cnt = 1;
+	} else
+		return 1;
+
+	dev_dbg(&sock->dev, "setting dma for %d blocks\n", dma_blk_cnt);
+	writel(sg_dma_address(sg) + dma_off, sock->addr + SOCK_DMA_ADDRESS);
+	if (r_data->flags & MMC_DATA_WRITE)
+		writel((dma_blk_cnt << 8) | TIFM_DMA_TX | TIFM_DMA_EN,
+		       sock->addr + SOCK_DMA_CONTROL);
+	else
+		writel((dma_blk_cnt << 8) | TIFM_DMA_EN,
+		       sock->addr + SOCK_DMA_CONTROL);
+
 	return 0;
 }
 
@@ -206,7 +373,7 @@ static void tifm_sd_exec(struct tifm_sd *host, struct mmc_command *cmd)
 {
 	struct tifm_dev *sock = host->dev;
 	unsigned int cmd_mask = tifm_sd_op_flags(cmd) |
-				(host->flags & OPENDRAIN);
+				(host->open_drain ? TIFM_MMCSD_ODTO : 0);
 
 	if (cmd->data && (cmd->data->flags & MMC_DATA_READ))
 		cmd_mask |= TIFM_MMCSD_READ;
@@ -231,191 +398,194 @@ static void tifm_sd_fetch_resp(struct mmc_command *cmd, struct tifm_dev *sock)
 		       | readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x00);
 }
 
-static void tifm_sd_process_cmd(struct tifm_dev *sock, struct tifm_sd *host,
-				       unsigned int host_status)
+static void tifm_sd_check_status(struct tifm_sd *host)
 {
+	struct tifm_dev *sock = host->dev;
 	struct mmc_command *cmd = host->req->cmd;
 
-change_state:
-	switch (host->state) {
-	case IDLE:
+	if (cmd->error != MMC_ERR_NONE)
+		goto finish_request;
+
+	if (!(host->cmd_flags & CMD_READY))
 		return;
-	case CMD:
-		if (host_status & (TIFM_MMCSD_EOC | TIFM_MMCSD_CERR)) {
-			tifm_sd_fetch_resp(cmd, sock);
-			if (cmd->data) {
-				host->state = BRS;
-			} else {
-				host->state = READY;
-			}
-			goto change_state;
-		}
-		break;
-	case BRS:
-		if (tifm_sd_transfer_data(sock, host, host_status)) {
-			if (cmd->data->flags & MMC_DATA_WRITE) {
-				host->state = CARD;
-			} else {
-				if (no_dma) {
-					if (host->req->stop) {
-						tifm_sd_exec(host, host->req->stop);
-						host->state = SCMD;
-					} else {
-						host->state = READY;
-					}
-				} else {
-					host->state = FIFO;
-				}
-			}
-			goto change_state;
-		}
-		break;
-	case SCMD:
-		if (host_status & TIFM_MMCSD_EOC) {
-			tifm_sd_fetch_resp(host->req->stop, sock);
-			host->state = READY;
-			goto change_state;
+
+	if (cmd->data) {
+		if (cmd->data->error != MMC_ERR_NONE) {
+			if ((host->cmd_flags & SCMD_ACTIVE)
+			    && !(host->cmd_flags & SCMD_READY))
+				return;
+
+			goto finish_request;
 		}
-		break;
-	case CARD:
-		dev_dbg(&sock->dev, "waiting for CARD, have %zd blocks\n",
-			host->written_blocks);
-		if (!(host->flags & CARD_BUSY)
-		    && (host->written_blocks == cmd->data->blocks)) {
-			if (no_dma) {
-				if (host->req->stop) {
+
+		if (!(host->cmd_flags & BRS_READY))
+			return;
+
+		if (!(host->no_dma || (host->cmd_flags & FIFO_READY)))
+			return;
+
+		if (cmd->data->flags & MMC_DATA_WRITE) {
+			if (host->req->stop) {
+				if (!(host->cmd_flags & SCMD_ACTIVE)) {
+					host->cmd_flags |= SCMD_ACTIVE;
+					writel(TIFM_MMCSD_EOFB
+					       | readl(sock->addr
+						       + SOCK_MMCSD_INT_ENABLE),
+					       sock->addr
+					       + SOCK_MMCSD_INT_ENABLE);
 					tifm_sd_exec(host, host->req->stop);
-					host->state = SCMD;
+					return;
 				} else {
-					host->state = READY;
+					if (!(host->cmd_flags & SCMD_READY)
+					    || (host->cmd_flags & CARD_BUSY))
+						return;
+					writel((~TIFM_MMCSD_EOFB)
+					       & readl(sock->addr
+						       + SOCK_MMCSD_INT_ENABLE),
+					       sock->addr
+					       + SOCK_MMCSD_INT_ENABLE);
 				}
 			} else {
-				host->state = FIFO;
+				if (host->cmd_flags & CARD_BUSY)
+					return;
+				writel((~TIFM_MMCSD_EOFB)
+				       & readl(sock->addr
+					       + SOCK_MMCSD_INT_ENABLE),
+				       sock->addr + SOCK_MMCSD_INT_ENABLE);
 			}
-			goto change_state;
-		}
-		break;
-	case FIFO:
-		if (host->flags & FIFO_RDY) {
-			host->flags &= ~FIFO_RDY;
+		} else {
 			if (host->req->stop) {
-				tifm_sd_exec(host, host->req->stop);
-				host->state = SCMD;
-			} else {
-				host->state = READY;
+				if (!(host->cmd_flags & SCMD_ACTIVE)) {
+					host->cmd_flags |= SCMD_ACTIVE;
+					tifm_sd_exec(host, host->req->stop);
+					return;
+				} else {
+					if (!(host->cmd_flags & SCMD_READY))
+						return;
+				}
 			}
-			goto change_state;
 		}
-		break;
-	case READY:
-		tasklet_schedule(&host->finish_tasklet);
-		return;
 	}
-
+finish_request:
+	tasklet_schedule(&host->finish_tasklet);
 }
 
 /* Called from interrupt handler */
-static void tifm_sd_signal_irq(struct tifm_dev *sock,
-			       unsigned int sock_irq_status)
+static void tifm_sd_data_event(struct tifm_dev *sock)
 {
 	struct tifm_sd *host;
-	unsigned int host_status = 0, fifo_status = 0;
-	int error_code = 0;
+	unsigned int fifo_status = 0;
+	struct mmc_data *r_data = NULL;
 
 	spin_lock(&sock->lock);
 	host = mmc_priv((struct mmc_host*)tifm_get_drvdata(sock));
+	fifo_status = readl(sock->addr + SOCK_DMA_FIFO_STATUS);
+	dev_dbg(&sock->dev, "data event: fifo_status %x, flags %x\n",
+		fifo_status, host->cmd_flags);
 
-	if (sock_irq_status & FIFO_EVENT) {
-		fifo_status = readl(sock->addr + SOCK_DMA_FIFO_STATUS);
-		writel(fifo_status, sock->addr + SOCK_DMA_FIFO_STATUS);
+	if (host->req) {
+		r_data = host->req->cmd->data;
 
-		host->flags |= fifo_status & FIFO_RDY;
+		if (r_data && (fifo_status & TIFM_FIFO_READY)) {
+			if (tifm_sd_set_dma_data(host, r_data)) {
+				host->cmd_flags |= FIFO_READY;
+				tifm_sd_check_status(host);
+			}
+		}
 	}
 
-	if (sock_irq_status & CARD_EVENT) {
-		host_status = readl(sock->addr + SOCK_MMCSD_STATUS);
-		writel(host_status, sock->addr + SOCK_MMCSD_STATUS);
+	writel(fifo_status, sock->addr + SOCK_DMA_FIFO_STATUS);
+	spin_unlock(&sock->lock);
+}
 
-		if (!host->req)
-			goto done;
+/* Called from interrupt handler */
+static void tifm_sd_event(struct tifm_dev *sock)
+{
+	struct tifm_sd *host;
+	unsigned int host_status = 0;
+	int cmd_error = MMC_ERR_NONE;
+	struct mmc_command *cmd = NULL;
+	unsigned long flags;
+
+	spin_lock(&sock->lock);
+	host = mmc_priv((struct mmc_host*)tifm_get_drvdata(sock));
+	host_status = readl(sock->addr + SOCK_MMCSD_STATUS);
+	dev_dbg(&sock->dev, "host event: host_status %x, flags %x\n",
+		host_status, host->cmd_flags);
+
+	if (host->req) {
+		cmd = host->req->cmd;
 
 		if (host_status & TIFM_MMCSD_ERRMASK) {
-			if (host_status & (TIFM_MMCSD_CTO | TIFM_MMCSD_DTO))
-				error_code = MMC_ERR_TIMEOUT;
-			else if (host_status
-				 & (TIFM_MMCSD_CCRC | TIFM_MMCSD_DCRC))
-				error_code = MMC_ERR_BADCRC;
+			writel(host_status & TIFM_MMCSD_ERRMASK,
+			       sock->addr + SOCK_MMCSD_STATUS);
+			if (host_status & TIFM_MMCSD_CTO)
+				cmd_error = MMC_ERR_TIMEOUT;
+			else if (host_status & TIFM_MMCSD_CCRC)
+				cmd_error = MMC_ERR_BADCRC;
+
+			if (cmd->data) {
+				if (host_status & TIFM_MMCSD_DTO)
+					cmd->data->error = MMC_ERR_TIMEOUT;
+				else if (host_status & TIFM_MMCSD_DCRC)
+					cmd->data->error = MMC_ERR_BADCRC;
+			}
 
 			writel(TIFM_FIFO_INT_SETALL,
 			       sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR);
 			writel(TIFM_DMA_RESET, sock->addr + SOCK_DMA_CONTROL);
 
 			if (host->req->stop) {
-				if (host->state == SCMD) {
-					host->req->stop->error = error_code;
-				} else if (host->state == BRS
-					   || host->state == CARD
-					   || host->state == FIFO) {
-					host->req->cmd->error = error_code;
+				if (host->cmd_flags & SCMD_ACTIVE) {
+					host->req->stop->error = cmd_error;
+					host->cmd_flags |= SCMD_READY;
+				} else {
+					cmd->error = cmd_error;
+					host->cmd_flags |= SCMD_ACTIVE;
 					tifm_sd_exec(host, host->req->stop);
-					host->state = SCMD;
 					goto done;
-				} else {
-					host->req->cmd->error = error_code;
 				}
-			} else {
-				host->req->cmd->error = error_code;
+			} else
+				cmd->error = cmd_error;
+		} else {
+			if (host_status & (TIFM_MMCSD_EOC | TIFM_MMCSD_CERR)) {
+				if (!(host->cmd_flags & CMD_READY)) {
+					host->cmd_flags |= CMD_READY;
+					tifm_sd_fetch_resp(cmd, sock);
+				} else if (host->cmd_flags & SCMD_ACTIVE) {
+					host->cmd_flags |= SCMD_READY;
+					tifm_sd_fetch_resp(host->req->stop,
+							   sock);
+				}
 			}
-			host->state = READY;
+			if (host_status & TIFM_MMCSD_BRS)
+				host->cmd_flags |= BRS_READY;
 		}
 
-		if (host_status & TIFM_MMCSD_CB)
-			host->flags |= CARD_BUSY;
-		if ((host_status & TIFM_MMCSD_EOFB)
-		    && (host->flags & CARD_BUSY)) {
-			host->written_blocks++;
-			host->flags &= ~CARD_BUSY;
+		if (host->no_dma && cmd->data) {
+			if (host_status & TIFM_MMCSD_AE)
+				writel(host_status & TIFM_MMCSD_AE,
+				       sock->addr + SOCK_MMCSD_STATUS);
+
+			if (host_status & (TIFM_MMCSD_AE | TIFM_MMCSD_AF
+					   | TIFM_MMCSD_BRS)) {
+				local_irq_save(flags);
+				tifm_sd_transfer_data(host);
+				local_irq_restore(flags);
+				host_status &= ~TIFM_MMCSD_AE;
+			}
 		}
-        }
-
-	if (host->req)
-		tifm_sd_process_cmd(sock, host, host_status);
-done:
-	dev_dbg(&sock->dev, "host_status %x, fifo_status %x\n",
-		host_status, fifo_status);
-	spin_unlock(&sock->lock);
-}
-
-static void tifm_sd_prepare_data(struct tifm_sd *host, struct mmc_command *cmd)
-{
-	struct tifm_dev *sock = host->dev;
-	unsigned int dest_cnt;
 
-	/* DMA style IO */
-	dev_dbg(&sock->dev, "setting dma for %d blocks\n",
-		cmd->data->blocks);
-	writel(TIFM_FIFO_INT_SETALL,
-	       sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR);
-	writel(ilog2(cmd->data->blksz) - 2,
-	       sock->addr + SOCK_FIFO_PAGE_SIZE);
-	writel(TIFM_FIFO_ENABLE, sock->addr + SOCK_FIFO_CONTROL);
-	writel(TIFM_FIFO_INTMASK, sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET);
+		if (host_status & TIFM_MMCSD_EOFB)
+			host->cmd_flags &= ~CARD_BUSY;
+		else if (host_status & TIFM_MMCSD_CB)
+			host->cmd_flags |= CARD_BUSY;
 
-	dest_cnt = (cmd->data->blocks) << 8;
-
-	writel(sg_dma_address(cmd->data->sg), sock->addr + SOCK_DMA_ADDRESS);
-
-	writel(cmd->data->blocks - 1, sock->addr + SOCK_MMCSD_NUM_BLOCKS);
-	writel(cmd->data->blksz - 1, sock->addr + SOCK_MMCSD_BLOCK_LEN);
-
-	if (cmd->data->flags & MMC_DATA_WRITE) {
-		writel(TIFM_MMCSD_TXDE, sock->addr + SOCK_MMCSD_BUFFER_CONFIG);
-		writel(dest_cnt | TIFM_DMA_TX | TIFM_DMA_EN,
-		       sock->addr + SOCK_DMA_CONTROL);
-	} else {
-		writel(TIFM_MMCSD_RXDE, sock->addr + SOCK_MMCSD_BUFFER_CONFIG);
-		writel(dest_cnt | TIFM_DMA_EN, sock->addr + SOCK_DMA_CONTROL);
+		tifm_sd_check_status(host);
 	}
+done:
+	writel(host_status, sock->addr + SOCK_MMCSD_STATUS);
+	spin_unlock(&sock->lock);
 }
 
 static void tifm_sd_set_data_timeout(struct tifm_sd *host,
@@ -451,146 +621,100 @@ static void tifm_sd_request(struct mmc_host *mmc, struct mmc_request *mrq)
 	struct tifm_sd *host = mmc_priv(mmc);
 	struct tifm_dev *sock = host->dev;
 	unsigned long flags;
-	int sg_count = 0;
 	struct mmc_data *r_data = mrq->cmd->data;
 
 	spin_lock_irqsave(&sock->lock, flags);
-	if (host->flags & EJECT) {
+	if (host->eject) {
 		spin_unlock_irqrestore(&sock->lock, flags);
 		goto err_out;
 	}
 
 	if (host->req) {
-		printk(KERN_ERR DRIVER_NAME ": unfinished request detected\n");
+		printk(KERN_ERR "%s : unfinished request detected\n",
+		       sock->dev.bus_id);
 		spin_unlock_irqrestore(&sock->lock, flags);
 		goto err_out;
 	}
 
+	host->cmd_flags = 0;
+	host->block_pos = 0;
+	host->sg_pos = 0;
+
 	if (r_data) {
 		tifm_sd_set_data_timeout(host, r_data);
 
-		sg_count = tifm_map_sg(sock, r_data->sg, r_data->sg_len,
-				       mrq->cmd->flags & MMC_DATA_WRITE
-				       ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
-		if (sg_count != 1) {
-			printk(KERN_ERR DRIVER_NAME
-				": scatterlist map failed\n");
-			spin_unlock_irqrestore(&sock->lock, flags);
-			goto err_out;
-		}
-
-		host->written_blocks = 0;
-		host->flags &= ~CARD_BUSY;
-		tifm_sd_prepare_data(host, mrq->cmd);
-	}
-
-	host->req = mrq;
-	mod_timer(&host->timer, jiffies + host->timeout_jiffies);
-	host->state = CMD;
-	writel(TIFM_CTRL_LED | readl(sock->addr + SOCK_CONTROL),
-	       sock->addr + SOCK_CONTROL);
-	tifm_sd_exec(host, mrq->cmd);
-	spin_unlock_irqrestore(&sock->lock, flags);
-	return;
-
-err_out:
-	if (sg_count > 0)
-		tifm_unmap_sg(sock, r_data->sg, r_data->sg_len,
-			      (r_data->flags & MMC_DATA_WRITE)
-			      ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
-
-	mrq->cmd->error = MMC_ERR_TIMEOUT;
-	mmc_request_done(mmc, mrq);
-}
-
-static void tifm_sd_end_cmd(unsigned long data)
-{
-	struct tifm_sd *host = (struct tifm_sd*)data;
-	struct tifm_dev *sock = host->dev;
-	struct mmc_host *mmc = tifm_get_drvdata(sock);
-	struct mmc_request *mrq;
-	struct mmc_data *r_data = NULL;
-	unsigned long flags;
-
-	spin_lock_irqsave(&sock->lock, flags);
-
-	del_timer(&host->timer);
-	mrq = host->req;
-	host->req = NULL;
-	host->state = IDLE;
+		if ((r_data->flags & MMC_DATA_WRITE) && !mrq->stop)
+			 writel(TIFM_MMCSD_EOFB
+				| readl(sock->addr + SOCK_MMCSD_INT_ENABLE),
+				sock->addr + SOCK_MMCSD_INT_ENABLE);
 
-	if (!mrq) {
-		printk(KERN_ERR DRIVER_NAME ": no request to complete?\n");
-		spin_unlock_irqrestore(&sock->lock, flags);
-		return;
-	}
+		if (host->no_dma) {
+			writel(TIFM_MMCSD_BUFINT
+			       | readl(sock->addr + SOCK_MMCSD_INT_ENABLE),
+			       sock->addr + SOCK_MMCSD_INT_ENABLE);
+			writel(((TIFM_MMCSD_FIFO_SIZE - 1) << 8)
+			       | (TIFM_MMCSD_FIFO_SIZE - 1),
+			       sock->addr + SOCK_MMCSD_BUFFER_CONFIG);
 
-	r_data = mrq->cmd->data;
-	if (r_data) {
-		if (r_data->flags & MMC_DATA_WRITE) {
-			r_data->bytes_xfered = host->written_blocks
-					       * r_data->blksz;
+			host->sg_len = r_data->sg_len;
 		} else {
-			r_data->bytes_xfered = r_data->blocks -
-				readl(sock->addr + SOCK_MMCSD_NUM_BLOCKS) - 1;
-			r_data->bytes_xfered *= r_data->blksz;
-			r_data->bytes_xfered += r_data->blksz -
-				readl(sock->addr + SOCK_MMCSD_BLOCK_LEN) + 1;
-		}
-		tifm_unmap_sg(sock, r_data->sg, r_data->sg_len,
-			      (r_data->flags & MMC_DATA_WRITE)
-			      ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
-	}
-
-	writel((~TIFM_CTRL_LED) & readl(sock->addr + SOCK_CONTROL),
-	       sock->addr + SOCK_CONTROL);
-
-	spin_unlock_irqrestore(&sock->lock, flags);
-	mmc_request_done(mmc, mrq);
-}
-
-static void tifm_sd_request_nodma(struct mmc_host *mmc, struct mmc_request *mrq)
-{
-	struct tifm_sd *host = mmc_priv(mmc);
-	struct tifm_dev *sock = host->dev;
-	unsigned long flags;
-	struct mmc_data *r_data = mrq->cmd->data;
-
-	spin_lock_irqsave(&sock->lock, flags);
-	if (host->flags & EJECT) {
-		spin_unlock_irqrestore(&sock->lock, flags);
-		goto err_out;
-	}
-
-	if (host->req) {
-		printk(KERN_ERR DRIVER_NAME ": unfinished request detected\n");
-		spin_unlock_irqrestore(&sock->lock, flags);
-		goto err_out;
-	}
+			host->bounce_buf.offset
+				= offset_in_page(host->bounce_buf_data);
+			host->bounce_buf.length = r_data->blksz;
+
+			if(1 != tifm_map_sg(sock, &host->bounce_buf, 1,
+					    r_data->flags & MMC_DATA_WRITE
+					    ? PCI_DMA_TODEVICE
+					    : PCI_DMA_FROMDEVICE)) {
+				printk(KERN_ERR "%s : scatterlist map failed\n",
+				       sock->dev.bus_id);
+				spin_unlock_irqrestore(&sock->lock, flags);
+				goto err_out;
+			}
+			host->sg_len = tifm_map_sg(sock, r_data->sg,
+						   r_data->sg_len,
+						   r_data->flags
+						   & MMC_DATA_WRITE
+						   ? PCI_DMA_TODEVICE
+						   : PCI_DMA_FROMDEVICE);
+			if (host->sg_len < 1) {
+				printk(KERN_ERR "%s : scatterlist map failed\n",
+				       sock->dev.bus_id);
+				tifm_unmap_sg(sock, &host->bounce_buf, 1,
+					      r_data->flags & MMC_DATA_WRITE
+					      ? PCI_DMA_TODEVICE
+					      : PCI_DMA_FROMDEVICE);
+				spin_unlock_irqrestore(&sock->lock, flags);
+				goto err_out;
+			}
 
-	if (r_data) {
-		tifm_sd_set_data_timeout(host, r_data);
+			writel(TIFM_FIFO_INT_SETALL,
+			       sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR);
+			writel(ilog2(r_data->blksz) - 2,
+			       sock->addr + SOCK_FIFO_PAGE_SIZE);
+			writel(TIFM_FIFO_ENABLE,
+			       sock->addr + SOCK_FIFO_CONTROL);
+			writel(TIFM_FIFO_INTMASK,
+			       sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET);
+
+			if (r_data->flags & MMC_DATA_WRITE)
+				writel(TIFM_MMCSD_TXDE,
+				       sock->addr + SOCK_MMCSD_BUFFER_CONFIG);
+			else
+				writel(TIFM_MMCSD_RXDE,
+				       sock->addr + SOCK_MMCSD_BUFFER_CONFIG);
+
+			tifm_sd_set_dma_data(host, r_data);
+		}
 
-		host->buffer_size = mrq->cmd->data->blocks
-				    * mrq->cmd->data->blksz;
-
-		writel(TIFM_MMCSD_BUFINT
-		       | readl(sock->addr + SOCK_MMCSD_INT_ENABLE),
-		       sock->addr + SOCK_MMCSD_INT_ENABLE);
-		writel(((TIFM_MMCSD_FIFO_SIZE - 1) << 8)
-		       | (TIFM_MMCSD_FIFO_SIZE - 1),
-		       sock->addr + SOCK_MMCSD_BUFFER_CONFIG);
-
-		host->written_blocks = 0;
-		host->flags &= ~CARD_BUSY;
-		host->buffer_pos = 0;
-		writel(r_data->blocks - 1, sock->addr + SOCK_MMCSD_NUM_BLOCKS);
-		writel(r_data->blksz - 1, sock->addr + SOCK_MMCSD_BLOCK_LEN);
+		writel(r_data->blocks - 1,
+		       sock->addr + SOCK_MMCSD_NUM_BLOCKS);
+		writel(r_data->blksz - 1,
+		       sock->addr + SOCK_MMCSD_BLOCK_LEN);
 	}
 
 	host->req = mrq;
 	mod_timer(&host->timer, jiffies + host->timeout_jiffies);
-	host->state = CMD;
 	writel(TIFM_CTRL_LED | readl(sock->addr + SOCK_CONTROL),
 	       sock->addr + SOCK_CONTROL);
 	tifm_sd_exec(host, mrq->cmd);
@@ -602,7 +726,7 @@ err_out:
 	mmc_request_done(mmc, mrq);
 }
 
-static void tifm_sd_end_cmd_nodma(unsigned long data)
+static void tifm_sd_end_cmd(unsigned long data)
 {
 	struct tifm_sd *host = (struct tifm_sd*)data;
 	struct tifm_dev *sock = host->dev;
@@ -616,68 +740,52 @@ static void tifm_sd_end_cmd_nodma(unsigned long data)
 	del_timer(&host->timer);
 	mrq = host->req;
 	host->req = NULL;
-	host->state = IDLE;
 
 	if (!mrq) {
-		printk(KERN_ERR DRIVER_NAME ": no request to complete?\n");
+		printk(KERN_ERR " %s : no request to complete?\n",
+		       sock->dev.bus_id);
 		spin_unlock_irqrestore(&sock->lock, flags);
 		return;
 	}
 
 	r_data = mrq->cmd->data;
 	if (r_data) {
-		writel((~TIFM_MMCSD_BUFINT) &
-			readl(sock->addr + SOCK_MMCSD_INT_ENABLE),
-			sock->addr + SOCK_MMCSD_INT_ENABLE);
-
-		if (r_data->flags & MMC_DATA_WRITE) {
-			r_data->bytes_xfered = host->written_blocks
-					       * r_data->blksz;
+		if (host->no_dma) {
+			writel((~TIFM_MMCSD_BUFINT)
+			       & readl(sock->addr + SOCK_MMCSD_INT_ENABLE),
+			       sock->addr + SOCK_MMCSD_INT_ENABLE);
 		} else {
-			r_data->bytes_xfered = r_data->blocks -
-				readl(sock->addr + SOCK_MMCSD_NUM_BLOCKS) - 1;
-			r_data->bytes_xfered *= r_data->blksz;
-			r_data->bytes_xfered += r_data->blksz -
-				readl(sock->addr + SOCK_MMCSD_BLOCK_LEN) + 1;
+			tifm_unmap_sg(sock, &host->bounce_buf, 1,
+				      (r_data->flags & MMC_DATA_WRITE)
+				      ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
+			tifm_unmap_sg(sock, r_data->sg, r_data->sg_len,
+				      (r_data->flags & MMC_DATA_WRITE)
+				      ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
 		}
-		host->buffer_pos = 0;
-		host->buffer_size = 0;
+
+		r_data->bytes_xfered = r_data->blocks
+			- readl(sock->addr + SOCK_MMCSD_NUM_BLOCKS) - 1;
+		r_data->bytes_xfered *= r_data->blksz;
+		r_data->bytes_xfered += r_data->blksz
+			- readl(sock->addr + SOCK_MMCSD_BLOCK_LEN) + 1;
 	}
 
 	writel((~TIFM_CTRL_LED) & readl(sock->addr + SOCK_CONTROL),
 	       sock->addr + SOCK_CONTROL);
 
 	spin_unlock_irqrestore(&sock->lock, flags);
-
 	mmc_request_done(mmc, mrq);
 }
 
-static void tifm_sd_terminate(struct tifm_sd *host)
-{
-	struct tifm_dev *sock = host->dev;
-	unsigned long flags;
-
-	writel(0, sock->addr + SOCK_MMCSD_INT_ENABLE);
-	mmiowb();
-	spin_lock_irqsave(&sock->lock, flags);
-	host->flags |= EJECT;
-	if (host->req) {
-		writel(TIFM_FIFO_INT_SETALL,
-		       sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR);
-		writel(0, sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET);
-		tasklet_schedule(&host->finish_tasklet);
-	}
-	spin_unlock_irqrestore(&sock->lock, flags);
-}
-
 static void tifm_sd_abort(unsigned long data)
 {
 	struct tifm_sd *host = (struct tifm_sd*)data;
 
-	printk(KERN_ERR DRIVER_NAME
-	       ": card failed to respond for a long period of time");
+	printk(KERN_ERR
+	       "%s : card failed to respond for a long period of time "
+	       "(%x, %x)\n",
+	       host->dev->dev.bus_id, host->req->cmd->opcode, host->cmd_flags);
 
-	tifm_sd_terminate(host);
 	tifm_eject(host->dev);
 }
 
@@ -690,8 +798,11 @@ static void tifm_sd_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 
 	spin_lock_irqsave(&sock->lock, flags);
 
-	dev_dbg(&sock->dev, "Setting bus width %d, power %d\n", ios->bus_width,
-		ios->power_mode);
+	dev_dbg(&sock->dev, "ios: clock = %u, vdd = %x, bus_mode = %x, "
+		"chip_select = %x, power_mode = %x, bus_width = %x\n",
+		ios->clock, ios->vdd, ios->bus_mode, ios->chip_select,
+		ios->power_mode, ios->bus_width);
+
 	if (ios->bus_width == MMC_BUS_WIDTH_4) {
 		writel(TIFM_MMCSD_4BBUS | readl(sock->addr + SOCK_MMCSD_CONFIG),
 		       sock->addr + SOCK_MMCSD_CONFIG);
@@ -736,41 +847,30 @@ static void tifm_sd_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 		  & readl(sock->addr + SOCK_MMCSD_CONFIG)),
 	       sock->addr + SOCK_MMCSD_CONFIG);
 
-	if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN)
-		host->flags |= OPENDRAIN;
-	else
-		host->flags &= ~OPENDRAIN;
+	host->open_drain = (ios->bus_mode == MMC_BUSMODE_OPENDRAIN);
 
 	/* chip_select : maybe later */
 	//vdd
 	//power is set before probe / after remove
-	//I believe, power_off when already marked for eject is sufficient to
-	// allow removal.
-	if ((host->flags & EJECT) && ios->power_mode == MMC_POWER_OFF) {
-		host->flags |= EJECT_DONE;
-		wake_up_all(&host->notify);
-	}
 
 	spin_unlock_irqrestore(&sock->lock, flags);
 }
 
 static int tifm_sd_ro(struct mmc_host *mmc)
 {
-	int rc;
+	int rc = 0;
 	struct tifm_sd *host = mmc_priv(mmc);
 	struct tifm_dev *sock = host->dev;
 	unsigned long flags;
 
 	spin_lock_irqsave(&sock->lock, flags);
-
-	host->flags |= (CARD_RO & readl(sock->addr + SOCK_PRESENT_STATE));
-	rc = (host->flags & CARD_RO) ? 1 : 0;
-
+	if (TIFM_MMCSD_CARD_RO & readl(sock->addr + SOCK_PRESENT_STATE))
+		rc = 1;
 	spin_unlock_irqrestore(&sock->lock, flags);
 	return rc;
 }
 
-static struct mmc_host_ops tifm_sd_ops = {
+static const struct mmc_host_ops tifm_sd_ops = {
 	.request = tifm_sd_request,
 	.set_ios = tifm_sd_ios,
 	.get_ro  = tifm_sd_ro
@@ -791,7 +891,7 @@ static int tifm_sd_initialize_host(struct tifm_sd *host)
 	       sock->addr + SOCK_MMCSD_CONFIG);
 
 	/* wait up to 0.51 sec for reset */
-	for (rc = 2; rc <= 256; rc <<= 1) {
+	for (rc = 32; rc <= 256; rc <<= 1) {
 		if (1 & readl(sock->addr + SOCK_MMCSD_SYSTEM_STATUS)) {
 			rc = 0;
 			break;
@@ -800,8 +900,8 @@ static int tifm_sd_initialize_host(struct tifm_sd *host)
 	}
 
 	if (rc) {
-		printk(KERN_ERR DRIVER_NAME
-		       ": controller failed to reset\n");
+		printk(KERN_ERR "%s : controller failed to reset\n",
+		       sock->dev.bus_id);
 		return -ENODEV;
 	}
 
@@ -814,8 +914,7 @@ static int tifm_sd_initialize_host(struct tifm_sd *host)
 	writel(64, sock->addr + SOCK_MMCSD_COMMAND_TO);
 	writel(TIFM_MMCSD_INAB, sock->addr + SOCK_MMCSD_COMMAND);
 
-	/* INAB should take much less than reset */
-	for (rc = 1; rc <= 16; rc <<= 1) {
+	for (rc = 16; rc <= 64; rc <<= 1) {
 		host_status = readl(sock->addr + SOCK_MMCSD_STATUS);
 		writel(host_status, sock->addr + SOCK_MMCSD_STATUS);
 		if (!(host_status & TIFM_MMCSD_ERRMASK)
@@ -827,12 +926,14 @@ static int tifm_sd_initialize_host(struct tifm_sd *host)
 	}
 
 	if (rc) {
-		printk(KERN_ERR DRIVER_NAME
-		       ": card not ready - probe failed on initialization\n");
+		printk(KERN_ERR
+		       "%s : card not ready - probe failed on initialization\n",
+		       sock->dev.bus_id);
 		return -ENODEV;
 	}
 
-	writel(TIFM_MMCSD_DATAMASK | TIFM_MMCSD_ERRMASK,
+	writel(TIFM_MMCSD_CERR | TIFM_MMCSD_BRS | TIFM_MMCSD_EOC
+	       | TIFM_MMCSD_ERRMASK,
 	       sock->addr + SOCK_MMCSD_INT_ENABLE);
 	mmiowb();
 
@@ -847,7 +948,8 @@ static int tifm_sd_probe(struct tifm_dev *sock)
 
 	if (!(TIFM_SOCK_STATE_OCCUPIED
 	      & readl(sock->addr + SOCK_PRESENT_STATE))) {
-		printk(KERN_WARNING DRIVER_NAME ": card gone, unexpectedly\n");
+		printk(KERN_WARNING "%s : card gone, unexpectedly\n",
+		       sock->dev.bus_id);
 		return rc;
 	}
 
@@ -856,41 +958,44 @@ static int tifm_sd_probe(struct tifm_dev *sock)
 		return -ENOMEM;
 
 	host = mmc_priv(mmc);
+	host->no_dma = no_dma;
 	tifm_set_drvdata(sock, mmc);
 	host->dev = sock;
 	host->timeout_jiffies = msecs_to_jiffies(1000);
 
-	init_waitqueue_head(&host->notify);
-	tasklet_init(&host->finish_tasklet,
-		     no_dma ? tifm_sd_end_cmd_nodma : tifm_sd_end_cmd,
+	host->bounce_buf.page = virt_to_page(host->bounce_buf_data);
+
+	tasklet_init(&host->finish_tasklet, tifm_sd_end_cmd,
 		     (unsigned long)host);
 	setup_timer(&host->timer, tifm_sd_abort, (unsigned long)host);
 
-	tifm_sd_ops.request = no_dma ? tifm_sd_request_nodma : tifm_sd_request;
 	mmc->ops = &tifm_sd_ops;
 	mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
 	mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE;
 	mmc->f_min = 20000000 / 60;
 	mmc->f_max = 24000000;
-	mmc->max_hw_segs = 1;
-	mmc->max_phys_segs = 1;
-	// limited by DMA counter - it's safer to stick with
-	// block counter has 11 bits though
-	mmc->max_blk_count = 256;
-	// 2k maximum hw block length
+
+	/* Updated to conform to new MMC core code.
+   	 * max_req_size based on original max_sectors value,
+   	 * max_blk_size and max_blk_count based on maximum
+   	 * allowable values */
+	mmc->max_hw_segs = 16;
+	mmc->max_phys_segs = mmc->max_hw_segs;
+	mmc->max_seg_size = 127 * 2048;
+
+	mmc->max_req_size = 127 * 16 * 512; /* 1016 Mbytes */
+	mmc->max_blk_count = 2048; /* limited by DMA counter, 11 bits */
 	mmc->max_blk_size = 2048;
-	mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
-	mmc->max_seg_size = mmc->max_req_size;
-	sock->signal_irq = tifm_sd_signal_irq;
+
+	sock->event = tifm_sd_event;
+	sock->data_event = tifm_sd_data_event;
 	rc = tifm_sd_initialize_host(host);
 
 	if (!rc)
 		rc = mmc_add_host(mmc);
-	if (rc)
-		goto out_free_mmc;
+	if (!rc)
+		return 0;
 
-	return 0;
-out_free_mmc:
 	mmc_free_host(mmc);
 	return rc;
 }
@@ -899,19 +1004,33 @@ static void tifm_sd_remove(struct tifm_dev *sock)
 {
 	struct mmc_host *mmc = tifm_get_drvdata(sock);
 	struct tifm_sd *host = mmc_priv(mmc);
+	unsigned long flags;
 
-	del_timer_sync(&host->timer);
-	tifm_sd_terminate(host);
-	wait_event_timeout(host->notify, host->flags & EJECT_DONE,
-			   host->timeout_jiffies);
 	tasklet_kill(&host->finish_tasklet);
+	spin_lock_irqsave(&sock->lock, flags);
+	host->eject = 1;
+	writel(0, sock->addr + SOCK_MMCSD_INT_ENABLE);
+	mmiowb();
+
+	if (host->req) {
+		writel(TIFM_FIFO_INT_SETALL,
+		       sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR);
+		writel(0, sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET);
+		host->req->cmd->error = MMC_ERR_TIMEOUT;
+		if (host->req->stop)
+			host->req->stop->error = MMC_ERR_TIMEOUT;
+		tasklet_schedule(&host->finish_tasklet);
+	}
+	spin_unlock_irqrestore(&sock->lock, flags);
+	// temporary hack
+	msleep(1000);
 	mmc_remove_host(mmc);
+	dev_dbg(&sock->dev, "after remove\n");
 
 	/* The meaning of the bit majority in this constant is unknown. */
 	writel(0xfff8 & readl(sock->addr + SOCK_CONTROL),
 	       sock->addr + SOCK_CONTROL);
 
-	tifm_set_drvdata(sock, NULL);
 	mmc_free_host(mmc);
 }
 
@@ -933,14 +1052,17 @@ static int tifm_sd_resume(struct tifm_dev *sock)
 {
 	struct mmc_host *mmc = tifm_get_drvdata(sock);
 	struct tifm_sd *host = mmc_priv(mmc);
+	int rc;
 
-	if (sock->media_id != FM_SD
-	    || tifm_sd_initialize_host(host)) {
-		tifm_eject(sock);
-		return 0;
-	} else {
-		return mmc_resume_host(mmc);
-	}
+	rc = tifm_sd_initialize_host(host);
+	dev_dbg(&sock->dev, "resume initialize %d\n", rc);
+
+	if (rc)
+		host->eject = 1;
+	else
+		rc = mmc_resume_host(mmc);
+
+	return rc;
 }
 
 #else
@@ -950,8 +1072,8 @@ static int tifm_sd_resume(struct tifm_dev *sock)
 
 #endif /* CONFIG_PM */
 
-static tifm_media_id tifm_sd_id_tbl[] = {
-	FM_SD, 0
+static struct tifm_device_id tifm_sd_id_tbl[] = {
+	{ TIFM_TYPE_SD }, { }
 };
 
 static struct tifm_driver tifm_sd_driver = {




More information about the kernel-team mailing list