All of lore.kernel.org
 help / color / mirror / Atom feed
* [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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.