Skip to content

Commit 0b722b8

Browse files
walshbgregkh
authored andcommitted
platform/chrome: cros_ec_lpc: MEC access can use an AML mutex
[ Upstream commit 60c7df6 ] Framework Laptops have ACPI code which accesses the MEC memory. It uses an AML mutex to prevent concurrent access. But the cros_ec_lpc driver was not aware of this mutex. The ACPI code and LPC driver both attempted to talk to the EC at the same time, messing up communication with the EC. Allow the LPC driver MEC code to find and use the AML mutex. Tested-by: Dustin L. Howett <[email protected]> Signed-off-by: Ben Walsh <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Tzung-Bi Shih <[email protected]> Signed-off-by: Sasha Levin <[email protected]>
1 parent 4be9fd1 commit 0b722b8

File tree

2 files changed

+85
-2
lines changed

2 files changed

+85
-2
lines changed

drivers/platform/chrome/cros_ec_lpc_mec.c

Lines changed: 74 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,65 @@
1010

1111
#include "cros_ec_lpc_mec.h"
1212

13+
#define ACPI_LOCK_DELAY_MS 500
14+
1315
/*
1416
* This mutex must be held while accessing the EMI unit. We can't rely on the
1517
* EC mutex because memmap data may be accessed without it being held.
1618
*/
1719
static DEFINE_MUTEX(io_mutex);
20+
/*
21+
* An alternative mutex to be used when the ACPI AML code may also
22+
* access memmap data. When set, this mutex is used in preference to
23+
* io_mutex.
24+
*/
25+
static acpi_handle aml_mutex;
26+
1827
static u16 mec_emi_base, mec_emi_end;
1928

29+
/**
30+
* cros_ec_lpc_mec_lock() - Acquire mutex for EMI
31+
*
32+
* @return: Negative error code, or zero for success
33+
*/
34+
static int cros_ec_lpc_mec_lock(void)
35+
{
36+
bool success;
37+
38+
if (!aml_mutex) {
39+
mutex_lock(&io_mutex);
40+
return 0;
41+
}
42+
43+
success = ACPI_SUCCESS(acpi_acquire_mutex(aml_mutex,
44+
NULL, ACPI_LOCK_DELAY_MS));
45+
if (!success)
46+
return -EBUSY;
47+
48+
return 0;
49+
}
50+
51+
/**
52+
* cros_ec_lpc_mec_unlock() - Release mutex for EMI
53+
*
54+
* @return: Negative error code, or zero for success
55+
*/
56+
static int cros_ec_lpc_mec_unlock(void)
57+
{
58+
bool success;
59+
60+
if (!aml_mutex) {
61+
mutex_unlock(&io_mutex);
62+
return 0;
63+
}
64+
65+
success = ACPI_SUCCESS(acpi_release_mutex(aml_mutex, NULL));
66+
if (!success)
67+
return -EBUSY;
68+
69+
return 0;
70+
}
71+
2072
/**
2173
* cros_ec_lpc_mec_emi_write_address() - Initialize EMI at a given address.
2274
*
@@ -77,6 +129,7 @@ u8 cros_ec_lpc_io_bytes_mec(enum cros_ec_lpc_mec_io_type io_type,
77129
int io_addr;
78130
u8 sum = 0;
79131
enum cros_ec_lpc_mec_emi_access_mode access, new_access;
132+
int ret;
80133

81134
/* Return checksum of 0 if window is not initialized */
82135
WARN_ON(mec_emi_base == 0 || mec_emi_end == 0);
@@ -92,7 +145,9 @@ u8 cros_ec_lpc_io_bytes_mec(enum cros_ec_lpc_mec_io_type io_type,
92145
else
93146
access = ACCESS_TYPE_LONG_AUTO_INCREMENT;
94147

95-
mutex_lock(&io_mutex);
148+
ret = cros_ec_lpc_mec_lock();
149+
if (ret)
150+
return ret;
96151

97152
/* Initialize I/O at desired address */
98153
cros_ec_lpc_mec_emi_write_address(offset, access);
@@ -134,7 +189,9 @@ u8 cros_ec_lpc_io_bytes_mec(enum cros_ec_lpc_mec_io_type io_type,
134189
}
135190

136191
done:
137-
mutex_unlock(&io_mutex);
192+
ret = cros_ec_lpc_mec_unlock();
193+
if (ret)
194+
return ret;
138195

139196
return sum;
140197
}
@@ -146,3 +203,18 @@ void cros_ec_lpc_mec_init(unsigned int base, unsigned int end)
146203
mec_emi_end = end;
147204
}
148205
EXPORT_SYMBOL(cros_ec_lpc_mec_init);
206+
207+
int cros_ec_lpc_mec_acpi_mutex(struct acpi_device *adev, const char *pathname)
208+
{
209+
int status;
210+
211+
if (!adev)
212+
return -ENOENT;
213+
214+
status = acpi_get_handle(adev->handle, pathname, &aml_mutex);
215+
if (ACPI_FAILURE(status))
216+
return -ENOENT;
217+
218+
return 0;
219+
}
220+
EXPORT_SYMBOL(cros_ec_lpc_mec_acpi_mutex);

drivers/platform/chrome/cros_ec_lpc_mec.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
#ifndef __CROS_EC_LPC_MEC_H
99
#define __CROS_EC_LPC_MEC_H
1010

11+
#include <linux/acpi.h>
12+
1113
enum cros_ec_lpc_mec_emi_access_mode {
1214
/* 8-bit access */
1315
ACCESS_TYPE_BYTE = 0x0,
@@ -45,6 +47,15 @@ enum cros_ec_lpc_mec_io_type {
4547
*/
4648
void cros_ec_lpc_mec_init(unsigned int base, unsigned int end);
4749

50+
/**
51+
* cros_ec_lpc_mec_acpi_mutex() - Find and set ACPI mutex for MEC
52+
*
53+
* @adev: Parent ACPI device
54+
* @pathname: Name of AML mutex
55+
* @return: Negative error code, or zero for success
56+
*/
57+
int cros_ec_lpc_mec_acpi_mutex(struct acpi_device *adev, const char *pathname);
58+
4859
/**
4960
* cros_ec_lpc_mec_in_range() - Determine if addresses are in MEC EMI range.
5061
*

0 commit comments

Comments
 (0)