mmc_spi: convert timeout handling to jiffies and avoid busy waiting
authorWolfgang Muees <wolfgang.mues@auerswald.de>
Tue, 7 Apr 2009 14:26:30 +0000 (15:26 +0100)
committerPierre Ossman <pierre@ossman.eu>
Wed, 8 Apr 2009 18:38:42 +0000 (20:38 +0200)
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>
drivers/mmc/host/mmc_spi.c

index 72f8bde..ed02ebd 100644 (file)
@@ -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);
 }
@@ -607,7 +610,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,7 +720,7 @@ 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;
@@ -803,7 +806,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 +820,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