Skip to content

Commit dc17111

Browse files
committed
ACPI: EC: Do not release locks during operation region accesses
It is not particularly useful to release locks (the EC mutex and the ACPI global lock, if present) and re-acquire them immediately thereafter during EC address space accesses in acpi_ec_space_handler(). First, releasing them for a while before grabbing them again does not really help anyone because there may not be enough time for another thread to acquire them. Second, if another thread successfully acquires them and carries out a new EC write or read in the middle if an operation region access in progress, it may confuse the EC firmware, especially after the burst mode has been enabled. Finally, manipulating the locks after writing or reading every single byte of data is overhead that it is better to avoid. Accordingly, modify the code to carry out EC address space accesses entirely without releasing the locks. Signed-off-by: Rafael J. Wysocki <[email protected]> Reviewed-by: Hans de Goede <[email protected]> Link: https://patch.msgid.link/[email protected]
1 parent 8400291 commit dc17111

File tree

1 file changed

+49
-6
lines changed

1 file changed

+49
-6
lines changed

drivers/acpi/ec.c

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -783,6 +783,9 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec,
783783
unsigned long tmp;
784784
int ret = 0;
785785

786+
if (t->rdata)
787+
memset(t->rdata, 0, t->rlen);
788+
786789
/* start transaction */
787790
spin_lock_irqsave(&ec->lock, tmp);
788791
/* Enable GPE for command processing (IBF=0/OBF=1) */
@@ -819,8 +822,6 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t)
819822

820823
if (!ec || (!t) || (t->wlen && !t->wdata) || (t->rlen && !t->rdata))
821824
return -EINVAL;
822-
if (t->rdata)
823-
memset(t->rdata, 0, t->rlen);
824825

825826
mutex_lock(&ec->mutex);
826827
if (ec->global_lock) {
@@ -847,7 +848,7 @@ static int acpi_ec_burst_enable(struct acpi_ec *ec)
847848
.wdata = NULL, .rdata = &d,
848849
.wlen = 0, .rlen = 1};
849850

850-
return acpi_ec_transaction(ec, &t);
851+
return acpi_ec_transaction_unlocked(ec, &t);
851852
}
852853

853854
static int acpi_ec_burst_disable(struct acpi_ec *ec)
@@ -857,7 +858,7 @@ static int acpi_ec_burst_disable(struct acpi_ec *ec)
857858
.wlen = 0, .rlen = 0};
858859

859860
return (acpi_ec_read_status(ec) & ACPI_EC_FLAG_BURST) ?
860-
acpi_ec_transaction(ec, &t) : 0;
861+
acpi_ec_transaction_unlocked(ec, &t) : 0;
861862
}
862863

863864
static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 *data)
@@ -873,6 +874,19 @@ static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 *data)
873874
return result;
874875
}
875876

877+
static int acpi_ec_read_unlocked(struct acpi_ec *ec, u8 address, u8 *data)
878+
{
879+
int result;
880+
u8 d;
881+
struct transaction t = {.command = ACPI_EC_COMMAND_READ,
882+
.wdata = &address, .rdata = &d,
883+
.wlen = 1, .rlen = 1};
884+
885+
result = acpi_ec_transaction_unlocked(ec, &t);
886+
*data = d;
887+
return result;
888+
}
889+
876890
static int acpi_ec_write(struct acpi_ec *ec, u8 address, u8 data)
877891
{
878892
u8 wdata[2] = { address, data };
@@ -883,6 +897,16 @@ static int acpi_ec_write(struct acpi_ec *ec, u8 address, u8 data)
883897
return acpi_ec_transaction(ec, &t);
884898
}
885899

900+
static int acpi_ec_write_unlocked(struct acpi_ec *ec, u8 address, u8 data)
901+
{
902+
u8 wdata[2] = { address, data };
903+
struct transaction t = {.command = ACPI_EC_COMMAND_WRITE,
904+
.wdata = wdata, .rdata = NULL,
905+
.wlen = 2, .rlen = 0};
906+
907+
return acpi_ec_transaction_unlocked(ec, &t);
908+
}
909+
886910
int ec_read(u8 addr, u8 *val)
887911
{
888912
int err;
@@ -1323,27 +1347,46 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address,
13231347
struct acpi_ec *ec = handler_context;
13241348
int result = 0, i, bytes = bits / 8;
13251349
u8 *value = (u8 *)value64;
1350+
u32 glk;
13261351

13271352
if ((address > 0xFF) || !value || !handler_context)
13281353
return AE_BAD_PARAMETER;
13291354

13301355
if (function != ACPI_READ && function != ACPI_WRITE)
13311356
return AE_BAD_PARAMETER;
13321357

1358+
mutex_lock(&ec->mutex);
1359+
1360+
if (ec->global_lock) {
1361+
acpi_status status;
1362+
1363+
status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
1364+
if (ACPI_FAILURE(status)) {
1365+
result = -ENODEV;
1366+
goto unlock;
1367+
}
1368+
}
1369+
13331370
if (ec->busy_polling || bits > 8)
13341371
acpi_ec_burst_enable(ec);
13351372

13361373
for (i = 0; i < bytes; ++i, ++address, ++value) {
13371374
result = (function == ACPI_READ) ?
1338-
acpi_ec_read(ec, address, value) :
1339-
acpi_ec_write(ec, address, *value);
1375+
acpi_ec_read_unlocked(ec, address, value) :
1376+
acpi_ec_write_unlocked(ec, address, *value);
13401377
if (result < 0)
13411378
break;
13421379
}
13431380

13441381
if (ec->busy_polling || bits > 8)
13451382
acpi_ec_burst_disable(ec);
13461383

1384+
if (ec->global_lock)
1385+
acpi_release_global_lock(glk);
1386+
1387+
unlock:
1388+
mutex_unlock(&ec->mutex);
1389+
13471390
switch (result) {
13481391
case -EINVAL:
13491392
return AE_BAD_PARAMETER;

0 commit comments

Comments
 (0)