Skip to content

Commit

Permalink
ACPI: EC: Add poll timer
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Alexey Starikovskiy authored and Len Brown committed Mar 25, 2008
1 parent e6e82a3 commit 845625c
Showing 1 changed file with 39 additions and 4 deletions.
43 changes: 39 additions & 4 deletions drivers/acpi/ec.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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
-------------------------------------------------------------------------- */
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -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;
}

Expand Down

0 comments on commit 845625c

Please sign in to comment.