===================================================================
@@ -76,8 +76,9 @@ enum ec_command {
enum {
EC_FLAGS_QUERY_PENDING, /* Query is pending */
EC_FLAGS_GPE_STORM, /* GPE storm detected */
- EC_FLAGS_HANDLERS_INSTALLED /* Handlers for GPE and
+ EC_FLAGS_HANDLERS_INSTALLED, /* Handlers for GPE and
* OpReg are installed */
+ EC_FLAGS_SUSPENDED, /* Driver is suspended */
};
/* If we find an EC via the ECDT, we need to keep a ptr to its context */
@@ -291,6 +292,12 @@ static int acpi_ec_transaction(struct ac
if (t->rdata)
memset(t->rdata, 0, t->rlen);
mutex_lock(&ec->lock);
+ if (test_bit(EC_FLAGS_SUSPENDED, &ec->flags)) {
+ pr_err(PREFIX
+ "EC transaction discarded due to power transition\n");
+ status = -EINVAL;
+ goto unlock;
+ }
if (ec->global_lock) {
status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
if (ACPI_FAILURE(status)) {
@@ -445,6 +452,29 @@ int ec_transaction(u8 command,
EXPORT_SYMBOL(ec_transaction);
+void acpi_ec_suspend_transactions(void)
+{
+ struct acpi_ec *ec = first_ec;
+
+ if (!ec)
+ return;
+
+ mutex_lock(&ec->lock);
+ /* Prevent transactions from happening while suspended */
+ set_bit(EC_FLAGS_SUSPENDED, &ec->flags);
+ mutex_unlock(&ec->lock);
+}
+
+void acpi_ec_resume_transactions(void)
+{
+ /*
+ * Allow transactions to happen again (this function is called from
+ * atomic context during wake-up, so we don't need to acquire the mutex)
+ */
+ if (first_ec)
+ clear_bit(EC_FLAGS_SUSPENDED, &first_ec->flags);
+}
+
static int acpi_ec_query_unlocked(struct acpi_ec *ec, u8 * data)
{
int result;
===================================================================
@@ -49,6 +49,8 @@ void acpi_early_processor_set_pdc(void);
int acpi_ec_init(void);
int acpi_ec_ecdt_probe(void);
int acpi_boot_ec_enable(void);
+void acpi_ec_suspend_transactions(void);
+void acpi_ec_resume_transactions(void);
/*--------------------------------------------------------------------------
Suspend/Resume
===================================================================
@@ -110,11 +110,12 @@ void __init acpi_old_suspend_ordering(vo
}
/**
- * acpi_pm_disable_gpes - Disable the GPEs.
+ * acpi_pm_freeze - Disable the GPEs and suspend EC transactions.
*/
-static int acpi_pm_disable_gpes(void)
+static int acpi_pm_freeze(void)
{
acpi_disable_all_gpes();
+ acpi_ec_suspend_transactions();
return 0;
}
@@ -142,7 +143,8 @@ static int acpi_pm_prepare(void)
int error = __acpi_pm_prepare();
if (!error)
- acpi_disable_all_gpes();
+ acpi_pm_freeze();
+
return error;
}
@@ -276,6 +278,8 @@ static int acpi_suspend_enter(suspend_st
*/
acpi_disable_all_gpes();
+ acpi_ec_resume_transactions();
+
local_irq_restore(flags);
printk(KERN_DEBUG "Back to C!\n");
@@ -333,7 +337,7 @@ static int acpi_suspend_begin_old(suspen
static struct platform_suspend_ops acpi_suspend_ops_old = {
.valid = acpi_suspend_state_valid,
.begin = acpi_suspend_begin_old,
- .prepare_late = acpi_pm_disable_gpes,
+ .prepare_late = acpi_pm_freeze,
.enter = acpi_suspend_enter,
.wake = acpi_pm_finish,
.end = acpi_pm_end,
@@ -522,6 +526,7 @@ static int acpi_hibernation_enter(void)
status = acpi_enter_sleep_state(ACPI_STATE_S4);
/* Reprogram control registers and execute _BFS */
acpi_leave_sleep_state_prep(ACPI_STATE_S4);
+ acpi_ec_resume_transactions();
local_irq_restore(flags);
return ACPI_SUCCESS(status) ? 0 : -EFAULT;
@@ -550,6 +555,7 @@ static void acpi_hibernation_leave(void)
}
/* Restore the NVS memory area */
hibernate_nvs_restore();
+ acpi_ec_resume_transactions();
}
static void acpi_pm_enable_gpes(void)
@@ -565,7 +571,7 @@ static struct platform_hibernation_ops a
.prepare = acpi_pm_prepare,
.enter = acpi_hibernation_enter,
.leave = acpi_hibernation_leave,
- .pre_restore = acpi_pm_disable_gpes,
+ .pre_restore = acpi_pm_freeze,
.restore_cleanup = acpi_pm_enable_gpes,
};
@@ -598,12 +604,9 @@ static int acpi_hibernation_begin_old(vo
static int acpi_hibernation_pre_snapshot_old(void)
{
- int error = acpi_pm_disable_gpes();
-
- if (!error)
- hibernate_nvs_save();
-
- return error;
+ acpi_pm_freeze();
+ hibernate_nvs_save();
+ return 0;
}
/*
@@ -615,10 +618,10 @@ static struct platform_hibernation_ops a
.end = acpi_pm_end,
.pre_snapshot = acpi_hibernation_pre_snapshot_old,
.finish = acpi_hibernation_finish,
- .prepare = acpi_pm_disable_gpes,
+ .prepare = acpi_pm_freeze,
.enter = acpi_hibernation_enter,
.leave = acpi_hibernation_leave,
- .pre_restore = acpi_pm_disable_gpes,
+ .pre_restore = acpi_pm_freeze,
.restore_cleanup = acpi_pm_enable_gpes,
.recover = acpi_pm_finish,
};