Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0fb4723d authored by Jarkko Lavinen's avatar Jarkko Lavinen Committed by Pierre Ossman
Browse files

MMC: OMAP: Move failing command abortion to workqueue



Abort failed command from workqueue rather than from an interrupt,
allowing longer delays in abortion.

Signed-off-by: default avatarJarkko Lavinen <jarkko.lavinen@nokia.com>
Signed-off-by: default avatarPierre Ossman <drzeus@drzeus.cx>
parent 7584d276
Loading
Loading
Loading
Loading
+49 −33
Original line number Original line Diff line number Diff line
@@ -134,8 +134,9 @@ struct mmc_omap_host {
	unsigned char		bus_mode;
	unsigned char		bus_mode;
	unsigned char		hw_bus_mode;
	unsigned char		hw_bus_mode;


	struct work_struct	cmd_abort;
	struct work_struct	cmd_abort_work;
	struct timer_list	cmd_timer;
	unsigned		abort:1;
	struct timer_list	cmd_abort_timer;


	unsigned int		sg_len;
	unsigned int		sg_len;
	int			sg_idx;
	int			sg_idx;
@@ -320,7 +321,7 @@ mmc_omap_start_command(struct mmc_omap_host *host, struct mmc_command *cmd)
	if (host->data && !(host->data->flags & MMC_DATA_WRITE))
	if (host->data && !(host->data->flags & MMC_DATA_WRITE))
		cmdreg |= 1 << 15;
		cmdreg |= 1 << 15;


	mod_timer(&host->cmd_timer, jiffies + HZ/2);
	mod_timer(&host->cmd_abort_timer, jiffies + HZ/2);


	OMAP_MMC_WRITE(host, CTO, 200);
	OMAP_MMC_WRITE(host, CTO, 200);
	OMAP_MMC_WRITE(host, ARGL, cmd->arg & 0xffff);
	OMAP_MMC_WRITE(host, ARGL, cmd->arg & 0xffff);
@@ -381,7 +382,7 @@ mmc_omap_xfer_done(struct mmc_omap_host *host, struct mmc_data *data)
}
}


static void
static void
mmc_omap_send_abort(struct mmc_omap_host *host)
mmc_omap_send_abort(struct mmc_omap_host *host, int maxloops)
{
{
	struct mmc_omap_slot *slot = host->current_slot;
	struct mmc_omap_slot *slot = host->current_slot;
	unsigned int restarts, passes, timeout;
	unsigned int restarts, passes, timeout;
@@ -390,7 +391,7 @@ mmc_omap_send_abort(struct mmc_omap_host *host)
	/* Sending abort takes 80 clocks. Have some extra and round up */
	/* Sending abort takes 80 clocks. Have some extra and round up */
	timeout = (120*1000000 + slot->fclk_freq - 1)/slot->fclk_freq;
	timeout = (120*1000000 + slot->fclk_freq - 1)/slot->fclk_freq;
	restarts = 0;
	restarts = 0;
	while (restarts < 10000) {
	while (restarts < maxloops) {
		OMAP_MMC_WRITE(host, STAT, 0xFFFF);
		OMAP_MMC_WRITE(host, STAT, 0xFFFF);
		OMAP_MMC_WRITE(host, CMD, (3 << 12) | (1 << 7));
		OMAP_MMC_WRITE(host, CMD, (3 << 12) | (1 << 7));


@@ -412,18 +413,13 @@ mmc_omap_send_abort(struct mmc_omap_host *host)
static void
static void
mmc_omap_abort_xfer(struct mmc_omap_host *host, struct mmc_data *data)
mmc_omap_abort_xfer(struct mmc_omap_host *host, struct mmc_data *data)
{
{
	u16 ie;

	if (host->dma_in_use)
	if (host->dma_in_use)
		mmc_omap_release_dma(host, data, 1);
		mmc_omap_release_dma(host, data, 1);


	host->data = NULL;
	host->data = NULL;
	host->sg_len = 0;
	host->sg_len = 0;


	ie = OMAP_MMC_READ(host, IE);
	mmc_omap_send_abort(host, 10000);
	OMAP_MMC_WRITE(host, IE, 0);
	OMAP_MMC_WRITE(host, IE, ie);
	mmc_omap_send_abort(host);
}
}


static void
static void
@@ -479,7 +475,7 @@ mmc_omap_cmd_done(struct mmc_omap_host *host, struct mmc_command *cmd)
{
{
	host->cmd = NULL;
	host->cmd = NULL;


	del_timer(&host->cmd_timer);
	del_timer(&host->cmd_abort_timer);


	if (cmd->flags & MMC_RSP_PRESENT) {
	if (cmd->flags & MMC_RSP_PRESENT) {
		if (cmd->flags & MMC_RSP_136) {
		if (cmd->flags & MMC_RSP_136) {
@@ -523,38 +519,48 @@ mmc_omap_cmd_done(struct mmc_omap_host *host, struct mmc_command *cmd)
static void mmc_omap_abort_command(struct work_struct *work)
static void mmc_omap_abort_command(struct work_struct *work)
{
{
	struct mmc_omap_host *host = container_of(work, struct mmc_omap_host,
	struct mmc_omap_host *host = container_of(work, struct mmc_omap_host,
						  cmd_abort);
						  cmd_abort_work);
	u16 ie;
	BUG_ON(!host->cmd);

	ie = OMAP_MMC_READ(host, IE);
	OMAP_MMC_WRITE(host, IE, 0);

	if (!host->cmd) {
		OMAP_MMC_WRITE(host, IE, ie);
		return;
	}


	dev_dbg(mmc_dev(host->mmc), "Aborting stuck command CMD%d\n",
	dev_dbg(mmc_dev(host->mmc), "Aborting stuck command CMD%d\n",
		host->cmd->opcode);
		host->cmd->opcode);


	if (host->data && host->dma_in_use)
	if (host->cmd->error == 0)
		mmc_omap_release_dma(host, host->data, 1);
		host->cmd->error = -ETIMEDOUT;


	host->data = NULL;
	if (host->data == NULL) {
	host->sg_len = 0;
		struct mmc_command *cmd;
		struct mmc_host    *mmc;


	mmc_omap_send_abort(host);
		cmd = host->cmd;
	host->cmd->error = -ETIMEDOUT;
		host->cmd = NULL;
		mmc_omap_send_abort(host, 10000);

		host->mrq = NULL;
		mmc = host->mmc;
		mmc_omap_release_slot(host->current_slot);
		mmc_request_done(mmc, cmd->mrq);
	} else
		mmc_omap_cmd_done(host, host->cmd);
		mmc_omap_cmd_done(host, host->cmd);
	OMAP_MMC_WRITE(host, IE, ie);

	host->abort = 0;
	enable_irq(host->irq);
}
}


static void
static void
mmc_omap_cmd_timer(unsigned long data)
mmc_omap_cmd_timer(unsigned long data)
{
{
	struct mmc_omap_host *host = (struct mmc_omap_host *) data;
	struct mmc_omap_host *host = (struct mmc_omap_host *) data;
	unsigned long flags;


	schedule_work(&host->cmd_abort);
	spin_lock_irqsave(&host->slot_lock, flags);
	if (host->cmd != NULL && !host->abort) {
		OMAP_MMC_WRITE(host, IE, 0);
		disable_irq(host->irq);
		host->abort = 1;
		schedule_work(&host->cmd_abort_work);
	}
	spin_unlock_irqrestore(&host->slot_lock, flags);
}
}


/* PIO only */
/* PIO only */
@@ -728,6 +734,15 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id)
		}
		}
	}
	}


	if (cmd_error && host->data) {
		del_timer(&host->cmd_abort_timer);
		host->abort = 1;
		OMAP_MMC_WRITE(host, IE, 0);
		disable_irq(host->irq);
		schedule_work(&host->cmd_abort_work);
		return IRQ_HANDLED;
	}

	if (end_command)
	if (end_command)
		mmc_omap_cmd_done(host, host->cmd);
		mmc_omap_cmd_done(host, host->cmd);
	if (host->data != NULL) {
	if (host->data != NULL) {
@@ -1316,8 +1331,9 @@ static int __init mmc_omap_probe(struct platform_device *pdev)
		goto err_free_mem_region;
		goto err_free_mem_region;
	}
	}


	INIT_WORK(&host->cmd_abort, mmc_omap_abort_command);
	INIT_WORK(&host->cmd_abort_work, mmc_omap_abort_command);
	setup_timer(&host->cmd_timer, mmc_omap_cmd_timer, (unsigned long) host);
	setup_timer(&host->cmd_abort_timer, mmc_omap_cmd_timer,
		    (unsigned long) host);


	spin_lock_init(&host->dma_lock);
	spin_lock_init(&host->dma_lock);
	setup_timer(&host->dma_timer, mmc_omap_dma_timer, (unsigned long) host);
	setup_timer(&host->dma_timer, mmc_omap_dma_timer, (unsigned long) host);