|
@@ -59,6 +59,38 @@
|
|
|
#define ACPI_EC_FLAG_BURST 0x10 /* burst mode */
|
|
|
#define ACPI_EC_FLAG_SCI 0x20 /* EC-SCI occurred */
|
|
|
|
|
|
+/*
|
|
|
+ * The SCI_EVT clearing timing is not defined by the ACPI specification.
|
|
|
+ * This leads to lots of practical timing issues for the host EC driver.
|
|
|
+ * The following variations are defined (from the target EC firmware's
|
|
|
+ * perspective):
|
|
|
+ * STATUS: After indicating SCI_EVT edge triggered IRQ to the host, the
|
|
|
+ * target can clear SCI_EVT at any time so long as the host can see
|
|
|
+ * the indication by reading the status register (EC_SC). So the
|
|
|
+ * host should re-check SCI_EVT after the first time the SCI_EVT
|
|
|
+ * indication is seen, which is the same time the query request
|
|
|
+ * (QR_EC) is written to the command register (EC_CMD). SCI_EVT set
|
|
|
+ * at any later time could indicate another event. Normally such
|
|
|
+ * kind of EC firmware has implemented an event queue and will
|
|
|
+ * return 0x00 to indicate "no outstanding event".
|
|
|
+ * QUERY: After seeing the query request (QR_EC) written to the command
|
|
|
+ * register (EC_CMD) by the host and having prepared the responding
|
|
|
+ * event value in the data register (EC_DATA), the target can safely
|
|
|
+ * clear SCI_EVT because the target can confirm that the current
|
|
|
+ * event is being handled by the host. The host then should check
|
|
|
+ * SCI_EVT right after reading the event response from the data
|
|
|
+ * register (EC_DATA).
|
|
|
+ * EVENT: After seeing the event response read from the data register
|
|
|
+ * (EC_DATA) by the host, the target can clear SCI_EVT. As the
|
|
|
+ * target requires time to notice the change in the data register
|
|
|
+ * (EC_DATA), the host may be required to wait additional guarding
|
|
|
+ * time before checking the SCI_EVT again. Such guarding may not be
|
|
|
+ * necessary if the host is notified via another IRQ.
|
|
|
+ */
|
|
|
+#define ACPI_EC_EVT_TIMING_STATUS 0x00
|
|
|
+#define ACPI_EC_EVT_TIMING_QUERY 0x01
|
|
|
+#define ACPI_EC_EVT_TIMING_EVENT 0x02
|
|
|
+
|
|
|
/* EC commands */
|
|
|
enum ec_command {
|
|
|
ACPI_EC_COMMAND_READ = 0x80,
|
|
@@ -76,6 +108,7 @@ enum ec_command {
|
|
|
|
|
|
enum {
|
|
|
EC_FLAGS_QUERY_PENDING, /* Query is pending */
|
|
|
+ EC_FLAGS_QUERY_GUARDING, /* Guard for SCI_EVT check */
|
|
|
EC_FLAGS_HANDLERS_INSTALLED, /* Handlers for GPE and
|
|
|
* OpReg are installed */
|
|
|
EC_FLAGS_STARTED, /* Driver is started */
|
|
@@ -100,6 +133,8 @@ static unsigned int ec_polling_guard __read_mostly = ACPI_EC_UDELAY_POLL;
|
|
|
module_param(ec_polling_guard, uint, 0644);
|
|
|
MODULE_PARM_DESC(ec_polling_guard, "Guard time(us) between EC accesses in polling modes");
|
|
|
|
|
|
+static unsigned int ec_event_clearing __read_mostly = ACPI_EC_EVT_TIMING_STATUS;
|
|
|
+
|
|
|
/*
|
|
|
* If the number of false interrupts per one transaction exceeds
|
|
|
* this threshold, will think there is a GPE storm happened and
|
|
@@ -400,6 +435,21 @@ static void acpi_ec_complete_query(struct acpi_ec *ec)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+static bool acpi_ec_guard_event(struct acpi_ec *ec)
|
|
|
+{
|
|
|
+ if (ec_event_clearing == ACPI_EC_EVT_TIMING_STATUS ||
|
|
|
+ ec_event_clearing == ACPI_EC_EVT_TIMING_QUERY ||
|
|
|
+ !test_bit(EC_FLAGS_QUERY_PENDING, &ec->flags) ||
|
|
|
+ (ec->curr && ec->curr->command == ACPI_EC_COMMAND_QUERY))
|
|
|
+ return false;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Postpone the query submission to allow the firmware to proceed,
|
|
|
+ * we shouldn't check SCI_EVT before the firmware reflagging it.
|
|
|
+ */
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
static int ec_transaction_polled(struct acpi_ec *ec)
|
|
|
{
|
|
|
unsigned long flags;
|
|
@@ -428,8 +478,15 @@ static inline void ec_transaction_transition(struct acpi_ec *ec, unsigned long f
|
|
|
{
|
|
|
ec->curr->flags |= flag;
|
|
|
if (ec->curr->command == ACPI_EC_COMMAND_QUERY) {
|
|
|
- if (flag == ACPI_EC_COMMAND_POLL)
|
|
|
+ if (ec_event_clearing == ACPI_EC_EVT_TIMING_STATUS &&
|
|
|
+ flag == ACPI_EC_COMMAND_POLL)
|
|
|
+ acpi_ec_complete_query(ec);
|
|
|
+ if (ec_event_clearing == ACPI_EC_EVT_TIMING_QUERY &&
|
|
|
+ flag == ACPI_EC_COMMAND_COMPLETE)
|
|
|
acpi_ec_complete_query(ec);
|
|
|
+ if (ec_event_clearing == ACPI_EC_EVT_TIMING_EVENT &&
|
|
|
+ flag == ACPI_EC_COMMAND_COMPLETE)
|
|
|
+ set_bit(EC_FLAGS_QUERY_GUARDING, &ec->flags);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -449,6 +506,17 @@ static void advance_transaction(struct acpi_ec *ec)
|
|
|
acpi_ec_clear_gpe(ec);
|
|
|
status = acpi_ec_read_status(ec);
|
|
|
t = ec->curr;
|
|
|
+ /*
|
|
|
+ * Another IRQ or a guarded polling mode advancement is detected,
|
|
|
+ * the next QR_EC submission is then allowed.
|
|
|
+ */
|
|
|
+ if (!t || !(t->flags & ACPI_EC_COMMAND_POLL)) {
|
|
|
+ if (ec_event_clearing == ACPI_EC_EVT_TIMING_EVENT &&
|
|
|
+ test_bit(EC_FLAGS_QUERY_GUARDING, &ec->flags)) {
|
|
|
+ clear_bit(EC_FLAGS_QUERY_GUARDING, &ec->flags);
|
|
|
+ acpi_ec_complete_query(ec);
|
|
|
+ }
|
|
|
+ }
|
|
|
if (!t)
|
|
|
goto err;
|
|
|
if (t->flags & ACPI_EC_COMMAND_POLL) {
|
|
@@ -534,11 +602,13 @@ static int ec_guard(struct acpi_ec *ec)
|
|
|
/*
|
|
|
* Perform wait polling
|
|
|
*
|
|
|
- * The following check is there to keep the old
|
|
|
- * logic - no inter-transaction guarding for the
|
|
|
- * wait polling mode.
|
|
|
+ * For SCI_EVT clearing timing of "event",
|
|
|
+ * performing guarding before re-checking the
|
|
|
+ * SCI_EVT. Otherwise, such guarding is not needed
|
|
|
+ * due to the old practices.
|
|
|
*/
|
|
|
- if (!ec_transaction_polled(ec))
|
|
|
+ if (!ec_transaction_polled(ec) &&
|
|
|
+ !acpi_ec_guard_event(ec))
|
|
|
break;
|
|
|
if (wait_event_timeout(ec->wait,
|
|
|
ec_transaction_completed(ec),
|
|
@@ -964,6 +1034,24 @@ static int acpi_ec_query(struct acpi_ec *ec, u8 *data)
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
+static void acpi_ec_check_event(struct acpi_ec *ec)
|
|
|
+{
|
|
|
+ unsigned long flags;
|
|
|
+
|
|
|
+ if (ec_event_clearing == ACPI_EC_EVT_TIMING_EVENT) {
|
|
|
+ if (ec_guard(ec)) {
|
|
|
+ spin_lock_irqsave(&ec->lock, flags);
|
|
|
+ /*
|
|
|
+ * Take care of the SCI_EVT unless no one else is
|
|
|
+ * taking care of it.
|
|
|
+ */
|
|
|
+ if (!ec->curr)
|
|
|
+ advance_transaction(ec);
|
|
|
+ spin_unlock_irqrestore(&ec->lock, flags);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
static void acpi_ec_event_handler(struct work_struct *work)
|
|
|
{
|
|
|
unsigned long flags;
|
|
@@ -981,6 +1069,8 @@ static void acpi_ec_event_handler(struct work_struct *work)
|
|
|
spin_unlock_irqrestore(&ec->lock, flags);
|
|
|
|
|
|
ec_dbg_evt("Event stopped");
|
|
|
+
|
|
|
+ acpi_ec_check_event(ec);
|
|
|
}
|
|
|
|
|
|
static u32 acpi_ec_gpe_handler(acpi_handle gpe_device,
|
|
@@ -1437,6 +1527,43 @@ error:
|
|
|
return -ENODEV;
|
|
|
}
|
|
|
|
|
|
+static int param_set_event_clearing(const char *val, struct kernel_param *kp)
|
|
|
+{
|
|
|
+ int result = 0;
|
|
|
+
|
|
|
+ if (!strncmp(val, "status", sizeof("status") - 1)) {
|
|
|
+ ec_event_clearing = ACPI_EC_EVT_TIMING_STATUS;
|
|
|
+ pr_info("Assuming SCI_EVT clearing on EC_SC accesses\n");
|
|
|
+ } else if (!strncmp(val, "query", sizeof("query") - 1)) {
|
|
|
+ ec_event_clearing = ACPI_EC_EVT_TIMING_QUERY;
|
|
|
+ pr_info("Assuming SCI_EVT clearing on QR_EC writes\n");
|
|
|
+ } else if (!strncmp(val, "event", sizeof("event") - 1)) {
|
|
|
+ ec_event_clearing = ACPI_EC_EVT_TIMING_EVENT;
|
|
|
+ pr_info("Assuming SCI_EVT clearing on event reads\n");
|
|
|
+ } else
|
|
|
+ result = -EINVAL;
|
|
|
+ return result;
|
|
|
+}
|
|
|
+
|
|
|
+static int param_get_event_clearing(char *buffer, struct kernel_param *kp)
|
|
|
+{
|
|
|
+ switch (ec_event_clearing) {
|
|
|
+ case ACPI_EC_EVT_TIMING_STATUS:
|
|
|
+ return sprintf(buffer, "status");
|
|
|
+ case ACPI_EC_EVT_TIMING_QUERY:
|
|
|
+ return sprintf(buffer, "query");
|
|
|
+ case ACPI_EC_EVT_TIMING_EVENT:
|
|
|
+ return sprintf(buffer, "event");
|
|
|
+ default:
|
|
|
+ return sprintf(buffer, "invalid");
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+module_param_call(ec_event_clearing, param_set_event_clearing, param_get_event_clearing,
|
|
|
+ NULL, 0644);
|
|
|
+MODULE_PARM_DESC(ec_event_clearing, "Assumed SCI_EVT clearing timing");
|
|
|
+
|
|
|
static struct acpi_driver acpi_ec_driver = {
|
|
|
.name = "ec",
|
|
|
.class = ACPI_EC_CLASS,
|