* [PATCH 1/6] Restore udelay in poll mode
@ 2008-03-21 14:06 Alexey Starikovskiy
2008-03-21 14:07 ` [PATCH 2/6] ACPI: EC: Add poll timer Alexey Starikovskiy
` (5 more replies)
0 siblings, 6 replies; 8+ messages in thread
From: Alexey Starikovskiy @ 2008-03-21 14:06 UTC (permalink / raw)
To: LenBrown; +Cc: Linux-acpi
Allow EC to serve keyboard even then we polling it.
Signed-off-by: Alexey Starikovskiy <astarikovskiy@suse.de>
---
drivers/acpi/ec.c | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 7222a18..828c752 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -73,6 +73,7 @@ enum ec_event {
#define ACPI_EC_DELAY 500 /* Wait 500ms max. during EC ops */
#define ACPI_EC_UDELAY_GLK 1000 /* Wait 1ms max. to get global lock */
+#define ACPI_EC_UDELAY 100 /* Wait 100us before polling EC again */
enum {
EC_FLAGS_WAIT_GPE = 0, /* Don't check status until GPE arrives */
@@ -227,6 +228,7 @@ static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, int force_poll)
while (time_before(jiffies, delay)) {
if (acpi_ec_check_status(ec, event))
goto end;
+ udelay(ACPI_EC_UDELAY);
}
}
pr_err(PREFIX "acpi_ec_wait timeout,"
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 2/6] ACPI: EC: Add poll timer
2008-03-21 14:06 [PATCH 1/6] Restore udelay in poll mode Alexey Starikovskiy
@ 2008-03-21 14:07 ` Alexey Starikovskiy
2008-03-21 14:07 ` [PATCH 3/6] Improve debug output Alexey Starikovskiy
` (4 subsequent siblings)
5 siblings, 0 replies; 8+ messages in thread
From: Alexey Starikovskiy @ 2008-03-21 14:07 UTC (permalink / raw)
To: LenBrown; +Cc: Linux-acpi
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>
---
drivers/acpi/ec.c | 43 +++++++++++++++++++++++++++++++++++++++----
1 files changed, 39 insertions(+), 4 deletions(-)
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 828c752..63e0ac2 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -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;
}
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 3/6] Improve debug output
2008-03-21 14:06 [PATCH 1/6] Restore udelay in poll mode Alexey Starikovskiy
2008-03-21 14:07 ` [PATCH 2/6] ACPI: EC: Add poll timer Alexey Starikovskiy
@ 2008-03-21 14:07 ` Alexey Starikovskiy
2008-03-21 14:07 ` [PATCH 4/6] Drop support for broken controllers Alexey Starikovskiy
` (3 subsequent siblings)
5 siblings, 0 replies; 8+ messages in thread
From: Alexey Starikovskiy @ 2008-03-21 14:07 UTC (permalink / raw)
To: LenBrown; +Cc: Linux-acpi
Signed-off-by: Alexey Starikovskiy <astarikovskiy@suse.de>
---
drivers/acpi/ec.c | 8 ++++----
1 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 63e0ac2..1a7949c 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -248,9 +248,9 @@ static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, int force_poll)
udelay(ACPI_EC_UDELAY);
}
}
- pr_err(PREFIX "acpi_ec_wait timeout,"
- " status = %d, expect_event = %d\n",
- acpi_ec_read_status(ec), event);
+ pr_err(PREFIX "acpi_ec_wait timeout, status = 0x%2.2x, event = %s\n",
+ acpi_ec_read_status(ec),
+ (event == ACPI_EC_EVENT_OBF_1) ? "\"b0=1\"" : "\"b1=0\"");
ret = -ETIME;
end:
clear_bit(EC_FLAGS_ADDRESS, &ec->flags);
@@ -264,8 +264,8 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command,
{
int result = 0;
set_bit(EC_FLAGS_WAIT_GPE, &ec->flags);
- acpi_ec_write_cmd(ec, command);
pr_debug(PREFIX "transaction start\n");
+ acpi_ec_write_cmd(ec, command);
for (; wdata_len > 0; --wdata_len) {
result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, force_poll);
if (result) {
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 4/6] Drop support for broken controllers
2008-03-21 14:06 [PATCH 1/6] Restore udelay in poll mode Alexey Starikovskiy
2008-03-21 14:07 ` [PATCH 2/6] ACPI: EC: Add poll timer Alexey Starikovskiy
2008-03-21 14:07 ` [PATCH 3/6] Improve debug output Alexey Starikovskiy
@ 2008-03-21 14:07 ` Alexey Starikovskiy
2008-03-21 14:07 ` [PATCH 5/6] ACPI: EC: Switch off GPE mode during suspend/resume Alexey Starikovskiy
` (2 subsequent siblings)
5 siblings, 0 replies; 8+ messages in thread
From: Alexey Starikovskiy @ 2008-03-21 14:07 UTC (permalink / raw)
To: LenBrown; +Cc: Linux-acpi
Put all broken controllers into fully functional poll mode
Signed-off-by: Alexey Starikovskiy <astarikovskiy@suse.de>
---
drivers/acpi/ec.c | 61 ++++++++++-------------------------------------------
1 files changed, 12 insertions(+), 49 deletions(-)
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 1a7949c..7f07b68 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -79,11 +79,7 @@ enum {
EC_FLAGS_WAIT_GPE = 0, /* Don't check status until GPE arrives */
EC_FLAGS_QUERY_PENDING, /* Query is pending */
EC_FLAGS_GPE_MODE, /* Expect GPE to be sent for status change */
- EC_FLAGS_NO_ADDRESS_GPE, /* Expect GPE only for non-address event */
- EC_FLAGS_ADDRESS, /* Address is being written */
- 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_NO_GPE, /* Don't use GPE mode */
EC_FLAGS_RESCHEDULE_POLL /* Re-schedule poll */
};
@@ -189,6 +185,7 @@ static void ec_schedule_ec_poll(struct acpi_ec *ec)
static void ec_switch_to_poll_mode(struct acpi_ec *ec)
{
+ set_bit(EC_FLAGS_NO_GPE, &ec->flags);
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);
@@ -196,65 +193,34 @@ static void ec_switch_to_poll_mode(struct acpi_ec *ec)
static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, int force_poll)
{
- int ret = 0;
-
- if (unlikely(event == ACPI_EC_EVENT_OBF_1 &&
- test_bit(EC_FLAGS_NO_OBF1_GPE, &ec->flags)))
- force_poll = 1;
- if (unlikely(test_bit(EC_FLAGS_ADDRESS, &ec->flags) &&
- test_bit(EC_FLAGS_NO_ADDRESS_GPE, &ec->flags)))
- force_poll = 1;
- if (unlikely(test_bit(EC_FLAGS_WDATA, &ec->flags) &&
- test_bit(EC_FLAGS_NO_WDATA_GPE, &ec->flags)))
- force_poll = 1;
if (likely(test_bit(EC_FLAGS_GPE_MODE, &ec->flags)) &&
likely(!force_poll)) {
if (wait_event_timeout(ec->wait, acpi_ec_check_status(ec, event),
msecs_to_jiffies(ACPI_EC_DELAY)))
- goto end;
+ return 0;
clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags);
if (acpi_ec_check_status(ec, event)) {
- if (event == ACPI_EC_EVENT_OBF_1) {
- /* miss OBF_1 GPE, don't expect it */
- pr_info(PREFIX "missing OBF confirmation, "
- "don't expect it any longer.\n");
- set_bit(EC_FLAGS_NO_OBF1_GPE, &ec->flags);
- } else if (test_bit(EC_FLAGS_ADDRESS, &ec->flags)) {
- /* miss address GPE, don't expect it anymore */
- pr_info(PREFIX "missing address confirmation, "
- "don't expect it any longer.\n");
- set_bit(EC_FLAGS_NO_ADDRESS_GPE, &ec->flags);
- } else if (test_bit(EC_FLAGS_WDATA, &ec->flags)) {
- /* miss write data GPE, don't expect it */
- pr_info(PREFIX "missing write data confirmation, "
- "don't expect it any longer.\n");
- set_bit(EC_FLAGS_NO_WDATA_GPE, &ec->flags);
- } else {
- /* missing GPEs, switch back to poll mode */
- if (printk_ratelimit())
- pr_info(PREFIX "missing confirmations, "
+ /* missing GPEs, switch back to poll mode */
+ if (printk_ratelimit())
+ pr_info(PREFIX "missing confirmations, "
"switch off interrupt mode.\n");
- ec_switch_to_poll_mode(ec);
- ec_schedule_ec_poll(ec);
- }
- goto end;
+ ec_switch_to_poll_mode(ec);
+ ec_schedule_ec_poll(ec);
+ return 0;
}
} else {
unsigned long delay = jiffies + msecs_to_jiffies(ACPI_EC_DELAY);
clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags);
while (time_before(jiffies, delay)) {
if (acpi_ec_check_status(ec, event))
- goto end;
+ return 0;
udelay(ACPI_EC_UDELAY);
}
}
pr_err(PREFIX "acpi_ec_wait timeout, status = 0x%2.2x, event = %s\n",
acpi_ec_read_status(ec),
(event == ACPI_EC_EVENT_OBF_1) ? "\"b0=1\"" : "\"b1=0\"");
- ret = -ETIME;
- end:
- clear_bit(EC_FLAGS_ADDRESS, &ec->flags);
- return ret;
+ return -ETIME;
}
static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command,
@@ -273,15 +239,11 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command,
"write_cmd timeout, command = %d\n", command);
goto end;
}
- /* mark the address byte written to EC */
- if (rdata_len + wdata_len > 1)
- set_bit(EC_FLAGS_ADDRESS, &ec->flags);
set_bit(EC_FLAGS_WAIT_GPE, &ec->flags);
acpi_ec_write_data(ec, *(wdata++));
}
if (!rdata_len) {
- set_bit(EC_FLAGS_WDATA, &ec->flags);
result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, force_poll);
if (result) {
pr_err(PREFIX
@@ -558,6 +520,7 @@ static u32 acpi_ec_gpe_handler(void *data)
status = acpi_os_execute(OSL_EC_BURST_HANDLER,
acpi_ec_gpe_query, ec);
} else if (!test_bit(EC_FLAGS_GPE_MODE, &ec->flags) &&
+ !test_bit(EC_FLAGS_NO_GPE, &ec->flags) &&
in_interrupt()) {
/* this is non-query, must be confirmation */
if (printk_ratelimit())
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 5/6] ACPI: EC: Switch off GPE mode during suspend/resume
2008-03-21 14:06 [PATCH 1/6] Restore udelay in poll mode Alexey Starikovskiy
` (2 preceding siblings ...)
2008-03-21 14:07 ` [PATCH 4/6] Drop support for broken controllers Alexey Starikovskiy
@ 2008-03-21 14:07 ` Alexey Starikovskiy
2008-03-21 14:07 ` [PATCH 6/6] ACPI: EC: Detect irq storm Alexey Starikovskiy
2008-03-25 0:52 ` [PATCH 1/6] Restore udelay in poll mode Len Brown
5 siblings, 0 replies; 8+ messages in thread
From: Alexey Starikovskiy @ 2008-03-21 14:07 UTC (permalink / raw)
To: LenBrown; +Cc: Linux-acpi
Signed-off-by: Alexey Starikovskiy <astarikovskiy@suse.de>
---
drivers/acpi/ec.c | 60 ++++++++++++++++++++++++++++++++++-------------------
1 files changed, 38 insertions(+), 22 deletions(-)
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 7f07b68..da67d22 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -83,28 +83,6 @@ enum {
EC_FLAGS_RESCHEDULE_POLL /* Re-schedule poll */
};
-static int acpi_ec_remove(struct acpi_device *device, int type);
-static int acpi_ec_start(struct acpi_device *device);
-static int acpi_ec_stop(struct acpi_device *device, int type);
-static int acpi_ec_add(struct acpi_device *device);
-
-static const struct acpi_device_id ec_device_ids[] = {
- {"PNP0C09", 0},
- {"", 0},
-};
-
-static struct acpi_driver acpi_ec_driver = {
- .name = "ec",
- .class = ACPI_EC_CLASS,
- .ids = ec_device_ids,
- .ops = {
- .add = acpi_ec_add,
- .remove = acpi_ec_remove,
- .start = acpi_ec_start,
- .stop = acpi_ec_stop,
- },
-};
-
/* If we find an EC via the ECDT, we need to keep a ptr to its context */
/* External interfaces use first EC only, so remember */
typedef int (*acpi_ec_query_func) (void *data);
@@ -924,6 +902,11 @@ int __init acpi_boot_ec_enable(void)
return -EFAULT;
}
+static const struct acpi_device_id ec_device_ids[] = {
+ {"PNP0C09", 0},
+ {"", 0},
+};
+
int __init acpi_ec_ecdt_probe(void)
{
int ret;
@@ -973,6 +956,39 @@ int __init acpi_ec_ecdt_probe(void)
return -ENODEV;
}
+static int acpi_ec_suspend(struct acpi_device *device, pm_message_t state)
+{
+ struct acpi_ec *ec = acpi_driver_data(device);
+ /* Stop using GPE */
+ set_bit(EC_FLAGS_NO_GPE, &ec->flags);
+ clear_bit(EC_FLAGS_GPE_MODE, &ec->flags);
+ acpi_disable_gpe(NULL, ec->gpe, ACPI_NOT_ISR);
+ return 0;
+}
+
+static int acpi_ec_resume(struct acpi_device *device)
+{
+ struct acpi_ec *ec = acpi_driver_data(device);
+ /* Enable use of GPE back */
+ clear_bit(EC_FLAGS_NO_GPE, &ec->flags);
+ acpi_enable_gpe(NULL, ec->gpe, ACPI_NOT_ISR);
+ return 0;
+}
+
+static struct acpi_driver acpi_ec_driver = {
+ .name = "ec",
+ .class = ACPI_EC_CLASS,
+ .ids = ec_device_ids,
+ .ops = {
+ .add = acpi_ec_add,
+ .remove = acpi_ec_remove,
+ .start = acpi_ec_start,
+ .stop = acpi_ec_stop,
+ .suspend = acpi_ec_suspend,
+ .resume = acpi_ec_resume,
+ },
+};
+
static int __init acpi_ec_init(void)
{
int result = 0;
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 6/6] ACPI: EC: Detect irq storm
2008-03-21 14:06 [PATCH 1/6] Restore udelay in poll mode Alexey Starikovskiy
` (3 preceding siblings ...)
2008-03-21 14:07 ` [PATCH 5/6] ACPI: EC: Switch off GPE mode during suspend/resume Alexey Starikovskiy
@ 2008-03-21 14:07 ` Alexey Starikovskiy
2008-03-21 16:36 ` [PATCH] " Alexey Starikovskiy
2008-03-25 0:52 ` [PATCH 1/6] Restore udelay in poll mode Len Brown
5 siblings, 1 reply; 8+ messages in thread
From: Alexey Starikovskiy @ 2008-03-21 14:07 UTC (permalink / raw)
To: LenBrown; +Cc: Linux-acpi
Problem seems to be that hw fails to clear GPE after we service it and write 1
into corresponding bit. Thus, as soon as we get interrupts enabled again, we
receive a new one. Google gives too many results for "acer interrupt storm" for
this being one-broken-machine case.
Reference: http://bugzilla.kernel.org/show_bug.cgi?id=9998
Signed-off-by: Alexey Starikovskiy <astarikovskiy@suse.de>
---
drivers/acpi/ec.c | 10 ++++++++++
1 files changed, 10 insertions(+), 0 deletions(-)
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index da67d22..284d421 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -106,6 +106,7 @@ static struct acpi_ec {
wait_queue_head_t wait;
struct list_head list;
struct delayed_work work;
+ atomic_t irq_count;
u8 handlers_installed;
} *boot_ec, *first_ec;
@@ -171,6 +172,7 @@ static void ec_switch_to_poll_mode(struct acpi_ec *ec)
static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, int force_poll)
{
+ atomic_set(&ec->irq_count, 0);
if (likely(test_bit(EC_FLAGS_GPE_MODE, &ec->flags)) &&
likely(!force_poll)) {
if (wait_event_timeout(ec->wait, acpi_ec_check_status(ec, event),
@@ -489,6 +491,12 @@ static u32 acpi_ec_gpe_handler(void *data)
u8 state = acpi_ec_read_status(ec);
pr_debug(PREFIX "~~~> interrupt\n");
+ atomic_inc(&ec->irq_count);
+ if (atomic_read(&ec->irq_count) > 5) {
+ pr_err(PREFIX "GPE storm detected, disabling EC GPE\n");
+ ec_switch_to_poll_mode(ec);
+ goto end;
+ }
clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags);
if (test_bit(EC_FLAGS_GPE_MODE, &ec->flags))
wake_up(&ec->wait);
@@ -507,6 +515,7 @@ static u32 acpi_ec_gpe_handler(void *data)
set_bit(EC_FLAGS_GPE_MODE, &ec->flags);
clear_bit(EC_FLAGS_RESCHEDULE_POLL, &ec->flags);
}
+end:
ec_schedule_ec_poll(ec);
return ACPI_SUCCESS(status) ?
ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED;
@@ -679,6 +688,7 @@ static struct acpi_ec *make_acpi_ec(void)
init_waitqueue_head(&ec->wait);
INIT_LIST_HEAD(&ec->list);
INIT_DELAYED_WORK_DEFERRABLE(&ec->work, do_ec_poll);
+ atomic_set(&ec->irq_count, 0);
return ec;
}
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH] ACPI: EC: Detect irq storm
2008-03-21 14:07 ` [PATCH 6/6] ACPI: EC: Detect irq storm Alexey Starikovskiy
@ 2008-03-21 16:36 ` Alexey Starikovskiy
0 siblings, 0 replies; 8+ messages in thread
From: Alexey Starikovskiy @ 2008-03-21 16:36 UTC (permalink / raw)
To: LenBrown; +Cc: Linux-acpi
Problem seems to be that hw fails to clear GPE after we service it and write 1
into corresponding bit. Thus, as soon as we get interrupts enabled again, we
receive a new one. Google gives too many results for "acer interrupt storm" for
this being one-broken-machine case.
Reference: http://bugzilla.kernel.org/show_bug.cgi?id=9998
Signed-off-by: Alexey Starikovskiy <astarikovskiy@suse.de>
---
drivers/acpi/ec.c | 11 +++++++++++
1 files changed, 11 insertions(+), 0 deletions(-)
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index da67d22..f0e8216 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -106,6 +106,7 @@ static struct acpi_ec {
wait_queue_head_t wait;
struct list_head list;
struct delayed_work work;
+ atomic_t irq_count;
u8 handlers_installed;
} *boot_ec, *first_ec;
@@ -171,6 +172,7 @@ static void ec_switch_to_poll_mode(struct acpi_ec *ec)
static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, int force_poll)
{
+ atomic_set(&ec->irq_count, 0);
if (likely(test_bit(EC_FLAGS_GPE_MODE, &ec->flags)) &&
likely(!force_poll)) {
if (wait_event_timeout(ec->wait, acpi_ec_check_status(ec, event),
@@ -489,6 +491,12 @@ static u32 acpi_ec_gpe_handler(void *data)
u8 state = acpi_ec_read_status(ec);
pr_debug(PREFIX "~~~> interrupt\n");
+ atomic_inc(&ec->irq_count);
+ if (atomic_read(&ec->irq_count) > 5) {
+ pr_err(PREFIX "GPE storm detected, disabling EC GPE\n");
+ ec_switch_to_poll_mode(ec);
+ goto end;
+ }
clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags);
if (test_bit(EC_FLAGS_GPE_MODE, &ec->flags))
wake_up(&ec->wait);
@@ -507,6 +515,7 @@ static u32 acpi_ec_gpe_handler(void *data)
set_bit(EC_FLAGS_GPE_MODE, &ec->flags);
clear_bit(EC_FLAGS_RESCHEDULE_POLL, &ec->flags);
}
+end:
ec_schedule_ec_poll(ec);
return ACPI_SUCCESS(status) ?
ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED;
@@ -515,6 +524,7 @@ static u32 acpi_ec_gpe_handler(void *data)
static void do_ec_poll(struct work_struct *work)
{
struct acpi_ec *ec = container_of(work, struct acpi_ec, work.work);
+ atomic_set(&ec->irq_count, 0);
(void)acpi_ec_gpe_handler(ec);
}
@@ -679,6 +689,7 @@ static struct acpi_ec *make_acpi_ec(void)
init_waitqueue_head(&ec->wait);
INIT_LIST_HEAD(&ec->list);
INIT_DELAYED_WORK_DEFERRABLE(&ec->work, do_ec_poll);
+ atomic_set(&ec->irq_count, 0);
return ec;
}
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH 1/6] Restore udelay in poll mode
2008-03-21 14:06 [PATCH 1/6] Restore udelay in poll mode Alexey Starikovskiy
` (4 preceding siblings ...)
2008-03-21 14:07 ` [PATCH 6/6] ACPI: EC: Detect irq storm Alexey Starikovskiy
@ 2008-03-25 0:52 ` Len Brown
5 siblings, 0 replies; 8+ messages in thread
From: Len Brown @ 2008-03-25 0:52 UTC (permalink / raw)
To: Alexey Starikovskiy; +Cc: Linux-acpi
1-6 added to acpi-test
thanks,
-Len
On Friday 21 March 2008, Alexey Starikovskiy wrote:
> Allow EC to serve keyboard even then we polling it.
>
> Signed-off-by: Alexey Starikovskiy <astarikovskiy@suse.de>
> ---
>
> drivers/acpi/ec.c | 2 ++
> 1 files changed, 2 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
> index 7222a18..828c752 100644
> --- a/drivers/acpi/ec.c
> +++ b/drivers/acpi/ec.c
> @@ -73,6 +73,7 @@ enum ec_event {
>
> #define ACPI_EC_DELAY 500 /* Wait 500ms max. during EC ops */
> #define ACPI_EC_UDELAY_GLK 1000 /* Wait 1ms max. to get global lock */
> +#define ACPI_EC_UDELAY 100 /* Wait 100us before polling EC again */
>
> enum {
> EC_FLAGS_WAIT_GPE = 0, /* Don't check status until GPE arrives */
> @@ -227,6 +228,7 @@ static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, int force_poll)
> while (time_before(jiffies, delay)) {
> if (acpi_ec_check_status(ec, event))
> goto end;
> + udelay(ACPI_EC_UDELAY);
> }
> }
> pr_err(PREFIX "acpi_ec_wait timeout,"
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2008-03-25 0:52 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-03-21 14:06 [PATCH 1/6] Restore udelay in poll mode Alexey Starikovskiy
2008-03-21 14:07 ` [PATCH 2/6] ACPI: EC: Add poll timer Alexey Starikovskiy
2008-03-21 14:07 ` [PATCH 3/6] Improve debug output Alexey Starikovskiy
2008-03-21 14:07 ` [PATCH 4/6] Drop support for broken controllers Alexey Starikovskiy
2008-03-21 14:07 ` [PATCH 5/6] ACPI: EC: Switch off GPE mode during suspend/resume Alexey Starikovskiy
2008-03-21 14:07 ` [PATCH 6/6] ACPI: EC: Detect irq storm Alexey Starikovskiy
2008-03-21 16:36 ` [PATCH] " Alexey Starikovskiy
2008-03-25 0:52 ` [PATCH 1/6] Restore udelay in poll mode Len Brown
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox