ACPI / EC: Add EC_FLAGS_QUERY_ENABLED to reveal a hidden logic

There is a hidden logic in the EC driver:
1. During boot, EC_FLAGS_QUERY_PENDING is responsible for blocking event
   handling;
2. During suspend, EC_FLAGS_STARTED is responsible for blocking event
   handling.
This patch uses a new EC_FLAGS_QUERY_ENABLED flag to make this hidden
logic explicit and have code cleaned up. No functional change.

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
Tested-by: Todd E Brandt <todd.e.brandt@linux.intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
This commit is contained in:
Lv Zheng 2016-08-03 16:01:24 +08:00 committed by Rafael J. Wysocki
parent df45db6177
commit 750f628be6
1 changed files with 71 additions and 32 deletions

View File

@ -104,6 +104,7 @@ enum ec_command {
#define ACPI_EC_MAX_QUERIES 16 /* Maximum number of parallel queries */
enum {
EC_FLAGS_QUERY_ENABLED, /* Query is enabled */
EC_FLAGS_QUERY_PENDING, /* Query is pending */
EC_FLAGS_QUERY_GUARDING, /* Guard for SCI_EVT check */
EC_FLAGS_GPE_HANDLER_INSTALLED, /* GPE handler installed */
@ -239,6 +240,22 @@ static bool acpi_ec_started(struct acpi_ec *ec)
!test_bit(EC_FLAGS_STOPPED, &ec->flags);
}
static bool acpi_ec_event_enabled(struct acpi_ec *ec)
{
/*
* There is an OSPM early stage logic. During the early stages
* (boot/resume), OSPMs shouldn't enable the event handling, only
* the EC transactions are allowed to be performed.
*/
if (!test_bit(EC_FLAGS_QUERY_ENABLED, &ec->flags))
return false;
/*
* The EC event handling is automatically disabled as soon as the
* EC driver is stopped.
*/
return test_bit(EC_FLAGS_STARTED, &ec->flags);
}
static bool acpi_ec_flushed(struct acpi_ec *ec)
{
return ec->reference_count == 1;
@ -429,7 +446,8 @@ static bool acpi_ec_submit_flushable_request(struct acpi_ec *ec)
static void acpi_ec_submit_query(struct acpi_ec *ec)
{
if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) {
if (acpi_ec_event_enabled(ec) &&
!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) {
ec_dbg_evt("Command(%s) submitted/blocked",
acpi_ec_cmd_string(ACPI_EC_COMMAND_QUERY));
ec->nr_pending_queries++;
@ -446,6 +464,52 @@ static void acpi_ec_complete_query(struct acpi_ec *ec)
}
}
static inline void __acpi_ec_enable_event(struct acpi_ec *ec)
{
if (!test_and_set_bit(EC_FLAGS_QUERY_ENABLED, &ec->flags))
ec_log_drv("event unblocked");
}
static inline void __acpi_ec_disable_event(struct acpi_ec *ec)
{
if (test_and_clear_bit(EC_FLAGS_QUERY_ENABLED, &ec->flags))
ec_log_drv("event blocked");
}
/*
* Process _Q events that might have accumulated in the EC.
* Run with locked ec mutex.
*/
static void acpi_ec_clear(struct acpi_ec *ec)
{
int i, status;
u8 value = 0;
for (i = 0; i < ACPI_EC_CLEAR_MAX; i++) {
status = acpi_ec_query(ec, &value);
if (status || !value)
break;
}
if (unlikely(i == ACPI_EC_CLEAR_MAX))
pr_warn("Warning: Maximum of %d stale EC events cleared\n", i);
else
pr_info("%d stale EC events cleared\n", i);
}
static void acpi_ec_enable_event(struct acpi_ec *ec)
{
unsigned long flags;
spin_lock_irqsave(&ec->lock, flags);
if (acpi_ec_started(ec))
__acpi_ec_enable_event(ec);
spin_unlock_irqrestore(&ec->lock, flags);
/* Drain additional events if hardware requires that */
if (EC_FLAGS_CLEAR_ON_RESUME)
acpi_ec_clear(ec);
}
static bool acpi_ec_guard_event(struct acpi_ec *ec)
{
bool guarded = true;
@ -832,27 +896,6 @@ acpi_handle ec_get_handle(void)
}
EXPORT_SYMBOL(ec_get_handle);
/*
* Process _Q events that might have accumulated in the EC.
* Run with locked ec mutex.
*/
static void acpi_ec_clear(struct acpi_ec *ec)
{
int i, status;
u8 value = 0;
for (i = 0; i < ACPI_EC_CLEAR_MAX; i++) {
status = acpi_ec_query(ec, &value);
if (status || !value)
break;
}
if (unlikely(i == ACPI_EC_CLEAR_MAX))
pr_warn("Warning: Maximum of %d stale EC events cleared\n", i);
else
pr_info("%d stale EC events cleared\n", i);
}
static void acpi_ec_start(struct acpi_ec *ec, bool resuming)
{
unsigned long flags;
@ -864,7 +907,8 @@ static void acpi_ec_start(struct acpi_ec *ec, bool resuming)
if (!resuming) {
acpi_ec_submit_request(ec);
ec_dbg_ref(ec, "Increase driver");
}
} else
__acpi_ec_enable_event(ec);
ec_log_drv("EC started");
}
spin_unlock_irqrestore(&ec->lock, flags);
@ -896,7 +940,8 @@ static void acpi_ec_stop(struct acpi_ec *ec, bool suspending)
if (!suspending) {
acpi_ec_complete_request(ec);
ec_dbg_ref(ec, "Decrease driver");
}
} else
__acpi_ec_disable_event(ec);
clear_bit(EC_FLAGS_STARTED, &ec->flags);
clear_bit(EC_FLAGS_STOPPED, &ec->flags);
ec_log_drv("EC stopped");
@ -927,8 +972,7 @@ void acpi_ec_unblock_transactions(void)
/* Allow transactions to be carried out again */
acpi_ec_start(ec, true);
if (EC_FLAGS_CLEAR_ON_RESUME)
acpi_ec_clear(ec);
acpi_ec_enable_event(ec);
}
void acpi_ec_unblock_transactions_early(void)
@ -1234,7 +1278,6 @@ static struct acpi_ec *make_acpi_ec(void)
if (!ec)
return NULL;
ec->flags = 1 << EC_FLAGS_QUERY_PENDING;
mutex_init(&ec->mutex);
init_waitqueue_head(&ec->wait);
INIT_LIST_HEAD(&ec->list);
@ -1421,11 +1464,7 @@ static int acpi_ec_add(struct acpi_device *device)
acpi_walk_dep_device_list(ec->handle);
/* EC is fully operational, allow queries */
clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags);
/* Clear stale _Q events if hardware might require that */
if (EC_FLAGS_CLEAR_ON_RESUME)
acpi_ec_clear(ec);
acpi_ec_enable_event(ec);
return ret;
}