From patchwork Wed Dec 1 12:49:21 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Chuanxiao.Dong" X-Patchwork-Id: 371061 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 oB1CqkY3010136 for ; Wed, 1 Dec 2010 12:52:46 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754993Ab0LAMw1 (ORCPT ); Wed, 1 Dec 2010 07:52:27 -0500 Received: from mga02.intel.com ([134.134.136.20]:29722 "EHLO mga02.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754854Ab0LAMw0 convert rfc822-to-8bit (ORCPT ); Wed, 1 Dec 2010 07:52:26 -0500 Received: from orsmga002.jf.intel.com ([10.7.209.21]) by orsmga101.jf.intel.com with ESMTP; 01 Dec 2010 04:52:25 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="4.59,283,1288594800"; d="scan'208,223";a="579446057" Received: from unknown (HELO intel.com) ([172.16.120.128]) by orsmga002.jf.intel.com with ESMTP; 01 Dec 2010 04:52:24 -0800 Date: Wed, 1 Dec 2010 20:49:21 +0800 From: Chuanxiao Dong To: linux-mmc@vger.kernel.org Cc: linux-kernel@vger.kernel.org, cjb@laptop.org, arjan@linux.intel.com, alan@linux.intel.com, akpm@linux-foundation.org Subject: [PATCH v4 2/4]add two new callback to help implement HW reset Message-ID: <20101201124921.GC5421@intel.com> Reply-To: Chuanxiao Dong MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.5.19 (2009-01-05) 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]); Wed, 01 Dec 2010 12:52:46 +0000 (UTC) diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 6286898..530fc35 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -82,6 +82,51 @@ static void mmc_flush_scheduled_work(void) } /** + * mmc_handle_timeout_error - handle command and data timeout + * errors. + * @host: MMC host used to handle error + * @error: error condition + * + * check whether there is a command or data timeout error occured, + * if so, reset and reinit eMMC card if card has such capbility. + * 1. let host controller do a specific hardware reset for eMMC + * card (trigger RST_n signal). + * 2. after reset done, reinit eMMC card. + */ +void mmc_handle_timeout_error(struct mmc_host *host, int error) +{ + struct mmc_card *card = host->card; + + /* + * If error condition is not timeout, do nothing + */ + if (error != -ETIMEDOUT) + return; + /* + * make sure mmc_reqeust is not NULL + * make sure mmc_card has HW reset capbility + */ + if (!card || !card->ext_csd.rst) + return; + + /* check whether host has such callback */ + if (!host->ops->hardware_reset || + !host->bus_ops->reinit) + return; + + /* + * if there occurs any timeout error, HW reset + * eMMC card and reinit again. + */ + if (host->ops->hardware_reset(host)) + pr_warn("MMC card reset failed\n"); + else + if (host->bus_ops->reinit(host)) + pr_warn("MMC card reinit failed\n"); +} +EXPORT_SYMBOL(mmc_handle_timeout_error); + +/** * mmc_request_done - finish processing an MMC request * @host: MMC host which completed request * @mrq: MMC request which request diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h index 026c975..4980e2f 100644 --- a/drivers/mmc/core/core.h +++ b/drivers/mmc/core/core.h @@ -24,6 +24,15 @@ struct mmc_bus_ops { int (*resume)(struct mmc_host *); int (*power_save)(struct mmc_host *); int (*power_restore)(struct mmc_host *); + /* + * New added callback + * Used to reinit card when HW reset occurs + * + * return value: + * 0: successfully reinit card. + * negative value: failed to reinit + */ + int (*reinit)(struct mmc_host *); }; void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops); diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 85cc7f6..bc4611a 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -732,6 +732,35 @@ static int mmc_awake(struct mmc_host *host) return err; } +/** + * mmc_reinit_card - reinitialize card after HW reset + * + * this callback is used to reinitialize card after a HW + * reset occurs. + * Reture value: + * 0: successfully reinitialize + * other: failed to reinitialize + * + * claim_host should be called before using this callback. + */ +static int mmc_reinit_card(struct mmc_host *host) +{ + int err; + /* + * Before init card, set the clock to be + * the init frequency + */ + host->ios.clock = host->f_init; + mmc_set_clock(host, host->ios.clock); + + err = mmc_init_card(host, host->ocr, host->card); + if (err) + pr_err("%s: Error %d while reinit card\n", + mmc_hostname(host), err); + + return err; +} + static const struct mmc_bus_ops mmc_ops = { .awake = mmc_awake, .sleep = mmc_sleep, @@ -740,6 +769,7 @@ static const struct mmc_bus_ops mmc_ops = { .suspend = NULL, .resume = NULL, .power_restore = mmc_power_restore, + .reinit = mmc_reinit_card, }; static const struct mmc_bus_ops mmc_ops_unsafe = { @@ -750,6 +780,7 @@ static const struct mmc_bus_ops mmc_ops_unsafe = { .suspend = mmc_suspend, .resume = mmc_resume, .power_restore = mmc_power_restore, + .reinit = mmc_reinit_card, }; static void mmc_attach_bus_ops(struct mmc_host *host) diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h index 64e013f..115d589 100644 --- a/include/linux/mmc/core.h +++ b/include/linux/mmc/core.h @@ -131,6 +131,7 @@ struct mmc_request { struct mmc_host; struct mmc_card; +extern void mmc_handle_timeout_error(struct mmc_host *, int); extern void mmc_wait_for_req(struct mmc_host *, struct mmc_request *); extern int mmc_wait_for_cmd(struct mmc_host *, struct mmc_command *, int); extern int mmc_wait_for_app_cmd(struct mmc_host *, struct mmc_card *, diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 381c77f..3a7008d 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -117,6 +117,19 @@ struct mmc_host_ops { /* optional callback for HC quirks */ void (*init_card)(struct mmc_host *host, struct mmc_card *card); + + /* + * eMMC4.4 HW reset feature callback + * + * eMMC4.4 card can be reset if host triggers a RST_n signal + * This callback will be used to for host to trigger such + * signal. + * + * return value: + * 0: successfully reset the eMMC card. + * -ENODEV: no valid hardware to do so. + */ + int (*hardware_reset)(struct mmc_host *host); }; struct mmc_card;