From patchwork Mon Aug 11 12:40:33 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dolev Raviv X-Patchwork-Id: 4707071 Return-Path: X-Original-To: patchwork-linux-arm-msm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 6B0959F38D for ; Mon, 11 Aug 2014 12:41:56 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 31AAB20115 for ; Mon, 11 Aug 2014 12:41:55 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 1648E2010F for ; Mon, 11 Aug 2014 12:41:54 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753409AbaHKMlw (ORCPT ); Mon, 11 Aug 2014 08:41:52 -0400 Received: from smtp.codeaurora.org ([198.145.11.231]:57352 "EHLO smtp.codeaurora.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753286AbaHKMlu (ORCPT ); Mon, 11 Aug 2014 08:41:50 -0400 Received: from smtp.codeaurora.org (localhost [127.0.0.1]) by smtp.codeaurora.org (Postfix) with ESMTP id C2ECB13F882; Mon, 11 Aug 2014 12:41:49 +0000 (UTC) Received: by smtp.codeaurora.org (Postfix, from userid 486) id AD1C013F88B; Mon, 11 Aug 2014 12:41:49 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Spam-Level: X-Spam-Status: No, score=-7.6 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=ham version=3.3.1 Received: from lx-draviv2.mea.qualcomm.com (unknown [185.23.60.4]) (using TLSv1.1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) (Authenticated sender: draviv@smtp.codeaurora.org) by smtp.codeaurora.org (Postfix) with ESMTPSA id D6B8113F882; Mon, 11 Aug 2014 12:41:46 +0000 (UTC) From: Dolev Raviv To: James.Bottomley@HansenPartnership.com, hch@infradead.org Cc: linux-scsi@vger.kernel.org, linux-scsi-owner@vger.kernel.org, linux-arm-msm@vger.kernel.org, santoshsy@gmail.com, Sujit Reddy Thumma , Dolev Raviv Subject: [RFC 05/10] scsi: ufs: improve init sequence Date: Mon, 11 Aug 2014 15:40:33 +0300 Message-Id: <1407760838-6406-6-git-send-email-draviv@codeaurora.org> X-Mailer: git-send-email 1.8.5.2 In-Reply-To: <1407760838-6406-1-git-send-email-draviv@codeaurora.org> References: <1407760838-6406-1-git-send-email-draviv@codeaurora.org> X-Virus-Scanned: ClamAV using ClamSMTP Sender: linux-arm-msm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-arm-msm@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Sujit Reddy Thumma In ->hce_enable_notify() callback the vendor specific initialization may carry out additional DME configuration using UIC commands and hence the UIC command completion interrupt enable bit should be set before the post reset notification. Add retries if the link-startup fails. This is required since due to hardware timing issues, the Uni-Pro link-startup might fail. The UFS HCI recovery procedure contradicts the Uni-Pro sequence. The UFS HCI specifies to resend DME_LINKSTARTUP command after IS.ULLS (link-lost interrupt) is received. The Uni-Pro specifies that if link-startup fails the link is in "down" state. The link-lost is indicated to the DME user only when the link is up. Hence, the UFS HCI recovery procedure of waiting for IS.ULLS and retrying link-startup may not work properly. At the end, if detection fails, power off (disable clocks, regulators, phy) if the UFS device detection fails. This saves power while UFS device is not embedded into the system. Signed-off-by: Sujit Reddy Thumma Signed-off-by: Dolev Raviv diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 57a8dbb..1fabff4 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -62,6 +62,12 @@ /* Task management command timeout */ #define TM_CMD_TIMEOUT 100 /* msecs */ +/* maximum number of link-startup retries */ +#define DME_LINKSTARTUP_RETRIES 3 + +/* maximum number of reset retries before giving up */ +#define MAX_HOST_RESET_RETRIES 5 + /* Expose the flag value from utp_upiu_query.value */ #define MASK_QUERY_UPIU_FLAG_LOC 0xFF @@ -137,6 +143,8 @@ static void ufshcd_tmc_handler(struct ufs_hba *hba); static void ufshcd_async_scan(void *data, async_cookie_t cookie); static int ufshcd_reset_and_restore(struct ufs_hba *hba); static int ufshcd_clear_tm_cmd(struct ufs_hba *hba, int tag); +static void ufshcd_hba_exit(struct ufs_hba *hba); +static int ufshcd_probe_hba(struct ufs_hba *hba); /* * ufshcd_wait_for_register - wait for register value to change @@ -2043,6 +2051,9 @@ static int ufshcd_hba_enable(struct ufs_hba *hba) msleep(5); } + /* enable UIC related interrupts */ + ufshcd_enable_intr(hba, UIC_COMMAND_COMPL); + if (hba->vops && hba->vops->hce_enable_notify) hba->vops->hce_enable_notify(hba, POST_CHANGE); @@ -2058,23 +2069,33 @@ static int ufshcd_hba_enable(struct ufs_hba *hba) static int ufshcd_link_startup(struct ufs_hba *hba) { int ret; + int retries = DME_LINKSTARTUP_RETRIES; - /* enable UIC related interrupts */ - ufshcd_enable_intr(hba, UIC_COMMAND_COMPL); + do { + if (hba->vops && hba->vops->link_startup_notify) + hba->vops->link_startup_notify(hba, PRE_CHANGE); - if (hba->vops && hba->vops->link_startup_notify) - hba->vops->link_startup_notify(hba, PRE_CHANGE); + ret = ufshcd_dme_link_startup(hba); - ret = ufshcd_dme_link_startup(hba); - if (ret) - goto out; + /* check if device is detected by inter-connect layer */ + if (!ret && !ufshcd_is_device_present(hba)) { + dev_err(hba->dev, "%s: Device not present\n", __func__); + ret = -ENXIO; + goto out; + } + + /* + * DME link lost indication is only received when link is up, + * but we can't be sure if the link is up until link startup + * succeeds. So reset the local Uni-Pro and try again. + */ + if (ret && ufshcd_hba_enable(hba)) + goto out; + } while (ret && retries--); - /* check if device is detected by inter-connect layer */ - if (!ufshcd_is_device_present(hba)) { - dev_err(hba->dev, "%s: Device not present\n", __func__); - ret = -ENXIO; + if (ret) + /* failed to get the link up... retire */ goto out; - } /* Include any host controller configuration via UIC commands */ if (hba->vops && hba->vops->link_startup_notify) { @@ -3139,7 +3160,6 @@ out: static int ufshcd_host_reset_and_restore(struct ufs_hba *hba) { int err; - async_cookie_t cookie; unsigned long flags; /* Reset the host controller */ @@ -3152,10 +3172,9 @@ static int ufshcd_host_reset_and_restore(struct ufs_hba *hba) goto out; /* Establish the link again and restore the device */ - cookie = async_schedule(ufshcd_async_scan, hba); - /* wait for async scan to be completed */ - async_synchronize_cookie(++cookie); - if (hba->ufshcd_state != UFSHCD_STATE_OPERATIONAL) + err = ufshcd_probe_hba(hba); + + if (!err && (hba->ufshcd_state != UFSHCD_STATE_OPERATIONAL)) err = -EIO; out: if (err) @@ -3177,8 +3196,11 @@ static int ufshcd_reset_and_restore(struct ufs_hba *hba) { int err = 0; unsigned long flags; + int retries = MAX_HOST_RESET_RETRIES; - err = ufshcd_host_reset_and_restore(hba); + do { + err = ufshcd_host_reset_and_restore(hba); + } while (err && --retries); /* * After reset the door-bell might be cleared, complete @@ -3243,13 +3265,13 @@ static int ufshcd_eh_host_reset_handler(struct scsi_cmnd *cmd) } /** - * ufshcd_async_scan - asynchronous execution for link startup - * @data: data pointer to pass to this function - * @cookie: cookie data + * ufshcd_probe_hba - probe hba to detect device and initialize + * @hba: per-adapter instance + * + * Execute link-startup and verify device initialization */ -static void ufshcd_async_scan(void *data, async_cookie_t cookie) +static int ufshcd_probe_hba(struct ufs_hba *hba) { - struct ufs_hba *hba = (struct ufs_hba *)data; int ret; ret = ufshcd_link_startup(hba); @@ -3275,7 +3297,26 @@ static void ufshcd_async_scan(void *data, async_cookie_t cookie) pm_runtime_put_sync(hba->dev); } out: - return; + /* + * If we failed to initialize the device or the device is not + * present, turn off the power/clocks etc. + */ + if (ret && !ufshcd_eh_in_progress(hba)) + ufshcd_hba_exit(hba); + + return ret; +} + +/** + * ufshcd_async_scan - asynchronous execution for probing hba + * @data: data pointer to pass to this function + * @cookie: cookie data + */ +static void ufshcd_async_scan(void *data, async_cookie_t cookie) +{ + struct ufs_hba *hba = (struct ufs_hba *)data; + + ufshcd_probe_hba(hba); } static struct scsi_host_template ufshcd_driver_template = { @@ -3596,6 +3637,7 @@ static int ufshcd_hba_init(struct ufs_hba *hba) if (err) goto out_disable_vreg; + hba->is_powered = true; goto out; out_disable_vreg: @@ -3608,9 +3650,12 @@ out: static void ufshcd_hba_exit(struct ufs_hba *hba) { - ufshcd_variant_hba_exit(hba); - ufshcd_setup_vreg(hba, false); - ufshcd_setup_clocks(hba, false); + if (hba->is_powered) { + ufshcd_variant_hba_exit(hba); + ufshcd_setup_vreg(hba, false); + ufshcd_setup_clocks(hba, false); + hba->is_powered = false; + } } /** diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index bc0f7ed..eddb3f3 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -228,6 +228,7 @@ struct ufs_hba_variant_ops { * @eh_flags: Error handling flags * @intr_mask: Interrupt Mask Bits * @ee_ctrl_mask: Exception event control mask + * @is_powered: flag to check if HBA is powered * @eh_work: Worker to handle UFS errors that require s/w attention * @eeh_work: Worker to handle exception events * @errors: HBA errors @@ -283,6 +284,7 @@ struct ufs_hba { u32 eh_flags; u32 intr_mask; u16 ee_ctrl_mask; + bool is_powered; /* Work Queues */ struct work_struct eh_work;