[V2] mmc: sdhci-pci: Fix BYT OCP setting
diff mbox series

Message ID 20190506083853.12741-1-adrian.hunter@intel.com
State New
Headers show
Series
  • [V2] mmc: sdhci-pci: Fix BYT OCP setting
Related show

Commit Message

Adrian Hunter May 6, 2019, 8:38 a.m. UTC
Some time ago, a fix was done for the sdhci-acpi driver, refer
commit 6e1c7d6103fe ("mmc: sdhci-acpi: Reduce Baytrail eMMC/SD/SDIO
hangs"). The same issue was not expected to affect the sdhci-pci driver,
but there have been reports to the contrary, so make the same hardware
setting change.

This patch applies to v5.0+ but before that backports will be required.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Cc: stable@vger.kernel.org
---



Changes in V2:
	Get rid of macros BYT_PM_OPS, BYT_SPM_OPS and BYT_RPM_OPS
	Add fix pm ops also to sdhci_intel_byt_emmc



 drivers/mmc/host/Kconfig          |  1 +
 drivers/mmc/host/sdhci-pci-core.c | 96 +++++++++++++++++++++++++++++++
 2 files changed, 97 insertions(+)

Comments

Ulf Hansson May 6, 2019, 9:51 a.m. UTC | #1
On Mon, 6 May 2019 at 10:39, Adrian Hunter <adrian.hunter@intel.com> wrote:
>
> Some time ago, a fix was done for the sdhci-acpi driver, refer
> commit 6e1c7d6103fe ("mmc: sdhci-acpi: Reduce Baytrail eMMC/SD/SDIO
> hangs"). The same issue was not expected to affect the sdhci-pci driver,
> but there have been reports to the contrary, so make the same hardware
> setting change.
>
> This patch applies to v5.0+ but before that backports will be required.
>
> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
> Cc: stable@vger.kernel.org

Applied for next, thanks!

Kind regards
Uffe


> ---
>
>
>
> Changes in V2:
>         Get rid of macros BYT_PM_OPS, BYT_SPM_OPS and BYT_RPM_OPS
>         Add fix pm ops also to sdhci_intel_byt_emmc
>
>
>
>  drivers/mmc/host/Kconfig          |  1 +
>  drivers/mmc/host/sdhci-pci-core.c | 96 +++++++++++++++++++++++++++++++
>  2 files changed, 97 insertions(+)
>
> diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
> index 9c01310a0d2e..d084a9d63623 100644
> --- a/drivers/mmc/host/Kconfig
> +++ b/drivers/mmc/host/Kconfig
> @@ -92,6 +92,7 @@ config MMC_SDHCI_PCI
>         tristate "SDHCI support on PCI bus"
>         depends on MMC_SDHCI && PCI
>         select MMC_CQHCI
> +       select IOSF_MBI if X86
>         help
>           This selects the PCI Secure Digital Host Controller Interface.
>           Most controllers found today are PCI devices.
> diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c
> index a3d7a9db76c5..ab9e2b901094 100644
> --- a/drivers/mmc/host/sdhci-pci-core.c
> +++ b/drivers/mmc/host/sdhci-pci-core.c
> @@ -31,6 +31,10 @@
>  #include <linux/mmc/sdhci-pci-data.h>
>  #include <linux/acpi.h>
>
> +#ifdef CONFIG_X86
> +#include <asm/iosf_mbi.h>
> +#endif
> +
>  #include "cqhci.h"
>
>  #include "sdhci.h"
> @@ -451,6 +455,50 @@ static const struct sdhci_pci_fixes sdhci_intel_pch_sdio = {
>         .probe_slot     = pch_hc_probe_slot,
>  };
>
> +#ifdef CONFIG_X86
> +
> +#define BYT_IOSF_SCCEP                 0x63
> +#define BYT_IOSF_OCP_NETCTRL0          0x1078
> +#define BYT_IOSF_OCP_TIMEOUT_BASE      GENMASK(10, 8)
> +
> +static void byt_ocp_setting(struct pci_dev *pdev)
> +{
> +       u32 val = 0;
> +
> +       if (pdev->device != PCI_DEVICE_ID_INTEL_BYT_EMMC &&
> +           pdev->device != PCI_DEVICE_ID_INTEL_BYT_SDIO &&
> +           pdev->device != PCI_DEVICE_ID_INTEL_BYT_SD &&
> +           pdev->device != PCI_DEVICE_ID_INTEL_BYT_EMMC2)
> +               return;
> +
> +       if (iosf_mbi_read(BYT_IOSF_SCCEP, MBI_CR_READ, BYT_IOSF_OCP_NETCTRL0,
> +                         &val)) {
> +               dev_err(&pdev->dev, "%s read error\n", __func__);
> +               return;
> +       }
> +
> +       if (!(val & BYT_IOSF_OCP_TIMEOUT_BASE))
> +               return;
> +
> +       val &= ~BYT_IOSF_OCP_TIMEOUT_BASE;
> +
> +       if (iosf_mbi_write(BYT_IOSF_SCCEP, MBI_CR_WRITE, BYT_IOSF_OCP_NETCTRL0,
> +                          val)) {
> +               dev_err(&pdev->dev, "%s write error\n", __func__);
> +               return;
> +       }
> +
> +       dev_dbg(&pdev->dev, "%s completed\n", __func__);
> +}
> +
> +#else
> +
> +static inline void byt_ocp_setting(struct pci_dev *pdev)
> +{
> +}
> +
> +#endif
> +
>  enum {
>         INTEL_DSM_FNS           =  0,
>         INTEL_DSM_V18_SWITCH    =  3,
> @@ -715,6 +763,8 @@ static void byt_probe_slot(struct sdhci_pci_slot *slot)
>
>         byt_read_dsm(slot);
>
> +       byt_ocp_setting(slot->chip->pdev);
> +
>         ops->execute_tuning = intel_execute_tuning;
>         ops->start_signal_voltage_switch = intel_start_signal_voltage_switch;
>
> @@ -938,7 +988,35 @@ static int byt_sd_probe_slot(struct sdhci_pci_slot *slot)
>         return 0;
>  }
>
> +#ifdef CONFIG_PM_SLEEP
> +
> +static int byt_resume(struct sdhci_pci_chip *chip)
> +{
> +       byt_ocp_setting(chip->pdev);
> +
> +       return sdhci_pci_resume_host(chip);
> +}
> +
> +#endif
> +
> +#ifdef CONFIG_PM
> +
> +static int byt_runtime_resume(struct sdhci_pci_chip *chip)
> +{
> +       byt_ocp_setting(chip->pdev);
> +
> +       return sdhci_pci_runtime_resume_host(chip);
> +}
> +
> +#endif
> +
>  static const struct sdhci_pci_fixes sdhci_intel_byt_emmc = {
> +#ifdef CONFIG_PM_SLEEP
> +       .resume         = byt_resume,
> +#endif
> +#ifdef CONFIG_PM
> +       .runtime_resume = byt_runtime_resume,
> +#endif
>         .allow_runtime_pm = true,
>         .probe_slot     = byt_emmc_probe_slot,
>         .quirks         = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC |
> @@ -972,6 +1050,12 @@ static const struct sdhci_pci_fixes sdhci_intel_glk_emmc = {
>  };
>
>  static const struct sdhci_pci_fixes sdhci_ni_byt_sdio = {
> +#ifdef CONFIG_PM_SLEEP
> +       .resume         = byt_resume,
> +#endif
> +#ifdef CONFIG_PM
> +       .runtime_resume = byt_runtime_resume,
> +#endif
>         .quirks         = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC |
>                           SDHCI_QUIRK_NO_LED,
>         .quirks2        = SDHCI_QUIRK2_HOST_OFF_CARD_ON |
> @@ -983,6 +1067,12 @@ static const struct sdhci_pci_fixes sdhci_ni_byt_sdio = {
>  };
>
>  static const struct sdhci_pci_fixes sdhci_intel_byt_sdio = {
> +#ifdef CONFIG_PM_SLEEP
> +       .resume         = byt_resume,
> +#endif
> +#ifdef CONFIG_PM
> +       .runtime_resume = byt_runtime_resume,
> +#endif
>         .quirks         = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC |
>                           SDHCI_QUIRK_NO_LED,
>         .quirks2        = SDHCI_QUIRK2_HOST_OFF_CARD_ON |
> @@ -994,6 +1084,12 @@ static const struct sdhci_pci_fixes sdhci_intel_byt_sdio = {
>  };
>
>  static const struct sdhci_pci_fixes sdhci_intel_byt_sd = {
> +#ifdef CONFIG_PM_SLEEP
> +       .resume         = byt_resume,
> +#endif
> +#ifdef CONFIG_PM
> +       .runtime_resume = byt_runtime_resume,
> +#endif
>         .quirks         = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC |
>                           SDHCI_QUIRK_NO_LED,
>         .quirks2        = SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON |
> --
> 2.17.1
>

Patch
diff mbox series

diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 9c01310a0d2e..d084a9d63623 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -92,6 +92,7 @@  config MMC_SDHCI_PCI
 	tristate "SDHCI support on PCI bus"
 	depends on MMC_SDHCI && PCI
 	select MMC_CQHCI
+	select IOSF_MBI if X86
 	help
 	  This selects the PCI Secure Digital Host Controller Interface.
 	  Most controllers found today are PCI devices.
diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c
index a3d7a9db76c5..ab9e2b901094 100644
--- a/drivers/mmc/host/sdhci-pci-core.c
+++ b/drivers/mmc/host/sdhci-pci-core.c
@@ -31,6 +31,10 @@ 
 #include <linux/mmc/sdhci-pci-data.h>
 #include <linux/acpi.h>
 
+#ifdef CONFIG_X86
+#include <asm/iosf_mbi.h>
+#endif
+
 #include "cqhci.h"
 
 #include "sdhci.h"
@@ -451,6 +455,50 @@  static const struct sdhci_pci_fixes sdhci_intel_pch_sdio = {
 	.probe_slot	= pch_hc_probe_slot,
 };
 
+#ifdef CONFIG_X86
+
+#define BYT_IOSF_SCCEP			0x63
+#define BYT_IOSF_OCP_NETCTRL0		0x1078
+#define BYT_IOSF_OCP_TIMEOUT_BASE	GENMASK(10, 8)
+
+static void byt_ocp_setting(struct pci_dev *pdev)
+{
+	u32 val = 0;
+
+	if (pdev->device != PCI_DEVICE_ID_INTEL_BYT_EMMC &&
+	    pdev->device != PCI_DEVICE_ID_INTEL_BYT_SDIO &&
+	    pdev->device != PCI_DEVICE_ID_INTEL_BYT_SD &&
+	    pdev->device != PCI_DEVICE_ID_INTEL_BYT_EMMC2)
+		return;
+
+	if (iosf_mbi_read(BYT_IOSF_SCCEP, MBI_CR_READ, BYT_IOSF_OCP_NETCTRL0,
+			  &val)) {
+		dev_err(&pdev->dev, "%s read error\n", __func__);
+		return;
+	}
+
+	if (!(val & BYT_IOSF_OCP_TIMEOUT_BASE))
+		return;
+
+	val &= ~BYT_IOSF_OCP_TIMEOUT_BASE;
+
+	if (iosf_mbi_write(BYT_IOSF_SCCEP, MBI_CR_WRITE, BYT_IOSF_OCP_NETCTRL0,
+			   val)) {
+		dev_err(&pdev->dev, "%s write error\n", __func__);
+		return;
+	}
+
+	dev_dbg(&pdev->dev, "%s completed\n", __func__);
+}
+
+#else
+
+static inline void byt_ocp_setting(struct pci_dev *pdev)
+{
+}
+
+#endif
+
 enum {
 	INTEL_DSM_FNS		=  0,
 	INTEL_DSM_V18_SWITCH	=  3,
@@ -715,6 +763,8 @@  static void byt_probe_slot(struct sdhci_pci_slot *slot)
 
 	byt_read_dsm(slot);
 
+	byt_ocp_setting(slot->chip->pdev);
+
 	ops->execute_tuning = intel_execute_tuning;
 	ops->start_signal_voltage_switch = intel_start_signal_voltage_switch;
 
@@ -938,7 +988,35 @@  static int byt_sd_probe_slot(struct sdhci_pci_slot *slot)
 	return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+
+static int byt_resume(struct sdhci_pci_chip *chip)
+{
+	byt_ocp_setting(chip->pdev);
+
+	return sdhci_pci_resume_host(chip);
+}
+
+#endif
+
+#ifdef CONFIG_PM
+
+static int byt_runtime_resume(struct sdhci_pci_chip *chip)
+{
+	byt_ocp_setting(chip->pdev);
+
+	return sdhci_pci_runtime_resume_host(chip);
+}
+
+#endif
+
 static const struct sdhci_pci_fixes sdhci_intel_byt_emmc = {
+#ifdef CONFIG_PM_SLEEP
+	.resume		= byt_resume,
+#endif
+#ifdef CONFIG_PM
+	.runtime_resume	= byt_runtime_resume,
+#endif
 	.allow_runtime_pm = true,
 	.probe_slot	= byt_emmc_probe_slot,
 	.quirks		= SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC |
@@ -972,6 +1050,12 @@  static const struct sdhci_pci_fixes sdhci_intel_glk_emmc = {
 };
 
 static const struct sdhci_pci_fixes sdhci_ni_byt_sdio = {
+#ifdef CONFIG_PM_SLEEP
+	.resume		= byt_resume,
+#endif
+#ifdef CONFIG_PM
+	.runtime_resume	= byt_runtime_resume,
+#endif
 	.quirks		= SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC |
 			  SDHCI_QUIRK_NO_LED,
 	.quirks2	= SDHCI_QUIRK2_HOST_OFF_CARD_ON |
@@ -983,6 +1067,12 @@  static const struct sdhci_pci_fixes sdhci_ni_byt_sdio = {
 };
 
 static const struct sdhci_pci_fixes sdhci_intel_byt_sdio = {
+#ifdef CONFIG_PM_SLEEP
+	.resume		= byt_resume,
+#endif
+#ifdef CONFIG_PM
+	.runtime_resume	= byt_runtime_resume,
+#endif
 	.quirks		= SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC |
 			  SDHCI_QUIRK_NO_LED,
 	.quirks2	= SDHCI_QUIRK2_HOST_OFF_CARD_ON |
@@ -994,6 +1084,12 @@  static const struct sdhci_pci_fixes sdhci_intel_byt_sdio = {
 };
 
 static const struct sdhci_pci_fixes sdhci_intel_byt_sd = {
+#ifdef CONFIG_PM_SLEEP
+	.resume		= byt_resume,
+#endif
+#ifdef CONFIG_PM
+	.runtime_resume	= byt_runtime_resume,
+#endif
 	.quirks		= SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC |
 			  SDHCI_QUIRK_NO_LED,
 	.quirks2	= SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON |