On 21 June 2017 at 14:08, Adrian Hunter <adrian.hunter@xxxxxxxxx> 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@xxxxxxxxx> > Acked-by: Hans de Goede <hdegoede@xxxxxxxxxx> > Tested-by: Hans de Goede <hdegoede@xxxxxxxxxx> > Cc: stable@xxxxxxxxxxxxxxx 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 > -- To unsubscribe from this list: send the line "unsubscribe linux-mmc" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html