mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-11 21:38:32 +08:00
ACPI: EC: Add poll timer
If we can not use interrupt mode of EC for some reason, start polling EC for events periodically. Signed-off-by: Alexey Starikovskiy <astarikovskiy@suse.de> Signed-off-by: Len Brown <len.brown@intel.com>
This commit is contained in:
parent
e6e82a3087
commit
845625cdcb
@ -84,6 +84,7 @@ enum {
|
||||
EC_FLAGS_NO_WDATA_GPE, /* Don't expect WDATA GPE event */
|
||||
EC_FLAGS_WDATA, /* Data is being written */
|
||||
EC_FLAGS_NO_OBF1_GPE, /* Don't expect GPE before read */
|
||||
EC_FLAGS_RESCHEDULE_POLL /* Re-schedule poll */
|
||||
};
|
||||
|
||||
static int acpi_ec_remove(struct acpi_device *device, int type);
|
||||
@ -130,6 +131,7 @@ static struct acpi_ec {
|
||||
struct mutex lock;
|
||||
wait_queue_head_t wait;
|
||||
struct list_head list;
|
||||
struct delayed_work work;
|
||||
u8 handlers_installed;
|
||||
} *boot_ec, *first_ec;
|
||||
|
||||
@ -178,6 +180,20 @@ static inline int acpi_ec_check_status(struct acpi_ec *ec, enum ec_event event)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ec_schedule_ec_poll(struct acpi_ec *ec)
|
||||
{
|
||||
if (test_bit(EC_FLAGS_RESCHEDULE_POLL, &ec->flags))
|
||||
schedule_delayed_work(&ec->work,
|
||||
msecs_to_jiffies(ACPI_EC_DELAY));
|
||||
}
|
||||
|
||||
static void ec_switch_to_poll_mode(struct acpi_ec *ec)
|
||||
{
|
||||
clear_bit(EC_FLAGS_GPE_MODE, &ec->flags);
|
||||
acpi_disable_gpe(NULL, ec->gpe, ACPI_NOT_ISR);
|
||||
set_bit(EC_FLAGS_RESCHEDULE_POLL, &ec->flags);
|
||||
}
|
||||
|
||||
static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, int force_poll)
|
||||
{
|
||||
int ret = 0;
|
||||
@ -218,7 +234,8 @@ static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, int force_poll)
|
||||
if (printk_ratelimit())
|
||||
pr_info(PREFIX "missing confirmations, "
|
||||
"switch off interrupt mode.\n");
|
||||
clear_bit(EC_FLAGS_GPE_MODE, &ec->flags);
|
||||
ec_switch_to_poll_mode(ec);
|
||||
ec_schedule_ec_poll(ec);
|
||||
}
|
||||
goto end;
|
||||
}
|
||||
@ -529,28 +546,37 @@ static u32 acpi_ec_gpe_handler(void *data)
|
||||
{
|
||||
acpi_status status = AE_OK;
|
||||
struct acpi_ec *ec = data;
|
||||
u8 state = acpi_ec_read_status(ec);
|
||||
|
||||
pr_debug(PREFIX "~~~> interrupt\n");
|
||||
clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags);
|
||||
if (test_bit(EC_FLAGS_GPE_MODE, &ec->flags))
|
||||
wake_up(&ec->wait);
|
||||
|
||||
if (acpi_ec_read_status(ec) & ACPI_EC_FLAG_SCI) {
|
||||
if (state & ACPI_EC_FLAG_SCI) {
|
||||
if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags))
|
||||
status = acpi_os_execute(OSL_EC_BURST_HANDLER,
|
||||
acpi_ec_gpe_query, ec);
|
||||
} else if (unlikely(!test_bit(EC_FLAGS_GPE_MODE, &ec->flags))) {
|
||||
} else if (!test_bit(EC_FLAGS_GPE_MODE, &ec->flags) &&
|
||||
in_interrupt()) {
|
||||
/* this is non-query, must be confirmation */
|
||||
if (printk_ratelimit())
|
||||
pr_info(PREFIX "non-query interrupt received,"
|
||||
" switching to interrupt mode\n");
|
||||
set_bit(EC_FLAGS_GPE_MODE, &ec->flags);
|
||||
clear_bit(EC_FLAGS_RESCHEDULE_POLL, &ec->flags);
|
||||
}
|
||||
|
||||
ec_schedule_ec_poll(ec);
|
||||
return ACPI_SUCCESS(status) ?
|
||||
ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED;
|
||||
}
|
||||
|
||||
static void do_ec_poll(struct work_struct *work)
|
||||
{
|
||||
struct acpi_ec *ec = container_of(work, struct acpi_ec, work.work);
|
||||
(void)acpi_ec_gpe_handler(ec);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
Address Space Management
|
||||
-------------------------------------------------------------------------- */
|
||||
@ -711,6 +737,7 @@ static struct acpi_ec *make_acpi_ec(void)
|
||||
mutex_init(&ec->lock);
|
||||
init_waitqueue_head(&ec->wait);
|
||||
INIT_LIST_HEAD(&ec->list);
|
||||
INIT_DELAYED_WORK_DEFERRABLE(&ec->work, do_ec_poll);
|
||||
return ec;
|
||||
}
|
||||
|
||||
@ -752,8 +779,15 @@ ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval)
|
||||
return AE_CTRL_TERMINATE;
|
||||
}
|
||||
|
||||
static void ec_poll_stop(struct acpi_ec *ec)
|
||||
{
|
||||
clear_bit(EC_FLAGS_RESCHEDULE_POLL, &ec->flags);
|
||||
cancel_delayed_work(&ec->work);
|
||||
}
|
||||
|
||||
static void ec_remove_handlers(struct acpi_ec *ec)
|
||||
{
|
||||
ec_poll_stop(ec);
|
||||
if (ACPI_FAILURE(acpi_remove_address_space_handler(ec->handle,
|
||||
ACPI_ADR_SPACE_EC, &acpi_ec_space_handler)))
|
||||
pr_err(PREFIX "failed to remove space handler\n");
|
||||
@ -899,6 +933,7 @@ static int acpi_ec_start(struct acpi_device *device)
|
||||
|
||||
/* EC is fully operational, allow queries */
|
||||
clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags);
|
||||
ec_schedule_ec_poll(ec);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user