Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3349fb64 authored by Chris Bainbridge's avatar Chris Bainbridge Committed by Rafael J. Wysocki
Browse files

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

Commit 7bc5a2ba '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: 7bc5a2ba 'ACPI: Support _OSI("Darwin") correctly'
Link: https://bugzilla.kernel.org/show_bug.cgi?id=94651


Signed-off-by: default avatarChris Bainbridge <chris.bainbridge@gmail.com>
Cc: 3.18+ <stable@vger.kernel.org> # 3.18+
[ rjw: Subject and changelog ]
Signed-off-by: default avatarRafael J. Wysocki <rafael.j.wysocki@intel.com>
parent 61f8ff69
Loading
Loading
Loading
Loading
+22 −0
Original line number Diff line number Diff line
@@ -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;