diff options
| author | Ingo Molnar <mingo@elte.hu> | 2009-05-11 14:44:27 +0200 | 
|---|---|---|
| committer | Ingo Molnar <mingo@elte.hu> | 2009-05-11 14:44:31 +0200 | 
| commit | 41fb454ebe6024f5c1e3b3cbc0abc0da762e7b51 (patch) | |
| tree | 51c50bcb67a5039448ddfa1869d7948cab1217e9 /drivers/mmc/host/mmc_spi.c | |
| parent | 19c1a6f5764d787113fa323ffb18be7991208f82 (diff) | |
| parent | 091bf7624d1c90cec9e578a18529f615213ff847 (diff) | |
Merge commit 'v2.6.30-rc5' into core/iommu
Merge reason: core/iommu was on an .30-rc1 base,
              update it to .30-rc5 to refresh.
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'drivers/mmc/host/mmc_spi.c')
| -rw-r--r-- | drivers/mmc/host/mmc_spi.c | 188 | 
1 files changed, 133 insertions, 55 deletions
diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c index 72f8bde4877..f48349d18c9 100644 --- a/drivers/mmc/host/mmc_spi.c +++ b/drivers/mmc/host/mmc_spi.c @@ -24,7 +24,7 @@   * 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/sched.h>  #include <linux/delay.h>  #include <linux/bio.h>  #include <linux/dma-mapping.h> @@ -95,7 +95,7 @@   * reads which takes nowhere near that long.  Older cards may be able to use   * shorter timeouts ... but why bother?   */ -#define r1b_timeout		ktime_set(3, 0) +#define r1b_timeout		(HZ * 3)  /****************************************************************************/ @@ -183,12 +183,11 @@ mmc_spi_readbytes(struct mmc_spi_host *host, unsigned len)  	return status;  } -static int -mmc_spi_skip(struct mmc_spi_host *host, ktime_t timeout, unsigned n, u8 byte) +static int mmc_spi_skip(struct mmc_spi_host *host, unsigned long timeout, +			unsigned n, u8 byte)  {  	u8		*cp = host->data->status; - -	timeout = ktime_add(timeout, ktime_get()); +	unsigned long start = jiffies;  	while (1) {  		int		status; @@ -203,22 +202,26 @@ mmc_spi_skip(struct mmc_spi_host *host, ktime_t timeout, unsigned n, u8 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) +		if (time_is_before_jiffies(start + timeout))  			break; + +		/* If we need long timeouts, we may release the CPU. +		 * We use jiffies here because we want to have a relation +		 * between elapsed time and the blocking of the scheduler. +		 */ +		if (time_is_before_jiffies(start+1)) +			schedule();  	}  	return -ETIMEDOUT;  }  static inline int -mmc_spi_wait_unbusy(struct mmc_spi_host *host, ktime_t timeout) +mmc_spi_wait_unbusy(struct mmc_spi_host *host, unsigned long timeout)  {  	return mmc_spi_skip(host, timeout, sizeof(host->data->status), 0);  } -static int mmc_spi_readtoken(struct mmc_spi_host *host, ktime_t timeout) +static int mmc_spi_readtoken(struct mmc_spi_host *host, unsigned long timeout)  {  	return mmc_spi_skip(host, timeout, 1, 0xff);  } @@ -251,6 +254,10 @@ static int mmc_spi_response_get(struct mmc_spi_host *host,  	u8	*cp = host->data->status;  	u8	*end = cp + host->t.len;  	int	value = 0; +	int	bitshift; +	u8 	leftover = 0; +	unsigned short rotator; +	int 	i;  	char	tag[32];  	snprintf(tag, sizeof(tag), "  ... CMD%d response SPI_%s", @@ -268,9 +275,8 @@ static int mmc_spi_response_get(struct mmc_spi_host *host,  	/* Data block reads (R1 response types) may need more data... */  	if (cp == end) { -		unsigned	i; -  		cp = host->data->status; +		end = cp+1;  		/* Card sends N(CR) (== 1..8) bytes of all-ones then one  		 * status byte ... and we already scanned 2 bytes. @@ -295,20 +301,34 @@ static int mmc_spi_response_get(struct mmc_spi_host *host,  	}  checkstatus: -	if (*cp & 0x80) { -		dev_dbg(&host->spi->dev, "%s: INVALID RESPONSE, %02x\n", -					tag, *cp); -		value = -EBADR; -		goto done; +	bitshift = 0; +	if (*cp & 0x80)	{ +		/* Houston, we have an ugly card with a bit-shifted response */ +		rotator = *cp++ << 8; +		/* read the next byte */ +		if (cp == end) { +			value = mmc_spi_readbytes(host, 1); +			if (value < 0) +				goto done; +			cp = host->data->status; +			end = cp+1; +		} +		rotator |= *cp++; +		while (rotator & 0x8000) { +			bitshift++; +			rotator <<= 1; +		} +		cmd->resp[0] = rotator >> 8; +		leftover = rotator; +	} else { +		cmd->resp[0] = *cp++;  	} - -	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) +				      | R1_SPI_ILLEGAL_COMMAND)  				& cmd->resp[0])  			value = -EINVAL;  		else if (R1_SPI_COM_CRC & cmd->resp[0]) @@ -336,12 +356,45 @@ checkstatus:  	 * SPI R5 == R1 + data byte; IO_RW_DIRECT  	 */  	case MMC_RSP_SPI_R2: -		cmd->resp[0] |= *cp << 8; +		/* read the next byte */ +		if (cp == end) { +			value = mmc_spi_readbytes(host, 1); +			if (value < 0) +				goto done; +			cp = host->data->status; +			end = cp+1; +		} +		if (bitshift) { +			rotator = leftover << 8; +			rotator |= *cp << bitshift; +			cmd->resp[0] |= (rotator & 0xFF00); +		} else { +			cmd->resp[0] |= *cp << 8; +		}  		break;  	/* SPI R3, R4, or R7 == R1 + 4 bytes */  	case MMC_RSP_SPI_R3: -		cmd->resp[1] = get_unaligned_be32(cp); +		rotator = leftover << 8; +		cmd->resp[1] = 0; +		for (i = 0; i < 4; i++) { +			cmd->resp[1] <<= 8; +			/* read the next byte */ +			if (cp == end) { +				value = mmc_spi_readbytes(host, 1); +				if (value < 0) +					goto done; +				cp = host->data->status; +				end = cp+1; +			} +			if (bitshift) { +				rotator |= *cp++ << bitshift; +				cmd->resp[1] |= (rotator >> 8); +				rotator <<= 8; +			} else { +				cmd->resp[1] |= *cp++; +			} +		}  		break;  	/* SPI R1 == just one status byte */ @@ -607,7 +660,7 @@ mmc_spi_setup_data_message(   */  static int  mmc_spi_writeblock(struct mmc_spi_host *host, struct spi_transfer *t, -	ktime_t timeout) +	unsigned long timeout)  {  	struct spi_device	*spi = host->spi;  	int			status, i; @@ -717,11 +770,13 @@ mmc_spi_writeblock(struct mmc_spi_host *host, struct spi_transfer *t,   */  static int  mmc_spi_readblock(struct mmc_spi_host *host, struct spi_transfer *t, -	ktime_t timeout) +	unsigned long timeout)  {  	struct spi_device	*spi = host->spi;  	int			status;  	struct scratch		*scratch = host->data; +	unsigned int 		bitshift; +	u8			leftover;  	/* At least one SD card sends an all-zeroes byte when N(CX)  	 * applies, before the all-ones bytes ... just cope with that. @@ -733,38 +788,60 @@ mmc_spi_readblock(struct mmc_spi_host *host, struct spi_transfer *t,  	if (status == 0xff || status == 0)  		status = mmc_spi_readtoken(host, timeout); -	if (status == SPI_TOKEN_SINGLE) { -		if (host->dma_dev) { -			dma_sync_single_for_device(host->dma_dev, -					host->data_dma, sizeof(*scratch), -					DMA_BIDIRECTIONAL); -			dma_sync_single_for_device(host->dma_dev, -					t->rx_dma, t->len, -					DMA_FROM_DEVICE); -		} +	if (status < 0) { +		dev_dbg(&spi->dev, "read error %02x (%d)\n", status, status); +		return status; +	} -		status = spi_sync(spi, &host->m); +	/* The token may be bit-shifted... +	 * the first 0-bit precedes the data stream. +	 */ +	bitshift = 7; +	while (status & 0x80) { +		status <<= 1; +		bitshift--; +	} +	leftover = status << 1; -		if (host->dma_dev) { -			dma_sync_single_for_cpu(host->dma_dev, -					host->data_dma, sizeof(*scratch), -					DMA_BIDIRECTIONAL); -			dma_sync_single_for_cpu(host->dma_dev, -					t->rx_dma, t->len, -					DMA_FROM_DEVICE); -		} +	if (host->dma_dev) { +		dma_sync_single_for_device(host->dma_dev, +				host->data_dma, sizeof(*scratch), +				DMA_BIDIRECTIONAL); +		dma_sync_single_for_device(host->dma_dev, +				t->rx_dma, t->len, +				DMA_FROM_DEVICE); +	} -	} else { -		dev_dbg(&spi->dev, "read error %02x (%d)\n", status, status); +	status = spi_sync(spi, &host->m); -		/* we've read extra garbage, timed out, etc */ -		if (status < 0) -			return status; +	if (host->dma_dev) { +		dma_sync_single_for_cpu(host->dma_dev, +				host->data_dma, sizeof(*scratch), +				DMA_BIDIRECTIONAL); +		dma_sync_single_for_cpu(host->dma_dev, +				t->rx_dma, t->len, +				DMA_FROM_DEVICE); +	} -		/* low four bits are an R2 subset, fifth seems to be -		 * vendor specific ... map them all to generic error.. +	if (bitshift) { +		/* Walk through the data and the crc and do +		 * all the magic to get byte-aligned data.  		 */ -		return -EIO; +		u8 *cp = t->rx_buf; +		unsigned int len; +		unsigned int bitright = 8 - bitshift; +		u8 temp; +		for (len = t->len; len; len--) { +			temp = *cp; +			*cp++ = leftover | (temp >> bitshift); +			leftover = temp << bitright; +		} +		cp = (u8 *) &scratch->crc_val; +		temp = *cp; +		*cp++ = leftover | (temp >> bitshift); +		leftover = temp << bitright; +		temp = *cp; +		*cp = leftover | (temp >> bitshift);  	}  	if (host->mmc->use_spi_crc) { @@ -803,7 +880,7 @@ mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd,  	unsigned		n_sg;  	int			multiple = (data->blocks > 1);  	u32			clock_rate; -	ktime_t			timeout; +	unsigned long		timeout;  	if (data->flags & MMC_DATA_READ)  		direction = DMA_FROM_DEVICE; @@ -817,8 +894,9 @@ mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd,  	else  		clock_rate = spi->max_speed_hz; -	timeout = ktime_add_ns(ktime_set(0, 0), data->timeout_ns + -			data->timeout_clks * 1000000 / clock_rate); +	timeout = data->timeout_ns + +		  data->timeout_clks * 1000000 / clock_rate; +	timeout = usecs_to_jiffies((unsigned int)(timeout / 1000)) + 1;  	/* Handle scatterlist segments one at a time, with synch for  	 * each 512-byte block  | 
