From patchwork Thu Jul 6 03:09:42 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Oza Pawandeep X-Patchwork-Id: 9827493 X-Patchwork-Delegate: bhelgaas@google.com Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 1B5D060351 for ; Thu, 6 Jul 2017 03:11:02 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 09E8E2859F for ; Thu, 6 Jul 2017 03:11:02 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id F2C14285AF; Thu, 6 Jul 2017 03:11:01 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 6470D2853D for ; Thu, 6 Jul 2017 03:11:01 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752831AbdGFDKn (ORCPT ); Wed, 5 Jul 2017 23:10:43 -0400 Received: from mail-wr0-f172.google.com ([209.85.128.172]:35207 "EHLO mail-wr0-f172.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752466AbdGFDKF (ORCPT ); Wed, 5 Jul 2017 23:10:05 -0400 Received: by mail-wr0-f172.google.com with SMTP id k67so9590107wrc.2 for ; Wed, 05 Jul 2017 20:10:04 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=broadcom.com; s=google; h=from:to:subject:date:message-id:in-reply-to:references; bh=4j2gCEzfDEfRh2roW5dbfcP4PSrnJv53UV1xIHqn6HA=; b=bahJxmSFf7PxNjZ5pQJUvppI9dKTpEbOnPNgSyB5WzgprA9Gl9IDxb5Bdup6RaE5JL Vmkewo9wr+vN9GU3cxJzb/KBQGp66vhG+RmtTt0NXjbbbgrY+W0Yyuyk0wKHeNTZrWXx Wgj/pz695jKfAyko03eyXl0CkxVxb1ZtMLSns= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=4j2gCEzfDEfRh2roW5dbfcP4PSrnJv53UV1xIHqn6HA=; b=IAMKn1RCsmHjTzpmKCfuLqtQZYgYRUhhXKCbzL6nmwT3llfoDL+pUmZcRsXyxygU7I hGxXogWzyZJo1Ll8DbqKB0D726TZx9qG9BoNG/K0ZY50A8CFsRf/kAekyvQPByw7bXjT l6UbwSpw/o+kgIGWe60yvehlXYAc6FEBuVcU1FRjnOAoGh+rOV8i8yPuYHanlkthl3i6 qby43qpA3NXBtCf22UO+a7kPYakrhmWgAiuFpbjKgPT4b5ma8xxDk09s3eLpvkQLJLWy LThzgYOB0BcN3XN+BgOgfVPJa3BItlYt4QHKA5mnzSXt+9vBkIEMrBHHmRW5OC26p6Xm rQCQ== X-Gm-Message-State: AKS2vOykLoKBhbAoRzMra5r/z0uGHpOUXM6jgYQ4aFPDLj3pWP7Xc0uZ eYjXmQusTNfnFy2X X-Received: by 10.28.182.137 with SMTP id g131mr34469561wmf.95.1499310603766; Wed, 05 Jul 2017 20:10:03 -0700 (PDT) Received: from anjanavk-OptiPlex-7010.dhcp.avagotech.net ([192.19.237.250]) by smtp.gmail.com with ESMTPSA id b94sm664946wrd.40.2017.07.05.20.09.58 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 05 Jul 2017 20:10:03 -0700 (PDT) From: Oza Pawandeep To: Bjorn Helgaas , Ray Jui , Scott Branden , Jon Mason , bcm-kernel-feedback-list@broadcom.com, Oza Pawandeep , Andy Gospodarek , linux-pci@vger.kernel.org, linux-kernel@vger.kernel.org, Oza Pawandeep Subject: [PATCH v5 2/2] PCI: iproc: add device shutdown for PCI RC Date: Thu, 6 Jul 2017 08:39:42 +0530 Message-Id: <1499310582-21193-3-git-send-email-oza.oza@broadcom.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1499310582-21193-1-git-send-email-oza.oza@broadcom.com> References: <1499310582-21193-1-git-send-email-oza.oza@broadcom.com> Sender: linux-pci-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pci@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP PERST must be asserted around ~500ms before the reboot is applied. During soft reset (e.g., "reboot" from Linux) on some iproc based SOCs LCPLL clock and PERST both goes off simultaneously. This will cause certain Endpoints Intel NVMe not get detected, upon next boot sequence. This is specifically happening with Intel P3700 400GB series. Endpoint is expecting the clock for some amount of time after PERST is asserted, which is not happening in Stingray (iproc based SOC). This causes NVMe to behave in undefined way. On the contrary, Intel x86 boards will have ref clock running, so we do not see this behavior there. Besides, PCI spec does not stipulate about such timings. In-fact it does not tell us, whether PCIe device should consider refclk to be available or not to be. It is completely up to vendor to design their EP the way they want with respect to ref clock availability. 500ms is just based on the observation and taken as safe margin. This patch adds platform shutdown where it should be called in device_shutdown while reboot command is issued. So in sequence first Endpoint Shutdown (e.g. nvme_shutdown) followed by RC shutdown, which issues safe PERST assertion. Signed-off-by: Oza Pawandeep Reviewed-by: Ray Jui Reviewed-by: Scott Branden diff --git a/drivers/pci/host/pcie-iproc-platform.c b/drivers/pci/host/pcie-iproc-platform.c index 90d2bdd..9512960 100644 --- a/drivers/pci/host/pcie-iproc-platform.c +++ b/drivers/pci/host/pcie-iproc-platform.c @@ -131,6 +131,13 @@ static int iproc_pcie_pltfm_remove(struct platform_device *pdev) return iproc_pcie_remove(pcie); } +static void iproc_pcie_pltfm_shutdown(struct platform_device *pdev) +{ + struct iproc_pcie *pcie = platform_get_drvdata(pdev); + + iproc_pcie_shutdown(pcie); +} + static struct platform_driver iproc_pcie_pltfm_driver = { .driver = { .name = "iproc-pcie", @@ -138,6 +145,7 @@ static int iproc_pcie_pltfm_remove(struct platform_device *pdev) }, .probe = iproc_pcie_pltfm_probe, .remove = iproc_pcie_pltfm_remove, + .shutdown = iproc_pcie_pltfm_shutdown, }; module_platform_driver(iproc_pcie_pltfm_driver); diff --git a/drivers/pci/host/pcie-iproc.c b/drivers/pci/host/pcie-iproc.c index b0abcd7..6804bd1 100644 --- a/drivers/pci/host/pcie-iproc.c +++ b/drivers/pci/host/pcie-iproc.c @@ -616,7 +616,7 @@ static int iproc_pcie_config_write32(struct pci_bus *bus, unsigned int devfn, .write = iproc_pcie_config_write32, }; -static void iproc_pcie_reset(struct iproc_pcie *pcie) +static void iproc_pcie_perst_ctrl(struct iproc_pcie *pcie, bool assert) { u32 val; @@ -628,20 +628,28 @@ static void iproc_pcie_reset(struct iproc_pcie *pcie) if (pcie->ep_is_internal) return; - /* - * Select perst_b signal as reset source. Put the device into reset, - * and then bring it out of reset - */ - val = iproc_pcie_read_reg(pcie, IPROC_PCIE_CLK_CTRL); - val &= ~EP_PERST_SOURCE_SELECT & ~EP_MODE_SURVIVE_PERST & - ~RC_PCIE_RST_OUTPUT; - iproc_pcie_write_reg(pcie, IPROC_PCIE_CLK_CTRL, val); - udelay(250); - - val |= RC_PCIE_RST_OUTPUT; - iproc_pcie_write_reg(pcie, IPROC_PCIE_CLK_CTRL, val); - msleep(100); + if (assert) { + val = iproc_pcie_read_reg(pcie, IPROC_PCIE_CLK_CTRL); + val &= ~EP_PERST_SOURCE_SELECT & ~EP_MODE_SURVIVE_PERST & + ~RC_PCIE_RST_OUTPUT; + iproc_pcie_write_reg(pcie, IPROC_PCIE_CLK_CTRL, val); + udelay(250); + } else { + val = iproc_pcie_read_reg(pcie, IPROC_PCIE_CLK_CTRL); + val |= RC_PCIE_RST_OUTPUT; + iproc_pcie_write_reg(pcie, IPROC_PCIE_CLK_CTRL, val); + msleep(100); + } +} + +int iproc_pcie_shutdown(struct iproc_pcie *pcie) +{ + iproc_pcie_perst_ctrl(pcie, true); + msleep(500); + + return 0; } +EXPORT_SYMBOL(iproc_pcie_shutdown); static int iproc_pcie_check_link(struct iproc_pcie *pcie, struct pci_bus *bus) { @@ -1318,7 +1326,8 @@ int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res) goto err_exit_phy; } - iproc_pcie_reset(pcie); + iproc_pcie_perst_ctrl(pcie, true); + iproc_pcie_perst_ctrl(pcie, false); if (pcie->need_ob_cfg) { ret = iproc_pcie_map_ranges(pcie, res); diff --git a/drivers/pci/host/pcie-iproc.h b/drivers/pci/host/pcie-iproc.h index 0bbe2ea..a6b55ce 100644 --- a/drivers/pci/host/pcie-iproc.h +++ b/drivers/pci/host/pcie-iproc.h @@ -110,6 +110,7 @@ struct iproc_pcie { int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res); int iproc_pcie_remove(struct iproc_pcie *pcie); +int iproc_pcie_shutdown(struct iproc_pcie *pcie); #ifdef CONFIG_PCIE_IPROC_MSI int iproc_msi_init(struct iproc_pcie *pcie, struct device_node *node);