EC_FLAGS_QUERY_ENABLED, /* Query is enabled */
EC_FLAGS_QUERY_PENDING, /* Query is pending */
EC_FLAGS_QUERY_GUARDING, /* Guard for SCI_EVT check */
----- EC_FLAGS_GPE_HANDLER_INSTALLED, /* GPE handler installed */
+++++ EC_FLAGS_EVENT_HANDLER_INSTALLED, /* Event handler installed */
EC_FLAGS_EC_HANDLER_INSTALLED, /* OpReg handler installed */
----- EC_FLAGS_EVT_HANDLER_INSTALLED, /* _Qxx handlers installed */
+++++ EC_FLAGS_QUERY_METHODS_INSTALLED, /* _Qxx handlers installed */
EC_FLAGS_STARTED, /* Driver is started */
EC_FLAGS_STOPPED, /* Driver is stopped */
----- EC_FLAGS_GPE_MASKED, /* GPE masked */
+++++ EC_FLAGS_EVENTS_MASKED, /* Events masked */
};
#define ACPI_EC_COMMAND_POLL 0x01 /* Available for command byte */
static void acpi_ec_submit_request(struct acpi_ec *ec)
{
ec->reference_count++;
----- if (test_bit(EC_FLAGS_GPE_HANDLER_INSTALLED, &ec->flags) &&
----- ec->reference_count == 1)
+++++ if (test_bit(EC_FLAGS_EVENT_HANDLER_INSTALLED, &ec->flags) &&
+++++ ec->gpe >= 0 && ec->reference_count == 1)
acpi_ec_enable_gpe(ec, true);
}
bool flushed = false;
ec->reference_count--;
----- if (test_bit(EC_FLAGS_GPE_HANDLER_INSTALLED, &ec->flags) &&
----- ec->reference_count == 0)
+++++ if (test_bit(EC_FLAGS_EVENT_HANDLER_INSTALLED, &ec->flags) &&
+++++ ec->gpe >= 0 && ec->reference_count == 0)
acpi_ec_disable_gpe(ec, true);
flushed = acpi_ec_flushed(ec);
if (flushed)
wake_up(&ec->wait);
}
-----static void acpi_ec_mask_gpe(struct acpi_ec *ec)
+++++static void acpi_ec_mask_events(struct acpi_ec *ec)
{
----- if (!test_bit(EC_FLAGS_GPE_MASKED, &ec->flags)) {
----- acpi_ec_disable_gpe(ec, false);
+++++ if (!test_bit(EC_FLAGS_EVENTS_MASKED, &ec->flags)) {
+++++ if (ec->gpe >= 0)
+++++ acpi_ec_disable_gpe(ec, false);
+++++ else
+++++ disable_irq_nosync(ec->irq);
+++++
ec_dbg_drv("Polling enabled");
----- set_bit(EC_FLAGS_GPE_MASKED, &ec->flags);
+++++ set_bit(EC_FLAGS_EVENTS_MASKED, &ec->flags);
}
}
-----static void acpi_ec_unmask_gpe(struct acpi_ec *ec)
+++++static void acpi_ec_unmask_events(struct acpi_ec *ec)
{
----- if (test_bit(EC_FLAGS_GPE_MASKED, &ec->flags)) {
----- clear_bit(EC_FLAGS_GPE_MASKED, &ec->flags);
----- acpi_ec_enable_gpe(ec, false);
+++++ if (test_bit(EC_FLAGS_EVENTS_MASKED, &ec->flags)) {
+++++ clear_bit(EC_FLAGS_EVENTS_MASKED, &ec->flags);
+++++ if (ec->gpe >= 0)
+++++ acpi_ec_enable_gpe(ec, false);
+++++ else
+++++ enable_irq(ec->irq);
+++++
ec_dbg_drv("Polling disabled");
}
}
static void acpi_ec_submit_query(struct acpi_ec *ec)
{
----- acpi_ec_mask_gpe(ec);
+++++ acpi_ec_mask_events(ec);
if (!acpi_ec_event_enabled(ec))
return;
if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) {
if (test_and_clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags))
ec_dbg_evt("Command(%s) unblocked",
acpi_ec_cmd_string(ACPI_EC_COMMAND_QUERY));
----- acpi_ec_unmask_gpe(ec);
+++++ acpi_ec_unmask_events(ec);
}
static inline void __acpi_ec_enable_event(struct acpi_ec *ec)
}
#ifdef CONFIG_PM_SLEEP
- ----static bool acpi_ec_query_flushed(struct acpi_ec *ec)
----{
---- bool flushed;
---- unsigned long flags;
----
---- spin_lock_irqsave(&ec->lock, flags);
---- flushed = !ec->nr_pending_queries;
---- spin_unlock_irqrestore(&ec->lock, flags);
---- return flushed;
----}
----
----static void __acpi_ec_flush_event(struct acpi_ec *ec)
+ ++++static void __acpi_ec_flush_work(void)
{
- bool flushed;
- unsigned long flags;
-
- spin_lock_irqsave(&ec->lock, flags);
- flushed = !ec->nr_pending_queries;
- spin_unlock_irqrestore(&ec->lock, flags);
- return flushed;
- }
-
- static void __acpi_ec_flush_event(struct acpi_ec *ec)
- {
- ---- /*
- ---- * When ec_freeze_events is true, we need to flush events in
- ---- * the proper position before entering the noirq stage.
- ---- */
- ---- wait_event(ec->wait, acpi_ec_query_flushed(ec));
- ---- if (ec_query_wq)
- ---- flush_workqueue(ec_query_wq);
+ ++++ flush_scheduled_work(); /* flush ec->work */
+ ++++ flush_workqueue(ec_query_wq); /* flush queries */
}
static void acpi_ec_disable_event(struct acpi_ec *ec)
spin_lock_irqsave(&ec->lock, flags);
__acpi_ec_disable_event(ec);
spin_unlock_irqrestore(&ec->lock, flags);
- ---- __acpi_ec_flush_event(ec);
+ ++++
+ ++++ /*
+ ++++ * When ec_freeze_events is true, we need to flush events in
+ ++++ * the proper position before entering the noirq stage.
+ ++++ */
+ ++++ __acpi_ec_flush_work();
}
void acpi_ec_flush_work(void)
{
- ---- if (first_ec)
- ---- __acpi_ec_flush_event(first_ec);
+ ++++ /* Without ec_query_wq there is nothing to flush. */
+ ++++ if (!ec_query_wq)
+ ++++ return;
- ---- flush_scheduled_work();
+ ++++ __acpi_ec_flush_work();
}
#endif /* CONFIG_PM_SLEEP */
* ensure a hardware STS 0->1 change after this clearing can always
* trigger a GPE interrupt.
*/
----- acpi_ec_clear_gpe(ec);
+++++ if (ec->gpe >= 0)
+++++ acpi_ec_clear_gpe(ec);
+++++
status = acpi_ec_read_status(ec);
t = ec->curr;
/*
++t->irq_count;
/* Allow triggering on 0 threshold */
if (t->irq_count == ec_storm_threshold)
----- acpi_ec_mask_gpe(ec);
+++++ acpi_ec_mask_events(ec);
}
}
out:
spin_lock_irqsave(&ec->lock, tmp);
if (t->irq_count == ec_storm_threshold)
----- acpi_ec_unmask_gpe(ec);
+++++ acpi_ec_unmask_events(ec);
ec_dbg_req("Command(%s) stopped", acpi_ec_cmd_string(t->command));
ec->curr = NULL;
/* Disable GPE for command processing (IBF=0/OBF=1) */
acpi_ec_check_event(ec);
}
-----static u32 acpi_ec_gpe_handler(acpi_handle gpe_device,
----- u32 gpe_number, void *data)
+++++static void acpi_ec_handle_interrupt(struct acpi_ec *ec)
{
unsigned long flags;
----- struct acpi_ec *ec = data;
spin_lock_irqsave(&ec->lock, flags);
advance_transaction(ec);
spin_unlock_irqrestore(&ec->lock, flags);
+++++}
+++++
+++++static u32 acpi_ec_gpe_handler(acpi_handle gpe_device,
+++++ u32 gpe_number, void *data)
+++++{
+++++ acpi_ec_handle_interrupt(data);
return ACPI_INTERRUPT_HANDLED;
}
+++++static irqreturn_t acpi_ec_irq_handler(int irq, void *data)
+++++{
+++++ acpi_ec_handle_interrupt(data);
+++++ return IRQ_HANDLED;
+++++}
+++++
/* --------------------------------------------------------------------------
* Address Space Management
* -------------------------------------------------------------------------- */
ec->timestamp = jiffies;
ec->busy_polling = true;
ec->polling_guard = 0;
+++++ ec->gpe = -1;
+++++ ec->irq = -1;
return ec;
}
/* Get GPE bit assignment (EC events). */
/* TODO: Add support for _GPE returning a package */
status = acpi_evaluate_integer(handle, "_GPE", NULL, &tmp);
----- if (ACPI_FAILURE(status))
----- return status;
----- ec->gpe = tmp;
+++++ if (ACPI_SUCCESS(status))
+++++ ec->gpe = tmp;
+++++
+++++ /*
+++++ * Errors are non-fatal, allowing for ACPI Reduced Hardware
+++++ * platforms which use GpioInt instead of GPE.
+++++ */
}
/* Use the global lock for all EC transactions? */
tmp = 0;
return AE_CTRL_TERMINATE;
}
+++++static void install_gpe_event_handler(struct acpi_ec *ec)
+++++{
+++++ acpi_status status =
+++++ acpi_install_gpe_raw_handler(NULL, ec->gpe,
+++++ ACPI_GPE_EDGE_TRIGGERED,
+++++ &acpi_ec_gpe_handler,
+++++ ec);
+++++ if (ACPI_SUCCESS(status)) {
+++++ /* This is not fatal as we can poll EC events */
+++++ set_bit(EC_FLAGS_EVENT_HANDLER_INSTALLED, &ec->flags);
+++++ acpi_ec_leave_noirq(ec);
+++++ if (test_bit(EC_FLAGS_STARTED, &ec->flags) &&
+++++ ec->reference_count >= 1)
+++++ acpi_ec_enable_gpe(ec, true);
+++++ }
+++++}
+++++
+++++/* ACPI reduced hardware platforms use a GpioInt specified in _CRS. */
+++++static int install_gpio_irq_event_handler(struct acpi_ec *ec,
+++++ struct acpi_device *device)
+++++{
+++++ int irq = acpi_dev_gpio_irq_get(device, 0);
+++++ int ret;
+++++
+++++ if (irq < 0)
+++++ return irq;
+++++
+++++ ret = request_irq(irq, acpi_ec_irq_handler, IRQF_SHARED,
+++++ "ACPI EC", ec);
+++++
+++++ /*
+++++ * Unlike the GPE case, we treat errors here as fatal, we'll only
+++++ * implement GPIO polling if we find a case that needs it.
+++++ */
+++++ if (ret < 0)
+++++ return ret;
+++++
+++++ ec->irq = irq;
+++++ set_bit(EC_FLAGS_EVENT_HANDLER_INSTALLED, &ec->flags);
+++++ acpi_ec_leave_noirq(ec);
+++++
+++++ return 0;
+++++}
+++++
/*
* Note: This function returns an error code only when the address space
* handler is not installed, which means "not able to handle
* transactions".
*/
-----static int ec_install_handlers(struct acpi_ec *ec, bool handle_events)
+++++static int ec_install_handlers(struct acpi_ec *ec, struct acpi_device *device,
+++++ bool handle_events)
{
acpi_status status;
if (!handle_events)
return 0;
----- if (!test_bit(EC_FLAGS_EVT_HANDLER_INSTALLED, &ec->flags)) {
+++++ if (!test_bit(EC_FLAGS_QUERY_METHODS_INSTALLED, &ec->flags)) {
/* Find and register all query methods */
acpi_walk_namespace(ACPI_TYPE_METHOD, ec->handle, 1,
acpi_ec_register_query_methods,
NULL, ec, NULL);
----- set_bit(EC_FLAGS_EVT_HANDLER_INSTALLED, &ec->flags);
+++++ set_bit(EC_FLAGS_QUERY_METHODS_INSTALLED, &ec->flags);
}
----- if (!test_bit(EC_FLAGS_GPE_HANDLER_INSTALLED, &ec->flags)) {
----- status = acpi_install_gpe_raw_handler(NULL, ec->gpe,
----- ACPI_GPE_EDGE_TRIGGERED,
----- &acpi_ec_gpe_handler, ec);
----- /* This is not fatal as we can poll EC events */
----- if (ACPI_SUCCESS(status)) {
----- set_bit(EC_FLAGS_GPE_HANDLER_INSTALLED, &ec->flags);
----- acpi_ec_leave_noirq(ec);
----- if (test_bit(EC_FLAGS_STARTED, &ec->flags) &&
----- ec->reference_count >= 1)
----- acpi_ec_enable_gpe(ec, true);
+++++ if (!test_bit(EC_FLAGS_EVENT_HANDLER_INSTALLED, &ec->flags)) {
+++++ if (ec->gpe >= 0) {
+++++ install_gpe_event_handler(ec);
+++++ } else if (device) {
+++++ int ret = install_gpio_irq_event_handler(ec, device);
+++++
+++++ if (ret)
+++++ return ret;
+++++ } else { /* No GPE and no GpioInt? */
+++++ return -ENODEV;
}
}
/* EC is fully operational, allow queries */
*/
acpi_ec_stop(ec, false);
----- if (test_bit(EC_FLAGS_GPE_HANDLER_INSTALLED, &ec->flags)) {
----- if (ACPI_FAILURE(acpi_remove_gpe_handler(NULL, ec->gpe,
----- &acpi_ec_gpe_handler)))
+++++ if (test_bit(EC_FLAGS_EVENT_HANDLER_INSTALLED, &ec->flags)) {
+++++ if (ec->gpe >= 0 &&
+++++ ACPI_FAILURE(acpi_remove_gpe_handler(NULL, ec->gpe,
+++++ &acpi_ec_gpe_handler)))
pr_err("failed to remove gpe handler\n");
----- clear_bit(EC_FLAGS_GPE_HANDLER_INSTALLED, &ec->flags);
+++++
+++++ if (ec->irq >= 0)
+++++ free_irq(ec->irq, ec);
+++++
+++++ clear_bit(EC_FLAGS_EVENT_HANDLER_INSTALLED, &ec->flags);
}
----- if (test_bit(EC_FLAGS_EVT_HANDLER_INSTALLED, &ec->flags)) {
+++++ if (test_bit(EC_FLAGS_QUERY_METHODS_INSTALLED, &ec->flags)) {
acpi_ec_remove_query_handlers(ec, true, 0);
----- clear_bit(EC_FLAGS_EVT_HANDLER_INSTALLED, &ec->flags);
+++++ clear_bit(EC_FLAGS_QUERY_METHODS_INSTALLED, &ec->flags);
}
}
-----static int acpi_ec_setup(struct acpi_ec *ec, bool handle_events)
+++++static int acpi_ec_setup(struct acpi_ec *ec, struct acpi_device *device,
+++++ bool handle_events)
{
int ret;
----- ret = ec_install_handlers(ec, handle_events);
+++++ ret = ec_install_handlers(ec, device, handle_events);
if (ret)
return ret;
}
acpi_handle_info(ec->handle,
----- "GPE=0x%x, EC_CMD/EC_SC=0x%lx, EC_DATA=0x%lx\n",
----- ec->gpe, ec->command_addr, ec->data_addr);
+++++ "GPE=0x%x, IRQ=%d, EC_CMD/EC_SC=0x%lx, EC_DATA=0x%lx\n",
+++++ ec->gpe, ec->irq, ec->command_addr, ec->data_addr);
return ret;
}
}
}
----- ret = acpi_ec_setup(ec, true);
+++++ ret = acpi_ec_setup(ec, device, true);
if (ret)
goto err_query;
* At this point, the GPE is not fully initialized, so do not to
* handle the events.
*/
----- ret = acpi_ec_setup(ec, false);
+++++ ret = acpi_ec_setup(ec, NULL, false);
if (ret) {
acpi_ec_free(ec);
return;
ec->command_addr = ecdt_ptr->control.address;
ec->data_addr = ecdt_ptr->data.address;
}
----- ec->gpe = ecdt_ptr->gpe;
+++++
+++++ /*
+++++ * Ignore the GPE value on Reduced Hardware platforms.
+++++ * Some products have this set to an erroneous value.
+++++ */
+++++ if (!acpi_gbl_reduced_hardware)
+++++ ec->gpe = ecdt_ptr->gpe;
+++++
ec->handle = ACPI_ROOT_OBJECT;
/*
* At this point, the namespace is not initialized, so do not find
* the namespace objects, or handle the events.
*/
----- ret = acpi_ec_setup(ec, false);
+++++ ret = acpi_ec_setup(ec, NULL, false);
if (ret) {
acpi_ec_free(ec);
return;
* masked at the low level without side effects.
*/
if (ec_no_wakeup && test_bit(EC_FLAGS_STARTED, &ec->flags) &&
----- ec->reference_count >= 1)
+++++ ec->gpe >= 0 && ec->reference_count >= 1)
acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_DISABLE);
acpi_ec_enter_noirq(ec);
acpi_ec_leave_noirq(ec);
if (ec_no_wakeup && test_bit(EC_FLAGS_STARTED, &ec->flags) &&
----- ec->reference_count >= 1)
+++++ ec->gpe >= 0 && ec->reference_count >= 1)
acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_ENABLE);
return 0;