Re: [PATCH] mmc: sdhci-acpi: Workaround conflict with PCI wifi on GPD Win handheld

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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



[Index of Archives]     [Linux USB Devel]     [Linux Media]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux