|
|
@@ -194,6 +194,7 @@ static struct workqueue_struct *ec_query_wq;
|
|
|
static int EC_FLAGS_QUERY_HANDSHAKE; /* Needs QR_EC issued when SCI_EVT set */
|
|
|
static int EC_FLAGS_CORRECT_ECDT; /* Needs ECDT port address correction */
|
|
|
static int EC_FLAGS_IGNORE_DSDT_GPE; /* Needs ECDT GPE as correction setting */
|
|
|
+static int EC_FLAGS_CLEAR_ON_RESUME; /* Needs acpi_ec_clear() on boot/resume */
|
|
|
|
|
|
/* --------------------------------------------------------------------------
|
|
|
* Logging/Debugging
|
|
|
@@ -499,6 +500,26 @@ static inline void __acpi_ec_disable_event(struct acpi_ec *ec)
|
|
|
ec_log_drv("event blocked");
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * Process _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(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);
|
|
|
+}
|
|
|
+
|
|
|
static void acpi_ec_enable_event(struct acpi_ec *ec)
|
|
|
{
|
|
|
unsigned long flags;
|
|
|
@@ -507,6 +528,10 @@ static void acpi_ec_enable_event(struct acpi_ec *ec)
|
|
|
if (acpi_ec_started(ec))
|
|
|
__acpi_ec_enable_event(ec);
|
|
|
spin_unlock_irqrestore(&ec->lock, flags);
|
|
|
+
|
|
|
+ /* Drain additional events if hardware requires that */
|
|
|
+ if (EC_FLAGS_CLEAR_ON_RESUME)
|
|
|
+ acpi_ec_clear(ec);
|
|
|
}
|
|
|
|
|
|
#ifdef CONFIG_PM_SLEEP
|
|
|
@@ -1820,6 +1845,31 @@ static int ec_flag_query_handshake(const struct dmi_system_id *id)
|
|
|
}
|
|
|
#endif
|
|
|
|
|
|
+/*
|
|
|
+ * 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;
|
|
|
+ ec_event_clearing = ACPI_EC_EVT_TIMING_STATUS;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Some ECDTs contain wrong register addresses.
|
|
|
* MSI MS-171F
|
|
|
@@ -1869,6 +1919,9 @@ static const struct dmi_system_id ec_dmi_table[] __initconst = {
|
|
|
ec_honor_ecdt_gpe, "ASUS X580VD", {
|
|
|
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
|
|
|
DMI_MATCH(DMI_PRODUCT_NAME, "X580VD"),}, NULL},
|
|
|
+ {
|
|
|
+ ec_clear_on_resume, "Samsung hardware", {
|
|
|
+ DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD.")}, NULL},
|
|
|
{},
|
|
|
};
|
|
|
|