diff mbox series

[2/2] sdhci: acpi: add qcom sdhci host reset quirk fix

Message ID 1534394923-2697-2-git-send-email-dongsheng.wang@hxt-semitech.com (mailing list archive)
State Accepted
Headers show
Series [1/2] sdhci: acpi: add free_slot callback | expand

Commit Message

Wang, Dongsheng Aug. 16, 2018, 4:48 a.m. UTC
After host requests RESET_FOR_ALL action, the hardware output an
interrupt for OS and waiting for the OS to approve.

Before writing this fix, ACPI GED has handled the interrupt. But
the ACPI GED belongs to a slow process, and sometimes the handling
process time is more than 100ms(Mutex wait more than 100ms). So
drop the GED solution and add this quirk fix.

Signed-off-by: Wang Dongsheng <dongsheng.wang@hxt-semitech.com>
---
 drivers/mmc/host/sdhci-acpi.c | 60 +++++++++++++++++++++++++++++++++++
 1 file changed, 60 insertions(+)

Comments

Adrian Hunter Aug. 27, 2018, 8:04 a.m. UTC | #1
On 16/08/18 07:48, Wang Dongsheng wrote:
> After host requests RESET_FOR_ALL action, the hardware output an
> interrupt for OS and waiting for the OS to approve.
> 
> Before writing this fix, ACPI GED has handled the interrupt. But
> the ACPI GED belongs to a slow process, and sometimes the handling
> process time is more than 100ms(Mutex wait more than 100ms). So
> drop the GED solution and add this quirk fix.
> 
> Signed-off-by: Wang Dongsheng <dongsheng.wang@hxt-semitech.com>

Acked-by: Adrian Hunter <adrian.hunter@intel.com>

> ---
>  drivers/mmc/host/sdhci-acpi.c | 60 +++++++++++++++++++++++++++++++++++
>  1 file changed, 60 insertions(+)
> 
> diff --git a/drivers/mmc/host/sdhci-acpi.c b/drivers/mmc/host/sdhci-acpi.c
> index c61109f7b793..82c9b9326e9e 100644
> --- a/drivers/mmc/host/sdhci-acpi.c
> +++ b/drivers/mmc/host/sdhci-acpi.c
> @@ -471,10 +471,70 @@ static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sd = {
>  	.priv_size	= sizeof(struct intel_host),
>  };
>  
> +#define VENDOR_SPECIFIC_PWRCTL_CLEAR_REG	0x1a8
> +#define VENDOR_SPECIFIC_PWRCTL_CTL_REG		0x1ac
> +static irqreturn_t sdhci_acpi_qcom_handler(int irq, void *ptr)
> +{
> +	struct sdhci_host *host = ptr;
> +
> +	sdhci_writel(host, 0x3, VENDOR_SPECIFIC_PWRCTL_CLEAR_REG);
> +	sdhci_writel(host, 0x1, VENDOR_SPECIFIC_PWRCTL_CTL_REG);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static int qcom_probe_slot(struct platform_device *pdev, const char *hid,
> +			   const char *uid)
> +{
> +	struct sdhci_acpi_host *c = platform_get_drvdata(pdev);
> +	struct sdhci_host *host = c->host;
> +	int *irq = sdhci_acpi_priv(c);
> +
> +	*irq = -EINVAL;
> +
> +	if (strcmp(hid, "QCOM8051"))
> +		return 0;
> +
> +	*irq = platform_get_irq(pdev, 1);
> +	if (*irq < 0)
> +		return 0;
> +
> +	return request_threaded_irq(*irq, NULL, sdhci_acpi_qcom_handler,
> +				    IRQF_ONESHOT | IRQF_TRIGGER_HIGH,
> +				    "sdhci_qcom", host);
> +}
> +
> +static int qcom_free_slot(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct sdhci_acpi_host *c = platform_get_drvdata(pdev);
> +	struct sdhci_host *host = c->host;
> +	struct acpi_device *adev;
> +	int *irq = sdhci_acpi_priv(c);
> +	const char *hid;
> +
> +	adev = ACPI_COMPANION(dev);
> +	if (!adev)
> +		return -ENODEV;
> +
> +	hid = acpi_device_hid(adev);
> +	if (strcmp(hid, "QCOM8051"))
> +		return 0;
> +
> +	if (*irq < 0)
> +		return 0;
> +
> +	free_irq(*irq, host);
> +	return 0;
> +}
> +
>  static const struct sdhci_acpi_slot sdhci_acpi_slot_qcom_sd_3v = {
>  	.quirks  = SDHCI_QUIRK_BROKEN_CARD_DETECTION,
>  	.quirks2 = SDHCI_QUIRK2_NO_1_8_V,
>  	.caps    = MMC_CAP_NONREMOVABLE,
> +	.priv_size	= sizeof(int),
> +	.probe_slot	= qcom_probe_slot,
> +	.free_slot	= qcom_free_slot,
>  };
>  
>  static const struct sdhci_acpi_slot sdhci_acpi_slot_qcom_sd = {
>
Ulf Hansson Aug. 27, 2018, 10:07 a.m. UTC | #2
On 16 August 2018 at 06:48, Wang Dongsheng
<dongsheng.wang@hxt-semitech.com> wrote:
> After host requests RESET_FOR_ALL action, the hardware output an
> interrupt for OS and waiting for the OS to approve.
>
> Before writing this fix, ACPI GED has handled the interrupt. But
> the ACPI GED belongs to a slow process, and sometimes the handling
> process time is more than 100ms(Mutex wait more than 100ms). So
> drop the GED solution and add this quirk fix.
>
> Signed-off-by: Wang Dongsheng <dongsheng.wang@hxt-semitech.com>

Thanks, applied for next!

Kind regards
Uffe

> ---
>  drivers/mmc/host/sdhci-acpi.c | 60 +++++++++++++++++++++++++++++++++++
>  1 file changed, 60 insertions(+)
>
> diff --git a/drivers/mmc/host/sdhci-acpi.c b/drivers/mmc/host/sdhci-acpi.c
> index c61109f7b793..82c9b9326e9e 100644
> --- a/drivers/mmc/host/sdhci-acpi.c
> +++ b/drivers/mmc/host/sdhci-acpi.c
> @@ -471,10 +471,70 @@ static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sd = {
>         .priv_size      = sizeof(struct intel_host),
>  };
>
> +#define VENDOR_SPECIFIC_PWRCTL_CLEAR_REG       0x1a8
> +#define VENDOR_SPECIFIC_PWRCTL_CTL_REG         0x1ac
> +static irqreturn_t sdhci_acpi_qcom_handler(int irq, void *ptr)
> +{
> +       struct sdhci_host *host = ptr;
> +
> +       sdhci_writel(host, 0x3, VENDOR_SPECIFIC_PWRCTL_CLEAR_REG);
> +       sdhci_writel(host, 0x1, VENDOR_SPECIFIC_PWRCTL_CTL_REG);
> +
> +       return IRQ_HANDLED;
> +}
> +
> +static int qcom_probe_slot(struct platform_device *pdev, const char *hid,
> +                          const char *uid)
> +{
> +       struct sdhci_acpi_host *c = platform_get_drvdata(pdev);
> +       struct sdhci_host *host = c->host;
> +       int *irq = sdhci_acpi_priv(c);
> +
> +       *irq = -EINVAL;
> +
> +       if (strcmp(hid, "QCOM8051"))
> +               return 0;
> +
> +       *irq = platform_get_irq(pdev, 1);
> +       if (*irq < 0)
> +               return 0;
> +
> +       return request_threaded_irq(*irq, NULL, sdhci_acpi_qcom_handler,
> +                                   IRQF_ONESHOT | IRQF_TRIGGER_HIGH,
> +                                   "sdhci_qcom", host);
> +}
> +
> +static int qcom_free_slot(struct platform_device *pdev)
> +{
> +       struct device *dev = &pdev->dev;
> +       struct sdhci_acpi_host *c = platform_get_drvdata(pdev);
> +       struct sdhci_host *host = c->host;
> +       struct acpi_device *adev;
> +       int *irq = sdhci_acpi_priv(c);
> +       const char *hid;
> +
> +       adev = ACPI_COMPANION(dev);
> +       if (!adev)
> +               return -ENODEV;
> +
> +       hid = acpi_device_hid(adev);
> +       if (strcmp(hid, "QCOM8051"))
> +               return 0;
> +
> +       if (*irq < 0)
> +               return 0;
> +
> +       free_irq(*irq, host);
> +       return 0;
> +}
> +
>  static const struct sdhci_acpi_slot sdhci_acpi_slot_qcom_sd_3v = {
>         .quirks  = SDHCI_QUIRK_BROKEN_CARD_DETECTION,
>         .quirks2 = SDHCI_QUIRK2_NO_1_8_V,
>         .caps    = MMC_CAP_NONREMOVABLE,
> +       .priv_size      = sizeof(int),
> +       .probe_slot     = qcom_probe_slot,
> +       .free_slot      = qcom_free_slot,
>  };
>
>  static const struct sdhci_acpi_slot sdhci_acpi_slot_qcom_sd = {
> --
> 2.18.0
>
diff mbox series

Patch

diff --git a/drivers/mmc/host/sdhci-acpi.c b/drivers/mmc/host/sdhci-acpi.c
index c61109f7b793..82c9b9326e9e 100644
--- a/drivers/mmc/host/sdhci-acpi.c
+++ b/drivers/mmc/host/sdhci-acpi.c
@@ -471,10 +471,70 @@  static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sd = {
 	.priv_size	= sizeof(struct intel_host),
 };
 
+#define VENDOR_SPECIFIC_PWRCTL_CLEAR_REG	0x1a8
+#define VENDOR_SPECIFIC_PWRCTL_CTL_REG		0x1ac
+static irqreturn_t sdhci_acpi_qcom_handler(int irq, void *ptr)
+{
+	struct sdhci_host *host = ptr;
+
+	sdhci_writel(host, 0x3, VENDOR_SPECIFIC_PWRCTL_CLEAR_REG);
+	sdhci_writel(host, 0x1, VENDOR_SPECIFIC_PWRCTL_CTL_REG);
+
+	return IRQ_HANDLED;
+}
+
+static int qcom_probe_slot(struct platform_device *pdev, const char *hid,
+			   const char *uid)
+{
+	struct sdhci_acpi_host *c = platform_get_drvdata(pdev);
+	struct sdhci_host *host = c->host;
+	int *irq = sdhci_acpi_priv(c);
+
+	*irq = -EINVAL;
+
+	if (strcmp(hid, "QCOM8051"))
+		return 0;
+
+	*irq = platform_get_irq(pdev, 1);
+	if (*irq < 0)
+		return 0;
+
+	return request_threaded_irq(*irq, NULL, sdhci_acpi_qcom_handler,
+				    IRQF_ONESHOT | IRQF_TRIGGER_HIGH,
+				    "sdhci_qcom", host);
+}
+
+static int qcom_free_slot(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct sdhci_acpi_host *c = platform_get_drvdata(pdev);
+	struct sdhci_host *host = c->host;
+	struct acpi_device *adev;
+	int *irq = sdhci_acpi_priv(c);
+	const char *hid;
+
+	adev = ACPI_COMPANION(dev);
+	if (!adev)
+		return -ENODEV;
+
+	hid = acpi_device_hid(adev);
+	if (strcmp(hid, "QCOM8051"))
+		return 0;
+
+	if (*irq < 0)
+		return 0;
+
+	free_irq(*irq, host);
+	return 0;
+}
+
 static const struct sdhci_acpi_slot sdhci_acpi_slot_qcom_sd_3v = {
 	.quirks  = SDHCI_QUIRK_BROKEN_CARD_DETECTION,
 	.quirks2 = SDHCI_QUIRK2_NO_1_8_V,
 	.caps    = MMC_CAP_NONREMOVABLE,
+	.priv_size	= sizeof(int),
+	.probe_slot	= qcom_probe_slot,
+	.free_slot	= qcom_free_slot,
 };
 
 static const struct sdhci_acpi_slot sdhci_acpi_slot_qcom_sd = {