--- /dev/null
+From a62e8f1978f49e52f87a711ff6711b323d4b12ff Mon Sep 17 00:00:00 2001
+From: Alexey Starikovskiy <astarikovskiy@suse.de>
+Date: Thu, 24 Dec 2009 11:34:16 +0300
+Subject: ACPI: EC: Accelerate query execution
+
+From: Alexey Starikovskiy <astarikovskiy@suse.de>
+
+commit a62e8f1978f49e52f87a711ff6711b323d4b12ff upstream.
+
+Split EC query handling into acknowledge and execution phase.
+This allows much smaller pending query lattency and lowers chances
+of EC going "wild" and losing events.
+
+Reference: http://bugzilla.kernel.org/show_bug.cgi?id=14858
+
+Signed-off-by: Alexey Starikovskiy <astarikovskiy@suse.de>
+Signed-off-by: Len Brown <len.brown@intel.com>
+Cc: François Valenduc <francois.valenduc@tvcablenet.be>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/acpi/ec.c | 122 ++++++++++++++++++++++++++++++++++--------------------
+ 1 file changed, 77 insertions(+), 45 deletions(-)
+
+--- a/drivers/acpi/ec.c
++++ b/drivers/acpi/ec.c
+@@ -201,14 +201,13 @@ unlock:
+ spin_unlock_irqrestore(&ec->curr_lock, flags);
+ }
+
+-static void acpi_ec_gpe_query(void *ec_cxt);
++static int acpi_ec_sync_query(struct acpi_ec *ec);
+
+-static int ec_check_sci(struct acpi_ec *ec, u8 state)
++static int ec_check_sci_sync(struct acpi_ec *ec, u8 state)
+ {
+ if (state & ACPI_EC_FLAG_SCI) {
+ if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags))
+- return acpi_os_execute(OSL_EC_BURST_HANDLER,
+- acpi_ec_gpe_query, ec);
++ return acpi_ec_sync_query(ec);
+ }
+ return 0;
+ }
+@@ -249,11 +248,6 @@ static int acpi_ec_transaction_unlocked(
+ {
+ unsigned long tmp;
+ int ret = 0;
+- pr_debug(PREFIX "transaction start\n");
+- /* disable GPE during transaction if storm is detected */
+- if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) {
+- acpi_disable_gpe(NULL, ec->gpe);
+- }
+ if (EC_FLAGS_MSI)
+ udelay(ACPI_EC_MSI_UDELAY);
+ /* start transaction */
+@@ -269,16 +263,6 @@ static int acpi_ec_transaction_unlocked(
+ spin_lock_irqsave(&ec->curr_lock, tmp);
+ ec->curr = NULL;
+ spin_unlock_irqrestore(&ec->curr_lock, tmp);
+- if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) {
+- /* check if we received SCI during transaction */
+- ec_check_sci(ec, acpi_ec_read_status(ec));
+- /* it is safe to enable GPE outside of transaction */
+- acpi_enable_gpe(NULL, ec->gpe);
+- } else if (t->irq_count > ACPI_EC_STORM_THRESHOLD) {
+- pr_info(PREFIX "GPE storm detected, "
+- "transactions will use polling mode\n");
+- set_bit(EC_FLAGS_GPE_STORM, &ec->flags);
+- }
+ return ret;
+ }
+
+@@ -321,7 +305,24 @@ static int acpi_ec_transaction(struct ac
+ status = -ETIME;
+ goto end;
+ }
++ pr_debug(PREFIX "transaction start\n");
++ /* disable GPE during transaction if storm is detected */
++ if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) {
++ acpi_disable_gpe(NULL, ec->gpe);
++ }
++
+ status = acpi_ec_transaction_unlocked(ec, t);
++
++ /* check if we received SCI during transaction */
++ ec_check_sci_sync(ec, acpi_ec_read_status(ec));
++ if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) {
++ /* it is safe to enable GPE outside of transaction */
++ acpi_enable_gpe(NULL, ec->gpe);
++ } else if (t->irq_count > ACPI_EC_STORM_THRESHOLD) {
++ pr_info(PREFIX "GPE storm detected, "
++ "transactions will use polling mode\n");
++ set_bit(EC_FLAGS_GPE_STORM, &ec->flags);
++ }
+ end:
+ if (ec->global_lock)
+ acpi_release_global_lock(glk);
+@@ -443,7 +444,7 @@ int ec_transaction(u8 command,
+
+ EXPORT_SYMBOL(ec_transaction);
+
+-static int acpi_ec_query(struct acpi_ec *ec, u8 * data)
++static int acpi_ec_query_unlocked(struct acpi_ec *ec, u8 * data)
+ {
+ int result;
+ u8 d;
+@@ -452,20 +453,16 @@ static int acpi_ec_query(struct acpi_ec
+ .wlen = 0, .rlen = 1};
+ if (!ec || !data)
+ return -EINVAL;
+-
+ /*
+ * Query the EC to find out which _Qxx method we need to evaluate.
+ * Note that successful completion of the query causes the ACPI_EC_SCI
+ * bit to be cleared (and thus clearing the interrupt source).
+ */
+-
+- result = acpi_ec_transaction(ec, &t);
++ result = acpi_ec_transaction_unlocked(ec, &t);
+ if (result)
+ return result;
+-
+ if (!d)
+ return -ENODATA;
+-
+ *data = d;
+ return 0;
+ }
+@@ -509,43 +506,78 @@ void acpi_ec_remove_query_handler(struct
+
+ EXPORT_SYMBOL_GPL(acpi_ec_remove_query_handler);
+
+-static void acpi_ec_gpe_query(void *ec_cxt)
++static void acpi_ec_run(void *cxt)
+ {
+- struct acpi_ec *ec = ec_cxt;
+- u8 value = 0;
+- struct acpi_ec_query_handler *handler, copy;
+-
+- if (!ec || acpi_ec_query(ec, &value))
++ struct acpi_ec_query_handler *handler = cxt;
++ if (!handler)
+ return;
+- mutex_lock(&ec->lock);
++ pr_debug(PREFIX "start query execution\n");
++ if (handler->func)
++ handler->func(handler->data);
++ else if (handler->handle)
++ acpi_evaluate_object(handler->handle, NULL, NULL, NULL);
++ pr_debug(PREFIX "stop query execution\n");
++ kfree(handler);
++}
++
++static int acpi_ec_sync_query(struct acpi_ec *ec)
++{
++ u8 value = 0;
++ int status;
++ struct acpi_ec_query_handler *handler, *copy;
++ if ((status = acpi_ec_query_unlocked(ec, &value)))
++ return status;
+ list_for_each_entry(handler, &ec->list, node) {
+ if (value == handler->query_bit) {
+ /* have custom handler for this bit */
+- memcpy(©, handler, sizeof(copy));
+- mutex_unlock(&ec->lock);
+- if (copy.func) {
+- copy.func(copy.data);
+- } else if (copy.handle) {
+- acpi_evaluate_object(copy.handle, NULL, NULL, NULL);
+- }
+- return;
++ copy = kmalloc(sizeof(*handler), GFP_KERNEL);
++ if (!copy)
++ return -ENOMEM;
++ memcpy(copy, handler, sizeof(*copy));
++ pr_debug(PREFIX "push query execution (0x%2x) on queue\n", value);
++ return acpi_os_execute(OSL_GPE_HANDLER,
++ acpi_ec_run, copy);
+ }
+ }
++ return 0;
++}
++
++static void acpi_ec_gpe_query(void *ec_cxt)
++{
++ struct acpi_ec *ec = ec_cxt;
++ if (!ec)
++ return;
++ mutex_lock(&ec->lock);
++ acpi_ec_sync_query(ec);
+ mutex_unlock(&ec->lock);
+ }
+
++static void acpi_ec_gpe_query(void *ec_cxt);
++
++static int ec_check_sci(struct acpi_ec *ec, u8 state)
++{
++ if (state & ACPI_EC_FLAG_SCI) {
++ if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) {
++ pr_debug(PREFIX "push gpe query to the queue\n");
++ return acpi_os_execute(OSL_NOTIFY_HANDLER,
++ acpi_ec_gpe_query, ec);
++ }
++ }
++ return 0;
++}
++
+ static u32 acpi_ec_gpe_handler(void *data)
+ {
+ struct acpi_ec *ec = data;
+- u8 status;
+
+ pr_debug(PREFIX "~~~> interrupt\n");
+- status = acpi_ec_read_status(ec);
+
+- advance_transaction(ec, status);
+- if (ec_transaction_done(ec) && (status & ACPI_EC_FLAG_IBF) == 0)
++ advance_transaction(ec, acpi_ec_read_status(ec));
++ if (ec_transaction_done(ec) &&
++ (acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF) == 0) {
+ wake_up(&ec->wait);
+- ec_check_sci(ec, status);
++ ec_check_sci(ec, acpi_ec_read_status(ec));
++ }
+ return ACPI_INTERRUPT_HANDLED;
+ }
+
--- /dev/null
+From 54070101f86ca9a6e9ba243c999d144721ec3db7 Mon Sep 17 00:00:00 2001
+From: Alexey Starikovskiy <astarikovskiy@suse.de>
+Date: Wed, 30 Dec 2009 15:53:10 +0300
+Subject: ACPI: EC: Add wait for irq storm
+
+From: Alexey Starikovskiy <astarikovskiy@suse.de>
+
+commit 54070101f86ca9a6e9ba243c999d144721ec3db7 upstream.
+
+Merge of poll and irq modes accelerated EC transaction, so
+that keyboard starts to suffer again. Add msleep(1) into
+transaction path for the storm to allow keyboard controller
+to do its job.
+
+Reference: http://bugzilla.kernel.org/show_bug.cgi?id=14747
+
+Signed-off-by: Alexey Starikovskiy <astarikovskiy@suse.de>
+Signed-off-by: Len Brown <len.brown@intel.com>
+Cc: François Valenduc <francois.valenduc@tvcablenet.be>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/acpi/ec.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/acpi/ec.c
++++ b/drivers/acpi/ec.c
+@@ -259,7 +259,6 @@ static int acpi_ec_transaction_unlocked(
+ clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags);
+ spin_unlock_irqrestore(&ec->curr_lock, tmp);
+ ret = ec_poll(ec);
+- pr_debug(PREFIX "transaction end\n");
+ spin_lock_irqsave(&ec->curr_lock, tmp);
+ ec->curr = NULL;
+ spin_unlock_irqrestore(&ec->curr_lock, tmp);
+@@ -316,6 +315,7 @@ static int acpi_ec_transaction(struct ac
+ /* check if we received SCI during transaction */
+ ec_check_sci_sync(ec, acpi_ec_read_status(ec));
+ if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) {
++ msleep(1);
+ /* it is safe to enable GPE outside of transaction */
+ acpi_enable_gpe(NULL, ec->gpe);
+ } else if (t->irq_count > ACPI_EC_STORM_THRESHOLD) {
+@@ -323,6 +323,7 @@ static int acpi_ec_transaction(struct ac
+ "transactions will use polling mode\n");
+ set_bit(EC_FLAGS_GPE_STORM, &ec->flags);
+ }
++ pr_debug(PREFIX "transaction end\n");
+ end:
+ if (ec->global_lock)
+ acpi_release_global_lock(glk);