diff mbox

ACPI/sbshc: Add 5us delay to fix SBS hang on MacBook

Message ID 20150429202140.GB25904@localhost (mailing list archive)
State Accepted, archived
Delegated to: Rafael Wysocki
Headers show

Commit Message

Chris Bainbridge April 29, 2015, 8:21 p.m. UTC
Regression in commit 7bc5a2bad0b8d9d1ac9f7b8b33150e4ddf197334
Author: Matthew Garrett <matthew.garrett@nebula.com>
Date:   Sat Sep 20 13:19:47 2014 +0200

    ACPI: Support _OSI("Darwin") correctly

Supporting _OSI("Darwin") 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 5us delay to the
start of each SMBUS transaction. This timing is the result of
experimentation - hangs were observed with 3us but never with 5us.

Link: https://bugzilla.kernel.org/show_bug.cgi?id=94651
Signed-off-by: Chris Bainbridge <chris.bainbridge@gmail.com>
---
 drivers/acpi/sbshc.c | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

Comments

Rafael J. Wysocki April 30, 2015, 10:15 p.m. UTC | #1
On Wednesday, April 29, 2015 09:21:40 PM Chris Bainbridge wrote:
> Regression in commit 7bc5a2bad0b8d9d1ac9f7b8b33150e4ddf197334
> Author: Matthew Garrett <matthew.garrett@nebula.com>
> Date:   Sat Sep 20 13:19:47 2014 +0200
> 
>     ACPI: Support _OSI("Darwin") correctly
> 
> Supporting _OSI("Darwin") 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 5us delay to the
> start of each SMBUS transaction. This timing is the result of
> experimentation - hangs were observed with 3us but never with 5us.
> 
> Link: https://bugzilla.kernel.org/show_bug.cgi?id=94651
> Signed-off-by: Chris Bainbridge <chris.bainbridge@gmail.com>

Looks much better, I've queued it up as a fix for 4.1, thanks!

> ---
>  drivers/acpi/sbshc.c | 22 ++++++++++++++++++++++
>  1 file changed, 22 insertions(+)
> 
> diff --git a/drivers/acpi/sbshc.c b/drivers/acpi/sbshc.c
> index 26e5b50..bf034f8 100644
> --- a/drivers/acpi/sbshc.c
> +++ b/drivers/acpi/sbshc.c
> @@ -14,6 +14,7 @@
>  #include <linux/delay.h>
>  #include <linux/module.h>
>  #include <linux/interrupt.h>
> +#include <linux/dmi.h>
>  #include "sbshc.h"
>  
>  #define PREFIX "ACPI: "
> @@ -87,6 +88,8 @@ enum acpi_smb_offset {
>  	ACPI_SMB_ALARM_DATA = 0x26,	/* 2 bytes alarm data */
>  };
>  
> +static bool macbook;
> +
>  static inline int smb_hc_read(struct acpi_smb_hc *hc, u8 address, u8 *data)
>  {
>  	return ec_read(hc->offset + address, data);
> @@ -132,6 +135,8 @@ static int acpi_smbus_transaction(struct acpi_smb_hc *hc, u8 protocol,
>  	}
>  
>  	mutex_lock(&hc->lock);
> +	if (macbook)
> +		udelay(5);
>  	if (smb_hc_read(hc, ACPI_SMB_PROTOCOL, &temp))
>  		goto end;
>  	if (temp) {
> @@ -257,12 +262,29 @@ extern int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit,
>  			      acpi_handle handle, acpi_ec_query_func func,
>  			      void *data);
>  
> +static int macbook_dmi_match(const struct dmi_system_id *d)
> +{
> +	pr_debug("Detected MacBook, enabling workaround\n");
> +	macbook = true;
> +	return 0;
> +}
> +
> +static struct dmi_system_id acpi_smbus_dmi_table[] = {
> +	{ macbook_dmi_match, "Apple MacBook", {
> +	  DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
> +	  DMI_MATCH(DMI_PRODUCT_NAME, "MacBook") },
> +	},
> +	{ },
> +};
> +
>  static int acpi_smbus_hc_add(struct acpi_device *device)
>  {
>  	int status;
>  	unsigned long long val;
>  	struct acpi_smb_hc *hc;
>  
> +	dmi_check_system(acpi_smbus_dmi_table);
> +
>  	if (!device)
>  		return -EINVAL;
>  
>
Brad Campbell May 18, 2015, 2:20 a.m. UTC | #2
On 30/04/15 04:21, Chris Bainbridge wrote:
>
> Supporting _OSI("Darwin") 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 5us delay to the
> start of each SMBUS transaction. This timing is the result of
> experimentation - hangs were observed with 3us but never with 5us.

G'day Chris,

Using 4.1-rc3 (whatever git head was from a couple of days ago) I've 
still been seeing ACPI lockups on my Macbook Pro (11,1). It appears to 
take a couple of suspend/resume cycles but seems to happen within 24 
hours of booting whereas before this patch it was easy to hit.

As a test (and I do wonder if it'll lock up after I press send on this 
E-mail) I upped the delay to 10us and I've now been up for 1 day, 17:23 
with the battery still responding to polling.

To make it easier to reproduce, I've been running a script that polls 
the battery every 60 seconds.

I figure I'll let it go for another couple of days, but I wanted to put 
this out there in case anyone else is seeing lockups after a longer 
period of uptime. The symptoms are the ACPI command just hangs as does 
'cat /sys/class/power_supply/BAT0/status'. From there I can't suspend as 
the tasks can't be frozen and I just end up hard booting the machine.

I've removed Len & Rafael from the cc.

Regards,
Brad
--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/acpi/sbshc.c b/drivers/acpi/sbshc.c
index 26e5b50..bf034f8 100644
--- a/drivers/acpi/sbshc.c
+++ b/drivers/acpi/sbshc.c
@@ -14,6 +14,7 @@ 
 #include <linux/delay.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
+#include <linux/dmi.h>
 #include "sbshc.h"
 
 #define PREFIX "ACPI: "
@@ -87,6 +88,8 @@  enum acpi_smb_offset {
 	ACPI_SMB_ALARM_DATA = 0x26,	/* 2 bytes alarm data */
 };
 
+static bool macbook;
+
 static inline int smb_hc_read(struct acpi_smb_hc *hc, u8 address, u8 *data)
 {
 	return ec_read(hc->offset + address, data);
@@ -132,6 +135,8 @@  static int acpi_smbus_transaction(struct acpi_smb_hc *hc, u8 protocol,
 	}
 
 	mutex_lock(&hc->lock);
+	if (macbook)
+		udelay(5);
 	if (smb_hc_read(hc, ACPI_SMB_PROTOCOL, &temp))
 		goto end;
 	if (temp) {
@@ -257,12 +262,29 @@  extern int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit,
 			      acpi_handle handle, acpi_ec_query_func func,
 			      void *data);
 
+static int macbook_dmi_match(const struct dmi_system_id *d)
+{
+	pr_debug("Detected MacBook, enabling workaround\n");
+	macbook = true;
+	return 0;
+}
+
+static struct dmi_system_id acpi_smbus_dmi_table[] = {
+	{ macbook_dmi_match, "Apple MacBook", {
+	  DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
+	  DMI_MATCH(DMI_PRODUCT_NAME, "MacBook") },
+	},
+	{ },
+};
+
 static int acpi_smbus_hc_add(struct acpi_device *device)
 {
 	int status;
 	unsigned long long val;
 	struct acpi_smb_hc *hc;
 
+	dmi_check_system(acpi_smbus_dmi_table);
+
 	if (!device)
 		return -EINVAL;