All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] mmc: sdhci-acpi: Workaround conflict with PCI wifi on GPD Win handheld
@ 2017-06-21 12:08 Adrian Hunter
  2017-07-06 11:17 ` Hans de Goede
  2017-07-11 13:11 ` Ulf Hansson
  0 siblings, 2 replies; 3+ messages in thread
From: Adrian Hunter @ 2017-06-21 12:08 UTC (permalink / raw)
  To: Ulf Hansson; +Cc: linux-mmc, Hans de Goede

GPDwin uses PCI wifi which conflicts with SDIO's use of
acpi_device_fix_up_power() on child device nodes. Specifically
acpi_device_fix_up_power() causes the wifi module to get turned off.
Identifying GPDwin is problematic, but since SDIO is only used for wifi,
the presence of the PCI wifi card in the expected slot with an ACPI
companion node, is used to indicate that acpi_device_fix_up_power() should
be avoided.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Acked-by: Hans de Goede <hdegoede@redhat.com>
Tested-by: Hans de Goede <hdegoede@redhat.com>
Cc: stable@vger.kernel.org
---
 drivers/mmc/host/sdhci-acpi.c | 70 +++++++++++++++++++++++++++++++++++++++----
 1 file changed, 64 insertions(+), 6 deletions(-)

diff --git a/drivers/mmc/host/sdhci-acpi.c b/drivers/mmc/host/sdhci-acpi.c
index cf66a3db71b8..ac678e9fb19a 100644
--- a/drivers/mmc/host/sdhci-acpi.c
+++ b/drivers/mmc/host/sdhci-acpi.c
@@ -45,6 +45,7 @@
 #include <asm/cpu_device_id.h>
 #include <asm/intel-family.h>
 #include <asm/iosf_mbi.h>
+#include <linux/pci.h>
 #endif
 
 #include "sdhci.h"
@@ -134,6 +135,16 @@ static bool sdhci_acpi_byt(void)
 	return x86_match_cpu(byt);
 }
 
+static bool sdhci_acpi_cht(void)
+{
+	static const struct x86_cpu_id cht[] = {
+		{ X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_AIRMONT },
+		{}
+	};
+
+	return x86_match_cpu(cht);
+}
+
 #define BYT_IOSF_SCCEP			0x63
 #define BYT_IOSF_OCP_NETCTRL0		0x1078
 #define BYT_IOSF_OCP_TIMEOUT_BASE	GENMASK(10, 8)
@@ -178,6 +189,45 @@ static bool sdhci_acpi_byt_defer(struct device *dev)
 	return false;
 }
 
+static bool sdhci_acpi_cht_pci_wifi(unsigned int vendor, unsigned int device,
+				    unsigned int slot, unsigned int parent_slot)
+{
+	struct pci_dev *dev, *parent, *from = NULL;
+
+	while (1) {
+		dev = pci_get_device(vendor, device, from);
+		pci_dev_put(from);
+		if (!dev)
+			break;
+		parent = pci_upstream_bridge(dev);
+		if (ACPI_COMPANION(&dev->dev) && PCI_SLOT(dev->devfn) == slot &&
+		    parent && PCI_SLOT(parent->devfn) == parent_slot &&
+		    !pci_upstream_bridge(parent)) {
+			pci_dev_put(dev);
+			return true;
+		}
+		from = dev;
+	}
+
+	return false;
+}
+
+/*
+ * GPDwin uses PCI wifi which conflicts with SDIO's use of
+ * acpi_device_fix_up_power() on child device nodes. Identifying GPDwin is
+ * problematic, but since SDIO is only used for wifi, the presence of the PCI
+ * wifi card in the expected slot with an ACPI companion node, is used to
+ * indicate that acpi_device_fix_up_power() should be avoided.
+ */
+static inline bool sdhci_acpi_no_fixup_child_power(const char *hid,
+						   const char *uid)
+{
+	return sdhci_acpi_cht() &&
+	       !strcmp(hid, "80860F14") &&
+	       !strcmp(uid, "2") &&
+	       sdhci_acpi_cht_pci_wifi(0x14e4, 0x43ec, 0, 28);
+}
+
 #else
 
 static inline void sdhci_acpi_byt_setting(struct device *dev)
@@ -189,6 +239,12 @@ static inline bool sdhci_acpi_byt_defer(struct device *dev)
 	return false;
 }
 
+static inline bool sdhci_acpi_no_fixup_child_power(const char *hid,
+						   const char *uid)
+{
+	return false;
+}
+
 #endif
 
 static int bxt_get_cd(struct mmc_host *mmc)
@@ -389,18 +445,20 @@ static int sdhci_acpi_probe(struct platform_device *pdev)
 	if (acpi_bus_get_device(handle, &device))
 		return -ENODEV;
 
+	hid = acpi_device_hid(device);
+	uid = device->pnp.unique_id;
+
 	/* Power on the SDHCI controller and its children */
 	acpi_device_fix_up_power(device);
-	list_for_each_entry(child, &device->children, node)
-		if (child->status.present && child->status.enabled)
-			acpi_device_fix_up_power(child);
+	if (!sdhci_acpi_no_fixup_child_power(hid, uid)) {
+		list_for_each_entry(child, &device->children, node)
+			if (child->status.present && child->status.enabled)
+				acpi_device_fix_up_power(child);
+	}
 
 	if (sdhci_acpi_byt_defer(dev))
 		return -EPROBE_DEFER;
 
-	hid = acpi_device_hid(device);
-	uid = device->pnp.unique_id;
-
 	iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!iomem)
 		return -ENOMEM;
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [PATCH] mmc: sdhci-acpi: Workaround conflict with PCI wifi on GPD Win handheld
  2017-06-21 12:08 [PATCH] mmc: sdhci-acpi: Workaround conflict with PCI wifi on GPD Win handheld Adrian Hunter
@ 2017-07-06 11:17 ` Hans de Goede
  2017-07-11 13:11 ` Ulf Hansson
  1 sibling, 0 replies; 3+ messages in thread
From: Hans de Goede @ 2017-07-06 11:17 UTC (permalink / raw)
  To: Ulf Hansson; +Cc: Adrian Hunter, linux-mmc

Hi Ulf,

On 21-06-17 14:08, Adrian Hunter wrote:
> GPDwin uses PCI wifi which conflicts with SDIO's use of
> acpi_device_fix_up_power() on child device nodes. Specifically
> acpi_device_fix_up_power() causes the wifi module to get turned off.
> Identifying GPDwin is problematic, but since SDIO is only used for wifi,
> the presence of the PCI wifi card in the expected slot with an ACPI
> companion node, is used to indicate that acpi_device_fix_up_power() should
> be avoided.
> 
> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
> Acked-by: Hans de Goede <hdegoede@redhat.com>
> Tested-by: Hans de Goede <hdegoede@redhat.com>
> Cc: stable@vger.kernel.org

Ulf this bugfix seems to be missing from ulfh/mmc/next and I'm getting
more and more mails from users that this is affecting them, can we please
get this merged ?

Regards,

Hans


> ---
>   drivers/mmc/host/sdhci-acpi.c | 70 +++++++++++++++++++++++++++++++++++++++----
>   1 file changed, 64 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/mmc/host/sdhci-acpi.c b/drivers/mmc/host/sdhci-acpi.c
> index cf66a3db71b8..ac678e9fb19a 100644
> --- a/drivers/mmc/host/sdhci-acpi.c
> +++ b/drivers/mmc/host/sdhci-acpi.c
> @@ -45,6 +45,7 @@
>   #include <asm/cpu_device_id.h>
>   #include <asm/intel-family.h>
>   #include <asm/iosf_mbi.h>
> +#include <linux/pci.h>
>   #endif
>   
>   #include "sdhci.h"
> @@ -134,6 +135,16 @@ static bool sdhci_acpi_byt(void)
>   	return x86_match_cpu(byt);
>   }
>   
> +static bool sdhci_acpi_cht(void)
> +{
> +	static const struct x86_cpu_id cht[] = {
> +		{ X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_AIRMONT },
> +		{}
> +	};
> +
> +	return x86_match_cpu(cht);
> +}
> +
>   #define BYT_IOSF_SCCEP			0x63
>   #define BYT_IOSF_OCP_NETCTRL0		0x1078
>   #define BYT_IOSF_OCP_TIMEOUT_BASE	GENMASK(10, 8)
> @@ -178,6 +189,45 @@ static bool sdhci_acpi_byt_defer(struct device *dev)
>   	return false;
>   }
>   
> +static bool sdhci_acpi_cht_pci_wifi(unsigned int vendor, unsigned int device,
> +				    unsigned int slot, unsigned int parent_slot)
> +{
> +	struct pci_dev *dev, *parent, *from = NULL;
> +
> +	while (1) {
> +		dev = pci_get_device(vendor, device, from);
> +		pci_dev_put(from);
> +		if (!dev)
> +			break;
> +		parent = pci_upstream_bridge(dev);
> +		if (ACPI_COMPANION(&dev->dev) && PCI_SLOT(dev->devfn) == slot &&
> +		    parent && PCI_SLOT(parent->devfn) == parent_slot &&
> +		    !pci_upstream_bridge(parent)) {
> +			pci_dev_put(dev);
> +			return true;
> +		}
> +		from = dev;
> +	}
> +
> +	return false;
> +}
> +
> +/*
> + * GPDwin uses PCI wifi which conflicts with SDIO's use of
> + * acpi_device_fix_up_power() on child device nodes. Identifying GPDwin is
> + * problematic, but since SDIO is only used for wifi, the presence of the PCI
> + * wifi card in the expected slot with an ACPI companion node, is used to
> + * indicate that acpi_device_fix_up_power() should be avoided.
> + */
> +static inline bool sdhci_acpi_no_fixup_child_power(const char *hid,
> +						   const char *uid)
> +{
> +	return sdhci_acpi_cht() &&
> +	       !strcmp(hid, "80860F14") &&
> +	       !strcmp(uid, "2") &&
> +	       sdhci_acpi_cht_pci_wifi(0x14e4, 0x43ec, 0, 28);
> +}
> +
>   #else
>   
>   static inline void sdhci_acpi_byt_setting(struct device *dev)
> @@ -189,6 +239,12 @@ static inline bool sdhci_acpi_byt_defer(struct device *dev)
>   	return false;
>   }
>   
> +static inline bool sdhci_acpi_no_fixup_child_power(const char *hid,
> +						   const char *uid)
> +{
> +	return false;
> +}
> +
>   #endif
>   
>   static int bxt_get_cd(struct mmc_host *mmc)
> @@ -389,18 +445,20 @@ static int sdhci_acpi_probe(struct platform_device *pdev)
>   	if (acpi_bus_get_device(handle, &device))
>   		return -ENODEV;
>   
> +	hid = acpi_device_hid(device);
> +	uid = device->pnp.unique_id;
> +
>   	/* Power on the SDHCI controller and its children */
>   	acpi_device_fix_up_power(device);
> -	list_for_each_entry(child, &device->children, node)
> -		if (child->status.present && child->status.enabled)
> -			acpi_device_fix_up_power(child);
> +	if (!sdhci_acpi_no_fixup_child_power(hid, uid)) {
> +		list_for_each_entry(child, &device->children, node)
> +			if (child->status.present && child->status.enabled)
> +				acpi_device_fix_up_power(child);
> +	}
>   
>   	if (sdhci_acpi_byt_defer(dev))
>   		return -EPROBE_DEFER;
>   
> -	hid = acpi_device_hid(device);
> -	uid = device->pnp.unique_id;
> -
>   	iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>   	if (!iomem)
>   		return -ENOMEM;
> 

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH] mmc: sdhci-acpi: Workaround conflict with PCI wifi on GPD Win handheld
  2017-06-21 12:08 [PATCH] mmc: sdhci-acpi: Workaround conflict with PCI wifi on GPD Win handheld Adrian Hunter
  2017-07-06 11:17 ` Hans de Goede
@ 2017-07-11 13:11 ` Ulf Hansson
  1 sibling, 0 replies; 3+ messages in thread
From: Ulf Hansson @ 2017-07-11 13:11 UTC (permalink / raw)
  To: Adrian Hunter; +Cc: linux-mmc, Hans de Goede

On 21 June 2017 at 14:08, Adrian Hunter <adrian.hunter@intel.com> wrote:
> GPDwin uses PCI wifi which conflicts with SDIO's use of
> acpi_device_fix_up_power() on child device nodes. Specifically
> acpi_device_fix_up_power() causes the wifi module to get turned off.
> Identifying GPDwin is problematic, but since SDIO is only used for wifi,
> the presence of the PCI wifi card in the expected slot with an ACPI
> companion node, is used to indicate that acpi_device_fix_up_power() should
> be avoided.
>
> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
> Acked-by: Hans de Goede <hdegoede@redhat.com>
> Tested-by: Hans de Goede <hdegoede@redhat.com>
> Cc: stable@vger.kernel.org

Sorry for the delay.

Applied for fixes!

Kind regards
Uffe

> ---
>  drivers/mmc/host/sdhci-acpi.c | 70 +++++++++++++++++++++++++++++++++++++++----
>  1 file changed, 64 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/mmc/host/sdhci-acpi.c b/drivers/mmc/host/sdhci-acpi.c
> index cf66a3db71b8..ac678e9fb19a 100644
> --- a/drivers/mmc/host/sdhci-acpi.c
> +++ b/drivers/mmc/host/sdhci-acpi.c
> @@ -45,6 +45,7 @@
>  #include <asm/cpu_device_id.h>
>  #include <asm/intel-family.h>
>  #include <asm/iosf_mbi.h>
> +#include <linux/pci.h>
>  #endif
>
>  #include "sdhci.h"
> @@ -134,6 +135,16 @@ static bool sdhci_acpi_byt(void)
>         return x86_match_cpu(byt);
>  }
>
> +static bool sdhci_acpi_cht(void)
> +{
> +       static const struct x86_cpu_id cht[] = {
> +               { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_AIRMONT },
> +               {}
> +       };
> +
> +       return x86_match_cpu(cht);
> +}
> +
>  #define BYT_IOSF_SCCEP                 0x63
>  #define BYT_IOSF_OCP_NETCTRL0          0x1078
>  #define BYT_IOSF_OCP_TIMEOUT_BASE      GENMASK(10, 8)
> @@ -178,6 +189,45 @@ static bool sdhci_acpi_byt_defer(struct device *dev)
>         return false;
>  }
>
> +static bool sdhci_acpi_cht_pci_wifi(unsigned int vendor, unsigned int device,
> +                                   unsigned int slot, unsigned int parent_slot)
> +{
> +       struct pci_dev *dev, *parent, *from = NULL;
> +
> +       while (1) {
> +               dev = pci_get_device(vendor, device, from);
> +               pci_dev_put(from);
> +               if (!dev)
> +                       break;
> +               parent = pci_upstream_bridge(dev);
> +               if (ACPI_COMPANION(&dev->dev) && PCI_SLOT(dev->devfn) == slot &&
> +                   parent && PCI_SLOT(parent->devfn) == parent_slot &&
> +                   !pci_upstream_bridge(parent)) {
> +                       pci_dev_put(dev);
> +                       return true;
> +               }
> +               from = dev;
> +       }
> +
> +       return false;
> +}
> +
> +/*
> + * GPDwin uses PCI wifi which conflicts with SDIO's use of
> + * acpi_device_fix_up_power() on child device nodes. Identifying GPDwin is
> + * problematic, but since SDIO is only used for wifi, the presence of the PCI
> + * wifi card in the expected slot with an ACPI companion node, is used to
> + * indicate that acpi_device_fix_up_power() should be avoided.
> + */
> +static inline bool sdhci_acpi_no_fixup_child_power(const char *hid,
> +                                                  const char *uid)
> +{
> +       return sdhci_acpi_cht() &&
> +              !strcmp(hid, "80860F14") &&
> +              !strcmp(uid, "2") &&
> +              sdhci_acpi_cht_pci_wifi(0x14e4, 0x43ec, 0, 28);
> +}
> +
>  #else
>
>  static inline void sdhci_acpi_byt_setting(struct device *dev)
> @@ -189,6 +239,12 @@ static inline bool sdhci_acpi_byt_defer(struct device *dev)
>         return false;
>  }
>
> +static inline bool sdhci_acpi_no_fixup_child_power(const char *hid,
> +                                                  const char *uid)
> +{
> +       return false;
> +}
> +
>  #endif
>
>  static int bxt_get_cd(struct mmc_host *mmc)
> @@ -389,18 +445,20 @@ static int sdhci_acpi_probe(struct platform_device *pdev)
>         if (acpi_bus_get_device(handle, &device))
>                 return -ENODEV;
>
> +       hid = acpi_device_hid(device);
> +       uid = device->pnp.unique_id;
> +
>         /* Power on the SDHCI controller and its children */
>         acpi_device_fix_up_power(device);
> -       list_for_each_entry(child, &device->children, node)
> -               if (child->status.present && child->status.enabled)
> -                       acpi_device_fix_up_power(child);
> +       if (!sdhci_acpi_no_fixup_child_power(hid, uid)) {
> +               list_for_each_entry(child, &device->children, node)
> +                       if (child->status.present && child->status.enabled)
> +                               acpi_device_fix_up_power(child);
> +       }
>
>         if (sdhci_acpi_byt_defer(dev))
>                 return -EPROBE_DEFER;
>
> -       hid = acpi_device_hid(device);
> -       uid = device->pnp.unique_id;
> -
>         iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>         if (!iomem)
>                 return -ENOMEM;
> --
> 1.9.1
>

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2017-07-11 13:11 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-06-21 12:08 [PATCH] mmc: sdhci-acpi: Workaround conflict with PCI wifi on GPD Win handheld Adrian Hunter
2017-07-06 11:17 ` Hans de Goede
2017-07-11 13:11 ` Ulf Hansson

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.