|
@@ -67,6 +67,8 @@ enum ec_command {
|
|
|
#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_MSI_UDELAY 550 /* Wait 550us for MSI EC */
|
|
|
+#define ACPI_EC_CLEAR_MAX 100 /* Maximum number of events to query
|
|
|
+ * when trying to clear the EC */
|
|
|
|
|
|
enum {
|
|
|
EC_FLAGS_QUERY_PENDING, /* Query is pending */
|
|
@@ -116,6 +118,7 @@ EXPORT_SYMBOL(first_ec);
|
|
|
static int EC_FLAGS_MSI; /* Out-of-spec MSI controller */
|
|
|
static int EC_FLAGS_VALIDATE_ECDT; /* ASUStec ECDTs need to be validated */
|
|
|
static int EC_FLAGS_SKIP_DSDT_SCAN; /* Not all BIOS survive early DSDT scan */
|
|
|
+static int EC_FLAGS_CLEAR_ON_RESUME; /* Needs acpi_ec_clear() on boot/resume */
|
|
|
|
|
|
/* --------------------------------------------------------------------------
|
|
|
Transaction Management
|
|
@@ -440,6 +443,29 @@ acpi_handle ec_get_handle(void)
|
|
|
|
|
|
EXPORT_SYMBOL(ec_get_handle);
|
|
|
|
|
|
+static int acpi_ec_query_unlocked(struct acpi_ec *ec, u8 *data);
|
|
|
+
|
|
|
+/*
|
|
|
+ * Clears stale _Q events that might have accumulated in the EC.
|
|
|
+ * Run with locked ec mutex.
|
|
|
+ */
|
|
|
+static void acpi_ec_clear(struct acpi_ec *ec)
|
|
|
+{
|
|
|
+ int i, status;
|
|
|
+ u8 value = 0;
|
|
|
+
|
|
|
+ for (i = 0; i < ACPI_EC_CLEAR_MAX; i++) {
|
|
|
+ status = acpi_ec_query_unlocked(ec, &value);
|
|
|
+ if (status || !value)
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (unlikely(i == ACPI_EC_CLEAR_MAX))
|
|
|
+ pr_warn("Warning: Maximum of %d stale EC events cleared\n", i);
|
|
|
+ else
|
|
|
+ pr_info("%d stale EC events cleared\n", i);
|
|
|
+}
|
|
|
+
|
|
|
void acpi_ec_block_transactions(void)
|
|
|
{
|
|
|
struct acpi_ec *ec = first_ec;
|
|
@@ -463,6 +489,10 @@ void acpi_ec_unblock_transactions(void)
|
|
|
mutex_lock(&ec->mutex);
|
|
|
/* Allow transactions to be carried out again */
|
|
|
clear_bit(EC_FLAGS_BLOCKED, &ec->flags);
|
|
|
+
|
|
|
+ if (EC_FLAGS_CLEAR_ON_RESUME)
|
|
|
+ acpi_ec_clear(ec);
|
|
|
+
|
|
|
mutex_unlock(&ec->mutex);
|
|
|
}
|
|
|
|
|
@@ -821,6 +851,13 @@ static int acpi_ec_add(struct acpi_device *device)
|
|
|
|
|
|
/* EC is fully operational, allow queries */
|
|
|
clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags);
|
|
|
+
|
|
|
+ /* Clear stale _Q events if hardware might require that */
|
|
|
+ if (EC_FLAGS_CLEAR_ON_RESUME) {
|
|
|
+ mutex_lock(&ec->mutex);
|
|
|
+ acpi_ec_clear(ec);
|
|
|
+ mutex_unlock(&ec->mutex);
|
|
|
+ }
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
@@ -922,6 +959,30 @@ static int ec_enlarge_storm_threshold(const struct dmi_system_id *id)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * On some hardware it is necessary to clear events accumulated by the EC during
|
|
|
+ * sleep. These ECs stop reporting GPEs until they are manually polled, if too
|
|
|
+ * many events are accumulated. (e.g. Samsung Series 5/9 notebooks)
|
|
|
+ *
|
|
|
+ * https://bugzilla.kernel.org/show_bug.cgi?id=44161
|
|
|
+ *
|
|
|
+ * Ideally, the EC should also be instructed NOT to accumulate events during
|
|
|
+ * sleep (which Windows seems to do somehow), but the interface to control this
|
|
|
+ * behaviour is not known at this time.
|
|
|
+ *
|
|
|
+ * Models known to be affected are Samsung 530Uxx/535Uxx/540Uxx/550Pxx/900Xxx,
|
|
|
+ * however it is very likely that other Samsung models are affected.
|
|
|
+ *
|
|
|
+ * On systems which don't accumulate _Q events during sleep, this extra check
|
|
|
+ * should be harmless.
|
|
|
+ */
|
|
|
+static int ec_clear_on_resume(const struct dmi_system_id *id)
|
|
|
+{
|
|
|
+ pr_debug("Detected system needing EC poll on resume.\n");
|
|
|
+ EC_FLAGS_CLEAR_ON_RESUME = 1;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
static struct dmi_system_id ec_dmi_table[] __initdata = {
|
|
|
{
|
|
|
ec_skip_dsdt_scan, "Compal JFL92", {
|
|
@@ -965,6 +1026,9 @@ static struct dmi_system_id ec_dmi_table[] __initdata = {
|
|
|
ec_validate_ecdt, "ASUS hardware", {
|
|
|
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTek Computer Inc."),
|
|
|
DMI_MATCH(DMI_PRODUCT_NAME, "L4R"),}, NULL},
|
|
|
+ {
|
|
|
+ ec_clear_on_resume, "Samsung hardware", {
|
|
|
+ DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD.")}, NULL},
|
|
|
{},
|
|
|
};
|
|
|
|