struct transaction transaction;
        struct work_struct work;
        struct acpi_ec_query_handler *handler;
+       struct acpi_ec *ec;
 };
 
 static int acpi_ec_query(struct acpi_ec *ec, u8 *data);
                ec_dbg_evt("Command(%s) submitted/blocked",
                           acpi_ec_cmd_string(ACPI_EC_COMMAND_QUERY));
                ec->nr_pending_queries++;
+               ec->events_in_progress++;
                queue_work(ec_wq, &ec->work);
        }
 }
 #ifdef CONFIG_PM_SLEEP
 static void __acpi_ec_flush_work(void)
 {
-       drain_workqueue(ec_wq); /* flush ec->work */
+       flush_workqueue(ec_wq); /* flush ec->work */
        flush_workqueue(ec_query_wq); /* flush queries */
 }
 
 }
 EXPORT_SYMBOL_GPL(acpi_ec_remove_query_handler);
 
-static struct acpi_ec_query *acpi_ec_create_query(u8 *pval)
+static struct acpi_ec_query *acpi_ec_create_query(struct acpi_ec *ec, u8 *pval)
 {
        struct acpi_ec_query *q;
        struct transaction *t;
        q = kzalloc(sizeof (struct acpi_ec_query), GFP_KERNEL);
        if (!q)
                return NULL;
+
        INIT_WORK(&q->work, acpi_ec_event_processor);
        t = &q->transaction;
        t->command = ACPI_EC_COMMAND_QUERY;
        t->rdata = pval;
        t->rlen = 1;
+       q->ec = ec;
        return q;
 }
 
 {
        struct acpi_ec_query *q = container_of(work, struct acpi_ec_query, work);
        struct acpi_ec_query_handler *handler = q->handler;
+       struct acpi_ec *ec = q->ec;
 
        ec_dbg_evt("Query(0x%02x) started", handler->query_bit);
+
        if (handler->func)
                handler->func(handler->data);
        else if (handler->handle)
                acpi_evaluate_object(handler->handle, NULL, NULL, NULL);
+
        ec_dbg_evt("Query(0x%02x) stopped", handler->query_bit);
+
+       spin_lock_irq(&ec->lock);
+       ec->queries_in_progress--;
+       spin_unlock_irq(&ec->lock);
+
        acpi_ec_delete_query(q);
 }
 
        int result;
        struct acpi_ec_query *q;
 
-       q = acpi_ec_create_query(&value);
+       q = acpi_ec_create_query(ec, &value);
        if (!q)
                return -ENOMEM;
 
        }
 
        /*
-        * It is reported that _Qxx are evaluated in a parallel way on
-        * Windows:
+        * It is reported that _Qxx are evaluated in a parallel way on Windows:
         * https://bugzilla.kernel.org/show_bug.cgi?id=94411
         *
-        * Put this log entry before schedule_work() in order to make
-        * it appearing before any other log entries occurred during the
-        * work queue execution.
+        * Put this log entry before queue_work() to make it appear in the log
+        * before any other messages emitted during workqueue handling.
         */
        ec_dbg_evt("Query(0x%02x) scheduled", value);
-       if (!queue_work(ec_query_wq, &q->work)) {
-               ec_dbg_evt("Query(0x%02x) overlapped", value);
-               result = -EBUSY;
-       }
+
+       spin_lock_irq(&ec->lock);
+
+       ec->queries_in_progress++;
+       queue_work(ec_query_wq, &q->work);
+
+       spin_unlock_irq(&ec->lock);
 
 err_exit:
        if (result)
        ec_dbg_evt("Event stopped");
 
        acpi_ec_check_event(ec);
+
+       spin_lock_irqsave(&ec->lock, flags);
+       ec->events_in_progress--;
+       spin_unlock_irqrestore(&ec->lock, flags);
 }
 
 static void acpi_ec_handle_interrupt(struct acpi_ec *ec)
 
 bool acpi_ec_dispatch_gpe(void)
 {
+       bool work_in_progress;
        u32 ret;
 
        if (!first_ec)
        if (ret == ACPI_INTERRUPT_HANDLED)
                pm_pr_dbg("ACPI EC GPE dispatched\n");
 
-       /* Flush the event and query workqueues. */
-       acpi_ec_flush_work();
+       /* Drain EC work. */
+       do {
+               acpi_ec_flush_work();
+
+               pm_pr_dbg("ACPI EC work flushed\n");
+
+               spin_lock_irq(&first_ec->lock);
+
+               work_in_progress = first_ec->events_in_progress +
+                       first_ec->queries_in_progress > 0;
+
+               spin_unlock_irq(&first_ec->lock);
+       } while (work_in_progress && !pm_wakeup_pending());
 
        return false;
 }