提交 17753d16 编写于 作者: A Adrian Hunter 提交者: Ulf Hansson

mmc: sdhci-acpi: Workaround conflict with PCI wifi on GPD Win handheld

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: NAdrian Hunter <adrian.hunter@intel.com>
Acked-by: NHans de Goede <hdegoede@redhat.com>
Tested-by: NHans de Goede <hdegoede@redhat.com>
Cc: stable@vger.kernel.org
Signed-off-by: NUlf Hansson <ulf.hansson@linaro.org>
上级 9967468c
...@@ -45,6 +45,7 @@ ...@@ -45,6 +45,7 @@
#include <asm/cpu_device_id.h> #include <asm/cpu_device_id.h>
#include <asm/intel-family.h> #include <asm/intel-family.h>
#include <asm/iosf_mbi.h> #include <asm/iosf_mbi.h>
#include <linux/pci.h>
#endif #endif
#include "sdhci.h" #include "sdhci.h"
...@@ -134,6 +135,16 @@ static bool sdhci_acpi_byt(void) ...@@ -134,6 +135,16 @@ static bool sdhci_acpi_byt(void)
return x86_match_cpu(byt); 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_SCCEP 0x63
#define BYT_IOSF_OCP_NETCTRL0 0x1078 #define BYT_IOSF_OCP_NETCTRL0 0x1078
#define BYT_IOSF_OCP_TIMEOUT_BASE GENMASK(10, 8) #define BYT_IOSF_OCP_TIMEOUT_BASE GENMASK(10, 8)
...@@ -178,6 +189,45 @@ static bool sdhci_acpi_byt_defer(struct device *dev) ...@@ -178,6 +189,45 @@ static bool sdhci_acpi_byt_defer(struct device *dev)
return false; 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 #else
static inline void sdhci_acpi_byt_setting(struct device *dev) static inline void sdhci_acpi_byt_setting(struct device *dev)
...@@ -189,6 +239,12 @@ static inline bool sdhci_acpi_byt_defer(struct device *dev) ...@@ -189,6 +239,12 @@ static inline bool sdhci_acpi_byt_defer(struct device *dev)
return false; return false;
} }
static inline bool sdhci_acpi_no_fixup_child_power(const char *hid,
const char *uid)
{
return false;
}
#endif #endif
static int bxt_get_cd(struct mmc_host *mmc) static int bxt_get_cd(struct mmc_host *mmc)
...@@ -389,18 +445,20 @@ static int sdhci_acpi_probe(struct platform_device *pdev) ...@@ -389,18 +445,20 @@ static int sdhci_acpi_probe(struct platform_device *pdev)
if (acpi_bus_get_device(handle, &device)) if (acpi_bus_get_device(handle, &device))
return -ENODEV; return -ENODEV;
hid = acpi_device_hid(device);
uid = device->pnp.unique_id;
/* Power on the SDHCI controller and its children */ /* Power on the SDHCI controller and its children */
acpi_device_fix_up_power(device); acpi_device_fix_up_power(device);
if (!sdhci_acpi_no_fixup_child_power(hid, uid)) {
list_for_each_entry(child, &device->children, node) list_for_each_entry(child, &device->children, node)
if (child->status.present && child->status.enabled) if (child->status.present && child->status.enabled)
acpi_device_fix_up_power(child); acpi_device_fix_up_power(child);
}
if (sdhci_acpi_byt_defer(dev)) if (sdhci_acpi_byt_defer(dev))
return -EPROBE_DEFER; return -EPROBE_DEFER;
hid = acpi_device_hid(device);
uid = device->pnp.unique_id;
iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!iomem) if (!iomem)
return -ENOMEM; return -ENOMEM;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册