Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Chris Bainbridge and committed by
Rafael J. Wysocki
3349fb64 61f8ff69

+22
+22
drivers/acpi/sbshc.c
··· 14 14 #include <linux/delay.h> 15 15 #include <linux/module.h> 16 16 #include <linux/interrupt.h> 17 + #include <linux/dmi.h> 17 18 #include "sbshc.h" 18 19 19 20 #define PREFIX "ACPI: " ··· 88 87 ACPI_SMB_ALARM_DATA = 0x26, /* 2 bytes alarm data */ 89 88 }; 90 89 90 + static bool macbook; 91 + 91 92 static inline int smb_hc_read(struct acpi_smb_hc *hc, u8 address, u8 *data) 92 93 { 93 94 return ec_read(hc->offset + address, data); ··· 135 132 } 136 133 137 134 mutex_lock(&hc->lock); 135 + if (macbook) 136 + udelay(5); 138 137 if (smb_hc_read(hc, ACPI_SMB_PROTOCOL, &temp)) 139 138 goto end; 140 139 if (temp) { ··· 262 257 acpi_handle handle, acpi_ec_query_func func, 263 258 void *data); 264 259 260 + static int macbook_dmi_match(const struct dmi_system_id *d) 261 + { 262 + pr_debug("Detected MacBook, enabling workaround\n"); 263 + macbook = true; 264 + return 0; 265 + } 266 + 267 + static struct dmi_system_id acpi_smbus_dmi_table[] = { 268 + { macbook_dmi_match, "Apple MacBook", { 269 + DMI_MATCH(DMI_BOARD_VENDOR, "Apple"), 270 + DMI_MATCH(DMI_PRODUCT_NAME, "MacBook") }, 271 + }, 272 + { }, 273 + }; 274 + 265 275 static int acpi_smbus_hc_add(struct acpi_device *device) 266 276 { 267 277 int status; 268 278 unsigned long long val; 269 279 struct acpi_smb_hc *hc; 280 + 281 + dmi_check_system(acpi_smbus_dmi_table); 270 282 271 283 if (!device) 272 284 return -EINVAL;