aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/ec.c
diff options
context:
space:
mode:
authorLv Zheng <lv.zheng@intel.com>2015-02-05 03:27:29 -0500
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2015-02-05 09:42:18 -0500
commit9e295ac14d6a59180beed0735e6a504c2ee87761 (patch)
tree90268475ce9937bd908dfabb0cffde87381abe5c /drivers/acpi/ec.c
parentca37bfdfbc8d0a3ec73e4b97bb26dcfa51d515aa (diff)
ACPI / EC: Reduce ec_poll() by referencing the last register access timestamp.
Timeout in the ec_poll() doesn't refer to the last register access time. It thus can win the competition against the acpi_ec_gpe_handler() if a transaction takes longer than 1ms but individual register accesses are less than 1ms. In some cases, it can make the following silicon bug easier to be triggered: GPE EN is not wired to the GPE trigger line, so when GPE STS is already set when 1 is written to GPE EN, no GPE can be triggered. This patch adds register access timestamp reference support for ec_poll() to reduce the number of ec_poll() invocations. Reported-by: Venkat Raghavulu <venkat.raghavulu@intel.com> Signed-off-by: Lv Zheng <lv.zheng@intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers/acpi/ec.c')
-rw-r--r--drivers/acpi/ec.c17
1 files changed, 14 insertions, 3 deletions
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 2540870e89f7..e000cf70378b 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -71,6 +71,7 @@ enum ec_command {
71#define ACPI_EC_DELAY 500 /* Wait 500ms max. during EC ops */ 71#define ACPI_EC_DELAY 500 /* Wait 500ms max. during EC ops */
72#define ACPI_EC_UDELAY_GLK 1000 /* Wait 1ms max. to get global lock */ 72#define ACPI_EC_UDELAY_GLK 1000 /* Wait 1ms max. to get global lock */
73#define ACPI_EC_MSI_UDELAY 550 /* Wait 550us for MSI EC */ 73#define ACPI_EC_MSI_UDELAY 550 /* Wait 550us for MSI EC */
74#define ACPI_EC_UDELAY_POLL 1000 /* Wait 1ms for EC transaction polling */
74#define ACPI_EC_CLEAR_MAX 100 /* Maximum number of events to query 75#define ACPI_EC_CLEAR_MAX 100 /* Maximum number of events to query
75 * when trying to clear the EC */ 76 * when trying to clear the EC */
76 77
@@ -118,6 +119,7 @@ struct transaction {
118 u8 wlen; 119 u8 wlen;
119 u8 rlen; 120 u8 rlen;
120 u8 flags; 121 u8 flags;
122 unsigned long timestamp;
121}; 123};
122 124
123static int acpi_ec_query(struct acpi_ec *ec, u8 *data); 125static int acpi_ec_query(struct acpi_ec *ec, u8 *data);
@@ -155,6 +157,7 @@ static inline u8 acpi_ec_read_data(struct acpi_ec *ec)
155{ 157{
156 u8 x = inb(ec->data_addr); 158 u8 x = inb(ec->data_addr);
157 159
160 ec->curr->timestamp = jiffies;
158 pr_debug("EC_DATA(R) = 0x%2.2x\n", x); 161 pr_debug("EC_DATA(R) = 0x%2.2x\n", x);
159 return x; 162 return x;
160} 163}
@@ -163,12 +166,14 @@ static inline void acpi_ec_write_cmd(struct acpi_ec *ec, u8 command)
163{ 166{
164 pr_debug("EC_SC(W) = 0x%2.2x\n", command); 167 pr_debug("EC_SC(W) = 0x%2.2x\n", command);
165 outb(command, ec->command_addr); 168 outb(command, ec->command_addr);
169 ec->curr->timestamp = jiffies;
166} 170}
167 171
168static inline void acpi_ec_write_data(struct acpi_ec *ec, u8 data) 172static inline void acpi_ec_write_data(struct acpi_ec *ec, u8 data)
169{ 173{
170 pr_debug("EC_DATA(W) = 0x%2.2x\n", data); 174 pr_debug("EC_DATA(W) = 0x%2.2x\n", data);
171 outb(data, ec->data_addr); 175 outb(data, ec->data_addr);
176 ec->curr->timestamp = jiffies;
172} 177}
173 178
174#ifdef DEBUG 179#ifdef DEBUG
@@ -359,6 +364,7 @@ static void start_transaction(struct acpi_ec *ec)
359{ 364{
360 ec->curr->irq_count = ec->curr->wi = ec->curr->ri = 0; 365 ec->curr->irq_count = ec->curr->wi = ec->curr->ri = 0;
361 ec->curr->flags = 0; 366 ec->curr->flags = 0;
367 ec->curr->timestamp = jiffies;
362 advance_transaction(ec); 368 advance_transaction(ec);
363} 369}
364 370
@@ -370,20 +376,25 @@ static int ec_poll(struct acpi_ec *ec)
370 while (repeat--) { 376 while (repeat--) {
371 unsigned long delay = jiffies + 377 unsigned long delay = jiffies +
372 msecs_to_jiffies(ec_delay); 378 msecs_to_jiffies(ec_delay);
379 unsigned long usecs = ACPI_EC_UDELAY_POLL;
373 do { 380 do {
374 /* don't sleep with disabled interrupts */ 381 /* don't sleep with disabled interrupts */
375 if (EC_FLAGS_MSI || irqs_disabled()) { 382 if (EC_FLAGS_MSI || irqs_disabled()) {
376 udelay(ACPI_EC_MSI_UDELAY); 383 usecs = ACPI_EC_MSI_UDELAY;
384 udelay(usecs);
377 if (ec_transaction_completed(ec)) 385 if (ec_transaction_completed(ec))
378 return 0; 386 return 0;
379 } else { 387 } else {
380 if (wait_event_timeout(ec->wait, 388 if (wait_event_timeout(ec->wait,
381 ec_transaction_completed(ec), 389 ec_transaction_completed(ec),
382 msecs_to_jiffies(1))) 390 usecs_to_jiffies(usecs)))
383 return 0; 391 return 0;
384 } 392 }
385 spin_lock_irqsave(&ec->lock, flags); 393 spin_lock_irqsave(&ec->lock, flags);
386 advance_transaction(ec); 394 if (time_after(jiffies,
395 ec->curr->timestamp +
396 usecs_to_jiffies(usecs)))
397 advance_transaction(ec);
387 spin_unlock_irqrestore(&ec->lock, flags); 398 spin_unlock_irqrestore(&ec->lock, flags);
388 } while (time_before(jiffies, delay)); 399 } while (time_before(jiffies, delay));
389 pr_debug("controller reset, restart transaction\n"); 400 pr_debug("controller reset, restart transaction\n");