This patch is based on patch [1] and adopt Adrian's comment. Due to flaws in hardware design, GL9763E takes long time to exit from L1 state. The I/O performance will suffer severe impact if it often enter and exit L1 state. Unfortunately, entering and exiting L1 state is signal handshake in physical layer, software knows nothiong about it. The only way to stop entering L1 state is to disable hardware LPM negotiation on GL9763E. To improve read performance and take battery life into account, we reject L1 negotiation while executing MMC_READ_MULTIPLE_BLOCK command and enable L1 negotiation again when receiving non-MMC_READ_MULTIPLE_BLOCK command. [1] https://patchwork.kernel.org/project/linux-mmc/list/?series=645165 Signed-off-by: Renius Chen <reniuschengl@xxxxxxxxx> Signed-off-by: Jason Lai <jason.lai@xxxxxxxxxxxxxxxxxxx> --- drivers/mmc/host/sdhci-pci-gli.c | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/drivers/mmc/host/sdhci-pci-gli.c b/drivers/mmc/host/sdhci-pci-gli.c index 86200b73c0b0..13c09202da9c 100644 --- a/drivers/mmc/host/sdhci-pci-gli.c +++ b/drivers/mmc/host/sdhci-pci-gli.c @@ -850,24 +850,29 @@ static void gl9763e_set_low_power_negotiation(struct sdhci_pci_slot *slot, bool pci_write_config_dword(pdev, PCIE_GLI_9763E_VHS, value); } +static void gl9763e_set_lpm_negotiation(struct sdhci_pci_slot *slot, bool enable) +{ + struct gli_host *gli_host = sdhci_pci_priv(slot); + + if (gli_host->lpm_negotiation_enabled == enable) + return; + + gli_host->lpm_negotiation_enabled = enable; + + gl9763e_set_low_power_negotiation(slot, enable); +} + static void gl9763e_request(struct mmc_host *mmc, struct mmc_request *mrq) { struct sdhci_host *host = mmc_priv(mmc); struct mmc_command *cmd; struct sdhci_pci_slot *slot = sdhci_priv(host); - struct gli_host *gli_host = sdhci_pci_priv(slot); cmd = mrq->cmd; - - if (cmd && (cmd->opcode == MMC_READ_MULTIPLE_BLOCK) && gli_host->lpm_negotiation_enabled) { - gl9763e_set_low_power_negotiation(slot, false); - gli_host->lpm_negotiation_enabled = false; - } else { - if (gli_host->lpm_negotiation_enabled == false) { - gl9763e_set_low_power_negotiation(slot, true); - gli_host->lpm_negotiation_enabled = true; - } - } + if (cmd && (cmd->opcode == MMC_READ_MULTIPLE_BLOCK)) + gl9763e_set_lpm_negotiation(slot, false); + else + gl9763e_set_lpm_negotiation(slot, true); sdhci_request(mmc, mrq); } @@ -975,6 +980,7 @@ static void gli_set_gl9763e(struct sdhci_pci_slot *slot) { struct pci_dev *pdev = slot->chip->pdev; u32 value; + struct gli_host *gli_host = sdhci_pci_priv(slot); pci_read_config_dword(pdev, PCIE_GLI_9763E_VHS, &value); value &= ~GLI_9763E_VHS_REV; @@ -995,6 +1001,9 @@ static void gli_set_gl9763e(struct sdhci_pci_slot *slot) value |= FIELD_PREP(GLI_9763E_CFG2_L1DLY, GLI_9763E_CFG2_L1DLY_MID); pci_write_config_dword(pdev, PCIE_GLI_9763E_CFG2, value); + /* Default setting of LPM negotiation is enabled. */ + gli_host->lpm_negotiation_enabled = true; + pci_read_config_dword(pdev, PCIE_GLI_9763E_CLKRXDLY, &value); value &= ~GLI_9763E_HS400_RXDLY; value |= FIELD_PREP(GLI_9763E_HS400_RXDLY, GLI_9763E_HS400_RXDLY_5); -- 2.36.1