From patchwork Thu Sep 23 13:33:53 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arnd Hannemann X-Patchwork-Id: 201962 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id o8NDXwjj010499 for ; Thu, 23 Sep 2010 13:33:58 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752761Ab0IWNd5 (ORCPT ); Thu, 23 Sep 2010 09:33:57 -0400 Received: from mta-2.ms.rz.RWTH-Aachen.DE ([134.130.7.73]:58396 "EHLO mta-2.ms.rz.rwth-aachen.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752091Ab0IWNd5 (ORCPT ); Thu, 23 Sep 2010 09:33:57 -0400 Content-transfer-encoding: 7BIT Received: from ironport-out-1.rz.rwth-aachen.de ([134.130.5.40]) by mta-2.ms.rz.RWTH-Aachen.de (Sun Java(tm) System Messaging Server 6.3-7.04 (built Sep 26 2008)) with ESMTP id <0L9700CQOCCJO840@mta-2.ms.rz.RWTH-Aachen.de>; Thu, 23 Sep 2010 15:33:55 +0200 (CEST) X-IronPort-AV: E=Sophos; i="4.57,223,1283724000"; d="scan'208"; a="73580590" Received: from smarthost-2.ms.rz.rwth-aachen.de (HELO smarthost.rwth-aachen.de) ([134.130.7.90]) by ironport-in-1.rz.rwth-aachen.de with ESMTP; Thu, 23 Sep 2010 15:33:55 +0200 Received: from localhost.localdomain (informatik-4-137-226-12-76.nn.RWTH-Aachen.DE [137.226.12.76] (may be forged)) by smarthost.rwth-aachen.de (8.14.4+Sun/8.13.8/1) with ESMTP id o8NDXtgO004269; Thu, 23 Sep 2010 15:33:55 +0200 (CEST) From: Arnd Hannemann To: linux-mmc@vger.kernel.org Cc: Ian Molton , linux-sh@vger.kernel.org, Arnd Hannemann Subject: [PATCH 1/2] tmio_mmc: handle missing HW interrupts Date: Thu, 23 Sep 2010 15:33:53 +0200 Message-id: <1285248834-4434-1-git-send-email-arnd@arndnet.de> X-Mailer: git-send-email 1.7.0.4 Sender: linux-mmc-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-mmc@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.3 (demeter1.kernel.org [140.211.167.41]); Thu, 23 Sep 2010 13:33:58 +0000 (UTC) diff --git a/drivers/mmc/host/tmio_mmc.c b/drivers/mmc/host/tmio_mmc.c index e7765a8..9a55afd 100644 --- a/drivers/mmc/host/tmio_mmc.c +++ b/drivers/mmc/host/tmio_mmc.c @@ -82,15 +82,60 @@ static void reset(struct tmio_mmc_host *host) msleep(10); } +static void tmio_mmc_reset_work(struct work_struct *work) +{ + struct tmio_mmc_host *host = container_of(work, struct tmio_mmc_host, + delayed_reset_work.work); + struct mmc_request *mrq; + unsigned long flags; + + spin_lock_irqsave(&host->lock, flags); + mrq = host->mrq; + + /* request already finished */ + if (!mrq + || time_is_after_jiffies(host->last_req_ts + + msecs_to_jiffies(2000))) { + spin_unlock_irqrestore(&host->lock, flags); + return; + } + + dev_warn(&host->pdev->dev, + "timeout waiting for hardware interrupt (CMD%u)\n", + mrq->cmd->opcode); + + if (host->data) + host->data->error = -ETIMEDOUT; + else if (host->cmd) + host->cmd->error = -ETIMEDOUT; + else + mrq->cmd->error = -ETIMEDOUT; + + host->cmd = NULL; + host->data = NULL; + host->mrq = NULL; + + spin_unlock_irqrestore(&host->lock, flags); + + reset(host); + + mmc_request_done(host->mmc, mrq); +} + static void tmio_mmc_finish_request(struct tmio_mmc_host *host) { struct mmc_request *mrq = host->mrq; + if (!mrq) + return; + host->mrq = NULL; host->cmd = NULL; host->data = NULL; + cancel_delayed_work(&host->delayed_reset_work); + mmc_request_done(host->mmc, mrq); } @@ -200,6 +245,7 @@ static void tmio_mmc_pio_irq(struct tmio_mmc_host *host) return; } +/* needs to be called with host->lock held */ static void tmio_mmc_do_data_irq(struct tmio_mmc_host *host) { struct mmc_data *data = host->data; @@ -254,10 +300,12 @@ static void tmio_mmc_do_data_irq(struct tmio_mmc_host *host) static void tmio_mmc_data_irq(struct tmio_mmc_host *host) { - struct mmc_data *data = host->data; + struct mmc_data *data; + spin_lock(&host->lock); + data = host->data; if (!data) - return; + goto out; if (host->chan_tx && (data->flags & MMC_DATA_WRITE)) { /* @@ -278,6 +326,8 @@ static void tmio_mmc_data_irq(struct tmio_mmc_host *host) } else { tmio_mmc_do_data_irq(host); } +out: + spin_unlock(&host->lock); } static void tmio_mmc_cmd_irq(struct tmio_mmc_host *host, @@ -286,9 +336,11 @@ static void tmio_mmc_cmd_irq(struct tmio_mmc_host *host, struct mmc_command *cmd = host->cmd; int i, addr; + spin_lock(&host->lock); + if (!host->cmd) { pr_debug("Spurious CMD irq\n"); - return; + goto out; } host->cmd = NULL; @@ -334,6 +386,9 @@ static void tmio_mmc_cmd_irq(struct tmio_mmc_host *host, tmio_mmc_finish_request(host); } +out: + spin_unlock(&host->lock); + return; } @@ -562,6 +617,12 @@ static void tmio_issue_tasklet_fn(unsigned long priv) static void tmio_tasklet_fn(unsigned long arg) { struct tmio_mmc_host *host = (struct tmio_mmc_host *)arg; + unsigned long flags; + + spin_lock_irqsave(&host->lock, flags); + + if (!host->data) + goto out; if (host->data->flags & MMC_DATA_READ) dma_unmap_sg(&host->pdev->dev, host->sg_ptr, host->dma_sglen, @@ -571,6 +632,8 @@ static void tmio_tasklet_fn(unsigned long arg) DMA_TO_DEVICE); tmio_mmc_do_data_irq(host); +out: + spin_unlock_irqrestore(&host->lock, flags); } /* It might be necessary to make filter MFD specific */ @@ -694,6 +757,8 @@ static void tmio_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq) if (host->mrq) pr_debug("request not null\n"); + host->last_req_ts = jiffies; + wmb(); host->mrq = mrq; if (mrq->data) { @@ -703,10 +767,14 @@ static void tmio_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq) } ret = tmio_mmc_start_command(host, mrq->cmd); - if (!ret) + if (!ret) { + schedule_delayed_work(&host->delayed_reset_work, + msecs_to_jiffies(2000)); return; + } fail: + host->mrq = NULL; mrq->cmd->error = ret; mmc_request_done(mmc, mrq); } @@ -896,6 +963,11 @@ static int __devinit tmio_mmc_probe(struct platform_device *dev) if (ret) goto cell_disable; + spin_lock_init(&host->lock); + + /* Init delayed work for request timeouts */ + INIT_DELAYED_WORK(&host->delayed_reset_work, tmio_mmc_reset_work); + /* See if we also get DMA */ tmio_mmc_request_dma(host, pdata); @@ -936,6 +1008,7 @@ static int __devexit tmio_mmc_remove(struct platform_device *dev) mmc_remove_host(mmc); tmio_mmc_release_dma(host); free_irq(host->irq, host); + cancel_delayed_work_sync(&host->delayed_reset_work); if (cell->disable) cell->disable(dev); iounmap(host->ctl); diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h index 0fedc78..a40b477 100644 --- a/drivers/mmc/host/tmio_mmc.h +++ b/drivers/mmc/host/tmio_mmc.h @@ -12,6 +12,8 @@ #include #include #include +#include +#include #define CTL_SD_CMD 0x00 #define CTL_ARG_REG 0x04 @@ -116,6 +118,11 @@ struct tmio_mmc_host { unsigned int dma_sglen; dma_cookie_t cookie; #endif + + /* Track lost interrupts */ + struct delayed_work delayed_reset_work; + spinlock_t lock; + unsigned long last_req_ts; }; #include