aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/ec.c
diff options
context:
space:
mode:
authorAlexey Starikovskiy <astarikovskiy@suse.de>2008-03-21 10:07:03 -0400
committerLen Brown <len.brown@intel.com>2008-03-24 20:48:10 -0400
commit845625cdcb17119d5f6c5c8dbe586f2f36e8008a (patch)
tree0bd8a2dccbbe07ee61667caaf440e61015944e55 /drivers/acpi/ec.c
parente6e82a3087e6dad619149246082c910623ea9c36 (diff)
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>
Diffstat (limited to 'drivers/acpi/ec.c')
-rw-r--r--drivers/acpi/ec.c43
1 files changed, 39 insertions, 4 deletions
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 828c75292cf6..63e0ac2644ad 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -84,6 +84,7 @@ enum {
84 EC_FLAGS_NO_WDATA_GPE, /* Don't expect WDATA GPE event */ 84 EC_FLAGS_NO_WDATA_GPE, /* Don't expect WDATA GPE event */
85 EC_FLAGS_WDATA, /* Data is being written */ 85 EC_FLAGS_WDATA, /* Data is being written */
86 EC_FLAGS_NO_OBF1_GPE, /* Don't expect GPE before read */ 86 EC_FLAGS_NO_OBF1_GPE, /* Don't expect GPE before read */
87 EC_FLAGS_RESCHEDULE_POLL /* Re-schedule poll */
87}; 88};
88 89
89static int acpi_ec_remove(struct acpi_device *device, int type); 90static int acpi_ec_remove(struct acpi_device *device, int type);
@@ -130,6 +131,7 @@ static struct acpi_ec {
130 struct mutex lock; 131 struct mutex lock;
131 wait_queue_head_t wait; 132 wait_queue_head_t wait;
132 struct list_head list; 133 struct list_head list;
134 struct delayed_work work;
133 u8 handlers_installed; 135 u8 handlers_installed;
134} *boot_ec, *first_ec; 136} *boot_ec, *first_ec;
135 137
@@ -178,6 +180,20 @@ static inline int acpi_ec_check_status(struct acpi_ec *ec, enum ec_event event)
178 return 0; 180 return 0;
179} 181}
180 182
183static void ec_schedule_ec_poll(struct acpi_ec *ec)
184{
185 if (test_bit(EC_FLAGS_RESCHEDULE_POLL, &ec->flags))
186 schedule_delayed_work(&ec->work,
187 msecs_to_jiffies(ACPI_EC_DELAY));
188}
189
190static void ec_switch_to_poll_mode(struct acpi_ec *ec)
191{
192 clear_bit(EC_FLAGS_GPE_MODE, &ec->flags);
193 acpi_disable_gpe(NULL, ec->gpe, ACPI_NOT_ISR);
194 set_bit(EC_FLAGS_RESCHEDULE_POLL, &ec->flags);
195}
196
181static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, int force_poll) 197static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, int force_poll)
182{ 198{
183 int ret = 0; 199 int ret = 0;
@@ -218,7 +234,8 @@ static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, int force_poll)
218 if (printk_ratelimit()) 234 if (printk_ratelimit())
219 pr_info(PREFIX "missing confirmations, " 235 pr_info(PREFIX "missing confirmations, "
220 "switch off interrupt mode.\n"); 236 "switch off interrupt mode.\n");
221 clear_bit(EC_FLAGS_GPE_MODE, &ec->flags); 237 ec_switch_to_poll_mode(ec);
238 ec_schedule_ec_poll(ec);
222 } 239 }
223 goto end; 240 goto end;
224 } 241 }
@@ -529,28 +546,37 @@ static u32 acpi_ec_gpe_handler(void *data)
529{ 546{
530 acpi_status status = AE_OK; 547 acpi_status status = AE_OK;
531 struct acpi_ec *ec = data; 548 struct acpi_ec *ec = data;
549 u8 state = acpi_ec_read_status(ec);
532 550
533 pr_debug(PREFIX "~~~> interrupt\n"); 551 pr_debug(PREFIX "~~~> interrupt\n");
534 clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags); 552 clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags);
535 if (test_bit(EC_FLAGS_GPE_MODE, &ec->flags)) 553 if (test_bit(EC_FLAGS_GPE_MODE, &ec->flags))
536 wake_up(&ec->wait); 554 wake_up(&ec->wait);
537 555
538 if (acpi_ec_read_status(ec) & ACPI_EC_FLAG_SCI) { 556 if (state & ACPI_EC_FLAG_SCI) {
539 if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) 557 if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags))
540 status = acpi_os_execute(OSL_EC_BURST_HANDLER, 558 status = acpi_os_execute(OSL_EC_BURST_HANDLER,
541 acpi_ec_gpe_query, ec); 559 acpi_ec_gpe_query, ec);
542 } else if (unlikely(!test_bit(EC_FLAGS_GPE_MODE, &ec->flags))) { 560 } else if (!test_bit(EC_FLAGS_GPE_MODE, &ec->flags) &&
561 in_interrupt()) {
543 /* this is non-query, must be confirmation */ 562 /* this is non-query, must be confirmation */
544 if (printk_ratelimit()) 563 if (printk_ratelimit())
545 pr_info(PREFIX "non-query interrupt received," 564 pr_info(PREFIX "non-query interrupt received,"
546 " switching to interrupt mode\n"); 565 " switching to interrupt mode\n");
547 set_bit(EC_FLAGS_GPE_MODE, &ec->flags); 566 set_bit(EC_FLAGS_GPE_MODE, &ec->flags);
567 clear_bit(EC_FLAGS_RESCHEDULE_POLL, &ec->flags);
548 } 568 }
549 569 ec_schedule_ec_poll(ec);
550 return ACPI_SUCCESS(status) ? 570 return ACPI_SUCCESS(status) ?
551 ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED; 571 ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED;
552} 572}
553 573
574static void do_ec_poll(struct work_struct *work)
575{
576 struct acpi_ec *ec = container_of(work, struct acpi_ec, work.work);
577 (void)acpi_ec_gpe_handler(ec);
578}
579
554/* -------------------------------------------------------------------------- 580/* --------------------------------------------------------------------------
555 Address Space Management 581 Address Space Management
556 -------------------------------------------------------------------------- */ 582 -------------------------------------------------------------------------- */
@@ -711,6 +737,7 @@ static struct acpi_ec *make_acpi_ec(void)
711 mutex_init(&ec->lock); 737 mutex_init(&ec->lock);
712 init_waitqueue_head(&ec->wait); 738 init_waitqueue_head(&ec->wait);
713 INIT_LIST_HEAD(&ec->list); 739 INIT_LIST_HEAD(&ec->list);
740 INIT_DELAYED_WORK_DEFERRABLE(&ec->work, do_ec_poll);
714 return ec; 741 return ec;
715} 742}
716 743
@@ -752,8 +779,15 @@ ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval)
752 return AE_CTRL_TERMINATE; 779 return AE_CTRL_TERMINATE;
753} 780}
754 781
782static void ec_poll_stop(struct acpi_ec *ec)
783{
784 clear_bit(EC_FLAGS_RESCHEDULE_POLL, &ec->flags);
785 cancel_delayed_work(&ec->work);
786}
787
755static void ec_remove_handlers(struct acpi_ec *ec) 788static void ec_remove_handlers(struct acpi_ec *ec)
756{ 789{
790 ec_poll_stop(ec);
757 if (ACPI_FAILURE(acpi_remove_address_space_handler(ec->handle, 791 if (ACPI_FAILURE(acpi_remove_address_space_handler(ec->handle,
758 ACPI_ADR_SPACE_EC, &acpi_ec_space_handler))) 792 ACPI_ADR_SPACE_EC, &acpi_ec_space_handler)))
759 pr_err(PREFIX "failed to remove space handler\n"); 793 pr_err(PREFIX "failed to remove space handler\n");
@@ -899,6 +933,7 @@ static int acpi_ec_start(struct acpi_device *device)
899 933
900 /* EC is fully operational, allow queries */ 934 /* EC is fully operational, allow queries */
901 clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags); 935 clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags);
936 ec_schedule_ec_poll(ec);
902 return ret; 937 return ret;
903} 938}
904 939