Skip to content

Commit 1202d61

Browse files
Sven van Ashbrookstorulf
authored andcommitted
mmc: sdhci-pci-gli: fix LPM negotiation so x86/S0ix SoCs can suspend
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 <[email protected]> Fixes: f9e5b33 ("mmc: host: Improve I/O read/write performance for GL9763E") Cc: [email protected] Signed-off-by: Sven van Ashbrook <[email protected]> Acked-by: Adrian Hunter <[email protected]> Link: https://lore.kernel.org/r/20230831160055.v3.1.I7ed1ca09797be2dd76ca914c57d88b32d24dac88@changeid Signed-off-by: Ulf Hansson <[email protected]>
1 parent 32a9cdb commit 1202d61

File tree

1 file changed

+66
-38
lines changed

1 file changed

+66
-38
lines changed

drivers/mmc/host/sdhci-pci-gli.c

Lines changed: 66 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1144,42 +1144,6 @@ static u32 sdhci_gl9750_readl(struct sdhci_host *host, int reg)
11441144
return value;
11451145
}
11461146

1147-
#ifdef CONFIG_PM_SLEEP
1148-
static int sdhci_pci_gli_resume(struct sdhci_pci_chip *chip)
1149-
{
1150-
struct sdhci_pci_slot *slot = chip->slots[0];
1151-
1152-
pci_free_irq_vectors(slot->chip->pdev);
1153-
gli_pcie_enable_msi(slot);
1154-
1155-
return sdhci_pci_resume_host(chip);
1156-
}
1157-
1158-
static int sdhci_cqhci_gli_resume(struct sdhci_pci_chip *chip)
1159-
{
1160-
struct sdhci_pci_slot *slot = chip->slots[0];
1161-
int ret;
1162-
1163-
ret = sdhci_pci_gli_resume(chip);
1164-
if (ret)
1165-
return ret;
1166-
1167-
return cqhci_resume(slot->host->mmc);
1168-
}
1169-
1170-
static int sdhci_cqhci_gli_suspend(struct sdhci_pci_chip *chip)
1171-
{
1172-
struct sdhci_pci_slot *slot = chip->slots[0];
1173-
int ret;
1174-
1175-
ret = cqhci_suspend(slot->host->mmc);
1176-
if (ret)
1177-
return ret;
1178-
1179-
return sdhci_suspend_host(slot->host);
1180-
}
1181-
#endif
1182-
11831147
static void gl9763e_hs400_enhanced_strobe(struct mmc_host *mmc,
11841148
struct mmc_ios *ios)
11851149
{
@@ -1420,6 +1384,70 @@ static int gl9763e_runtime_resume(struct sdhci_pci_chip *chip)
14201384
}
14211385
#endif
14221386

1387+
#ifdef CONFIG_PM_SLEEP
1388+
static int sdhci_pci_gli_resume(struct sdhci_pci_chip *chip)
1389+
{
1390+
struct sdhci_pci_slot *slot = chip->slots[0];
1391+
1392+
pci_free_irq_vectors(slot->chip->pdev);
1393+
gli_pcie_enable_msi(slot);
1394+
1395+
return sdhci_pci_resume_host(chip);
1396+
}
1397+
1398+
static int gl9763e_resume(struct sdhci_pci_chip *chip)
1399+
{
1400+
struct sdhci_pci_slot *slot = chip->slots[0];
1401+
int ret;
1402+
1403+
ret = sdhci_pci_gli_resume(chip);
1404+
if (ret)
1405+
return ret;
1406+
1407+
ret = cqhci_resume(slot->host->mmc);
1408+
if (ret)
1409+
return ret;
1410+
1411+
/*
1412+
* Disable LPM negotiation to bring device back in sync
1413+
* with its runtime_pm state.
1414+
*/
1415+
gl9763e_set_low_power_negotiation(slot, false);
1416+
1417+
return 0;
1418+
}
1419+
1420+
static int gl9763e_suspend(struct sdhci_pci_chip *chip)
1421+
{
1422+
struct sdhci_pci_slot *slot = chip->slots[0];
1423+
int ret;
1424+
1425+
/*
1426+
* Certain SoCs can suspend only with the bus in low-
1427+
* power state, notably x86 SoCs when using S0ix.
1428+
* Re-enable LPM negotiation to allow entering L1 state
1429+
* and entering system suspend.
1430+
*/
1431+
gl9763e_set_low_power_negotiation(slot, true);
1432+
1433+
ret = cqhci_suspend(slot->host->mmc);
1434+
if (ret)
1435+
goto err_suspend;
1436+
1437+
ret = sdhci_suspend_host(slot->host);
1438+
if (ret)
1439+
goto err_suspend_host;
1440+
1441+
return 0;
1442+
1443+
err_suspend_host:
1444+
cqhci_resume(slot->host->mmc);
1445+
err_suspend:
1446+
gl9763e_set_low_power_negotiation(slot, false);
1447+
return ret;
1448+
}
1449+
#endif
1450+
14231451
static int gli_probe_slot_gl9763e(struct sdhci_pci_slot *slot)
14241452
{
14251453
struct pci_dev *pdev = slot->chip->pdev;
@@ -1527,8 +1555,8 @@ const struct sdhci_pci_fixes sdhci_gl9763e = {
15271555
.probe_slot = gli_probe_slot_gl9763e,
15281556
.ops = &sdhci_gl9763e_ops,
15291557
#ifdef CONFIG_PM_SLEEP
1530-
.resume = sdhci_cqhci_gli_resume,
1531-
.suspend = sdhci_cqhci_gli_suspend,
1558+
.resume = gl9763e_resume,
1559+
.suspend = gl9763e_suspend,
15321560
#endif
15331561
#ifdef CONFIG_PM
15341562
.runtime_suspend = gl9763e_runtime_suspend,

0 commit comments

Comments
 (0)