aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLv Zheng <lv.zheng@intel.com>2015-01-14 06:28:47 -0500
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2015-01-23 16:06:49 -0500
commit74443bbed72ab22ee005ecb6ecdc657a8018e1db (patch)
treef982a768793dc655eba51929a95ac4c11aaed338
parentf3e14329517ee190d34455d729430ef9d0473675 (diff)
ACPI / EC: Fix issues related to the SCI_EVT handling
This patch fixes 2 issues related to the draining behavior. But it doesn't implement the draining support, it only cleans up code so that further draining support is possible. The draining behavior is expected by some platforms (for example, Samsung) where SCI_EVT is set only once for a set of events and might be cleared for the very first QR_EC command issued after SCI_EVT is set. EC firmware on such platforms will return 0x00 to indicate "no outstanding event". Thus after seeing an SCI_EVT indication, EC driver need to fetch events until 0x00 returned (see acpi_ec_clear()). Issue 1 - acpi_ec_submit_query(): It's reported on Samsung laptops that SCI_EVT isn't checked when the transactions are advanced in ec_poll(), which leads to SCI_EVT triggering source lost: If no EC GPE IRQs are arrived after that, EC driver cannot detect this event and handle it. See comment 244/247 for kernel bugzilla 44161. This patch fixes this issue by moving SCI_EVT checks into advance_transaction(). So that SCI_EVT is checked each time we are going to handle the EC firmware indications. And this check will happen for both IRQ context and task context. Since after doing that, SCI_EVT is also checked after completing a transaction, ec_check_sci() and ec_check_sci_sync() can be removed. Issue 2 - acpi_ec_complete_query(): We expect to clear EC_FLAGS_QUERY_PENDING to allow queuing another draining QR_EC after writing a QR_EC command and before reading the event. After reading the event, SCI_EVT might be cleared by the firmware, thus it may not be possible to queue such a draining QR_EC at that time. But putting the EC_FLAGS_QUERY_PENDING clearing code after start_transaction() is wrong as there are chances that after start_transaction(), QR_EC can fail to be sent. If this happens, EC_FLAG_QUERY_PENDING will be cleared earlier. As a consequence, the draining QR_EC will also be queued earlier than expected. This patch also moves this code into advance_transaction() where QR_EC is just sent (ACPI_EC_COMMAND_POLL flagged) to fix this issue. Notes: 1. After introducing the 2 SCI_EVT related handlings into advance_transaction(), a next QR_EC can be queued right after writing the current QR_EC command and before reading the event. But this still hasn't implemented the draining behavior as the draining support requires: If a previous returned event value isn't 0x00, a draining QR_EC need to be issued even when SCI_EVT isn't set. 2. In this patch, acpi_os_execute() is also converted into a seperate work item to avoid invoking kmalloc() in the atomic context. We can do this because of the previous global lock fix. 3. Originally, EC_FLAGS_EVENT_PENDING is also used to avoid queuing up multiple work items (created by acpi_os_execute()), this can be covered by only using a single work item. But this patch still keeps this flag as there are different usages in the driver initialization steps relying on this flag. Link: https://bugzilla.kernel.org/show_bug.cgi?id=44161 Reported-by: Kieran Clancy <clancy.kieran@gmail.com> Signed-off-by: Lv Zheng <lv.zheng@intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-rw-r--r--drivers/acpi/ec.c59
-rw-r--r--drivers/acpi/internal.h1
2 files changed, 26 insertions, 34 deletions
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 3c97122eacd7..89e89b21dd54 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -120,6 +120,8 @@ struct transaction {
120 u8 flags; 120 u8 flags;
121}; 121};
122 122
123static int acpi_ec_sync_query(struct acpi_ec *ec, u8 *data);
124
123struct acpi_ec *boot_ec, *first_ec; 125struct acpi_ec *boot_ec, *first_ec;
124EXPORT_SYMBOL(first_ec); 126EXPORT_SYMBOL(first_ec);
125 127
@@ -189,6 +191,22 @@ static const char *acpi_ec_cmd_string(u8 cmd)
189#define acpi_ec_cmd_string(cmd) "UNDEF" 191#define acpi_ec_cmd_string(cmd) "UNDEF"
190#endif 192#endif
191 193
194static void acpi_ec_submit_query(struct acpi_ec *ec)
195{
196 if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) {
197 pr_debug("***** Event started *****\n");
198 schedule_work(&ec->work);
199 }
200}
201
202static void acpi_ec_complete_query(struct acpi_ec *ec)
203{
204 if (ec->curr->command == ACPI_EC_COMMAND_QUERY) {
205 clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags);
206 pr_debug("***** Event stopped *****\n");
207 }
208}
209
192static int ec_transaction_completed(struct acpi_ec *ec) 210static int ec_transaction_completed(struct acpi_ec *ec)
193{ 211{
194 unsigned long flags; 212 unsigned long flags;
@@ -242,6 +260,7 @@ static void advance_transaction(struct acpi_ec *ec)
242 !(status & ACPI_EC_FLAG_SCI) && 260 !(status & ACPI_EC_FLAG_SCI) &&
243 (t->command == ACPI_EC_COMMAND_QUERY)) { 261 (t->command == ACPI_EC_COMMAND_QUERY)) {
244 t->flags |= ACPI_EC_COMMAND_POLL; 262 t->flags |= ACPI_EC_COMMAND_POLL;
263 acpi_ec_complete_query(ec);
245 t->rdata[t->ri++] = 0x00; 264 t->rdata[t->ri++] = 0x00;
246 t->flags |= ACPI_EC_COMMAND_COMPLETE; 265 t->flags |= ACPI_EC_COMMAND_COMPLETE;
247 pr_debug("***** Command(%s) software completion *****\n", 266 pr_debug("***** Command(%s) software completion *****\n",
@@ -250,6 +269,7 @@ static void advance_transaction(struct acpi_ec *ec)
250 } else if ((status & ACPI_EC_FLAG_IBF) == 0) { 269 } else if ((status & ACPI_EC_FLAG_IBF) == 0) {
251 acpi_ec_write_cmd(ec, t->command); 270 acpi_ec_write_cmd(ec, t->command);
252 t->flags |= ACPI_EC_COMMAND_POLL; 271 t->flags |= ACPI_EC_COMMAND_POLL;
272 acpi_ec_complete_query(ec);
253 } else 273 } else
254 goto err; 274 goto err;
255 goto out; 275 goto out;
@@ -264,6 +284,8 @@ err:
264 ++t->irq_count; 284 ++t->irq_count;
265 } 285 }
266out: 286out:
287 if (status & ACPI_EC_FLAG_SCI)
288 acpi_ec_submit_query(ec);
267 if (wakeup && in_interrupt()) 289 if (wakeup && in_interrupt())
268 wake_up(&ec->wait); 290 wake_up(&ec->wait);
269} 291}
@@ -275,17 +297,6 @@ static void start_transaction(struct acpi_ec *ec)
275 advance_transaction(ec); 297 advance_transaction(ec);
276} 298}
277 299
278static int acpi_ec_sync_query(struct acpi_ec *ec, u8 *data);
279
280static int ec_check_sci_sync(struct acpi_ec *ec, u8 state)
281{
282 if (state & ACPI_EC_FLAG_SCI) {
283 if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags))
284 return acpi_ec_sync_query(ec, NULL);
285 }
286 return 0;
287}
288
289static int ec_poll(struct acpi_ec *ec) 300static int ec_poll(struct acpi_ec *ec)
290{ 301{
291 unsigned long flags; 302 unsigned long flags;
@@ -333,10 +344,6 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec,
333 pr_debug("***** Command(%s) started *****\n", 344 pr_debug("***** Command(%s) started *****\n",
334 acpi_ec_cmd_string(t->command)); 345 acpi_ec_cmd_string(t->command));
335 start_transaction(ec); 346 start_transaction(ec);
336 if (ec->curr->command == ACPI_EC_COMMAND_QUERY) {
337 clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags);
338 pr_debug("***** Event stopped *****\n");
339 }
340 spin_unlock_irqrestore(&ec->lock, tmp); 347 spin_unlock_irqrestore(&ec->lock, tmp);
341 ret = ec_poll(ec); 348 ret = ec_poll(ec);
342 spin_lock_irqsave(&ec->lock, tmp); 349 spin_lock_irqsave(&ec->lock, tmp);
@@ -376,8 +383,6 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t)
376 383
377 status = acpi_ec_transaction_unlocked(ec, t); 384 status = acpi_ec_transaction_unlocked(ec, t);
378 385
379 /* check if we received SCI during transaction */
380 ec_check_sci_sync(ec, acpi_ec_read_status(ec));
381 if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) { 386 if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) {
382 msleep(1); 387 msleep(1);
383 /* It is safe to enable the GPE outside of the transaction. */ 388 /* It is safe to enable the GPE outside of the transaction. */
@@ -687,14 +692,12 @@ static int acpi_ec_sync_query(struct acpi_ec *ec, u8 *data)
687 return result; 692 return result;
688} 693}
689 694
690static void acpi_ec_gpe_query(void *ec_cxt) 695static void acpi_ec_gpe_poller(struct work_struct *work)
691{ 696{
692 struct acpi_ec *ec = ec_cxt;
693 acpi_status status; 697 acpi_status status;
694 u32 glk; 698 u32 glk;
699 struct acpi_ec *ec = container_of(work, struct acpi_ec, work);
695 700
696 if (!ec)
697 return;
698 mutex_lock(&ec->mutex); 701 mutex_lock(&ec->mutex);
699 if (ec->global_lock) { 702 if (ec->global_lock) {
700 status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk); 703 status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
@@ -708,18 +711,6 @@ unlock:
708 mutex_unlock(&ec->mutex); 711 mutex_unlock(&ec->mutex);
709} 712}
710 713
711static int ec_check_sci(struct acpi_ec *ec, u8 state)
712{
713 if (state & ACPI_EC_FLAG_SCI) {
714 if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) {
715 pr_debug("***** Event started *****\n");
716 return acpi_os_execute(OSL_NOTIFY_HANDLER,
717 acpi_ec_gpe_query, ec);
718 }
719 }
720 return 0;
721}
722
723static u32 acpi_ec_gpe_handler(acpi_handle gpe_device, 714static u32 acpi_ec_gpe_handler(acpi_handle gpe_device,
724 u32 gpe_number, void *data) 715 u32 gpe_number, void *data)
725{ 716{
@@ -729,7 +720,6 @@ static u32 acpi_ec_gpe_handler(acpi_handle gpe_device,
729 spin_lock_irqsave(&ec->lock, flags); 720 spin_lock_irqsave(&ec->lock, flags);
730 advance_transaction(ec); 721 advance_transaction(ec);
731 spin_unlock_irqrestore(&ec->lock, flags); 722 spin_unlock_irqrestore(&ec->lock, flags);
732 ec_check_sci(ec, acpi_ec_read_status(ec));
733 return ACPI_INTERRUPT_HANDLED | ACPI_REENABLE_GPE; 723 return ACPI_INTERRUPT_HANDLED | ACPI_REENABLE_GPE;
734} 724}
735 725
@@ -793,6 +783,7 @@ static struct acpi_ec *make_acpi_ec(void)
793 init_waitqueue_head(&ec->wait); 783 init_waitqueue_head(&ec->wait);
794 INIT_LIST_HEAD(&ec->list); 784 INIT_LIST_HEAD(&ec->list);
795 spin_lock_init(&ec->lock); 785 spin_lock_init(&ec->lock);
786 INIT_WORK(&ec->work, acpi_ec_gpe_poller);
796 return ec; 787 return ec;
797} 788}
798 789
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index 163e82f536fa..dc420787ffcd 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -127,6 +127,7 @@ struct acpi_ec {
127 struct list_head list; 127 struct list_head list;
128 struct transaction *curr; 128 struct transaction *curr;
129 spinlock_t lock; 129 spinlock_t lock;
130 struct work_struct work;
130}; 131};
131 132
132extern struct acpi_ec *first_ec; 133extern struct acpi_ec *first_ec;