diff options
author | Chris Bainbridge <chris.bainbridge@gmail.com> | 2015-04-29 16:21:40 -0400 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2015-04-30 17:18:11 -0400 |
commit | 3349fb64b2927407017d970dd5c4daf3c5ad69f8 (patch) | |
tree | 7f446e4537f411daa245f1b0a16ec628a76442d1 | |
parent | 61f8ff693923e4b19748b0e8287b99778f2661c7 (diff) |
ACPI / SBS: Add 5 us delay to fix SBS hangs on MacBook
Commit 7bc5a2bad0b8 'ACPI: Support _OSI("Darwin") correctly' caused
the MacBook firmware to expose the SBS, resulting in intermittent
hangs of several minutes on boot, and failure to detect or report
the battery. Fix this by adding a 5 us delay to the start of each
SMBUS transaction. This timing is the result of experimentation -
hangs were observed with 3 us but never with 5 us.
Fixes: 7bc5a2bad0b8 'ACPI: Support _OSI("Darwin") correctly'
Link: https://bugzilla.kernel.org/show_bug.cgi?id=94651
Signed-off-by: Chris Bainbridge <chris.bainbridge@gmail.com>
Cc: 3.18+ <stable@vger.kernel.org> # 3.18+
[ rjw: Subject and changelog ]
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-rw-r--r-- | drivers/acpi/sbshc.c | 22 |
1 files changed, 22 insertions, 0 deletions
diff --git a/drivers/acpi/sbshc.c b/drivers/acpi/sbshc.c index 26e5b5060523..bf034f8b7c1a 100644 --- a/drivers/acpi/sbshc.c +++ b/drivers/acpi/sbshc.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/delay.h> | 14 | #include <linux/delay.h> |
15 | #include <linux/module.h> | 15 | #include <linux/module.h> |
16 | #include <linux/interrupt.h> | 16 | #include <linux/interrupt.h> |
17 | #include <linux/dmi.h> | ||
17 | #include "sbshc.h" | 18 | #include "sbshc.h" |
18 | 19 | ||
19 | #define PREFIX "ACPI: " | 20 | #define PREFIX "ACPI: " |
@@ -87,6 +88,8 @@ enum acpi_smb_offset { | |||
87 | ACPI_SMB_ALARM_DATA = 0x26, /* 2 bytes alarm data */ | 88 | ACPI_SMB_ALARM_DATA = 0x26, /* 2 bytes alarm data */ |
88 | }; | 89 | }; |
89 | 90 | ||
91 | static bool macbook; | ||
92 | |||
90 | static inline int smb_hc_read(struct acpi_smb_hc *hc, u8 address, u8 *data) | 93 | static inline int smb_hc_read(struct acpi_smb_hc *hc, u8 address, u8 *data) |
91 | { | 94 | { |
92 | return ec_read(hc->offset + address, data); | 95 | return ec_read(hc->offset + address, data); |
@@ -132,6 +135,8 @@ static int acpi_smbus_transaction(struct acpi_smb_hc *hc, u8 protocol, | |||
132 | } | 135 | } |
133 | 136 | ||
134 | mutex_lock(&hc->lock); | 137 | mutex_lock(&hc->lock); |
138 | if (macbook) | ||
139 | udelay(5); | ||
135 | if (smb_hc_read(hc, ACPI_SMB_PROTOCOL, &temp)) | 140 | if (smb_hc_read(hc, ACPI_SMB_PROTOCOL, &temp)) |
136 | goto end; | 141 | goto end; |
137 | if (temp) { | 142 | if (temp) { |
@@ -257,12 +262,29 @@ extern int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit, | |||
257 | acpi_handle handle, acpi_ec_query_func func, | 262 | acpi_handle handle, acpi_ec_query_func func, |
258 | void *data); | 263 | void *data); |
259 | 264 | ||
265 | static int macbook_dmi_match(const struct dmi_system_id *d) | ||
266 | { | ||
267 | pr_debug("Detected MacBook, enabling workaround\n"); | ||
268 | macbook = true; | ||
269 | return 0; | ||
270 | } | ||
271 | |||
272 | static struct dmi_system_id acpi_smbus_dmi_table[] = { | ||
273 | { macbook_dmi_match, "Apple MacBook", { | ||
274 | DMI_MATCH(DMI_BOARD_VENDOR, "Apple"), | ||
275 | DMI_MATCH(DMI_PRODUCT_NAME, "MacBook") }, | ||
276 | }, | ||
277 | { }, | ||
278 | }; | ||
279 | |||
260 | static int acpi_smbus_hc_add(struct acpi_device *device) | 280 | static int acpi_smbus_hc_add(struct acpi_device *device) |
261 | { | 281 | { |
262 | int status; | 282 | int status; |
263 | unsigned long long val; | 283 | unsigned long long val; |
264 | struct acpi_smb_hc *hc; | 284 | struct acpi_smb_hc *hc; |
265 | 285 | ||
286 | dmi_check_system(acpi_smbus_dmi_table); | ||
287 | |||
266 | if (!device) | 288 | if (!device) |
267 | return -EINVAL; | 289 | return -EINVAL; |
268 | 290 | ||