mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-29 13:53:33 +00:00
mmc: sdhci-pci-gli: fix LPM negotiation so x86/S0ix SoCs can suspend
commit1202d617e3
upstream. To improve the r/w performance of GL9763E, the current driver inhibits LPM negotiation while the device is active. This prevents a large number of SoCs from suspending, notably x86 systems which commonly use S0ix as the suspend mechanism - for example, Intel Alder Lake and Raptor Lake processors. Failure description: 1. Userspace initiates s2idle suspend (e.g. via writing to /sys/power/state) 2. This switches the runtime_pm device state to active, which disables LPM negotiation, then calls the "regular" suspend callback 3. With LPM negotiation disabled, the bus cannot enter low-power state 4. On a large number of SoCs, if the bus not in a low-power state, S0ix cannot be entered, which in turn prevents the SoC from entering suspend. Fix by re-enabling LPM negotiation in the device's suspend callback. Suggested-by: Stanislaw Kardach <skardach@google.com> Fixes:f9e5b33934
("mmc: host: Improve I/O read/write performance for GL9763E") Cc: stable@vger.kernel.org Signed-off-by: Sven van Ashbrook <svenva@chromium.org> Acked-by: Adrian Hunter <adrian.hunter@intel.com> Link: https://lore.kernel.org/r/20230831160055.v3.1.I7ed1ca09797be2dd76ca914c57d88b32d24dac88@changeid Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
55c2428658
commit
43f588b820
1 changed files with 66 additions and 38 deletions
|
@ -756,42 +756,6 @@ static u32 sdhci_gl9750_readl(struct sdhci_host *host, int reg)
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_PM_SLEEP
|
|
||||||
static int sdhci_pci_gli_resume(struct sdhci_pci_chip *chip)
|
|
||||||
{
|
|
||||||
struct sdhci_pci_slot *slot = chip->slots[0];
|
|
||||||
|
|
||||||
pci_free_irq_vectors(slot->chip->pdev);
|
|
||||||
gli_pcie_enable_msi(slot);
|
|
||||||
|
|
||||||
return sdhci_pci_resume_host(chip);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int sdhci_cqhci_gli_resume(struct sdhci_pci_chip *chip)
|
|
||||||
{
|
|
||||||
struct sdhci_pci_slot *slot = chip->slots[0];
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret = sdhci_pci_gli_resume(chip);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
return cqhci_resume(slot->host->mmc);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int sdhci_cqhci_gli_suspend(struct sdhci_pci_chip *chip)
|
|
||||||
{
|
|
||||||
struct sdhci_pci_slot *slot = chip->slots[0];
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret = cqhci_suspend(slot->host->mmc);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
return sdhci_suspend_host(slot->host);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static void gl9763e_hs400_enhanced_strobe(struct mmc_host *mmc,
|
static void gl9763e_hs400_enhanced_strobe(struct mmc_host *mmc,
|
||||||
struct mmc_ios *ios)
|
struct mmc_ios *ios)
|
||||||
{
|
{
|
||||||
|
@ -1040,6 +1004,70 @@ static int gl9763e_runtime_resume(struct sdhci_pci_chip *chip)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_PM_SLEEP
|
||||||
|
static int sdhci_pci_gli_resume(struct sdhci_pci_chip *chip)
|
||||||
|
{
|
||||||
|
struct sdhci_pci_slot *slot = chip->slots[0];
|
||||||
|
|
||||||
|
pci_free_irq_vectors(slot->chip->pdev);
|
||||||
|
gli_pcie_enable_msi(slot);
|
||||||
|
|
||||||
|
return sdhci_pci_resume_host(chip);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int gl9763e_resume(struct sdhci_pci_chip *chip)
|
||||||
|
{
|
||||||
|
struct sdhci_pci_slot *slot = chip->slots[0];
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = sdhci_pci_gli_resume(chip);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = cqhci_resume(slot->host->mmc);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Disable LPM negotiation to bring device back in sync
|
||||||
|
* with its runtime_pm state.
|
||||||
|
*/
|
||||||
|
gl9763e_set_low_power_negotiation(slot, false);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int gl9763e_suspend(struct sdhci_pci_chip *chip)
|
||||||
|
{
|
||||||
|
struct sdhci_pci_slot *slot = chip->slots[0];
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Certain SoCs can suspend only with the bus in low-
|
||||||
|
* power state, notably x86 SoCs when using S0ix.
|
||||||
|
* Re-enable LPM negotiation to allow entering L1 state
|
||||||
|
* and entering system suspend.
|
||||||
|
*/
|
||||||
|
gl9763e_set_low_power_negotiation(slot, true);
|
||||||
|
|
||||||
|
ret = cqhci_suspend(slot->host->mmc);
|
||||||
|
if (ret)
|
||||||
|
goto err_suspend;
|
||||||
|
|
||||||
|
ret = sdhci_suspend_host(slot->host);
|
||||||
|
if (ret)
|
||||||
|
goto err_suspend_host;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err_suspend_host:
|
||||||
|
cqhci_resume(slot->host->mmc);
|
||||||
|
err_suspend:
|
||||||
|
gl9763e_set_low_power_negotiation(slot, false);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static int gli_probe_slot_gl9763e(struct sdhci_pci_slot *slot)
|
static int gli_probe_slot_gl9763e(struct sdhci_pci_slot *slot)
|
||||||
{
|
{
|
||||||
struct pci_dev *pdev = slot->chip->pdev;
|
struct pci_dev *pdev = slot->chip->pdev;
|
||||||
|
@ -1147,8 +1175,8 @@ const struct sdhci_pci_fixes sdhci_gl9763e = {
|
||||||
.probe_slot = gli_probe_slot_gl9763e,
|
.probe_slot = gli_probe_slot_gl9763e,
|
||||||
.ops = &sdhci_gl9763e_ops,
|
.ops = &sdhci_gl9763e_ops,
|
||||||
#ifdef CONFIG_PM_SLEEP
|
#ifdef CONFIG_PM_SLEEP
|
||||||
.resume = sdhci_cqhci_gli_resume,
|
.resume = gl9763e_resume,
|
||||||
.suspend = sdhci_cqhci_gli_suspend,
|
.suspend = gl9763e_suspend,
|
||||||
#endif
|
#endif
|
||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM
|
||||||
.runtime_suspend = gl9763e_runtime_suspend,
|
.runtime_suspend = gl9763e_runtime_suspend,
|
||||||
|
|
Loading…
Reference in a new issue