diff options
author | Alexey Starikovskiy <astarikovskiy@suse.de> | 2007-10-22 06:18:43 -0400 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2007-10-25 16:31:31 -0400 |
commit | 7843932ac42899b936085beaea8620d4489b8b3f (patch) | |
tree | 6a3edbf8fc9d14c29c635f6759ca960088ee226f /drivers/acpi/ec.c | |
parent | 0c5d31f48e54b2e56e9cef8d49ffedaef1e0ea52 (diff) |
ACPI: EC: auto select interrupt mode
Start in POLL mode, and if we receive confirmation GPE,
switch to INT mode.
If confirmations are not sent, switch back to POLL.
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.c | 51 |
1 files changed, 16 insertions, 35 deletions
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 5ce90ce22b58..50d55fe71a30 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c | |||
@@ -71,14 +71,10 @@ enum ec_event { | |||
71 | #define ACPI_EC_DELAY 500 /* Wait 500ms max. during EC ops */ | 71 | #define ACPI_EC_DELAY 500 /* Wait 500ms max. during EC ops */ |
72 | #define ACPI_EC_UDELAY_GLK 1000 /* Wait 1ms max. to get global lock */ | 72 | #define ACPI_EC_UDELAY_GLK 1000 /* Wait 1ms max. to get global lock */ |
73 | 73 | ||
74 | static enum ec_mode { | ||
75 | EC_INTR = 1, /* Output buffer full */ | ||
76 | EC_POLL, /* Input buffer empty */ | ||
77 | } acpi_ec_mode = EC_INTR; | ||
78 | |||
79 | enum { | 74 | enum { |
80 | EC_FLAGS_WAIT_GPE = 0, /* Don't check status until GPE arrives */ | 75 | EC_FLAGS_WAIT_GPE = 0, /* Don't check status until GPE arrives */ |
81 | EC_FLAGS_QUERY_PENDING, /* Query is pending */ | 76 | EC_FLAGS_QUERY_PENDING, /* Query is pending */ |
77 | EC_FLAGS_GPE_MODE, /* Expect GPE to be sent for status change */ | ||
82 | }; | 78 | }; |
83 | 79 | ||
84 | static int acpi_ec_remove(struct acpi_device *device, int type); | 80 | static int acpi_ec_remove(struct acpi_device *device, int type); |
@@ -169,21 +165,23 @@ static inline int acpi_ec_check_status(struct acpi_ec *ec, enum ec_event event) | |||
169 | 165 | ||
170 | static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, int force_poll) | 166 | static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, int force_poll) |
171 | { | 167 | { |
172 | if (unlikely(force_poll) || acpi_ec_mode == EC_POLL) { | 168 | if (likely(test_bit(EC_FLAGS_GPE_MODE, &ec->flags)) && |
173 | unsigned long delay = jiffies + msecs_to_jiffies(ACPI_EC_DELAY); | 169 | likely(!force_poll)) { |
174 | clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags); | ||
175 | while (time_before(jiffies, delay)) { | ||
176 | if (acpi_ec_check_status(ec, event)) | ||
177 | return 0; | ||
178 | } | ||
179 | } else { | ||
180 | if (wait_event_timeout(ec->wait, acpi_ec_check_status(ec, event), | 170 | if (wait_event_timeout(ec->wait, acpi_ec_check_status(ec, event), |
181 | msecs_to_jiffies(ACPI_EC_DELAY))) | 171 | msecs_to_jiffies(ACPI_EC_DELAY))) |
182 | return 0; | 172 | return 0; |
183 | clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags); | 173 | clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags); |
184 | if (acpi_ec_check_status(ec, event)) { | 174 | if (acpi_ec_check_status(ec, event)) { |
175 | clear_bit(EC_FLAGS_GPE_MODE, &ec->flags); | ||
185 | return 0; | 176 | return 0; |
186 | } | 177 | } |
178 | } else { | ||
179 | unsigned long delay = jiffies + msecs_to_jiffies(ACPI_EC_DELAY); | ||
180 | clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags); | ||
181 | while (time_before(jiffies, delay)) { | ||
182 | if (acpi_ec_check_status(ec, event)) | ||
183 | return 0; | ||
184 | } | ||
187 | } | 185 | } |
188 | printk(KERN_ERR PREFIX "acpi_ec_wait timeout," | 186 | printk(KERN_ERR PREFIX "acpi_ec_wait timeout," |
189 | " status = %d, expect_event = %d\n", | 187 | " status = %d, expect_event = %d\n", |
@@ -481,18 +479,17 @@ static u32 acpi_ec_gpe_handler(void *data) | |||
481 | struct acpi_ec *ec = data; | 479 | struct acpi_ec *ec = data; |
482 | 480 | ||
483 | clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags); | 481 | clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags); |
484 | 482 | if (test_bit(EC_FLAGS_GPE_MODE, &ec->flags)) | |
485 | if (acpi_ec_mode == EC_INTR) { | ||
486 | wake_up(&ec->wait); | 483 | wake_up(&ec->wait); |
487 | } | ||
488 | 484 | ||
489 | if (acpi_ec_read_status(ec) & ACPI_EC_FLAG_SCI) { | 485 | if (acpi_ec_read_status(ec) & ACPI_EC_FLAG_SCI) { |
490 | if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) | 486 | if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) |
491 | status = acpi_os_execute(OSL_EC_BURST_HANDLER, | 487 | status = acpi_os_execute(OSL_EC_BURST_HANDLER, |
492 | acpi_ec_gpe_query, ec); | 488 | acpi_ec_gpe_query, ec); |
493 | } | 489 | } else if (unlikely(!test_bit(EC_FLAGS_GPE_MODE, &ec->flags))) |
490 | set_bit(EC_FLAGS_GPE_MODE, &ec->flags); | ||
494 | 491 | ||
495 | return status == AE_OK ? | 492 | return ACPI_SUCCESS(status) ? |
496 | ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED; | 493 | ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED; |
497 | } | 494 | } |
498 | 495 | ||
@@ -923,20 +920,4 @@ static void __exit acpi_ec_exit(void) | |||
923 | 920 | ||
924 | return; | 921 | return; |
925 | } | 922 | } |
926 | #endif /* 0 */ | 923 | #endif /* 0 */ |
927 | |||
928 | static int __init acpi_ec_set_intr_mode(char *str) | ||
929 | { | ||
930 | int intr; | ||
931 | |||
932 | if (!get_option(&str, &intr)) | ||
933 | return 0; | ||
934 | |||
935 | acpi_ec_mode = (intr) ? EC_INTR : EC_POLL; | ||
936 | |||
937 | printk(KERN_NOTICE PREFIX "%s mode.\n", intr ? "interrupt" : "polling"); | ||
938 | |||
939 | return 1; | ||
940 | } | ||
941 | |||
942 | __setup("ec_intr=", acpi_ec_set_intr_mode); | ||