Skip to content

Commit c33676a

Browse files
committed
ACPI: EC: Make the event work state machine visible
The EC driver uses a relatively simple state machine for the event work handling, but it is not really straightforward to figure out. The states are as follows: "Ready": The event handling work can be submitted. In this state, the EC_FLAGS_QUERY_PENDING flag is clear. "In progress": The event handling work is pending or is being processed. It cannot be submitted again. In ths state, the EC_FLAGS_QUERY_PENDING flag is set and both the events_to_process count is nonzero and the EC_FLAGS_QUERY_GUARDING flag is clear. "Complete": The event handling work has been completed, but it still cannot be submitted again. In ths state, the EC_FLAGS_QUERY_PENDING flag is set and the events_to_process count is zero or the EC_FLAGS_QUERY_GUARDING flag is set. The state changes from "Ready" to "In progress" when new event is detected by advance_transaction() and acpi_ec_submit_event() is called by it. Next, the state can change from "In progress" directly to "Ready" in the following situations: * ec_event_clearing is ACPI_EC_EVT_TIMING_STATUS and the state of an ACPI_EC_COMMAND_QUERY transaction becomes ACPI_EC_COMMAND_POLL. * ec_event_clearing is ACPI_EC_EVT_TIMING_QUERY and the state of an ACPI_EC_COMMAND_QUERY transaction becomes ACPI_EC_COMMAND_COMPLETE. * ec_event_clearing is either ACPI_EC_EVT_TIMING_STATUS or ACPI_EC_EVT_TIMING_QUERY and there are no more events to process (ie. ec->events_to_process becomes 0). If ec_event_clearing is ACPI_EC_EVT_TIMING_EVENT, however, the state must change from "In progress" to "Complete" before it can change to "Ready". The changes from "In progress" to "Complete" in that case occur in the following situations: * The state of an ACPI_EC_COMMAND_QUERY transaction becomes ACPI_EC_COMMAND_COMPLETE. * There are no more events to process (ie. ec->events_to_process becomes 0). Finally, the state changes from "Complete" to "Ready" when advance_transaction() is invoked when the state is "Complete" and the state of the current transaction is not ACPI_EC_COMMAND_POLL. To make this state machine visible in the code, add a new event_state field to struct acpi_ec and modify the code to use it istead the EC_FLAGS_QUERY_PENDING and EC_FLAGS_QUERY_GUARDING flags. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
1 parent c793570 commit c33676a

2 files changed

Lines changed: 52 additions & 31 deletions

File tree

drivers/acpi/ec.c

Lines changed: 44 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,6 @@ enum ec_command {
9292

9393
enum {
9494
EC_FLAGS_QUERY_ENABLED, /* Query is enabled */
95-
EC_FLAGS_QUERY_PENDING, /* Query is pending */
96-
EC_FLAGS_QUERY_GUARDING, /* Guard for SCI_EVT check */
9795
EC_FLAGS_EVENT_HANDLER_INSTALLED, /* Event handler installed */
9896
EC_FLAGS_EC_HANDLER_INSTALLED, /* OpReg handler installed */
9997
EC_FLAGS_QUERY_METHODS_INSTALLED, /* _Qxx handlers installed */
@@ -450,9 +448,11 @@ static bool acpi_ec_submit_event(struct acpi_ec *ec)
450448
if (!acpi_ec_event_enabled(ec))
451449
return false;
452450

453-
if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) {
451+
if (ec->event_state == EC_EVENT_READY) {
454452
ec_dbg_evt("Command(%s) submitted/blocked",
455453
acpi_ec_cmd_string(ACPI_EC_COMMAND_QUERY));
454+
455+
ec->event_state = EC_EVENT_IN_PROGRESS;
456456
/*
457457
* If events_to_process is greqter than 0 at this point, the
458458
* while () loop in acpi_ec_event_handler() is still running
@@ -474,11 +474,19 @@ static bool acpi_ec_submit_event(struct acpi_ec *ec)
474474
return true;
475475
}
476476

477+
static void acpi_ec_complete_event(struct acpi_ec *ec)
478+
{
479+
if (ec->event_state == EC_EVENT_IN_PROGRESS)
480+
ec->event_state = EC_EVENT_COMPLETE;
481+
}
482+
477483
static void acpi_ec_close_event(struct acpi_ec *ec)
478484
{
479-
if (test_and_clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags))
485+
if (ec->event_state != EC_EVENT_READY)
480486
ec_dbg_evt("Command(%s) unblocked",
481487
acpi_ec_cmd_string(ACPI_EC_COMMAND_QUERY));
488+
489+
ec->event_state = EC_EVENT_READY;
482490
acpi_ec_unmask_events(ec);
483491
}
484492

@@ -565,8 +573,8 @@ void acpi_ec_flush_work(void)
565573

566574
static bool acpi_ec_guard_event(struct acpi_ec *ec)
567575
{
568-
bool guarded = true;
569576
unsigned long flags;
577+
bool guarded;
570578

571579
spin_lock_irqsave(&ec->lock, flags);
572580
/*
@@ -575,19 +583,15 @@ static bool acpi_ec_guard_event(struct acpi_ec *ec)
575583
* evaluating _Qxx, so we need to re-check SCI_EVT after waiting an
576584
* acceptable period.
577585
*
578-
* The guarding period begins when EC_FLAGS_QUERY_PENDING is
579-
* flagged, which means SCI_EVT check has just been performed.
580-
* But if the current transaction is ACPI_EC_COMMAND_QUERY, the
581-
* guarding should have already been performed (via
582-
* EC_FLAGS_QUERY_GUARDING) and should not be applied so that the
583-
* ACPI_EC_COMMAND_QUERY transaction can be transitioned into
584-
* ACPI_EC_COMMAND_POLL state immediately.
586+
* The guarding period is applicable if the event state is not
587+
* EC_EVENT_READY, but otherwise if the current transaction is of the
588+
* ACPI_EC_COMMAND_QUERY type, the guarding should have elapsed already
589+
* and it should not be applied to let the transaction transition into
590+
* the ACPI_EC_COMMAND_POLL state immediately.
585591
*/
586-
if (ec_event_clearing == ACPI_EC_EVT_TIMING_STATUS ||
587-
ec_event_clearing == ACPI_EC_EVT_TIMING_QUERY ||
588-
!test_bit(EC_FLAGS_QUERY_PENDING, &ec->flags) ||
589-
(ec->curr && ec->curr->command == ACPI_EC_COMMAND_QUERY))
590-
guarded = false;
592+
guarded = ec_event_clearing == ACPI_EC_EVT_TIMING_EVENT &&
593+
ec->event_state != EC_EVENT_READY &&
594+
(!ec->curr || ec->curr->command != ACPI_EC_COMMAND_QUERY);
591595
spin_unlock_irqrestore(&ec->lock, flags);
592596
return guarded;
593597
}
@@ -619,16 +623,26 @@ static int ec_transaction_completed(struct acpi_ec *ec)
619623
static inline void ec_transaction_transition(struct acpi_ec *ec, unsigned long flag)
620624
{
621625
ec->curr->flags |= flag;
622-
if (ec->curr->command == ACPI_EC_COMMAND_QUERY) {
623-
if (ec_event_clearing == ACPI_EC_EVT_TIMING_STATUS &&
624-
flag == ACPI_EC_COMMAND_POLL)
626+
627+
if (ec->curr->command != ACPI_EC_COMMAND_QUERY)
628+
return;
629+
630+
switch (ec_event_clearing) {
631+
case ACPI_EC_EVT_TIMING_STATUS:
632+
if (flag == ACPI_EC_COMMAND_POLL)
625633
acpi_ec_close_event(ec);
626-
if (ec_event_clearing == ACPI_EC_EVT_TIMING_QUERY &&
627-
flag == ACPI_EC_COMMAND_COMPLETE)
634+
635+
return;
636+
637+
case ACPI_EC_EVT_TIMING_QUERY:
638+
if (flag == ACPI_EC_COMMAND_COMPLETE)
628639
acpi_ec_close_event(ec);
629-
if (ec_event_clearing == ACPI_EC_EVT_TIMING_EVENT &&
630-
flag == ACPI_EC_COMMAND_COMPLETE)
631-
set_bit(EC_FLAGS_QUERY_GUARDING, &ec->flags);
640+
641+
return;
642+
643+
case ACPI_EC_EVT_TIMING_EVENT:
644+
if (flag == ACPI_EC_COMMAND_COMPLETE)
645+
acpi_ec_complete_event(ec);
632646
}
633647
}
634648

@@ -674,11 +688,9 @@ static bool advance_transaction(struct acpi_ec *ec, bool interrupt)
674688
*/
675689
if (!t || !(t->flags & ACPI_EC_COMMAND_POLL)) {
676690
if (ec_event_clearing == ACPI_EC_EVT_TIMING_EVENT &&
677-
(!ec->events_to_process ||
678-
test_bit(EC_FLAGS_QUERY_GUARDING, &ec->flags))) {
679-
clear_bit(EC_FLAGS_QUERY_GUARDING, &ec->flags);
691+
ec->event_state == EC_EVENT_COMPLETE)
680692
acpi_ec_close_event(ec);
681-
}
693+
682694
if (!t)
683695
goto out;
684696
}
@@ -1246,8 +1258,9 @@ static void acpi_ec_event_handler(struct work_struct *work)
12461258
* event handling work again regardless of whether or not the query
12471259
* queued up above is processed successfully.
12481260
*/
1249-
if (ec_event_clearing == ACPI_EC_EVT_TIMING_STATUS ||
1250-
ec_event_clearing == ACPI_EC_EVT_TIMING_QUERY)
1261+
if (ec_event_clearing == ACPI_EC_EVT_TIMING_EVENT)
1262+
acpi_ec_complete_event(ec);
1263+
else
12511264
acpi_ec_close_event(ec);
12521265

12531266
spin_unlock_irq(&ec->lock);

drivers/acpi/internal.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,13 @@ static inline void acpi_early_processor_osc(void) {}
166166
/* --------------------------------------------------------------------------
167167
Embedded Controller
168168
-------------------------------------------------------------------------- */
169+
170+
enum acpi_ec_event_state {
171+
EC_EVENT_READY = 0, /* Event work can be submitted */
172+
EC_EVENT_IN_PROGRESS, /* Event work is pending or being processed */
173+
EC_EVENT_COMPLETE, /* Event work processing has completed */
174+
};
175+
169176
struct acpi_ec {
170177
acpi_handle handle;
171178
int gpe;
@@ -182,6 +189,7 @@ struct acpi_ec {
182189
spinlock_t lock;
183190
struct work_struct work;
184191
unsigned long timestamp;
192+
enum acpi_ec_event_state event_state;
185193
unsigned int events_to_process;
186194
unsigned int events_in_progress;
187195
unsigned int queries_in_progress;

0 commit comments

Comments
 (0)