tifm_sd: Switch software timeout handler from work_struct to timer

Two changes are introduced to software timeout handler in order to simplify
its management:
1. The implementation is switched from work_struct to timer
2. Previously, software timeout was rearmed with each interrupt. Now,
current request must complete entirely within timeout interval.

Signed-off-by: Alex Dubov <oakad@yahoo.com>
Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>
diff --git a/drivers/mmc/tifm_sd.c b/drivers/mmc/tifm_sd.c
index 3e76277..69b78eb 100644
--- a/drivers/mmc/tifm_sd.c
+++ b/drivers/mmc/tifm_sd.c
@@ -95,11 +95,11 @@
 	card_state_t        state;
 	unsigned int        clk_freq;
 	unsigned int        clk_div;
-	unsigned long       timeout_jiffies; // software timeout - 2 sec
+	unsigned long       timeout_jiffies;
 
+	struct timer_list     timer;
 	struct mmc_request    *req;
 	struct work_struct    cmd_handler;
-	struct delayed_work   abort_handler;
 	wait_queue_head_t     can_eject;
 
 	size_t                written_blocks;
@@ -321,8 +321,6 @@
 		return;
 	}
 
-	queue_delayed_work(sock->wq, &host->abort_handler,
-				host->timeout_jiffies);
 }
 
 /* Called from interrupt handler */
@@ -335,7 +333,6 @@
 
 	spin_lock(&sock->lock);
 	host = mmc_priv((struct mmc_host*)tifm_get_drvdata(sock));
-	cancel_delayed_work(&host->abort_handler);
 
 	if (sock_irq_status & FIFO_EVENT) {
 		fifo_status = readl(sock->addr + SOCK_DMA_FIFO_STATUS);
@@ -375,9 +372,6 @@
 					   || host->state == FIFO) {
 					host->req->cmd->error = error_code;
 					tifm_sd_exec(host, host->req->stop);
-					queue_delayed_work(sock->wq,
-						&host->abort_handler,
-						host->timeout_jiffies);
 					host->state = SCMD;
 					goto done;
 				} else {
@@ -506,9 +500,8 @@
 	}
 
 	host->req = mrq;
+	mod_timer(&host->timer, jiffies + host->timeout_jiffies);
 	host->state = CMD;
-	queue_delayed_work(sock->wq, &host->abort_handler,
-				host->timeout_jiffies);
 	writel(TIFM_CTRL_LED | readl(sock->addr + SOCK_CONTROL),
 		sock->addr + SOCK_CONTROL);
 	tifm_sd_exec(host, mrq->cmd);
@@ -536,6 +529,7 @@
 
 	spin_lock_irqsave(&sock->lock, flags);
 
+	del_timer(&host->timer);
 	mrq = host->req;
 	host->req = NULL;
 	host->state = IDLE;
@@ -610,9 +604,8 @@
 	}
 
 	host->req = mrq;
+	mod_timer(&host->timer, jiffies + host->timeout_jiffies);
 	host->state = CMD;
-	queue_delayed_work(sock->wq, &host->abort_handler,
-				host->timeout_jiffies);
 	writel(TIFM_CTRL_LED | readl(sock->addr + SOCK_CONTROL),
 		sock->addr + SOCK_CONTROL);
 	tifm_sd_exec(host, mrq->cmd);
@@ -635,6 +628,7 @@
 
 	spin_lock_irqsave(&sock->lock, flags);
 
+	del_timer(&host->timer);
 	mrq = host->req;
 	host->req = NULL;
 	host->state = IDLE;
@@ -673,14 +667,11 @@
 	mmc_request_done(mmc, mrq);
 }
 
-static void tifm_sd_abort(struct work_struct *work)
+static void tifm_sd_abort(unsigned long data)
 {
-	struct tifm_sd *host =
-		container_of(work, struct tifm_sd, abort_handler.work);
-
 	printk(KERN_ERR DRIVER_NAME
-		": card failed to respond for a long period of time");
-	tifm_eject(host->dev);
+	       ": card failed to respond for a long period of time");
+	tifm_eject(((struct tifm_sd*)data)->dev);
 }
 
 static void tifm_sd_ios(struct mmc_host *mmc, struct mmc_ios *ios)
@@ -785,6 +776,7 @@
 	unsigned long flags;
 
 	spin_lock_irqsave(&sock->lock, flags);
+	del_timer(&host->timer);
 	host->flags |= HOST_REG;
 	PREPARE_WORK(&host->cmd_handler,
 			no_dma ? tifm_sd_end_cmd_nodma : tifm_sd_end_cmd);
@@ -814,7 +806,7 @@
 	host->clk_div = 61;
 	init_waitqueue_head(&host->can_eject);
 	INIT_WORK(&host->cmd_handler, tifm_sd_register_host);
-	INIT_DELAYED_WORK(&host->abort_handler, tifm_sd_abort);
+	setup_timer(&host->timer, tifm_sd_abort, (unsigned long)host);
 
 	tifm_set_drvdata(sock, mmc);
 	sock->signal_irq = tifm_sd_signal_irq;
@@ -866,8 +858,7 @@
 	writel(host->clk_div | TIFM_MMCSD_POWER,
 			sock->addr + SOCK_MMCSD_CONFIG);
 
-	queue_delayed_work(sock->wq, &host->abort_handler,
-			host->timeout_jiffies);
+	mod_timer(&host->timer, jiffies + host->timeout_jiffies);
 
 	return 0;
 }
@@ -891,6 +882,7 @@
 	struct tifm_sd *host = mmc_priv(mmc);
 	unsigned long flags;
 
+	del_timer_sync(&host->timer);
 	spin_lock_irqsave(&sock->lock, flags);
 	host->flags |= EJECT;
 	if (host->req)