summary refs log tree commit diff
path: root/drivers/mmc/core
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mmc/core')
-rw-r--r--drivers/mmc/core/core.c41
-rw-r--r--drivers/mmc/core/mmc.c2
-rw-r--r--drivers/mmc/core/sd.c6
-rw-r--r--drivers/mmc/core/sdio_cis.c6
-rw-r--r--drivers/mmc/core/sdio_io.c167
5 files changed, 175 insertions, 47 deletions
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 01ced4c5a61d..3ee5b8c3b5ce 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -3,7 +3,7 @@
  *
  *  Copyright (C) 2003-2004 Russell King, All Rights Reserved.
  *  SD support Copyright (C) 2004 Ian Molton, All Rights Reserved.
- *  Copyright (C) 2005-2007 Pierre Ossman, All Rights Reserved.
+ *  Copyright (C) 2005-2008 Pierre Ossman, All Rights Reserved.
  *  MMCv4 support Copyright (C) 2006 Philip Langdale, All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify
@@ -295,6 +295,33 @@ void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card)
 EXPORT_SYMBOL(mmc_set_data_timeout);
 
 /**
+ *	mmc_align_data_size - pads a transfer size to a more optimal value
+ *	@card: the MMC card associated with the data transfer
+ *	@sz: original transfer size
+ *
+ *	Pads the original data size with a number of extra bytes in
+ *	order to avoid controller bugs and/or performance hits
+ *	(e.g. some controllers revert to PIO for certain sizes).
+ *
+ *	Returns the improved size, which might be unmodified.
+ *
+ *	Note that this function is only relevant when issuing a
+ *	single scatter gather entry.
+ */
+unsigned int mmc_align_data_size(struct mmc_card *card, unsigned int sz)
+{
+	/*
+	 * FIXME: We don't have a system for the controller to tell
+	 * the core about its problems yet, so for now we just 32-bit
+	 * align the size.
+	 */
+	sz = ((sz + 3) / 4) * 4;
+
+	return sz;
+}
+EXPORT_SYMBOL(mmc_align_data_size);
+
+/**
  *	__mmc_claim_host - exclusively claim a host
  *	@host: mmc host to claim
  *	@abort: whether or not the operation should be aborted
@@ -638,6 +665,9 @@ void mmc_rescan(struct work_struct *work)
 		 */
 		mmc_bus_put(host);
 
+		if (host->ops->get_cd && host->ops->get_cd(host) == 0)
+			goto out;
+
 		mmc_claim_host(host);
 
 		mmc_power_up(host);
@@ -652,7 +682,7 @@ void mmc_rescan(struct work_struct *work)
 		if (!err) {
 			if (mmc_attach_sdio(host, ocr))
 				mmc_power_off(host);
-			return;
+			goto out;
 		}
 
 		/*
@@ -662,7 +692,7 @@ void mmc_rescan(struct work_struct *work)
 		if (!err) {
 			if (mmc_attach_sd(host, ocr))
 				mmc_power_off(host);
-			return;
+			goto out;
 		}
 
 		/*
@@ -672,7 +702,7 @@ void mmc_rescan(struct work_struct *work)
 		if (!err) {
 			if (mmc_attach_mmc(host, ocr))
 				mmc_power_off(host);
-			return;
+			goto out;
 		}
 
 		mmc_release_host(host);
@@ -683,6 +713,9 @@ void mmc_rescan(struct work_struct *work)
 
 		mmc_bus_put(host);
 	}
+out:
+	if (host->caps & MMC_CAP_NEEDS_POLL)
+		mmc_schedule_delayed_work(&host->detect, HZ);
 }
 
 void mmc_start_host(struct mmc_host *host)
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 3da29eef8f7d..fdd7c760be8c 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -288,7 +288,7 @@ static struct device_type mmc_type = {
 /*
  * Handle the detection and initialisation of a card.
  *
- * In the case of a resume, "curcard" will contain the card
+ * In the case of a resume, "oldcard" will contain the card
  * we're trying to reinitialise.
  */
 static int mmc_init_card(struct mmc_host *host, u32 ocr,
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index 7ef3b15c5e3d..26fc098d77cd 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -326,7 +326,7 @@ static struct device_type sd_type = {
 /*
  * Handle the detection and initialisation of a card.
  *
- * In the case of a resume, "curcard" will contain the card
+ * In the case of a resume, "oldcard" will contain the card
  * we're trying to reinitialise.
  */
 static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
@@ -494,13 +494,13 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
 	 * Check if read-only switch is active.
 	 */
 	if (!oldcard) {
-		if (!host->ops->get_ro) {
+		if (!host->ops->get_ro || host->ops->get_ro(host) < 0) {
 			printk(KERN_WARNING "%s: host does not "
 				"support reading read-only "
 				"switch. assuming write-enable.\n",
 				mmc_hostname(host));
 		} else {
-			if (host->ops->get_ro(host))
+			if (host->ops->get_ro(host) > 0)
 				mmc_card_set_readonly(card);
 		}
 	}
diff --git a/drivers/mmc/core/sdio_cis.c b/drivers/mmc/core/sdio_cis.c
index d5e51b1c7b3f..956bd7677502 100644
--- a/drivers/mmc/core/sdio_cis.c
+++ b/drivers/mmc/core/sdio_cis.c
@@ -129,6 +129,12 @@ static int cistpl_funce_func(struct sdio_func *func,
 	/* TPLFE_MAX_BLK_SIZE */
 	func->max_blksize = buf[12] | (buf[13] << 8);
 
+	/* TPLFE_ENABLE_TIMEOUT_VAL, present in ver 1.1 and above */
+	if (vsn > SDIO_SDIO_REV_1_00)
+		func->enable_timeout = (buf[28] | (buf[29] << 8)) * 10;
+	else
+		func->enable_timeout = jiffies_to_msecs(HZ);
+
 	return 0;
 }
 
diff --git a/drivers/mmc/core/sdio_io.c b/drivers/mmc/core/sdio_io.c
index 625b92ce9cef..f61fc2d4cd0a 100644
--- a/drivers/mmc/core/sdio_io.c
+++ b/drivers/mmc/core/sdio_io.c
@@ -1,7 +1,7 @@
 /*
  *  linux/drivers/mmc/core/sdio_io.c
  *
- *  Copyright 2007 Pierre Ossman
+ *  Copyright 2007-2008 Pierre Ossman
  *
  * 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
@@ -76,11 +76,7 @@ int sdio_enable_func(struct sdio_func *func)
 	if (ret)
 		goto err;
 
-	/*
-	 * FIXME: This should timeout based on information in the CIS,
-	 * but we don't have card to parse that yet.
-	 */
-	timeout = jiffies + HZ;
+	timeout = jiffies + msecs_to_jiffies(func->enable_timeout);
 
 	while (1) {
 		ret = mmc_io_rw_direct(func->card, 0, 0, SDIO_CCCR_IORx, 0, &reg);
@@ -167,10 +163,8 @@ int sdio_set_block_size(struct sdio_func *func, unsigned blksz)
 		return -EINVAL;
 
 	if (blksz == 0) {
-		blksz = min(min(
-			func->max_blksize,
-			func->card->host->max_blk_size),
-			512u);
+		blksz = min(func->max_blksize, func->card->host->max_blk_size);
+		blksz = min(blksz, 512u);
 	}
 
 	ret = mmc_io_rw_direct(func->card, 1, 0,
@@ -186,9 +180,116 @@ int sdio_set_block_size(struct sdio_func *func, unsigned blksz)
 	func->cur_blksize = blksz;
 	return 0;
 }
-
 EXPORT_SYMBOL_GPL(sdio_set_block_size);
 
+/*
+ * Calculate the maximum byte mode transfer size
+ */
+static inline unsigned int sdio_max_byte_size(struct sdio_func *func)
+{
+	unsigned mval =	min(func->card->host->max_seg_size,
+			    func->card->host->max_blk_size);
+	mval = min(mval, func->max_blksize);
+	return min(mval, 512u); /* maximum size for byte mode */
+}
+
+/**
+ *	sdio_align_size - pads a transfer size to a more optimal value
+ *	@func: SDIO function
+ *	@sz: original transfer size
+ *
+ *	Pads the original data size with a number of extra bytes in
+ *	order to avoid controller bugs and/or performance hits
+ *	(e.g. some controllers revert to PIO for certain sizes).
+ *
+ *	If possible, it will also adjust the size so that it can be
+ *	handled in just a single request.
+ *
+ *	Returns the improved size, which might be unmodified.
+ */
+unsigned int sdio_align_size(struct sdio_func *func, unsigned int sz)
+{
+	unsigned int orig_sz;
+	unsigned int blk_sz, byte_sz;
+	unsigned chunk_sz;
+
+	orig_sz = sz;
+
+	/*
+	 * Do a first check with the controller, in case it
+	 * wants to increase the size up to a point where it
+	 * might need more than one block.
+	 */
+	sz = mmc_align_data_size(func->card, sz);
+
+	/*
+	 * If we can still do this with just a byte transfer, then
+	 * we're done.
+	 */
+	if (sz <= sdio_max_byte_size(func))
+		return sz;
+
+	if (func->card->cccr.multi_block) {
+		/*
+		 * Check if the transfer is already block aligned
+		 */
+		if ((sz % func->cur_blksize) == 0)
+			return sz;
+
+		/*
+		 * Realign it so that it can be done with one request,
+		 * and recheck if the controller still likes it.
+		 */
+		blk_sz = ((sz + func->cur_blksize - 1) /
+			func->cur_blksize) * func->cur_blksize;
+		blk_sz = mmc_align_data_size(func->card, blk_sz);
+
+		/*
+		 * This value is only good if it is still just
+		 * one request.
+		 */
+		if ((blk_sz % func->cur_blksize) == 0)
+			return blk_sz;
+
+		/*
+		 * We failed to do one request, but at least try to
+		 * pad the remainder properly.
+		 */
+		byte_sz = mmc_align_data_size(func->card,
+				sz % func->cur_blksize);
+		if (byte_sz <= sdio_max_byte_size(func)) {
+			blk_sz = sz / func->cur_blksize;
+			return blk_sz * func->cur_blksize + byte_sz;
+		}
+	} else {
+		/*
+		 * We need multiple requests, so first check that the
+		 * controller can handle the chunk size;
+		 */
+		chunk_sz = mmc_align_data_size(func->card,
+				sdio_max_byte_size(func));
+		if (chunk_sz == sdio_max_byte_size(func)) {
+			/*
+			 * Fix up the size of the remainder (if any)
+			 */
+			byte_sz = orig_sz % chunk_sz;
+			if (byte_sz) {
+				byte_sz = mmc_align_data_size(func->card,
+						byte_sz);
+			}
+
+			return (orig_sz / chunk_sz) * chunk_sz + byte_sz;
+		}
+	}
+
+	/*
+	 * The controller is simply incapable of transferring the size
+	 * we want in decent manner, so just return the original size.
+	 */
+	return orig_sz;
+}
+EXPORT_SYMBOL_GPL(sdio_align_size);
+
 /* Split an arbitrarily sized data transfer into several
  * IO_RW_EXTENDED commands. */
 static int sdio_io_rw_ext_helper(struct sdio_func *func, int write,
@@ -199,14 +300,13 @@ static int sdio_io_rw_ext_helper(struct sdio_func *func, int write,
 	int ret;
 
 	/* Do the bulk of the transfer using block mode (if supported). */
-	if (func->card->cccr.multi_block) {
+	if (func->card->cccr.multi_block && (size > sdio_max_byte_size(func))) {
 		/* Blocks per command is limited by host count, host transfer
 		 * size (we only use a single sg entry) and the maximum for
 		 * IO_RW_EXTENDED of 511 blocks. */
-		max_blocks = min(min(
-			func->card->host->max_blk_count,
-			func->card->host->max_seg_size / func->cur_blksize),
-			511u);
+		max_blocks = min(func->card->host->max_blk_count,
+			func->card->host->max_seg_size / func->cur_blksize);
+		max_blocks = min(max_blocks, 511u);
 
 		while (remainder > func->cur_blksize) {
 			unsigned blocks;
@@ -231,11 +331,7 @@ static int sdio_io_rw_ext_helper(struct sdio_func *func, int write,
 
 	/* Write the remainder using byte mode. */
 	while (remainder > 0) {
-		size = remainder;
-		if (size > func->cur_blksize)
-			size = func->cur_blksize;
-		if (size > 512)
-			size = 512; /* maximum size for byte mode */
+		size = min(remainder, sdio_max_byte_size(func));
 
 		ret = mmc_io_rw_extended(func->card, write, func->num, addr,
 			 incr_addr, buf, 1, size);
@@ -260,11 +356,10 @@ static int sdio_io_rw_ext_helper(struct sdio_func *func, int write,
  *	function. If there is a problem reading the address, 0xff
  *	is returned and @err_ret will contain the error code.
  */
-unsigned char sdio_readb(struct sdio_func *func, unsigned int addr,
-	int *err_ret)
+u8 sdio_readb(struct sdio_func *func, unsigned int addr, int *err_ret)
 {
 	int ret;
-	unsigned char val;
+	u8 val;
 
 	BUG_ON(!func);
 
@@ -293,8 +388,7 @@ EXPORT_SYMBOL_GPL(sdio_readb);
  *	function. @err_ret will contain the status of the actual
  *	transfer.
  */
-void sdio_writeb(struct sdio_func *func, unsigned char b, unsigned int addr,
-	int *err_ret)
+void sdio_writeb(struct sdio_func *func, u8 b, unsigned int addr, int *err_ret)
 {
 	int ret;
 
@@ -355,7 +449,6 @@ int sdio_readsb(struct sdio_func *func, void *dst, unsigned int addr,
 {
 	return sdio_io_rw_ext_helper(func, 0, addr, 0, dst, count);
 }
-
 EXPORT_SYMBOL_GPL(sdio_readsb);
 
 /**
@@ -385,8 +478,7 @@ EXPORT_SYMBOL_GPL(sdio_writesb);
  *	function. If there is a problem reading the address, 0xffff
  *	is returned and @err_ret will contain the error code.
  */
-unsigned short sdio_readw(struct sdio_func *func, unsigned int addr,
-	int *err_ret)
+u16 sdio_readw(struct sdio_func *func, unsigned int addr, int *err_ret)
 {
 	int ret;
 
@@ -400,7 +492,7 @@ unsigned short sdio_readw(struct sdio_func *func, unsigned int addr,
 		return 0xFFFF;
 	}
 
-	return le16_to_cpu(*(u16*)func->tmpbuf);
+	return le16_to_cpup((__le16 *)func->tmpbuf);
 }
 EXPORT_SYMBOL_GPL(sdio_readw);
 
@@ -415,12 +507,11 @@ EXPORT_SYMBOL_GPL(sdio_readw);
  *	function. @err_ret will contain the status of the actual
  *	transfer.
  */
-void sdio_writew(struct sdio_func *func, unsigned short b, unsigned int addr,
-	int *err_ret)
+void sdio_writew(struct sdio_func *func, u16 b, unsigned int addr, int *err_ret)
 {
 	int ret;
 
-	*(u16*)func->tmpbuf = cpu_to_le16(b);
+	*(__le16 *)func->tmpbuf = cpu_to_le16(b);
 
 	ret = sdio_memcpy_toio(func, addr, func->tmpbuf, 2);
 	if (err_ret)
@@ -439,8 +530,7 @@ EXPORT_SYMBOL_GPL(sdio_writew);
  *	0xffffffff is returned and @err_ret will contain the error
  *	code.
  */
-unsigned long sdio_readl(struct sdio_func *func, unsigned int addr,
-	int *err_ret)
+u32 sdio_readl(struct sdio_func *func, unsigned int addr, int *err_ret)
 {
 	int ret;
 
@@ -454,7 +544,7 @@ unsigned long sdio_readl(struct sdio_func *func, unsigned int addr,
 		return 0xFFFFFFFF;
 	}
 
-	return le32_to_cpu(*(u32*)func->tmpbuf);
+	return le32_to_cpup((__le32 *)func->tmpbuf);
 }
 EXPORT_SYMBOL_GPL(sdio_readl);
 
@@ -469,12 +559,11 @@ EXPORT_SYMBOL_GPL(sdio_readl);
  *	function. @err_ret will contain the status of the actual
  *	transfer.
  */
-void sdio_writel(struct sdio_func *func, unsigned long b, unsigned int addr,
-	int *err_ret)
+void sdio_writel(struct sdio_func *func, u32 b, unsigned int addr, int *err_ret)
 {
 	int ret;
 
-	*(u32*)func->tmpbuf = cpu_to_le32(b);
+	*(__le32 *)func->tmpbuf = cpu_to_le32(b);
 
 	ret = sdio_memcpy_toio(func, addr, func->tmpbuf, 4);
 	if (err_ret)