linux-spi.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [patch 0/4 2.6.23-rc2 + mm2-git-mmc] latest MMC-over-SPI support
@ 2007-08-08 16:06 David Brownell
       [not found] ` <200708080906.18993.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
  0 siblings, 1 reply; 35+ messages in thread
From: David Brownell @ 2007-08-08 16:06 UTC (permalink / raw)
  To: Pierre Ossman
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	Mikael Starvik, Hans-Peter Nilsson, Mike Lavender

Same deal as before ... refreshed against the latest git-mmc.patch,
four patches:

 - headers
 - block
 - core
 - mmc_spi host

Differences from the very last patches sent are primarily that this one
includes the lock/unlock changes again (since it's against git-mmc not
against kernel.org), and code for the SDIO stuff is there (ditto).  But
also, a few more of Pierre's comments have kicked in.

I'm hoping this version gets merged into git-mmc.  :)

- Dave


-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems?  Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >>  http://get.splunk.com/

^ permalink raw reply	[flat|nested] 35+ messages in thread

* [patch 1/4 2.6.23-rc2 + mm2-git-mmc] MMC headers learn about SPI
       [not found] ` <200708080906.18993.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
@ 2007-08-08 16:09   ` David Brownell
  2007-08-08 16:10   ` [patch 2/4 2.6.23-rc2 + mm2-git-mmc] MMC/SD card driver learns SPI David Brownell
                     ` (4 subsequent siblings)
  5 siblings, 0 replies; 35+ messages in thread
From: David Brownell @ 2007-08-08 16:09 UTC (permalink / raw)
  To: Pierre Ossman
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	Mikael Starvik, Hans-Peter Nilsson, Mike Lavender

Teach the MMC/SD/SDIO system headers that some hosts use SPI mode

 - New host capabilities and status bits
    * MMC_CAP_SPI, with mmc_host_is_spi() test
    * mmc_host.use_spi_crc flag
 
 - SPI-specific declarations:
    * Response types, MMC_RSP_SPI_R*
    * Two SPI-only commands 
    * Status bits used native to SPI:  R1_SPI_*, R2_SPI_*

 - Fix a few (unrelated) whitespace bugs in the headers.

 - Reorder a few mmc_host fields, removing several bytes of padding

None of these changes affect current code.

Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
---
Against: git-mmc.patch  from 2.6.21-rc1-mm2

 include/linux/mmc/core.h |   26 ++++++++++++++++++++++++--
 include/linux/mmc/host.h |   16 +++++++++++-----
 include/linux/mmc/mmc.h  |   47 +++++++++++++++++++++++++++++++++++++++++------
 3 files changed, 76 insertions(+), 13 deletions(-)

--- g26.orig/include/linux/mmc/host.h	2007-08-08 09:07:48.000000000 -0700
+++ g26/include/linux/mmc/host.h	2007-08-08 09:07:54.000000000 -0700
@@ -92,6 +92,7 @@ struct mmc_host {
 #define MMC_CAP_MMC_HIGHSPEED	(1 << 2)	/* Can do MMC high-speed timing */
 #define MMC_CAP_SD_HIGHSPEED	(1 << 3)	/* Can do SD high-speed timing */
 #define MMC_CAP_SDIO_IRQ	(1 << 4)	/* Can signal pending SDIO IRQs */
+#define MMC_CAP_SPI		(1 << 5)	/* Talks only SPI protocols */
 
 	/* host specific block data */
 	unsigned int		max_seg_size;	/* see blk_queue_max_segment_size */
@@ -108,6 +109,14 @@ struct mmc_host {
 	struct mmc_ios		ios;		/* current io bus settings */
 	u32			ocr;		/* the current OCR setting */
 
+	/* group bitfields together to minimize padding */
+	unsigned int		use_spi_crc:1;
+	unsigned int		claimed:1;	/* host exclusively claimed */
+	unsigned int		bus_dead:1;	/* bus has been released */
+#ifdef CONFIG_MMC_DEBUG
+	unsigned int		removed:1;	/* host is being removed */
+#endif
+
 	unsigned int		mode;		/* current card mode of host */
 #define MMC_MODE_MMC		0
 #define MMC_MODE_SD		1
@@ -115,16 +124,11 @@ struct mmc_host {
 	struct mmc_card		*card;		/* device attached to this host */
 
 	wait_queue_head_t	wq;
-	unsigned int		claimed:1;	/* host exclusively claimed */
 
 	struct delayed_work	detect;
-#ifdef CONFIG_MMC_DEBUG
-	unsigned int		removed:1;	/* host is being removed */
-#endif
 
 	const struct mmc_bus_ops *bus_ops;	/* current bus driver */
 	unsigned int		bus_refs;	/* reference counter */
-	unsigned int		bus_dead:1;	/* bus has been released */
 
 	unsigned int		sdio_irqs;
 	struct task_struct	*sdio_irq_thread;
@@ -143,6 +147,8 @@ static inline void *mmc_priv(struct mmc_
 	return (void *)host->private;
 }
 
+#define mmc_host_is_spi(host)	((host)->caps & MMC_CAP_SPI)
+
 #define mmc_dev(x)	((x)->parent)
 #define mmc_classdev(x)	(&(x)->class_dev)
 #define mmc_hostname(x)	((x)->class_dev.bus_id)
--- g26.orig/include/linux/mmc/core.h	2007-08-08 09:07:48.000000000 -0700
+++ g26/include/linux/mmc/core.h	2007-08-08 09:07:54.000000000 -0700
@@ -25,14 +25,20 @@ struct mmc_command {
 #define MMC_RSP_CRC	(1 << 2)		/* expect valid crc */
 #define MMC_RSP_BUSY	(1 << 3)		/* card may send busy */
 #define MMC_RSP_OPCODE	(1 << 4)		/* response contains opcode */
-#define MMC_CMD_MASK	(3 << 5)		/* command type */
+
+#define MMC_CMD_MASK	(3 << 5)		/* non-SPI command type */
 #define MMC_CMD_AC	(0 << 5)
 #define MMC_CMD_ADTC	(1 << 5)
 #define MMC_CMD_BC	(2 << 5)
 #define MMC_CMD_BCR	(3 << 5)
 
+#define MMC_RSP_SPI_S1	(1 << 7)		/* one status byte */
+#define MMC_RSP_SPI_S2	(1 << 8)		/* second byte */
+#define MMC_RSP_SPI_B4	(1 << 9)		/* four data bytes */
+#define MMC_RSP_SPI_BUSY (1 << 10)		/* card may send busy */
+
 /*
- * These are the response types, and correspond to valid bit
+ * These are the native response types, and correspond to valid bit
  * patterns of the above flags.  One additional valid pattern
  * is all zeros, which means we don't expect a response.
  */
@@ -49,6 +55,22 @@ struct mmc_command {
 #define mmc_resp_type(cmd)	((cmd)->flags & (MMC_RSP_PRESENT|MMC_RSP_136|MMC_RSP_CRC|MMC_RSP_BUSY|MMC_RSP_OPCODE))
 
 /*
+ * These are the SPI response types for MMC, SD, and SDIO cards.
+ * Commands return R1, with maybe more info.  Zero is an error type;
+ * callers must always provide the appropriate MMC_RSP_SPI_Rx flags.
+ */
+#define MMC_RSP_SPI_R1	(MMC_RSP_SPI_S1)
+#define MMC_RSP_SPI_R1B	(MMC_RSP_SPI_S1|MMC_RSP_SPI_BUSY)
+#define MMC_RSP_SPI_R2	(MMC_RSP_SPI_S1|MMC_RSP_SPI_S2)
+#define MMC_RSP_SPI_R3	(MMC_RSP_SPI_S1|MMC_RSP_SPI_B4)
+#define MMC_RSP_SPI_R4	(MMC_RSP_SPI_S1|MMC_RSP_SPI_B4)
+#define MMC_RSP_SPI_R5	(MMC_RSP_SPI_S1|MMC_RSP_SPI_S2)
+#define MMC_RSP_SPI_R7	(MMC_RSP_SPI_S1|MMC_RSP_SPI_B4)
+
+#define mmc_spi_resp_type(cmd)	((cmd)->flags & \
+		(MMC_RSP_SPI_S1|MMC_RSP_SPI_BUSY|MMC_RSP_SPI_S2|MMC_RSP_SPI_B4))
+
+/*
  * These are the command types.
  */
 #define mmc_cmd_type(cmd)	((cmd)->flags & MMC_CMD_MASK)
--- g26.orig/include/linux/mmc/mmc.h	2007-08-08 09:07:48.000000000 -0700
+++ g26/include/linux/mmc/mmc.h	2007-08-08 09:07:54.000000000 -0700
@@ -27,7 +27,7 @@
 
 /* Standard MMC commands (4.1)           type  argument     response */
    /* class 1 */
-#define	MMC_GO_IDLE_STATE         0   /* bc                          */
+#define MMC_GO_IDLE_STATE         0   /* bc                          */
 #define MMC_SEND_OP_COND          1   /* bcr  [31:0] OCR         R3  */
 #define MMC_ALL_SEND_CID          2   /* bcr                     R2  */
 #define MMC_SET_RELATIVE_ADDR     3   /* ac   [31:16] RCA        R1  */
@@ -39,8 +39,10 @@
 #define MMC_SEND_CID             10   /* ac   [31:16] RCA        R2  */
 #define MMC_READ_DAT_UNTIL_STOP  11   /* adtc [31:0] dadr        R1  */
 #define MMC_STOP_TRANSMISSION    12   /* ac                      R1b */
-#define MMC_SEND_STATUS	         13   /* ac   [31:16] RCA        R1  */
+#define MMC_SEND_STATUS          13   /* ac   [31:16] RCA        R1  */
 #define MMC_GO_INACTIVE_STATE    15   /* ac   [31:16] RCA            */
+#define MMC_SPI_READ_OCR         58   /* spi                  spi_R3 */
+#define MMC_SPI_CRC_ON_OFF       59   /* spi  [0:0] flag      spi_R1 */
 
   /* class 2 */
 #define MMC_SET_BLOCKLEN         16   /* ac   [31:0] block len   R1  */
@@ -90,15 +92,15 @@
  */
 
 /*
-  MMC status in R1
+  MMC status in R1, for native mode (SPI bits are different)
   Type
-  	e : error bit
+	e : error bit
 	s : status bit
 	r : detected and set for the actual command response
 	x : detected and set during command execution. the host must poll
             the card by sending status command in order to read these bits.
   Clear condition
-  	a : according to the card state
+	a : according to the card state
 	b : always related to the previous command. Reception of
             a valid command will clear it (with a delay of one command)
 	c : clear by read
@@ -124,10 +126,42 @@
 #define R1_CARD_ECC_DISABLED	(1 << 14)	/* sx, a */
 #define R1_ERASE_RESET		(1 << 13)	/* sr, c */
 #define R1_STATUS(x)            (x & 0xFFFFE000)
-#define R1_CURRENT_STATE(x)    	((x & 0x00001E00) >> 9)	/* sx, b (4 bits) */
+#define R1_CURRENT_STATE(x)	((x & 0x00001E00) >> 9)	/* sx, b (4 bits) */
 #define R1_READY_FOR_DATA	(1 << 8)	/* sx, a */
 #define R1_APP_CMD		(1 << 5)	/* sr, c */
 
+/*
+ * MMC/SD in SPI mode reports R1 status always, and R2 for SEND_STATUS
+ * R1 is the low order byte; R2 is the next highest byte, when present.
+ */
+#define R1_SPI_IDLE		(1 << 0)
+#define R1_SPI_ERASE_RESET	(1 << 1)
+#define R1_SPI_ILLEGAL_COMMAND	(1 << 2)
+#define R1_SPI_COM_CRC		(1 << 3)
+#define R1_SPI_ERASE_SEQ	(1 << 4)
+#define R1_SPI_ADDRESS		(1 << 5)
+#define R1_SPI_PARAMETER	(1 << 6)
+/* R1 bit 7 is always zero */
+#define R2_SPI_CARD_LOCKED	(1 << 8)
+#define R2_SPI_WP_ERASE_SKIP	(1 << 9)	/* or lock/unlock fail */
+#define R2_SPI_LOCK_UNLOCK_FAIL	R2_SPI_WP_ERASE_SKIP
+#define R2_SPI_ERROR		(1 << 10)
+#define R2_SPI_CC_ERROR		(1 << 11)
+#define R2_SPI_CARD_ECC_ERROR	(1 << 12)
+#define R2_SPI_WP_VIOLATION	(1 << 13)
+#define R2_SPI_ERASE_PARAM	(1 << 14)
+#define R2_SPI_OUT_OF_RANGE	(1 << 15)	/* or CSD overwrite */
+#define R2_SPI_CSD_OVERWRITE	R2_SPI_OUT_OF_RANGE
+
+static inline int mmc_status_card_is_locked(struct mmc_host *host, u32 status)
+{
+	if (mmc_host_is_spi(host))
+		return status & R2_SPI_CARD_LOCKED;
+	else
+		return status & R1_CARD_IS_LOCKED;
+}
+
+
 /* These are unpacked versions of the actual responses */
 
 struct _mmc_csd {
@@ -182,6 +216,7 @@ struct _mmc_csd {
  */
 #define CCC_BASIC		(1<<0)	/* (0) Basic protocol functions */
 					/* (CMD0,1,2,3,4,7,9,10,12,13,15) */
+					/* (and for SPI, CMD58,59) */
 #define CCC_STREAM_READ		(1<<1)	/* (1) Stream read commands */
 					/* (CMD11) */
 #define CCC_BLOCK_READ		(1<<2)	/* (2) Block read commands */




-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems?  Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >>  http://get.splunk.com/

^ permalink raw reply	[flat|nested] 35+ messages in thread

* [patch 2/4 2.6.23-rc2 + mm2-git-mmc] MMC/SD card driver learns SPI
       [not found] ` <200708080906.18993.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
  2007-08-08 16:09   ` [patch 1/4 2.6.23-rc2 + mm2-git-mmc] MMC headers learn about SPI David Brownell
@ 2007-08-08 16:10   ` David Brownell
  2007-08-08 16:11   ` [patch 3/4 2.6.23-rc2 + mm2-git-mmc] MMC core learns about SPI David Brownell
                     ` (3 subsequent siblings)
  5 siblings, 0 replies; 35+ messages in thread
From: David Brownell @ 2007-08-08 16:10 UTC (permalink / raw)
  To: Pierre Ossman
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	Mikael Starvik, Hans-Peter Nilsson, Mike Lavender

Teaching the MMC/SD block card driver about SPI.

 - Provide the SPI response type flags with each request issued.

 - Understand that multiblock SPI writes don't use STOP_TRANSMISSION.

 - Correct check for APP_CMD failure.

Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
---
Against: git-mmc.patch  from 2.6.21-rc1-mm2

 drivers/mmc/card/block.c |   23 +++++++++++++++--------
 1 files changed, 15 insertions(+), 8 deletions(-)

--- g26.orig/drivers/mmc/card/block.c	2007-08-08 09:07:48.000000000 -0700
+++ g26/drivers/mmc/card/block.c	2007-08-08 09:07:56.000000000 -0700
@@ -151,17 +151,19 @@ static u32 mmc_sd_num_wr_blocks(struct m
 
 	cmd.opcode = MMC_APP_CMD;
 	cmd.arg = card->rca << 16;
-	cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+	cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
 
 	err = mmc_wait_for_cmd(card->host, &cmd, 0);
-	if (err || !(cmd.resp[0] & R1_APP_CMD))
+	if (err)
+		return (u32)-1;
+	if (!mmc_host_is_spi(card->host) && !(cmd.resp[0] & R1_APP_CMD))
 		return (u32)-1;
 
 	memset(&cmd, 0, sizeof(struct mmc_command));
 
 	cmd.opcode = SD_APP_SEND_NUM_WR_BLKS;
 	cmd.arg = 0;
-	cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+	cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
 
 	memset(&data, 0, sizeof(struct mmc_data));
 
@@ -220,11 +222,11 @@ static int mmc_blk_issue_rq(struct mmc_q
 		brq.cmd.arg = req->sector;
 		if (!mmc_card_blockaddr(card))
 			brq.cmd.arg <<= 9;
-		brq.cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+		brq.cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
 		brq.data.blksz = 1 << md->block_bits;
 		brq.stop.opcode = MMC_STOP_TRANSMISSION;
 		brq.stop.arg = 0;
-		brq.stop.flags = MMC_RSP_R1B | MMC_CMD_AC;
+		brq.stop.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
 		brq.data.blocks = req->nr_sectors >> (md->block_bits - 9);
 		if (brq.data.blocks > card->host->max_blk_count)
 			brq.data.blocks = card->host->max_blk_count;
@@ -241,7 +243,12 @@ static int mmc_blk_issue_rq(struct mmc_q
 			brq.data.blocks = 1;
 
 		if (brq.data.blocks > 1) {
-			brq.mrq.stop = &brq.stop;
+			/* SPI multiblock writes terminate using a special
+			 * token, not a STOP_TRANSMISSION request.
+			 */
+			if (!mmc_host_is_spi(card->host)
+					|| rq_data_dir(req) == READ)
+				brq.mrq.stop = &brq.stop;
 			readcmd = MMC_READ_MULTIPLE_BLOCK;
 			writecmd = MMC_WRITE_MULTIPLE_BLOCK;
 		} else {
@@ -301,7 +308,7 @@ static int mmc_blk_issue_rq(struct mmc_q
 			goto cmd_err;
 		}
 
-		if (rq_data_dir(req) != READ) {
+		if (!mmc_host_is_spi(card->host) && rq_data_dir(req) != READ) {
 			do {
 				int err;
 
@@ -509,7 +516,7 @@ mmc_blk_set_blksize(struct mmc_blk_data 
 	mmc_claim_host(card->host);
 	cmd.opcode = MMC_SET_BLOCKLEN;
 	cmd.arg = 1 << md->block_bits;
-	cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+	cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
 	err = mmc_wait_for_cmd(card->host, &cmd, 5);
 	mmc_release_host(card->host);
 



-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems?  Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >>  http://get.splunk.com/

^ permalink raw reply	[flat|nested] 35+ messages in thread

* [patch 3/4 2.6.23-rc2 + mm2-git-mmc] MMC core learns about SPI
       [not found] ` <200708080906.18993.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
  2007-08-08 16:09   ` [patch 1/4 2.6.23-rc2 + mm2-git-mmc] MMC headers learn about SPI David Brownell
  2007-08-08 16:10   ` [patch 2/4 2.6.23-rc2 + mm2-git-mmc] MMC/SD card driver learns SPI David Brownell
@ 2007-08-08 16:11   ` David Brownell
       [not found]     ` <200708080911.33099.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
  2007-08-08 16:12   ` [patch 4/4 2.6.23-rc2 + mm2-git-mmc] mmc_spi host driver David Brownell
                     ` (2 subsequent siblings)
  5 siblings, 1 reply; 35+ messages in thread
From: David Brownell @ 2007-08-08 16:11 UTC (permalink / raw)
  To: Pierre Ossman
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	Mikael Starvik, Hans-Peter Nilsson, Mike Lavender

Teach the MMC/SD/SDIO core about using SPI mode.

 - Use mmc_host_is_spi() so enumeration works through SPI signaling
   and protocols, not just the native versions.

 - Provide the SPI response type flags with each request issued,
   including requests from the new lock/unlock code.

 - Understand that cmd->resp[0] and mmc_get_status() results for SPI
   return different values than for "native" MMC/SD protocol; this
   affects resetting, checking card lock status, and some others.

 - Understand that some commands act a bit differently ... notably:
     * OP_COND command doesn't return the OCR
     * APP_CMD status doesn't have an R1_APP_CMD analogue

Those changes required some new and updated primitives:

 - Provide utilities to access two SPI-only requests, and one
   request that wasn't previously needed:
     * mmc_spi_read_ocr() ... SPI only
     * mmc_spi_set_crc() ... SPI only (override by module parm)
     * mmc_send_cid() ... for use without broadcast mode

 - Updated internal routines:
     * Previous mmc_send_csd() modified into mmc_send_cxd_native();
       it uses native "R2" responses, which include 16 bytes of data.
     * Previous mmc_send_ext_csd() becomes new mmc_send_cxd_data()
       helper for command-and-data access
     * Bugfix to that mmc_send_cxd_data() code:  dma-to-stack is
       unsafe/nonportable, so kmalloc a bounce buffer instead.

 - Modified mmc_send_ext_csd() now uses mmc_send_cxd_data() helper

 - Modified mmc_send_csd(), and new mmc_spi_send_cid(), routines use
   those helper routines based on whether they're native or SPI

The newest categories of cards supported by the MMC stack aren't expected
to work yet with SPI:  MMC or SD cards with over 4GB data, and SDIO.
All those cards support SPI mode, so eventually they should work too.

Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
---
Against: git-mmc.patch from 2.6.21-rc1-mm2.   Changes since last version:
restore the lock/unlock hooks; SDIO is coded-to-spec.  So it's bigger.

 drivers/mmc/core/core.c     |   39 +++++++--
 drivers/mmc/core/core.h     |    2 
 drivers/mmc/core/mmc.c      |   43 ++++++----
 drivers/mmc/core/mmc_ops.c  |  185 ++++++++++++++++++++++++++++++++++----------
 drivers/mmc/core/mmc_ops.h  |    3 
 drivers/mmc/core/sd.c       |   39 ++++++---
 drivers/mmc/core/sd_ops.c   |   38 ++++++---
 drivers/mmc/core/sdio_ops.c |   49 +++++++----
 8 files changed, 301 insertions(+), 97 deletions(-)

--- g26.orig/drivers/mmc/core/mmc_ops.h	2007-08-08 09:07:48.000000000 -0700
+++ g26/drivers/mmc/core/mmc_ops.h	2007-08-08 09:07:57.000000000 -0700
@@ -25,6 +25,9 @@ int mmc_send_ext_csd(struct mmc_card *ca
 int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value);
 int mmc_send_status(struct mmc_card *card, u32 *status);
 int mmc_lock_unlock(struct mmc_card *card, struct key *key, int mode);
+int mmc_send_cid(struct mmc_host *host, u32 *cid);
+int mmc_spi_read_ocr(struct mmc_host *host, u32 *ocrp);
+int mmc_spi_set_crc(struct mmc_host *host, int use_crc);
 
 #endif
 
--- g26.orig/drivers/mmc/core/core.c	2007-08-08 09:07:48.000000000 -0700
+++ g26/drivers/mmc/core/core.c	2007-08-08 09:07:57.000000000 -0700
@@ -43,6 +43,14 @@ extern int mmc_attach_sdio(struct mmc_ho
 static struct workqueue_struct *workqueue;
 
 /*
+ * Enabling software CRCs on the data blocks can be a significant (30%)
+ * performance cost, and for other reasons may not always be desired.
+ * So we allow it it to be disabled.
+ */
+int use_spi_crc = 1;
+module_param(use_spi_crc, bool, 0);
+
+/*
  * Internal function. Schedule delayed work in the MMC work queue.
  */
 static int mmc_schedule_delayed_work(struct delayed_work *work,
@@ -72,6 +80,11 @@ void mmc_request_done(struct mmc_host *h
 	struct mmc_command *cmd = mrq->cmd;
 	int err = cmd->error;
 
+	if (err && cmd->retries && mmc_host_is_spi(host)) {
+		if (cmd->resp[0] & R1_SPI_ILLEGAL_COMMAND)
+			cmd->retries = 0;
+	}
+
 	if (err && cmd->retries) {
 		pr_debug("%s: req failed (CMD%u): %d, retrying...\n",
 			mmc_hostname(host), cmd->opcode, err);
@@ -445,8 +458,13 @@ static void mmc_power_up(struct mmc_host
 	int bit = fls(host->ocr_avail) - 1;
 
 	host->ios.vdd = bit;
-	host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
-	host->ios.chip_select = MMC_CS_DONTCARE;
+	if (mmc_host_is_spi(host)) {
+		host->ios.chip_select = MMC_CS_HIGH;
+		host->ios.bus_mode = MMC_BUSMODE_PUSHPULL;
+	} else {
+		host->ios.chip_select = MMC_CS_DONTCARE;
+		host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
+	}
 	host->ios.power_mode = MMC_POWER_UP;
 	host->ios.bus_width = MMC_BUS_WIDTH_1;
 	host->ios.timing = MMC_TIMING_LEGACY;
@@ -465,8 +483,10 @@ static void mmc_power_off(struct mmc_hos
 {
 	host->ios.clock = 0;
 	host->ios.vdd = 0;
-	host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
-	host->ios.chip_select = MMC_CS_DONTCARE;
+	if (!mmc_host_is_spi(host)) {
+		host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
+		host->ios.chip_select = MMC_CS_DONTCARE;
+	}
 	host->ios.power_mode = MMC_POWER_OFF;
 	host->ios.bus_width = MMC_BUS_WIDTH_1;
 	host->ios.timing = MMC_TIMING_LEGACY;
@@ -624,17 +644,24 @@ void mmc_rescan(struct work_struct *work
 		 */
 		err = mmc_send_app_op_cond(host, 0, &ocr);
 		if (!err) {
-			if (mmc_attach_sd(host, ocr))
+			if (mmc_host_is_spi(host))
+				err = mmc_spi_read_ocr(host, &ocr);
+			if (err || mmc_attach_sd(host, ocr))
 				mmc_power_off(host);
 			return;
 		}
 
 		/*
 		 * ...and finally MMC.
+		 *
+		 * REVISIT we currently expect that MMC4 cards (4+ GB)
+		 * will fail on SPI hosts.
 		 */
 		err = mmc_send_op_cond(host, 0, &ocr);
 		if (!err) {
-			if (mmc_attach_mmc(host, ocr))
+			if (mmc_host_is_spi(host))
+				err = mmc_spi_read_ocr(host, &ocr);
+			if (err || mmc_attach_mmc(host, ocr))
 				mmc_power_off(host);
 			return;
 		}
--- g26.orig/drivers/mmc/core/mmc_ops.c	2007-08-08 09:07:48.000000000 -0700
+++ g26/drivers/mmc/core/mmc_ops.c	2007-08-08 09:07:57.000000000 -0700
@@ -67,23 +67,36 @@ int mmc_go_idle(struct mmc_host *host)
 	int err;
 	struct mmc_command cmd;
 
-	mmc_set_chip_select(host, MMC_CS_HIGH);
-
-	mmc_delay(1);
+	/*
+	 * Non-SPI hosts need to prevent chipselect going active during
+	 * GO_IDLE; that would put chips into SPI mode.  Remind them of
+	 * that in case of hardware that won't pull up DAT3/nCS otherwise.
+	 *
+	 * SPI hosts ignore ios.chip_select; it's managed according to
+	 * rules that must accomodate non-MMC slaves which this layer
+	 * won't even know about.
+	 */
+	if (!mmc_host_is_spi(host)) {
+		mmc_set_chip_select(host, MMC_CS_HIGH);
+		mmc_delay(1);
+	}
 
 	memset(&cmd, 0, sizeof(struct mmc_command));
 
 	cmd.opcode = MMC_GO_IDLE_STATE;
 	cmd.arg = 0;
-	cmd.flags = MMC_RSP_NONE | MMC_CMD_BC;
+	cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_NONE | MMC_CMD_BC;
 
 	err = mmc_wait_for_cmd(host, &cmd, 0);
 
 	mmc_delay(1);
 
-	mmc_set_chip_select(host, MMC_CS_DONTCARE);
+	if (!mmc_host_is_spi(host)) {
+		mmc_set_chip_select(host, MMC_CS_DONTCARE);
+		mmc_delay(1);
+	}
 
-	mmc_delay(1);
+	host->use_spi_crc = 0;
 
 	return err;
 }
@@ -98,15 +111,19 @@ int mmc_send_op_cond(struct mmc_host *ho
 	memset(&cmd, 0, sizeof(struct mmc_command));
 
 	cmd.opcode = MMC_SEND_OP_COND;
-	cmd.arg = ocr;
-	cmd.flags = MMC_RSP_R3 | MMC_CMD_BCR;
+	cmd.arg = mmc_host_is_spi(host) ? 0 : ocr;
+	cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R3 | MMC_CMD_BCR;
 
 	for (i = 100; i; i--) {
 		err = mmc_wait_for_cmd(host, &cmd, 0);
 		if (err)
 			break;
 
-		if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0)
+		if (mmc_host_is_spi(host)) {
+			/* wait until reset completes */
+			if (!(cmd.resp[0] & R1_SPI_IDLE))
+				break;
+		} else if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0)
 			break;
 
 		err = -ETIMEDOUT;
@@ -114,7 +131,7 @@ int mmc_send_op_cond(struct mmc_host *ho
 		mmc_delay(10);
 	}
 
-	if (rocr)
+	if (rocr && !mmc_host_is_spi(host))
 		*rocr = cmd.resp[0];
 
 	return err;
@@ -164,40 +181,46 @@ int mmc_set_relative_addr(struct mmc_car
 	return 0;
 }
 
-int mmc_send_csd(struct mmc_card *card, u32 *csd)
+static int
+mmc_send_cxd_native(struct mmc_host *host, u32 arg, u32 *cxd, int opcode)
 {
 	int err;
 	struct mmc_command cmd;
 
-	BUG_ON(!card);
-	BUG_ON(!card->host);
-	BUG_ON(!csd);
+	BUG_ON(!host);
+	BUG_ON(!cxd);
 
 	memset(&cmd, 0, sizeof(struct mmc_command));
 
-	cmd.opcode = MMC_SEND_CSD;
-	cmd.arg = card->rca << 16;
+	cmd.opcode = opcode;
+	cmd.arg = arg;
 	cmd.flags = MMC_RSP_R2 | MMC_CMD_AC;
 
-	err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
+	err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
 	if (err)
 		return err;
 
-	memcpy(csd, cmd.resp, sizeof(u32) * 4);
+	memcpy(cxd, cmd.resp, sizeof(u32) * 4);
 
 	return 0;
 }
 
-int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd)
+static int
+mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host,
+		u32 opcode, void *buf, unsigned len)
 {
 	struct mmc_request mrq;
 	struct mmc_command cmd;
 	struct mmc_data data;
 	struct scatterlist sg;
+	void *data_buf;
 
-	BUG_ON(!card);
-	BUG_ON(!card->host);
-	BUG_ON(!ext_csd);
+	/* dma onto stack is unsafe/nonportable, but callers to this
+	 * routine normally provide temporary on-stack buffers ...
+	 */
+	data_buf = kmalloc(len, GFP_KERNEL);
+	if (data_buf == NULL)
+		return -ENOMEM;
 
 	memset(&mrq, 0, sizeof(struct mmc_request));
 	memset(&cmd, 0, sizeof(struct mmc_command));
@@ -206,21 +229,31 @@ int mmc_send_ext_csd(struct mmc_card *ca
 	mrq.cmd = &cmd;
 	mrq.data = &data;
 
-	cmd.opcode = MMC_SEND_EXT_CSD;
+	cmd.opcode = opcode;
 	cmd.arg = 0;
-	cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
 
-	data.blksz = 512;
+	/* NOTE HACK:  the MMC_RSP_SPI_R1 is always correct here, but we
+	 * rely on callers to never use this with "native" calls for reading
+	 * CSD or CID.  Native versions of those commands use the R2 type,
+	 * not R1 plus a data block.
+	 */
+	cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
+
+	data.blksz = len;
 	data.blocks = 1;
 	data.flags = MMC_DATA_READ;
 	data.sg = &sg;
 	data.sg_len = 1;
 
-	sg_init_one(&sg, ext_csd, 512);
+	sg_init_one(&sg, data_buf, len);
 
-	mmc_set_data_timeout(&data, card);
+	if (card)
+		mmc_set_data_timeout(&data, card);
 
-	mmc_wait_for_req(card->host, &mrq);
+	mmc_wait_for_req(host, &mrq);
+
+	memcpy(buf, data_buf, len);
+	kfree(data_buf);
 
 	if (cmd.error)
 		return cmd.error;
@@ -230,6 +263,66 @@ int mmc_send_ext_csd(struct mmc_card *ca
 	return 0;
 }
 
+int mmc_send_csd(struct mmc_card *card, u32 *csd)
+{
+	if (!mmc_host_is_spi(card->host))
+		return mmc_send_cxd_native(card->host, card->rca << 16,
+				csd, MMC_SEND_CSD);
+
+	return mmc_send_cxd_data(card, card->host, MMC_SEND_CSD, csd, 16);
+}
+
+int mmc_send_cid(struct mmc_host *host, u32 *cid)
+{
+	if (!mmc_host_is_spi(host)) {
+		if (!host->card)
+			return -EINVAL;
+		return mmc_send_cxd_native(host, host->card->rca << 16,
+				cid, MMC_SEND_CID);
+	}
+
+	return mmc_send_cxd_data(NULL, host, MMC_SEND_CID, cid, 16);
+}
+
+int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd)
+{
+	return mmc_send_cxd_data(card, card->host, MMC_SEND_EXT_CSD,
+			ext_csd, 512);
+}
+
+int mmc_spi_read_ocr(struct mmc_host *host, u32 *ocrp)
+{
+	struct mmc_command cmd;
+	int err;
+
+	memset(&cmd, 0, sizeof(struct mmc_command));
+
+	cmd.opcode = MMC_SPI_READ_OCR;
+	cmd.flags = MMC_RSP_SPI_R3;
+
+	err = mmc_wait_for_cmd(host, &cmd, 0);
+
+	*ocrp = cmd.resp[1];
+	return err;
+}
+
+int mmc_spi_set_crc(struct mmc_host *host, int use_crc)
+{
+	struct mmc_command cmd;
+	int err;
+
+	memset(&cmd, 0, sizeof(struct mmc_command));
+
+	cmd.opcode = MMC_SPI_CRC_ON_OFF;
+	cmd.flags = MMC_RSP_SPI_R1;
+	cmd.arg = use_crc;
+
+	err = mmc_wait_for_cmd(host, &cmd, 0);
+	if (!err)
+		host->use_spi_crc = use_crc;
+	return err;
+}
+
 int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value)
 {
 	int err;
@@ -245,7 +338,7 @@ int mmc_switch(struct mmc_card *card, u8
 		  (index << 16) |
 		  (value << 8) |
 		  set;
-	cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
+	cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
 
 	err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
 	if (err)
@@ -265,13 +358,17 @@ int mmc_send_status(struct mmc_card *car
 	memset(&cmd, 0, sizeof(struct mmc_command));
 
 	cmd.opcode = MMC_SEND_STATUS;
-	cmd.arg = card->rca << 16;
-	cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+	if (!mmc_host_is_spi(card->host))
+		cmd.arg = card->rca << 16;
+	cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_AC;
 
 	err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
 	if (err)
 		return err;
 
+	/* NOTE: callers are required to understand the difference
+	 * between "native" and SPI format status words!
+	 */
 	if (status)
 		*status = cmd.resp[0];
 
@@ -316,7 +413,7 @@ int mmc_lock_unlock(struct mmc_card *car
 
 	cmd.opcode = MMC_SET_BLOCKLEN;
 	cmd.arg = data_size;
-	cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+	cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
 	err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
 	if (err)
 		goto out;
@@ -325,7 +422,7 @@ int mmc_lock_unlock(struct mmc_card *car
 
 	cmd.opcode = MMC_LOCK_UNLOCK;
 	cmd.arg = 0;
-	cmd.flags = MMC_RSP_R1B | MMC_CMD_ADTC;
+	cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_ADTC;
 
 	memset(&data, 0, sizeof(struct mmc_data));
 
@@ -353,9 +450,16 @@ int mmc_lock_unlock(struct mmc_card *car
 
 	memset(&cmd, 0, sizeof(struct mmc_command));
 
+	/* NOTE:  for SPI, LOCK_UNLOCK definitions seem to vary... MMC
+	 * card docs show it as R1B, and SD cards show it as R1 but with
+	 * no way to tell when operations complete (e.g. forced erase).
+	 * We treat both as R1B, since that makes more sense, and since
+	 * if there are no busy tokens it's the same as R1.  In either
+	 * case, the SPI host won't leave cards busy.
+	 */
 	cmd.opcode = MMC_SEND_STATUS;
 	cmd.arg = card->rca << 16;
-	cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+	cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_AC;
 
 	/* set timeout for forced erase operation to 3 min. (see MMC spec) */
 	erase_timeout = jiffies + 180 * HZ;
@@ -364,7 +468,7 @@ int mmc_lock_unlock(struct mmc_card *car
 		 * R1_LOCK_UNLOCK_FAILED bit is cleared by subsequent reads to
 		 * the status register, hiding the error condition */
 		err = mmc_wait_for_cmd(card->host, &cmd, 0);
-		if (err)
+		if (err || mmc_host_is_spi(card->host))
 			break;
 		/* the other modes don't need timeout checking */
 		if (!(mode & MMC_LOCK_MODE_ERASE))
@@ -374,13 +478,18 @@ int mmc_lock_unlock(struct mmc_card *car
 			err = -ETIMEDOUT;
 			break;
 		}
+		/* NOTE: for SPI, cmd.resp[0] format is different! */
 	} while (!(cmd.resp[0] & R1_READY_FOR_DATA));
-	if (cmd.resp[0] & R1_LOCK_UNLOCK_FAILED) {
+
+	if (cmd.resp[0] & (mmc_host_is_spi(card->host)
+			? R2_SPI_LOCK_UNLOCK_FAIL
+			: R1_LOCK_UNLOCK_FAILED)) {
 		dev_dbg(&card->dev, "LOCK_UNLOCK operation failed\n");
-		err = -EIO;
+		if (!err)
+			err = -EIO;
 	}
 
-	if (cmd.resp[0] & R1_CARD_IS_LOCKED)
+	if (mmc_status_card_is_locked(card->host, cmd.resp[0]))
 		mmc_card_set_locked(card);
 	else
 		card->state &= ~MMC_STATE_LOCKED;
--- g26.orig/drivers/mmc/core/mmc.c	2007-08-08 09:07:48.000000000 -0700
+++ g26/drivers/mmc/core/mmc.c	2007-08-08 09:07:57.000000000 -0700
@@ -166,8 +166,6 @@ static int mmc_read_ext_csd(struct mmc_c
 
 	BUG_ON(!card);
 
-	err = -EIO;
-
 	if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
 		return 0;
 
@@ -282,9 +280,21 @@ static int mmc_init_card(struct mmc_host
 		goto err;
 
 	/*
+	 * For SPI, enable CRC as appropriate.
+	 */
+	if (mmc_host_is_spi(host)) {
+		err = mmc_spi_set_crc(host, use_spi_crc);
+		if (err)
+			goto err;
+	}
+
+	/*
 	 * Fetch CID from card.
 	 */
-	err = mmc_all_send_cid(host, cid);
+	if (mmc_host_is_spi(host))
+		err = mmc_send_cid(host, cid);
+	else
+		err = mmc_all_send_cid(host, cid);
 	if (err)
 		goto err;
 
@@ -311,13 +321,15 @@ static int mmc_init_card(struct mmc_host
 	}
 
 	/*
-	 * Set card RCA.
+	 * For native busses:  set card RCA and quit open drain mode.
 	 */
-	err = mmc_set_relative_addr(card);
-	if (err)
-		goto free_card;
+	if (!mmc_host_is_spi(host)) {
+		err = mmc_set_relative_addr(card);
+		if (err)
+			goto free_card;
 
-	mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL);
+		mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL);
+	}
 
 	/*
 	 * Check if card is locked.
@@ -325,7 +337,7 @@ static int mmc_init_card(struct mmc_host
 	err = mmc_send_status(card, &status);
 	if (err)
 		goto free_card;
-	if (status & R1_CARD_IS_LOCKED)
+	if (mmc_status_card_is_locked(host, status))
 		mmc_card_set_locked(card);
 
 	if (!oldcard) {
@@ -347,13 +359,15 @@ static int mmc_init_card(struct mmc_host
 	/*
 	 * Select card, as all following commands rely on that.
 	 */
-	err = mmc_select_card(card);
-	if (err)
-		goto free_card;
+	if (!mmc_host_is_spi(host)) {
+		err = mmc_select_card(card);
+		if (err)
+			goto free_card;
+	}
 
 	if (!oldcard) {
 		/*
-		 * Fetch and process extened CSD.
+		 * Fetch and process extended CSD.
 		 */
 		err = mmc_read_ext_csd(card);
 		if (err)
@@ -520,7 +534,8 @@ static void mmc_suspend(struct mmc_host 
 	BUG_ON(!host->card);
 
 	mmc_claim_host(host);
-	mmc_deselect_cards(host);
+	if (!mmc_host_is_spi(host))
+		mmc_deselect_cards(host);
 	host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_LOCKED);
 	mmc_release_host(host);
 }
--- g26.orig/drivers/mmc/core/sd.c	2007-08-08 09:07:48.000000000 -0700
+++ g26/drivers/mmc/core/sd.c	2007-08-08 09:07:57.000000000 -0700
@@ -327,9 +327,21 @@ static int mmc_sd_init_card(struct mmc_h
 		goto err;
 
 	/*
+	 * For SPI, enable CRC as appropriate.
+	 */
+	if (mmc_host_is_spi(host)) {
+		err = mmc_spi_set_crc(host, use_spi_crc);
+		if (err)
+			goto err;
+	}
+
+	/*
 	 * Fetch CID from card.
 	 */
-	err = mmc_all_send_cid(host, cid);
+	if (mmc_host_is_spi(host))
+		err = mmc_send_cid(host, cid);
+	else
+		err = mmc_all_send_cid(host, cid);
 	if (err)
 		goto err;
 
@@ -355,13 +367,15 @@ static int mmc_sd_init_card(struct mmc_h
 	}
 
 	/*
-	 * Set card RCA.
+	 * For native busses:  get card RCA and quit open drain mode.
 	 */
-	err = mmc_send_relative_addr(host, &card->rca);
-	if (err)
-		goto free_card;
+	if (!mmc_host_is_spi(host)) {
+		err = mmc_send_relative_addr(host, &card->rca);
+		if (err)
+			goto free_card;
 
-	mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL);
+		mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL);
+	}
 
 	/*
 	 * Check if card is locked.
@@ -369,7 +383,7 @@ static int mmc_sd_init_card(struct mmc_h
 	err = mmc_send_status(card, &status);
 	if (err)
 		goto free_card;
-	if (status & R1_CARD_IS_LOCKED)
+	if (mmc_status_card_is_locked(host, status))
 		mmc_card_set_locked(card);
 
 	if (!oldcard) {
@@ -390,9 +404,11 @@ static int mmc_sd_init_card(struct mmc_h
 	/*
 	 * Select card, as all following commands rely on that.
 	 */
-	err = mmc_select_card(card);
-	if (err)
-		goto free_card;
+	if (!mmc_host_is_spi(host)) {
+		err = mmc_select_card(card);
+		if (err)
+			goto free_card;
+	}
 
 	if (!oldcard) {
 		/*
@@ -582,7 +598,8 @@ static void mmc_sd_suspend(struct mmc_ho
 	BUG_ON(!host->card);
 
 	mmc_claim_host(host);
-	mmc_deselect_cards(host);
+	if (!mmc_host_is_spi(host))
+		mmc_deselect_cards(host);
 	host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_LOCKED);
 	mmc_release_host(host);
 }
--- g26.orig/drivers/mmc/core/sd_ops.c	2007-08-08 09:07:48.000000000 -0700
+++ g26/drivers/mmc/core/sd_ops.c	2007-08-08 09:07:57.000000000 -0700
@@ -33,10 +33,10 @@ static int mmc_app_cmd(struct mmc_host *
 
 	if (card) {
 		cmd.arg = card->rca << 16;
-		cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+		cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
 	} else {
 		cmd.arg = 0;
-		cmd.flags = MMC_RSP_R1 | MMC_CMD_BCR;
+		cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_BCR;
 	}
 
 	err = mmc_wait_for_cmd(host, &cmd, 0);
@@ -44,7 +44,7 @@ static int mmc_app_cmd(struct mmc_host *
 		return err;
 
 	/* Check that card supported application commands */
-	if (!(cmd.resp[0] & R1_APP_CMD))
+	if (!mmc_host_is_spi(host) && !(cmd.resp[0] & R1_APP_CMD))
 		return -EOPNOTSUPP;
 
 	return 0;
@@ -83,8 +83,14 @@ int mmc_wait_for_app_cmd(struct mmc_host
 		memset(&mrq, 0, sizeof(struct mmc_request));
 
 		err = mmc_app_cmd(host, card);
-		if (err)
+		if (err) {
+			/* no point in retrying; no APP commands allowed */
+			if (mmc_host_is_spi(host)) {
+				if (cmd->resp[0] & R1_SPI_ILLEGAL_COMMAND)
+					break;
+			}
 			continue;
+		}
 
 		memset(&mrq, 0, sizeof(struct mmc_request));
 
@@ -99,6 +105,12 @@ int mmc_wait_for_app_cmd(struct mmc_host
 		err = cmd->error;
 		if (!cmd->error)
 			break;
+
+		/* no point in retrying illegal APP commands */
+		if (mmc_host_is_spi(host)) {
+			if (cmd->resp[0] & R1_SPI_ILLEGAL_COMMAND)
+				break;
+		}
 	}
 
 	return err;
@@ -148,14 +160,18 @@ int mmc_send_app_op_cond(struct mmc_host
 
 	cmd.opcode = SD_APP_OP_COND;
 	cmd.arg = ocr;
-	cmd.flags = MMC_RSP_R3 | MMC_CMD_BCR;
+	cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R3 | MMC_CMD_BCR;
 
 	for (i = 100; i; i--) {
 		err = mmc_wait_for_app_cmd(host, NULL, &cmd, MMC_CMD_RETRIES);
 		if (err)
 			break;
 
-		if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0)
+		if (mmc_host_is_spi(host)) {
+			/* wait until reset completes */
+			if (!(cmd.resp[0] & R1_SPI_IDLE))
+				break;
+		} else if ((cmd.resp[0] & MMC_CARD_BUSY) || ocr == 0)
 			break;
 
 		err = -ETIMEDOUT;
@@ -182,7 +198,7 @@ int mmc_send_if_cond(struct mmc_host *ho
 	 */
 	cmd.opcode = SD_SEND_IF_COND;
 	cmd.arg = ((ocr & 0xFF8000) != 0) << 8 | test_pattern;
-	cmd.flags = MMC_RSP_R7 | MMC_CMD_BCR;
+	cmd.flags = MMC_RSP_SPI_R7 | MMC_RSP_R7 | MMC_CMD_BCR;
 
 	err = mmc_wait_for_cmd(host, &cmd, 0);
 	if (err)
@@ -229,6 +245,8 @@ int mmc_app_send_scr(struct mmc_card *ca
 	BUG_ON(!card->host);
 	BUG_ON(!scr);
 
+	/* NOTE: caller guarantees scr is heap-allocated */
+
 	err = mmc_app_cmd(card->host, card);
 	if (err)
 		return err;
@@ -242,7 +260,7 @@ int mmc_app_send_scr(struct mmc_card *ca
 
 	cmd.opcode = SD_APP_SEND_SCR;
 	cmd.arg = 0;
-	cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+	cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
 
 	data.blksz = 8;
 	data.blocks = 1;
@@ -278,6 +296,8 @@ int mmc_sd_switch(struct mmc_card *card,
 	BUG_ON(!card);
 	BUG_ON(!card->host);
 
+	/* NOTE: caller guarantees resp is heap-allocated */
+
 	mode = !!mode;
 	value &= 0xF;
 
@@ -292,7 +312,7 @@ int mmc_sd_switch(struct mmc_card *card,
 	cmd.arg = mode << 31 | 0x00FFFFFF;
 	cmd.arg &= ~(0xF << (group * 4));
 	cmd.arg |= value << (group * 4);
-	cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+	cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
 
 	data.blksz = 64;
 	data.blocks = 1;
--- g26.orig/drivers/mmc/core/core.h	2007-08-08 09:07:48.000000000 -0700
+++ g26/drivers/mmc/core/core.h	2007-08-08 09:07:57.000000000 -0700
@@ -48,5 +48,7 @@ void mmc_rescan(struct work_struct *work
 void mmc_start_host(struct mmc_host *host);
 void mmc_stop_host(struct mmc_host *host);
 
+extern int use_spi_crc;
+
 #endif
 
--- g26.orig/drivers/mmc/core/sdio_ops.c	2007-08-08 09:07:48.000000000 -0700
+++ g26/drivers/mmc/core/sdio_ops.c	2007-08-08 09:07:57.000000000 -0700
@@ -30,14 +30,18 @@ int mmc_send_io_op_cond(struct mmc_host 
 
 	cmd.opcode = SD_IO_SEND_OP_COND;
 	cmd.arg = ocr;
-	cmd.flags = MMC_RSP_R4 | MMC_CMD_BCR;
+	cmd.flags = MMC_RSP_SPI_R4 | MMC_RSP_R4 | MMC_CMD_BCR;
 
 	for (i = 100; i; i--) {
 		err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
 		if (err)
 			break;
 
-		if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0)
+		if (mmc_host_is_spi(host)) {
+			/* wait until reset completes */
+			if (!(cmd.resp[0] & R1_SPI_IDLE))
+				break;
+		} else if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0)
 			break;
 
 		err = -ETIMEDOUT;
@@ -46,7 +50,7 @@ int mmc_send_io_op_cond(struct mmc_host 
 	}
 
 	if (rocr)
-		*rocr = cmd.resp[0];
+		*rocr = cmd.resp[mmc_host_is_spi(host) ? 1 : 0];
 
 	return err;
 }
@@ -68,21 +72,26 @@ int mmc_io_rw_direct(struct mmc_card *ca
 	cmd.arg |= (write && out) ? 0x08000000 : 0x00000000;
 	cmd.arg |= addr << 9;
 	cmd.arg |= in;
-	cmd.flags = MMC_RSP_R5 | MMC_CMD_AC;
+	cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_AC;
 
 	err = mmc_wait_for_cmd(card->host, &cmd, 0);
 	if (err)
 		return err;
 
-	if (cmd.resp[0] & R5_ERROR)
-		return -EIO;
-	if (cmd.resp[0] & R5_FUNCTION_NUMBER)
-		return -EINVAL;
-	if (cmd.resp[0] & R5_OUT_OF_RANGE)
-		return -ERANGE;
+	if (mmc_host_is_spi(card->host)) {
+		if (out)
+			*out = (cmd.resp[0] >> 8) & 0xFF;
+	} else {
+		if (cmd.resp[0] & R5_ERROR)
+			return -EIO;
+		if (cmd.resp[0] & R5_FUNCTION_NUMBER)
+			return -EINVAL;
+		if (cmd.resp[0] & R5_OUT_OF_RANGE)
+			return -ERANGE;
 
-	if (out)
-		*out = cmd.resp[0] & 0xFF;
+		if (out)
+			*out = cmd.resp[0] & 0xFF;
+	}
 
 	return 0;
 }
@@ -112,7 +121,7 @@ int mmc_io_rw_extended(struct mmc_card *
 	cmd.arg |= bang ? 0x00000000 : 0x04000000;
 	cmd.arg |= addr << 9;
 	cmd.arg |= (size == 512) ? 0 : size;
-	cmd.flags = MMC_RSP_R5 | MMC_CMD_ADTC;
+	cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_ADTC;
 
 	data.blksz = size;
 	data.blocks = 1;
@@ -131,12 +140,14 @@ int mmc_io_rw_extended(struct mmc_card *
 	if (data.error)
 		return data.error;
 
-	if (cmd.resp[0] & R5_ERROR)
-		return -EIO;
-	if (cmd.resp[0] & R5_FUNCTION_NUMBER)
-		return -EINVAL;
-	if (cmd.resp[0] & R5_OUT_OF_RANGE)
-		return -ERANGE;
+	if (!mmc_host_is_spi(card->host)) {
+		if (cmd.resp[0] & R5_ERROR)
+			return -EIO;
+		if (cmd.resp[0] & R5_FUNCTION_NUMBER)
+			return -EINVAL;
+		if (cmd.resp[0] & R5_OUT_OF_RANGE)
+			return -ERANGE;
+	}
 
 	return 0;
 }



-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems?  Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >>  http://get.splunk.com/

^ permalink raw reply	[flat|nested] 35+ messages in thread

* [patch 4/4 2.6.23-rc2 + mm2-git-mmc] mmc_spi host driver
       [not found] ` <200708080906.18993.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
                     ` (2 preceding siblings ...)
  2007-08-08 16:11   ` [patch 3/4 2.6.23-rc2 + mm2-git-mmc] MMC core learns about SPI David Brownell
@ 2007-08-08 16:12   ` David Brownell
       [not found]     ` <200708080912.54918.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
  2007-08-09 10:45   ` [patch 0/4 2.6.23-rc2 + mm2-git-mmc] latest MMC-over-SPI support Anton Vorontsov
  2007-08-09 13:05   ` Pierre Ossman
  5 siblings, 1 reply; 35+ messages in thread
From: David Brownell @ 2007-08-08 16:12 UTC (permalink / raw)
  To: Pierre Ossman
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	Mikael Starvik, Hans-Peter Nilsson, Mike Lavender

This is the latest version of the MMC-over-SPI support.  It works
on 2.6.23-rc2 plus git-mmc (from rc1-mm2), along with the preceding
patches which teach the rest of the MMC stack about SPI.

The main issue of note is that sometimes cards need to be power cycled
to recover after certain faults.  Also, it may sometimes be necessary
to disable CRCs.  ("modprobe mmc_core use_spi_crc=n")

Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
Cc: mikael.starvik-VrBV9hrLPhE@public.gmane.org,
Cc: Hans-Peter Nilsson <hp-VrBV9hrLPhE@public.gmane.org>
Cc: Jan Nikitenko <jan.nikitenko-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Cc: Mike Lavender <mike-UTnDXsALFwNjMdQLN6DIHgC/G2K4zDHf@public.gmane.org>
---
 drivers/mmc/host/Kconfig    |   13 
 drivers/mmc/host/Makefile   |    1 
 drivers/mmc/host/mmc_spi.c  | 1398 ++++++++++++++++++++++++++++++++++++++++++++
 include/linux/spi/mmc_spi.h |   33 +
 4 files changed, 1445 insertions(+)

--- g26.orig/drivers/mmc/host/Kconfig	2007-08-08 09:07:48.000000000 -0700
+++ g26/drivers/mmc/host/Kconfig	2007-08-08 09:07:59.000000000 -0700
@@ -100,3 +100,16 @@ config MMC_TIFM_SD
           To compile this driver as a module, choose M here: the
 	  module will be called tifm_sd.
 
+config MMC_SPI
+	tristate "MMC/SD over SPI (EXPERIMENTAL)"
+	depends on MMC && SPI_MASTER && !HIGHMEM && EXPERIMENTAL
+	select CRC7
+	select CRC_ITU_T
+	help
+	  Some systems accss MMC/SD cards using a SPI controller instead of
+	  using a "native" MMC/SD controller.  This has a disadvantage of
+	  being relatively high overhead, but a compensating advantage of
+	  working on many systems without dedicated MMC/SD controllers.
+
+	  If unsure, or if your system has no SPI master driver, say N.
+
--- g26.orig/drivers/mmc/host/Makefile	2007-08-08 09:07:48.000000000 -0700
+++ g26/drivers/mmc/host/Makefile	2007-08-08 09:07:59.000000000 -0700
@@ -15,4 +15,5 @@ obj-$(CONFIG_MMC_AU1X)		+= au1xmmc.o
 obj-$(CONFIG_MMC_OMAP)		+= omap.o
 obj-$(CONFIG_MMC_AT91)		+= at91_mci.o
 obj-$(CONFIG_MMC_TIFM_SD)	+= tifm_sd.o
+obj-$(CONFIG_MMC_SPI)		+= mmc_spi.o
 
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ g26/include/linux/spi/mmc_spi.h	2007-08-08 09:07:59.000000000 -0700
@@ -0,0 +1,33 @@
+#ifndef __LINUX_SPI_MMC_SPI_H
+#define __LINUX_SPI_MMC_SPI_H
+
+struct device;
+struct mmc_host;
+
+/* Put this in platform_data of a device being used to manage an MMC/SD
+ * card slot.  (Modeled after PXA mmc glue; see that for usage examples.)
+ *
+ * REVISIT This is not a spi-specific notion.  Any card slot should be
+ * able to handle it.  If the MMC core doesn't adopt this kind of notion,
+ * switch the "struct device *" parameters over to "struct spi_device *".
+ */
+struct mmc_spi_platform_data {
+	/* driver activation and (optional) card detect irq hookup */
+	int (*init)(struct device *,
+		irqreturn_t (*)(int, void *),
+		void *);
+	void (*exit)(struct device *, void *);
+
+	/* sense switch on sd cards */
+	int (*get_ro)(struct device *);
+
+	/* how long to debounce card detect, in msecs */
+	u16 detect_delay;
+
+	/* power management */
+	u16 powerup_msecs;		/* delay of up to 250 msec */
+	u32 ocr_mask;			/* available voltages */
+	void (*setpower)(struct device *, unsigned int maskval);
+};
+
+#endif /* __LINUX_SPI_MMC_SPI_H */
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ g26/drivers/mmc/host/mmc_spi.c	2007-08-08 09:07:59.000000000 -0700
@@ -0,0 +1,1398 @@
+/*
+ * mmc_spi.c - Access SD/MMC cards through SPI master controllers
+ *
+ * (C) Copyright 2005, Intec Automation,
+ *		Mike Lavender (mike@steroidmicros)
+ * (C) Copyright 2006-2007, David Brownell
+ * (C) Copyright 2007, Axis Communications,
+ *		Hans-Peter Nilsson (hp-VrBV9hrLPhE@public.gmane.org)
+ * (C) Copyright 2007, ATRON electronic GmbH,
+ *		Jan Nikitenko <jan.nikitenko-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/hrtimer.h>
+#include <linux/delay.h>
+#include <linux/blkdev.h>
+#include <linux/dma-mapping.h>
+#include <linux/crc7.h>
+#include <linux/crc-itu-t.h>
+
+#include <linux/mmc/host.h>
+#include <linux/mmc/mmc.h>		/* for R1_SPI_* bit values */
+
+#include <linux/spi/spi.h>
+#include <linux/spi/mmc_spi.h>
+
+#include <asm/unaligned.h>
+
+
+/* NOTES:
+ *
+ * - For now, we won't try to interoperate with a real mmc/sd/sdio
+ *   controller, although some of them do have hardware support for
+ *   SPI protocol.  The main reason for such configs would be mmc-ish
+ *   cards like DataFlash, which don't support that "native" protocol.
+ *
+ *   We don't have a "DataFlash/MMC/SD/SDIO card slot" abstraction to
+ *   switch between driver stacks, and in any case if "native" mode
+ *   is available, it will be faster and hence preferable.
+ *
+ * - MMC depends on a different chipselect management policy than the
+ *   SPI interface currently supports for shared bus segments:  it needs
+ *   to issue multiple spi_message requests with the chipselect active,
+ *   using the results of one message to decide the next one to issue.
+ *
+ *   Pending updates to the programming interface, this driver expects
+ *   that it not share the bus with other drivers (precluding conflicts).
+ *
+ * - We tell the controller to keep the chipselect active from the
+ *   beginning of an mmc_host_ops.request until the end.  So beware
+ *   of SPI controller drivers that mis-handle the cs_change flag!
+ *
+ *   However, many cards seem OK with chipselect flapping up/down
+ *   during that time ... at least on unshared bus segments.
+ */
+
+
+/*
+ * Local protocol constants, internal to data block protocols.
+ */
+
+/* Response tokens used to ack each block written: */
+#define SPI_MMC_RESPONSE_CODE(x)	((x) & 0x1f)
+#define SPI_RESPONSE_ACCEPTED		((2 << 1)|1)
+#define SPI_RESPONSE_CRC_ERR		((5 << 1)|1)
+#define SPI_RESPONSE_WRITE_ERR		((6 << 1)|1)
+
+/* Read and write blocks start with these tokens and end with crc;
+ * on error, read tokens act like a subset of R2_SPI_* values.
+ */
+#define SPI_TOKEN_SINGLE	0xfe	/* single block r/w, multiblock read */
+#define SPI_TOKEN_MULTI_WRITE	0xfc	/* multiblock write */
+#define SPI_TOKEN_STOP_TRAN	0xfd	/* terminate multiblock write */
+
+#define MMC_SPI_BLOCKSIZE	512
+
+
+/* These fixed timeouts come from the latest SD specs, which say to ignore
+ * the CSD values.  The R1B value is for card erase (e.g. the "I forgot the
+ * card's password" scenario); it's mostly applied to STOP_TRANSMISSION after
+ * reads which takes nowhere near that long.  Older cards may be able to use
+ * shorter timeouts ... but why bother?
+ */
+#define readblock_timeout	ktime_set(0, 100 * 1000 * 1000)
+#define writeblock_timeout	ktime_set(0, 250 * 1000 * 1000)
+#define r1b_timeout		ktime_set(3, 0)
+
+
+/****************************************************************************/
+
+/*
+ * Local Data Structures
+ */
+
+/* "scratch" is per-{command,block} data exchanged with the card */
+struct scratch {
+	u8			status[29];
+	u8			data_token;
+	__be16			crc_val;
+};
+
+struct mmc_spi_host {
+	struct mmc_host		*mmc;
+	struct spi_device	*spi;
+
+	unsigned char		power_mode;
+	u16			powerup_msecs;
+
+	struct mmc_spi_platform_data	*pdata;
+
+	/* for bulk data transfers */
+	struct spi_transfer	token, t, crc, early_status;
+	struct spi_message	m;
+
+	/* for status readback */
+	struct spi_transfer	status;
+	struct spi_message	readback;
+
+	/* underlying DMA-aware controller, or null */
+	struct device		*dma_dev;
+
+	/* buffer used for commands and for message "overhead" */
+	struct scratch		*data;
+	dma_addr_t		data_dma;
+
+	/* Specs say to write ones most of the time, even when the card
+	 * has no need to read its input data; and many cards won't care.
+	 * This is our source of those ones.
+	 */
+	void			*ones;
+	dma_addr_t		ones_dma;
+};
+
+
+/****************************************************************************/
+
+/*
+ * MMC-over-SPI protocol glue, used by the MMC stack interface
+ */
+
+static inline int mmc_cs_off(struct mmc_spi_host *host)
+{
+	/* chipselect will always be inactive after setup() */
+	return spi_setup(host->spi);
+}
+
+static int
+mmc_spi_readbytes(struct mmc_spi_host *host, unsigned len)
+{
+	int status;
+
+	if (len > sizeof(*host->data)) {
+		WARN_ON(1);
+		return -EIO;
+	}
+
+	host->status.len = len;
+
+	if (host->dma_dev)
+		dma_sync_single_for_device(host->dma_dev,
+				host->data_dma, sizeof(*host->data),
+				DMA_FROM_DEVICE);
+
+	status = spi_sync(host->spi, &host->readback);
+	if (status == 0)
+		status = host->readback.status;
+
+	if (host->dma_dev)
+		dma_sync_single_for_cpu(host->dma_dev,
+				host->data_dma, sizeof(*host->data),
+				DMA_FROM_DEVICE);
+
+	return status;
+}
+
+static int
+mmc_spi_skip(struct mmc_spi_host *host, ktime_t timeout, unsigned n, u8 byte)
+{
+	u8		*cp = host->data->status;
+
+	timeout = ktime_add(timeout, ktime_get());
+
+	while (1) {
+		int		status;
+		unsigned	i;
+
+		status = mmc_spi_readbytes(host, n);
+		if (status < 0)
+			return status;
+
+		for (i = 0; i < n; i++) {
+			if (cp[i] != byte)
+				return cp[i];
+		}
+
+		/* REVISIT investigate msleep() to avoid busy-wait I/O
+		 * in at least some cases.
+		 */
+		if (ktime_to_ns(ktime_sub(ktime_get(), timeout)) > 0)
+			break;
+	}
+	return -ETIMEDOUT;
+}
+
+static inline int
+mmc_spi_wait_unbusy(struct mmc_spi_host *host, ktime_t timeout)
+{
+	return mmc_spi_skip(host, timeout, sizeof(host->data->status), 0);
+}
+
+static int mmc_spi_readtoken(struct mmc_spi_host *host)
+{
+	return mmc_spi_skip(host, readblock_timeout, 1, 0xff);
+}
+
+
+/*
+ * Note that for SPI, cmd->resp[0] is not the same data as "native" protocol
+ * hosts return!  The low byte holds R1_SPI bits.  The next byte may hold
+ * R2_SPI bits ... for SEND_STATUS, or after data read errors.
+ *
+ * cmd->resp[1] holds any four-byte response, for R3 (READ_OCR) and on
+ * newer cards R7 (IF_COND).
+ */
+
+static char *maptype(struct mmc_command *cmd)
+{
+	switch (mmc_spi_resp_type(cmd)) {
+	case MMC_RSP_SPI_R1:	return "R1";
+	case MMC_RSP_SPI_R1B:	return "R1B";
+	case MMC_RSP_SPI_R2:	return "R2/R5";
+	case MMC_RSP_SPI_R3:	return "R3/R4/R7";
+	default:		return "?";
+	}
+}
+
+/* return zero, else negative errno after setting cmd->error */
+static int mmc_spi_response_get(struct mmc_spi_host *host,
+		struct mmc_command *cmd, int cs_on)
+{
+	u8	*cp = host->data->status;
+	u8	*end = cp + host->t.len;
+	int	value = 0;
+	char	tag[32];
+
+	snprintf(tag, sizeof(tag), "  ... CMD%d response SPI_%s",
+		cmd->opcode, maptype(cmd));
+
+	/* Except for data block reads, the whole response will already
+	 * be stored in the scratch buffer.  It's somewhere after the
+	 * command and the first byte we read after it.  We ignore that
+	 * first byte.  After STOP_TRANSMISSION command it may include
+	 * two data bits, but otherwise it's all ones.
+	 */
+	cp += 8;
+	while (cp < end && *cp == 0xff)
+		cp++;
+
+	/* Data block reads (R1 response types) may need more data... */
+	if (cp == end) {
+		unsigned	i;
+
+		cp = host->data->status;
+
+		/* Card sends N(CR) (== 1..8) bytes of all-ones then one
+		 * status byte ... and we already scanned 2 bytes.
+		 *
+		 * REVISIT block read paths use nasty byte-at-a-time I/O
+		 * so it can always DMA directly into the target buffer.
+		 * It'd probably be better to memcpy() the first chunk and
+		 * avoid extra i/o calls...
+		 */
+		for (i = 2; i < 9; i++) {
+			value = mmc_spi_readbytes(host, 1);
+			if (value < 0)
+				goto done;
+			if (*cp != 0xff)
+				goto checkstatus;
+		}
+		value = -ETIMEDOUT;
+		goto done;
+	}
+
+checkstatus:
+	if (*cp & 0x80) {
+		dev_dbg(&host->spi->dev, "%s: INVALID RESPONSE, %02x\n",
+					tag, *cp);
+		value = -EBADR;
+		goto done;
+	}
+
+	cmd->resp[0] = *cp++;
+	cmd->error = 0;
+
+	/* Status byte: the entire seven-bit R1 response.  */
+	if (cmd->resp[0] != 0) {
+		if ((R1_SPI_PARAMETER | R1_SPI_ADDRESS
+					| R1_SPI_ILLEGAL_COMMAND)
+				& cmd->resp[0])
+			value = -EINVAL;
+		else if (R1_SPI_COM_CRC & cmd->resp[0])
+			value = -EILSEQ;
+		else if ((R1_SPI_ERASE_SEQ | R1_SPI_ERASE_RESET)
+				& cmd->resp[0])
+			value = -EIO;
+		/* else R1_SPI_IDLE, "it's resetting" */
+	}
+
+	switch (mmc_spi_resp_type(cmd)) {
+
+	/* SPI R1B == R1 + busy; STOP_TRANSMISSION (for multiblock reads)
+	 * and less-common stuff like various erase operations.
+	 */
+	case MMC_RSP_SPI_R1B:
+		/* maybe we read all the busy tokens already */
+		while (cp < end && *cp == 0)
+			cp++;
+		if (cp == end)
+			mmc_spi_wait_unbusy(host, r1b_timeout);
+		break;
+
+	/* SPI R2 == R1 + second status byte; SEND_STATUS
+	 * SPI R5 == R1 + data byte; IO_RW_DIRECT
+	 */
+	case MMC_RSP_SPI_R2:
+		cmd->resp[0] |= *cp << 8;
+		break;
+
+	/* SPI R3, R4, or R7 == R1 + 4 bytes */
+	case MMC_RSP_SPI_R3:
+		cmd->resp[1] = be32_to_cpu(get_unaligned((u32 *)cp));
+		break;
+
+	/* SPI R1 == just one status byte */
+	case MMC_RSP_SPI_R1:
+		break;
+
+	default:
+		dev_dbg(&host->spi->dev, "bad response type %04x\n",
+				mmc_spi_resp_type(cmd));
+		if (value >= 0)
+			value = -EINVAL;
+		goto done;
+	}
+
+	if (value < 0)
+		dev_dbg(&host->spi->dev, "%s: resp %04x %08x\n",
+			tag, cmd->resp[0], cmd->resp[1]);
+
+	/* disable chipselect on errors and some success cases */
+	if (value >= 0 && cs_on)
+		return value;
+done:
+	if (value < 0)
+		cmd->error = value;
+	mmc_cs_off(host);
+	return value;
+}
+
+/* Issue command and read its response.
+ * Returns zero on success, negative for error.
+ *
+ * On error, caller must cope with mmc core retry mechanism.  That
+ * means immediate low-level resubmit, which affects the bus lock...
+ */
+static int
+mmc_spi_command_send(struct mmc_spi_host *host,
+		struct mmc_request *mrq,
+		struct mmc_command *cmd, int cs_on)
+{
+	struct scratch		*data = host->data;
+	u8			*cp = data->status;
+	u32			arg = cmd->arg;
+	int			status;
+	struct spi_transfer	*t;
+
+	/* We can handle most commands (except block reads) in one full
+	 * duplex I/O operation before either starting the next transfer
+	 * (data block or command) or else deselecting the card.
+	 *
+	 * First, write 7 bytes:
+	 *  - an all-ones byte to ensure the card is ready
+	 *  - opcode byte (plus start and transmission bits)
+	 *  - four bytes of big-endian argument
+	 *  - crc7 (plus end bit) ... always computed, it's cheap
+	 *
+	 * We init the whole buffer to all-ones, which is what we need
+	 * to write while we're reading (later) response data.
+	 */
+	memset(cp++, 0xff, sizeof(data->status));
+
+	*cp++ = 0x40 | cmd->opcode;
+	*cp++ = (u8)(arg >> 24);
+	*cp++ = (u8)(arg >> 16);
+	*cp++ = (u8)(arg >> 8);
+	*cp++ = (u8)arg;
+	*cp++ = (crc7(0, &data->status[1], 5) << 1) | 0x01;
+
+	/* Then, read up to 13 bytes (while writing all-ones):
+	 *  - N(CR) (== 1..8) bytes of all-ones
+	 *  - status byte (for all response types)
+	 *  - the rest of the response, either:
+	 *      + nothing, for R1 or R1B responses
+	 *	+ second status byte, for R2 responses
+	 *	+ four data bytes, for R3 and R7 responses
+	 *
+	 * Finally, read some more bytes ... in the nice cases we know in
+	 * advance how many, and reading 1 more is always OK:
+	 *  - N(EC) (== 0..N) bytes of all-ones, before deselect/finish
+	 *  - N(RC) (== 1..N) bytes of all-ones, before next command
+	 *  - N(WR) (== 1..N) bytes of all-ones, before data write
+	 *
+	 * So in those cases one full duplex I/O of at most 21 bytes will
+	 * handle the whole command, leaving the card ready to receive a
+	 * data block or new command.  We do that whenever we can, shaving
+	 * CPU and IRQ costs (especially when using DMA or FIFOs).
+	 *
+	 * There are two other cases, where it's not generally practical
+	 * to rely on a single I/O:
+	 *
+	 *  - R1B responses need at least N(EC) bytes of all-zeroes.
+	 *
+	 *    In this case we can *try* to fit it into one I/O, then
+	 *    maybe read more data later.
+	 *
+	 *  - Data block reads are more troublesome, since a variable
+	 *    number of padding bytes precede the token and data.
+	 *      + N(CX) (== 0..8) bytes of all-ones, before CSD or CID
+	 *      + N(AC) (== 1..many) bytes of all-ones
+	 *
+	 *    In this case we currently only have minimal speedups here:
+	 *    when N(CR) == 1 we can avoid I/O in response_get().
+	 */
+	if (cs_on && (mrq->data->flags & MMC_DATA_READ)) {
+		cp += 2;	/* min(N(CR)) + status */
+		/* R1 */
+	} else {
+		cp += 10;	/* max(N(CR)) + status + min(N(RC),N(WR)) */
+		if (cmd->flags & MMC_RSP_SPI_S2)	/* R2/R5 */
+			cp++;
+		else if (cmd->flags & MMC_RSP_SPI_B4)	/* R3/R4/R7 */
+			cp += 4;
+		else if (cmd->flags & MMC_RSP_BUSY)	/* R1B */
+			cp = data->status + sizeof(data->status);
+		/* else:  R1 (most commands) */
+	}
+
+	dev_dbg(&host->spi->dev, "  mmc_spi: CMD%d, resp %s\n",
+		cmd->opcode, maptype(cmd));
+
+	/* send command, leaving chipselect active */
+	spi_message_init(&host->m);
+
+	t = &host->t;
+	memset(t, 0, sizeof(*t));
+	t->tx_buf = t->rx_buf = data->status;
+	t->tx_dma = t->rx_dma = host->data_dma;
+	t->len = cp - data->status;
+	t->cs_change = 1;
+	spi_message_add_tail(t, &host->m);
+
+	if (host->dma_dev) {
+		host->m.is_dma_mapped = 1;
+		dma_sync_single_for_device(host->dma_dev,
+				host->data_dma, sizeof(*host->data),
+				DMA_BIDIRECTIONAL);
+	}
+	status = spi_sync(host->spi, &host->m);
+	if (status == 0)
+		status = host->m.status;
+
+	if (host->dma_dev)
+		dma_sync_single_for_cpu(host->dma_dev,
+				host->data_dma, sizeof(*host->data),
+				DMA_BIDIRECTIONAL);
+	if (status < 0) {
+		dev_dbg(&host->spi->dev, "  ... write returned %d\n", status);
+		cmd->error = status;
+		return status;
+	}
+
+	/* after no-data commands and STOP_TRANSMISSION, chipselect off */
+	return mmc_spi_response_get(host, cmd, cs_on);
+}
+
+/* Build data message with up to four separate transfers.  For TX, we
+ * start by writing the data token.  And in most cases, we finish with
+ * a status transfer.
+ *
+ * We always provide TX data for data and CRC.  The MMC/SD protocol
+ * requires us to write ones; but Linux defaults to writing zeroes;
+ * so we explicitly initialize it to all ones on RX paths.
+ *
+ * We also handle DMA mapping, so the underlying SPI controller does
+ * not need to (re)do it for each message.
+ */
+static void
+mmc_spi_setup_data_message(
+	struct mmc_spi_host	*host,
+	int			multiple,
+	enum dma_data_direction	direction)
+{
+	struct spi_transfer	*t;
+	struct scratch		*scratch = host->data;
+	dma_addr_t		dma = host->data_dma;
+
+	spi_message_init(&host->m);
+	if (dma)
+		host->m.is_dma_mapped = 1;
+
+	/* for reads, readblock() skips 0xff bytes before finding
+	 * the token; for writes, this transfer issues that token.
+	 */
+	if (direction == DMA_TO_DEVICE) {
+		t = &host->token;
+		memset(t, 0, sizeof(*t));
+		t->len = 1;
+		if (multiple)
+			scratch->data_token = SPI_TOKEN_MULTI_WRITE;
+		else
+			scratch->data_token = SPI_TOKEN_SINGLE;
+		t->tx_buf = &scratch->data_token;
+		if (dma)
+			t->tx_dma = dma + offsetof(struct scratch, data_token);
+		spi_message_add_tail(t, &host->m);
+	}
+
+	/* Body of transfer is buffer, then CRC ...
+	 * either TX-only, or RX with TX-ones.
+	 */
+	t = &host->t;
+	memset(t, 0, sizeof(*t));
+	t->tx_buf = host->ones;
+	t->tx_dma = host->ones_dma;
+	/* length and actual buffer info are written later */
+	spi_message_add_tail(t, &host->m);
+
+	t = &host->crc;
+	memset(t, 0, sizeof(*t));
+	t->len = 2;
+	if (direction == DMA_TO_DEVICE) {
+		/* the actual CRC may get written later */
+		t->tx_buf = &scratch->crc_val;
+		if (dma)
+			t->tx_dma = dma + offsetof(struct scratch, crc_val);
+	} else {
+		t->tx_buf = host->ones;
+		t->tx_dma = host->ones_dma;
+		t->rx_buf = &scratch->crc_val;
+		if (dma)
+			t->rx_dma = dma + offsetof(struct scratch, crc_val);
+	}
+	spi_message_add_tail(t, &host->m);
+
+	/*
+	 * A single block read is followed by N(EC) [0+] all-ones bytes
+	 * before deselect ... don't bother.
+	 *
+	 * Multiblock reads are followed by N(AC) [1+] all-ones bytes before
+	 * the next block is read, or a STOP_TRANSMISSION is issued.  We'll
+	 * collect that single byte, so readblock() doesn't need to.
+	 *
+	 * For a write, the one-byte data response follows immediately, then
+	 * come zero or more busy bytes, then N(WR) [1+] all-ones bytes.
+	 * Then single block reads may deselect, and multiblock ones issue
+	 * the next token (next data block, or STOP_TRAN).  We can try to
+	 * minimize I/O ops by using a single read to collect end-of-busy.
+	 */
+	if (multiple || direction == DMA_TO_DEVICE) {
+		t = &host->early_status;
+		memset(t, 0, sizeof(*t));
+		t->len = (direction == DMA_TO_DEVICE)
+				? sizeof(scratch->status)
+				: 1;
+		t->tx_buf = host->ones;
+		t->tx_dma = host->ones_dma;
+		t->rx_buf = scratch->status;
+		if (dma)
+			t->rx_dma = dma + offsetof(struct scratch, status);
+		t->cs_change = 1;
+		spi_message_add_tail(t, &host->m);
+	}
+}
+
+/*
+ * Write one block:
+ *  - caller handled preceding N(WR) [1+] all-ones bytes
+ *  - data block
+ *	+ token
+ *	+ data bytes
+ *	+ crc16
+ *  - an all-ones byte ... card writes a data-response byte
+ *  - followed by N(EC) [0+] all-ones bytes, card writes zero/'busy'
+ *
+ * Return negative errno, else success.
+ */
+static int
+mmc_spi_writeblock(struct mmc_spi_host *host, struct spi_transfer *t)
+{
+	struct spi_device	*spi = host->spi;
+	int			status, i;
+	struct scratch		*scratch = host->data;
+
+	if (host->mmc->use_spi_crc)
+		scratch->crc_val = cpu_to_be16(
+				crc_itu_t(0, t->tx_buf, t->len));
+	if (host->dma_dev)
+		dma_sync_single_for_device(host->dma_dev,
+				host->data_dma, sizeof(*scratch),
+				DMA_BIDIRECTIONAL);
+
+	status = spi_sync(spi, &host->m);
+	if (status == 0)
+		status = host->m.status;
+
+	if (status != 0) {
+		dev_dbg(&spi->dev, "write error (%d)\n", status);
+		return status;
+	}
+
+	if (host->dma_dev)
+		dma_sync_single_for_cpu(host->dma_dev,
+				host->data_dma, sizeof(*scratch),
+				DMA_BIDIRECTIONAL);
+
+	/*
+	 * Get the transmission data-response reply.  It must follow
+	 * immediately after the data block we transferred.  This reply
+	 * doesn't necessarily tell whether the write operation succeeded;
+	 * it just says if the transmission was ok and whether *earlier*
+	 * writes succeeded; see the standard.
+	 */
+	switch (SPI_MMC_RESPONSE_CODE(scratch->status[0])) {
+	case SPI_RESPONSE_ACCEPTED:
+		status = 0;
+		break;
+	case SPI_RESPONSE_CRC_ERR:
+		/* host shall then issue MMC_STOP_TRANSMISSION */
+		status = -EILSEQ;
+		break;
+	case SPI_RESPONSE_WRITE_ERR:
+		/* host shall then issue MMC_STOP_TRANSMISSION,
+		 * and should MMC_SEND_STATUS to sort it out
+		 */
+		status = -EIO;
+		break;
+	default:
+		status = -EPROTO;
+		break;
+	}
+	if (status != 0) {
+		dev_dbg(&spi->dev, "write error %02x (%d)\n",
+			scratch->status[0], status);
+		return status;
+	}
+
+	t->tx_buf += t->len;
+	if (host->dma_dev)
+		t->tx_dma += t->len;
+
+	/* Return when not busy.  If we didn't collect that status yet,
+	 * we'll need some more I/O.
+	 */
+	for (i = 1; i < sizeof(scratch->status); i++) {
+		if (scratch->status[i] != 0)
+			return 0;
+	}
+	return mmc_spi_wait_unbusy(host, writeblock_timeout);
+}
+
+/*
+ * Read one block:
+ *  - skip leading all-ones bytes ... either
+ *      + N(AC) [1..f(clock,CSD)] usually, else
+ *      + N(CX) [0..8] when reading CSD or CID
+ *  - data block
+ *	+ token ... if error token, no data or crc
+ *	+ data bytes
+ *	+ crc16
+ *
+ * After single block reads, we're done; N(EC) [0+] all-ones bytes follow
+ * before dropping chipselect.
+ *
+ * For multiblock reads, caller either reads the next block or issues a
+ * STOP_TRANSMISSION command.
+ */
+static int
+mmc_spi_readblock(struct mmc_spi_host *host, struct spi_transfer *t)
+{
+	struct spi_device	*spi = host->spi;
+	int			status;
+	struct scratch		*scratch = host->data;
+
+	/* At least one SD card sends an all-zeroes byte when N(CX)
+	 * applies, before the all-ones bytes ... just cope with that.
+	 */
+	status = mmc_spi_readbytes(host, 1);
+	if (status < 0)
+		return status;
+	status = scratch->status[0];
+	if (status == 0xff || status == 0)
+		status = mmc_spi_readtoken(host);
+
+	if (status == SPI_TOKEN_SINGLE) {
+		if (host->dma_dev)
+			dma_sync_single_for_device(host->dma_dev,
+					host->data_dma, sizeof(*scratch),
+					DMA_BIDIRECTIONAL);
+
+		status = spi_sync(spi, &host->m);
+		if (status == 0)
+			status = host->m.status;
+
+		if (host->dma_dev)
+			dma_sync_single_for_cpu(host->dma_dev,
+					host->data_dma, sizeof(*scratch),
+					DMA_BIDIRECTIONAL);
+	} else {
+		dev_dbg(&spi->dev, "read error %02x (%d)\n", status, status);
+
+		/* we've read extra garbage, timed out, etc */
+		if (status < 0)
+			return status;
+
+		/* low four bits are an R2 subset, fifth seems to be
+		 * vendor specific ... map them all to generic error..
+		 */
+		return -EIO;
+	}
+
+	if (host->mmc->use_spi_crc) {
+		u16 crc = crc_itu_t(0, t->rx_buf, t->len);
+
+		be16_to_cpus(&scratch->crc_val);
+		if (scratch->crc_val != crc) {
+			dev_dbg(&spi->dev, "read - crc error: crc_val=0x%04x, "
+					"computed=0x%04x len=%d\n",
+					scratch->crc_val, crc, t->len);
+			return -EILSEQ;
+		}
+	}
+
+	t->rx_buf += t->len;
+	if (host->dma_dev)
+		t->rx_dma += t->len;
+
+	return 0;
+}
+
+/*
+ * An MMC/SD data stage includes one or more blocks, optional CRCs,
+ * and inline handshaking.  That handhaking makes it unlike most
+ * other SPI protocol stacks.
+ */
+static void
+mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd,
+		struct mmc_data *data, u32 blk_size)
+{
+	struct spi_device	*spi = host->spi;
+	struct device		*dma_dev = host->dma_dev;
+	struct spi_transfer	*t;
+	enum dma_data_direction	direction;
+	struct scatterlist	*sg;
+	unsigned		n_sg;
+	int			multiple = (data->blocks > 1);
+
+	if (data->flags & MMC_DATA_READ)
+		direction = DMA_FROM_DEVICE;
+	else
+		direction = DMA_TO_DEVICE;
+	mmc_spi_setup_data_message(host, multiple, direction);
+	t = &host->t;
+
+	/* Handle scatterlist segments one at a time, with synch for
+	 * each 512-byte block
+	 */
+	for (sg = data->sg, n_sg = data->sg_len; n_sg; n_sg--, sg++) {
+		int			status = 0;
+		dma_addr_t		dma_addr = 0;
+		void			*kmap_addr;
+		unsigned		length = sg->length;
+		enum dma_data_direction	dir = direction;
+
+		/* set up dma mapping for controller drivers that might
+		 * use DMA ... though they may fall back to PIO
+		 */
+		if (dma_dev) {
+			/* never invalidate whole *shared* pages ... */
+			if ((sg->offset != 0 || length != PAGE_SIZE)
+					&& dir == DMA_FROM_DEVICE)
+				dir = DMA_BIDIRECTIONAL;
+
+			dma_addr = dma_map_page(dma_dev, sg->page, 0,
+						PAGE_SIZE, dir);
+			if (direction == DMA_TO_DEVICE)
+				t->tx_dma = dma_addr + sg->offset;
+			else
+				t->rx_dma = dma_addr + sg->offset;
+		}
+
+		/* allow pio too; we don't allow highmem */
+		kmap_addr = kmap(sg->page);
+		if (direction == DMA_TO_DEVICE)
+			t->tx_buf = kmap_addr + sg->offset;
+		else
+			t->rx_buf = kmap_addr + sg->offset;
+
+		/* transfer each block, and update request status */
+		while (length) {
+			t->len = min(length, blk_size);
+
+			dev_dbg(&host->spi->dev,
+				"    mmc_spi: %s block, %d bytes\n",
+				(direction == DMA_TO_DEVICE)
+				? "write"
+				: "read",
+				t->len);
+
+			if (direction == DMA_TO_DEVICE)
+				status = mmc_spi_writeblock(host, t);
+			else
+				status = mmc_spi_readblock(host, t);
+			if (status < 0)
+				break;
+
+			data->bytes_xfered += t->len;
+			length -= t->len;
+
+			if (!multiple)
+				break;
+		}
+
+		/* discard mappings */
+		if (direction == DMA_FROM_DEVICE)
+			flush_kernel_dcache_page(sg->page);
+		kunmap(sg->page);
+		if (dma_dev)
+			dma_unmap_page(dma_dev, dma_addr, PAGE_SIZE, dir);
+
+		if (status < 0) {
+			data->error = status;
+			dev_dbg(&spi->dev, "%s status %d\n",
+				(direction == DMA_TO_DEVICE)
+					? "write" : "read",
+				status);
+			break;
+		}
+	}
+
+	/* NOTE some docs describe an MMC-only SET_BLOCK_COUNT (CMD23) that
+	 * can be issued before multiblock writes.  Unlike its more widely
+	 * documented analogue for SD cards (SET_WR_BLK_ERASE_COUNT, ACMD23),
+	 * that can affect the STOP_TRAN logic.   Complete (and current)
+	 * MMC specs should sort that out before Linux starts using CMD23.
+	 */
+	if (direction == DMA_TO_DEVICE && multiple) {
+		struct scratch	*scratch = host->data;
+		int		tmp;
+		const unsigned	statlen = sizeof(scratch->status);
+
+		dev_dbg(&spi->dev, "    mmc_spi: STOP_TRAN\n");
+
+		/* Tweak the per-block message we set up earlier by morphing
+		 * it to hold single buffer with the token followed by some
+		 * all-ones bytes ... skip N(BR) (0..1), scan the rest for
+		 * "not busy any longer" status, and leave chip selected.
+		 */
+		INIT_LIST_HEAD(&host->m.transfers);
+		list_add(&host->early_status.transfer_list,
+				&host->m.transfers);
+
+		scratch->status[0] = SPI_TOKEN_STOP_TRAN;
+		memset(scratch->status + 1, 0xff, statlen - 1);
+		host->early_status.tx_buf = host->early_status.rx_buf;
+		host->early_status.tx_dma = host->early_status.rx_dma;
+		host->early_status.len = 1 + statlen;
+
+		if (host->dma_dev)
+			dma_sync_single_for_device(host->dma_dev,
+					host->data_dma, sizeof(*scratch),
+					DMA_BIDIRECTIONAL);
+
+		tmp = spi_sync(spi, &host->m);
+		if (tmp == 0)
+			tmp = host->m.status;
+
+		if (host->dma_dev)
+			dma_sync_single_for_cpu(host->dma_dev,
+					host->data_dma, sizeof(*scratch),
+					DMA_BIDIRECTIONAL);
+
+		if (tmp < 0) {
+			if (!data->error)
+				data->error = tmp;
+			return;
+		}
+
+		/* Ideally we collected "not busy" status with one I/O,
+		 * avoiding wasteful byte-at-a-time scanning... but more
+		 * I/O is often needed.
+		 */
+		for (tmp = 2; tmp < statlen; tmp++) {
+			if (scratch->status[tmp] != 0)
+				return;
+		}
+		tmp = mmc_spi_wait_unbusy(host, writeblock_timeout);
+		if (tmp < 0 && !data->error)
+			data->error = tmp;
+	}
+}
+
+/****************************************************************************/
+
+/*
+ * MMC driver implementation -- the interface to the MMC stack
+ */
+
+static void mmc_spi_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+	struct mmc_spi_host	*host = mmc_priv(mmc);
+	int			status = -EINVAL;
+
+#ifdef DEBUG
+	/* MMC core and layered drivers *MUST* issue SPI-aware commands */
+	{
+		struct mmc_command	*cmd;
+		int			invalid = 0;
+
+		cmd = mrq->cmd;
+		if (!mmc_spi_resp_type(cmd)) {
+			dev_dbg(&host->spi->dev, "bogus command\n");
+			cmd->error = -EINVAL;
+			invalid = 1;
+		}
+
+		cmd = mrq->stop;
+		if (cmd && !mmc_spi_resp_type(cmd)) {
+			dev_dbg(&host->spi->dev, "bogus STOP command\n");
+			cmd->error = -EINVAL;
+			invalid = 1;
+		}
+
+		if (invalid) {
+			dump_stack();
+			mmc_request_done(host->mmc, mrq);
+			return;
+		}
+	}
+#endif
+
+	/* issue command; then optionally data and stop */
+	status = mmc_spi_command_send(host, mrq, mrq->cmd, mrq->data != NULL);
+	if (status == 0 && mrq->data) {
+		mmc_spi_data_do(host, mrq->cmd, mrq->data, mrq->data->blksz);
+		if (mrq->stop)
+			status = mmc_spi_command_send(host, mrq, mrq->stop, 0);
+		else
+			mmc_cs_off(host);
+	}
+
+	mmc_request_done(host->mmc, mrq);
+}
+
+/* See Section 6.4.1, in SD "Simplified Physical Layer Specification 2.0"
+ *
+ * NOTE that here we can't know that the card has just been powered up;
+ * not all MMC/SD sockets support power switching.
+ *
+ * FIXME when the card is still in SPI mode, e.g. from a previous kernel,
+ * this doesn't seem to do the right thing at all...
+ */
+static void mmc_spi_initsequence(struct mmc_spi_host *host)
+{
+	/* Try to be very sure any previous command has completed;
+	 * wait till not-busy, skip debris from any old commands.
+	 */
+	mmc_spi_wait_unbusy(host, r1b_timeout);
+	mmc_spi_readbytes(host, 10);
+
+	/*
+	 * Do a burst with chipselect active-high.  We need to do this to
+	 * meet the requirement of 74 clock cycles with both chipselect
+	 * and CMD (MOSI) high before CMD0 ... after the card has been
+	 * powered up to Vdd(min), and so is ready to take commands.
+	 *
+	 * Some cards are particularly needy of this (e.g. Viking "SD256")
+	 * while most others don't seem to care.
+	 *
+	 * Note that this is one of the places MMC/SD plays games with the
+	 * SPI protocol.  Another is that when chipselect is released while
+	 * the card returns BUSY status, the clock must issue several cycles
+	 * with chipselect high before the card will stop driving its output.
+	 */
+	host->spi->mode |= SPI_CS_HIGH;
+	if (spi_setup(host->spi) != 0) {
+		/* Just warn; most cards work without it. */
+		dev_warn(&host->spi->dev,
+				"can't change chip-select polarity\n");
+		host->spi->mode &= ~SPI_CS_HIGH;
+	} else {
+		mmc_spi_readbytes(host, 18);
+
+		host->spi->mode &= ~SPI_CS_HIGH;
+		if (spi_setup(host->spi) != 0) {
+			/* Wot, we can't get the same setup we had before? */
+			dev_err(&host->spi->dev,
+					"can't restore chip-select polarity\n");
+		}
+	}
+}
+
+static char *mmc_powerstring(u8 power_mode)
+{
+	switch (power_mode) {
+	case MMC_POWER_OFF: return "off";
+	case MMC_POWER_UP:  return "up";
+	case MMC_POWER_ON:  return "on";
+	}
+	return "?";
+}
+
+static void mmc_spi_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+	struct mmc_spi_host *host = mmc_priv(mmc);
+
+	if (host->power_mode != ios->power_mode) {
+		int		canpower;
+
+		canpower = host->pdata && host->pdata->setpower;
+
+		dev_dbg(&host->spi->dev, "mmc_spi: power %s (%d)%s\n",
+				mmc_powerstring(ios->power_mode),
+				ios->vdd,
+				canpower ? ", can switch" : "");
+
+		/* switch power on/off if possible, accounting for
+		 * max 250msec powerup time if needed.
+		 */
+		if (canpower) {
+			switch (ios->power_mode) {
+			case MMC_POWER_OFF:
+			case MMC_POWER_UP:
+				host->pdata->setpower(&host->spi->dev,
+						ios->vdd);
+				if (ios->power_mode == MMC_POWER_UP)
+					msleep(host->powerup_msecs);
+			}
+		}
+
+		/* See 6.4.1 in the simplified SD card physical spec 2.0 */
+		if (ios->power_mode == MMC_POWER_ON)
+			mmc_spi_initsequence(host);
+
+		/* If powering down, ground all card inputs to avoid power
+		 * delivery from data lines!  On a shared SPI bus, this
+		 * will probably be temporary; 6.4.2 of the simplified SD
+		 * spec says this must last at least 1msec.
+		 *
+		 *   - Clock low means CPOL 0, e.g. mode 0
+		 *   - MOSI low comes from writing zero
+		 *   - Chipselect is usually active low...
+		 */
+		if (canpower && ios->power_mode == MMC_POWER_OFF) {
+			int mres;
+
+			host->spi->mode &= ~(SPI_CPOL|SPI_CPHA);
+			mres = spi_setup(host->spi);
+			if (mres < 0)
+				dev_dbg(&host->spi->dev,
+					"switch to SPI mode 0 failed\n");
+
+			if (spi_w8r8(host->spi, 0x00) < 0)
+				dev_dbg(&host->spi->dev,
+					"put spi signals to low failed\n");
+
+			/*
+			 * Now clock should be low due to spi mode 0;
+			 * MOSI should be low because of written 0x00;
+			 * chipselect should be low (it is active low)
+			 * power supply is off, so now MMC is off too!
+			 *
+			 * FIXME no, chipselect can be high since the
+			 * device is inactive and SPI_CS_HIGH is clear...
+			 */
+			msleep(10);
+			if (mres == 0) {
+				host->spi->mode |= (SPI_CPOL|SPI_CPHA);
+				mres = spi_setup(host->spi);
+				if (mres < 0)
+					dev_dbg(&host->spi->dev,
+						"switch back to SPI mode 3"
+						" failed\n");
+			}
+		}
+
+		host->power_mode = ios->power_mode;
+	}
+
+	if (host->spi->max_speed_hz != ios->clock && ios->clock != 0) {
+		int		status;
+
+		host->spi->max_speed_hz = ios->clock;
+		status = spi_setup(host->spi);
+		dev_dbg(&host->spi->dev,
+			"mmc_spi:  clock to %d Hz, %d\n",
+			host->spi->max_speed_hz, status);
+	}
+}
+
+static int mmc_spi_get_ro(struct mmc_host *mmc)
+{
+	struct mmc_spi_host *host = mmc_priv(mmc);
+
+	if (host->pdata && host->pdata->get_ro)
+		return host->pdata->get_ro(mmc->parent);
+	/* board doesn't support read only detection; assume writeable */
+	return 0;
+}
+
+
+static const struct mmc_host_ops mmc_spi_ops = {
+	.request	= mmc_spi_request,
+	.set_ios	= mmc_spi_set_ios,
+	.get_ro		= mmc_spi_get_ro,
+};
+
+
+/****************************************************************************/
+
+/*
+ * SPI driver implementation
+ */
+
+static irqreturn_t
+mmc_spi_detect_irq(int irq, void *mmc)
+{
+	struct mmc_spi_host *host = mmc_priv(mmc);
+	u16 delay_msec = max(host->pdata->detect_delay, (u16)100);
+
+	mmc_detect_change(mmc, msecs_to_jiffies(delay_msec));
+	return IRQ_HANDLED;
+}
+
+static int mmc_spi_probe(struct spi_device *spi)
+{
+	void			*ones;
+	struct mmc_host		*mmc;
+	struct mmc_spi_host	*host;
+	int			status;
+
+	/* MMC and SD specs only seem to care that sampling is on the
+	 * rising edge ... meaning SPI modes 0 or 3.  So either SPI mode
+	 * should be legit.  We'll use mode 0 since it seems to be a
+	 * bit less troublesome on some hardware ... unclear why.
+	 */
+	spi->mode = SPI_MODE_0;
+	spi->bits_per_word = 8;
+
+	status = spi_setup(spi);
+	if (status < 0) {
+		dev_dbg(&spi->dev, "needs SPI mode %02x, %d KHz; %d\n",
+				spi->mode, spi->max_speed_hz / 1000,
+				status);
+		return status;
+	}
+
+	/* We can use the bus safely iff nobody else will interfere with
+	 * us.  That is, either we have the experimental exclusive access
+	 * primitives ... or else there's nobody to share it with.
+	 */
+	if (spi->master->num_chipselect > 1) {
+		struct device	*parent = spi->dev.parent;
+
+		/* If there are multiple devices on this bus, we
+		 * can't proceed.
+		 */
+		spin_lock(&parent->klist_children.k_lock);
+		if (parent->klist_children.k_list.next
+				!= parent->klist_children.k_list.prev)
+			status = -EMLINK;
+		else
+			status = 0;
+		spin_unlock(&parent->klist_children.k_lock);
+		if (status < 0) {
+			dev_err(&spi->dev, "can't share SPI bus\n");
+			return status;
+		}
+
+		/* REVISIT we can't guarantee another device won't
+		 * be added later.  It's uncommon though ... for now,
+		 * work as if this is safe.
+		 */
+		dev_warn(&spi->dev, "ASSUMING unshared SPI bus!\n");
+	}
+
+	/* We need a supply of ones to transmit.  This is the only time
+	 * the CPU touches these, so cache coherency isn't a concern.
+	 *
+	 * NOTE if many systems use more than one MMC-over-SPI connector
+	 * it'd save some memory to share this.  That's evidently rare.
+	 */
+	status = -ENOMEM;
+	ones = kmalloc(MMC_SPI_BLOCKSIZE, GFP_KERNEL);
+	if (!ones)
+		goto nomem;
+	memset(ones, 0xff, MMC_SPI_BLOCKSIZE);
+
+	mmc = mmc_alloc_host(sizeof(*host), &spi->dev);
+	if (!mmc)
+		goto nomem;
+
+	mmc->ops = &mmc_spi_ops;
+	mmc->max_blk_size = MMC_SPI_BLOCKSIZE;
+
+	/* As long as we keep track of the number of successfully
+	 * transmitted blocks, we're good for multiwrite.
+	 */
+	mmc->caps = MMC_CAP_SPI | MMC_CAP_MULTIWRITE;
+
+	/* SPI doesn't need the lowspeed device identification thing for
+	 * MMC or SD cards, since it never comes up in open drain mode.
+	 * That's good; some SPI masters can't handle very low speeds!
+	 *
+	 * However, low speed SDIO cards need not handle over 400 KHz;
+	 * that's the only reason not to use a few MHz for f_min (until
+	 * the upper layer reads the target frequency from the CSD).
+	 */
+	mmc->f_min = 400000;
+	mmc->f_max = spi->max_speed_hz;
+
+	host = mmc_priv(mmc);
+	host->mmc = mmc;
+	host->spi = spi;
+
+	host->ones = ones;
+
+	/* Platform data is used to hook up things like card sensing
+	 * and power switching gpios.
+	 */
+	host->pdata = spi->dev.platform_data;
+	if (host->pdata)
+		mmc->ocr_avail = host->pdata->ocr_mask;
+	if (!mmc->ocr_avail) {
+		dev_warn(&spi->dev, "ASSUMING 3.2-3.4 V slot power\n");
+		mmc->ocr_avail = MMC_VDD_32_33|MMC_VDD_33_34;
+	}
+	if (host->pdata && host->pdata->setpower) {
+		host->powerup_msecs = host->pdata->powerup_msecs;
+		if (!host->powerup_msecs || host->powerup_msecs > 250)
+			host->powerup_msecs = 250;
+	}
+
+	dev_set_drvdata(&spi->dev, mmc);
+
+	/* preallocate dma buffers */
+	host->data = kmalloc(sizeof(*host->data), GFP_KERNEL);
+	if (!host->data)
+		goto fail_nobuf1;
+
+	if (spi->master->cdev.dev->dma_mask) {
+		struct device	*dev = spi->master->cdev.dev;
+
+		host->dma_dev = dev;
+		host->ones_dma = dma_map_single(dev, ones,
+				MMC_SPI_BLOCKSIZE, DMA_TO_DEVICE);
+		host->data_dma = dma_map_single(dev, host->data,
+				sizeof(*host->data), DMA_BIDIRECTIONAL);
+
+		/* REVISIT in theory those map operations can fail... */
+
+		dma_sync_single_for_cpu(host->dma_dev,
+				host->data_dma, sizeof(*host->data),
+				DMA_BIDIRECTIONAL);
+	}
+
+	/* setup message for status/busy readback */
+	spi_message_init(&host->readback);
+	host->readback.is_dma_mapped = (host->dma_dev != NULL);
+
+	spi_message_add_tail(&host->status, &host->readback);
+	host->status.tx_buf = host->ones;
+	host->status.tx_dma = host->ones_dma;
+	host->status.rx_buf = &host->data->status;
+	host->status.rx_dma = host->data_dma + offsetof(struct scratch, status);
+	host->status.cs_change = 1;
+
+	/* register card detect irq */
+	if (host->pdata && host->pdata->init) {
+		status = host->pdata->init(&spi->dev, mmc_spi_detect_irq, mmc);
+		if (status != 0)
+			goto fail_glue_init;
+	}
+
+	status = mmc_add_host(mmc);
+	if (status != 0)
+		goto fail_add_host;
+
+	dev_info(&spi->dev, "SD/MMC host %s%s%s%s\n",
+			mmc->class_dev.bus_id,
+			host->dma_dev ? "" : ", no DMA",
+			(host->pdata && host->pdata->get_ro)
+				? "" : ", no WP",
+			(host->pdata && host->pdata->setpower)
+				? "" : ", no poweroff");
+	return 0;
+
+fail_add_host:
+	mmc_remove_host (mmc);
+fail_glue_init:
+	if (host->dma_dev)
+		dma_unmap_single(host->dma_dev, host->data_dma,
+				sizeof(*host->data), DMA_BIDIRECTIONAL);
+	kfree(host->data);
+
+fail_nobuf1:
+	mmc_free_host(mmc);
+	dev_set_drvdata(&spi->dev, NULL);
+
+nomem:
+	kfree(ones);
+	return status;
+}
+
+
+static int __devexit mmc_spi_remove(struct spi_device *spi)
+{
+	struct mmc_host		*mmc = dev_get_drvdata(&spi->dev);
+	struct mmc_spi_host	*host;
+
+	if (mmc) {
+		host = mmc_priv(mmc);
+
+		/* prevent new mmc_detect_change() calls */
+		if (host->pdata && host->pdata->exit)
+			host->pdata->exit(&spi->dev, mmc);
+
+		mmc_remove_host(mmc);
+
+		if (host->dma_dev) {
+			dma_unmap_single(host->dma_dev, host->ones_dma,
+				MMC_SPI_BLOCKSIZE, DMA_TO_DEVICE);
+			dma_unmap_single(host->dma_dev, host->data_dma,
+				sizeof(*host->data), DMA_BIDIRECTIONAL);
+		}
+
+		kfree(host->data);
+		kfree(host->ones);
+
+		spi->max_speed_hz = mmc->f_max;
+		mmc_free_host(mmc);
+		dev_set_drvdata(&spi->dev, NULL);
+	}
+	return 0;
+}
+
+
+static struct spi_driver mmc_spi_driver = {
+	.driver = {
+		.name =		"mmc_spi",
+		.bus =		&spi_bus_type,
+		.owner =	THIS_MODULE,
+	},
+	.probe =	mmc_spi_probe,
+	.remove =	__devexit_p(mmc_spi_remove),
+};
+
+
+static int __init mmc_spi_init(void)
+{
+	return spi_register_driver(&mmc_spi_driver);
+}
+module_init(mmc_spi_init);
+
+
+static void __exit mmc_spi_exit(void)
+{
+	spi_unregister_driver(&mmc_spi_driver);
+}
+module_exit(mmc_spi_exit);
+
+
+MODULE_AUTHOR("Mike Lavender, David Brownell, "
+		"Hans-Peter Nilsson, Jan Nikitenko");
+MODULE_DESCRIPTION("SPI SD/MMC host driver");
+MODULE_LICENSE("GPL");

-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems?  Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >>  http://get.splunk.com/

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [patch 0/4 2.6.23-rc2 + mm2-git-mmc] latest MMC-over-SPI support
       [not found] ` <200708080906.18993.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
                     ` (3 preceding siblings ...)
  2007-08-08 16:12   ` [patch 4/4 2.6.23-rc2 + mm2-git-mmc] mmc_spi host driver David Brownell
@ 2007-08-09 10:45   ` Anton Vorontsov
  2007-08-09 13:05   ` Pierre Ossman
  5 siblings, 0 replies; 35+ messages in thread
From: Anton Vorontsov @ 2007-08-09 10:45 UTC (permalink / raw)
  To: David Brownell
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	Mikael Starvik, Hans-Peter Nilsson, Mike Lavender, Pierre Ossman

On Wed, Aug 08, 2007 at 09:06:18AM -0700, David Brownell wrote:
> Same deal as before ... refreshed against the latest git-mmc.patch,
> four patches:
> 
>  - headers
>  - block
>  - core
>  - mmc_spi host
> 
> Differences from the very last patches sent are primarily that this one
> includes the lock/unlock changes again (since it's against git-mmc not
> against kernel.org), and code for the SDIO stuff is there (ditto).  But
> also, a few more of Pierre's comments have kicked in.
> 
> I'm hoping this version gets merged into git-mmc.  :)

Works great here. Thanks!

-- 
Anton Vorontsov
email: cbou-JGs/UdohzUI@public.gmane.org
backup email: ya-cbou-o+MxOtu4lMCHXe+LvDLADg@public.gmane.org
irc://irc.freenode.net/bd2

-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems?  Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >>  http://get.splunk.com/

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [patch 0/4 2.6.23-rc2 + mm2-git-mmc] latest MMC-over-SPI support
       [not found] ` <200708080906.18993.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
                     ` (4 preceding siblings ...)
  2007-08-09 10:45   ` [patch 0/4 2.6.23-rc2 + mm2-git-mmc] latest MMC-over-SPI support Anton Vorontsov
@ 2007-08-09 13:05   ` Pierre Ossman
  5 siblings, 0 replies; 35+ messages in thread
From: Pierre Ossman @ 2007-08-09 13:05 UTC (permalink / raw)
  To: David Brownell
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	Mikael Starvik, Hans-Peter Nilsson, Mike Lavender

On Wed, 8 Aug 2007 09:06:18 -0700
David Brownell <david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> wrote:

> 
> I'm hoping this version gets merged into git-mmc.  :)
> 

The emperor is pleased. Code merged.

Your great leader
-- 
     -- Pierre Ossman

  Linux kernel, MMC maintainer        http://www.kernel.org
  PulseAudio, core developer          http://pulseaudio.org
  rdesktop, core developer          http://www.rdesktop.org

-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems?  Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >>  http://get.splunk.com/

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [patch 3/4 2.6.23-rc2 + mm2-git-mmc] MMC core learns about SPI
       [not found]     ` <200708080911.33099.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
@ 2007-08-09 13:07       ` Pierre Ossman
       [not found]         ` <20070809150747.62b1447a-mgABNEgzgxm+PRNnhPf8W5YgPPQkE1Si@public.gmane.org>
  2007-08-12 15:50       ` David Brownell
  2007-08-29  9:22       ` Sascha Hauer
  2 siblings, 1 reply; 35+ messages in thread
From: Pierre Ossman @ 2007-08-09 13:07 UTC (permalink / raw)
  To: David Brownell
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	Mikael Starvik, Hans-Peter Nilsson, Mike Lavender

On Wed, 8 Aug 2007 09:11:32 -0700
David Brownell <david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> wrote:

> @@ -68,21 +72,26 @@ int mmc_io_rw_direct(struct mmc_card *ca
>  	cmd.arg |= (write && out) ? 0x08000000 : 0x00000000;
>  	cmd.arg |= addr << 9;
>  	cmd.arg |= in;
> -	cmd.flags = MMC_RSP_R5 | MMC_CMD_AC;
> +	cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_AC;
>  
>  	err = mmc_wait_for_cmd(card->host, &cmd, 0);
>  	if (err)
>  		return err;
>  
> -	if (cmd.resp[0] & R5_ERROR)
> -		return -EIO;
> -	if (cmd.resp[0] & R5_FUNCTION_NUMBER)
> -		return -EINVAL;
> -	if (cmd.resp[0] & R5_OUT_OF_RANGE)
> -		return -ERANGE;
> +	if (mmc_host_is_spi(card->host)) {
> +		if (out)
> +			*out = (cmd.resp[0] >> 8) & 0xFF;
> +	} else {
> +		if (cmd.resp[0] & R5_ERROR)
> +			return -EIO;
> +		if (cmd.resp[0] & R5_FUNCTION_NUMBER)
> +			return -EINVAL;
> +		if (cmd.resp[0] & R5_OUT_OF_RANGE)
> +			return -ERANGE;
>  
> -	if (out)
> -		*out = cmd.resp[0] & 0xFF;
> +		if (out)
> +			*out = cmd.resp[0] & 0xFF;
> +	}
>  
>  	return 0;
>  }

What about error bits in the spi case? And could you do two if:s, one
for the error bits, and one for the different handling of getting the
data? I think that would be clearer in detailing the differences.

> @@ -131,12 +140,14 @@ int mmc_io_rw_extended(struct mmc_card *
>  	if (data.error)
>  		return data.error;
>  
> -	if (cmd.resp[0] & R5_ERROR)
> -		return -EIO;
> -	if (cmd.resp[0] & R5_FUNCTION_NUMBER)
> -		return -EINVAL;
> -	if (cmd.resp[0] & R5_OUT_OF_RANGE)
> -		return -ERANGE;
> +	if (!mmc_host_is_spi(card->host)) {
> +		if (cmd.resp[0] & R5_ERROR)
> +			return -EIO;
> +		if (cmd.resp[0] & R5_FUNCTION_NUMBER)
> +			return -EINVAL;
> +		if (cmd.resp[0] & R5_OUT_OF_RANGE)
> +			return -ERANGE;
> +	}
>  
>  	return 0;
>  }
> 
> 

Ditto on the error bits.

The emperor expects a follow-up patch.

-- 
     -- Pierre Ossman

  Linux kernel, MMC maintainer        http://www.kernel.org
  PulseAudio, core developer          http://pulseaudio.org
  rdesktop, core developer          http://www.rdesktop.org

-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems?  Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >>  http://get.splunk.com/

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [patch 3/4 2.6.23-rc2 + mm2-git-mmc] MMC core learns about SPI
       [not found]         ` <20070809150747.62b1447a-mgABNEgzgxm+PRNnhPf8W5YgPPQkE1Si@public.gmane.org>
@ 2007-08-09 15:35           ` David Brownell
       [not found]             ` <200708090835.42279.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
  0 siblings, 1 reply; 35+ messages in thread
From: David Brownell @ 2007-08-09 15:35 UTC (permalink / raw)
  To: Pierre Ossman
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	Mikael Starvik, Hans-Peter Nilsson, Mike Lavender

On Thursday 09 August 2007, Pierre Ossman wrote:
> > @@ -68,21 +72,26 @@ int mmc_io_rw_direct(struct mmc_card *ca
> >  	cmd.arg |= (write && out) ? 0x08000000 : 0x00000000;
> >  	cmd.arg |= addr << 9;
> >  	cmd.arg |= in;
> > -	cmd.flags = MMC_RSP_R5 | MMC_CMD_AC;
> > +	cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_AC;
> >  
> >  	err = mmc_wait_for_cmd(card->host, &cmd, 0);
> >  	if (err)
> >  		return err;
> >  
> > -	if (cmd.resp[0] & R5_ERROR)
> > -		return -EIO;
> > -	if (cmd.resp[0] & R5_FUNCTION_NUMBER)
> > -		return -EINVAL;
> > -	if (cmd.resp[0] & R5_OUT_OF_RANGE)
> > -		return -ERANGE;
> > +	if (mmc_host_is_spi(card->host)) {
> > +		if (out)
> > +			*out = (cmd.resp[0] >> 8) & 0xFF;
> > +	} else {
> > +		if (cmd.resp[0] & R5_ERROR)
> > +			return -EIO;
> > +		if (cmd.resp[0] & R5_FUNCTION_NUMBER)
> > +			return -EINVAL;
> > +		if (cmd.resp[0] & R5_OUT_OF_RANGE)
> > +			return -ERANGE;
> >  
> > -	if (out)
> > -		*out = cmd.resp[0] & 0xFF;
> > +		if (out)
> > +			*out = cmd.resp[0] & 0xFF;
> > +	}
> >  
> >  	return 0;
> >  }
> 
> What about error bits in the spi case?

Either they're already handled correctly in the mmc_spi host code
(and don't need duplicate handling here), or they need attention
from someone with all the relevant hardware in hand...


> And could you do two if:s, one 
> for the error bits, and one for the different handling of getting the
> data? I think that would be clearer in detailing the differences.

If you insist ... appended.

=========
Tweak the (untested) SDIO-over-SPI code paths.

Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
---
 drivers/mmc/core/sdio_ops.c |   13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)

--- g26.orig/drivers/mmc/core/sdio_ops.c	2007-08-09 08:29:36.000000000 -0700
+++ g26/drivers/mmc/core/sdio_ops.c	2007-08-09 08:32:32.000000000 -0700
@@ -79,8 +79,7 @@ int mmc_io_rw_direct(struct mmc_card *ca
 		return err;
 
 	if (mmc_host_is_spi(card->host)) {
-		if (out)
-			*out = (cmd.resp[0] >> 8) & 0xFF;
+		/* host driver already reported errors */
 	} else {
 		if (cmd.resp[0] & R5_ERROR)
 			return -EIO;
@@ -88,8 +87,12 @@ int mmc_io_rw_direct(struct mmc_card *ca
 			return -EINVAL;
 		if (cmd.resp[0] & R5_OUT_OF_RANGE)
 			return -ERANGE;
+	}
 
-		if (out)
+	if (out) {
+		if (mmc_host_is_spi(card->host))
+			*out = (cmd.resp[0] >> 8) & 0xFF;
+		else
 			*out = cmd.resp[0] & 0xFF;
 	}
 
@@ -140,7 +143,9 @@ int mmc_io_rw_extended(struct mmc_card *
 	if (data.error)
 		return data.error;
 
-	if (!mmc_host_is_spi(card->host)) {
+	if (mmc_host_is_spi(card->host)) {
+		/* host driver already reported errors */
+	} else {
 		if (cmd.resp[0] & R5_ERROR)
 			return -EIO;
 		if (cmd.resp[0] & R5_FUNCTION_NUMBER)

-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems?  Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >>  http://get.splunk.com/

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [patch 3/4 2.6.23-rc2 + mm2-git-mmc] MMC core learns about SPI
       [not found]             ` <200708090835.42279.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
@ 2007-08-09 20:18               ` Pierre Ossman
  0 siblings, 0 replies; 35+ messages in thread
From: Pierre Ossman @ 2007-08-09 20:18 UTC (permalink / raw)
  To: David Brownell
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	Mikael Starvik, Hans-Peter Nilsson, Mike Lavender

On Thu, 9 Aug 2007 08:35:41 -0700
David Brownell <david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> wrote:

> On Thursday 09 August 2007, Pierre Ossman wrote:
> > 
> > What about error bits in the spi case?
> 
> Either they're already handled correctly in the mmc_spi host code
> (and don't need duplicate handling here), or they need attention
> from someone with all the relevant hardware in hand...
> 

I'll put it on my list. The hardware is in the mail (kudos to Atmel), so
I'll hopefully be running sdio cards of SPI in a short while.

> 
> > And could you do two if:s, one 
> > for the error bits, and one for the different handling of getting
> > the data? I think that would be clearer in detailing the
> > differences.
> 
> If you insist ... appended.
> 

Muchos gracias.

Btw, the first batch is already pushed to Andrew. So it will be in his
next -mm.

Rgds
-- 
     -- Pierre Ossman

  Linux kernel, MMC maintainer        http://www.kernel.org
  PulseAudio, core developer          http://pulseaudio.org
  rdesktop, core developer          http://www.rdesktop.org

-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems?  Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >>  http://get.splunk.com/

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [patch 3/4 2.6.23-rc2 + mm2-git-mmc] MMC core learns about SPI
       [not found]     ` <200708080911.33099.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
  2007-08-09 13:07       ` Pierre Ossman
@ 2007-08-12 15:50       ` David Brownell
       [not found]         ` <200708120850.04271.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
  2007-08-29  9:22       ` Sascha Hauer
  2 siblings, 1 reply; 35+ messages in thread
From: David Brownell @ 2007-08-12 15:50 UTC (permalink / raw)
  To: Pierre Ossman
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	Mikael Starvik, Hans-Peter Nilsson, Mike Lavender

This wasn't merged correctly into 2.6.23-rc2-mm2's version of git-mmc,
and that goof guarantees oopsing while enumerating at least SD-cards.

When the merge botch is fixed, that version of git-mmc.patch passes
sanity testing with MMC-over-SPI.


On Wednesday 08 August 2007, David Brownell wrote:
>
>	...
>
> --- g26.orig/drivers/mmc/core/mmc_ops.c 2007-08-08 09:07:48.000000000 -0700
> +++ g26/drivers/mmc/core/mmc_ops.c      2007-08-08 09:07:57.000000000 -0700
>
>	...
>
> @@ -206,21 +229,31 @@ int mmc_send_ext_csd(struct mmc_card *ca
>         mrq.cmd = &cmd;
>         mrq.data = &data;
>  
> -       cmd.opcode = MMC_SEND_EXT_CSD;
> +       cmd.opcode = opcode;
>         cmd.arg = 0;
> -       cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
>  
> -       data.blksz = 512;
> +       /* NOTE HACK:  the MMC_RSP_SPI_R1 is always correct here, but we
> +        * rely on callers to never use this with "native" calls for reading
> +        * CSD or CID.  Native versions of those commands use the R2 type,
> +        * not R1 plus a data block.
> +        */
> +       cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
> +
> +       data.blksz = len;
>         data.blocks = 1;
>         data.flags = MMC_DATA_READ;
>         data.sg = &sg;
>         data.sg_len = 1;
>  
> -       sg_init_one(&sg, ext_csd, 512);
> +       sg_init_one(&sg, data_buf, len);
>  
> -       mmc_set_data_timeout(&data, card);
> +       if (card)
> +               mmc_set_data_timeout(&data, card);
>  
> -       mmc_wait_for_req(card->host, &mrq);
> +       mmc_wait_for_req(host, &mrq);

The line above was merged as "mmc_wait_for_req(card->host, &mrq);" ...

Note the preceding "if (card) ...".  When "card" is null, as it
usually is during SPI enumeration, this always oopses.


> +
> +       memcpy(buf, data_buf, len);
> +       kfree(data_buf);
>  
>         if (cmd.error)
>                 return cmd.error;



-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems?  Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >>  http://get.splunk.com/

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [patch 3/4 2.6.23-rc2 + mm2-git-mmc] MMC core learns about SPI
       [not found]         ` <200708120850.04271.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
@ 2007-08-12 15:52           ` Pierre Ossman
  0 siblings, 0 replies; 35+ messages in thread
From: Pierre Ossman @ 2007-08-12 15:52 UTC (permalink / raw)
  To: David Brownell
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	Mikael Starvik, Hans-Peter Nilsson, Mike Lavender

On Sun, 12 Aug 2007 08:50:03 -0700
David Brownell <david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> wrote:

> This wasn't merged correctly into 2.6.23-rc2-mm2's version of git-mmc,
> and that goof guarantees oopsing while enumerating at least SD-cards.
> 
> When the merge botch is fixed, that version of git-mmc.patch passes
> sanity testing with MMC-over-SPI.
> 

I can only agree, ooops :)

Rgds
-- 
     -- Pierre Ossman

  Linux kernel, MMC maintainer        http://www.kernel.org
  PulseAudio, core developer          http://pulseaudio.org
  rdesktop, core developer          http://www.rdesktop.org

-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems?  Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >>  http://get.splunk.com/

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [patch 3/4 2.6.23-rc2 + mm2-git-mmc] MMC core learns about SPI
       [not found]     ` <200708080911.33099.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
  2007-08-09 13:07       ` Pierre Ossman
  2007-08-12 15:50       ` David Brownell
@ 2007-08-29  9:22       ` Sascha Hauer
       [not found]         ` <20070829092247.GA15021-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
  2 siblings, 1 reply; 35+ messages in thread
From: Sascha Hauer @ 2007-08-29  9:22 UTC (permalink / raw)
  To: David Brownell
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	Mikael Starvik, Hans-Peter Nilsson, Mike Lavender, Pierre Ossman

Hi David and all,

I need the following patch on my (little endian) System to successfully
read the csd/cid structure.

Sascha


CSD/CID is transfered in big endian format. Convert it to cpu endianess.

Signed-off-by: Sascha Hauer <s.hauer-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>

---
 drivers/mmc/core/mmc_ops.c |    7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

Index: linux-2.6-arm/drivers/mmc/core/mmc_ops.c
===================================================================
--- linux-2.6-arm.orig/drivers/mmc/core/mmc_ops.c
+++ linux-2.6-arm/drivers/mmc/core/mmc_ops.c
@@ -207,6 +207,7 @@ mmc_send_cxd_data(struct mmc_host *host,
 	struct mmc_data data;
 	struct scatterlist sg;
 	void *data_buf;
+	int i;
 
 	/* dma onto stack is unsafe/nonportable, but callers here
 	 * normally provide temporary on-stack buffers.
@@ -246,7 +247,11 @@ mmc_send_cxd_data(struct mmc_host *host,
 
 	mmc_wait_for_req(host, &mrq);
 
-	memcpy(buf, data_buf, len);
+	for (i = 0; i < (len >> 2); i++) {
+		u32 *buf32 = buf;
+		buf32[i] = be32_to_cpu(*((u32 *)data_buf + i));
+	}
+
 	kfree(data_buf);
 
 	if (cmd.error != MMC_ERR_NONE)


-- 
Pengutronix - Linux Solutions for Science and Industry
Entwicklungszentrum Nord     http://www.pengutronix.de

-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems?  Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >>  http://get.splunk.com/

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [patch 4/4 2.6.23-rc2 + mm2-git-mmc] mmc_spi host driver
       [not found]     ` <200708080912.54918.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
@ 2007-08-29 10:07       ` Sascha Hauer
       [not found]         ` <20070829100708.GB15021-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
  0 siblings, 1 reply; 35+ messages in thread
From: Sascha Hauer @ 2007-08-29 10:07 UTC (permalink / raw)
  To: David Brownell
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	Mikael Starvik, Hans-Peter Nilsson, Mike Lavender, Pierre Ossman

Hi,

On Wed, Aug 08, 2007 at 09:12:54AM -0700, David Brownell wrote:
 +
> +	/* NOTE some docs describe an MMC-only SET_BLOCK_COUNT (CMD23) that
> +	 * can be issued before multiblock writes.  Unlike its more widely
> +	 * documented analogue for SD cards (SET_WR_BLK_ERASE_COUNT, ACMD23),
> +	 * that can affect the STOP_TRAN logic.   Complete (and current)
> +	 * MMC specs should sort that out before Linux starts using CMD23.
> +	 */
> +	if (direction == DMA_TO_DEVICE && multiple) {
> +		struct scratch	*scratch = host->data;
> +		int		tmp;
> +		const unsigned	statlen = sizeof(scratch->status);
> +
> +		dev_dbg(&spi->dev, "    mmc_spi: STOP_TRAN\n");
> +
> +		/* Tweak the per-block message we set up earlier by morphing
> +		 * it to hold single buffer with the token followed by some
> +		 * all-ones bytes ... skip N(BR) (0..1), scan the rest for
> +		 * "not busy any longer" status, and leave chip selected.
> +		 */
> +		INIT_LIST_HEAD(&host->m.transfers);
> +		list_add(&host->early_status.transfer_list,
> +				&host->m.transfers);
> +
> +		scratch->status[0] = SPI_TOKEN_STOP_TRAN;
> +		memset(scratch->status + 1, 0xff, statlen - 1);
> +		host->early_status.tx_buf = host->early_status.rx_buf;
> +		host->early_status.tx_dma = host->early_status.rx_dma;
> +		host->early_status.len = 1 + statlen;
> +

The length to transfer here is statlen, not statlen + 1. With the following
patch applied the driver works more reliably for me, though not perfect.
I still get occasional errors like this from some SD cards:

mmcblk0: error 2 sending stop command

This is a crc error. There may be still problems in my (Hilscher netx)spi driver.
The mmc over spi stuff is the first testbed for this fresh driver. For a
real crc error I would expect that they are somewhat dependent on the
clock rate, but this does not seem to be the case. Before going deeper
here, has any of you seen this or got an idea where to look for it?

Sascha


Signed-off-by: Sascha Hauer <s.hauer-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>

---
 drivers/mmc/host/mmc_spi.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

Index: linux-2.6-arm/drivers/mmc/host/mmc_spi.c
===================================================================
--- linux-2.6-arm.orig/drivers/mmc/host/mmc_spi.c
+++ linux-2.6-arm/drivers/mmc/host/mmc_spi.c
@@ -886,7 +886,7 @@ mmc_spi_data_do(struct mmc_spi_host *hos
 		memset(scratch->status + 1, 0xff, statlen - 1);
 		host->early_status.tx_buf = host->early_status.rx_buf;
 		host->early_status.tx_dma = host->early_status.rx_dma;
-		host->early_status.len = 1 + statlen;
+		host->early_status.len = statlen;
 
 		if (host->dma_dev)
 			dma_sync_single_for_device(host->dma_dev,



-- 
Pengutronix - Linux Solutions for Science and Industry
Entwicklungszentrum Nord     http://www.pengutronix.de

-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems?  Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >>  http://get.splunk.com/

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [patch 3/4 2.6.23-rc2 + mm2-git-mmc] MMC core learns about SPI
       [not found]         ` <20070829092247.GA15021-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
@ 2007-08-29 14:52           ` Pierre Ossman
       [not found]             ` <20070829165243.0236cc89-mgABNEgzgxm+PRNnhPf8W5YgPPQkE1Si@public.gmane.org>
  0 siblings, 1 reply; 35+ messages in thread
From: Pierre Ossman @ 2007-08-29 14:52 UTC (permalink / raw)
  To: Sascha Hauer
  Cc: David Brownell,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	Mikael Starvik, Hans-Peter Nilsson, Mike Lavender

On Wed, 29 Aug 2007 11:22:47 +0200
Sascha Hauer <s.hauer-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org> wrote:

> Hi David and all,
> 
> I need the following patch on my (little endian) System to
> successfully read the csd/cid structure.
> 

The resp field should already be in host order, so there must be a bug
in the mmc/spi host controller driver.

Rgds
-- 
     -- Pierre Ossman

  Linux kernel, MMC maintainer        http://www.kernel.org
  PulseAudio, core developer          http://pulseaudio.org
  rdesktop, core developer          http://www.rdesktop.org

-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems?  Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >>  http://get.splunk.com/

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [patch 3/4 2.6.23-rc2 + mm2-git-mmc] MMC core learns about SPI
       [not found]             ` <20070829165243.0236cc89-mgABNEgzgxm+PRNnhPf8W5YgPPQkE1Si@public.gmane.org>
@ 2007-08-29 16:43               ` David Brownell
       [not found]                 ` <200708290943.59450.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
  0 siblings, 1 reply; 35+ messages in thread
From: David Brownell @ 2007-08-29 16:43 UTC (permalink / raw)
  To: Pierre Ossman
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	Hans-Peter Nilsson, Mikael Starvik, Mike Lavender

On Wednesday 29 August 2007, Pierre Ossman wrote:
> 
> > I need the following patch on my (little endian) System to
> > successfully read the csd/cid structure.
> 
> The resp field should already be in host order, so there must be a bug
> in the mmc/spi host controller driver.

I wouldn't think it could be in host order ... what would have
changed it from wire-order, if not for a patch like Sascha sent?

This sounds like exactly the failure I'd expect from bugs caused
by omitted byteswapping, since I did all my recent work on a
big-endian machine.

- Dave

-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems?  Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >>  http://get.splunk.com/

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [patch 4/4 2.6.23-rc2 + mm2-git-mmc] mmc_spi host driver
       [not found]         ` <20070829100708.GB15021-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
@ 2007-08-29 16:59           ` David Brownell
       [not found]             ` <200708290959.33584.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
  0 siblings, 1 reply; 35+ messages in thread
From: David Brownell @ 2007-08-29 16:59 UTC (permalink / raw)
  To: Sascha Hauer
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	Mikael Starvik, Hans-Peter Nilsson, Mike Lavender, Pierre Ossman

On Wednesday 29 August 2007, Sascha Hauer wrote:
> Hi,
> 
> On Wed, Aug 08, 2007 at 09:12:54AM -0700, David Brownell wrote:
> > +
> > +		dev_dbg(&spi->dev, "    mmc_spi: STOP_TRAN\n");
> > +
> > +		/* Tweak the per-block message we set up earlier by morphing
> > +		 * it to hold single buffer with the token followed by some
> > +		 * all-ones bytes ... skip N(BR) (0..1), scan the rest for
> > +		 * "not busy any longer" status, and leave chip selected.
> > +		 */
> > +		INIT_LIST_HEAD(&host->m.transfers);
> > +		list_add(&host->early_status.transfer_list,
> > +				&host->m.transfers);
> > +
> > +		scratch->status[0] = SPI_TOKEN_STOP_TRAN;
> > +		memset(scratch->status + 1, 0xff, statlen - 1);
> > +		host->early_status.tx_buf = host->early_status.rx_buf;
> > +		host->early_status.tx_dma = host->early_status.rx_dma;
> > +		host->early_status.len = 1 + statlen;
> > +
> 
> The length to transfer here is statlen, not statlen + 1.

Right -- ACK.  Although the code could be shrunk a smidgeon
(and IMO made clearer) by doing the memset of the full buffer,
then just overwriting the first byte with that token.


> With the following 
> patch applied the driver works more reliably for me, though not perfect.
> I still get occasional errors like this from some SD cards:
> 
> mmcblk0: error 2 sending stop command

That would be an error on the READ path, yes?  Because the
SPI protocols only use a STOP command on multiblock reads.


> This is a crc error.

You're sure?  On my systems, error 2 == ENOENT, which is
only reported when an MMC or SD card fails CID fetch...


> There may be still problems in my (Hilscher netx)spi driver. 
> The mmc over spi stuff is the first testbed for this fresh driver. 

Feeling brave, aren't you?  :)


> For a 
> real crc error I would expect that they are somewhat dependent on the
> clock rate, but this does not seem to be the case. Before going deeper
> here, has any of you seen this or got an idea where to look for it?

Haven't noticed such a beast myself.  You can disable CRCs,
that could help rule out CRCs as the cause (or finger them
a bit more clearly).

- Dave

> 
> Sascha
> 
> 
> Signed-off-by: Sascha Hauer <s.hauer-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
> 
> ---
>  drivers/mmc/host/mmc_spi.c |    2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> Index: linux-2.6-arm/drivers/mmc/host/mmc_spi.c
> ===================================================================
> --- linux-2.6-arm.orig/drivers/mmc/host/mmc_spi.c
> +++ linux-2.6-arm/drivers/mmc/host/mmc_spi.c
> @@ -886,7 +886,7 @@ mmc_spi_data_do(struct mmc_spi_host *hos
>  		memset(scratch->status + 1, 0xff, statlen - 1);
>  		host->early_status.tx_buf = host->early_status.rx_buf;
>  		host->early_status.tx_dma = host->early_status.rx_dma;
> -		host->early_status.len = 1 + statlen;
> +		host->early_status.len = statlen;
>  
>  		if (host->dma_dev)
>  			dma_sync_single_for_device(host->dma_dev,
> 
> 
> 


-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems?  Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >>  http://get.splunk.com/

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [patch 4/4 2.6.23-rc2 + mm2-git-mmc] mmc_spi host driver
       [not found]             ` <200708290959.33584.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
@ 2007-08-29 19:39               ` Pierre Ossman
       [not found]                 ` <20070829213905.71236d24-mgABNEgzgxm+PRNnhPf8W5YgPPQkE1Si@public.gmane.org>
  2007-08-30  8:59               ` Sascha Hauer
  1 sibling, 1 reply; 35+ messages in thread
From: Pierre Ossman @ 2007-08-29 19:39 UTC (permalink / raw)
  To: David Brownell
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	Hans-Peter Nilsson, Mikael Starvik, Mike Lavender

On Wed, 29 Aug 2007 09:59:32 -0700
David Brownell <david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> wrote:

> On Wednesday 29 August 2007, Sascha Hauer wrote:
> > 
> > The length to transfer here is statlen, not statlen + 1.
> 
> Right -- ACK.  Although the code could be shrunk a smidgeon
> (and IMO made clearer) by doing the memset of the full buffer,
> then just overwriting the first byte with that token.
> 

Could I get that patch instead? Pretty please? :)

Rgds
-- 
     -- Pierre Ossman

  Linux kernel, MMC maintainer        http://www.kernel.org
  PulseAudio, core developer          http://pulseaudio.org
  rdesktop, core developer          http://www.rdesktop.org

-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems?  Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >>  http://get.splunk.com/

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [patch 4/4 2.6.23-rc2 + mm2-git-mmc] mmc_spi host driver
       [not found]                 ` <20070829213905.71236d24-mgABNEgzgxm+PRNnhPf8W5YgPPQkE1Si@public.gmane.org>
@ 2007-08-29 20:00                   ` David Brownell
  0 siblings, 0 replies; 35+ messages in thread
From: David Brownell @ 2007-08-29 20:00 UTC (permalink / raw)
  To: Pierre Ossman
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	Hans-Peter Nilsson, Mikael Starvik, Mike Lavender

On Wednesday 29 August 2007, Pierre Ossman wrote:

> Could I get that patch instead? Pretty please? :)

=======	CUT HERE
Small bugfix for an issue noted by Sascha Hauer <s.hauer-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>,
whereby a buffer length was the passed with the wrong size.  This also
includes a minor cleanup, to eliminate the error-prone +1/-1 stuff.

Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
---
 drivers/mmc/host/mmc_spi.c |    5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

--- g26.orig/drivers/mmc/host/mmc_spi.c	2007-08-29 12:53:41.000000000 -0700
+++ g26/drivers/mmc/host/mmc_spi.c	2007-08-29 12:54:24.000000000 -0700
@@ -882,11 +882,12 @@ mmc_spi_data_do(struct mmc_spi_host *hos
 		list_add(&host->early_status.transfer_list,
 				&host->m.transfers);
 
+		memset(scratch->status, 0xff, statlen);
 		scratch->status[0] = SPI_TOKEN_STOP_TRAN;
-		memset(scratch->status + 1, 0xff, statlen - 1);
+
 		host->early_status.tx_buf = host->early_status.rx_buf;
 		host->early_status.tx_dma = host->early_status.rx_dma;
-		host->early_status.len = 1 + statlen;
+		host->early_status.len = statlen;
 
 		if (host->dma_dev)
 			dma_sync_single_for_device(host->dma_dev,

-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems?  Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >>  http://get.splunk.com/

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [patch 4/4 2.6.23-rc2 + mm2-git-mmc] mmc_spi host driver
       [not found]             ` <200708290959.33584.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
  2007-08-29 19:39               ` Pierre Ossman
@ 2007-08-30  8:59               ` Sascha Hauer
       [not found]                 ` <20070830085900.GA18374-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
  1 sibling, 1 reply; 35+ messages in thread
From: Sascha Hauer @ 2007-08-30  8:59 UTC (permalink / raw)
  To: David Brownell
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	Mikael Starvik, Hans-Peter Nilsson, Mike Lavender, Pierre Ossman

On Wed, Aug 29, 2007 at 09:59:32AM -0700, David Brownell wrote:
> On Wednesday 29 August 2007, Sascha Hauer wrote:
> > Hi,
> > 
> > On Wed, Aug 08, 2007 at 09:12:54AM -0700, David Brownell wrote:
> > > +
> > > +		dev_dbg(&spi->dev, "    mmc_spi: STOP_TRAN\n");
> > > +
> > > +		/* Tweak the per-block message we set up earlier by morphing
> > > +		 * it to hold single buffer with the token followed by some
> > > +		 * all-ones bytes ... skip N(BR) (0..1), scan the rest for
> > > +		 * "not busy any longer" status, and leave chip selected.
> > > +		 */
> > > +		INIT_LIST_HEAD(&host->m.transfers);
> > > +		list_add(&host->early_status.transfer_list,
> > > +				&host->m.transfers);
> > > +
> > > +		scratch->status[0] = SPI_TOKEN_STOP_TRAN;
> > > +		memset(scratch->status + 1, 0xff, statlen - 1);
> > > +		host->early_status.tx_buf = host->early_status.rx_buf;
> > > +		host->early_status.tx_dma = host->early_status.rx_dma;
> > > +		host->early_status.len = 1 + statlen;
> > > +
> > 
> > The length to transfer here is statlen, not statlen + 1.
> 
> Right -- ACK.  Although the code could be shrunk a smidgeon
> (and IMO made clearer) by doing the memset of the full buffer,
> then just overwriting the first byte with that token.
> 
> 
> > With the following 
> > patch applied the driver works more reliably for me, though not perfect.
> > I still get occasional errors like this from some SD cards:
> > 
> > mmcblk0: error 2 sending stop command
> 
> That would be an error on the READ path, yes?  Because the
> SPI protocols only use a STOP command on multiblock reads.
> 
> 
> > This is a crc error.
> 
> You're sure?  On my systems, error 2 == ENOENT, which is
> only reported when an MMC or SD card fails CID fetch...

No, it's MMC_ERR_BADCRC. I don't use the patches from -mm at the moment,
I noticed that they report errno instead of MMC_ERR_*.

The problem with the crc is reproducible. I watched this on the logic
analyzer, it's the response from the card to a SPI_TOKEN_STOP_TRAN
transfer. It occurs on the very last block on an SD card:

mmc0: new SD card at address 0000
mmcblk0: mmc0:0000 S016B 14560KiB
 mmcblk0: p1

 root@netx:~> cat /dev/mmcblk0p1 > /dev/null
 mmcblk0: error 2 sending stop command
 end_request: I/O error, dev mmcblk0, sector 29112
 Buffer I/O error on device mmcblk0p1, logical block 3637
 mmcblk0: error 5 sending read/write command
 end_request: I/O error, dev mmcblk0, sector 29112
 Buffer I/O error on device mmcblk0p1, logical block 3637
 mmcblk0: error 5 sending read/write command
 end_request: I/O error, dev mmcblk0, sector 29112
 Buffer I/O error on device mmcblk0p1, logical block 3637
 cat: read error: Input/output error
 root@netx:~>                                                                

14560 * 1024 - 29112 * 512 = 4096

I tested this with six SD cards. They all behave like this except one
512MB Kingston card which works. A MMC card I tested works too.
Maybe we have to use a single block transfer on the last sector?

> 
> 
> > There may be still problems in my (Hilscher netx)spi driver. 
> > The mmc over spi stuff is the first testbed for this fresh driver. 
> 
> Feeling brave, aren't you?  :)

Sure, we do quality software here ;)

Sascha

-- 
Pengutronix - Linux Solutions for Science and Industry
Entwicklungszentrum Nord     http://www.pengutronix.de

-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems?  Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >>  http://get.splunk.com/

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [patch 4/4 2.6.23-rc2 + mm2-git-mmc] mmc_spi host driver
       [not found]                 ` <20070830085900.GA18374-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
@ 2007-08-30 18:56                   ` David Brownell
       [not found]                     ` <20070830185623.9C6CD231986-ZcXrCSuhvln6VZ3dlLfH/g4gEjPzgfUyLrfjE7I9kuVHxeISYlDBzl6hYfS7NtTn@public.gmane.org>
  0 siblings, 1 reply; 35+ messages in thread
From: David Brownell @ 2007-08-30 18:56 UTC (permalink / raw)
  To: s.hauer-bIcnvbaLZ9MEGnE8C9+IrQ
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	mikael.starvik-VrBV9hrLPhE, hans-peter.nilsson-VrBV9hrLPhE,
	mike-UTnDXsALFwNjMdQLN6DIHgC/G2K4zDHf,
	drzeus-mmc-p3sGCRWkH8CeZLLa646FqQ

> > > This is a crc error.
> > 
> > You're sure?  On my systems, error 2 == ENOENT, which is
> > only reported when an MMC or SD card fails CID fetch...
>
> No, it's MMC_ERR_BADCRC. I don't use the patches from -mm at the moment,
> I noticed that they report errno instead of MMC_ERR_*.

You should use the current patchset.  I think the rc3-mm1 git-mmc.patch
includes the fix for that merge botch I noted, and I *know* it also
includes a few notable fixes that earlier code didn't.  (None that
would seem to relate to this issue though.)


> The problem with the crc is reproducible. I watched this on the logic
> analyzer, it's the response from the card to a SPI_TOKEN_STOP_TRAN
> transfer. It occurs on the very last block on an SD card:

ISTR seeing some comment in a document pointing out that there can
be some odd faults reported when reading that block.  Maybe you've
found a case where the mmc_spi code needs updating.


> I tested this with six SD cards. They all behave like this except one
> 512MB Kingston card which works. A MMC card I tested works too.
> Maybe we have to use a single block transfer on the last sector?

Could be.  See what the current "Simplified SD" spec says ... I do
recall language about reading that sector, but it didn't seem to
matter for any of the cards I have for testing.  So I probably didn't
pay enough attention to those words.


> > > There may be still problems in my (Hilscher netx)spi driver. 
> > > The mmc over spi stuff is the first testbed for this fresh driver. 
> > 
> > Feeling brave, aren't you?  :)
>
> Sure, we do quality software here ;)

I can only applaud!  :)

None of the other protocol level SPI drivers seem to be quite as
demanding of the underlying controller drivers, so in that sense
it's a good testbed.  On the other hand, the mmc-over-SPI code is
a bit young, and various integration and corner-case issues are
still to be expected.

- Dave


-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems?  Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >>  http://get.splunk.com/

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [patch 4/4 2.6.23-rc2 + mm2-git-mmc] mmc_spi host driver
       [not found]                     ` <20070830185623.9C6CD231986-ZcXrCSuhvln6VZ3dlLfH/g4gEjPzgfUyLrfjE7I9kuVHxeISYlDBzl6hYfS7NtTn@public.gmane.org>
@ 2007-08-31 17:00                       ` Sascha Hauer
       [not found]                         ` <20070831170054.GA11112-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
  0 siblings, 1 reply; 35+ messages in thread
From: Sascha Hauer @ 2007-08-31 17:00 UTC (permalink / raw)
  To: David Brownell
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	mikael.starvik-VrBV9hrLPhE, hans-peter.nilsson-VrBV9hrLPhE,
	mike-UTnDXsALFwNjMdQLN6DIHgC/G2K4zDHf,
	drzeus-mmc-p3sGCRWkH8CeZLLa646FqQ

On Thu, Aug 30, 2007 at 11:56:23AM -0700, David Brownell wrote:
> > > > This is a crc error.
> > > 
> > > You're sure?  On my systems, error 2 == ENOENT, which is
> > > only reported when an MMC or SD card fails CID fetch...
> >
> > No, it's MMC_ERR_BADCRC. I don't use the patches from -mm at the moment,
> > I noticed that they report errno instead of MMC_ERR_*.
> 
> You should use the current patchset.  I think the rc3-mm1 git-mmc.patch
> includes the fix for that merge botch I noted, and I *know* it also
> includes a few notable fixes that earlier code didn't.  (None that
> would seem to relate to this issue though.)

Will do.

> 
> 
> > The problem with the crc is reproducible. I watched this on the logic
> > analyzer, it's the response from the card to a SPI_TOKEN_STOP_TRAN
> > transfer. It occurs on the very last block on an SD card:
> 
> ISTR seeing some comment in a document pointing out that there can
> be some odd faults reported when reading that block.  Maybe you've
> found a case where the mmc_spi code needs updating.
> 
> 
> > I tested this with six SD cards. They all behave like this except one
> > 512MB Kingston card which works. A MMC card I tested works too.
> > Maybe we have to use a single block transfer on the last sector?
> 
> Could be.  See what the current "Simplified SD" spec says ... I do
> recall language about reading that sector, but it didn't seem to
> matter for any of the cards I have for testing.  So I probably didn't
> pay enough attention to those words.

Unfortunately I did not find anything about that in the spec. If no
other idea comes up I will try what happens when I read the last block
using a single block read next week. The easiest way would be to fix it
in the mmc block driver. That should not be too much overhead for 'real'
SD cards, or is it?

> 
> 
> > > > There may be still problems in my (Hilscher netx)spi driver. 
> > > > The mmc over spi stuff is the first testbed for this fresh driver. 
> > > 
> > > Feeling brave, aren't you?  :)
> >
> > Sure, we do quality software here ;)
> 
> I can only applaud!  :)
> 
> None of the other protocol level SPI drivers seem to be quite as
> demanding of the underlying controller drivers, so in that sense
> it's a good testbed.  On the other hand, the mmc-over-SPI code is
> a bit young, and various integration and corner-case issues are
> still to be expected.

btw what is the reason why mmc_spi requires an unshared bus? Even the SD
spec talks about connecting multiple cards to one spi bus. Is it because
of the CS high phase during initialization?

Sascha

-- 
Pengutronix - Linux Solutions for Science and Industry
Entwicklungszentrum Nord     http://www.pengutronix.de

-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems?  Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >>  http://get.splunk.com/

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [patch 4/4 2.6.23-rc2 + mm2-git-mmc] mmc_spi host driver
       [not found]                         ` <20070831170054.GA11112-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
@ 2007-08-31 23:00                           ` David Brownell
       [not found]                             ` <20070831230050.4F31F2371AF-ZcXrCSuhvln6VZ3dlLfH/g4gEjPzgfUyLrfjE7I9kuVHxeISYlDBzl6hYfS7NtTn@public.gmane.org>
  0 siblings, 1 reply; 35+ messages in thread
From: David Brownell @ 2007-08-31 23:00 UTC (permalink / raw)
  To: s.hauer-bIcnvbaLZ9MEGnE8C9+IrQ
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	mikael.starvik-VrBV9hrLPhE, hans-peter.nilsson-VrBV9hrLPhE,
	mike-UTnDXsALFwNjMdQLN6DIHgC/G2K4zDHf,
	drzeus-mmc-p3sGCRWkH8CeZLLa646FqQ

> > > The problem with the crc is reproducible. I watched this on the logic
> > > analyzer, it's the response from the card to a SPI_TOKEN_STOP_TRAN
> > > transfer. It occurs on the very last block on an SD card:
> > 
> > ISTR seeing some comment in a document pointing out that there can
> > be some odd faults reported when reading that block.  Maybe you've
> > found a case where the mmc_spi code needs updating.

Did you verify that even with CRCs disabled, a problem appears?


> > > I tested this with six SD cards. They all behave like this except one
> > > 512MB Kingston card which works. A MMC card I tested works too.
> > > Maybe we have to use a single block transfer on the last sector?
> > 
> > Could be.  See what the current "Simplified SD" spec says ... I do
> > recall language about reading that sector, but it didn't seem to
> > matter for any of the cards I have for testing.  So I probably didn't
> > pay enough attention to those words.
>
> Unfortunately I did not find anything about that in the spec.

I'm sure I saw that, but have no idea what document it was in.  If
not the "Simplified" spec, then a vendor's card spec ... either
Sandisk (MMC, SD), Samsung, Hitachi, whatever.


>		If no
> other idea comes up I will try what happens when I read the last block
> using a single block read next week. The easiest way would be to fix it
> in the mmc block driver. That should not be too much overhead for 'real'
> SD cards, or is it?

I'd not think so.  That's more Pierre's call though.



> btw what is the reason why mmc_spi requires an unshared bus? Even the SD
> spec talks about connecting multiple cards to one spi bus. Is it because
> of the CS high phase during initialization?

There are a bunch of chipselect games MMC plays.  Notice how most of the
commands require the card to drive MISO for at least eight clocks after
they're deselected, too ... that means having the SPI host drive the
clock during that period too, also shifting out ones on MOSI.

I'm remembering that one of the issues was the handling of BUSY status,
which is a bit awkward but still remains one of the few places where
it would make sense to drop the chipselect and access another device.
But it still has those silly rules about "working" after chip deselect...

The canonical trouble spot is probably just reading a block.  That's
built out of any number of transactions, and it's not possible to know
in advance how many it will be.  So the host has to issue one, see if
the card's got data ready; if not, repeat until it is; then finally
process the actual data.  All *without* dropping chipselect.  And the
same issue comes up with both single and multiblock reads.

- Dave


-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems?  Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >>  http://get.splunk.com/

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [patch 4/4 2.6.23-rc2 + mm2-git-mmc] mmc_spi host driver
       [not found]                             ` <20070831230050.4F31F2371AF-ZcXrCSuhvln6VZ3dlLfH/g4gEjPzgfUyLrfjE7I9kuVHxeISYlDBzl6hYfS7NtTn@public.gmane.org>
@ 2007-09-04 10:54                               ` Sascha Hauer
       [not found]                                 ` <20070904105453.GD7579-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
  0 siblings, 1 reply; 35+ messages in thread
From: Sascha Hauer @ 2007-09-04 10:54 UTC (permalink / raw)
  To: David Brownell
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	mikael.starvik-VrBV9hrLPhE, hans-peter.nilsson-VrBV9hrLPhE,
	mike-UTnDXsALFwNjMdQLN6DIHgC/G2K4zDHf,
	drzeus-mmc-p3sGCRWkH8CeZLLa646FqQ

Hi David,

On Fri, Aug 31, 2007 at 04:00:51PM -0700, David Brownell wrote:
> > > > The problem with the crc is reproducible. I watched this on the logic
> > > > analyzer, it's the response from the card to a SPI_TOKEN_STOP_TRAN
> > > > transfer. It occurs on the very last block on an SD card:
> > > 
> > > ISTR seeing some comment in a document pointing out that there can
> > > be some odd faults reported when reading that block.  Maybe you've
> > > found a case where the mmc_spi code needs updating.
> 
> Did you verify that even with CRCs disabled, a problem appears?

Yes, this does not change anything.

> 
> 
> > > > I tested this with six SD cards. They all behave like this except one
> > > > 512MB Kingston card which works. A MMC card I tested works too.
> > > > Maybe we have to use a single block transfer on the last sector?
> > > 
> > > Could be.  See what the current "Simplified SD" spec says ... I do
> > > recall language about reading that sector, but it didn't seem to
> > > matter for any of the cards I have for testing.  So I probably didn't
> > > pay enough attention to those words.
> >
> > Unfortunately I did not find anything about that in the spec.
> 
> I'm sure I saw that, but have no idea what document it was in.  If
> not the "Simplified" spec, then a vendor's card spec ... either
> Sandisk (MMC, SD), Samsung, Hitachi, whatever.
> 

Still did not find something about it. I looked in the simplified spec
and in vendor specs from Toshiba and Sandisk.

I tried using a single block read for the last sector and this works for
me. I would be glad if a third person confirms that he actually needs
this patch as I'm still not sure whether theres a bug in my driver.

Here's the patch:


Some SD cards in SPI mode return a crc error when trying to read the
last block using a multiple block read. Use a single block read instead.

Signed-off-by: Sascha Hauer <s.hauer-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>

---
 drivers/mmc/card/block.c |   10 ++++++++++
 1 file changed, 10 insertions(+)

Index: linux-2.6-arm/drivers/mmc/card/block.c
===================================================================
--- linux-2.6-arm.orig/drivers/mmc/card/block.c
+++ linux-2.6-arm/drivers/mmc/card/block.c
@@ -244,6 +244,16 @@ static int mmc_blk_issue_rq(struct mmc_q
 		    !mmc_card_sd(card))
 			brq.data.blocks = 1;
 
+		/* Some SD cards in SPI mode return a crc error when trying
+		 * to read the last block using a multiread command.
+		 */
+		if (mmc_host_is_spi(card->host)
+				&& brq.data.blocks > 1
+				&& rq_data_dir(req) == READ
+				&& req->sector + req->nr_sectors ==
+					get_capacity(md->disk))
+			brq.data.blocks--;
+
 		if (brq.data.blocks > 1) {
 			brq.data.flags |= MMC_DATA_MULTI;
 			/* SPI multiblock writes terminate using a special



-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems?  Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >>  http://get.splunk.com/

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [patch 3/4 2.6.23-rc2 + mm2-git-mmc] MMC core learns about SPI
       [not found]                 ` <200708290943.59450.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
@ 2007-10-08 17:09                   ` Jan Nikitenko
       [not found]                     ` <470A644A.8030405-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
  0 siblings, 1 reply; 35+ messages in thread
From: Jan Nikitenko @ 2007-10-08 17:09 UTC (permalink / raw)
  To: David Brownell
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	Mikael Starvik, Hans-Peter Nilsson, Mike Lavender, Pierre Ossman

[-- Attachment #1: Type: text/plain, Size: 2704 bytes --]

David Brownell wrote:
> On Wednesday 29 August 2007, Pierre Ossman wrote:
>>> I need the following patch on my (little endian) System to
>>> successfully read the csd/cid structure.
>> The resp field should already be in host order, so there must be a bug
>> in the mmc/spi host controller driver.
> 
> I wouldn't think it could be in host order ... what would have
> changed it from wire-order, if not for a patch like Sascha sent?
> 
> This sounds like exactly the failure I'd expect from bugs caused
> by omitted byteswapping, since I did all my recent work on a
> big-endian machine.
> 

I can confirm, that the byte-swapping patch from Sascha is needed on my
little endian mips testbed too.

I can also see, that in earlier versions of mmc-spi, the byte swapping
was present in there together with routine to read csd/cid. Now it is
handled in mmc core, without byte swapping, so it does not work on
little endian systems...

I've tested mmc-spi from linux-2.6.23-rc8-mm2, plus:
  - added byte-swapping patch from Sascha
  - added buffer length patch from Sascha as improved by David

This resulted in nearly working mmc-spi, except the problem with the
last sector(s).
Tried to apply the fix to force single block read for last sector as
suggested by Sascha, but it fails not with the last sector, but several
of them at the end, with following error:
mmcblk0: error -22 sending stop command

Changing the patch to use single block reads for any of 8 sectors at the
end of sd card, it works perfectly.

In addition to that, it seems, that retries are not enabled for sector
access in mmc core, so I needed to add set of brq.cmd.retries into
mmc_blk_issue_rq() and also checking of mrq->data->error and
mrq->stop->error with call to host->ops->request() into mmc_request_done().

Otherwise, block transfers are never retried. And there are cases, that
errors are caused by too long wires and high frequencies in my
environment, so retries are sometimes very useful.

Finally I have tested also the suspend/resume callbacks of mmc core.
As I am using sd card in embedded environment (assuming that sd card
will never be removed), so MMC_UNSAFE_RESUME is good to me.

However, it seems to me, that the
-               if (!blk_queue_plugged(q))
                        req = elv_next_request(q);
in mmc_queue_thread() is too kind to accept new requests, even when the
queue is stopped.

This seems to be much better for faster suspending:
+               if (!blk_queue_plugged(q) && !blk_queue_stopped(q))
                        req = elv_next_request(q);
so that new requests are not accepted if queue is stopped or plugged.

See the complete patches bellow, please.

Thanks and best regards,
Jan


[-- Attachment #2: mmc-last-block-single-block-read.patch --]
[-- Type: text/plain, Size: 811 bytes --]

diff -urNp linux-2.6-orig/drivers/mmc/card/block.c linux-2.6/drivers/mmc/card/block.c
--- linux-2.6-orig/drivers/mmc/card/block.c	2007-10-08 15:39:28.000000000 +0200
+++ linux-2.6/drivers/mmc/card/block.c	2007-10-08 15:00:55.000000000 +0200
@@ -244,6 +244,16 @@ static int mmc_blk_issue_rq(struct mmc_q
 		    !mmc_card_sd(card))
 			brq.data.blocks = 1;
 
+		/* Some SD cards in SPI mode return a crc error when trying
+		 * to read the last block using a multiread command.
+		 */
+		if (mmc_host_is_spi(card->host)
+				&& brq.data.blocks > 1
+				&& rq_data_dir(req) == READ
+				&& req->sector + req->nr_sectors >=
+					get_capacity(md->disk)-8)
+			brq.data.blocks = 1;
+
 		if (brq.data.blocks > 1) {
 			/* SPI multiblock writes terminate using a special
 			 * token, not a STOP_TRANSMISSION request.

[-- Attachment #3: mmc-sector-retry-enable.patch --]
[-- Type: text/plain, Size: 1612 bytes --]

diff -urNp linux-2.6-orig/drivers/mmc/card/block.c linux-2.6/drivers/mmc/card/block.c
--- linux-2.6-orig/drivers/mmc/card/block.c	2007-10-08 10:26:01.000000000 +0200
+++ linux-2.6/drivers/mmc/card/block.c	2007-10-08 10:29:17.000000000 +0200
@@ -224,6 +224,7 @@ static int mmc_blk_issue_rq(struct mmc_q
 		if (!mmc_card_blockaddr(card))
 			brq.cmd.arg <<= 9;
 		brq.cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
+		brq.cmd.retries = 8;
 		brq.data.blksz = 1 << md->block_bits;
 		brq.stop.opcode = MMC_STOP_TRANSMISSION;
 		brq.stop.arg = 0;
diff -urNp linux-2.6-orig/drivers/mmc/core/core.c linux-2.6/drivers/mmc/core/core.c
--- linux-2.6-orig/drivers/mmc/core/core.c	2007-10-08 10:26:01.000000000 +0200
+++ linux-2.6/drivers/mmc/core/core.c	2007-10-08 17:01:12.000000000 +0200
@@ -102,6 +102,13 @@ void mmc_request_done(struct mmc_host *h
 			pr_debug("%s:     %d bytes transferred: %d\n",
 				mmc_hostname(host),
 				mrq->data->bytes_xfered, mrq->data->error);
+			if (mrq->data->error && cmd->retries) {
+				pr_debug("  ...DATA error: retrying...\n");
+				cmd->retries--;
+				cmd->error = 0;
+				mrq->data->error = 0;
+				host->ops->request(host, mrq);
+			}
 		}
 
 		if (mrq->stop) {
@@ -110,6 +117,13 @@ void mmc_request_done(struct mmc_host *h
 				mrq->stop->error,
 				mrq->stop->resp[0], mrq->stop->resp[1],
 				mrq->stop->resp[2], mrq->stop->resp[3]);
+			if (mrq->stop->error && cmd->retries) {
+				pr_debug("  ...STOP error: retrying...\n");
+				cmd->retries--;
+				cmd->error = 0;
+				mrq->stop->error = 0;
+				host->ops->request(host, mrq);
+			}
 		}
 
 		if (mrq->done)

[-- Attachment #4: mmc-suspend-queue-fix.patch --]
[-- Type: text/plain, Size: 542 bytes --]

diff -urNp linux-2.6-orig/drivers/mmc/card/queue.c linux-2.6/drivers/mmc/card/queue.c
--- linux-2.6-orig/drivers/mmc/card/queue.c	2007-10-08 10:26:01.000000000 +0200
+++ linux-2.6/drivers/mmc/card/queue.c	2007-10-08 10:31:00.000000000 +0200
@@ -53,7 +53,7 @@ static int mmc_queue_thread(void *d)
 
 		spin_lock_irq(q->queue_lock);
 		set_current_state(TASK_INTERRUPTIBLE);
-		if (!blk_queue_plugged(q))
+		if (!blk_queue_plugged(q) && !blk_queue_stopped(q))
 			req = elv_next_request(q);
 		mq->req = req;
 		spin_unlock_irq(q->queue_lock);

[-- Attachment #5: Type: text/plain, Size: 314 bytes --]

-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems?  Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >> http://get.splunk.com/

[-- Attachment #6: Type: text/plain, Size: 210 bytes --]

_______________________________________________
spi-devel-general mailing list
spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org
https://lists.sourceforge.net/lists/listinfo/spi-devel-general

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [patch 3/4 2.6.23-rc2 + mm2-git-mmc] MMC core learns about SPI
       [not found]                     ` <470A644A.8030405-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
@ 2007-10-10 18:36                       ` Pierre Ossman
       [not found]                         ` <c4bc83220710190240wd13bfd1r991ba9b1b1128f6c@mail.gmail.com>
  0 siblings, 1 reply; 35+ messages in thread
From: Pierre Ossman @ 2007-10-10 18:36 UTC (permalink / raw)
  To: Jan Nikitenko
  Cc: David Brownell,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	Mikael Starvik, Hans-Peter Nilsson, Mike Lavender

On Mon, 08 Oct 2007 19:09:30 +0200
Jan Nikitenko <jan.nikitenko-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:

> 
> I can confirm, that the byte-swapping patch from Sascha is needed on
> my little endian mips testbed too.
> 
> I can also see, that in earlier versions of mmc-spi, the byte swapping
> was present in there together with routine to read csd/cid. Now it is
> handled in mmc core, without byte swapping, so it does not work on
> little endian systems...
> 

Odd. Could you point to the byte swapping in the earlier version?

> I've tested mmc-spi from linux-2.6.23-rc8-mm2, plus:
>   - added byte-swapping patch from Sascha
>   - added buffer length patch from Sascha as improved by David
> 
> This resulted in nearly working mmc-spi, except the problem with the
> last sector(s).
> Tried to apply the fix to force single block read for last sector as
> suggested by Sascha, but it fails not with the last sector, but
> several of them at the end, with following error:
> mmcblk0: error -22 sending stop command
> 
> Changing the patch to use single block reads for any of 8 sectors at
> the end of sd card, it works perfectly.
> 

This is extremely weird. How common is this? (i.e. how many cards have
you tested and how many fail).

Also, do you have some easy test case so that I can check with my stash?

> In addition to that, it seems, that retries are not enabled for sector
> access in mmc core, so I needed to add set of brq.cmd.retries into
> mmc_blk_issue_rq() and also checking of mrq->data->error and
> mrq->stop->error with call to host->ops->request() into
> mmc_request_done().
> 
> Otherwise, block transfers are never retried. And there are cases,
> that errors are caused by too long wires and high frequencies in my
> environment, so retries are sometimes very useful.
> 

Then you need to fix your board. Retrying write with a translation
layer in the middle (the FTL on the card) can cause all kinds of weird
results. So it's up to upper layers how to handle failures.

> Finally I have tested also the suspend/resume callbacks of mmc core.
> As I am using sd card in embedded environment (assuming that sd card
> will never be removed), so MMC_UNSAFE_RESUME is good to me.
> 
> However, it seems to me, that the
> -               if (!blk_queue_plugged(q))
>                         req = elv_next_request(q);
> in mmc_queue_thread() is too kind to accept new requests, even when
> the queue is stopped.
> 
> This seems to be much better for faster suspending:
> +               if (!blk_queue_plugged(q) && !blk_queue_stopped(q))
>                         req = elv_next_request(q);
> so that new requests are not accepted if queue is stopped or plugged.
> 

I'd rather not muck about with working code unless there is an actual
gain. Have you observed a problem caused by the queue flush?

Rgds
-- 
     -- Pierre Ossman

  Linux kernel, MMC maintainer        http://www.kernel.org
  PulseAudio, core developer          http://pulseaudio.org
  rdesktop, core developer          http://www.rdesktop.org

-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems?  Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >> http://get.splunk.com/

^ permalink raw reply	[flat|nested] 35+ messages in thread

* [patch 3/4 2.6.23-rc2 + mm2-git-mmc] MMC core learns about SPI
       [not found]                           ` <c4bc83220710190240wd13bfd1r991ba9b1b1128f6c-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2007-10-19  9:50                             ` Jan Nikitenko
       [not found]                               ` <c4bc83220710190250m6c3401end194917e2daa9104-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
  0 siblings, 1 reply; 35+ messages in thread
From: Jan Nikitenko @ 2007-10-19  9:50 UTC (permalink / raw)
  To: Pierre Ossman
  Cc: David Brownell,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	Mikael Starvik, Hans-Peter Nilsson, Mike Lavender

On 10/10/07, Pierre Ossman <drzeus-mmc-p3sGCRWkH8CeZLLa646FqQ@public.gmane.org> wrote:
> On Mon, 08 Oct 2007 19:09:30 +0200
> Jan Nikitenko <jan.nikitenko-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
>
> >
> > I can confirm, that the byte-swapping patch from Sascha is needed on
> > my little endian mips testbed too.
> >
> > I can also see, that in earlier versions of mmc-spi, the byte swapping
> > was present in there together with routine to read csd/cid. Now it is
> > handled in mmc core, without byte swapping, so it does not work on
> > little endian systems...
> >
>
> Odd. Could you point to the byte swapping in the earlier version?

It was present in mmc-spi update patch posted here for example:
http://sourceforge.net/mailarchive/message.php?msg_id=200706042025.18252.david-b%40pacbell.net
Check the mmc_spi_read_cXd(), there are be32_to_cpus() calls present.

>
> > I've tested mmc-spi from linux-2.6.23-rc8-mm2, plus:
> >   - added byte-swapping patch from Sascha
> >   - added buffer length patch from Sascha as improved by David
> >
> > This resulted in nearly working mmc-spi, except the problem with the
> > last sector(s).
> > Tried to apply the fix to force single block read for last sector as
> > suggested by Sascha, but it fails not with the last sector, but
> > several of them at the end, with following error:
> > mmcblk0: error -22 sending stop command
> >
> > Changing the patch to use single block reads for any of 8 sectors at
> > the end of sd card, it works perfectly.
> >
>
> This is extremely weird. How common is this? (i.e. how many cards have
> you tested and how many fail).

well, it is the same for all 3 out of 3 different SD cards I have here:
mmcblk0: mmc0:0000 SD    999936KiB    (myFlash Turbo SD 150x 1GB A-Data)
mmcblk0: mmc0:0000 SMI-S 126464KiB  (X4store?)
mmcblk0: mmc0:0000 AF SD 249856KiB  (X4store?)

>
> Also, do you have some easy test case so that I can check with my stash?

I used just the dd command to read last 256 sectors (i.e.128KiB).
With patch from Sascha, it reads only 248 sectors.
Using my modification, it reads full 256 sectors at the end of sd card.

>
> > In addition to that, it seems, that retries are not enabled for sector
> > access in mmc core, so I needed to add set of brq.cmd.retries into
> > mmc_blk_issue_rq() and also checking of mrq->data->error and
> > mrq->stop->error with call to host->ops->request() into
> > mmc_request_done().
> >
> > Otherwise, block transfers are never retried. And there are cases,
> > that errors are caused by too long wires and high frequencies in my
> > environment, so retries are sometimes very useful.
> >
>
> Then you need to fix your board. Retrying write with a translation
> layer in the middle (the FTL on the card) can cause all kinds of weird
> results. So it's up to upper layers how to handle failures.

The board is ok, it is due to that the sd card is on external board,
connected wia cable, so it might happen rarely using 8.1MHz spi clock,
that there is an error in the transfer. As said, it works in 99.9%.
But when there is an error, retry is useful. The number of retries of
8 was a bit exaggerated, just one retry suffices for the setup I have
here.
What do you mean by FTL on the card?

>
> > Finally I have tested also the suspend/resume callbacks of mmc core.
> > As I am using sd card in embedded environment (assuming that sd card
> > will never be removed), so MMC_UNSAFE_RESUME is good to me.
> >
> > However, it seems to me, that the
> > -               if (!blk_queue_plugged(q))
> >                         req = elv_next_request(q);
> > in mmc_queue_thread() is too kind to accept new requests, even when
> > the queue is stopped.
> >
> > This seems to be much better for faster suspending:
> > +               if (!blk_queue_plugged(q) && !blk_queue_stopped(q))
> >                         req = elv_next_request(q);
> > so that new requests are not accepted if queue is stopped or plugged.
> >
>
> I'd rather not muck about with working code unless there is an actual
> gain. Have you observed a problem caused by the queue flush?

Without the !blk_queue_stopped(q) check, the suspend waits until dd
command finishes it's  job.
If the check is there, it's possible to suspend when dd command (or
any other file copy command) is running and properly resume after.

Best regards,
Jan

-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems?  Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >> http://get.splunk.com/

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [patch 3/4 2.6.23-rc2 + mm2-git-mmc] MMC core learns about SPI
       [not found]                               ` <c4bc83220710190250m6c3401end194917e2daa9104-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2007-10-22 18:34                                 ` Pierre Ossman
       [not found]                                   ` <20071022203428.300117e4-mgABNEgzgxm+PRNnhPf8W5YgPPQkE1Si@public.gmane.org>
  0 siblings, 1 reply; 35+ messages in thread
From: Pierre Ossman @ 2007-10-22 18:34 UTC (permalink / raw)
  To: Jan Nikitenko
  Cc: David Brownell,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	Mikael Starvik, Hans-Peter Nilsson, Mike Lavender

[-- Attachment #1: Type: text/plain, Size: 1818 bytes --]

On Fri, 19 Oct 2007 11:50:16 +0200
"Jan Nikitenko" <jan.nikitenko-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:

> On 10/10/07, Pierre Ossman <drzeus-mmc-p3sGCRWkH8CeZLLa646FqQ@public.gmane.org> wrote:
> >
> > Odd. Could you point to the byte swapping in the earlier version?
> 
> It was present in mmc-spi update patch posted here for example:
> http://sourceforge.net/mailarchive/message.php?msg_id=200706042025.18252.david-b%40pacbell.net
> Check the mmc_spi_read_cXd(), there are be32_to_cpus() calls present.
> 

Ah. I see what you mean now. The problem is in the data transfer, not a response field. So Sacha's patch was almost correct. Could you test if the included patch solves your issue?

> What do you mean by FTL on the card?
> 

The wear leveling and other voodoo that translates block commands to NAND storage. If we send a write multiple times and the card fails it partially, then we have no idea what it has actually committed to NAND. Hence we play it safe and let upper layers handle the policy of retrying.

> 
> Without the !blk_queue_stopped(q) check, the suspend waits until dd
> command finishes it's  job.

Not quite. It should just wait for the data dd has currently queued up (which should be 1 bs plus possible read-ahead).

> If the check is there, it's possible to suspend when dd command (or
> any other file copy command) is running and properly resume after.
> 

OTOH, letting them finish reduces the number of dirty pages that might have to be committed to disk for a hibernation.

Is this really a problem that plagues you, or just something you noticed in the code?

Rgds
-- 
     -- Pierre Ossman

  Linux kernel, MMC maintainer        http://www.kernel.org
  PulseAudio, core developer          http://pulseaudio.org
  rdesktop, core developer          http://www.rdesktop.org

[-- Attachment #2: be32.patch --]
[-- Type: text/x-patch, Size: 1217 bytes --]

diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index bf4bc6a..8b20e55 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -267,15 +267,26 @@ mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host,
 
 int mmc_send_csd(struct mmc_card *card, u32 *csd)
 {
+	int ret, i;
+
 	if (!mmc_host_is_spi(card->host))
 		return mmc_send_cxd_native(card->host, card->rca << 16,
 				csd, MMC_SEND_CSD);
 
-	return mmc_send_cxd_data(card, card->host, MMC_SEND_CSD, csd, 16);
+	ret = mmc_send_cxd_data(card, card->host, MMC_SEND_CSD, csd, 16);
+	if (ret)
+		return ret;
+
+	for (i = 0;i < 4;i++)
+		csd[i] = be32_to_cpu(csd[i]);
+
+	return 0;
 }
 
 int mmc_send_cid(struct mmc_host *host, u32 *cid)
 {
+	int ret, i;
+
 	if (!mmc_host_is_spi(host)) {
 		if (!host->card)
 			return -EINVAL;
@@ -283,7 +294,14 @@ int mmc_send_cid(struct mmc_host *host, u32 *cid)
 				cid, MMC_SEND_CID);
 	}
 
-	return mmc_send_cxd_data(NULL, host, MMC_SEND_CID, cid, 16);
+	ret = mmc_send_cxd_data(NULL, host, MMC_SEND_CID, cid, 16);
+	if (ret)
+		return ret;
+
+	for (i = 0;i < 4;i++)
+		cid[i] = be32_to_cpu(cid[i]);
+
+	return 0;
 }
 
 int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd)

[-- Attachment #3: Type: text/plain, Size: 314 bytes --]

-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems?  Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >> http://get.splunk.com/

[-- Attachment #4: Type: text/plain, Size: 210 bytes --]

_______________________________________________
spi-devel-general mailing list
spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org
https://lists.sourceforge.net/lists/listinfo/spi-devel-general

^ permalink raw reply related	[flat|nested] 35+ messages in thread

* Re: [patch 3/4 2.6.23-rc2 + mm2-git-mmc] MMC core learns about SPI
       [not found]                                   ` <20071022203428.300117e4-mgABNEgzgxm+PRNnhPf8W5YgPPQkE1Si@public.gmane.org>
@ 2007-10-23  8:06                                     ` Jan Nikitenko
       [not found]                                       ` <471DAB71.8000808-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
  0 siblings, 1 reply; 35+ messages in thread
From: Jan Nikitenko @ 2007-10-23  8:06 UTC (permalink / raw)
  To: Pierre Ossman
  Cc: Hans-Peter Nilsson, David Brownell, Mikael Starvik,
	Mike Lavender,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f

Pierre Ossman wrote:
> On Fri, 19 Oct 2007 11:50:16 +0200
> "Jan Nikitenko" <jan.nikitenko-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
> 
>> On 10/10/07, Pierre Ossman <drzeus-mmc-p3sGCRWkH8CeZLLa646FqQ@public.gmane.org> wrote:
>>> Odd. Could you point to the byte swapping in the earlier version?
>> It was present in mmc-spi update patch posted here for example:
>> http://sourceforge.net/mailarchive/message.php?msg_id=200706042025.18252.david-b%40pacbell.net
>> Check the mmc_spi_read_cXd(), there are be32_to_cpus() calls present.
>>
> 
> Ah. I see what you mean now. The problem is in the data transfer, not a response field. So Sacha's patch was almost correct. Could you test if the included patch solves your issue?

With your patch it works as good as with the one from Sascha.

>> Without the !blk_queue_stopped(q) check, the suspend waits until dd
>> command finishes it's  job.
> 
> Not quite. It should just wait for the data dd has currently queued up (which should be 1 bs plus possible read-ahead).
> 
>> If the check is there, it's possible to suspend when dd command (or
>> any other file copy command) is running and properly resume after.
>>
> 
> OTOH, letting them finish reduces the number of dirty pages that might have to be committed to disk for a hibernation.

That's true.

> 
> Is this really a problem that plagues you, or just something you noticed in the code?

It is that we need to suspend as soon as possible because of power loss.
Waiting to flush all the caches does not help, because there will not be
enough time with backup power. So it's better not to start any new block
requests to safe as much backup power as possible and to avoid
interrupted block transfer.

Best regards,
Jan

-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems?  Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >> http://get.splunk.com/

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [patch 3/4 2.6.23-rc2 + mm2-git-mmc] MMC core learns about SPI
       [not found]                                       ` <471DAB71.8000808-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
@ 2007-10-27 12:08                                         ` Pierre Ossman
       [not found]                                           ` <20071027140823.5d7ec7e2-mgABNEgzgxm+PRNnhPf8W5YgPPQkE1Si@public.gmane.org>
  0 siblings, 1 reply; 35+ messages in thread
From: Pierre Ossman @ 2007-10-27 12:08 UTC (permalink / raw)
  To: Jan Nikitenko
  Cc: Hans-Peter Nilsson, David Brownell, Mikael Starvik,
	Mike Lavender,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f

On Tue, 23 Oct 2007 10:06:09 +0200
Jan Nikitenko <jan.nikitenko-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:

> Pierre Ossman wrote:
> > Ah. I see what you mean now. The problem is in the data transfer, not a response field. So Sacha's patch was almost correct. Could you test if the included patch solves your issue?
> 
> With your patch it works as good as with the one from Sascha.
> 

Great. I'll send it to Linus then.

(Just in case it wasn't apparent, my patch was different from Sascha's as his flipped some stuff that shouldn't)

> > 
> > Is this really a problem that plagues you, or just something you noticed in the code?
> 
> It is that we need to suspend as soon as possible because of power loss.
> Waiting to flush all the caches does not help, because there will not be
> enough time with backup power. So it's better not to start any new block
> requests to safe as much backup power as possible and to avoid
> interrupted block transfer.
> 

Ah, that is a very good point. Could I bother you with having a look at how other parts of the kernel does things?

Rgds
-- 
     -- Pierre Ossman

  Linux kernel, MMC maintainer        http://www.kernel.org
  PulseAudio, core developer          http://pulseaudio.org
  rdesktop, core developer          http://www.rdesktop.org

-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems?  Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >> http://get.splunk.com/

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [patch 3/4 2.6.23-rc2 + mm2-git-mmc] MMC core learns about SPI
       [not found]                                           ` <20071027140823.5d7ec7e2-mgABNEgzgxm+PRNnhPf8W5YgPPQkE1Si@public.gmane.org>
@ 2007-10-27 16:33                                             ` David Brownell
       [not found]                                               ` <200710270933.30538.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
  0 siblings, 1 reply; 35+ messages in thread
From: David Brownell @ 2007-10-27 16:33 UTC (permalink / raw)
  To: Pierre Ossman
  Cc: Hans-Peter Nilsson, Mikael Starvik, Mike Lavender,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f

On Saturday 27 October 2007, Pierre Ossman wrote:
> > > Is this really a problem that plagues you, or just something you
> > > noticed in the code? 
> > 
> > It is that we need to suspend as soon as possible because of power loss.
> > Waiting to flush all the caches does not help, because there will not be
> > enough time with backup power. So it's better not to start any new block
> > requests to safe as much backup power as possible and to avoid
> > interrupted block transfer.
> 
> Ah, that is a very good point. Could I bother you with having a look at how
> other parts of the kernel does things? 

That'll be interesting to know ... but I think the "panic suspend"
should probably have different code paths than "normal suspend".

In the normal case, there's no power shortage *just now* and the
safest shutdown sequence is appropriate.  Notably, all removable
media should have I/O be fully flushed, and the filesystem made
consistent.  And on resume, the filesystem should NOT be assumed
to be in the same state it was on suspend.

In the panic case, like this, power may not be available, and the
prayer is that some can be found before too long.

>From earlier discussions elsewhere, I think neither of those cases
is handled all that well.  If anything, there's an assumption that
suspend is never done in a panic ... but that there's no need to
make the filesystem fully consistent/clean since media aren't
removable.

- Dave

-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems?  Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >> http://get.splunk.com/

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [patch 3/4 2.6.23-rc2 + mm2-git-mmc] MMC core learns about SPI
       [not found]                                               ` <200710270933.30538.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
@ 2007-10-29  8:02                                                 ` Jan Nikitenko
  0 siblings, 0 replies; 35+ messages in thread
From: Jan Nikitenko @ 2007-10-29  8:02 UTC (permalink / raw)
  To: David Brownell
  Cc: Hans-Peter Nilsson, Mikael Starvik, Mike Lavender,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	Pierre Ossman

David Brownell wrote:
> On Saturday 27 October 2007, Pierre Ossman wrote:
>>>> Is this really a problem that plagues you, or just something you
>>>> noticed in the code? 
>>> It is that we need to suspend as soon as possible because of power loss.
>>> Waiting to flush all the caches does not help, because there will not be
>>> enough time with backup power. So it's better not to start any new block
>>> requests to safe as much backup power as possible and to avoid
>>> interrupted block transfer.
>> Ah, that is a very good point. Could I bother you with having a look at how
>> other parts of the kernel does things? 
> 
> That'll be interesting to know ... but I think the "panic suspend"
> should probably have different code paths than "normal suspend".

I completely agree.

The thing with having a look at other parts of the kernel in this matter
is that we do not use the latest kernel because of corporate policy
unfortunately. So I need to backport useful things to 2.6.17 kernel:-(

Best regards,
Jan

-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems?  Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >> http://get.splunk.com/

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [patch 4/4 2.6.23-rc2 + mm2-git-mmc] mmc_spi host driver
       [not found]                                 ` <20070904105453.GD7579-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
@ 2007-11-15 23:30                                   ` David Brownell
       [not found]                                     ` <200711151530.06591.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
  0 siblings, 1 reply; 35+ messages in thread
From: David Brownell @ 2007-11-15 23:30 UTC (permalink / raw)
  To: Sascha Hauer, drzeus-mmc-p3sGCRWkH8CeZLLa646FqQ
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	mikael.starvik-VrBV9hrLPhE, hans-peter.nilsson-VrBV9hrLPhE,
	mike-UTnDXsALFwNjMdQLN6DIHgC/G2K4zDHf

On Tuesday 04 September 2007, Sascha Hauer wrote:
> Hi David,
> 
> On Fri, Aug 31, 2007 at 04:00:51PM -0700, David Brownell wrote:
> > > > > The problem with the crc is reproducible. I watched this on the logic
> > > > > analyzer, it's the response from the card to a SPI_TOKEN_STOP_TRAN
> > > > > transfer. It occurs on the very last block on an SD card:
> > > > 
> > > > ISTR seeing some comment in a document pointing out that there can
> > > > be some odd faults reported when reading that block.  Maybe you've
> > > > found a case where the mmc_spi code needs updating.
> > 
> > Did you verify that even with CRCs disabled, a problem appears?
> 
> Yes, this does not change anything.

I suspect this is a case where a fault code gets overloaded.
There aren't many codes defined, after all!


> > > > > I tested this with six SD cards. They all behave like this except one
> > > > > 512MB Kingston card which works. A MMC card I tested works too.
> > > > > Maybe we have to use a single block transfer on the last sector?
> > > > 
> > > > Could be.  See what the current "Simplified SD" spec says ... I do
> > > > recall language about reading that sector, but it didn't seem to
> > > > matter for any of the cards I have for testing.  So I probably didn't
> > > > pay enough attention to those words.
> > >
> > > Unfortunately I did not find anything about that in the spec.
> > 
> > I'm sure I saw that, but have no idea what document it was in.  If
> > not the "Simplified" spec, then a vendor's card spec ... either
> > Sandisk (MMC, SD), Samsung, Hitachi, whatever.
> > 
> 
> Still did not find something about it. I looked in the simplified spec
> and in vendor specs from Toshiba and Sandisk.

I'm still sure I saw it.  Maybe I'll try searching for that text
myself, it's surely in one of half a dozen huge documents I have
sitting around in PDF form.  ;)

I think there may be a regression in this area.  When debugging
this updated code, I was able to "dd" an entire SanDisk SD card
without any errors.  But when I tried this a short while ago, I
saw the kind of error you report.  I don't believe the SanDisk
card suddenly broke.

Your patch prevented that problem from appearing ...

Now, taking only a very brief look at this, I wonder if maybe
this isn't partly a symptom of an off-by-one error of some kind,
with the current MMC stack asking for too much data.  It must
be requesting two blocks, since subtracting one turns it into
a single block read ... but for some reason I count a multiblock
read of eight blocks, indicating sg_len is eight not two.

Anyway, here's some debug output.  It's the tail end of two
DD sessions, one with a generic kernel and one with your patch.
Only the latter one worked.

- Dave


====	#1

	This is generic 2.6.24-rc2 (in terms of MMC patches), with
	mmc_spi debugging enabled

	The card is a 128 MB SanDisk SD card.  The command is:

	# dd bs=4k if=/dev/mmcblk0 of=/dev/null

	Gets a CRC error (-84, -EILSEQ) from R1_SPI_COM_CRC status (0x08)
	when issuing CMD12 (MMC_STOP_TRANSMISSION).

mmc_spi spi1.0:   mmc_spi: CMD18, resp R1
mmc_spi spi1.0:     mmc_spi: read block, 512 bytes
mmc_spi spi1.0:     mmc_spi: read block, 512 bytes
mmc_spi spi1.0:     mmc_spi: read block, 512 bytes
mmc_spi spi1.0:     mmc_spi: read block, 512 bytes
mmc_spi spi1.0:     mmc_spi: read block, 512 bytes
mmc_spi spi1.0:     mmc_spi: read block, 512 bytes
mmc_spi spi1.0:     mmc_spi: read block, 512 bytes
mmc_spi spi1.0:     mmc_spi: read block, 512 bytes
mmc_spi spi1.0:   mmc_spi: CMD12, resp R1B
mmc_spi spi1.0:   mmc_spi: CMD18, resp R1
mmc_spi spi1.0:     mmc_spi: read block, 512 bytes
mmc_spi spi1.0:     mmc_spi: read block, 512 bytes
mmc_spi spi1.0:     mmc_spi: read block, 512 bytes
mmc_spi spi1.0:     mmc_spi: read block, 512 bytes
mmc_spi spi1.0:     mmc_spi: read block, 512 bytes
mmc_spi spi1.0:     mmc_spi: read block, 512 bytes
mmc_spi spi1.0:     mmc_spi: read block, 512 bytes
mmc_spi spi1.0:     mmc_spi: read block, 512 bytes
mmc_spi spi1.0:   mmc_spi: CMD12, resp R1B
mmc_spi spi1.0:   ... CMD12 response SPI_R1B: resp 0008 00000000
mmcblk0: error -84 sending stop command
end_request: I/O error, dev mmcblk0, sector 246008
Buffer I/O error on device mmcblk0, logical block 30751
mmc_spi spi1.0:   mmc_spi: CMD18, resp R1
mmc_spi spi1.0:   ... CMD18 response SPI_R1: resp 0004 00000000
mmcblk0: error -22 sending read/write command
end_request: I/O error, dev mmcblk0, sector 246008
Buffer I/O error on device mmcblk0, logical block 30751

	... and the DD command failed.


====	#2
	This is generic 2.6.24-rc2 (in terms of MMC patches), with
	mmc_spi debugging enabled, plus the patch from Sascha Hauer.

	The card is a 128 MB SanDisk SD card.  The command is:
 
	# dd bs=4k if=/dev/mmcblk0 of=/dev/null

	No problems ... although note that there was only *ONE* block
	read at the end, where the failing case tried reading eight.

mmc_spi spi1.0:   mmc_spi: CMD18, resp R1
mmc_spi spi1.0:     mmc_spi: read block, 512 bytes
mmc_spi spi1.0:     mmc_spi: read block, 512 bytes
mmc_spi spi1.0:     mmc_spi: read block, 512 bytes
mmc_spi spi1.0:     mmc_spi: read block, 512 bytes
mmc_spi spi1.0:     mmc_spi: read block, 512 bytes
mmc_spi spi1.0:     mmc_spi: read block, 512 bytes
mmc_spi spi1.0:     mmc_spi: read block, 512 bytes
mmc_spi spi1.0:     mmc_spi: read block, 512 bytes
mmc_spi spi1.0:   mmc_spi: CMD12, resp R1B
mmc_spi spi1.0:   mmc_spi: CMD18, resp R1
mmc_spi spi1.0:     mmc_spi: read block, 512 bytes
mmc_spi spi1.0:     mmc_spi: read block, 512 bytes
mmc_spi spi1.0:     mmc_spi: read block, 512 bytes
mmc_spi spi1.0:     mmc_spi: read block, 512 bytes
mmc_spi spi1.0:     mmc_spi: read block, 512 bytes
mmc_spi spi1.0:     mmc_spi: read block, 512 bytes
mmc_spi spi1.0:     mmc_spi: read block, 512 bytes
mmc_spi spi1.0:   mmc_spi: CMD12, resp R1B
mmc_spi spi1.0:   mmc_spi: CMD17, resp R1
mmc_spi spi1.0:     mmc_spi: read block, 512 bytes

	... and the DD command succeeded.


> I tried using a single block read for the last sector and this works for
> me. I would be glad if a third person confirms that he actually needs
> this patch as I'm still not sure whether theres a bug in my driver.

Looks to me like an issue higher up in the stack than your driver.

 
> Here's the patch:
> 
> 
> Some SD cards in SPI mode return a crc error when trying to read the
> last block using a multiple block read. Use a single block read instead.
> 
> Signed-off-by: Sascha Hauer <s.hauer-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
> 
> ---
>  drivers/mmc/card/block.c |   10 ++++++++++
>  1 file changed, 10 insertions(+)
> 
> Index: linux-2.6-arm/drivers/mmc/card/block.c
> ===================================================================
> --- linux-2.6-arm.orig/drivers/mmc/card/block.c
> +++ linux-2.6-arm/drivers/mmc/card/block.c
> @@ -244,6 +244,16 @@ static int mmc_blk_issue_rq(struct mmc_q
>  		    !mmc_card_sd(card))
>  			brq.data.blocks = 1;
>  
> +		/* Some SD cards in SPI mode return a crc error when trying
> +		 * to read the last block using a multiread command.
> +		 */
> +		if (mmc_host_is_spi(card->host)
> +				&& brq.data.blocks > 1
> +				&& rq_data_dir(req) == READ
> +				&& req->sector + req->nr_sectors ==
> +					get_capacity(md->disk))
> +			brq.data.blocks--;
> +
>  		if (brq.data.blocks > 1) {
>  			brq.data.flags |= MMC_DATA_MULTI;
>  			/* SPI multiblock writes terminate using a special
> 
> 



-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2005.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [patch 4/4 2.6.23-rc2 + mm2-git-mmc] mmc_spi host driver
       [not found]                                     ` <200711151530.06591.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
@ 2007-11-16  1:02                                       ` Hans-Peter Nilsson
       [not found]                                         ` <200711160102.lAG12Fdo031436-PT6ZA4s7Vg53Mq0XhIy4CVaTQe2KTcn/@public.gmane.org>
  0 siblings, 1 reply; 35+ messages in thread
From: Hans-Peter Nilsson @ 2007-11-16  1:02 UTC (permalink / raw)
  To: david-b-yBeKhBN/0LDR7s880joybQ
  Cc: hans-peter.nilsson-VrBV9hrLPhE, mikael.starvik-VrBV9hrLPhE,
	mike-UTnDXsALFwNjMdQLN6DIHgC/G2K4zDHf,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	drzeus-mmc-p3sGCRWkH8CeZLLa646FqQ

> From: David Brownell <david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
> Date: Thu, 15 Nov 2007 15:30:05 -0800

> On Tuesday 04 September 2007, Sascha Hauer wrote:
> > On Fri, Aug 31, 2007 at 04:00:51PM -0700, David Brownell wrote:
    (further attributions lost)
> > > > > > I tested this with six SD cards. They all behave like this except one
> > > > > > 512MB Kingston card which works. A MMC card I tested works too.
> > > > > > Maybe we have to use a single block transfer on the last sector?
> > > > > 
> > > > > Could be.  See what the current "Simplified SD" spec says ... I do
> > > > > recall language about reading that sector, but it didn't seem to
> > > > > matter for any of the cards I have for testing.  So I probably didn't
> > > > > pay enough attention to those words.
> > > >
> > > > Unfortunately I did not find anything about that in the spec.
> > > 
> > > I'm sure I saw that, but have no idea what document it was in.  If
> > > not the "Simplified" spec, then a vendor's card spec ... either
> > > Sandisk (MMC, SD), Samsung, Hitachi, whatever.
> > > 
> > 
> > Still did not find something about it. I looked in the simplified spec
> > and in vendor specs from Toshiba and Sandisk.
> 
> I'm still sure I saw it.  Maybe I'll try searching for that text
> myself, it's surely in one of half a dozen huge documents I have
> sitting around in PDF form.  ;)

That kind of rung a bell, and I just had to dive into my virtual
pile of MMC/SPI PDFs.  At time of this writing, the document is
still downloadable from www.sandisk.com.  The site changed since
I last was there, but once I just clicked my way to it:
<http://www.sandisk.com/Assets/File/OEM/Manuals/ProdManRS-MMCv1.3.pdf>.

In "Chapter 5 SPI Mode", section "5.14 Read Ahead in Multiple
Block Read Operation" on page 74, it says: "In Multiple Block
read operations, in order to improve read performance, the card
may fetch data from the memory array, ahead of the host. In this
case, when the host is reading the last addresses of the memory,
the card attempts to fetch data beyond the last physical memory
address and generates an OUT_OF_RANGE error. Therefore, even if
the host times the Stop Transmission command to stop the card
immediately after the last byte of data was read, the card may
already have generated the error, which will show in the
response to the Stop Transmission command. The host should
ignore this error."

HTH.

brgds, H-P
PS. FWIW, I've not been near MMC/SPI programming since January.

-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2005.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [patch 4/4 2.6.23-rc2 + mm2-git-mmc] mmc_spi host driver
       [not found]                                         ` <200711160102.lAG12Fdo031436-PT6ZA4s7Vg53Mq0XhIy4CVaTQe2KTcn/@public.gmane.org>
@ 2007-11-16 20:28                                           ` David Brownell
  0 siblings, 0 replies; 35+ messages in thread
From: David Brownell @ 2007-11-16 20:28 UTC (permalink / raw)
  To: Hans-Peter Nilsson
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	mikael.starvik-VrBV9hrLPhE,
	mike-UTnDXsALFwNjMdQLN6DIHgC/G2K4zDHf,
	drzeus-mmc-p3sGCRWkH8CeZLLa646FqQ

On Thursday 15 November 2007, Hans-Peter Nilsson wrote:
> That kind of rung a bell, and I just had to dive into my virtual
> pile of MMC/SPI PDFs.  At time of this writing, the document is
> still downloadable from www.sandisk.com.  The site changed since
> I last was there, but once I just clicked my way to it:
> <http://www.sandisk.com/Assets/File/OEM/Manuals/ProdManRS-MMCv1.3.pdf>.
> 
> In "Chapter 5 SPI Mode", section "5.14 Read Ahead in Multiple
> Block Read Operation" on page 74,

This seems to be what I was thinking about, thanks.


> it says: "In Multiple Block 
> read operations, in order to improve read performance, the card
> may fetch data from the memory array, ahead of the host. In this
> case, when the host is reading the last addresses of the memory,
> the card attempts to fetch data beyond the last physical memory
> address and generates an OUT_OF_RANGE error. Therefore, even if
> the host times the Stop Transmission command to stop the card
> immediately after the last byte of data was read, the card may
> already have generated the error, which will show in the
> response to the Stop Transmission command. The host should
> ignore this error."
> 
> HTH.

Yes, but it doesn't quite explain the specific failure mode
being observed ... which is a CRC error on the STOP command,
rather than an OUT_OF_RANGE token replacing start-of-data.

It's a small puzzle...

- Dave



> 
> brgds, H-P
> PS. FWIW, I've not been near MMC/SPI programming since January.
> 



-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2005.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/

^ permalink raw reply	[flat|nested] 35+ messages in thread

end of thread, other threads:[~2007-11-16 20:28 UTC | newest]

Thread overview: 35+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-08-08 16:06 [patch 0/4 2.6.23-rc2 + mm2-git-mmc] latest MMC-over-SPI support David Brownell
     [not found] ` <200708080906.18993.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
2007-08-08 16:09   ` [patch 1/4 2.6.23-rc2 + mm2-git-mmc] MMC headers learn about SPI David Brownell
2007-08-08 16:10   ` [patch 2/4 2.6.23-rc2 + mm2-git-mmc] MMC/SD card driver learns SPI David Brownell
2007-08-08 16:11   ` [patch 3/4 2.6.23-rc2 + mm2-git-mmc] MMC core learns about SPI David Brownell
     [not found]     ` <200708080911.33099.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
2007-08-09 13:07       ` Pierre Ossman
     [not found]         ` <20070809150747.62b1447a-mgABNEgzgxm+PRNnhPf8W5YgPPQkE1Si@public.gmane.org>
2007-08-09 15:35           ` David Brownell
     [not found]             ` <200708090835.42279.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
2007-08-09 20:18               ` Pierre Ossman
2007-08-12 15:50       ` David Brownell
     [not found]         ` <200708120850.04271.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
2007-08-12 15:52           ` Pierre Ossman
2007-08-29  9:22       ` Sascha Hauer
     [not found]         ` <20070829092247.GA15021-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
2007-08-29 14:52           ` Pierre Ossman
     [not found]             ` <20070829165243.0236cc89-mgABNEgzgxm+PRNnhPf8W5YgPPQkE1Si@public.gmane.org>
2007-08-29 16:43               ` David Brownell
     [not found]                 ` <200708290943.59450.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
2007-10-08 17:09                   ` Jan Nikitenko
     [not found]                     ` <470A644A.8030405-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2007-10-10 18:36                       ` Pierre Ossman
     [not found]                         ` <c4bc83220710190240wd13bfd1r991ba9b1b1128f6c@mail.gmail.com>
     [not found]                           ` <c4bc83220710190240wd13bfd1r991ba9b1b1128f6c-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2007-10-19  9:50                             ` Jan Nikitenko
     [not found]                               ` <c4bc83220710190250m6c3401end194917e2daa9104-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2007-10-22 18:34                                 ` Pierre Ossman
     [not found]                                   ` <20071022203428.300117e4-mgABNEgzgxm+PRNnhPf8W5YgPPQkE1Si@public.gmane.org>
2007-10-23  8:06                                     ` Jan Nikitenko
     [not found]                                       ` <471DAB71.8000808-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2007-10-27 12:08                                         ` Pierre Ossman
     [not found]                                           ` <20071027140823.5d7ec7e2-mgABNEgzgxm+PRNnhPf8W5YgPPQkE1Si@public.gmane.org>
2007-10-27 16:33                                             ` David Brownell
     [not found]                                               ` <200710270933.30538.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
2007-10-29  8:02                                                 ` Jan Nikitenko
2007-08-08 16:12   ` [patch 4/4 2.6.23-rc2 + mm2-git-mmc] mmc_spi host driver David Brownell
     [not found]     ` <200708080912.54918.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
2007-08-29 10:07       ` Sascha Hauer
     [not found]         ` <20070829100708.GB15021-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
2007-08-29 16:59           ` David Brownell
     [not found]             ` <200708290959.33584.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
2007-08-29 19:39               ` Pierre Ossman
     [not found]                 ` <20070829213905.71236d24-mgABNEgzgxm+PRNnhPf8W5YgPPQkE1Si@public.gmane.org>
2007-08-29 20:00                   ` David Brownell
2007-08-30  8:59               ` Sascha Hauer
     [not found]                 ` <20070830085900.GA18374-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
2007-08-30 18:56                   ` David Brownell
     [not found]                     ` <20070830185623.9C6CD231986-ZcXrCSuhvln6VZ3dlLfH/g4gEjPzgfUyLrfjE7I9kuVHxeISYlDBzl6hYfS7NtTn@public.gmane.org>
2007-08-31 17:00                       ` Sascha Hauer
     [not found]                         ` <20070831170054.GA11112-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
2007-08-31 23:00                           ` David Brownell
     [not found]                             ` <20070831230050.4F31F2371AF-ZcXrCSuhvln6VZ3dlLfH/g4gEjPzgfUyLrfjE7I9kuVHxeISYlDBzl6hYfS7NtTn@public.gmane.org>
2007-09-04 10:54                               ` Sascha Hauer
     [not found]                                 ` <20070904105453.GD7579-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
2007-11-15 23:30                                   ` David Brownell
     [not found]                                     ` <200711151530.06591.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
2007-11-16  1:02                                       ` Hans-Peter Nilsson
     [not found]                                         ` <200711160102.lAG12Fdo031436-PT6ZA4s7Vg53Mq0XhIy4CVaTQe2KTcn/@public.gmane.org>
2007-11-16 20:28                                           ` David Brownell
2007-08-09 10:45   ` [patch 0/4 2.6.23-rc2 + mm2-git-mmc] latest MMC-over-SPI support Anton Vorontsov
2007-08-09 13:05   ` Pierre Ossman

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).