diff options
-rw-r--r-- | drivers/acpi/Makefile | 1 | ||||
-rw-r--r-- | drivers/acpi/bus.c | 5 | ||||
-rw-r--r-- | drivers/acpi/x86/utils.c | 85 | ||||
-rw-r--r-- | include/acpi/acpi_bus.h | 9 |
4 files changed, 100 insertions, 0 deletions
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index d94f92f88ca1..2a81d278bcf3 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile | |||
@@ -50,6 +50,7 @@ acpi-$(CONFIG_ACPI_REDUCED_HARDWARE_ONLY) += evged.o | |||
50 | acpi-y += sysfs.o | 50 | acpi-y += sysfs.o |
51 | acpi-y += property.o | 51 | acpi-y += property.o |
52 | acpi-$(CONFIG_X86) += acpi_cmos_rtc.o | 52 | acpi-$(CONFIG_X86) += acpi_cmos_rtc.o |
53 | acpi-$(CONFIG_X86) += x86/utils.o | ||
53 | acpi-$(CONFIG_DEBUG_FS) += debugfs.o | 54 | acpi-$(CONFIG_DEBUG_FS) += debugfs.o |
54 | acpi-$(CONFIG_ACPI_NUMA) += numa.o | 55 | acpi-$(CONFIG_ACPI_NUMA) += numa.o |
55 | acpi-$(CONFIG_ACPI_PROCFS_POWER) += cm_sbs.o | 56 | acpi-$(CONFIG_ACPI_PROCFS_POWER) += cm_sbs.o |
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 34fbe027e73a..784bda663d16 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c | |||
@@ -114,6 +114,11 @@ int acpi_bus_get_status(struct acpi_device *device) | |||
114 | acpi_status status; | 114 | acpi_status status; |
115 | unsigned long long sta; | 115 | unsigned long long sta; |
116 | 116 | ||
117 | if (acpi_device_always_present(device)) { | ||
118 | acpi_set_device_status(device, ACPI_STA_DEFAULT); | ||
119 | return 0; | ||
120 | } | ||
121 | |||
117 | status = acpi_bus_get_status_handle(device->handle, &sta); | 122 | status = acpi_bus_get_status_handle(device->handle, &sta); |
118 | if (ACPI_FAILURE(status)) | 123 | if (ACPI_FAILURE(status)) |
119 | return -ENODEV; | 124 | return -ENODEV; |
diff --git a/drivers/acpi/x86/utils.c b/drivers/acpi/x86/utils.c new file mode 100644 index 000000000000..c8e90ef4485f --- /dev/null +++ b/drivers/acpi/x86/utils.c | |||
@@ -0,0 +1,85 @@ | |||
1 | /* | ||
2 | * X86 ACPI Utility Functions | ||
3 | * | ||
4 | * Copyright (C) 2017 Hans de Goede <hdegoede@redhat.com> | ||
5 | * | ||
6 | * Based on various non upstream patches to support the CHT Whiskey Cove PMIC: | ||
7 | * Copyright (C) 2013-2015 Intel Corporation. All rights reserved. | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | */ | ||
13 | |||
14 | #include <linux/acpi.h> | ||
15 | #include <asm/cpu_device_id.h> | ||
16 | #include <asm/intel-family.h> | ||
17 | #include "../internal.h" | ||
18 | |||
19 | /* | ||
20 | * Some ACPI devices are hidden (status == 0x0) in recent BIOS-es because | ||
21 | * some recent Windows drivers bind to one device but poke at multiple | ||
22 | * devices at the same time, so the others get hidden. | ||
23 | * We work around this by always reporting ACPI_STA_DEFAULT for these | ||
24 | * devices. Note this MUST only be done for devices where this is safe. | ||
25 | * | ||
26 | * This forcing of devices to be present is limited to specific CPU (SoC) | ||
27 | * models both to avoid potentially causing trouble on other models and | ||
28 | * because some HIDs are re-used on different SoCs for completely | ||
29 | * different devices. | ||
30 | */ | ||
31 | struct always_present_id { | ||
32 | struct acpi_device_id hid[2]; | ||
33 | struct x86_cpu_id cpu_ids[2]; | ||
34 | const char *uid; | ||
35 | }; | ||
36 | |||
37 | #define ICPU(model) { X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, } | ||
38 | |||
39 | #define ENTRY(hid, uid, cpu_models) { \ | ||
40 | { { hid, }, {} }, \ | ||
41 | { cpu_models, {} }, \ | ||
42 | uid, \ | ||
43 | } | ||
44 | |||
45 | static const struct always_present_id always_present_ids[] = { | ||
46 | /* | ||
47 | * Bay / Cherry Trail PWM directly poked by GPU driver in win10, | ||
48 | * but Linux uses a separate PWM driver, harmless if not used. | ||
49 | */ | ||
50 | ENTRY("80860F09", "1", ICPU(INTEL_FAM6_ATOM_SILVERMONT1)), | ||
51 | ENTRY("80862288", "1", ICPU(INTEL_FAM6_ATOM_AIRMONT)), | ||
52 | }; | ||
53 | |||
54 | bool acpi_device_always_present(struct acpi_device *adev) | ||
55 | { | ||
56 | u32 *status = (u32 *)&adev->status; | ||
57 | u32 old_status = *status; | ||
58 | bool ret = false; | ||
59 | unsigned int i; | ||
60 | |||
61 | /* acpi_match_device_ids checks status, so set it to default */ | ||
62 | *status = ACPI_STA_DEFAULT; | ||
63 | for (i = 0; i < ARRAY_SIZE(always_present_ids); i++) { | ||
64 | if (acpi_match_device_ids(adev, always_present_ids[i].hid)) | ||
65 | continue; | ||
66 | |||
67 | if (!adev->pnp.unique_id || | ||
68 | strcmp(adev->pnp.unique_id, always_present_ids[i].uid)) | ||
69 | continue; | ||
70 | |||
71 | if (!x86_match_cpu(always_present_ids[i].cpu_ids)) | ||
72 | continue; | ||
73 | |||
74 | if (old_status != ACPI_STA_DEFAULT) /* Log only once */ | ||
75 | dev_info(&adev->dev, | ||
76 | "Device [%s] is in always present list\n", | ||
77 | adev->pnp.bus_id); | ||
78 | |||
79 | ret = true; | ||
80 | break; | ||
81 | } | ||
82 | *status = old_status; | ||
83 | |||
84 | return ret; | ||
85 | } | ||
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index ef0ae8aaa567..b86b90489140 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h | |||
@@ -586,6 +586,15 @@ struct acpi_pci_root *acpi_pci_find_root(acpi_handle handle); | |||
586 | int acpi_enable_wakeup_device_power(struct acpi_device *dev, int state); | 586 | int acpi_enable_wakeup_device_power(struct acpi_device *dev, int state); |
587 | int acpi_disable_wakeup_device_power(struct acpi_device *dev); | 587 | int acpi_disable_wakeup_device_power(struct acpi_device *dev); |
588 | 588 | ||
589 | #ifdef CONFIG_X86 | ||
590 | bool acpi_device_always_present(struct acpi_device *adev); | ||
591 | #else | ||
592 | static inline bool acpi_device_always_present(struct acpi_device *adev) | ||
593 | { | ||
594 | return false; | ||
595 | } | ||
596 | #endif | ||
597 | |||
589 | #ifdef CONFIG_PM | 598 | #ifdef CONFIG_PM |
590 | acpi_status acpi_add_pm_notifier(struct acpi_device *adev, struct device *dev, | 599 | acpi_status acpi_add_pm_notifier(struct acpi_device *adev, struct device *dev, |
591 | void (*work_func)(struct work_struct *work)); | 600 | void (*work_func)(struct work_struct *work)); |