On Wed, Jan 3, 2024 at 6:53 PM Ulf Hansson <ulf.hansson@xxxxxxxxxx> wrote: > > On Thu, 21 Dec 2023 at 04:23, Kai-Heng Feng <kai.heng.feng@xxxxxxxxxxxxx> wrote: > > > > Spamming `lspci -vv` can still observe the replay timer timeout error > > even after commit 015c9cbcf0ad ("mmc: sdhci-pci-gli: GL9750: Mask the > > replay timer timeout of AER"), albeit with a lower reproduce rate. > > > > Such AER interrupt can still prevent the system from suspending, so let > > root port mask and unmask replay timer timeout during suspend and > > resume, respectively. > > > > Cc: Victor Shih <victor.shih@xxxxxxxxxxxxxxxxxxx> > > Cc: Ben Chuang <benchuanggli@xxxxxxxxx> > > Signed-off-by: Kai-Heng Feng <kai.heng.feng@xxxxxxxxxxxxx> > > --- > > v2: > > - Change subject to reflect it works on GL9750 & GL9755 > > - Fix when aer_cap is missing > > > > drivers/mmc/host/sdhci-pci-core.c | 2 +- > > drivers/mmc/host/sdhci-pci-gli.c | 55 +++++++++++++++++++++++++++++-- > > drivers/mmc/host/sdhci-pci.h | 1 + > > 3 files changed, 55 insertions(+), 3 deletions(-) > > > > diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c > > index 025b31aa712c..59ae4da72974 100644 > > --- a/drivers/mmc/host/sdhci-pci-core.c > > +++ b/drivers/mmc/host/sdhci-pci-core.c > > @@ -68,7 +68,7 @@ static int sdhci_pci_init_wakeup(struct sdhci_pci_chip *chip) > > return 0; > > } > > > > -static int sdhci_pci_suspend_host(struct sdhci_pci_chip *chip) > > +int sdhci_pci_suspend_host(struct sdhci_pci_chip *chip) > > { > > int i, ret; > > > > diff --git a/drivers/mmc/host/sdhci-pci-gli.c b/drivers/mmc/host/sdhci-pci-gli.c > > index 77911a57b12c..54943e9df835 100644 > > --- a/drivers/mmc/host/sdhci-pci-gli.c > > +++ b/drivers/mmc/host/sdhci-pci-gli.c > > @@ -1429,6 +1429,55 @@ static int sdhci_pci_gli_resume(struct sdhci_pci_chip *chip) > > return sdhci_pci_resume_host(chip); > > } > > > > +#ifdef CONFIG_PCIEAER > > +static void mask_replay_timer_timeout(struct pci_dev *pdev) > > +{ > > + struct pci_dev *parent = pci_upstream_bridge(pdev); > > + u32 val; > > + > > + if (!parent || !parent->aer_cap) > > Wouldn't it be more correct to use pci_aer_available(), rather than > just checking the aer_cap? pci_aer_available() is more of a global check, so checking aer_cap is still required for the device. > > If pci_aer_available() can be used, we wouldn't even need the stubs as > the is already stubs for pci_aer_available(). A helper that checks both aer_cap and pci_aer_available() can be added for such purpose, but there aren't many users of that. Kai-Heng > > > + return; > > + > > + pci_read_config_dword(parent, parent->aer_cap + PCI_ERR_COR_MASK, &val); > > + val |= PCI_ERR_COR_REP_TIMER; > > + pci_write_config_dword(parent, parent->aer_cap + PCI_ERR_COR_MASK, val); > > +} > > + > > +static void unmask_replay_timer_timeout(struct pci_dev *pdev) > > +{ > > + struct pci_dev *parent = pci_upstream_bridge(pdev); > > + u32 val; > > + > > + if (!parent || !parent->aer_cap) > > + return; > > + > > + pci_read_config_dword(pdev, parent->aer_cap + PCI_ERR_COR_MASK, &val); > > + val &= ~PCI_ERR_COR_REP_TIMER; > > + pci_write_config_dword(pdev, parent->aer_cap + PCI_ERR_COR_MASK, val); > > +} > > +#else > > +static inline void mask_replay_timer_timeout(struct pci_dev *pdev) { } > > +static inline void unmask_replay_timer_timeout(struct pci_dev *pdev) { } > > +#endif > > + > > +static int sdhci_pci_gl975x_suspend(struct sdhci_pci_chip *chip) > > +{ > > + mask_replay_timer_timeout(chip->pdev); > > + > > + return sdhci_pci_suspend_host(chip); > > +} > > + > > +static int sdhci_pci_gl975x_resume(struct sdhci_pci_chip *chip) > > +{ > > + int ret; > > + > > + ret = sdhci_pci_gli_resume(chip); > > + > > + unmask_replay_timer_timeout(chip->pdev); > > + > > + return ret; > > +} > > + > > static int gl9763e_resume(struct sdhci_pci_chip *chip) > > { > > struct sdhci_pci_slot *slot = chip->slots[0]; > > @@ -1547,7 +1596,8 @@ const struct sdhci_pci_fixes sdhci_gl9755 = { > > .probe_slot = gli_probe_slot_gl9755, > > .ops = &sdhci_gl9755_ops, > > #ifdef CONFIG_PM_SLEEP > > - .resume = sdhci_pci_gli_resume, > > + .suspend = sdhci_pci_gl975x_suspend, > > + .resume = sdhci_pci_gl975x_resume, > > #endif > > }; > > > > @@ -1570,7 +1620,8 @@ const struct sdhci_pci_fixes sdhci_gl9750 = { > > .probe_slot = gli_probe_slot_gl9750, > > .ops = &sdhci_gl9750_ops, > > #ifdef CONFIG_PM_SLEEP > > - .resume = sdhci_pci_gli_resume, > > + .suspend = sdhci_pci_gl975x_suspend, > > + .resume = sdhci_pci_gl975x_resume, > > #endif > > }; > > > > diff --git a/drivers/mmc/host/sdhci-pci.h b/drivers/mmc/host/sdhci-pci.h > > index 153704f812ed..19253dce687d 100644 > > --- a/drivers/mmc/host/sdhci-pci.h > > +++ b/drivers/mmc/host/sdhci-pci.h > > @@ -190,6 +190,7 @@ static inline void *sdhci_pci_priv(struct sdhci_pci_slot *slot) > > } > > > > #ifdef CONFIG_PM_SLEEP > > +int sdhci_pci_suspend_host(struct sdhci_pci_chip *chip); > > int sdhci_pci_resume_host(struct sdhci_pci_chip *chip); > > #endif > > int sdhci_pci_enable_dma(struct sdhci_host *host); > > Kind regards > Uffe