Commit 56e303eb authored by Wolfgang Muees's avatar Wolfgang Muees Committed by Pierre Ossman

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: default avatarWolfgang Muees <wolfgang.mues@auerswald.de>
Signed-off-by: default avatarPierre Ossman <pierre@ossman.eu>
parent 9d9f25c0
...@@ -24,7 +24,7 @@ ...@@ -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 @@ ...@@ -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) ...@@ -183,12 +183,11 @@ mmc_spi_readbytes(struct mmc_spi_host *host, unsigned len)
return status; return status;
} }
static int static int mmc_spi_skip(struct mmc_spi_host *host, unsigned long timeout,
mmc_spi_skip(struct mmc_spi_host *host, ktime_t timeout, unsigned n, u8 byte) unsigned n, u8 byte)
{ {
u8 *cp = host->data->status; u8 *cp = host->data->status;
unsigned long start = jiffies;
timeout = ktime_add(timeout, ktime_get());
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) ...@@ -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 if (time_is_before_jiffies(start + timeout))
* in at least some cases.
*/
if (ktime_to_ns(ktime_sub(ktime_get(), timeout)) > 0)
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( ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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 + timeout = data->timeout_ns +
data->timeout_clks * 1000000 / clock_rate); 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
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment