Commit 5847d2d2 authored by Rafael J. Wysocki's avatar Rafael J. Wysocki

Merge branches 'acpi-ec' and 'acpi-processor'

Merge ACPI EC driver updates and ACPI processor driver updates for
5.17-rc1:

 - Rework flushing of EC work while suspended to idle and clean up
   the handling of events in the ACPI EC driver (Rafael Wysocki).

 - Prohibit ec_sys module parameter write_support from being used
   when the system is locked down (Hans de Goede).

 - Make the ACPI processor thermal driver use cpufreq_cpu_get() to
   check for presence of cpufreq policy (Manfred Spraul).

 - Avoid unnecessary CPU cache flushing in the ACPI processor idle
   driver (Kirill A. Shutemov).

 - Replace kernel.h with the necessary inclusions in the ACPI
   processor driver (Andy Shevchenko).

 - Use swap() instead of open coding it in the ACPI processor idle
   driver (Guo Zhengkui).

* acpi-ec:
  ACPI: EC: Mark the ec_sys write_support param as module_param_hw()
  ACPI: EC: Relocate acpi_ec_create_query() and drop acpi_ec_delete_query()
  ACPI: EC: Make the event work state machine visible
  ACPI: EC: Avoid queuing unnecessary work in acpi_ec_submit_event()
  ACPI: EC: Rename three functions
  ACPI: EC: Simplify locking in acpi_ec_event_handler()
  ACPI: EC: Rearrange the loop in acpi_ec_event_handler()
  ACPI: EC: Fold acpi_ec_check_event() into acpi_ec_event_handler()
  ACPI: EC: Pass one argument to acpi_ec_query()
  ACPI: EC: Call advance_transaction() from acpi_ec_dispatch_gpe()
  ACPI: EC: Rework flushing of EC work while suspended to idle

* acpi-processor:
  ACPI: processor: thermal: avoid cpufreq_get_policy()
  ACPI: processor: idle: Only flush cache on entering C3
  ACPI: processor idle: Use swap() instead of open coding it
  ACPI: processor: Replace kernel.h with the necessary inclusions
...@@ -92,8 +92,6 @@ enum ec_command { ...@@ -92,8 +92,6 @@ enum ec_command {
enum { enum {
EC_FLAGS_QUERY_ENABLED, /* Query is enabled */ 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_EVENT_HANDLER_INSTALLED, /* Event handler installed */ EC_FLAGS_EVENT_HANDLER_INSTALLED, /* Event handler installed */
EC_FLAGS_EC_HANDLER_INSTALLED, /* OpReg handler installed */ EC_FLAGS_EC_HANDLER_INSTALLED, /* OpReg handler installed */
EC_FLAGS_QUERY_METHODS_INSTALLED, /* _Qxx handlers installed */ EC_FLAGS_QUERY_METHODS_INSTALLED, /* _Qxx handlers installed */
...@@ -166,12 +164,12 @@ struct acpi_ec_query { ...@@ -166,12 +164,12 @@ struct acpi_ec_query {
struct transaction transaction; struct transaction transaction;
struct work_struct work; struct work_struct work;
struct acpi_ec_query_handler *handler; struct acpi_ec_query_handler *handler;
struct acpi_ec *ec;
}; };
static int acpi_ec_query(struct acpi_ec *ec, u8 *data); static int acpi_ec_submit_query(struct acpi_ec *ec);
static void advance_transaction(struct acpi_ec *ec, bool interrupt); static bool advance_transaction(struct acpi_ec *ec, bool interrupt);
static void acpi_ec_event_handler(struct work_struct *work); static void acpi_ec_event_handler(struct work_struct *work);
static void acpi_ec_event_processor(struct work_struct *work);
struct acpi_ec *first_ec; struct acpi_ec *first_ec;
EXPORT_SYMBOL(first_ec); EXPORT_SYMBOL(first_ec);
...@@ -443,24 +441,51 @@ static bool acpi_ec_submit_flushable_request(struct acpi_ec *ec) ...@@ -443,24 +441,51 @@ static bool acpi_ec_submit_flushable_request(struct acpi_ec *ec)
return true; return true;
} }
static void acpi_ec_submit_query(struct acpi_ec *ec) static bool acpi_ec_submit_event(struct acpi_ec *ec)
{ {
acpi_ec_mask_events(ec); acpi_ec_mask_events(ec);
if (!acpi_ec_event_enabled(ec)) if (!acpi_ec_event_enabled(ec))
return; return false;
if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) {
if (ec->event_state == EC_EVENT_READY) {
ec_dbg_evt("Command(%s) submitted/blocked", ec_dbg_evt("Command(%s) submitted/blocked",
acpi_ec_cmd_string(ACPI_EC_COMMAND_QUERY)); acpi_ec_cmd_string(ACPI_EC_COMMAND_QUERY));
ec->nr_pending_queries++;
queue_work(ec_wq, &ec->work); ec->event_state = EC_EVENT_IN_PROGRESS;
/*
* If events_to_process is greqter than 0 at this point, the
* while () loop in acpi_ec_event_handler() is still running
* and incrementing events_to_process will cause it to invoke
* acpi_ec_submit_query() once more, so it is not necessary to
* queue up the event work to start the same loop again.
*/
if (ec->events_to_process++ > 0)
return true;
ec->events_in_progress++;
return queue_work(ec_wq, &ec->work);
} }
/*
* The event handling work has not been completed yet, so it needs to be
* flushed.
*/
return true;
}
static void acpi_ec_complete_event(struct acpi_ec *ec)
{
if (ec->event_state == EC_EVENT_IN_PROGRESS)
ec->event_state = EC_EVENT_COMPLETE;
} }
static void acpi_ec_complete_query(struct acpi_ec *ec) static void acpi_ec_close_event(struct acpi_ec *ec)
{ {
if (test_and_clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) if (ec->event_state != EC_EVENT_READY)
ec_dbg_evt("Command(%s) unblocked", ec_dbg_evt("Command(%s) unblocked",
acpi_ec_cmd_string(ACPI_EC_COMMAND_QUERY)); acpi_ec_cmd_string(ACPI_EC_COMMAND_QUERY));
ec->event_state = EC_EVENT_READY;
acpi_ec_unmask_events(ec); acpi_ec_unmask_events(ec);
} }
...@@ -487,12 +512,10 @@ static inline void __acpi_ec_disable_event(struct acpi_ec *ec) ...@@ -487,12 +512,10 @@ static inline void __acpi_ec_disable_event(struct acpi_ec *ec)
*/ */
static void acpi_ec_clear(struct acpi_ec *ec) static void acpi_ec_clear(struct acpi_ec *ec)
{ {
int i, status; int i;
u8 value = 0;
for (i = 0; i < ACPI_EC_CLEAR_MAX; i++) { for (i = 0; i < ACPI_EC_CLEAR_MAX; i++) {
status = acpi_ec_query(ec, &value); if (acpi_ec_submit_query(ec))
if (status || !value)
break; break;
} }
if (unlikely(i == ACPI_EC_CLEAR_MAX)) if (unlikely(i == ACPI_EC_CLEAR_MAX))
...@@ -518,7 +541,7 @@ static void acpi_ec_enable_event(struct acpi_ec *ec) ...@@ -518,7 +541,7 @@ static void acpi_ec_enable_event(struct acpi_ec *ec)
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
static void __acpi_ec_flush_work(void) static void __acpi_ec_flush_work(void)
{ {
drain_workqueue(ec_wq); /* flush ec->work */ flush_workqueue(ec_wq); /* flush ec->work */
flush_workqueue(ec_query_wq); /* flush queries */ flush_workqueue(ec_query_wq); /* flush queries */
} }
...@@ -549,8 +572,8 @@ void acpi_ec_flush_work(void) ...@@ -549,8 +572,8 @@ void acpi_ec_flush_work(void)
static bool acpi_ec_guard_event(struct acpi_ec *ec) static bool acpi_ec_guard_event(struct acpi_ec *ec)
{ {
bool guarded = true;
unsigned long flags; unsigned long flags;
bool guarded;
spin_lock_irqsave(&ec->lock, flags); spin_lock_irqsave(&ec->lock, flags);
/* /*
...@@ -559,19 +582,15 @@ static bool acpi_ec_guard_event(struct acpi_ec *ec) ...@@ -559,19 +582,15 @@ static bool acpi_ec_guard_event(struct acpi_ec *ec)
* evaluating _Qxx, so we need to re-check SCI_EVT after waiting an * evaluating _Qxx, so we need to re-check SCI_EVT after waiting an
* acceptable period. * acceptable period.
* *
* The guarding period begins when EC_FLAGS_QUERY_PENDING is * The guarding period is applicable if the event state is not
* flagged, which means SCI_EVT check has just been performed. * EC_EVENT_READY, but otherwise if the current transaction is of the
* But if the current transaction is ACPI_EC_COMMAND_QUERY, the * ACPI_EC_COMMAND_QUERY type, the guarding should have elapsed already
* guarding should have already been performed (via * and it should not be applied to let the transaction transition into
* EC_FLAGS_QUERY_GUARDING) and should not be applied so that the * the ACPI_EC_COMMAND_POLL state immediately.
* ACPI_EC_COMMAND_QUERY transaction can be transitioned into
* ACPI_EC_COMMAND_POLL state immediately.
*/ */
if (ec_event_clearing == ACPI_EC_EVT_TIMING_STATUS || guarded = ec_event_clearing == ACPI_EC_EVT_TIMING_EVENT &&
ec_event_clearing == ACPI_EC_EVT_TIMING_QUERY || ec->event_state != EC_EVENT_READY &&
!test_bit(EC_FLAGS_QUERY_PENDING, &ec->flags) || (!ec->curr || ec->curr->command != ACPI_EC_COMMAND_QUERY);
(ec->curr && ec->curr->command == ACPI_EC_COMMAND_QUERY))
guarded = false;
spin_unlock_irqrestore(&ec->lock, flags); spin_unlock_irqrestore(&ec->lock, flags);
return guarded; return guarded;
} }
...@@ -603,16 +622,26 @@ static int ec_transaction_completed(struct acpi_ec *ec) ...@@ -603,16 +622,26 @@ static int ec_transaction_completed(struct acpi_ec *ec)
static inline void ec_transaction_transition(struct acpi_ec *ec, unsigned long flag) static inline void ec_transaction_transition(struct acpi_ec *ec, unsigned long flag)
{ {
ec->curr->flags |= flag; ec->curr->flags |= flag;
if (ec->curr->command == ACPI_EC_COMMAND_QUERY) {
if (ec_event_clearing == ACPI_EC_EVT_TIMING_STATUS && if (ec->curr->command != ACPI_EC_COMMAND_QUERY)
flag == ACPI_EC_COMMAND_POLL) return;
acpi_ec_complete_query(ec);
if (ec_event_clearing == ACPI_EC_EVT_TIMING_QUERY && switch (ec_event_clearing) {
flag == ACPI_EC_COMMAND_COMPLETE) case ACPI_EC_EVT_TIMING_STATUS:
acpi_ec_complete_query(ec); if (flag == ACPI_EC_COMMAND_POLL)
if (ec_event_clearing == ACPI_EC_EVT_TIMING_EVENT && acpi_ec_close_event(ec);
flag == ACPI_EC_COMMAND_COMPLETE)
set_bit(EC_FLAGS_QUERY_GUARDING, &ec->flags); return;
case ACPI_EC_EVT_TIMING_QUERY:
if (flag == ACPI_EC_COMMAND_COMPLETE)
acpi_ec_close_event(ec);
return;
case ACPI_EC_EVT_TIMING_EVENT:
if (flag == ACPI_EC_COMMAND_COMPLETE)
acpi_ec_complete_event(ec);
} }
} }
...@@ -626,10 +655,11 @@ static void acpi_ec_spurious_interrupt(struct acpi_ec *ec, struct transaction *t ...@@ -626,10 +655,11 @@ static void acpi_ec_spurious_interrupt(struct acpi_ec *ec, struct transaction *t
acpi_ec_mask_events(ec); acpi_ec_mask_events(ec);
} }
static void advance_transaction(struct acpi_ec *ec, bool interrupt) static bool advance_transaction(struct acpi_ec *ec, bool interrupt)
{ {
struct transaction *t = ec->curr; struct transaction *t = ec->curr;
bool wakeup = false; bool wakeup = false;
bool ret = false;
u8 status; u8 status;
ec_dbg_stm("%s (%d)", interrupt ? "IRQ" : "TASK", smp_processor_id()); ec_dbg_stm("%s (%d)", interrupt ? "IRQ" : "TASK", smp_processor_id());
...@@ -657,11 +687,9 @@ static void advance_transaction(struct acpi_ec *ec, bool interrupt) ...@@ -657,11 +687,9 @@ static void advance_transaction(struct acpi_ec *ec, bool interrupt)
*/ */
if (!t || !(t->flags & ACPI_EC_COMMAND_POLL)) { if (!t || !(t->flags & ACPI_EC_COMMAND_POLL)) {
if (ec_event_clearing == ACPI_EC_EVT_TIMING_EVENT && if (ec_event_clearing == ACPI_EC_EVT_TIMING_EVENT &&
(!ec->nr_pending_queries || ec->event_state == EC_EVENT_COMPLETE)
test_bit(EC_FLAGS_QUERY_GUARDING, &ec->flags))) { acpi_ec_close_event(ec);
clear_bit(EC_FLAGS_QUERY_GUARDING, &ec->flags);
acpi_ec_complete_query(ec);
}
if (!t) if (!t)
goto out; goto out;
} }
...@@ -696,10 +724,12 @@ static void advance_transaction(struct acpi_ec *ec, bool interrupt) ...@@ -696,10 +724,12 @@ static void advance_transaction(struct acpi_ec *ec, bool interrupt)
out: out:
if (status & ACPI_EC_FLAG_SCI) if (status & ACPI_EC_FLAG_SCI)
acpi_ec_submit_query(ec); ret = acpi_ec_submit_event(ec);
if (wakeup && interrupt) if (wakeup && interrupt)
wake_up(&ec->wait); wake_up(&ec->wait);
return ret;
} }
static void start_transaction(struct acpi_ec *ec) static void start_transaction(struct acpi_ec *ec)
...@@ -1103,7 +1133,30 @@ void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit) ...@@ -1103,7 +1133,30 @@ void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit)
} }
EXPORT_SYMBOL_GPL(acpi_ec_remove_query_handler); EXPORT_SYMBOL_GPL(acpi_ec_remove_query_handler);
static struct acpi_ec_query *acpi_ec_create_query(u8 *pval) static void acpi_ec_event_processor(struct work_struct *work)
{
struct acpi_ec_query *q = container_of(work, struct acpi_ec_query, work);
struct acpi_ec_query_handler *handler = q->handler;
struct acpi_ec *ec = q->ec;
ec_dbg_evt("Query(0x%02x) started", handler->query_bit);
if (handler->func)
handler->func(handler->data);
else if (handler->handle)
acpi_evaluate_object(handler->handle, NULL, NULL, NULL);
ec_dbg_evt("Query(0x%02x) stopped", handler->query_bit);
spin_lock_irq(&ec->lock);
ec->queries_in_progress--;
spin_unlock_irq(&ec->lock);
acpi_ec_put_query_handler(handler);
kfree(q);
}
static struct acpi_ec_query *acpi_ec_create_query(struct acpi_ec *ec, u8 *pval)
{ {
struct acpi_ec_query *q; struct acpi_ec_query *q;
struct transaction *t; struct transaction *t;
...@@ -1111,44 +1164,23 @@ static struct acpi_ec_query *acpi_ec_create_query(u8 *pval) ...@@ -1111,44 +1164,23 @@ static struct acpi_ec_query *acpi_ec_create_query(u8 *pval)
q = kzalloc(sizeof (struct acpi_ec_query), GFP_KERNEL); q = kzalloc(sizeof (struct acpi_ec_query), GFP_KERNEL);
if (!q) if (!q)
return NULL; return NULL;
INIT_WORK(&q->work, acpi_ec_event_processor); INIT_WORK(&q->work, acpi_ec_event_processor);
t = &q->transaction; t = &q->transaction;
t->command = ACPI_EC_COMMAND_QUERY; t->command = ACPI_EC_COMMAND_QUERY;
t->rdata = pval; t->rdata = pval;
t->rlen = 1; t->rlen = 1;
q->ec = ec;
return q; return q;
} }
static void acpi_ec_delete_query(struct acpi_ec_query *q) static int acpi_ec_submit_query(struct acpi_ec *ec)
{
if (q) {
if (q->handler)
acpi_ec_put_query_handler(q->handler);
kfree(q);
}
}
static void acpi_ec_event_processor(struct work_struct *work)
{
struct acpi_ec_query *q = container_of(work, struct acpi_ec_query, work);
struct acpi_ec_query_handler *handler = q->handler;
ec_dbg_evt("Query(0x%02x) started", handler->query_bit);
if (handler->func)
handler->func(handler->data);
else if (handler->handle)
acpi_evaluate_object(handler->handle, NULL, NULL, NULL);
ec_dbg_evt("Query(0x%02x) stopped", handler->query_bit);
acpi_ec_delete_query(q);
}
static int acpi_ec_query(struct acpi_ec *ec, u8 *data)
{ {
struct acpi_ec_query *q;
u8 value = 0; u8 value = 0;
int result; int result;
struct acpi_ec_query *q;
q = acpi_ec_create_query(&value); q = acpi_ec_create_query(ec, &value);
if (!q) if (!q)
return -ENOMEM; return -ENOMEM;
...@@ -1158,11 +1190,14 @@ static int acpi_ec_query(struct acpi_ec *ec, u8 *data) ...@@ -1158,11 +1190,14 @@ static int acpi_ec_query(struct acpi_ec *ec, u8 *data)
* bit to be cleared (and thus clearing the interrupt source). * bit to be cleared (and thus clearing the interrupt source).
*/ */
result = acpi_ec_transaction(ec, &q->transaction); result = acpi_ec_transaction(ec, &q->transaction);
if (!value)
result = -ENODATA;
if (result) if (result)
goto err_exit; goto err_exit;
if (!value) {
result = -ENODATA;
goto err_exit;
}
q->handler = acpi_ec_get_query_handler_by_value(ec, value); q->handler = acpi_ec_get_query_handler_by_value(ec, value);
if (!q->handler) { if (!q->handler) {
result = -ENODATA; result = -ENODATA;
...@@ -1170,76 +1205,73 @@ static int acpi_ec_query(struct acpi_ec *ec, u8 *data) ...@@ -1170,76 +1205,73 @@ static int acpi_ec_query(struct acpi_ec *ec, u8 *data)
} }
/* /*
* It is reported that _Qxx are evaluated in a parallel way on * It is reported that _Qxx are evaluated in a parallel way on Windows:
* Windows:
* https://bugzilla.kernel.org/show_bug.cgi?id=94411 * https://bugzilla.kernel.org/show_bug.cgi?id=94411
* *
* Put this log entry before schedule_work() in order to make * Put this log entry before queue_work() to make it appear in the log
* it appearing before any other log entries occurred during the * before any other messages emitted during workqueue handling.
* work queue execution.
*/ */
ec_dbg_evt("Query(0x%02x) scheduled", value); ec_dbg_evt("Query(0x%02x) scheduled", value);
if (!queue_work(ec_query_wq, &q->work)) {
ec_dbg_evt("Query(0x%02x) overlapped", value);
result = -EBUSY;
}
err_exit: spin_lock_irq(&ec->lock);
if (result)
acpi_ec_delete_query(q);
if (data)
*data = value;
return result;
}
static void acpi_ec_check_event(struct acpi_ec *ec) ec->queries_in_progress++;
{ queue_work(ec_query_wq, &q->work);
unsigned long flags;
if (ec_event_clearing == ACPI_EC_EVT_TIMING_EVENT) { spin_unlock_irq(&ec->lock);
if (ec_guard(ec)) {
spin_lock_irqsave(&ec->lock, flags); return 0;
/*
* Take care of the SCI_EVT unless no one else is err_exit:
* taking care of it. kfree(q);
*/
if (!ec->curr) return result;
advance_transaction(ec, false);
spin_unlock_irqrestore(&ec->lock, flags);
}
}
} }
static void acpi_ec_event_handler(struct work_struct *work) static void acpi_ec_event_handler(struct work_struct *work)
{ {
unsigned long flags;
struct acpi_ec *ec = container_of(work, struct acpi_ec, work); struct acpi_ec *ec = container_of(work, struct acpi_ec, work);
ec_dbg_evt("Event started"); ec_dbg_evt("Event started");
spin_lock_irqsave(&ec->lock, flags); spin_lock_irq(&ec->lock);
while (ec->nr_pending_queries) {
spin_unlock_irqrestore(&ec->lock, flags); while (ec->events_to_process) {
(void)acpi_ec_query(ec, NULL); spin_unlock_irq(&ec->lock);
spin_lock_irqsave(&ec->lock, flags);
ec->nr_pending_queries--; acpi_ec_submit_query(ec);
/*
* Before exit, make sure that this work item can be spin_lock_irq(&ec->lock);
* scheduled again. There might be QR_EC failures, leaving ec->events_to_process--;
* EC_FLAGS_QUERY_PENDING uncleared and preventing this work
* item from being scheduled again.
*/
if (!ec->nr_pending_queries) {
if (ec_event_clearing == ACPI_EC_EVT_TIMING_STATUS ||
ec_event_clearing == ACPI_EC_EVT_TIMING_QUERY)
acpi_ec_complete_query(ec);
}
} }
spin_unlock_irqrestore(&ec->lock, flags);
/*
* Before exit, make sure that the it will be possible to queue up the
* event handling work again regardless of whether or not the query
* queued up above is processed successfully.
*/
if (ec_event_clearing == ACPI_EC_EVT_TIMING_EVENT)
acpi_ec_complete_event(ec);
else
acpi_ec_close_event(ec);
spin_unlock_irq(&ec->lock);
ec_dbg_evt("Event stopped"); ec_dbg_evt("Event stopped");
acpi_ec_check_event(ec); if (ec_event_clearing == ACPI_EC_EVT_TIMING_EVENT && ec_guard(ec)) {
spin_lock_irq(&ec->lock);
/* Take care of SCI_EVT unless someone else is doing that. */
if (!ec->curr)
advance_transaction(ec, false);
spin_unlock_irq(&ec->lock);
}
spin_lock_irq(&ec->lock);
ec->events_in_progress--;
spin_unlock_irq(&ec->lock);
} }
static void acpi_ec_handle_interrupt(struct acpi_ec *ec) static void acpi_ec_handle_interrupt(struct acpi_ec *ec)
...@@ -2021,7 +2053,7 @@ void acpi_ec_set_gpe_wake_mask(u8 action) ...@@ -2021,7 +2053,7 @@ void acpi_ec_set_gpe_wake_mask(u8 action)
bool acpi_ec_dispatch_gpe(void) bool acpi_ec_dispatch_gpe(void)
{ {
u32 ret; bool work_in_progress = false;
if (!first_ec) if (!first_ec)
return acpi_any_gpe_status_set(U32_MAX); return acpi_any_gpe_status_set(U32_MAX);
...@@ -2037,12 +2069,31 @@ bool acpi_ec_dispatch_gpe(void) ...@@ -2037,12 +2069,31 @@ bool acpi_ec_dispatch_gpe(void)
* Dispatch the EC GPE in-band, but do not report wakeup in any case * Dispatch the EC GPE in-band, but do not report wakeup in any case
* to allow the caller to process events properly after that. * to allow the caller to process events properly after that.
*/ */
ret = acpi_dispatch_gpe(NULL, first_ec->gpe); spin_lock_irq(&first_ec->lock);
if (ret == ACPI_INTERRUPT_HANDLED)
pm_pr_dbg("ACPI EC GPE dispatched\n"); if (acpi_ec_gpe_status_set(first_ec))
work_in_progress = advance_transaction(first_ec, false);
spin_unlock_irq(&first_ec->lock);
if (!work_in_progress)
return false;
pm_pr_dbg("ACPI EC GPE dispatched\n");
/* Drain EC work. */
do {
acpi_ec_flush_work();
pm_pr_dbg("ACPI EC work flushed\n");
spin_lock_irq(&first_ec->lock);
work_in_progress = first_ec->events_in_progress +
first_ec->queries_in_progress > 0;
/* Flush the event and query workqueues. */ spin_unlock_irq(&first_ec->lock);
acpi_ec_flush_work(); } while (work_in_progress && !pm_wakeup_pending());
return false; return false;
} }
......
...@@ -19,7 +19,7 @@ MODULE_DESCRIPTION("ACPI EC sysfs access driver"); ...@@ -19,7 +19,7 @@ MODULE_DESCRIPTION("ACPI EC sysfs access driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
static bool write_support; static bool write_support;
module_param(write_support, bool, 0644); module_param_hw(write_support, bool, other, 0644);
MODULE_PARM_DESC(write_support, "Dangerous, reboot and removal of battery may " MODULE_PARM_DESC(write_support, "Dangerous, reboot and removal of battery may "
"be needed."); "be needed.");
......
...@@ -166,6 +166,13 @@ static inline void acpi_early_processor_osc(void) {} ...@@ -166,6 +166,13 @@ static inline void acpi_early_processor_osc(void) {}
/* -------------------------------------------------------------------------- /* --------------------------------------------------------------------------
Embedded Controller Embedded Controller
-------------------------------------------------------------------------- */ -------------------------------------------------------------------------- */
enum acpi_ec_event_state {
EC_EVENT_READY = 0, /* Event work can be submitted */
EC_EVENT_IN_PROGRESS, /* Event work is pending or being processed */
EC_EVENT_COMPLETE, /* Event work processing has completed */
};
struct acpi_ec { struct acpi_ec {
acpi_handle handle; acpi_handle handle;
int gpe; int gpe;
...@@ -182,7 +189,10 @@ struct acpi_ec { ...@@ -182,7 +189,10 @@ struct acpi_ec {
spinlock_t lock; spinlock_t lock;
struct work_struct work; struct work_struct work;
unsigned long timestamp; unsigned long timestamp;
unsigned long nr_pending_queries; enum acpi_ec_event_state event_state;
unsigned int events_to_process;
unsigned int events_in_progress;
unsigned int queries_in_progress;
bool busy_polling; bool busy_polling;
unsigned int polling_guard; unsigned int polling_guard;
}; };
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <linux/tick.h> #include <linux/tick.h>
#include <linux/cpuidle.h> #include <linux/cpuidle.h>
#include <linux/cpu.h> #include <linux/cpu.h>
#include <linux/minmax.h>
#include <acpi/processor.h> #include <acpi/processor.h>
/* /*
...@@ -400,13 +401,10 @@ static int acpi_cst_latency_cmp(const void *a, const void *b) ...@@ -400,13 +401,10 @@ static int acpi_cst_latency_cmp(const void *a, const void *b)
static void acpi_cst_latency_swap(void *a, void *b, int n) static void acpi_cst_latency_swap(void *a, void *b, int n)
{ {
struct acpi_processor_cx *x = a, *y = b; struct acpi_processor_cx *x = a, *y = b;
u32 tmp;
if (!(x->valid && y->valid)) if (!(x->valid && y->valid))
return; return;
tmp = x->latency; swap(x->latency, y->latency);
x->latency = y->latency;
y->latency = tmp;
} }
static int acpi_processor_power_verify(struct acpi_processor *pr) static int acpi_processor_power_verify(struct acpi_processor *pr)
...@@ -567,7 +565,8 @@ static int acpi_idle_play_dead(struct cpuidle_device *dev, int index) ...@@ -567,7 +565,8 @@ static int acpi_idle_play_dead(struct cpuidle_device *dev, int index)
{ {
struct acpi_processor_cx *cx = per_cpu(acpi_cstate[index], dev->cpu); struct acpi_processor_cx *cx = per_cpu(acpi_cstate[index], dev->cpu);
ACPI_FLUSH_CPU_CACHE(); if (cx->type == ACPI_STATE_C3)
ACPI_FLUSH_CPU_CACHE();
while (1) { while (1) {
......
...@@ -53,10 +53,17 @@ static int phys_package_first_cpu(int cpu) ...@@ -53,10 +53,17 @@ static int phys_package_first_cpu(int cpu)
static int cpu_has_cpufreq(unsigned int cpu) static int cpu_has_cpufreq(unsigned int cpu)
{ {
struct cpufreq_policy policy; struct cpufreq_policy *policy;
if (!acpi_processor_cpufreq_init || cpufreq_get_policy(&policy, cpu))
if (!acpi_processor_cpufreq_init)
return 0; return 0;
return 1;
policy = cpufreq_cpu_get(cpu);
if (policy) {
cpufreq_cpu_put(policy);
return 1;
}
return 0;
} }
static int cpufreq_get_max_state(unsigned int cpu) static int cpufreq_get_max_state(unsigned int cpu)
......
...@@ -3,7 +3,6 @@ ...@@ -3,7 +3,6 @@
#define __ACPI_NUMA_H #define __ACPI_NUMA_H
#ifdef CONFIG_ACPI_NUMA #ifdef CONFIG_ACPI_NUMA
#include <linux/kernel.h>
#include <linux/numa.h> #include <linux/numa.h>
/* Proximity bitmap length */ /* Proximity bitmap length */
......
...@@ -2,11 +2,16 @@ ...@@ -2,11 +2,16 @@
#ifndef __ACPI_PROCESSOR_H #ifndef __ACPI_PROCESSOR_H
#define __ACPI_PROCESSOR_H #define __ACPI_PROCESSOR_H
#include <linux/kernel.h>
#include <linux/cpu.h> #include <linux/cpu.h>
#include <linux/cpufreq.h> #include <linux/cpufreq.h>
#include <linux/pm_qos.h> #include <linux/pm_qos.h>
#include <linux/printk.h>
#include <linux/sched.h>
#include <linux/smp.h>
#include <linux/thermal.h> #include <linux/thermal.h>
#include <linux/types.h>
#include <linux/workqueue.h>
#include <asm/acpi.h> #include <asm/acpi.h>
#define ACPI_PROCESSOR_CLASS "processor" #define ACPI_PROCESSOR_CLASS "processor"
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment