Message ID | 1715666198-9140-1-git-send-email-hongxing.zhu@nxp.com (mailing list archive) |
---|---|
State | Superseded |
Headers | show |
Series | [v2] PCI: dwc: Fix suspend hang when e1000e network card is connected | expand |
On Tue, May 14, 2024 at 3:16 AM Richard Zhu <hongxing.zhu@nxp.com> wrote: > > In dw_pcie_suspend_noirq() and after the PME_TURN_OFF messgage is sent out, > one PMC version2.0 endpoint device E1000E network card hangs in LTSSM stat > polling and L2 stat check. > > To avoid this hang issue after the PME_TURN_OFF message is sent out. > Only poll and check LTSSM L2 stat if the EP's PMC version is 3 or later, > > Signed-off-by: Richard Zhu <hongxing.zhu@nxp.com> Fixes tag?
On Tue, May 14, 2024 at 01:56:38PM +0800, Richard Zhu wrote: > In dw_pcie_suspend_noirq() and after the PME_TURN_OFF messgage is sent out, > one PMC version2.0 endpoint device E1000E network card hangs in LTSSM stat > polling and L2 stat check. > > To avoid this hang issue after the PME_TURN_OFF message is sent out. > Only poll and check LTSSM L2 stat if the EP's PMC version is 3 or later, > > Signed-off-by: Richard Zhu <hongxing.zhu@nxp.com> > --- > - Add a new help function dwc_get_devices_pmc_version() to get devices PMC > versions. > > .../pci/controller/dwc/pcie-designware-host.c | 46 ++++++++++++++++++- > 1 file changed, 45 insertions(+), 1 deletion(-) > > diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c > index cb8c3c2bcc790..0c2794e7bcf0a 100644 > --- a/drivers/pci/controller/dwc/pcie-designware-host.c > +++ b/drivers/pci/controller/dwc/pcie-designware-host.c > @@ -884,6 +884,42 @@ int dw_pcie_setup_rc(struct dw_pcie_rp *pp) > } > EXPORT_SYMBOL_GPL(dw_pcie_setup_rc); > > +static int dwc_get_devices_pmc_version(struct dw_pcie *pci) > +{ > + int ret; > + u16 pmc, ver = 0; > + struct dw_pcie_rp *pp = &pci->pp; > + struct pci_bus *child, *root_bus = NULL; > + struct pci_dev *pdev; > + > + /* Check the remote EP's PMC version */ > + list_for_each_entry(child, &pp->bridge->bus->children, node) { > + if (child->parent == pp->bridge->bus) { > + root_bus = child; > + break; > + } > + } > + > + if (!root_bus) { > + dev_err(pci->dev, "Failed to find downstream devices\n"); > + return -ENODEV; > + } > + > + list_for_each_entry(pdev, &root_bus->devices, bus_list) { > + if (PCI_SLOT(pdev->devfn) == 0) { > + /* find PCI PM capability in list */ > + ret = pci_find_capability(pdev, PCI_CAP_ID_PM); > + if (!ret) > + return ret; > + /* Check device's PM ability version */ > + pci_read_config_word(pdev, ret + PCI_PM_PMC, &pmc); > + ver &= pmc; ver is 0. so ver will be always 0 by '&='. By the ways, in 7.5.2 PCI Power Management Capability Structure I have not found version info. Frank > + } > + } > + > + return ver; > +} > + > static int dw_pcie_pme_turn_off(struct dw_pcie *pci) > { > struct dw_pcie_ob_atu_cfg atu = { 0 }; > @@ -924,7 +960,7 @@ int dw_pcie_suspend_noirq(struct dw_pcie *pci) > { > u8 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP); > u32 val; > - int ret = 0; > + int pmc_ver, ret = 0; > > /* > * If L1SS is supported, then do not put the link into L2 as some > @@ -933,6 +969,8 @@ int dw_pcie_suspend_noirq(struct dw_pcie *pci) > if (dw_pcie_readw_dbi(pci, offset + PCI_EXP_LNKCTL) & PCI_EXP_LNKCTL_ASPM_L1) > return 0; > > + pmc_ver = dwc_get_devices_pmc_version(pci); > + > if (dw_pcie_get_ltssm(pci) > DW_PCIE_LTSSM_DETECT_ACT) { > /* Only send out PME_TURN_OFF when PCIE link is up */ > if (pci->pp.ops->pme_turn_off) > @@ -942,7 +980,13 @@ int dw_pcie_suspend_noirq(struct dw_pcie *pci) > > if (ret) > return ret; > + } > > + /* > + * PMC Ver2.0 device e1000e NIC hangs in LTSSM polling and L2 check. > + * Only do the L2 check when PMC version is Ver3.0 or later. > + */ > + if (pmc_ver >= 3) { > ret = read_poll_timeout(dw_pcie_get_ltssm, val, val == DW_PCIE_LTSSM_L2_IDLE, > PCIE_PME_TO_L2_TIMEOUT_US/10, > PCIE_PME_TO_L2_TIMEOUT_US, false, pci); > -- > 2.37.1 >
> -----Original Message----- > From: Frank Li <frank.li@nxp.com> > Sent: 2024年5月14日 22:29 > To: Hongxing Zhu <hongxing.zhu@nxp.com> > Cc: imx@lists.linux.dev > Subject: Re: [PATCH v2] PCI: dwc: Fix suspend hang when e1000e network card is > connected > > On Tue, May 14, 2024 at 01:56:38PM +0800, Richard Zhu wrote: > > In dw_pcie_suspend_noirq() and after the PME_TURN_OFF messgage is sent > > out, one PMC version2.0 endpoint device E1000E network card hangs in > > LTSSM stat polling and L2 stat check. > > > > To avoid this hang issue after the PME_TURN_OFF message is sent out. > > Only poll and check LTSSM L2 stat if the EP's PMC version is 3 or > > later, > > > > Signed-off-by: Richard Zhu <hongxing.zhu@nxp.com> > > --- > > - Add a new help function dwc_get_devices_pmc_version() to get devices PMC > > versions. > > > > .../pci/controller/dwc/pcie-designware-host.c | 46 > > ++++++++++++++++++- > > 1 file changed, 45 insertions(+), 1 deletion(-) > > > > diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c > > b/drivers/pci/controller/dwc/pcie-designware-host.c > > index cb8c3c2bcc790..0c2794e7bcf0a 100644 > > --- a/drivers/pci/controller/dwc/pcie-designware-host.c > > +++ b/drivers/pci/controller/dwc/pcie-designware-host.c > > @@ -884,6 +884,42 @@ int dw_pcie_setup_rc(struct dw_pcie_rp *pp) } > > EXPORT_SYMBOL_GPL(dw_pcie_setup_rc); > > > > +static int dwc_get_devices_pmc_version(struct dw_pcie *pci) { > > + int ret; > > + u16 pmc, ver = 0; > > + struct dw_pcie_rp *pp = &pci->pp; > > + struct pci_bus *child, *root_bus = NULL; > > + struct pci_dev *pdev; > > + > > + /* Check the remote EP's PMC version */ > > + list_for_each_entry(child, &pp->bridge->bus->children, node) { > > + if (child->parent == pp->bridge->bus) { > > + root_bus = child; > > + break; > > + } > > + } > > + > > + if (!root_bus) { > > + dev_err(pci->dev, "Failed to find downstream devices\n"); > > + return -ENODEV; > > + } > > + > > + list_for_each_entry(pdev, &root_bus->devices, bus_list) { > > + if (PCI_SLOT(pdev->devfn) == 0) { > > + /* find PCI PM capability in list */ > > + ret = pci_find_capability(pdev, PCI_CAP_ID_PM); > > + if (!ret) > > + return ret; > > + /* Check device's PM ability version */ > > + pci_read_config_word(pdev, ret + PCI_PM_PMC, &pmc); > > + ver &= pmc; > > ver is 0. so ver will be always 0 by '&='. > > By the ways, in 7.5.2 PCI Power Management Capability Structure I have not > found version info. Nice caught, it’s logic error. Would change it later. The PMC is defined in "PCI Bus Power Management Interface Specification" Best Regards Richard Zhu > > Frank > > > + } > > + } > > + > > + return ver; > > +} > > + > > static int dw_pcie_pme_turn_off(struct dw_pcie *pci) { > > struct dw_pcie_ob_atu_cfg atu = { 0 }; @@ -924,7 +960,7 @@ int > > dw_pcie_suspend_noirq(struct dw_pcie *pci) { > > u8 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP); > > u32 val; > > - int ret = 0; > > + int pmc_ver, ret = 0; > > > > /* > > * If L1SS is supported, then do not put the link into L2 as some @@ > > -933,6 +969,8 @@ int dw_pcie_suspend_noirq(struct dw_pcie *pci) > > if (dw_pcie_readw_dbi(pci, offset + PCI_EXP_LNKCTL) & > PCI_EXP_LNKCTL_ASPM_L1) > > return 0; > > > > + pmc_ver = dwc_get_devices_pmc_version(pci); > > + > > if (dw_pcie_get_ltssm(pci) > DW_PCIE_LTSSM_DETECT_ACT) { > > /* Only send out PME_TURN_OFF when PCIE link is up */ > > if (pci->pp.ops->pme_turn_off) > > @@ -942,7 +980,13 @@ int dw_pcie_suspend_noirq(struct dw_pcie *pci) > > > > if (ret) > > return ret; > > + } > > > > + /* > > + * PMC Ver2.0 device e1000e NIC hangs in LTSSM polling and L2 check. > > + * Only do the L2 check when PMC version is Ver3.0 or later. > > + */ > > + if (pmc_ver >= 3) { > > ret = read_poll_timeout(dw_pcie_get_ltssm, val, val == > DW_PCIE_LTSSM_L2_IDLE, > > PCIE_PME_TO_L2_TIMEOUT_US/10, > > PCIE_PME_TO_L2_TIMEOUT_US, false, pci); > > -- > > 2.37.1 > >
> -----Original Message----- > From: Fabio Estevam <festevam@gmail.com> > Sent: 2024年5月14日 19:03 > To: Hongxing Zhu <hongxing.zhu@nxp.com> > Cc: Frank Li <frank.li@nxp.com>; imx@lists.linux.dev > Subject: Re: [PATCH v2] PCI: dwc: Fix suspend hang when e1000e network card is > connected > > On Tue, May 14, 2024 at 3:16 AM Richard Zhu <hongxing.zhu@nxp.com> wrote: > > > > In dw_pcie_suspend_noirq() and after the PME_TURN_OFF messgage is sent > > out, one PMC version2.0 endpoint device E1000E network card hangs in > > LTSSM stat polling and L2 stat check. > > > > To avoid this hang issue after the PME_TURN_OFF message is sent out. > > Only poll and check LTSSM L2 stat if the EP's PMC version is 3 or > > later, > > > > Signed-off-by: Richard Zhu <hongxing.zhu@nxp.com> > > Fixes tag? Thanks. Yes, one Fixes tag is required. Best Regards Richard Zhu
diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index cb8c3c2bcc790..0c2794e7bcf0a 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -884,6 +884,42 @@ int dw_pcie_setup_rc(struct dw_pcie_rp *pp) } EXPORT_SYMBOL_GPL(dw_pcie_setup_rc); +static int dwc_get_devices_pmc_version(struct dw_pcie *pci) +{ + int ret; + u16 pmc, ver = 0; + struct dw_pcie_rp *pp = &pci->pp; + struct pci_bus *child, *root_bus = NULL; + struct pci_dev *pdev; + + /* Check the remote EP's PMC version */ + list_for_each_entry(child, &pp->bridge->bus->children, node) { + if (child->parent == pp->bridge->bus) { + root_bus = child; + break; + } + } + + if (!root_bus) { + dev_err(pci->dev, "Failed to find downstream devices\n"); + return -ENODEV; + } + + list_for_each_entry(pdev, &root_bus->devices, bus_list) { + if (PCI_SLOT(pdev->devfn) == 0) { + /* find PCI PM capability in list */ + ret = pci_find_capability(pdev, PCI_CAP_ID_PM); + if (!ret) + return ret; + /* Check device's PM ability version */ + pci_read_config_word(pdev, ret + PCI_PM_PMC, &pmc); + ver &= pmc; + } + } + + return ver; +} + static int dw_pcie_pme_turn_off(struct dw_pcie *pci) { struct dw_pcie_ob_atu_cfg atu = { 0 }; @@ -924,7 +960,7 @@ int dw_pcie_suspend_noirq(struct dw_pcie *pci) { u8 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP); u32 val; - int ret = 0; + int pmc_ver, ret = 0; /* * If L1SS is supported, then do not put the link into L2 as some @@ -933,6 +969,8 @@ int dw_pcie_suspend_noirq(struct dw_pcie *pci) if (dw_pcie_readw_dbi(pci, offset + PCI_EXP_LNKCTL) & PCI_EXP_LNKCTL_ASPM_L1) return 0; + pmc_ver = dwc_get_devices_pmc_version(pci); + if (dw_pcie_get_ltssm(pci) > DW_PCIE_LTSSM_DETECT_ACT) { /* Only send out PME_TURN_OFF when PCIE link is up */ if (pci->pp.ops->pme_turn_off) @@ -942,7 +980,13 @@ int dw_pcie_suspend_noirq(struct dw_pcie *pci) if (ret) return ret; + } + /* + * PMC Ver2.0 device e1000e NIC hangs in LTSSM polling and L2 check. + * Only do the L2 check when PMC version is Ver3.0 or later. + */ + if (pmc_ver >= 3) { ret = read_poll_timeout(dw_pcie_get_ltssm, val, val == DW_PCIE_LTSSM_L2_IDLE, PCIE_PME_TO_L2_TIMEOUT_US/10, PCIE_PME_TO_L2_TIMEOUT_US, false, pci);
In dw_pcie_suspend_noirq() and after the PME_TURN_OFF messgage is sent out, one PMC version2.0 endpoint device E1000E network card hangs in LTSSM stat polling and L2 stat check. To avoid this hang issue after the PME_TURN_OFF message is sent out. Only poll and check LTSSM L2 stat if the EP's PMC version is 3 or later, Signed-off-by: Richard Zhu <hongxing.zhu@nxp.com> --- - Add a new help function dwc_get_devices_pmc_version() to get devices PMC versions. .../pci/controller/dwc/pcie-designware-host.c | 46 ++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-)