Browse Source

mmc_spi: convert timeout handling to jiffies and avoid busy waiting

SD/MMC card timeouts can be very high. So avoid busy-waiting,
using the scheduler. Calculate all timeouts in jiffies units,
because this will give us the correct sign when to involve
the scheduler.

Signed-off-by: Wolfgang Muees <wolfgang.mues@auerswald.de>
Signed-off-by: Pierre Ossman <pierre@ossman.eu>
Wolfgang Muees 16 years ago
parent
commit
56e303ebee
1 changed files with 21 additions and 17 deletions
  1. 21 17
      drivers/mmc/host/mmc_spi.c

+ 21 - 17
drivers/mmc/host/mmc_spi.c

@@ -24,7 +24,7 @@
  * along with this program; if not, write to the Free Software
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
  */
-#include <linux/hrtimer.h>
+#include <linux/sched.h>
 #include <linux/delay.h>
 #include <linux/delay.h>
 #include <linux/bio.h>
 #include <linux/bio.h>
 #include <linux/dma-mapping.h>
 #include <linux/dma-mapping.h>
@@ -95,7 +95,7 @@
  * reads which takes nowhere near that long.  Older cards may be able to use
  * reads which takes nowhere near that long.  Older cards may be able to use
  * shorter timeouts ... but why bother?
  * 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;
 	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;
 	u8		*cp = host->data->status;
-
-	timeout = ktime_add(timeout, ktime_get());
+	unsigned long start = jiffies;
 
 
 	while (1) {
 	while (1) {
 		int		status;
 		int		status;
@@ -203,22 +202,26 @@ mmc_spi_skip(struct mmc_spi_host *host, ktime_t timeout, unsigned n, u8 byte)
 				return cp[i];
 				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;
 			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;
 	return -ETIMEDOUT;
 }
 }
 
 
 static inline int
 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);
 	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);
 	return mmc_spi_skip(host, timeout, 1, 0xff);
 }
 }
@@ -607,7 +610,7 @@ mmc_spi_setup_data_message(
  */
  */
 static int
 static int
 mmc_spi_writeblock(struct mmc_spi_host *host, struct spi_transfer *t,
 mmc_spi_writeblock(struct mmc_spi_host *host, struct spi_transfer *t,
-	ktime_t timeout)
+	unsigned long timeout)
 {
 {
 	struct spi_device	*spi = host->spi;
 	struct spi_device	*spi = host->spi;
 	int			status, i;
 	int			status, i;
@@ -717,7 +720,7 @@ mmc_spi_writeblock(struct mmc_spi_host *host, struct spi_transfer *t,
  */
  */
 static int
 static int
 mmc_spi_readblock(struct mmc_spi_host *host, struct spi_transfer *t,
 mmc_spi_readblock(struct mmc_spi_host *host, struct spi_transfer *t,
-	ktime_t timeout)
+	unsigned long timeout)
 {
 {
 	struct spi_device	*spi = host->spi;
 	struct spi_device	*spi = host->spi;
 	int			status;
 	int			status;
@@ -803,7 +806,7 @@ mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd,
 	unsigned		n_sg;
 	unsigned		n_sg;
 	int			multiple = (data->blocks > 1);
 	int			multiple = (data->blocks > 1);
 	u32			clock_rate;
 	u32			clock_rate;
-	ktime_t			timeout;
+	unsigned long		timeout;
 
 
 	if (data->flags & MMC_DATA_READ)
 	if (data->flags & MMC_DATA_READ)
 		direction = DMA_FROM_DEVICE;
 		direction = DMA_FROM_DEVICE;
@@ -817,8 +820,9 @@ mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd,
 	else
 	else
 		clock_rate = spi->max_speed_hz;
 		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
 	/* Handle scatterlist segments one at a time, with synch for
 	 * each 512-byte block
 	 * each 512-byte block