OSDN Git Service

mmc: host: Improve I/O read/write performance for GL9763E
authorJason Lai <jasonlai.genesyslogic@gmail.com>
Mon, 13 Jun 2022 09:29:07 +0000 (17:29 +0800)
committerUlf Hansson <ulf.hansson@linaro.org>
Tue, 12 Jul 2022 10:25:38 +0000 (12:25 +0200)
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 during I/O requests.

To improve I/O read/write performance and take battery life into account,
let's turn on GL9763E L1 negotiation before entering runtime suspend and
turn off GL9763E L1 negotiation while executing runtime resume. That is to
say, GL9763E will not enter L1 state when executing I/O requests and enter
L1 state when PCIe bus idle.

Signed-off-by: Renius Chen <reniuschengl@gmail.com>
Signed-off-by: Jason Lai <jason.lai@genesyslogic.com.tw>
Link: https://lore.kernel.org/r/20220613092907.2502-1-jason.lai@genesyslogic.com.tw
[Ulf: Improved the commit message a bit]
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
drivers/mmc/host/sdhci-pci-gli.c

index f13c08d..a76506a 100644 (file)
@@ -95,6 +95,9 @@
 #define PCIE_GLI_9763E_SCR      0x8E0
 #define   GLI_9763E_SCR_AXI_REQ           BIT(9)
 
+#define PCIE_GLI_9763E_CFG       0x8A0
+#define   GLI_9763E_CFG_LPSN_DIS   BIT(12)
+
 #define PCIE_GLI_9763E_CFG2      0x8A4
 #define   GLI_9763E_CFG2_L1DLY     GENMASK(28, 19)
 #define   GLI_9763E_CFG2_L1DLY_MID 0x54
@@ -828,6 +831,31 @@ static void sdhci_gl9763e_dumpregs(struct mmc_host *mmc)
        sdhci_dumpregs(mmc_priv(mmc));
 }
 
+static void gl9763e_set_low_power_negotiation(struct sdhci_pci_slot *slot, bool enable)
+{
+       struct pci_dev *pdev = slot->chip->pdev;
+       u32 value;
+
+       pci_read_config_dword(pdev, PCIE_GLI_9763E_VHS, &value);
+       value &= ~GLI_9763E_VHS_REV;
+       value |= FIELD_PREP(GLI_9763E_VHS_REV, GLI_9763E_VHS_REV_W);
+       pci_write_config_dword(pdev, PCIE_GLI_9763E_VHS, value);
+
+       pci_read_config_dword(pdev, PCIE_GLI_9763E_CFG, &value);
+
+       if (enable)
+               value &= ~GLI_9763E_CFG_LPSN_DIS;
+       else
+               value |= GLI_9763E_CFG_LPSN_DIS;
+
+       pci_write_config_dword(pdev, PCIE_GLI_9763E_CFG, value);
+
+       pci_read_config_dword(pdev, PCIE_GLI_9763E_VHS, &value);
+       value &= ~GLI_9763E_VHS_REV;
+       value |= FIELD_PREP(GLI_9763E_VHS_REV, GLI_9763E_VHS_REV_R);
+       pci_write_config_dword(pdev, PCIE_GLI_9763E_VHS, value);
+}
+
 static void sdhci_gl9763e_cqe_pre_enable(struct mmc_host *mmc)
 {
        struct cqhci_host *cq_host = mmc->cqe_private;
@@ -969,6 +997,9 @@ static int gl9763e_runtime_suspend(struct sdhci_pci_chip *chip)
        struct sdhci_host *host = slot->host;
        u16 clock;
 
+       /* Enable LPM negotiation to allow entering L1 state */
+       gl9763e_set_low_power_negotiation(slot, true);
+
        clock = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
        clock &= ~(SDHCI_CLOCK_PLL_EN | SDHCI_CLOCK_CARD_EN);
        sdhci_writew(host, clock, SDHCI_CLOCK_CONTROL);
@@ -1002,6 +1033,9 @@ static int gl9763e_runtime_resume(struct sdhci_pci_chip *chip)
        clock |= SDHCI_CLOCK_CARD_EN;
        sdhci_writew(host, clock, SDHCI_CLOCK_CONTROL);
 
+       /* Disable LPM negotiation to avoid entering L1 state. */
+       gl9763e_set_low_power_negotiation(slot, false);
+
        return 0;
 }
 #endif