Message ID | 20230502083923.34562-1-ilpo.jarvinen@linux.intel.com |
---|---|
State | New |
Headers |
Return-Path: <linux-kernel-owner@vger.kernel.org> Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:b0ea:0:b0:3b6:4342:cba0 with SMTP id b10csp449271vqo; Tue, 2 May 2023 01:43:35 -0700 (PDT) X-Google-Smtp-Source: ACHHUZ76TxDtRnBR9jIgd8TqGXlBepqMdN4Iv9GLKUZTjootD4p4hN1T/FnfNHfirf3mf3l7nZet X-Received: by 2002:a17:903:1cb:b0:1a9:86ca:38cd with SMTP id e11-20020a17090301cb00b001a986ca38cdmr20552453plh.2.1683017015256; Tue, 02 May 2023 01:43:35 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1683017015; cv=none; d=google.com; s=arc-20160816; b=hy6sg9YDouF5VZB8Nk/6RxnN4QLbBT1mKUph7jUuzcD4sQ6857mCFOFDQJ7c+gkD9m 9hdXDPG0gP3XG1ZpE7dVNbGPz2aYNDd1hblSapSFp9tB065h/CDLxgGYUdYV/Z4WqolR 3lGAYEvyZrTJy8NoIIXki7f975cFhZG6UCnrrkzdGv4C9Hx4+b/3SxSS0b5uHrpQ+o/d NHJOUaHuAbiUtEjCwwn5wtDYzSykqZlmPDzdjMbYKzWA4iL9ov96oICs/C9j3yqwJOii ArwHGO+1a5Vub1q6Zaf4P1c4GjWnZlgIMHFW/S5lbgDon72I3q7sK+hJ4w+rZR0jZXWo Ncxg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :message-id:date:subject:cc:to:from:dkim-signature; bh=qimllMDGYQD6dbCJvfAUlKkP7rhH5Y/vilPZ5eANtWk=; b=K8pHfZGHMbAh3nIs1X+ElokBltiu7jP0IODrn+fpLVfWiIrE+uNcet/andpE6LOUdy klSPFufUX4Yk77Q1ScAMvodIUDWcRB8CJVIdGyM/p9E+EiEIGF2ubm5Uj4OgQGQdMWQR Ewec3PHm5PQ3joLNyXnw/nsyQ/oUmQ8MqJiXaWhUDB1yrZy4m8zi+XrVATw9MubvWPi+ JL0OQow5TtClMuAsHw1EQrMRNMNzmNcFZweeTOFrL90rxDdBKy/9BNPHryK7777JPZfm xR/rAqd4rsH6CNKuQ+J0cT5FCwxXqUOXGhKQwoMCwUDRgYCcZM82eIXRVTiAoARtCyxo nHOw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@intel.com header.s=Intel header.b=SDxPQPNT; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=intel.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id p10-20020a170902ebca00b001a10c64c68csi30592914plg.113.2023.05.02.01.43.22; Tue, 02 May 2023 01:43:35 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@intel.com header.s=Intel header.b=SDxPQPNT; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=intel.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233805AbjEBIjh (ORCPT <rfc822;rbbytesnap@gmail.com> + 99 others); Tue, 2 May 2023 04:39:37 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45884 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233588AbjEBIjf (ORCPT <rfc822;linux-kernel@vger.kernel.org>); Tue, 2 May 2023 04:39:35 -0400 Received: from mga09.intel.com (mga09.intel.com [134.134.136.24]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 64ACF10B; Tue, 2 May 2023 01:39:34 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1683016774; x=1714552774; h=from:to:cc:subject:date:message-id:mime-version: content-transfer-encoding; bh=NQ7UtzDQj6DonGb4HNH9Xd0QLx15TZUY6naY4Em3T/4=; b=SDxPQPNTI1UiE+Gjvi6MBbYz18+/PhndnXY33X92I6K7Lg4mtHV2QVKu 9gVXqKhOPHuIk0TsdildpgTIzFGyT+hK7BWA/B78egWo8NZj/xWSB19TX ofDYeVqxtLDPF45dNVoUAijM3dm+hJGRq8Nl5n1DEc6HkqUk3JNGCPW/S eZ8bHAh9AXE/zjtSfHwTOdvZ3VSOdJHaTvrF3rtQIS8TPbmAUX4a6akja t2inhdOvTkjmnCy64/XTomCV5bInZcW25cyFs0tyVPawCKqSXS5Xoy1KU Uq27sCKUKJFiy0BAMek+6DBK3kj1d3LjeoQDEqwog3r/P45sB/B5nMI0r A==; X-IronPort-AV: E=McAfee;i="6600,9927,10697"; a="350421628" X-IronPort-AV: E=Sophos;i="5.99,243,1677571200"; d="scan'208";a="350421628" Received: from orsmga001.jf.intel.com ([10.7.209.18]) by orsmga102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 02 May 2023 01:39:34 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10697"; a="728850171" X-IronPort-AV: E=Sophos;i="5.99,243,1677571200"; d="scan'208";a="728850171" Received: from rmasarlx-mobl1.gar.corp.intel.com (HELO ijarvine-MOBL2.ger.corp.intel.com) ([10.252.34.132]) by orsmga001-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 02 May 2023 01:39:31 -0700 From: =?utf-8?q?Ilpo_J=C3=A4rvinen?= <ilpo.jarvinen@linux.intel.com> To: Bjorn Helgaas <bhelgaas@google.com>, Shaohua Li <shaohua.li@intel.com>, Greg Kroah-Hartman <gregkh@suse.de>, linux-pci@vger.kernel.org, linux-kernel@vger.kernel.org Cc: =?utf-8?q?Ilpo_J=C3=A4rvinen?= <ilpo.jarvinen@linux.intel.com>, Lukas Wunner <lukas@wunner.de>, stable@vger.kernel.org Subject: [PATCH 1/1] PCI/ASPM: Handle link retraining race Date: Tue, 2 May 2023 11:39:23 +0300 Message-Id: <20230502083923.34562-1-ilpo.jarvinen@linux.intel.com> X-Mailer: git-send-email 2.30.2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-4.5 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_EF,RCVD_IN_DNSWL_MED, RCVD_IN_MSPIKE_H3,RCVD_IN_MSPIKE_WL,SPF_HELO_NONE,SPF_NONE, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: <linux-kernel.vger.kernel.org> X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1764771249775129933?= X-GMAIL-MSGID: =?utf-8?q?1764771249775129933?= |
Series |
[1/1] PCI/ASPM: Handle link retraining race
|
|
Commit Message
Ilpo Järvinen
May 2, 2023, 8:39 a.m. UTC
Implementation Note at the end of PCIe r6.0.1 sec 7.5.3.7 recommends handling LTSSM race to ensure link retraining acquires correct parameters from the LNKCTL register. According to the implementation note, LTSSM might transition into Recovery or Configuration state independently of the driver requesting it, and if retraining due to such an event is still ongoing, the value written into the LNKCTL register might not be considered by the link retraining. Ensure link training bit is clear before toggling link retraining bit to meet the requirements of the Implementation Note. Fixes: 7d715a6c1ae5 ("PCI: add PCI Express ASPM support") Suggested-by: Lukas Wunner <lukas@wunner.de> Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com> Reviewed-by: Lukas Wunner <lukas@wunner.de> Cc: stable@vger.kernel.org --- drivers/pci/pcie/aspm.c | 37 +++++++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 10 deletions(-)
Comments
On Tue, May 02, 2023 at 11:39:23AM +0300, Ilpo Järvinen wrote: > Implementation Note at the end of PCIe r6.0.1 sec 7.5.3.7 recommends > handling LTSSM race to ensure link retraining acquires correct > parameters from the LNKCTL register. According to the implementation > note, LTSSM might transition into Recovery or Configuration state > independently of the driver requesting it, and if retraining due to > such an event is still ongoing, the value written into the LNKCTL > register might not be considered by the link retraining. > > Ensure link training bit is clear before toggling link retraining bit > to meet the requirements of the Implementation Note. > > Fixes: 7d715a6c1ae5 ("PCI: add PCI Express ASPM support") > Suggested-by: Lukas Wunner <lukas@wunner.de> > Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com> > Reviewed-by: Lukas Wunner <lukas@wunner.de> > Cc: stable@vger.kernel.org Thanks for this! The existing pcie_retrain_link() and pcie_wait_for_retrain() both return bool, but neither is named as a predicate, and it's always a little hard for me to keep track of what the true/false return values mean. I propose tweaking them so they both return 0 for success or -ETIMEDOUT for failure. What do you think? It does make the patch bigger, which is kind of unfortunate. Bjorn commit f55ef626b57f ("PCI/ASPM: Avoid link retraining race") parent e8d05f522fae Author: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com> Date: Tue May 2 11:39:23 2023 +0300 PCI/ASPM: Avoid link retraining race PCIe r6.0.1, sec 7.5.3.7, recommends setting the link control parameters, then waiting for the Link Training bit to be clear before setting the Retrain Link bit. This avoids a race where the LTSSM may not use the updated parameters if it is already in the midst of link training because of other normal link activity. Wait for the Link Training bit to be clear before toggling the Retrain Link bit to ensure that the LTSSM uses the updated link control parameters. [bhelgaas: commit log, return 0 (success)/-ETIMEDOUT instead of bool for both pcie_wait_for_retrain() and the existing pcie_retrain_link()] Suggested-by: Lukas Wunner <lukas@wunner.de> Fixes: 7d715a6c1ae5 ("PCI: add PCI Express ASPM support") Link: https://lore.kernel.org/r/20230502083923.34562-1-ilpo.jarvinen@linux.intel.com Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Reviewed-by: Lukas Wunner <lukas@wunner.de> Cc: stable@vger.kernel.org diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index 72cdb30a924a..3aa73ecdf86f 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -193,12 +193,39 @@ static void pcie_clkpm_cap_init(struct pcie_link_state *link, int blacklist) link->clkpm_disable = blacklist ? 1 : 0; } -static bool pcie_retrain_link(struct pcie_link_state *link) +static int pcie_wait_for_retrain(struct pci_dev *pdev) { - struct pci_dev *parent = link->pdev; unsigned long end_jiffies; u16 reg16; + /* Wait for Link Training to be cleared by hardware */ + end_jiffies = jiffies + LINK_RETRAIN_TIMEOUT; + do { + pcie_capability_read_word(pdev, PCI_EXP_LNKSTA, ®16); + if (!(reg16 & PCI_EXP_LNKSTA_LT)) + return 0; + msleep(1); + } while (time_before(jiffies, end_jiffies)); + + return -ETIMEDOUT; +} + +static int pcie_retrain_link(struct pcie_link_state *link) +{ + struct pci_dev *parent = link->pdev; + int rc; + u16 reg16; + + /* + * Ensure the updated LNKCTL parameters are used during link + * training by checking that there is no ongoing link training to + * avoid LTSSM race as recommended in Implementation Note at the + * end of PCIe r6.0.1 sec 7.5.3.7. + */ + rc = pcie_wait_for_retrain(parent); + if (rc) + return rc; + pcie_capability_read_word(parent, PCI_EXP_LNKCTL, ®16); reg16 |= PCI_EXP_LNKCTL_RL; pcie_capability_write_word(parent, PCI_EXP_LNKCTL, reg16); @@ -212,15 +239,7 @@ static bool pcie_retrain_link(struct pcie_link_state *link) pcie_capability_write_word(parent, PCI_EXP_LNKCTL, reg16); } - /* Wait for link training end. Break out after waiting for timeout */ - end_jiffies = jiffies + LINK_RETRAIN_TIMEOUT; - do { - pcie_capability_read_word(parent, PCI_EXP_LNKSTA, ®16); - if (!(reg16 & PCI_EXP_LNKSTA_LT)) - break; - msleep(1); - } while (time_before(jiffies, end_jiffies)); - return !(reg16 & PCI_EXP_LNKSTA_LT); + return pcie_wait_for_retrain(parent); } /* @@ -289,15 +308,15 @@ static void pcie_aspm_configure_common_clock(struct pcie_link_state *link) reg16 &= ~PCI_EXP_LNKCTL_CCC; pcie_capability_write_word(parent, PCI_EXP_LNKCTL, reg16); - if (pcie_retrain_link(link)) - return; + if (pcie_retrain_link(link)) { - /* Training failed. Restore common clock configurations */ - pci_err(parent, "ASPM: Could not configure common clock\n"); - list_for_each_entry(child, &linkbus->devices, bus_list) - pcie_capability_write_word(child, PCI_EXP_LNKCTL, + /* Training failed. Restore common clock configurations */ + pci_err(parent, "ASPM: Could not configure common clock\n"); + list_for_each_entry(child, &linkbus->devices, bus_list) + pcie_capability_write_word(child, PCI_EXP_LNKCTL, child_reg[PCI_FUNC(child->devfn)]); - pcie_capability_write_word(parent, PCI_EXP_LNKCTL, parent_reg); + pcie_capability_write_word(parent, PCI_EXP_LNKCTL, parent_reg); + } } /* Convert L0s latency encoding to ns */ > --- > drivers/pci/pcie/aspm.c | 37 +++++++++++++++++++++++++++---------- > 1 file changed, 27 insertions(+), 10 deletions(-) > > diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c > index 66d7514ca111..dde1ef13d0d1 100644 > --- a/drivers/pci/pcie/aspm.c > +++ b/drivers/pci/pcie/aspm.c > @@ -193,12 +193,37 @@ static void pcie_clkpm_cap_init(struct pcie_link_state *link, int blacklist) > link->clkpm_disable = blacklist ? 1 : 0; > } > > +static bool pcie_wait_for_retrain(struct pci_dev *pdev) > +{ > + unsigned long end_jiffies; > + u16 reg16; > + > + /* Wait for link training end. Break out after waiting for timeout */ > + end_jiffies = jiffies + LINK_RETRAIN_TIMEOUT; > + do { > + pcie_capability_read_word(pdev, PCI_EXP_LNKSTA, ®16); > + if (!(reg16 & PCI_EXP_LNKSTA_LT)) > + break; > + msleep(1); > + } while (time_before(jiffies, end_jiffies)); > + > + return !(reg16 & PCI_EXP_LNKSTA_LT); > +} > + > static bool pcie_retrain_link(struct pcie_link_state *link) > { > struct pci_dev *parent = link->pdev; > - unsigned long end_jiffies; > u16 reg16; > > + /* > + * Ensure the updated LNKCTL parameters are used during link > + * training by checking that there is no ongoing link training to > + * avoid LTSSM race as recommended in Implementation Note at the end > + * of PCIe r6.0.1 sec 7.5.3.7. > + */ > + if (!pcie_wait_for_retrain(parent)) > + return false; > + > pcie_capability_read_word(parent, PCI_EXP_LNKCTL, ®16); > reg16 |= PCI_EXP_LNKCTL_RL; > pcie_capability_write_word(parent, PCI_EXP_LNKCTL, reg16); > @@ -212,15 +237,7 @@ static bool pcie_retrain_link(struct pcie_link_state *link) > pcie_capability_write_word(parent, PCI_EXP_LNKCTL, reg16); > } > > - /* Wait for link training end. Break out after waiting for timeout */ > - end_jiffies = jiffies + LINK_RETRAIN_TIMEOUT; > - do { > - pcie_capability_read_word(parent, PCI_EXP_LNKSTA, ®16); > - if (!(reg16 & PCI_EXP_LNKSTA_LT)) > - break; > - msleep(1); > - } while (time_before(jiffies, end_jiffies)); > - return !(reg16 & PCI_EXP_LNKSTA_LT); > + return pcie_wait_for_retrain(parent); > } > > /* > -- > 2.30.2 >
On Thu, 18 May 2023, Bjorn Helgaas wrote: > On Tue, May 02, 2023 at 11:39:23AM +0300, Ilpo Järvinen wrote: > > Implementation Note at the end of PCIe r6.0.1 sec 7.5.3.7 recommends > > handling LTSSM race to ensure link retraining acquires correct > > parameters from the LNKCTL register. According to the implementation > > note, LTSSM might transition into Recovery or Configuration state > > independently of the driver requesting it, and if retraining due to > > such an event is still ongoing, the value written into the LNKCTL > > register might not be considered by the link retraining. > > > > Ensure link training bit is clear before toggling link retraining bit > > to meet the requirements of the Implementation Note. > > > > Fixes: 7d715a6c1ae5 ("PCI: add PCI Express ASPM support") > > Suggested-by: Lukas Wunner <lukas@wunner.de> > > Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com> > > Reviewed-by: Lukas Wunner <lukas@wunner.de> > > Cc: stable@vger.kernel.org > > Thanks for this! > > The existing pcie_retrain_link() and pcie_wait_for_retrain() both > return bool, but neither is named as a predicate, and it's always a > little hard for me to keep track of what the true/false return values > mean. > > I propose tweaking them so they both return 0 for success or > -ETIMEDOUT for failure. What do you think? It does make the patch > bigger, which is kind of unfortunate. It's better, yes, unless stable folks think it's not a minimal change. As a confirmation for your return tweak improving things, I recall that I had to be careful with the bool in this case for the reasons you mention (it requires more mental capacity and verification which way the return is). (Also, expect the error handling reindent to cause a conflict with the RMW series.)
On Fri, May 19, 2023 at 12:30:34PM +0300, Ilpo Järvinen wrote: > On Thu, 18 May 2023, Bjorn Helgaas wrote: > > On Tue, May 02, 2023 at 11:39:23AM +0300, Ilpo Järvinen wrote: > > > Implementation Note at the end of PCIe r6.0.1 sec 7.5.3.7 recommends > > > handling LTSSM race to ensure link retraining acquires correct > > > parameters from the LNKCTL register. According to the implementation > > > note, LTSSM might transition into Recovery or Configuration state > > > independently of the driver requesting it, and if retraining due to > > > such an event is still ongoing, the value written into the LNKCTL > > > register might not be considered by the link retraining. > > > > > > Ensure link training bit is clear before toggling link retraining bit > > > to meet the requirements of the Implementation Note. > > > > > > Fixes: 7d715a6c1ae5 ("PCI: add PCI Express ASPM support") > > > Suggested-by: Lukas Wunner <lukas@wunner.de> > > > Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com> > > > Reviewed-by: Lukas Wunner <lukas@wunner.de> > > > Cc: stable@vger.kernel.org > > > > Thanks for this! > > > > The existing pcie_retrain_link() and pcie_wait_for_retrain() both > > return bool, but neither is named as a predicate, and it's always a > > little hard for me to keep track of what the true/false return values > > mean. > > > > I propose tweaking them so they both return 0 for success or > > -ETIMEDOUT for failure. What do you think? It does make the patch > > bigger, which is kind of unfortunate. > > It's better, yes, unless stable folks think it's not a minimal change. > > As a confirmation for your return tweak improving things, I recall that I > had to be careful with the bool in this case for the reasons you mention > (it requires more mental capacity and verification which way the return > is). > > (Also, expect the error handling reindent to cause a conflict with the RMW > series.) OK, thanks for taking a look! I applied the revised patch to pci/aspm for v6.5. I'll take care of any conflicts with the RMW series. > > commit f55ef626b57f ("PCI/ASPM: Avoid link retraining race") > > parent e8d05f522fae > > Author: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com> > > Date: Tue May 2 11:39:23 2023 +0300 > > > > PCI/ASPM: Avoid link retraining race > > > > PCIe r6.0.1, sec 7.5.3.7, recommends setting the link control parameters, > > then waiting for the Link Training bit to be clear before setting the > > Retrain Link bit. > > > > This avoids a race where the LTSSM may not use the updated parameters if it > > is already in the midst of link training because of other normal link > > activity. > > > > Wait for the Link Training bit to be clear before toggling the Retrain Link > > bit to ensure that the LTSSM uses the updated link control parameters. > > > > [bhelgaas: commit log, return 0 (success)/-ETIMEDOUT instead of bool for > > both pcie_wait_for_retrain() and the existing pcie_retrain_link()] > > Suggested-by: Lukas Wunner <lukas@wunner.de> > > Fixes: 7d715a6c1ae5 ("PCI: add PCI Express ASPM support") > > Link: https://lore.kernel.org/r/20230502083923.34562-1-ilpo.jarvinen@linux.intel.com > > Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com> > > Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> > > Reviewed-by: Lukas Wunner <lukas@wunner.de> > > Cc: stable@vger.kernel.org > > > > diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c > > index 72cdb30a924a..3aa73ecdf86f 100644 > > --- a/drivers/pci/pcie/aspm.c > > +++ b/drivers/pci/pcie/aspm.c > > @@ -193,12 +193,39 @@ static void pcie_clkpm_cap_init(struct pcie_link_state *link, int blacklist) > > link->clkpm_disable = blacklist ? 1 : 0; > > } > > > > -static bool pcie_retrain_link(struct pcie_link_state *link) > > +static int pcie_wait_for_retrain(struct pci_dev *pdev) > > { > > - struct pci_dev *parent = link->pdev; > > unsigned long end_jiffies; > > u16 reg16; > > > > + /* Wait for Link Training to be cleared by hardware */ > > + end_jiffies = jiffies + LINK_RETRAIN_TIMEOUT; > > + do { > > + pcie_capability_read_word(pdev, PCI_EXP_LNKSTA, ®16); > > + if (!(reg16 & PCI_EXP_LNKSTA_LT)) > > + return 0; > > + msleep(1); > > + } while (time_before(jiffies, end_jiffies)); > > + > > + return -ETIMEDOUT; > > +} > > + > > +static int pcie_retrain_link(struct pcie_link_state *link) > > +{ > > + struct pci_dev *parent = link->pdev; > > + int rc; > > + u16 reg16; > > + > > + /* > > + * Ensure the updated LNKCTL parameters are used during link > > + * training by checking that there is no ongoing link training to > > + * avoid LTSSM race as recommended in Implementation Note at the > > + * end of PCIe r6.0.1 sec 7.5.3.7. > > + */ > > + rc = pcie_wait_for_retrain(parent); > > + if (rc) > > + return rc; > > + > > pcie_capability_read_word(parent, PCI_EXP_LNKCTL, ®16); > > reg16 |= PCI_EXP_LNKCTL_RL; > > pcie_capability_write_word(parent, PCI_EXP_LNKCTL, reg16); > > @@ -212,15 +239,7 @@ static bool pcie_retrain_link(struct pcie_link_state *link) > > pcie_capability_write_word(parent, PCI_EXP_LNKCTL, reg16); > > } > > > > - /* Wait for link training end. Break out after waiting for timeout */ > > - end_jiffies = jiffies + LINK_RETRAIN_TIMEOUT; > > - do { > > - pcie_capability_read_word(parent, PCI_EXP_LNKSTA, ®16); > > - if (!(reg16 & PCI_EXP_LNKSTA_LT)) > > - break; > > - msleep(1); > > - } while (time_before(jiffies, end_jiffies)); > > - return !(reg16 & PCI_EXP_LNKSTA_LT); > > + return pcie_wait_for_retrain(parent); > > } > > > > /* > > @@ -289,15 +308,15 @@ static void pcie_aspm_configure_common_clock(struct pcie_link_state *link) > > reg16 &= ~PCI_EXP_LNKCTL_CCC; > > pcie_capability_write_word(parent, PCI_EXP_LNKCTL, reg16); > > > > - if (pcie_retrain_link(link)) > > - return; > > + if (pcie_retrain_link(link)) { > > > > - /* Training failed. Restore common clock configurations */ > > - pci_err(parent, "ASPM: Could not configure common clock\n"); > > - list_for_each_entry(child, &linkbus->devices, bus_list) > > - pcie_capability_write_word(child, PCI_EXP_LNKCTL, > > + /* Training failed. Restore common clock configurations */ > > + pci_err(parent, "ASPM: Could not configure common clock\n"); > > + list_for_each_entry(child, &linkbus->devices, bus_list) > > + pcie_capability_write_word(child, PCI_EXP_LNKCTL, > > child_reg[PCI_FUNC(child->devfn)]); > > - pcie_capability_write_word(parent, PCI_EXP_LNKCTL, parent_reg); > > + pcie_capability_write_word(parent, PCI_EXP_LNKCTL, parent_reg); > > + } > > } > > > > /* Convert L0s latency encoding to ns */
diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index 66d7514ca111..dde1ef13d0d1 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -193,12 +193,37 @@ static void pcie_clkpm_cap_init(struct pcie_link_state *link, int blacklist) link->clkpm_disable = blacklist ? 1 : 0; } +static bool pcie_wait_for_retrain(struct pci_dev *pdev) +{ + unsigned long end_jiffies; + u16 reg16; + + /* Wait for link training end. Break out after waiting for timeout */ + end_jiffies = jiffies + LINK_RETRAIN_TIMEOUT; + do { + pcie_capability_read_word(pdev, PCI_EXP_LNKSTA, ®16); + if (!(reg16 & PCI_EXP_LNKSTA_LT)) + break; + msleep(1); + } while (time_before(jiffies, end_jiffies)); + + return !(reg16 & PCI_EXP_LNKSTA_LT); +} + static bool pcie_retrain_link(struct pcie_link_state *link) { struct pci_dev *parent = link->pdev; - unsigned long end_jiffies; u16 reg16; + /* + * Ensure the updated LNKCTL parameters are used during link + * training by checking that there is no ongoing link training to + * avoid LTSSM race as recommended in Implementation Note at the end + * of PCIe r6.0.1 sec 7.5.3.7. + */ + if (!pcie_wait_for_retrain(parent)) + return false; + pcie_capability_read_word(parent, PCI_EXP_LNKCTL, ®16); reg16 |= PCI_EXP_LNKCTL_RL; pcie_capability_write_word(parent, PCI_EXP_LNKCTL, reg16); @@ -212,15 +237,7 @@ static bool pcie_retrain_link(struct pcie_link_state *link) pcie_capability_write_word(parent, PCI_EXP_LNKCTL, reg16); } - /* Wait for link training end. Break out after waiting for timeout */ - end_jiffies = jiffies + LINK_RETRAIN_TIMEOUT; - do { - pcie_capability_read_word(parent, PCI_EXP_LNKSTA, ®16); - if (!(reg16 & PCI_EXP_LNKSTA_LT)) - break; - msleep(1); - } while (time_before(jiffies, end_jiffies)); - return !(reg16 & PCI_EXP_LNKSTA_LT); + return pcie_wait_for_retrain(parent); } /*