2005-04-16 15:20:36 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								/*
							 | 
						
					
						
							
								
									
										
										
										
											2015-02-05 16:27:35 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								 *  ec.c - ACPI Embedded Controller Driver (v3)
							 | 
						
					
						
							
								
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 *
							 | 
						
					
						
							
								
									
										
										
										
											2015-02-05 16:27:35 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								 *  Copyright (C) 2001-2015 Intel Corporation
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 *    Author: 2014, 2015 Lv Zheng <lv.zheng@intel.com>
							 | 
						
					
						
							
								
									
										
										
										
											2014-06-15 08:42:19 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								 *            2006, 2007 Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 *            2006       Denis Sadykov <denis.m.sadykov@intel.com>
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 *            2004       Luming Yu <luming.yu@intel.com>
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 *            2001, 2002 Andy Grover <andrew.grover@intel.com>
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 *            2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 *  Copyright (C) 2008      Alexey Starikovskiy <astarikovskiy@suse.de>
							 | 
						
					
						
							
								
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 *
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 *
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 *  This program is free software; you can redistribute it and/or modify
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 *  it under the terms of the GNU General Public License as published by
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 *  the Free Software Foundation; either version 2 of the License, or (at
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 *  your option) any later version.
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 *
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 *  This program is distributed in the hope that it will be useful, but
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 *  WITHOUT ANY WARRANTY; without even the implied warranty of
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 *  General Public License for more details.
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 *
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 *  You should have received a copy of the GNU General Public License along
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 *  with this program; if not, write to the Free Software Foundation, Inc.,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 *
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-09-25 21:00:31 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/* Uncomment next line to get verbose printout */
							 | 
						
					
						
							
								
									
										
										
										
											2008-01-23 22:34:09 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/* #define DEBUG */
							 | 
						
					
						
							
								
									
										
										
										
											2013-09-12 03:32:04 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								#define pr_fmt(fmt) "ACPI : EC: " fmt
							 | 
						
					
						
							
								
									
										
										
										
											2008-01-23 22:34:09 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								#include <linux/kernel.h>
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								#include <linux/module.h>
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								#include <linux/init.h>
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								#include <linux/types.h>
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								#include <linux/delay.h>
							 | 
						
					
						
							
								
									
										
										
										
											2005-03-19 01:10:05 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								#include <linux/interrupt.h>
							 | 
						
					
						
							
								
									
										
										
										
											2007-05-29 16:43:02 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								#include <linux/list.h>
							 | 
						
					
						
							
								
									
										
										
										
											2008-09-25 21:00:31 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								#include <linux/spinlock.h>
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit slab.h inclusion from percpu.h
percpu.h is included by sched.h and module.h and thus ends up being
included when building most .c files.  percpu.h includes slab.h which
in turn includes gfp.h making everything defined by the two files
universally available and complicating inclusion dependencies.
percpu.h -> slab.h dependency is about to be removed.  Prepare for
this change by updating users of gfp and slab facilities include those
headers directly instead of assuming availability.  As this conversion
needs to touch large number of source files, the following script is
used as the basis of conversion.
  http://userweb.kernel.org/~tj/misc/slabh-sweep.py
The script does the followings.
* Scan files for gfp and slab usages and update includes such that
  only the necessary includes are there.  ie. if only gfp is used,
  gfp.h, if slab is used, slab.h.
* When the script inserts a new include, it looks at the include
  blocks and try to put the new include such that its order conforms
  to its surrounding.  It's put in the include block which contains
  core kernel includes, in the same order that the rest are ordered -
  alphabetical, Christmas tree, rev-Xmas-tree or at the end if there
  doesn't seem to be any matching order.
* If the script can't find a place to put a new include (mostly
  because the file doesn't have fitting include block), it prints out
  an error message indicating which .h file needs to be added to the
  file.
The conversion was done in the following steps.
1. The initial automatic conversion of all .c files updated slightly
   over 4000 files, deleting around 700 includes and adding ~480 gfp.h
   and ~3000 slab.h inclusions.  The script emitted errors for ~400
   files.
2. Each error was manually checked.  Some didn't need the inclusion,
   some needed manual addition while adding it to implementation .h or
   embedding .c file was more appropriate for others.  This step added
   inclusions to around 150 files.
3. The script was run again and the output was compared to the edits
   from #2 to make sure no file was left behind.
4. Several build tests were done and a couple of problems were fixed.
   e.g. lib/decompress_*.c used malloc/free() wrappers around slab
   APIs requiring slab.h to be added manually.
5. The script was run on all .h files but without automatically
   editing them as sprinkling gfp.h and slab.h inclusions around .h
   files could easily lead to inclusion dependency hell.  Most gfp.h
   inclusion directives were ignored as stuff from gfp.h was usually
   wildly available and often used in preprocessor macros.  Each
   slab.h inclusion directive was examined and added manually as
   necessary.
6. percpu.h was updated not to include slab.h.
7. Build test were done on the following configurations and failures
   were fixed.  CONFIG_GCOV_KERNEL was turned off for all tests (as my
   distributed build env didn't work with gcov compiles) and a few
   more options had to be turned off depending on archs to make things
   build (like ipr on powerpc/64 which failed due to missing writeq).
   * x86 and x86_64 UP and SMP allmodconfig and a custom test config.
   * powerpc and powerpc64 SMP allmodconfig
   * sparc and sparc64 SMP allmodconfig
   * ia64 SMP allmodconfig
   * s390 SMP allmodconfig
   * alpha SMP allmodconfig
   * um on x86_64 SMP allmodconfig
8. percpu.h modifications were reverted so that it could be applied as
   a separate patch and serve as bisection point.
Given the fact that I had only a couple of failures from tests on step
6, I'm fairly confident about the coverage of this conversion patch.
If there is a breakage, it's likely to be something in one of the arch
headers which should be easily discoverable easily on most builds of
the specific arch.
Signed-off-by: Tejun Heo <tj@kernel.org>
Guess-its-ok-by: Christoph Lameter <cl@linux-foundation.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Lee Schermerhorn <Lee.Schermerhorn@hp.com>
											
										 
										
											2010-03-24 17:04:11 +09:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								#include <linux/slab.h>
							 | 
						
					
						
							
								
									
										
										
										
											2013-12-03 08:49:16 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								#include <linux/acpi.h>
							 | 
						
					
						
							
								
									
										
										
										
											2009-07-06 23:40:19 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								#include <linux/dmi.h>
							 | 
						
					
						
							
								
									
										
										
										
											2013-12-03 08:49:16 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								#include <asm/io.h>
							 | 
						
					
						
							
								
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2010-07-16 13:11:31 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								#include "internal.h"
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								#define ACPI_EC_CLASS			"embedded_controller"
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								#define ACPI_EC_DEVICE_NAME		"Embedded Controller"
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								#define ACPI_EC_FILE_INFO		"info"
							 | 
						
					
						
							
								
									
										
										
										
											2007-05-29 16:43:02 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2006-09-26 19:50:33 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/* EC status register */
							 | 
						
					
						
							
								
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								#define ACPI_EC_FLAG_OBF	0x01	/* Output buffer full */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								#define ACPI_EC_FLAG_IBF	0x02	/* Input buffer full */
							 | 
						
					
						
							
								
									
										
										
										
											2014-06-15 08:42:42 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								#define ACPI_EC_FLAG_CMD	0x08	/* Input buffer contains a command */
							 | 
						
					
						
							
								
									
										
										
										
											2005-03-19 01:10:05 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								#define ACPI_EC_FLAG_BURST	0x10	/* burst mode */
							 | 
						
					
						
							
								
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								#define ACPI_EC_FLAG_SCI	0x20	/* EC-SCI occurred */
							 | 
						
					
						
							
								
									
										
										
										
											2007-05-29 16:42:57 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2006-09-26 19:50:33 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/* EC commands */
							 | 
						
					
						
							
								
									
										
										
										
											2006-12-07 18:42:17 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								enum ec_command {
							 | 
						
					
						
							
								
									
										
										
										
											2006-12-07 18:42:17 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									ACPI_EC_COMMAND_READ = 0x80,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									ACPI_EC_COMMAND_WRITE = 0x81,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									ACPI_EC_BURST_ENABLE = 0x82,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									ACPI_EC_BURST_DISABLE = 0x83,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									ACPI_EC_COMMAND_QUERY = 0x84,
							 | 
						
					
						
							
								
									
										
										
										
											2006-12-07 18:42:17 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								};
							 | 
						
					
						
							
								
									
										
										
										
											2007-05-29 16:43:02 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2006-12-07 18:42:16 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								#define ACPI_EC_DELAY		500	/* Wait 500ms max. during EC ops */
							 | 
						
					
						
							
								
									
										
										
										
											2006-09-26 19:50:33 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								#define ACPI_EC_UDELAY_GLK	1000	/* Wait 1ms max. to get global lock */
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-30 03:06:14 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								#define ACPI_EC_MSI_UDELAY	550	/* Wait 550us for MSI EC */
							 | 
						
					
						
							
								
									
										
										
										
											2015-02-05 16:27:29 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								#define ACPI_EC_UDELAY_POLL	1000	/* Wait 1ms for EC transaction polling */
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												ACPI / EC: Clear stale EC events on Samsung systems
A number of Samsung notebooks (530Uxx/535Uxx/540Uxx/550Pxx/900Xxx/etc)
continue to log events during sleep (lid open/close, AC plug/unplug,
battery level change), which accumulate in the EC until a buffer fills.
After the buffer is full (tests suggest it holds 8 events), GPEs stop
being triggered for new events. This state persists on wake or even on
power cycle, and prevents new events from being registered until the EC
is manually polled.
This is the root cause of a number of bugs, including AC not being
detected properly, lid close not triggering suspend, and low ambient
light not triggering the keyboard backlight. The bug also seemed to be
responsible for performance issues on at least one user's machine.
Juan Manuel Cabo found the cause of bug and the workaround of polling
the EC manually on wake.
The loop which clears the stale events is based on an earlier patch by
Lan Tianyu (see referenced attachment).
This patch:
 - Adds a function acpi_ec_clear() which polls the EC for stale _Q
   events at most ACPI_EC_CLEAR_MAX (currently 100) times. A warning is
   logged if this limit is reached.
 - Adds a flag EC_FLAGS_CLEAR_ON_RESUME which is set to 1 if the DMI
   system vendor is Samsung. This check could be replaced by several
   more specific DMI vendor/product pairs, but it's likely that the bug
   affects more Samsung products than just the five series mentioned
   above. Further, it should not be harmful to run acpi_ec_clear() on
   systems without the bug; it will return immediately after finding no
   data waiting.
 - Runs acpi_ec_clear() on initialisation (boot), from acpi_ec_add()
 - Runs acpi_ec_clear() on wake, from acpi_ec_unblock_transactions()
References: https://bugzilla.kernel.org/show_bug.cgi?id=44161
References: https://bugzilla.kernel.org/show_bug.cgi?id=45461
References: https://bugzilla.kernel.org/show_bug.cgi?id=57271
References: https://bugzilla.kernel.org/attachment.cgi?id=126801
Suggested-by: Juan Manuel Cabo <juanmanuel.cabo@gmail.com>
Signed-off-by: Kieran Clancy <clancy.kieran@gmail.com>
Reviewed-by: Lan Tianyu <tianyu.lan@intel.com>
Reviewed-by: Dennis Jansen <dennis.jansen@web.de>
Tested-by: Kieran Clancy <clancy.kieran@gmail.com>
Tested-by: Juan Manuel Cabo <juanmanuel.cabo@gmail.com>
Tested-by: Dennis Jansen <dennis.jansen@web.de>
Tested-by: Maurizio D'Addona <mauritiusdadd@gmail.com>
Tested-by: San Zamoyski <san@plusnet.pl>
Cc: All applicable <stable@vger.kernel.org>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
											
										 
										
											2014-03-01 00:42:28 +10:30
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								#define ACPI_EC_CLEAR_MAX	100	/* Maximum number of events to query
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
													 * when trying to clear the EC */
							 | 
						
					
						
							
								
									
										
										
										
											2006-09-26 19:50:33 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-22 14:18:30 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								enum {
							 | 
						
					
						
							
								
									
										
										
										
											2015-02-11 17:35:05 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									EC_FLAGS_QUERY_PENDING,		/* Query is pending */
							 | 
						
					
						
							
								
									
										
										
										
											2010-03-04 01:52:58 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									EC_FLAGS_HANDLERS_INSTALLED,	/* Handlers for GPE and
							 | 
						
					
						
							
								
									
										
										
										
											2008-09-25 21:00:31 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
													 * OpReg are installed */
							 | 
						
					
						
							
								
									
										
										
										
											2015-02-06 08:57:52 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									EC_FLAGS_STARTED,		/* Driver is started */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									EC_FLAGS_STOPPED,		/* Driver is stopped */
							 | 
						
					
						
							
								
									
										
										
										
											2015-02-06 08:58:05 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									EC_FLAGS_COMMAND_STORM,		/* GPE storms occurred to the
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
													 * current command processing */
							 | 
						
					
						
							
								
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								};
							 | 
						
					
						
							
								
									
										
										
										
											2006-09-26 19:50:33 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2014-06-15 08:41:35 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								#define ACPI_EC_COMMAND_POLL		0x01 /* Available for command byte */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								#define ACPI_EC_COMMAND_COMPLETE	0x02 /* Completed last byte */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2010-10-21 18:24:57 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/* ec.c is compiled in acpi namespace so this shows up as acpi.ec_delay param */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								static unsigned int ec_delay __read_mostly = ACPI_EC_DELAY;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								module_param(ec_delay, uint, 0644);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								MODULE_PARM_DESC(ec_delay, "Timeout(ms) waited until an EC command completes");
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2012-09-28 15:22:00 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/*
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * If the number of false interrupts per one transaction exceeds
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * this threshold, will think there is a GPE storm happened and
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * will disable the GPE for normal transaction.
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								static unsigned int ec_storm_threshold  __read_mostly = 8;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								module_param(ec_storm_threshold, uint, 0644);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								MODULE_PARM_DESC(ec_storm_threshold, "Maxim false GPE numbers not considered as GPE storm");
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2007-05-29 16:43:02 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								struct acpi_ec_query_handler {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									struct list_head node;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									acpi_ec_query_func func;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									acpi_handle handle;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									void *data;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									u8 query_bit;
							 | 
						
					
						
							
								
									
										
										
										
											2015-01-14 19:28:28 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									struct kref kref;
							 | 
						
					
						
							
								
									
										
										
										
											2007-05-29 16:43:02 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								};
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-09-26 00:54:28 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								struct transaction {
							 | 
						
					
						
							
								
									
										
										
										
											2008-09-25 21:00:31 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									const u8 *wdata;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									u8 *rdata;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									unsigned short irq_count;
							 | 
						
					
						
							
								
									
										
										
										
											2008-09-26 00:54:28 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									u8 command;
							 | 
						
					
						
							
								
									
										
										
										
											2008-11-12 01:40:19 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									u8 wi;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									u8 ri;
							 | 
						
					
						
							
								
									
										
										
										
											2008-09-25 21:00:31 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									u8 wlen;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									u8 rlen;
							 | 
						
					
						
							
								
									
										
										
										
											2014-06-15 08:41:35 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									u8 flags;
							 | 
						
					
						
							
								
									
										
										
										
											2015-02-05 16:27:29 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									unsigned long timestamp;
							 | 
						
					
						
							
								
									
										
										
										
											2008-09-25 21:00:31 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								};
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2015-01-14 19:28:53 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								static int acpi_ec_query(struct acpi_ec *ec, u8 *data);
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												ACPI / EC: Fix several GPE handling issues by deploying ACPI_GPE_DISPATCH_RAW_HANDLER mode.
This patch switches EC driver into ACPI_GPE_DISPATCH_RAW_HANDLER mode where
the GPE lock is not held for acpi_ec_gpe_handler() and the ACPICA internal
GPE enabling/disabling/clearing operations are bypassed so that further
improvements are possible with the GPE APIs.
There are 2 strong reasons for deploying raw GPE handler mode in the EC
driver:
1. Some hardware logics can control their interrupts via their own
   registers, so their interrupts can be disabled/enabled/acknowledged
   without using the super IRQ controller provided functions. While there
   is no mean (EC commands) for the EC driver to achieve this.
2. During suspending, the EC driver is still working for a while to
   complete the platform firmware provided functionailities using ec_poll()
   after all GPEs are disabled (see acpi_ec_block_transactions()), which
   means the EC driver will drive the EC GPE out of the GPE core's control.
Without deploying the raw GPE handler mode, we can see many races between
the EC driver and the GPE core due to the above restrictions:
1. There is a race condition due to ACPICA internal GPE
   disabling/clearing/enabling logics in acpi_ev_gpe_dispatch():
     Orignally EC GPE is disabled (EN=0), cleared (STS=0) before invoking a
     GPE handler and re-enabled (EN=1) after invoking a GPE handler in
     acpi_ev_gpe_dispatch(). When re-enabling appears, GPE may be flagged
     (STS=1).
       =================================================================
       (event pending A)
       =================================================================
       acpi_ev_gpe_dispatch()    ec_poll()
         EN=0
         STS=0
         acpi_ec_gpe_handler()
       *****************************************************************
       (event handling A)
           Lock(EC)
           advance_transaction()
             EC_SC read
       =================================================================
       (event pending B)
       =================================================================
             EC_SC handled
           Unlock(EC)
       *****************************************************************
       *****************************************************************
       (event handling B)
                                   Lock(EC)
                                   advance_transaction()
                                     EC_SC read
       =================================================================
       (event pending C)
       =================================================================
                                     EC_SC handled
                                   Unlock(EC)
       *****************************************************************
           EN=1
   This race condition is the root cause of different issues on different
   silicon variations.
   A. Silicon variation A:
      On some platforms, GPE will be triggered due to "writing 1 to EN when
      STS=1". This is because both EN and STS lines are wired to the GPE
      trigger line.
      1. Issue 1:
         We can see no-op acpi_ec_gpe_handler() invoked on such platforms.
         This is because:
         a. event pending B: An event can arrive after ACPICA's GPE
            clearing performed in acpi_ev_gpe_dispatch(), this event may
            fail to be detected by EC_SC read that is performed before its
            arrival;
         b. event handling B: The event can be handled in ec_poll() because
            EC lock is released after acpi_ec_gpe_handler() invocation;
         c. There is no code in ec_poll() to clear STS but the GPE can
            still be triggered by the EN=1 write performed in
            acpi_ev_finish_gpe(), this leads to a no-op EC GPE handler
            invocation;
         d. As no-op GPE handler invocations are counted by the EC driver
            to trigger the command storming conditions, the wrong no-op
            GPE handler invocations thus can easily trigger wrong command
            storming conditions.
         Note 1:
         If we removed GPE disabling/enabling code from
         acpi_ev_gpe_dispatch(), we could still see no-op GPE handlers
         triggered by the event arriving after the GPE clearing and before
         the GPE handling on both silicon variation A and B. This can only
         occur if the CPU is very slow (timing slice between STS=0 write
         and EC_SC read should be short enough before hardware sets another
         GPE indication). Thus this is very rare and is not what we need to
         fix.
   B. Silicon variation B:
      On other platforms, GPE may not be triggered due to "writing 1 to EN
      when STS=1". This is because only STS line is wired to the GPE
      trigger line.
      2. Issue 2:
         We can see GPE loss on such platforms. This is because:
         a. event pending B vs. event handling A: An event can arrive after
            ACPICA's GPE handling performed in acpi_ev_gpe_dispatch(), or
            event pending C vs. event handling B: An event can arrive after
            Linux's GPE handling performed in ec_poll(),
            these events may fail to be detected by EC_SC read that is
            performed before their arrival;
         b. The GPE cannot be triggered by EN=1 write performed in
            acpi_ev_finish_gpe();
         c. If no polling mechanism is implemented in the driver for the
            pending event (for example, SCI_EVT), this event is lost due to
            no GPE being triggered.
         Note 2:
         On most platforms, there might be another rule that GPE may not be
         triggered due to "writing 1 to STS when STS=1 and EN=1".
         Then on silicon variation B, an even worse case is if the issue 2
         event loss happens, further events may never trigger GPE again on
         such platforms due to being blocked by the current STS=1. Unless
         someone clears STS, all events have to be polled.
2. There is a race condition due to lacking in GPE status checking in EC
   driver:
     Originally, GPE status is checked in ACPICA core but not checked in
     the GPE handler. Thus since the status checking and handling is not
     locked, it can be interrupted by another handling path.
       =================================================================
       (event pending A)
       =================================================================
       acpi_ev_gpe_detect()        ec_poll()
         if (EN==1 && STS==1)
       *****************************************************************
       (event handling A)
                                     Lock(EC)
                                     advance_transaction()
                                       EC_SC read
                                       EC_SC handled
                                     Unlock(EC)
       *****************************************************************
         acpi_ev_gpe_dispatch()
           EN=0
           STS=0
           acpi_ec_gpe_handler()
       *****************************************************************
       (event handling B)
             Lock(EC)
             advance_transaction()
               EC_SC read
             Unlock(EC)
       *****************************************************************
      3. Issue 3:
         We can see no-op acpi_ec_gpe_handler() invoked on both silicon
         variation A and B. This is because:
         a. event pending A: An event can arrive to trigger an EC GPE and
            ACPICA checks it and is about to invoke the EC GPE handler;
         b. event handling A: The event can be handled in ec_poll() because
            EC lock is not held after the GPE status checking;
         c. event handling B: Then when the EC GPE handler is invoked, it
            becomes a no-op GPE handler invocation.
         d. As no-op GPE handler invocations are counted by the EC driver
            to trigger the command storming conditions, the wrong no-op
            GPE handler invocations thus can easily trigger wrong command
            storming conditions.
      Note 3:
      This no-op GPE handler invocation is rare because the time between
      the IRQ arrival and the acpi_ec_gpe_handler() invocation is less than
      the timeout value waited in ec_poll(). So most of the no-op GPE
      handler invocations are caused by the reason described in issue 1.
3. There is a race condition due to ACPICA internal GPE clearing logic in
   acpi_enable_gpe():
     During runtime, acpi_enable_gpe() can be invoked by the EC storming
     prevention code. When it is invoked, GPE may be flagged (STS=1).
       =================================================================
       (event pending A)
       =================================================================
       acpi_ev_gpe_dispatch()    acpi_ec_transaction()
         EN=0
         STS=0
         acpi_ec_gpe_handler()
       *****************************************************************
       (event handling A)
           Lock(EC)
           advance_transaction()
             EC_SC read
             EC_SC handled
           Unlock(EC)
       *****************************************************************
         EN=1 ?
                                   Lock(EC)
                                   Unlock(EC)
       =================================================================
       (event pending B)
       =================================================================
                                   acpi_enable_gpe()
                                     STS=0
                                     EN=1
    4. Issue 4:
       We can see GPE loss on both silicon variation A and B platforms.
       This is because:
       a. event pending B: An event can arrive right before ACPICA's GPE
          clearing performed in acpi_enable_gpe();
       b. If the GPE is cleared when GPE is disabled, then EN=1 write in
          acpi_enable_gpe() cannot trigger this GPE;
       c. If no polling mechanism is implemented in the driver for this
          event (for example, SCI_EVT), this event is lost due to no GPE
          being triggered.
       Note 4:
       Currently we don't have this issue, but after we switch the EC
       driver into ACPI_GPE_DISPATCH_RAW_HANDLER mode, we need to take care
       of handling this because the EN=1 write in acpi_ev_gpe_dispatch()
       will be abandoned.
There might be more race issues for the current GPE handler usages. This is
because the EC IRQ's enabling/disabling/checking/clearing/handling
operations should be locked by a single lock that is under the EC driver's
control to achieve the serialization. Which means we need to invoke GPE
APIs with EC driver's lock held and all ACPICA internal GPE operations
related to the GPE handler should be abandoned. Invoking GPE APIs inside of
the EC driver lock and bypassing ACPICA internal GPE operations requires
the ACPI_GPE_DISPATCH_RAW_HANDLER mode where the same lock used by the APIs
are released prior than invoking the handlers. Otherwise, we can see dead
locks due to circular locking dependencies (see Reference below).
This patch then switches the EC driver into the
ACPI_GPE_DISPATCH_RAW_HANDLER mode so that it can perform correct GPE
operations using the GPE APIs:
1. Bypasses EN modifications performed in acpi_ev_gpe_dispatch() by
   using acpi_install_gpe_raw_handler() and invoking all GPE APIs with EC
   spin lock held. This can fix issue 1 as it makes a non frequent GPE
   enabling/disabling environment.
2. Bypasses STS clearing performed in acpi_enable_gpe() by replacing
   acpi_enable_gpe()/acpi_disable_gpe() with acpi_set_gpe(). This can fix
   issue 4. And this can also help to fix issue 1 as it makes a no sudden
   GPE clearing environment when GPE is frequently enabled/disabled.
3. Ensures STS acknowledged before handling by invoking acpi_clear_gpe()
   in advance_transaction(). This can finally fix issue 1 even in a
   frequent GPE enabling/disabling environment. And this can also finally
   fix issue 3 when issue 2 is fixed.
   Note 3:
   GPE clearing is edge triggered W1C, which means we can clear it right
   before handling it. Since all EC GPE indications are handled in
   advance_transaction() by previous commits, we can now move GPE clearing
   into it to implement the correct GPE clearing.
   Note 4:
   We can use acpi_set_gpe() which is not shared GPE safer instead of
   acpi_enable_gpe()/acpi_disable_gpe() because EC GPE is not shared by
   other hardware, which is mentioned in the ACPI specification 5.0, 12.6
   Interrupt Model: "OSPM driver treats this as an edge event (the EC SCI
   cannot be shared)". So we can stop using shared GPE safer APIs
   acpi_enable_gpe()/acpi_disable_gpe() in the EC driver. Otherwise
   cleanups need to be made in acpi_ev_enable_gpe() to bypass the GPE
   clearing logic before keeping acpi_enable_gpe().
This patch also invokes advance_transaction() when GPE is re-enabled in the
task context which:
1. Ensures EN=1 can trigger GPE by checking and handling EC status register
   right after EN=1 writes. This can fix issue 2.
After applying this patch, without frequent GPE enablings considered:
       =================================================================
       (event pending A)
       =================================================================
       acpi_ec_gpe_handler()     ec_poll()
       *****************************************************************
       (event handling A)
         Lock(EC)
           advance_transaction()
             if STS==1
               STS=0
             EC_SC read
       =================================================================
       (event pending B)
       =================================================================
             EC_SC handled
         Unlock(EC)
       *****************************************************************
       *****************************************************************
       (event handling B)
                                   Lock(EC)
                                     advance_transaction()
                                       if STS==1
                                         STS=0
                                       EC_SC read
       =================================================================
       (event pending C)
       =================================================================
                                       EC_SC handled
                                   Unlock(EC)
       *****************************************************************
The event pending for issue 1 (event pending B) can arrive as a next GPE
due to the previous IRQ context STS=0 write. And if it is handled by
ec_poll() (event handling B), as it is also acknowledged by ec_poll(), the
event pending for issue 2 (event pending C) can properly arrive as a next
GPE after the task context STS=0 write. So no GPE will be lost and never
triggered due to GPE clearing performed in the wrong position. And since
all GPE handling is performed after a locked GPE status checking, we can
hardly see no-op GPE handler invocations due to issue 1 and 3. We may still
see no-op GPE handler invocations due to "Note 1", but as it is inevitable,
it needn't be fixed.
After applying this patch, with frequent GPE enablings considered:
       =================================================================
       (event pending A)
       =================================================================
       acpi_ec_gpe_handler()     acpi_ec_transaction()
       *****************************************************************
       (event handling A)
         Lock(EC)
           advance_transaction()
             if STS==1
               STS=0
             EC_SC read
       =================================================================
       (event pending B)
       =================================================================
             EC_SC handled
         Unlock(EC)
       *****************************************************************
       *****************************************************************
       (event handling B)
                                   Lock(EC)
                                     EN=1
                                     if STS==1
                                       advance_transaction()
                                         if STS==1
                                           STS=0
                                         EC_SC read
       =================================================================
       (event pending C)
       =================================================================
                                         EC_SC handled
                                   Unlock(EC)
       *****************************************************************
The event pending for issue 2 can be manually handled by
advance_transaction(). And after the STS=0 write performed in the manual
triggered advance_transaction(), GPE can always arrive. So no GPE will be
lost due to frequent GPE disabling/enabling performed in the driver like
issue 4.
Note 5:
It's ideally when EN=1 write occurred, an IRQ thread should be woken up to
handle the GPE when the GPE was raised. But this requires the IRQ thread to
contain the poller code for all EC GPE indications, while currently some of
the indications are handled in the user tasks. It then is very hard for the
code to determine whether a user task should be invoked or the poller work
item should be scheduled. So we have to invoke advance_transaction()
directly now and it leaves us such a restriction for the GPE re-enabling:
it must be performed in the task context to avoid starving the GPEs.
As a conclusion: we can see the EC GPE is always handled in serial after
deploying the raw GPE handler mode:
  Lock(EC)
  if (STS==1)
    STS=0
  EC_SC read
  EC_SC handled
  Unlock(EC)
The EC driver specific lock is responsible to make the EC GPE handling
processes serialized so that EC can handle its GPE from both IRQ and task
contexts and the next IRQ can be ensured to arrive after this process.
Note 6:
We have many EC_FLAGS_MSI qurik users in the current driver. They all seem
to be suffering from unexpected GPE triggering source lost. And they are
false root caused to a timing issue. Since EC communication protocol has
already flow control defined, timing shouldn't be the root cause, while
this fix might be fixing the root cause of the old bugs.
Link: https://lkml.org/lkml/2014/11/4/974
Link: https://lkml.org/lkml/2014/11/18/316
Link: https://www.spinics.net/lists/linux-acpi/msg54340.html
Signed-off-by: Lv Zheng <lv.zheng@intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
											
										 
										
											2015-02-05 16:27:22 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								static void advance_transaction(struct acpi_ec *ec);
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												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>
											
										 
										
											2015-01-14 19:28:47 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2010-07-16 13:11:31 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								struct acpi_ec *boot_ec, *first_ec;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								EXPORT_SYMBOL(first_ec);
							 | 
						
					
						
							
								
									
										
										
										
											2006-09-26 19:50:33 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-02-21 12:18:13 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								static int EC_FLAGS_MSI; /* Out-of-spec MSI controller */
							 | 
						
					
						
							
								
									
										
										
										
											2009-10-02 20:21:33 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								static int EC_FLAGS_VALIDATE_ECDT; /* ASUStec ECDTs need to be validated */
							 | 
						
					
						
							
								
									
										
										
										
											2009-10-02 20:21:40 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								static int EC_FLAGS_SKIP_DSDT_SCAN; /* Not all BIOS survive early DSDT scan */
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												ACPI / EC: Clear stale EC events on Samsung systems
A number of Samsung notebooks (530Uxx/535Uxx/540Uxx/550Pxx/900Xxx/etc)
continue to log events during sleep (lid open/close, AC plug/unplug,
battery level change), which accumulate in the EC until a buffer fills.
After the buffer is full (tests suggest it holds 8 events), GPEs stop
being triggered for new events. This state persists on wake or even on
power cycle, and prevents new events from being registered until the EC
is manually polled.
This is the root cause of a number of bugs, including AC not being
detected properly, lid close not triggering suspend, and low ambient
light not triggering the keyboard backlight. The bug also seemed to be
responsible for performance issues on at least one user's machine.
Juan Manuel Cabo found the cause of bug and the workaround of polling
the EC manually on wake.
The loop which clears the stale events is based on an earlier patch by
Lan Tianyu (see referenced attachment).
This patch:
 - Adds a function acpi_ec_clear() which polls the EC for stale _Q
   events at most ACPI_EC_CLEAR_MAX (currently 100) times. A warning is
   logged if this limit is reached.
 - Adds a flag EC_FLAGS_CLEAR_ON_RESUME which is set to 1 if the DMI
   system vendor is Samsung. This check could be replaced by several
   more specific DMI vendor/product pairs, but it's likely that the bug
   affects more Samsung products than just the five series mentioned
   above. Further, it should not be harmful to run acpi_ec_clear() on
   systems without the bug; it will return immediately after finding no
   data waiting.
 - Runs acpi_ec_clear() on initialisation (boot), from acpi_ec_add()
 - Runs acpi_ec_clear() on wake, from acpi_ec_unblock_transactions()
References: https://bugzilla.kernel.org/show_bug.cgi?id=44161
References: https://bugzilla.kernel.org/show_bug.cgi?id=45461
References: https://bugzilla.kernel.org/show_bug.cgi?id=57271
References: https://bugzilla.kernel.org/attachment.cgi?id=126801
Suggested-by: Juan Manuel Cabo <juanmanuel.cabo@gmail.com>
Signed-off-by: Kieran Clancy <clancy.kieran@gmail.com>
Reviewed-by: Lan Tianyu <tianyu.lan@intel.com>
Reviewed-by: Dennis Jansen <dennis.jansen@web.de>
Tested-by: Kieran Clancy <clancy.kieran@gmail.com>
Tested-by: Juan Manuel Cabo <juanmanuel.cabo@gmail.com>
Tested-by: Dennis Jansen <dennis.jansen@web.de>
Tested-by: Maurizio D'Addona <mauritiusdadd@gmail.com>
Tested-by: San Zamoyski <san@plusnet.pl>
Cc: All applicable <stable@vger.kernel.org>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
											
										 
										
											2014-03-01 00:42:28 +10:30
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								static int EC_FLAGS_CLEAR_ON_RESUME; /* Needs acpi_ec_clear() on boot/resume */
							 | 
						
					
						
							
								
									
										
										
										
											2014-10-29 11:33:49 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								static int EC_FLAGS_QUERY_HANDSHAKE; /* Needs QR_EC issued when SCI_EVT set */
							 | 
						
					
						
							
								
									
										
										
										
											2009-02-21 12:18:13 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2015-02-06 08:57:52 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/* --------------------------------------------------------------------------
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 *                           Device Flags
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * -------------------------------------------------------------------------- */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								static bool acpi_ec_started(struct acpi_ec *ec)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									return test_bit(EC_FLAGS_STARTED, &ec->flags) &&
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									       !test_bit(EC_FLAGS_STOPPED, &ec->flags);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2015-02-06 08:57:59 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								static bool acpi_ec_flushed(struct acpi_ec *ec)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									return ec->reference_count == 1;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								/* --------------------------------------------------------------------------
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												ACPI / EC: Fix several GPE handling issues by deploying ACPI_GPE_DISPATCH_RAW_HANDLER mode.
This patch switches EC driver into ACPI_GPE_DISPATCH_RAW_HANDLER mode where
the GPE lock is not held for acpi_ec_gpe_handler() and the ACPICA internal
GPE enabling/disabling/clearing operations are bypassed so that further
improvements are possible with the GPE APIs.
There are 2 strong reasons for deploying raw GPE handler mode in the EC
driver:
1. Some hardware logics can control their interrupts via their own
   registers, so their interrupts can be disabled/enabled/acknowledged
   without using the super IRQ controller provided functions. While there
   is no mean (EC commands) for the EC driver to achieve this.
2. During suspending, the EC driver is still working for a while to
   complete the platform firmware provided functionailities using ec_poll()
   after all GPEs are disabled (see acpi_ec_block_transactions()), which
   means the EC driver will drive the EC GPE out of the GPE core's control.
Without deploying the raw GPE handler mode, we can see many races between
the EC driver and the GPE core due to the above restrictions:
1. There is a race condition due to ACPICA internal GPE
   disabling/clearing/enabling logics in acpi_ev_gpe_dispatch():
     Orignally EC GPE is disabled (EN=0), cleared (STS=0) before invoking a
     GPE handler and re-enabled (EN=1) after invoking a GPE handler in
     acpi_ev_gpe_dispatch(). When re-enabling appears, GPE may be flagged
     (STS=1).
       =================================================================
       (event pending A)
       =================================================================
       acpi_ev_gpe_dispatch()    ec_poll()
         EN=0
         STS=0
         acpi_ec_gpe_handler()
       *****************************************************************
       (event handling A)
           Lock(EC)
           advance_transaction()
             EC_SC read
       =================================================================
       (event pending B)
       =================================================================
             EC_SC handled
           Unlock(EC)
       *****************************************************************
       *****************************************************************
       (event handling B)
                                   Lock(EC)
                                   advance_transaction()
                                     EC_SC read
       =================================================================
       (event pending C)
       =================================================================
                                     EC_SC handled
                                   Unlock(EC)
       *****************************************************************
           EN=1
   This race condition is the root cause of different issues on different
   silicon variations.
   A. Silicon variation A:
      On some platforms, GPE will be triggered due to "writing 1 to EN when
      STS=1". This is because both EN and STS lines are wired to the GPE
      trigger line.
      1. Issue 1:
         We can see no-op acpi_ec_gpe_handler() invoked on such platforms.
         This is because:
         a. event pending B: An event can arrive after ACPICA's GPE
            clearing performed in acpi_ev_gpe_dispatch(), this event may
            fail to be detected by EC_SC read that is performed before its
            arrival;
         b. event handling B: The event can be handled in ec_poll() because
            EC lock is released after acpi_ec_gpe_handler() invocation;
         c. There is no code in ec_poll() to clear STS but the GPE can
            still be triggered by the EN=1 write performed in
            acpi_ev_finish_gpe(), this leads to a no-op EC GPE handler
            invocation;
         d. As no-op GPE handler invocations are counted by the EC driver
            to trigger the command storming conditions, the wrong no-op
            GPE handler invocations thus can easily trigger wrong command
            storming conditions.
         Note 1:
         If we removed GPE disabling/enabling code from
         acpi_ev_gpe_dispatch(), we could still see no-op GPE handlers
         triggered by the event arriving after the GPE clearing and before
         the GPE handling on both silicon variation A and B. This can only
         occur if the CPU is very slow (timing slice between STS=0 write
         and EC_SC read should be short enough before hardware sets another
         GPE indication). Thus this is very rare and is not what we need to
         fix.
   B. Silicon variation B:
      On other platforms, GPE may not be triggered due to "writing 1 to EN
      when STS=1". This is because only STS line is wired to the GPE
      trigger line.
      2. Issue 2:
         We can see GPE loss on such platforms. This is because:
         a. event pending B vs. event handling A: An event can arrive after
            ACPICA's GPE handling performed in acpi_ev_gpe_dispatch(), or
            event pending C vs. event handling B: An event can arrive after
            Linux's GPE handling performed in ec_poll(),
            these events may fail to be detected by EC_SC read that is
            performed before their arrival;
         b. The GPE cannot be triggered by EN=1 write performed in
            acpi_ev_finish_gpe();
         c. If no polling mechanism is implemented in the driver for the
            pending event (for example, SCI_EVT), this event is lost due to
            no GPE being triggered.
         Note 2:
         On most platforms, there might be another rule that GPE may not be
         triggered due to "writing 1 to STS when STS=1 and EN=1".
         Then on silicon variation B, an even worse case is if the issue 2
         event loss happens, further events may never trigger GPE again on
         such platforms due to being blocked by the current STS=1. Unless
         someone clears STS, all events have to be polled.
2. There is a race condition due to lacking in GPE status checking in EC
   driver:
     Originally, GPE status is checked in ACPICA core but not checked in
     the GPE handler. Thus since the status checking and handling is not
     locked, it can be interrupted by another handling path.
       =================================================================
       (event pending A)
       =================================================================
       acpi_ev_gpe_detect()        ec_poll()
         if (EN==1 && STS==1)
       *****************************************************************
       (event handling A)
                                     Lock(EC)
                                     advance_transaction()
                                       EC_SC read
                                       EC_SC handled
                                     Unlock(EC)
       *****************************************************************
         acpi_ev_gpe_dispatch()
           EN=0
           STS=0
           acpi_ec_gpe_handler()
       *****************************************************************
       (event handling B)
             Lock(EC)
             advance_transaction()
               EC_SC read
             Unlock(EC)
       *****************************************************************
      3. Issue 3:
         We can see no-op acpi_ec_gpe_handler() invoked on both silicon
         variation A and B. This is because:
         a. event pending A: An event can arrive to trigger an EC GPE and
            ACPICA checks it and is about to invoke the EC GPE handler;
         b. event handling A: The event can be handled in ec_poll() because
            EC lock is not held after the GPE status checking;
         c. event handling B: Then when the EC GPE handler is invoked, it
            becomes a no-op GPE handler invocation.
         d. As no-op GPE handler invocations are counted by the EC driver
            to trigger the command storming conditions, the wrong no-op
            GPE handler invocations thus can easily trigger wrong command
            storming conditions.
      Note 3:
      This no-op GPE handler invocation is rare because the time between
      the IRQ arrival and the acpi_ec_gpe_handler() invocation is less than
      the timeout value waited in ec_poll(). So most of the no-op GPE
      handler invocations are caused by the reason described in issue 1.
3. There is a race condition due to ACPICA internal GPE clearing logic in
   acpi_enable_gpe():
     During runtime, acpi_enable_gpe() can be invoked by the EC storming
     prevention code. When it is invoked, GPE may be flagged (STS=1).
       =================================================================
       (event pending A)
       =================================================================
       acpi_ev_gpe_dispatch()    acpi_ec_transaction()
         EN=0
         STS=0
         acpi_ec_gpe_handler()
       *****************************************************************
       (event handling A)
           Lock(EC)
           advance_transaction()
             EC_SC read
             EC_SC handled
           Unlock(EC)
       *****************************************************************
         EN=1 ?
                                   Lock(EC)
                                   Unlock(EC)
       =================================================================
       (event pending B)
       =================================================================
                                   acpi_enable_gpe()
                                     STS=0
                                     EN=1
    4. Issue 4:
       We can see GPE loss on both silicon variation A and B platforms.
       This is because:
       a. event pending B: An event can arrive right before ACPICA's GPE
          clearing performed in acpi_enable_gpe();
       b. If the GPE is cleared when GPE is disabled, then EN=1 write in
          acpi_enable_gpe() cannot trigger this GPE;
       c. If no polling mechanism is implemented in the driver for this
          event (for example, SCI_EVT), this event is lost due to no GPE
          being triggered.
       Note 4:
       Currently we don't have this issue, but after we switch the EC
       driver into ACPI_GPE_DISPATCH_RAW_HANDLER mode, we need to take care
       of handling this because the EN=1 write in acpi_ev_gpe_dispatch()
       will be abandoned.
There might be more race issues for the current GPE handler usages. This is
because the EC IRQ's enabling/disabling/checking/clearing/handling
operations should be locked by a single lock that is under the EC driver's
control to achieve the serialization. Which means we need to invoke GPE
APIs with EC driver's lock held and all ACPICA internal GPE operations
related to the GPE handler should be abandoned. Invoking GPE APIs inside of
the EC driver lock and bypassing ACPICA internal GPE operations requires
the ACPI_GPE_DISPATCH_RAW_HANDLER mode where the same lock used by the APIs
are released prior than invoking the handlers. Otherwise, we can see dead
locks due to circular locking dependencies (see Reference below).
This patch then switches the EC driver into the
ACPI_GPE_DISPATCH_RAW_HANDLER mode so that it can perform correct GPE
operations using the GPE APIs:
1. Bypasses EN modifications performed in acpi_ev_gpe_dispatch() by
   using acpi_install_gpe_raw_handler() and invoking all GPE APIs with EC
   spin lock held. This can fix issue 1 as it makes a non frequent GPE
   enabling/disabling environment.
2. Bypasses STS clearing performed in acpi_enable_gpe() by replacing
   acpi_enable_gpe()/acpi_disable_gpe() with acpi_set_gpe(). This can fix
   issue 4. And this can also help to fix issue 1 as it makes a no sudden
   GPE clearing environment when GPE is frequently enabled/disabled.
3. Ensures STS acknowledged before handling by invoking acpi_clear_gpe()
   in advance_transaction(). This can finally fix issue 1 even in a
   frequent GPE enabling/disabling environment. And this can also finally
   fix issue 3 when issue 2 is fixed.
   Note 3:
   GPE clearing is edge triggered W1C, which means we can clear it right
   before handling it. Since all EC GPE indications are handled in
   advance_transaction() by previous commits, we can now move GPE clearing
   into it to implement the correct GPE clearing.
   Note 4:
   We can use acpi_set_gpe() which is not shared GPE safer instead of
   acpi_enable_gpe()/acpi_disable_gpe() because EC GPE is not shared by
   other hardware, which is mentioned in the ACPI specification 5.0, 12.6
   Interrupt Model: "OSPM driver treats this as an edge event (the EC SCI
   cannot be shared)". So we can stop using shared GPE safer APIs
   acpi_enable_gpe()/acpi_disable_gpe() in the EC driver. Otherwise
   cleanups need to be made in acpi_ev_enable_gpe() to bypass the GPE
   clearing logic before keeping acpi_enable_gpe().
This patch also invokes advance_transaction() when GPE is re-enabled in the
task context which:
1. Ensures EN=1 can trigger GPE by checking and handling EC status register
   right after EN=1 writes. This can fix issue 2.
After applying this patch, without frequent GPE enablings considered:
       =================================================================
       (event pending A)
       =================================================================
       acpi_ec_gpe_handler()     ec_poll()
       *****************************************************************
       (event handling A)
         Lock(EC)
           advance_transaction()
             if STS==1
               STS=0
             EC_SC read
       =================================================================
       (event pending B)
       =================================================================
             EC_SC handled
         Unlock(EC)
       *****************************************************************
       *****************************************************************
       (event handling B)
                                   Lock(EC)
                                     advance_transaction()
                                       if STS==1
                                         STS=0
                                       EC_SC read
       =================================================================
       (event pending C)
       =================================================================
                                       EC_SC handled
                                   Unlock(EC)
       *****************************************************************
The event pending for issue 1 (event pending B) can arrive as a next GPE
due to the previous IRQ context STS=0 write. And if it is handled by
ec_poll() (event handling B), as it is also acknowledged by ec_poll(), the
event pending for issue 2 (event pending C) can properly arrive as a next
GPE after the task context STS=0 write. So no GPE will be lost and never
triggered due to GPE clearing performed in the wrong position. And since
all GPE handling is performed after a locked GPE status checking, we can
hardly see no-op GPE handler invocations due to issue 1 and 3. We may still
see no-op GPE handler invocations due to "Note 1", but as it is inevitable,
it needn't be fixed.
After applying this patch, with frequent GPE enablings considered:
       =================================================================
       (event pending A)
       =================================================================
       acpi_ec_gpe_handler()     acpi_ec_transaction()
       *****************************************************************
       (event handling A)
         Lock(EC)
           advance_transaction()
             if STS==1
               STS=0
             EC_SC read
       =================================================================
       (event pending B)
       =================================================================
             EC_SC handled
         Unlock(EC)
       *****************************************************************
       *****************************************************************
       (event handling B)
                                   Lock(EC)
                                     EN=1
                                     if STS==1
                                       advance_transaction()
                                         if STS==1
                                           STS=0
                                         EC_SC read
       =================================================================
       (event pending C)
       =================================================================
                                         EC_SC handled
                                   Unlock(EC)
       *****************************************************************
The event pending for issue 2 can be manually handled by
advance_transaction(). And after the STS=0 write performed in the manual
triggered advance_transaction(), GPE can always arrive. So no GPE will be
lost due to frequent GPE disabling/enabling performed in the driver like
issue 4.
Note 5:
It's ideally when EN=1 write occurred, an IRQ thread should be woken up to
handle the GPE when the GPE was raised. But this requires the IRQ thread to
contain the poller code for all EC GPE indications, while currently some of
the indications are handled in the user tasks. It then is very hard for the
code to determine whether a user task should be invoked or the poller work
item should be scheduled. So we have to invoke advance_transaction()
directly now and it leaves us such a restriction for the GPE re-enabling:
it must be performed in the task context to avoid starving the GPEs.
As a conclusion: we can see the EC GPE is always handled in serial after
deploying the raw GPE handler mode:
  Lock(EC)
  if (STS==1)
    STS=0
  EC_SC read
  EC_SC handled
  Unlock(EC)
The EC driver specific lock is responsible to make the EC GPE handling
processes serialized so that EC can handle its GPE from both IRQ and task
contexts and the next IRQ can be ensured to arrive after this process.
Note 6:
We have many EC_FLAGS_MSI qurik users in the current driver. They all seem
to be suffering from unexpected GPE triggering source lost. And they are
false root caused to a timing issue. Since EC communication protocol has
already flow control defined, timing shouldn't be the root cause, while
this fix might be fixing the root cause of the old bugs.
Link: https://lkml.org/lkml/2014/11/4/974
Link: https://lkml.org/lkml/2014/11/18/316
Link: https://www.spinics.net/lists/linux-acpi/msg54340.html
Signed-off-by: Lv Zheng <lv.zheng@intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
											
										 
										
											2015-02-05 16:27:22 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								 *                           EC Registers
							 | 
						
					
						
							
								
									
										
										
										
											2014-10-14 14:24:01 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								 * -------------------------------------------------------------------------- */
							 | 
						
					
						
							
								
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2006-09-26 19:50:33 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								static inline u8 acpi_ec_read_status(struct acpi_ec *ec)
							 | 
						
					
						
							
								
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							
								
									
										
										
										
											2007-11-21 03:23:26 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									u8 x = inb(ec->command_addr);
							 | 
						
					
						
							
								
									
										
										
										
											2014-10-14 14:24:01 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2014-06-15 08:42:42 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									pr_debug("EC_SC(R) = 0x%2.2x "
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										 "SCI_EVT=%d BURST=%d CMD=%d IBF=%d OBF=%d\n",
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										 x,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										 !!(x & ACPI_EC_FLAG_SCI),
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										 !!(x & ACPI_EC_FLAG_BURST),
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										 !!(x & ACPI_EC_FLAG_CMD),
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										 !!(x & ACPI_EC_FLAG_IBF),
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										 !!(x & ACPI_EC_FLAG_OBF));
							 | 
						
					
						
							
								
									
										
										
										
											2007-11-21 03:23:26 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									return x;
							 | 
						
					
						
							
								
									
										
										
										
											2005-03-19 01:10:05 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2006-09-26 19:50:33 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								static inline u8 acpi_ec_read_data(struct acpi_ec *ec)
							 | 
						
					
						
							
								
									
										
										
										
											2006-09-26 19:50:33 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							
								
									
										
										
										
											2007-11-21 03:23:26 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									u8 x = inb(ec->data_addr);
							 | 
						
					
						
							
								
									
										
										
										
											2014-10-14 14:24:01 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2015-02-05 16:27:29 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									ec->curr->timestamp = jiffies;
							 | 
						
					
						
							
								
									
										
										
										
											2014-06-15 08:42:42 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									pr_debug("EC_DATA(R) = 0x%2.2x\n", x);
							 | 
						
					
						
							
								
									
										
										
										
											2008-09-25 21:00:31 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									return x;
							 | 
						
					
						
							
								
									
										
										
										
											2006-09-26 19:50:33 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2006-09-26 19:50:33 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								static inline void acpi_ec_write_cmd(struct acpi_ec *ec, u8 command)
							 | 
						
					
						
							
								
									
										
										
										
											2005-07-23 04:08:00 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							
								
									
										
										
										
											2014-06-15 08:42:42 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									pr_debug("EC_SC(W) = 0x%2.2x\n", command);
							 | 
						
					
						
							
								
									
										
										
										
											2006-09-26 19:50:33 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									outb(command, ec->command_addr);
							 | 
						
					
						
							
								
									
										
										
										
											2015-02-05 16:27:29 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									ec->curr->timestamp = jiffies;
							 | 
						
					
						
							
								
									
										
										
										
											2005-07-23 04:08:00 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2006-09-26 19:50:33 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								static inline void acpi_ec_write_data(struct acpi_ec *ec, u8 data)
							 | 
						
					
						
							
								
									
										
										
										
											2005-07-23 04:08:00 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							
								
									
										
										
										
											2014-06-15 08:42:42 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									pr_debug("EC_DATA(W) = 0x%2.2x\n", data);
							 | 
						
					
						
							
								
									
										
										
										
											2006-09-26 19:50:33 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									outb(data, ec->data_addr);
							 | 
						
					
						
							
								
									
										
										
										
											2015-02-05 16:27:29 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									ec->curr->timestamp = jiffies;
							 | 
						
					
						
							
								
									
										
										
										
											2006-09-26 19:50:33 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							
								
									
										
										
										
											2005-07-23 04:08:00 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2014-10-14 14:23:49 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								#ifdef DEBUG
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								static const char *acpi_ec_cmd_string(u8 cmd)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									switch (cmd) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									case 0x80:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										return "RD_EC";
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									case 0x81:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										return "WR_EC";
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									case 0x82:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										return "BE_EC";
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									case 0x83:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										return "BD_EC";
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									case 0x84:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										return "QR_EC";
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									return "UNKNOWN";
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								#else
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								#define acpi_ec_cmd_string(cmd)		"UNDEF"
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								#endif
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												ACPI / EC: Fix several GPE handling issues by deploying ACPI_GPE_DISPATCH_RAW_HANDLER mode.
This patch switches EC driver into ACPI_GPE_DISPATCH_RAW_HANDLER mode where
the GPE lock is not held for acpi_ec_gpe_handler() and the ACPICA internal
GPE enabling/disabling/clearing operations are bypassed so that further
improvements are possible with the GPE APIs.
There are 2 strong reasons for deploying raw GPE handler mode in the EC
driver:
1. Some hardware logics can control their interrupts via their own
   registers, so their interrupts can be disabled/enabled/acknowledged
   without using the super IRQ controller provided functions. While there
   is no mean (EC commands) for the EC driver to achieve this.
2. During suspending, the EC driver is still working for a while to
   complete the platform firmware provided functionailities using ec_poll()
   after all GPEs are disabled (see acpi_ec_block_transactions()), which
   means the EC driver will drive the EC GPE out of the GPE core's control.
Without deploying the raw GPE handler mode, we can see many races between
the EC driver and the GPE core due to the above restrictions:
1. There is a race condition due to ACPICA internal GPE
   disabling/clearing/enabling logics in acpi_ev_gpe_dispatch():
     Orignally EC GPE is disabled (EN=0), cleared (STS=0) before invoking a
     GPE handler and re-enabled (EN=1) after invoking a GPE handler in
     acpi_ev_gpe_dispatch(). When re-enabling appears, GPE may be flagged
     (STS=1).
       =================================================================
       (event pending A)
       =================================================================
       acpi_ev_gpe_dispatch()    ec_poll()
         EN=0
         STS=0
         acpi_ec_gpe_handler()
       *****************************************************************
       (event handling A)
           Lock(EC)
           advance_transaction()
             EC_SC read
       =================================================================
       (event pending B)
       =================================================================
             EC_SC handled
           Unlock(EC)
       *****************************************************************
       *****************************************************************
       (event handling B)
                                   Lock(EC)
                                   advance_transaction()
                                     EC_SC read
       =================================================================
       (event pending C)
       =================================================================
                                     EC_SC handled
                                   Unlock(EC)
       *****************************************************************
           EN=1
   This race condition is the root cause of different issues on different
   silicon variations.
   A. Silicon variation A:
      On some platforms, GPE will be triggered due to "writing 1 to EN when
      STS=1". This is because both EN and STS lines are wired to the GPE
      trigger line.
      1. Issue 1:
         We can see no-op acpi_ec_gpe_handler() invoked on such platforms.
         This is because:
         a. event pending B: An event can arrive after ACPICA's GPE
            clearing performed in acpi_ev_gpe_dispatch(), this event may
            fail to be detected by EC_SC read that is performed before its
            arrival;
         b. event handling B: The event can be handled in ec_poll() because
            EC lock is released after acpi_ec_gpe_handler() invocation;
         c. There is no code in ec_poll() to clear STS but the GPE can
            still be triggered by the EN=1 write performed in
            acpi_ev_finish_gpe(), this leads to a no-op EC GPE handler
            invocation;
         d. As no-op GPE handler invocations are counted by the EC driver
            to trigger the command storming conditions, the wrong no-op
            GPE handler invocations thus can easily trigger wrong command
            storming conditions.
         Note 1:
         If we removed GPE disabling/enabling code from
         acpi_ev_gpe_dispatch(), we could still see no-op GPE handlers
         triggered by the event arriving after the GPE clearing and before
         the GPE handling on both silicon variation A and B. This can only
         occur if the CPU is very slow (timing slice between STS=0 write
         and EC_SC read should be short enough before hardware sets another
         GPE indication). Thus this is very rare and is not what we need to
         fix.
   B. Silicon variation B:
      On other platforms, GPE may not be triggered due to "writing 1 to EN
      when STS=1". This is because only STS line is wired to the GPE
      trigger line.
      2. Issue 2:
         We can see GPE loss on such platforms. This is because:
         a. event pending B vs. event handling A: An event can arrive after
            ACPICA's GPE handling performed in acpi_ev_gpe_dispatch(), or
            event pending C vs. event handling B: An event can arrive after
            Linux's GPE handling performed in ec_poll(),
            these events may fail to be detected by EC_SC read that is
            performed before their arrival;
         b. The GPE cannot be triggered by EN=1 write performed in
            acpi_ev_finish_gpe();
         c. If no polling mechanism is implemented in the driver for the
            pending event (for example, SCI_EVT), this event is lost due to
            no GPE being triggered.
         Note 2:
         On most platforms, there might be another rule that GPE may not be
         triggered due to "writing 1 to STS when STS=1 and EN=1".
         Then on silicon variation B, an even worse case is if the issue 2
         event loss happens, further events may never trigger GPE again on
         such platforms due to being blocked by the current STS=1. Unless
         someone clears STS, all events have to be polled.
2. There is a race condition due to lacking in GPE status checking in EC
   driver:
     Originally, GPE status is checked in ACPICA core but not checked in
     the GPE handler. Thus since the status checking and handling is not
     locked, it can be interrupted by another handling path.
       =================================================================
       (event pending A)
       =================================================================
       acpi_ev_gpe_detect()        ec_poll()
         if (EN==1 && STS==1)
       *****************************************************************
       (event handling A)
                                     Lock(EC)
                                     advance_transaction()
                                       EC_SC read
                                       EC_SC handled
                                     Unlock(EC)
       *****************************************************************
         acpi_ev_gpe_dispatch()
           EN=0
           STS=0
           acpi_ec_gpe_handler()
       *****************************************************************
       (event handling B)
             Lock(EC)
             advance_transaction()
               EC_SC read
             Unlock(EC)
       *****************************************************************
      3. Issue 3:
         We can see no-op acpi_ec_gpe_handler() invoked on both silicon
         variation A and B. This is because:
         a. event pending A: An event can arrive to trigger an EC GPE and
            ACPICA checks it and is about to invoke the EC GPE handler;
         b. event handling A: The event can be handled in ec_poll() because
            EC lock is not held after the GPE status checking;
         c. event handling B: Then when the EC GPE handler is invoked, it
            becomes a no-op GPE handler invocation.
         d. As no-op GPE handler invocations are counted by the EC driver
            to trigger the command storming conditions, the wrong no-op
            GPE handler invocations thus can easily trigger wrong command
            storming conditions.
      Note 3:
      This no-op GPE handler invocation is rare because the time between
      the IRQ arrival and the acpi_ec_gpe_handler() invocation is less than
      the timeout value waited in ec_poll(). So most of the no-op GPE
      handler invocations are caused by the reason described in issue 1.
3. There is a race condition due to ACPICA internal GPE clearing logic in
   acpi_enable_gpe():
     During runtime, acpi_enable_gpe() can be invoked by the EC storming
     prevention code. When it is invoked, GPE may be flagged (STS=1).
       =================================================================
       (event pending A)
       =================================================================
       acpi_ev_gpe_dispatch()    acpi_ec_transaction()
         EN=0
         STS=0
         acpi_ec_gpe_handler()
       *****************************************************************
       (event handling A)
           Lock(EC)
           advance_transaction()
             EC_SC read
             EC_SC handled
           Unlock(EC)
       *****************************************************************
         EN=1 ?
                                   Lock(EC)
                                   Unlock(EC)
       =================================================================
       (event pending B)
       =================================================================
                                   acpi_enable_gpe()
                                     STS=0
                                     EN=1
    4. Issue 4:
       We can see GPE loss on both silicon variation A and B platforms.
       This is because:
       a. event pending B: An event can arrive right before ACPICA's GPE
          clearing performed in acpi_enable_gpe();
       b. If the GPE is cleared when GPE is disabled, then EN=1 write in
          acpi_enable_gpe() cannot trigger this GPE;
       c. If no polling mechanism is implemented in the driver for this
          event (for example, SCI_EVT), this event is lost due to no GPE
          being triggered.
       Note 4:
       Currently we don't have this issue, but after we switch the EC
       driver into ACPI_GPE_DISPATCH_RAW_HANDLER mode, we need to take care
       of handling this because the EN=1 write in acpi_ev_gpe_dispatch()
       will be abandoned.
There might be more race issues for the current GPE handler usages. This is
because the EC IRQ's enabling/disabling/checking/clearing/handling
operations should be locked by a single lock that is under the EC driver's
control to achieve the serialization. Which means we need to invoke GPE
APIs with EC driver's lock held and all ACPICA internal GPE operations
related to the GPE handler should be abandoned. Invoking GPE APIs inside of
the EC driver lock and bypassing ACPICA internal GPE operations requires
the ACPI_GPE_DISPATCH_RAW_HANDLER mode where the same lock used by the APIs
are released prior than invoking the handlers. Otherwise, we can see dead
locks due to circular locking dependencies (see Reference below).
This patch then switches the EC driver into the
ACPI_GPE_DISPATCH_RAW_HANDLER mode so that it can perform correct GPE
operations using the GPE APIs:
1. Bypasses EN modifications performed in acpi_ev_gpe_dispatch() by
   using acpi_install_gpe_raw_handler() and invoking all GPE APIs with EC
   spin lock held. This can fix issue 1 as it makes a non frequent GPE
   enabling/disabling environment.
2. Bypasses STS clearing performed in acpi_enable_gpe() by replacing
   acpi_enable_gpe()/acpi_disable_gpe() with acpi_set_gpe(). This can fix
   issue 4. And this can also help to fix issue 1 as it makes a no sudden
   GPE clearing environment when GPE is frequently enabled/disabled.
3. Ensures STS acknowledged before handling by invoking acpi_clear_gpe()
   in advance_transaction(). This can finally fix issue 1 even in a
   frequent GPE enabling/disabling environment. And this can also finally
   fix issue 3 when issue 2 is fixed.
   Note 3:
   GPE clearing is edge triggered W1C, which means we can clear it right
   before handling it. Since all EC GPE indications are handled in
   advance_transaction() by previous commits, we can now move GPE clearing
   into it to implement the correct GPE clearing.
   Note 4:
   We can use acpi_set_gpe() which is not shared GPE safer instead of
   acpi_enable_gpe()/acpi_disable_gpe() because EC GPE is not shared by
   other hardware, which is mentioned in the ACPI specification 5.0, 12.6
   Interrupt Model: "OSPM driver treats this as an edge event (the EC SCI
   cannot be shared)". So we can stop using shared GPE safer APIs
   acpi_enable_gpe()/acpi_disable_gpe() in the EC driver. Otherwise
   cleanups need to be made in acpi_ev_enable_gpe() to bypass the GPE
   clearing logic before keeping acpi_enable_gpe().
This patch also invokes advance_transaction() when GPE is re-enabled in the
task context which:
1. Ensures EN=1 can trigger GPE by checking and handling EC status register
   right after EN=1 writes. This can fix issue 2.
After applying this patch, without frequent GPE enablings considered:
       =================================================================
       (event pending A)
       =================================================================
       acpi_ec_gpe_handler()     ec_poll()
       *****************************************************************
       (event handling A)
         Lock(EC)
           advance_transaction()
             if STS==1
               STS=0
             EC_SC read
       =================================================================
       (event pending B)
       =================================================================
             EC_SC handled
         Unlock(EC)
       *****************************************************************
       *****************************************************************
       (event handling B)
                                   Lock(EC)
                                     advance_transaction()
                                       if STS==1
                                         STS=0
                                       EC_SC read
       =================================================================
       (event pending C)
       =================================================================
                                       EC_SC handled
                                   Unlock(EC)
       *****************************************************************
The event pending for issue 1 (event pending B) can arrive as a next GPE
due to the previous IRQ context STS=0 write. And if it is handled by
ec_poll() (event handling B), as it is also acknowledged by ec_poll(), the
event pending for issue 2 (event pending C) can properly arrive as a next
GPE after the task context STS=0 write. So no GPE will be lost and never
triggered due to GPE clearing performed in the wrong position. And since
all GPE handling is performed after a locked GPE status checking, we can
hardly see no-op GPE handler invocations due to issue 1 and 3. We may still
see no-op GPE handler invocations due to "Note 1", but as it is inevitable,
it needn't be fixed.
After applying this patch, with frequent GPE enablings considered:
       =================================================================
       (event pending A)
       =================================================================
       acpi_ec_gpe_handler()     acpi_ec_transaction()
       *****************************************************************
       (event handling A)
         Lock(EC)
           advance_transaction()
             if STS==1
               STS=0
             EC_SC read
       =================================================================
       (event pending B)
       =================================================================
             EC_SC handled
         Unlock(EC)
       *****************************************************************
       *****************************************************************
       (event handling B)
                                   Lock(EC)
                                     EN=1
                                     if STS==1
                                       advance_transaction()
                                         if STS==1
                                           STS=0
                                         EC_SC read
       =================================================================
       (event pending C)
       =================================================================
                                         EC_SC handled
                                   Unlock(EC)
       *****************************************************************
The event pending for issue 2 can be manually handled by
advance_transaction(). And after the STS=0 write performed in the manual
triggered advance_transaction(), GPE can always arrive. So no GPE will be
lost due to frequent GPE disabling/enabling performed in the driver like
issue 4.
Note 5:
It's ideally when EN=1 write occurred, an IRQ thread should be woken up to
handle the GPE when the GPE was raised. But this requires the IRQ thread to
contain the poller code for all EC GPE indications, while currently some of
the indications are handled in the user tasks. It then is very hard for the
code to determine whether a user task should be invoked or the poller work
item should be scheduled. So we have to invoke advance_transaction()
directly now and it leaves us such a restriction for the GPE re-enabling:
it must be performed in the task context to avoid starving the GPEs.
As a conclusion: we can see the EC GPE is always handled in serial after
deploying the raw GPE handler mode:
  Lock(EC)
  if (STS==1)
    STS=0
  EC_SC read
  EC_SC handled
  Unlock(EC)
The EC driver specific lock is responsible to make the EC GPE handling
processes serialized so that EC can handle its GPE from both IRQ and task
contexts and the next IRQ can be ensured to arrive after this process.
Note 6:
We have many EC_FLAGS_MSI qurik users in the current driver. They all seem
to be suffering from unexpected GPE triggering source lost. And they are
false root caused to a timing issue. Since EC communication protocol has
already flow control defined, timing shouldn't be the root cause, while
this fix might be fixing the root cause of the old bugs.
Link: https://lkml.org/lkml/2014/11/4/974
Link: https://lkml.org/lkml/2014/11/18/316
Link: https://www.spinics.net/lists/linux-acpi/msg54340.html
Signed-off-by: Lv Zheng <lv.zheng@intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
											
										 
										
											2015-02-05 16:27:22 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/* --------------------------------------------------------------------------
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 *                           GPE Registers
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * -------------------------------------------------------------------------- */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								static inline bool acpi_ec_is_gpe_raised(struct acpi_ec *ec)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									acpi_event_status gpe_status = 0;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									(void)acpi_get_gpe_status(NULL, ec->gpe, &gpe_status);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									return (gpe_status & ACPI_EVENT_FLAG_SET) ? true : false;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								static inline void acpi_ec_enable_gpe(struct acpi_ec *ec, bool open)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									if (open)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										acpi_enable_gpe(NULL, ec->gpe);
							 | 
						
					
						
							
								
									
										
										
										
											2015-02-06 08:58:05 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									else {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										BUG_ON(ec->reference_count < 1);
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												ACPI / EC: Fix several GPE handling issues by deploying ACPI_GPE_DISPATCH_RAW_HANDLER mode.
This patch switches EC driver into ACPI_GPE_DISPATCH_RAW_HANDLER mode where
the GPE lock is not held for acpi_ec_gpe_handler() and the ACPICA internal
GPE enabling/disabling/clearing operations are bypassed so that further
improvements are possible with the GPE APIs.
There are 2 strong reasons for deploying raw GPE handler mode in the EC
driver:
1. Some hardware logics can control their interrupts via their own
   registers, so their interrupts can be disabled/enabled/acknowledged
   without using the super IRQ controller provided functions. While there
   is no mean (EC commands) for the EC driver to achieve this.
2. During suspending, the EC driver is still working for a while to
   complete the platform firmware provided functionailities using ec_poll()
   after all GPEs are disabled (see acpi_ec_block_transactions()), which
   means the EC driver will drive the EC GPE out of the GPE core's control.
Without deploying the raw GPE handler mode, we can see many races between
the EC driver and the GPE core due to the above restrictions:
1. There is a race condition due to ACPICA internal GPE
   disabling/clearing/enabling logics in acpi_ev_gpe_dispatch():
     Orignally EC GPE is disabled (EN=0), cleared (STS=0) before invoking a
     GPE handler and re-enabled (EN=1) after invoking a GPE handler in
     acpi_ev_gpe_dispatch(). When re-enabling appears, GPE may be flagged
     (STS=1).
       =================================================================
       (event pending A)
       =================================================================
       acpi_ev_gpe_dispatch()    ec_poll()
         EN=0
         STS=0
         acpi_ec_gpe_handler()
       *****************************************************************
       (event handling A)
           Lock(EC)
           advance_transaction()
             EC_SC read
       =================================================================
       (event pending B)
       =================================================================
             EC_SC handled
           Unlock(EC)
       *****************************************************************
       *****************************************************************
       (event handling B)
                                   Lock(EC)
                                   advance_transaction()
                                     EC_SC read
       =================================================================
       (event pending C)
       =================================================================
                                     EC_SC handled
                                   Unlock(EC)
       *****************************************************************
           EN=1
   This race condition is the root cause of different issues on different
   silicon variations.
   A. Silicon variation A:
      On some platforms, GPE will be triggered due to "writing 1 to EN when
      STS=1". This is because both EN and STS lines are wired to the GPE
      trigger line.
      1. Issue 1:
         We can see no-op acpi_ec_gpe_handler() invoked on such platforms.
         This is because:
         a. event pending B: An event can arrive after ACPICA's GPE
            clearing performed in acpi_ev_gpe_dispatch(), this event may
            fail to be detected by EC_SC read that is performed before its
            arrival;
         b. event handling B: The event can be handled in ec_poll() because
            EC lock is released after acpi_ec_gpe_handler() invocation;
         c. There is no code in ec_poll() to clear STS but the GPE can
            still be triggered by the EN=1 write performed in
            acpi_ev_finish_gpe(), this leads to a no-op EC GPE handler
            invocation;
         d. As no-op GPE handler invocations are counted by the EC driver
            to trigger the command storming conditions, the wrong no-op
            GPE handler invocations thus can easily trigger wrong command
            storming conditions.
         Note 1:
         If we removed GPE disabling/enabling code from
         acpi_ev_gpe_dispatch(), we could still see no-op GPE handlers
         triggered by the event arriving after the GPE clearing and before
         the GPE handling on both silicon variation A and B. This can only
         occur if the CPU is very slow (timing slice between STS=0 write
         and EC_SC read should be short enough before hardware sets another
         GPE indication). Thus this is very rare and is not what we need to
         fix.
   B. Silicon variation B:
      On other platforms, GPE may not be triggered due to "writing 1 to EN
      when STS=1". This is because only STS line is wired to the GPE
      trigger line.
      2. Issue 2:
         We can see GPE loss on such platforms. This is because:
         a. event pending B vs. event handling A: An event can arrive after
            ACPICA's GPE handling performed in acpi_ev_gpe_dispatch(), or
            event pending C vs. event handling B: An event can arrive after
            Linux's GPE handling performed in ec_poll(),
            these events may fail to be detected by EC_SC read that is
            performed before their arrival;
         b. The GPE cannot be triggered by EN=1 write performed in
            acpi_ev_finish_gpe();
         c. If no polling mechanism is implemented in the driver for the
            pending event (for example, SCI_EVT), this event is lost due to
            no GPE being triggered.
         Note 2:
         On most platforms, there might be another rule that GPE may not be
         triggered due to "writing 1 to STS when STS=1 and EN=1".
         Then on silicon variation B, an even worse case is if the issue 2
         event loss happens, further events may never trigger GPE again on
         such platforms due to being blocked by the current STS=1. Unless
         someone clears STS, all events have to be polled.
2. There is a race condition due to lacking in GPE status checking in EC
   driver:
     Originally, GPE status is checked in ACPICA core but not checked in
     the GPE handler. Thus since the status checking and handling is not
     locked, it can be interrupted by another handling path.
       =================================================================
       (event pending A)
       =================================================================
       acpi_ev_gpe_detect()        ec_poll()
         if (EN==1 && STS==1)
       *****************************************************************
       (event handling A)
                                     Lock(EC)
                                     advance_transaction()
                                       EC_SC read
                                       EC_SC handled
                                     Unlock(EC)
       *****************************************************************
         acpi_ev_gpe_dispatch()
           EN=0
           STS=0
           acpi_ec_gpe_handler()
       *****************************************************************
       (event handling B)
             Lock(EC)
             advance_transaction()
               EC_SC read
             Unlock(EC)
       *****************************************************************
      3. Issue 3:
         We can see no-op acpi_ec_gpe_handler() invoked on both silicon
         variation A and B. This is because:
         a. event pending A: An event can arrive to trigger an EC GPE and
            ACPICA checks it and is about to invoke the EC GPE handler;
         b. event handling A: The event can be handled in ec_poll() because
            EC lock is not held after the GPE status checking;
         c. event handling B: Then when the EC GPE handler is invoked, it
            becomes a no-op GPE handler invocation.
         d. As no-op GPE handler invocations are counted by the EC driver
            to trigger the command storming conditions, the wrong no-op
            GPE handler invocations thus can easily trigger wrong command
            storming conditions.
      Note 3:
      This no-op GPE handler invocation is rare because the time between
      the IRQ arrival and the acpi_ec_gpe_handler() invocation is less than
      the timeout value waited in ec_poll(). So most of the no-op GPE
      handler invocations are caused by the reason described in issue 1.
3. There is a race condition due to ACPICA internal GPE clearing logic in
   acpi_enable_gpe():
     During runtime, acpi_enable_gpe() can be invoked by the EC storming
     prevention code. When it is invoked, GPE may be flagged (STS=1).
       =================================================================
       (event pending A)
       =================================================================
       acpi_ev_gpe_dispatch()    acpi_ec_transaction()
         EN=0
         STS=0
         acpi_ec_gpe_handler()
       *****************************************************************
       (event handling A)
           Lock(EC)
           advance_transaction()
             EC_SC read
             EC_SC handled
           Unlock(EC)
       *****************************************************************
         EN=1 ?
                                   Lock(EC)
                                   Unlock(EC)
       =================================================================
       (event pending B)
       =================================================================
                                   acpi_enable_gpe()
                                     STS=0
                                     EN=1
    4. Issue 4:
       We can see GPE loss on both silicon variation A and B platforms.
       This is because:
       a. event pending B: An event can arrive right before ACPICA's GPE
          clearing performed in acpi_enable_gpe();
       b. If the GPE is cleared when GPE is disabled, then EN=1 write in
          acpi_enable_gpe() cannot trigger this GPE;
       c. If no polling mechanism is implemented in the driver for this
          event (for example, SCI_EVT), this event is lost due to no GPE
          being triggered.
       Note 4:
       Currently we don't have this issue, but after we switch the EC
       driver into ACPI_GPE_DISPATCH_RAW_HANDLER mode, we need to take care
       of handling this because the EN=1 write in acpi_ev_gpe_dispatch()
       will be abandoned.
There might be more race issues for the current GPE handler usages. This is
because the EC IRQ's enabling/disabling/checking/clearing/handling
operations should be locked by a single lock that is under the EC driver's
control to achieve the serialization. Which means we need to invoke GPE
APIs with EC driver's lock held and all ACPICA internal GPE operations
related to the GPE handler should be abandoned. Invoking GPE APIs inside of
the EC driver lock and bypassing ACPICA internal GPE operations requires
the ACPI_GPE_DISPATCH_RAW_HANDLER mode where the same lock used by the APIs
are released prior than invoking the handlers. Otherwise, we can see dead
locks due to circular locking dependencies (see Reference below).
This patch then switches the EC driver into the
ACPI_GPE_DISPATCH_RAW_HANDLER mode so that it can perform correct GPE
operations using the GPE APIs:
1. Bypasses EN modifications performed in acpi_ev_gpe_dispatch() by
   using acpi_install_gpe_raw_handler() and invoking all GPE APIs with EC
   spin lock held. This can fix issue 1 as it makes a non frequent GPE
   enabling/disabling environment.
2. Bypasses STS clearing performed in acpi_enable_gpe() by replacing
   acpi_enable_gpe()/acpi_disable_gpe() with acpi_set_gpe(). This can fix
   issue 4. And this can also help to fix issue 1 as it makes a no sudden
   GPE clearing environment when GPE is frequently enabled/disabled.
3. Ensures STS acknowledged before handling by invoking acpi_clear_gpe()
   in advance_transaction(). This can finally fix issue 1 even in a
   frequent GPE enabling/disabling environment. And this can also finally
   fix issue 3 when issue 2 is fixed.
   Note 3:
   GPE clearing is edge triggered W1C, which means we can clear it right
   before handling it. Since all EC GPE indications are handled in
   advance_transaction() by previous commits, we can now move GPE clearing
   into it to implement the correct GPE clearing.
   Note 4:
   We can use acpi_set_gpe() which is not shared GPE safer instead of
   acpi_enable_gpe()/acpi_disable_gpe() because EC GPE is not shared by
   other hardware, which is mentioned in the ACPI specification 5.0, 12.6
   Interrupt Model: "OSPM driver treats this as an edge event (the EC SCI
   cannot be shared)". So we can stop using shared GPE safer APIs
   acpi_enable_gpe()/acpi_disable_gpe() in the EC driver. Otherwise
   cleanups need to be made in acpi_ev_enable_gpe() to bypass the GPE
   clearing logic before keeping acpi_enable_gpe().
This patch also invokes advance_transaction() when GPE is re-enabled in the
task context which:
1. Ensures EN=1 can trigger GPE by checking and handling EC status register
   right after EN=1 writes. This can fix issue 2.
After applying this patch, without frequent GPE enablings considered:
       =================================================================
       (event pending A)
       =================================================================
       acpi_ec_gpe_handler()     ec_poll()
       *****************************************************************
       (event handling A)
         Lock(EC)
           advance_transaction()
             if STS==1
               STS=0
             EC_SC read
       =================================================================
       (event pending B)
       =================================================================
             EC_SC handled
         Unlock(EC)
       *****************************************************************
       *****************************************************************
       (event handling B)
                                   Lock(EC)
                                     advance_transaction()
                                       if STS==1
                                         STS=0
                                       EC_SC read
       =================================================================
       (event pending C)
       =================================================================
                                       EC_SC handled
                                   Unlock(EC)
       *****************************************************************
The event pending for issue 1 (event pending B) can arrive as a next GPE
due to the previous IRQ context STS=0 write. And if it is handled by
ec_poll() (event handling B), as it is also acknowledged by ec_poll(), the
event pending for issue 2 (event pending C) can properly arrive as a next
GPE after the task context STS=0 write. So no GPE will be lost and never
triggered due to GPE clearing performed in the wrong position. And since
all GPE handling is performed after a locked GPE status checking, we can
hardly see no-op GPE handler invocations due to issue 1 and 3. We may still
see no-op GPE handler invocations due to "Note 1", but as it is inevitable,
it needn't be fixed.
After applying this patch, with frequent GPE enablings considered:
       =================================================================
       (event pending A)
       =================================================================
       acpi_ec_gpe_handler()     acpi_ec_transaction()
       *****************************************************************
       (event handling A)
         Lock(EC)
           advance_transaction()
             if STS==1
               STS=0
             EC_SC read
       =================================================================
       (event pending B)
       =================================================================
             EC_SC handled
         Unlock(EC)
       *****************************************************************
       *****************************************************************
       (event handling B)
                                   Lock(EC)
                                     EN=1
                                     if STS==1
                                       advance_transaction()
                                         if STS==1
                                           STS=0
                                         EC_SC read
       =================================================================
       (event pending C)
       =================================================================
                                         EC_SC handled
                                   Unlock(EC)
       *****************************************************************
The event pending for issue 2 can be manually handled by
advance_transaction(). And after the STS=0 write performed in the manual
triggered advance_transaction(), GPE can always arrive. So no GPE will be
lost due to frequent GPE disabling/enabling performed in the driver like
issue 4.
Note 5:
It's ideally when EN=1 write occurred, an IRQ thread should be woken up to
handle the GPE when the GPE was raised. But this requires the IRQ thread to
contain the poller code for all EC GPE indications, while currently some of
the indications are handled in the user tasks. It then is very hard for the
code to determine whether a user task should be invoked or the poller work
item should be scheduled. So we have to invoke advance_transaction()
directly now and it leaves us such a restriction for the GPE re-enabling:
it must be performed in the task context to avoid starving the GPEs.
As a conclusion: we can see the EC GPE is always handled in serial after
deploying the raw GPE handler mode:
  Lock(EC)
  if (STS==1)
    STS=0
  EC_SC read
  EC_SC handled
  Unlock(EC)
The EC driver specific lock is responsible to make the EC GPE handling
processes serialized so that EC can handle its GPE from both IRQ and task
contexts and the next IRQ can be ensured to arrive after this process.
Note 6:
We have many EC_FLAGS_MSI qurik users in the current driver. They all seem
to be suffering from unexpected GPE triggering source lost. And they are
false root caused to a timing issue. Since EC communication protocol has
already flow control defined, timing shouldn't be the root cause, while
this fix might be fixing the root cause of the old bugs.
Link: https://lkml.org/lkml/2014/11/4/974
Link: https://lkml.org/lkml/2014/11/18/316
Link: https://www.spinics.net/lists/linux-acpi/msg54340.html
Signed-off-by: Lv Zheng <lv.zheng@intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
											
										 
										
											2015-02-05 16:27:22 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_ENABLE);
							 | 
						
					
						
							
								
									
										
										
										
											2015-02-06 08:58:05 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									}
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												ACPI / EC: Fix several GPE handling issues by deploying ACPI_GPE_DISPATCH_RAW_HANDLER mode.
This patch switches EC driver into ACPI_GPE_DISPATCH_RAW_HANDLER mode where
the GPE lock is not held for acpi_ec_gpe_handler() and the ACPICA internal
GPE enabling/disabling/clearing operations are bypassed so that further
improvements are possible with the GPE APIs.
There are 2 strong reasons for deploying raw GPE handler mode in the EC
driver:
1. Some hardware logics can control their interrupts via their own
   registers, so their interrupts can be disabled/enabled/acknowledged
   without using the super IRQ controller provided functions. While there
   is no mean (EC commands) for the EC driver to achieve this.
2. During suspending, the EC driver is still working for a while to
   complete the platform firmware provided functionailities using ec_poll()
   after all GPEs are disabled (see acpi_ec_block_transactions()), which
   means the EC driver will drive the EC GPE out of the GPE core's control.
Without deploying the raw GPE handler mode, we can see many races between
the EC driver and the GPE core due to the above restrictions:
1. There is a race condition due to ACPICA internal GPE
   disabling/clearing/enabling logics in acpi_ev_gpe_dispatch():
     Orignally EC GPE is disabled (EN=0), cleared (STS=0) before invoking a
     GPE handler and re-enabled (EN=1) after invoking a GPE handler in
     acpi_ev_gpe_dispatch(). When re-enabling appears, GPE may be flagged
     (STS=1).
       =================================================================
       (event pending A)
       =================================================================
       acpi_ev_gpe_dispatch()    ec_poll()
         EN=0
         STS=0
         acpi_ec_gpe_handler()
       *****************************************************************
       (event handling A)
           Lock(EC)
           advance_transaction()
             EC_SC read
       =================================================================
       (event pending B)
       =================================================================
             EC_SC handled
           Unlock(EC)
       *****************************************************************
       *****************************************************************
       (event handling B)
                                   Lock(EC)
                                   advance_transaction()
                                     EC_SC read
       =================================================================
       (event pending C)
       =================================================================
                                     EC_SC handled
                                   Unlock(EC)
       *****************************************************************
           EN=1
   This race condition is the root cause of different issues on different
   silicon variations.
   A. Silicon variation A:
      On some platforms, GPE will be triggered due to "writing 1 to EN when
      STS=1". This is because both EN and STS lines are wired to the GPE
      trigger line.
      1. Issue 1:
         We can see no-op acpi_ec_gpe_handler() invoked on such platforms.
         This is because:
         a. event pending B: An event can arrive after ACPICA's GPE
            clearing performed in acpi_ev_gpe_dispatch(), this event may
            fail to be detected by EC_SC read that is performed before its
            arrival;
         b. event handling B: The event can be handled in ec_poll() because
            EC lock is released after acpi_ec_gpe_handler() invocation;
         c. There is no code in ec_poll() to clear STS but the GPE can
            still be triggered by the EN=1 write performed in
            acpi_ev_finish_gpe(), this leads to a no-op EC GPE handler
            invocation;
         d. As no-op GPE handler invocations are counted by the EC driver
            to trigger the command storming conditions, the wrong no-op
            GPE handler invocations thus can easily trigger wrong command
            storming conditions.
         Note 1:
         If we removed GPE disabling/enabling code from
         acpi_ev_gpe_dispatch(), we could still see no-op GPE handlers
         triggered by the event arriving after the GPE clearing and before
         the GPE handling on both silicon variation A and B. This can only
         occur if the CPU is very slow (timing slice between STS=0 write
         and EC_SC read should be short enough before hardware sets another
         GPE indication). Thus this is very rare and is not what we need to
         fix.
   B. Silicon variation B:
      On other platforms, GPE may not be triggered due to "writing 1 to EN
      when STS=1". This is because only STS line is wired to the GPE
      trigger line.
      2. Issue 2:
         We can see GPE loss on such platforms. This is because:
         a. event pending B vs. event handling A: An event can arrive after
            ACPICA's GPE handling performed in acpi_ev_gpe_dispatch(), or
            event pending C vs. event handling B: An event can arrive after
            Linux's GPE handling performed in ec_poll(),
            these events may fail to be detected by EC_SC read that is
            performed before their arrival;
         b. The GPE cannot be triggered by EN=1 write performed in
            acpi_ev_finish_gpe();
         c. If no polling mechanism is implemented in the driver for the
            pending event (for example, SCI_EVT), this event is lost due to
            no GPE being triggered.
         Note 2:
         On most platforms, there might be another rule that GPE may not be
         triggered due to "writing 1 to STS when STS=1 and EN=1".
         Then on silicon variation B, an even worse case is if the issue 2
         event loss happens, further events may never trigger GPE again on
         such platforms due to being blocked by the current STS=1. Unless
         someone clears STS, all events have to be polled.
2. There is a race condition due to lacking in GPE status checking in EC
   driver:
     Originally, GPE status is checked in ACPICA core but not checked in
     the GPE handler. Thus since the status checking and handling is not
     locked, it can be interrupted by another handling path.
       =================================================================
       (event pending A)
       =================================================================
       acpi_ev_gpe_detect()        ec_poll()
         if (EN==1 && STS==1)
       *****************************************************************
       (event handling A)
                                     Lock(EC)
                                     advance_transaction()
                                       EC_SC read
                                       EC_SC handled
                                     Unlock(EC)
       *****************************************************************
         acpi_ev_gpe_dispatch()
           EN=0
           STS=0
           acpi_ec_gpe_handler()
       *****************************************************************
       (event handling B)
             Lock(EC)
             advance_transaction()
               EC_SC read
             Unlock(EC)
       *****************************************************************
      3. Issue 3:
         We can see no-op acpi_ec_gpe_handler() invoked on both silicon
         variation A and B. This is because:
         a. event pending A: An event can arrive to trigger an EC GPE and
            ACPICA checks it and is about to invoke the EC GPE handler;
         b. event handling A: The event can be handled in ec_poll() because
            EC lock is not held after the GPE status checking;
         c. event handling B: Then when the EC GPE handler is invoked, it
            becomes a no-op GPE handler invocation.
         d. As no-op GPE handler invocations are counted by the EC driver
            to trigger the command storming conditions, the wrong no-op
            GPE handler invocations thus can easily trigger wrong command
            storming conditions.
      Note 3:
      This no-op GPE handler invocation is rare because the time between
      the IRQ arrival and the acpi_ec_gpe_handler() invocation is less than
      the timeout value waited in ec_poll(). So most of the no-op GPE
      handler invocations are caused by the reason described in issue 1.
3. There is a race condition due to ACPICA internal GPE clearing logic in
   acpi_enable_gpe():
     During runtime, acpi_enable_gpe() can be invoked by the EC storming
     prevention code. When it is invoked, GPE may be flagged (STS=1).
       =================================================================
       (event pending A)
       =================================================================
       acpi_ev_gpe_dispatch()    acpi_ec_transaction()
         EN=0
         STS=0
         acpi_ec_gpe_handler()
       *****************************************************************
       (event handling A)
           Lock(EC)
           advance_transaction()
             EC_SC read
             EC_SC handled
           Unlock(EC)
       *****************************************************************
         EN=1 ?
                                   Lock(EC)
                                   Unlock(EC)
       =================================================================
       (event pending B)
       =================================================================
                                   acpi_enable_gpe()
                                     STS=0
                                     EN=1
    4. Issue 4:
       We can see GPE loss on both silicon variation A and B platforms.
       This is because:
       a. event pending B: An event can arrive right before ACPICA's GPE
          clearing performed in acpi_enable_gpe();
       b. If the GPE is cleared when GPE is disabled, then EN=1 write in
          acpi_enable_gpe() cannot trigger this GPE;
       c. If no polling mechanism is implemented in the driver for this
          event (for example, SCI_EVT), this event is lost due to no GPE
          being triggered.
       Note 4:
       Currently we don't have this issue, but after we switch the EC
       driver into ACPI_GPE_DISPATCH_RAW_HANDLER mode, we need to take care
       of handling this because the EN=1 write in acpi_ev_gpe_dispatch()
       will be abandoned.
There might be more race issues for the current GPE handler usages. This is
because the EC IRQ's enabling/disabling/checking/clearing/handling
operations should be locked by a single lock that is under the EC driver's
control to achieve the serialization. Which means we need to invoke GPE
APIs with EC driver's lock held and all ACPICA internal GPE operations
related to the GPE handler should be abandoned. Invoking GPE APIs inside of
the EC driver lock and bypassing ACPICA internal GPE operations requires
the ACPI_GPE_DISPATCH_RAW_HANDLER mode where the same lock used by the APIs
are released prior than invoking the handlers. Otherwise, we can see dead
locks due to circular locking dependencies (see Reference below).
This patch then switches the EC driver into the
ACPI_GPE_DISPATCH_RAW_HANDLER mode so that it can perform correct GPE
operations using the GPE APIs:
1. Bypasses EN modifications performed in acpi_ev_gpe_dispatch() by
   using acpi_install_gpe_raw_handler() and invoking all GPE APIs with EC
   spin lock held. This can fix issue 1 as it makes a non frequent GPE
   enabling/disabling environment.
2. Bypasses STS clearing performed in acpi_enable_gpe() by replacing
   acpi_enable_gpe()/acpi_disable_gpe() with acpi_set_gpe(). This can fix
   issue 4. And this can also help to fix issue 1 as it makes a no sudden
   GPE clearing environment when GPE is frequently enabled/disabled.
3. Ensures STS acknowledged before handling by invoking acpi_clear_gpe()
   in advance_transaction(). This can finally fix issue 1 even in a
   frequent GPE enabling/disabling environment. And this can also finally
   fix issue 3 when issue 2 is fixed.
   Note 3:
   GPE clearing is edge triggered W1C, which means we can clear it right
   before handling it. Since all EC GPE indications are handled in
   advance_transaction() by previous commits, we can now move GPE clearing
   into it to implement the correct GPE clearing.
   Note 4:
   We can use acpi_set_gpe() which is not shared GPE safer instead of
   acpi_enable_gpe()/acpi_disable_gpe() because EC GPE is not shared by
   other hardware, which is mentioned in the ACPI specification 5.0, 12.6
   Interrupt Model: "OSPM driver treats this as an edge event (the EC SCI
   cannot be shared)". So we can stop using shared GPE safer APIs
   acpi_enable_gpe()/acpi_disable_gpe() in the EC driver. Otherwise
   cleanups need to be made in acpi_ev_enable_gpe() to bypass the GPE
   clearing logic before keeping acpi_enable_gpe().
This patch also invokes advance_transaction() when GPE is re-enabled in the
task context which:
1. Ensures EN=1 can trigger GPE by checking and handling EC status register
   right after EN=1 writes. This can fix issue 2.
After applying this patch, without frequent GPE enablings considered:
       =================================================================
       (event pending A)
       =================================================================
       acpi_ec_gpe_handler()     ec_poll()
       *****************************************************************
       (event handling A)
         Lock(EC)
           advance_transaction()
             if STS==1
               STS=0
             EC_SC read
       =================================================================
       (event pending B)
       =================================================================
             EC_SC handled
         Unlock(EC)
       *****************************************************************
       *****************************************************************
       (event handling B)
                                   Lock(EC)
                                     advance_transaction()
                                       if STS==1
                                         STS=0
                                       EC_SC read
       =================================================================
       (event pending C)
       =================================================================
                                       EC_SC handled
                                   Unlock(EC)
       *****************************************************************
The event pending for issue 1 (event pending B) can arrive as a next GPE
due to the previous IRQ context STS=0 write. And if it is handled by
ec_poll() (event handling B), as it is also acknowledged by ec_poll(), the
event pending for issue 2 (event pending C) can properly arrive as a next
GPE after the task context STS=0 write. So no GPE will be lost and never
triggered due to GPE clearing performed in the wrong position. And since
all GPE handling is performed after a locked GPE status checking, we can
hardly see no-op GPE handler invocations due to issue 1 and 3. We may still
see no-op GPE handler invocations due to "Note 1", but as it is inevitable,
it needn't be fixed.
After applying this patch, with frequent GPE enablings considered:
       =================================================================
       (event pending A)
       =================================================================
       acpi_ec_gpe_handler()     acpi_ec_transaction()
       *****************************************************************
       (event handling A)
         Lock(EC)
           advance_transaction()
             if STS==1
               STS=0
             EC_SC read
       =================================================================
       (event pending B)
       =================================================================
             EC_SC handled
         Unlock(EC)
       *****************************************************************
       *****************************************************************
       (event handling B)
                                   Lock(EC)
                                     EN=1
                                     if STS==1
                                       advance_transaction()
                                         if STS==1
                                           STS=0
                                         EC_SC read
       =================================================================
       (event pending C)
       =================================================================
                                         EC_SC handled
                                   Unlock(EC)
       *****************************************************************
The event pending for issue 2 can be manually handled by
advance_transaction(). And after the STS=0 write performed in the manual
triggered advance_transaction(), GPE can always arrive. So no GPE will be
lost due to frequent GPE disabling/enabling performed in the driver like
issue 4.
Note 5:
It's ideally when EN=1 write occurred, an IRQ thread should be woken up to
handle the GPE when the GPE was raised. But this requires the IRQ thread to
contain the poller code for all EC GPE indications, while currently some of
the indications are handled in the user tasks. It then is very hard for the
code to determine whether a user task should be invoked or the poller work
item should be scheduled. So we have to invoke advance_transaction()
directly now and it leaves us such a restriction for the GPE re-enabling:
it must be performed in the task context to avoid starving the GPEs.
As a conclusion: we can see the EC GPE is always handled in serial after
deploying the raw GPE handler mode:
  Lock(EC)
  if (STS==1)
    STS=0
  EC_SC read
  EC_SC handled
  Unlock(EC)
The EC driver specific lock is responsible to make the EC GPE handling
processes serialized so that EC can handle its GPE from both IRQ and task
contexts and the next IRQ can be ensured to arrive after this process.
Note 6:
We have many EC_FLAGS_MSI qurik users in the current driver. They all seem
to be suffering from unexpected GPE triggering source lost. And they are
false root caused to a timing issue. Since EC communication protocol has
already flow control defined, timing shouldn't be the root cause, while
this fix might be fixing the root cause of the old bugs.
Link: https://lkml.org/lkml/2014/11/4/974
Link: https://lkml.org/lkml/2014/11/18/316
Link: https://www.spinics.net/lists/linux-acpi/msg54340.html
Signed-off-by: Lv Zheng <lv.zheng@intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
											
										 
										
											2015-02-05 16:27:22 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									if (acpi_ec_is_gpe_raised(ec)) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										/*
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										 * On some platforms, EN=1 writes cannot trigger GPE. So
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										 * software need to manually trigger a pseudo GPE event on
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										 * EN=1 writes.
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										 */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										pr_debug("***** Polling quirk *****\n");
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										advance_transaction(ec);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								static inline void acpi_ec_disable_gpe(struct acpi_ec *ec, bool close)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									if (close)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										acpi_disable_gpe(NULL, ec->gpe);
							 | 
						
					
						
							
								
									
										
										
										
											2015-02-06 08:58:05 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									else {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										BUG_ON(ec->reference_count < 1);
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												ACPI / EC: Fix several GPE handling issues by deploying ACPI_GPE_DISPATCH_RAW_HANDLER mode.
This patch switches EC driver into ACPI_GPE_DISPATCH_RAW_HANDLER mode where
the GPE lock is not held for acpi_ec_gpe_handler() and the ACPICA internal
GPE enabling/disabling/clearing operations are bypassed so that further
improvements are possible with the GPE APIs.
There are 2 strong reasons for deploying raw GPE handler mode in the EC
driver:
1. Some hardware logics can control their interrupts via their own
   registers, so their interrupts can be disabled/enabled/acknowledged
   without using the super IRQ controller provided functions. While there
   is no mean (EC commands) for the EC driver to achieve this.
2. During suspending, the EC driver is still working for a while to
   complete the platform firmware provided functionailities using ec_poll()
   after all GPEs are disabled (see acpi_ec_block_transactions()), which
   means the EC driver will drive the EC GPE out of the GPE core's control.
Without deploying the raw GPE handler mode, we can see many races between
the EC driver and the GPE core due to the above restrictions:
1. There is a race condition due to ACPICA internal GPE
   disabling/clearing/enabling logics in acpi_ev_gpe_dispatch():
     Orignally EC GPE is disabled (EN=0), cleared (STS=0) before invoking a
     GPE handler and re-enabled (EN=1) after invoking a GPE handler in
     acpi_ev_gpe_dispatch(). When re-enabling appears, GPE may be flagged
     (STS=1).
       =================================================================
       (event pending A)
       =================================================================
       acpi_ev_gpe_dispatch()    ec_poll()
         EN=0
         STS=0
         acpi_ec_gpe_handler()
       *****************************************************************
       (event handling A)
           Lock(EC)
           advance_transaction()
             EC_SC read
       =================================================================
       (event pending B)
       =================================================================
             EC_SC handled
           Unlock(EC)
       *****************************************************************
       *****************************************************************
       (event handling B)
                                   Lock(EC)
                                   advance_transaction()
                                     EC_SC read
       =================================================================
       (event pending C)
       =================================================================
                                     EC_SC handled
                                   Unlock(EC)
       *****************************************************************
           EN=1
   This race condition is the root cause of different issues on different
   silicon variations.
   A. Silicon variation A:
      On some platforms, GPE will be triggered due to "writing 1 to EN when
      STS=1". This is because both EN and STS lines are wired to the GPE
      trigger line.
      1. Issue 1:
         We can see no-op acpi_ec_gpe_handler() invoked on such platforms.
         This is because:
         a. event pending B: An event can arrive after ACPICA's GPE
            clearing performed in acpi_ev_gpe_dispatch(), this event may
            fail to be detected by EC_SC read that is performed before its
            arrival;
         b. event handling B: The event can be handled in ec_poll() because
            EC lock is released after acpi_ec_gpe_handler() invocation;
         c. There is no code in ec_poll() to clear STS but the GPE can
            still be triggered by the EN=1 write performed in
            acpi_ev_finish_gpe(), this leads to a no-op EC GPE handler
            invocation;
         d. As no-op GPE handler invocations are counted by the EC driver
            to trigger the command storming conditions, the wrong no-op
            GPE handler invocations thus can easily trigger wrong command
            storming conditions.
         Note 1:
         If we removed GPE disabling/enabling code from
         acpi_ev_gpe_dispatch(), we could still see no-op GPE handlers
         triggered by the event arriving after the GPE clearing and before
         the GPE handling on both silicon variation A and B. This can only
         occur if the CPU is very slow (timing slice between STS=0 write
         and EC_SC read should be short enough before hardware sets another
         GPE indication). Thus this is very rare and is not what we need to
         fix.
   B. Silicon variation B:
      On other platforms, GPE may not be triggered due to "writing 1 to EN
      when STS=1". This is because only STS line is wired to the GPE
      trigger line.
      2. Issue 2:
         We can see GPE loss on such platforms. This is because:
         a. event pending B vs. event handling A: An event can arrive after
            ACPICA's GPE handling performed in acpi_ev_gpe_dispatch(), or
            event pending C vs. event handling B: An event can arrive after
            Linux's GPE handling performed in ec_poll(),
            these events may fail to be detected by EC_SC read that is
            performed before their arrival;
         b. The GPE cannot be triggered by EN=1 write performed in
            acpi_ev_finish_gpe();
         c. If no polling mechanism is implemented in the driver for the
            pending event (for example, SCI_EVT), this event is lost due to
            no GPE being triggered.
         Note 2:
         On most platforms, there might be another rule that GPE may not be
         triggered due to "writing 1 to STS when STS=1 and EN=1".
         Then on silicon variation B, an even worse case is if the issue 2
         event loss happens, further events may never trigger GPE again on
         such platforms due to being blocked by the current STS=1. Unless
         someone clears STS, all events have to be polled.
2. There is a race condition due to lacking in GPE status checking in EC
   driver:
     Originally, GPE status is checked in ACPICA core but not checked in
     the GPE handler. Thus since the status checking and handling is not
     locked, it can be interrupted by another handling path.
       =================================================================
       (event pending A)
       =================================================================
       acpi_ev_gpe_detect()        ec_poll()
         if (EN==1 && STS==1)
       *****************************************************************
       (event handling A)
                                     Lock(EC)
                                     advance_transaction()
                                       EC_SC read
                                       EC_SC handled
                                     Unlock(EC)
       *****************************************************************
         acpi_ev_gpe_dispatch()
           EN=0
           STS=0
           acpi_ec_gpe_handler()
       *****************************************************************
       (event handling B)
             Lock(EC)
             advance_transaction()
               EC_SC read
             Unlock(EC)
       *****************************************************************
      3. Issue 3:
         We can see no-op acpi_ec_gpe_handler() invoked on both silicon
         variation A and B. This is because:
         a. event pending A: An event can arrive to trigger an EC GPE and
            ACPICA checks it and is about to invoke the EC GPE handler;
         b. event handling A: The event can be handled in ec_poll() because
            EC lock is not held after the GPE status checking;
         c. event handling B: Then when the EC GPE handler is invoked, it
            becomes a no-op GPE handler invocation.
         d. As no-op GPE handler invocations are counted by the EC driver
            to trigger the command storming conditions, the wrong no-op
            GPE handler invocations thus can easily trigger wrong command
            storming conditions.
      Note 3:
      This no-op GPE handler invocation is rare because the time between
      the IRQ arrival and the acpi_ec_gpe_handler() invocation is less than
      the timeout value waited in ec_poll(). So most of the no-op GPE
      handler invocations are caused by the reason described in issue 1.
3. There is a race condition due to ACPICA internal GPE clearing logic in
   acpi_enable_gpe():
     During runtime, acpi_enable_gpe() can be invoked by the EC storming
     prevention code. When it is invoked, GPE may be flagged (STS=1).
       =================================================================
       (event pending A)
       =================================================================
       acpi_ev_gpe_dispatch()    acpi_ec_transaction()
         EN=0
         STS=0
         acpi_ec_gpe_handler()
       *****************************************************************
       (event handling A)
           Lock(EC)
           advance_transaction()
             EC_SC read
             EC_SC handled
           Unlock(EC)
       *****************************************************************
         EN=1 ?
                                   Lock(EC)
                                   Unlock(EC)
       =================================================================
       (event pending B)
       =================================================================
                                   acpi_enable_gpe()
                                     STS=0
                                     EN=1
    4. Issue 4:
       We can see GPE loss on both silicon variation A and B platforms.
       This is because:
       a. event pending B: An event can arrive right before ACPICA's GPE
          clearing performed in acpi_enable_gpe();
       b. If the GPE is cleared when GPE is disabled, then EN=1 write in
          acpi_enable_gpe() cannot trigger this GPE;
       c. If no polling mechanism is implemented in the driver for this
          event (for example, SCI_EVT), this event is lost due to no GPE
          being triggered.
       Note 4:
       Currently we don't have this issue, but after we switch the EC
       driver into ACPI_GPE_DISPATCH_RAW_HANDLER mode, we need to take care
       of handling this because the EN=1 write in acpi_ev_gpe_dispatch()
       will be abandoned.
There might be more race issues for the current GPE handler usages. This is
because the EC IRQ's enabling/disabling/checking/clearing/handling
operations should be locked by a single lock that is under the EC driver's
control to achieve the serialization. Which means we need to invoke GPE
APIs with EC driver's lock held and all ACPICA internal GPE operations
related to the GPE handler should be abandoned. Invoking GPE APIs inside of
the EC driver lock and bypassing ACPICA internal GPE operations requires
the ACPI_GPE_DISPATCH_RAW_HANDLER mode where the same lock used by the APIs
are released prior than invoking the handlers. Otherwise, we can see dead
locks due to circular locking dependencies (see Reference below).
This patch then switches the EC driver into the
ACPI_GPE_DISPATCH_RAW_HANDLER mode so that it can perform correct GPE
operations using the GPE APIs:
1. Bypasses EN modifications performed in acpi_ev_gpe_dispatch() by
   using acpi_install_gpe_raw_handler() and invoking all GPE APIs with EC
   spin lock held. This can fix issue 1 as it makes a non frequent GPE
   enabling/disabling environment.
2. Bypasses STS clearing performed in acpi_enable_gpe() by replacing
   acpi_enable_gpe()/acpi_disable_gpe() with acpi_set_gpe(). This can fix
   issue 4. And this can also help to fix issue 1 as it makes a no sudden
   GPE clearing environment when GPE is frequently enabled/disabled.
3. Ensures STS acknowledged before handling by invoking acpi_clear_gpe()
   in advance_transaction(). This can finally fix issue 1 even in a
   frequent GPE enabling/disabling environment. And this can also finally
   fix issue 3 when issue 2 is fixed.
   Note 3:
   GPE clearing is edge triggered W1C, which means we can clear it right
   before handling it. Since all EC GPE indications are handled in
   advance_transaction() by previous commits, we can now move GPE clearing
   into it to implement the correct GPE clearing.
   Note 4:
   We can use acpi_set_gpe() which is not shared GPE safer instead of
   acpi_enable_gpe()/acpi_disable_gpe() because EC GPE is not shared by
   other hardware, which is mentioned in the ACPI specification 5.0, 12.6
   Interrupt Model: "OSPM driver treats this as an edge event (the EC SCI
   cannot be shared)". So we can stop using shared GPE safer APIs
   acpi_enable_gpe()/acpi_disable_gpe() in the EC driver. Otherwise
   cleanups need to be made in acpi_ev_enable_gpe() to bypass the GPE
   clearing logic before keeping acpi_enable_gpe().
This patch also invokes advance_transaction() when GPE is re-enabled in the
task context which:
1. Ensures EN=1 can trigger GPE by checking and handling EC status register
   right after EN=1 writes. This can fix issue 2.
After applying this patch, without frequent GPE enablings considered:
       =================================================================
       (event pending A)
       =================================================================
       acpi_ec_gpe_handler()     ec_poll()
       *****************************************************************
       (event handling A)
         Lock(EC)
           advance_transaction()
             if STS==1
               STS=0
             EC_SC read
       =================================================================
       (event pending B)
       =================================================================
             EC_SC handled
         Unlock(EC)
       *****************************************************************
       *****************************************************************
       (event handling B)
                                   Lock(EC)
                                     advance_transaction()
                                       if STS==1
                                         STS=0
                                       EC_SC read
       =================================================================
       (event pending C)
       =================================================================
                                       EC_SC handled
                                   Unlock(EC)
       *****************************************************************
The event pending for issue 1 (event pending B) can arrive as a next GPE
due to the previous IRQ context STS=0 write. And if it is handled by
ec_poll() (event handling B), as it is also acknowledged by ec_poll(), the
event pending for issue 2 (event pending C) can properly arrive as a next
GPE after the task context STS=0 write. So no GPE will be lost and never
triggered due to GPE clearing performed in the wrong position. And since
all GPE handling is performed after a locked GPE status checking, we can
hardly see no-op GPE handler invocations due to issue 1 and 3. We may still
see no-op GPE handler invocations due to "Note 1", but as it is inevitable,
it needn't be fixed.
After applying this patch, with frequent GPE enablings considered:
       =================================================================
       (event pending A)
       =================================================================
       acpi_ec_gpe_handler()     acpi_ec_transaction()
       *****************************************************************
       (event handling A)
         Lock(EC)
           advance_transaction()
             if STS==1
               STS=0
             EC_SC read
       =================================================================
       (event pending B)
       =================================================================
             EC_SC handled
         Unlock(EC)
       *****************************************************************
       *****************************************************************
       (event handling B)
                                   Lock(EC)
                                     EN=1
                                     if STS==1
                                       advance_transaction()
                                         if STS==1
                                           STS=0
                                         EC_SC read
       =================================================================
       (event pending C)
       =================================================================
                                         EC_SC handled
                                   Unlock(EC)
       *****************************************************************
The event pending for issue 2 can be manually handled by
advance_transaction(). And after the STS=0 write performed in the manual
triggered advance_transaction(), GPE can always arrive. So no GPE will be
lost due to frequent GPE disabling/enabling performed in the driver like
issue 4.
Note 5:
It's ideally when EN=1 write occurred, an IRQ thread should be woken up to
handle the GPE when the GPE was raised. But this requires the IRQ thread to
contain the poller code for all EC GPE indications, while currently some of
the indications are handled in the user tasks. It then is very hard for the
code to determine whether a user task should be invoked or the poller work
item should be scheduled. So we have to invoke advance_transaction()
directly now and it leaves us such a restriction for the GPE re-enabling:
it must be performed in the task context to avoid starving the GPEs.
As a conclusion: we can see the EC GPE is always handled in serial after
deploying the raw GPE handler mode:
  Lock(EC)
  if (STS==1)
    STS=0
  EC_SC read
  EC_SC handled
  Unlock(EC)
The EC driver specific lock is responsible to make the EC GPE handling
processes serialized so that EC can handle its GPE from both IRQ and task
contexts and the next IRQ can be ensured to arrive after this process.
Note 6:
We have many EC_FLAGS_MSI qurik users in the current driver. They all seem
to be suffering from unexpected GPE triggering source lost. And they are
false root caused to a timing issue. Since EC communication protocol has
already flow control defined, timing shouldn't be the root cause, while
this fix might be fixing the root cause of the old bugs.
Link: https://lkml.org/lkml/2014/11/4/974
Link: https://lkml.org/lkml/2014/11/18/316
Link: https://www.spinics.net/lists/linux-acpi/msg54340.html
Signed-off-by: Lv Zheng <lv.zheng@intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
											
										 
										
											2015-02-05 16:27:22 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_DISABLE);
							 | 
						
					
						
							
								
									
										
										
										
											2015-02-06 08:58:05 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									}
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												ACPI / EC: Fix several GPE handling issues by deploying ACPI_GPE_DISPATCH_RAW_HANDLER mode.
This patch switches EC driver into ACPI_GPE_DISPATCH_RAW_HANDLER mode where
the GPE lock is not held for acpi_ec_gpe_handler() and the ACPICA internal
GPE enabling/disabling/clearing operations are bypassed so that further
improvements are possible with the GPE APIs.
There are 2 strong reasons for deploying raw GPE handler mode in the EC
driver:
1. Some hardware logics can control their interrupts via their own
   registers, so their interrupts can be disabled/enabled/acknowledged
   without using the super IRQ controller provided functions. While there
   is no mean (EC commands) for the EC driver to achieve this.
2. During suspending, the EC driver is still working for a while to
   complete the platform firmware provided functionailities using ec_poll()
   after all GPEs are disabled (see acpi_ec_block_transactions()), which
   means the EC driver will drive the EC GPE out of the GPE core's control.
Without deploying the raw GPE handler mode, we can see many races between
the EC driver and the GPE core due to the above restrictions:
1. There is a race condition due to ACPICA internal GPE
   disabling/clearing/enabling logics in acpi_ev_gpe_dispatch():
     Orignally EC GPE is disabled (EN=0), cleared (STS=0) before invoking a
     GPE handler and re-enabled (EN=1) after invoking a GPE handler in
     acpi_ev_gpe_dispatch(). When re-enabling appears, GPE may be flagged
     (STS=1).
       =================================================================
       (event pending A)
       =================================================================
       acpi_ev_gpe_dispatch()    ec_poll()
         EN=0
         STS=0
         acpi_ec_gpe_handler()
       *****************************************************************
       (event handling A)
           Lock(EC)
           advance_transaction()
             EC_SC read
       =================================================================
       (event pending B)
       =================================================================
             EC_SC handled
           Unlock(EC)
       *****************************************************************
       *****************************************************************
       (event handling B)
                                   Lock(EC)
                                   advance_transaction()
                                     EC_SC read
       =================================================================
       (event pending C)
       =================================================================
                                     EC_SC handled
                                   Unlock(EC)
       *****************************************************************
           EN=1
   This race condition is the root cause of different issues on different
   silicon variations.
   A. Silicon variation A:
      On some platforms, GPE will be triggered due to "writing 1 to EN when
      STS=1". This is because both EN and STS lines are wired to the GPE
      trigger line.
      1. Issue 1:
         We can see no-op acpi_ec_gpe_handler() invoked on such platforms.
         This is because:
         a. event pending B: An event can arrive after ACPICA's GPE
            clearing performed in acpi_ev_gpe_dispatch(), this event may
            fail to be detected by EC_SC read that is performed before its
            arrival;
         b. event handling B: The event can be handled in ec_poll() because
            EC lock is released after acpi_ec_gpe_handler() invocation;
         c. There is no code in ec_poll() to clear STS but the GPE can
            still be triggered by the EN=1 write performed in
            acpi_ev_finish_gpe(), this leads to a no-op EC GPE handler
            invocation;
         d. As no-op GPE handler invocations are counted by the EC driver
            to trigger the command storming conditions, the wrong no-op
            GPE handler invocations thus can easily trigger wrong command
            storming conditions.
         Note 1:
         If we removed GPE disabling/enabling code from
         acpi_ev_gpe_dispatch(), we could still see no-op GPE handlers
         triggered by the event arriving after the GPE clearing and before
         the GPE handling on both silicon variation A and B. This can only
         occur if the CPU is very slow (timing slice between STS=0 write
         and EC_SC read should be short enough before hardware sets another
         GPE indication). Thus this is very rare and is not what we need to
         fix.
   B. Silicon variation B:
      On other platforms, GPE may not be triggered due to "writing 1 to EN
      when STS=1". This is because only STS line is wired to the GPE
      trigger line.
      2. Issue 2:
         We can see GPE loss on such platforms. This is because:
         a. event pending B vs. event handling A: An event can arrive after
            ACPICA's GPE handling performed in acpi_ev_gpe_dispatch(), or
            event pending C vs. event handling B: An event can arrive after
            Linux's GPE handling performed in ec_poll(),
            these events may fail to be detected by EC_SC read that is
            performed before their arrival;
         b. The GPE cannot be triggered by EN=1 write performed in
            acpi_ev_finish_gpe();
         c. If no polling mechanism is implemented in the driver for the
            pending event (for example, SCI_EVT), this event is lost due to
            no GPE being triggered.
         Note 2:
         On most platforms, there might be another rule that GPE may not be
         triggered due to "writing 1 to STS when STS=1 and EN=1".
         Then on silicon variation B, an even worse case is if the issue 2
         event loss happens, further events may never trigger GPE again on
         such platforms due to being blocked by the current STS=1. Unless
         someone clears STS, all events have to be polled.
2. There is a race condition due to lacking in GPE status checking in EC
   driver:
     Originally, GPE status is checked in ACPICA core but not checked in
     the GPE handler. Thus since the status checking and handling is not
     locked, it can be interrupted by another handling path.
       =================================================================
       (event pending A)
       =================================================================
       acpi_ev_gpe_detect()        ec_poll()
         if (EN==1 && STS==1)
       *****************************************************************
       (event handling A)
                                     Lock(EC)
                                     advance_transaction()
                                       EC_SC read
                                       EC_SC handled
                                     Unlock(EC)
       *****************************************************************
         acpi_ev_gpe_dispatch()
           EN=0
           STS=0
           acpi_ec_gpe_handler()
       *****************************************************************
       (event handling B)
             Lock(EC)
             advance_transaction()
               EC_SC read
             Unlock(EC)
       *****************************************************************
      3. Issue 3:
         We can see no-op acpi_ec_gpe_handler() invoked on both silicon
         variation A and B. This is because:
         a. event pending A: An event can arrive to trigger an EC GPE and
            ACPICA checks it and is about to invoke the EC GPE handler;
         b. event handling A: The event can be handled in ec_poll() because
            EC lock is not held after the GPE status checking;
         c. event handling B: Then when the EC GPE handler is invoked, it
            becomes a no-op GPE handler invocation.
         d. As no-op GPE handler invocations are counted by the EC driver
            to trigger the command storming conditions, the wrong no-op
            GPE handler invocations thus can easily trigger wrong command
            storming conditions.
      Note 3:
      This no-op GPE handler invocation is rare because the time between
      the IRQ arrival and the acpi_ec_gpe_handler() invocation is less than
      the timeout value waited in ec_poll(). So most of the no-op GPE
      handler invocations are caused by the reason described in issue 1.
3. There is a race condition due to ACPICA internal GPE clearing logic in
   acpi_enable_gpe():
     During runtime, acpi_enable_gpe() can be invoked by the EC storming
     prevention code. When it is invoked, GPE may be flagged (STS=1).
       =================================================================
       (event pending A)
       =================================================================
       acpi_ev_gpe_dispatch()    acpi_ec_transaction()
         EN=0
         STS=0
         acpi_ec_gpe_handler()
       *****************************************************************
       (event handling A)
           Lock(EC)
           advance_transaction()
             EC_SC read
             EC_SC handled
           Unlock(EC)
       *****************************************************************
         EN=1 ?
                                   Lock(EC)
                                   Unlock(EC)
       =================================================================
       (event pending B)
       =================================================================
                                   acpi_enable_gpe()
                                     STS=0
                                     EN=1
    4. Issue 4:
       We can see GPE loss on both silicon variation A and B platforms.
       This is because:
       a. event pending B: An event can arrive right before ACPICA's GPE
          clearing performed in acpi_enable_gpe();
       b. If the GPE is cleared when GPE is disabled, then EN=1 write in
          acpi_enable_gpe() cannot trigger this GPE;
       c. If no polling mechanism is implemented in the driver for this
          event (for example, SCI_EVT), this event is lost due to no GPE
          being triggered.
       Note 4:
       Currently we don't have this issue, but after we switch the EC
       driver into ACPI_GPE_DISPATCH_RAW_HANDLER mode, we need to take care
       of handling this because the EN=1 write in acpi_ev_gpe_dispatch()
       will be abandoned.
There might be more race issues for the current GPE handler usages. This is
because the EC IRQ's enabling/disabling/checking/clearing/handling
operations should be locked by a single lock that is under the EC driver's
control to achieve the serialization. Which means we need to invoke GPE
APIs with EC driver's lock held and all ACPICA internal GPE operations
related to the GPE handler should be abandoned. Invoking GPE APIs inside of
the EC driver lock and bypassing ACPICA internal GPE operations requires
the ACPI_GPE_DISPATCH_RAW_HANDLER mode where the same lock used by the APIs
are released prior than invoking the handlers. Otherwise, we can see dead
locks due to circular locking dependencies (see Reference below).
This patch then switches the EC driver into the
ACPI_GPE_DISPATCH_RAW_HANDLER mode so that it can perform correct GPE
operations using the GPE APIs:
1. Bypasses EN modifications performed in acpi_ev_gpe_dispatch() by
   using acpi_install_gpe_raw_handler() and invoking all GPE APIs with EC
   spin lock held. This can fix issue 1 as it makes a non frequent GPE
   enabling/disabling environment.
2. Bypasses STS clearing performed in acpi_enable_gpe() by replacing
   acpi_enable_gpe()/acpi_disable_gpe() with acpi_set_gpe(). This can fix
   issue 4. And this can also help to fix issue 1 as it makes a no sudden
   GPE clearing environment when GPE is frequently enabled/disabled.
3. Ensures STS acknowledged before handling by invoking acpi_clear_gpe()
   in advance_transaction(). This can finally fix issue 1 even in a
   frequent GPE enabling/disabling environment. And this can also finally
   fix issue 3 when issue 2 is fixed.
   Note 3:
   GPE clearing is edge triggered W1C, which means we can clear it right
   before handling it. Since all EC GPE indications are handled in
   advance_transaction() by previous commits, we can now move GPE clearing
   into it to implement the correct GPE clearing.
   Note 4:
   We can use acpi_set_gpe() which is not shared GPE safer instead of
   acpi_enable_gpe()/acpi_disable_gpe() because EC GPE is not shared by
   other hardware, which is mentioned in the ACPI specification 5.0, 12.6
   Interrupt Model: "OSPM driver treats this as an edge event (the EC SCI
   cannot be shared)". So we can stop using shared GPE safer APIs
   acpi_enable_gpe()/acpi_disable_gpe() in the EC driver. Otherwise
   cleanups need to be made in acpi_ev_enable_gpe() to bypass the GPE
   clearing logic before keeping acpi_enable_gpe().
This patch also invokes advance_transaction() when GPE is re-enabled in the
task context which:
1. Ensures EN=1 can trigger GPE by checking and handling EC status register
   right after EN=1 writes. This can fix issue 2.
After applying this patch, without frequent GPE enablings considered:
       =================================================================
       (event pending A)
       =================================================================
       acpi_ec_gpe_handler()     ec_poll()
       *****************************************************************
       (event handling A)
         Lock(EC)
           advance_transaction()
             if STS==1
               STS=0
             EC_SC read
       =================================================================
       (event pending B)
       =================================================================
             EC_SC handled
         Unlock(EC)
       *****************************************************************
       *****************************************************************
       (event handling B)
                                   Lock(EC)
                                     advance_transaction()
                                       if STS==1
                                         STS=0
                                       EC_SC read
       =================================================================
       (event pending C)
       =================================================================
                                       EC_SC handled
                                   Unlock(EC)
       *****************************************************************
The event pending for issue 1 (event pending B) can arrive as a next GPE
due to the previous IRQ context STS=0 write. And if it is handled by
ec_poll() (event handling B), as it is also acknowledged by ec_poll(), the
event pending for issue 2 (event pending C) can properly arrive as a next
GPE after the task context STS=0 write. So no GPE will be lost and never
triggered due to GPE clearing performed in the wrong position. And since
all GPE handling is performed after a locked GPE status checking, we can
hardly see no-op GPE handler invocations due to issue 1 and 3. We may still
see no-op GPE handler invocations due to "Note 1", but as it is inevitable,
it needn't be fixed.
After applying this patch, with frequent GPE enablings considered:
       =================================================================
       (event pending A)
       =================================================================
       acpi_ec_gpe_handler()     acpi_ec_transaction()
       *****************************************************************
       (event handling A)
         Lock(EC)
           advance_transaction()
             if STS==1
               STS=0
             EC_SC read
       =================================================================
       (event pending B)
       =================================================================
             EC_SC handled
         Unlock(EC)
       *****************************************************************
       *****************************************************************
       (event handling B)
                                   Lock(EC)
                                     EN=1
                                     if STS==1
                                       advance_transaction()
                                         if STS==1
                                           STS=0
                                         EC_SC read
       =================================================================
       (event pending C)
       =================================================================
                                         EC_SC handled
                                   Unlock(EC)
       *****************************************************************
The event pending for issue 2 can be manually handled by
advance_transaction(). And after the STS=0 write performed in the manual
triggered advance_transaction(), GPE can always arrive. So no GPE will be
lost due to frequent GPE disabling/enabling performed in the driver like
issue 4.
Note 5:
It's ideally when EN=1 write occurred, an IRQ thread should be woken up to
handle the GPE when the GPE was raised. But this requires the IRQ thread to
contain the poller code for all EC GPE indications, while currently some of
the indications are handled in the user tasks. It then is very hard for the
code to determine whether a user task should be invoked or the poller work
item should be scheduled. So we have to invoke advance_transaction()
directly now and it leaves us such a restriction for the GPE re-enabling:
it must be performed in the task context to avoid starving the GPEs.
As a conclusion: we can see the EC GPE is always handled in serial after
deploying the raw GPE handler mode:
  Lock(EC)
  if (STS==1)
    STS=0
  EC_SC read
  EC_SC handled
  Unlock(EC)
The EC driver specific lock is responsible to make the EC GPE handling
processes serialized so that EC can handle its GPE from both IRQ and task
contexts and the next IRQ can be ensured to arrive after this process.
Note 6:
We have many EC_FLAGS_MSI qurik users in the current driver. They all seem
to be suffering from unexpected GPE triggering source lost. And they are
false root caused to a timing issue. Since EC communication protocol has
already flow control defined, timing shouldn't be the root cause, while
this fix might be fixing the root cause of the old bugs.
Link: https://lkml.org/lkml/2014/11/4/974
Link: https://lkml.org/lkml/2014/11/18/316
Link: https://www.spinics.net/lists/linux-acpi/msg54340.html
Signed-off-by: Lv Zheng <lv.zheng@intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
											
										 
										
											2015-02-05 16:27:22 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								static inline void acpi_ec_clear_gpe(struct acpi_ec *ec)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									/*
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									 * GPE STS is a W1C register, which means:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									 * 1. Software can clear it without worrying about clearing other
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									 *    GPEs' STS bits when the hardware sets them in parallel.
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									 * 2. As long as software can ensure only clearing it when it is
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									 *    set, hardware won't set it in parallel.
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									 * So software can clear GPE in any contexts.
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									 * Warning: do not move the check into advance_transaction() as the
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									 * EC commands will be sent without GPE raised.
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									 */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									if (!acpi_ec_is_gpe_raised(ec))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										return;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									acpi_clear_gpe(NULL, ec->gpe);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								/* --------------------------------------------------------------------------
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 *                           Transaction Management
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * -------------------------------------------------------------------------- */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2015-02-06 08:57:59 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								static void acpi_ec_submit_request(struct acpi_ec *ec)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									ec->reference_count++;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									if (ec->reference_count == 1)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										acpi_ec_enable_gpe(ec, true);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								static void acpi_ec_complete_request(struct acpi_ec *ec)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									bool flushed = false;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									ec->reference_count--;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									if (ec->reference_count == 0)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										acpi_ec_disable_gpe(ec, true);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									flushed = acpi_ec_flushed(ec);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									if (flushed)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										wake_up(&ec->wait);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2015-02-06 08:58:05 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								static void acpi_ec_set_storm(struct acpi_ec *ec, u8 flag)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									if (!test_bit(flag, &ec->flags)) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										acpi_ec_disable_gpe(ec, false);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										pr_debug("+++++ Polling enabled +++++\n");
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										set_bit(flag, &ec->flags);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								static void acpi_ec_clear_storm(struct acpi_ec *ec, u8 flag)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									if (test_bit(flag, &ec->flags)) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										clear_bit(flag, &ec->flags);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										acpi_ec_enable_gpe(ec, false);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										pr_debug("+++++ Polling disabled +++++\n");
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2015-02-06 08:57:59 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/*
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * acpi_ec_submit_flushable_request() - Increase the reference count unless
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 *                                      the flush operation is not in
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 *                                      progress
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * @ec: the EC device
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 *
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * This function must be used before taking a new action that should hold
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * the reference count.  If this function returns false, then the action
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * must be discarded or it will prevent the flush operation from being
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * completed.
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 */
							 | 
						
					
						
							
								
									
										
										
										
											2015-02-11 17:35:05 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								static bool acpi_ec_submit_flushable_request(struct acpi_ec *ec)
							 | 
						
					
						
							
								
									
										
										
										
											2015-02-06 08:57:59 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							
								
									
										
										
										
											2015-02-11 17:35:05 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									if (!acpi_ec_started(ec))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										return false;
							 | 
						
					
						
							
								
									
										
										
										
											2015-02-06 08:57:59 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									acpi_ec_submit_request(ec);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									return true;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2015-02-11 17:35:05 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								static void acpi_ec_submit_query(struct acpi_ec *ec)
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												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>
											
										 
										
											2015-01-14 19:28:47 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							
								
									
										
										
										
											2015-02-11 17:35:05 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										pr_debug("***** Event started *****\n");
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												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>
											
										 
										
											2015-01-14 19:28:47 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										schedule_work(&ec->work);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2015-02-11 17:35:05 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								static void acpi_ec_complete_query(struct acpi_ec *ec)
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												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>
											
										 
										
											2015-01-14 19:28:47 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									if (ec->curr->command == ACPI_EC_COMMAND_QUERY) {
							 | 
						
					
						
							
								
									
										
										
										
											2015-02-11 17:35:05 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										pr_debug("***** Event stopped *****\n");
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												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>
											
										 
										
											2015-01-14 19:28:47 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2014-06-15 08:41:35 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								static int ec_transaction_completed(struct acpi_ec *ec)
							 | 
						
					
						
							
								
									
										
										
										
											2006-09-26 19:50:33 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							
								
									
										
										
										
											2008-09-25 21:00:31 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									unsigned long flags;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									int ret = 0;
							 | 
						
					
						
							
								
									
										
										
										
											2014-10-14 14:24:01 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2012-10-23 01:29:27 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									spin_lock_irqsave(&ec->lock, flags);
							 | 
						
					
						
							
								
									
										
										
										
											2014-06-15 08:42:07 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									if (ec->curr && (ec->curr->flags & ACPI_EC_COMMAND_COMPLETE))
							 | 
						
					
						
							
								
									
										
										
										
											2008-09-25 21:00:31 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										ret = 1;
							 | 
						
					
						
							
								
									
										
										
										
											2012-10-23 01:29:27 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									spin_unlock_irqrestore(&ec->lock, flags);
							 | 
						
					
						
							
								
									
										
										
										
											2008-09-25 21:00:31 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									return ret;
							 | 
						
					
						
							
								
									
										
										
										
											2005-07-23 04:08:00 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							
								
									
										
										
										
											2005-03-19 01:10:05 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2015-01-14 19:28:22 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								static void advance_transaction(struct acpi_ec *ec)
							 | 
						
					
						
							
								
									
										
										
										
											2006-09-26 19:50:33 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							
								
									
										
										
										
											2013-11-15 11:41:29 -08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									struct transaction *t;
							 | 
						
					
						
							
								
									
										
										
										
											2014-06-15 08:41:17 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									u8 status;
							 | 
						
					
						
							
								
									
										
										
										
											2014-06-15 08:42:07 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									bool wakeup = false;
							 | 
						
					
						
							
								
									
										
										
										
											2012-10-23 01:29:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2014-10-14 14:23:38 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									pr_debug("===== %s (%d) =====\n",
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										 in_interrupt() ? "IRQ" : "TASK", smp_processor_id());
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												ACPI / EC: Fix several GPE handling issues by deploying ACPI_GPE_DISPATCH_RAW_HANDLER mode.
This patch switches EC driver into ACPI_GPE_DISPATCH_RAW_HANDLER mode where
the GPE lock is not held for acpi_ec_gpe_handler() and the ACPICA internal
GPE enabling/disabling/clearing operations are bypassed so that further
improvements are possible with the GPE APIs.
There are 2 strong reasons for deploying raw GPE handler mode in the EC
driver:
1. Some hardware logics can control their interrupts via their own
   registers, so their interrupts can be disabled/enabled/acknowledged
   without using the super IRQ controller provided functions. While there
   is no mean (EC commands) for the EC driver to achieve this.
2. During suspending, the EC driver is still working for a while to
   complete the platform firmware provided functionailities using ec_poll()
   after all GPEs are disabled (see acpi_ec_block_transactions()), which
   means the EC driver will drive the EC GPE out of the GPE core's control.
Without deploying the raw GPE handler mode, we can see many races between
the EC driver and the GPE core due to the above restrictions:
1. There is a race condition due to ACPICA internal GPE
   disabling/clearing/enabling logics in acpi_ev_gpe_dispatch():
     Orignally EC GPE is disabled (EN=0), cleared (STS=0) before invoking a
     GPE handler and re-enabled (EN=1) after invoking a GPE handler in
     acpi_ev_gpe_dispatch(). When re-enabling appears, GPE may be flagged
     (STS=1).
       =================================================================
       (event pending A)
       =================================================================
       acpi_ev_gpe_dispatch()    ec_poll()
         EN=0
         STS=0
         acpi_ec_gpe_handler()
       *****************************************************************
       (event handling A)
           Lock(EC)
           advance_transaction()
             EC_SC read
       =================================================================
       (event pending B)
       =================================================================
             EC_SC handled
           Unlock(EC)
       *****************************************************************
       *****************************************************************
       (event handling B)
                                   Lock(EC)
                                   advance_transaction()
                                     EC_SC read
       =================================================================
       (event pending C)
       =================================================================
                                     EC_SC handled
                                   Unlock(EC)
       *****************************************************************
           EN=1
   This race condition is the root cause of different issues on different
   silicon variations.
   A. Silicon variation A:
      On some platforms, GPE will be triggered due to "writing 1 to EN when
      STS=1". This is because both EN and STS lines are wired to the GPE
      trigger line.
      1. Issue 1:
         We can see no-op acpi_ec_gpe_handler() invoked on such platforms.
         This is because:
         a. event pending B: An event can arrive after ACPICA's GPE
            clearing performed in acpi_ev_gpe_dispatch(), this event may
            fail to be detected by EC_SC read that is performed before its
            arrival;
         b. event handling B: The event can be handled in ec_poll() because
            EC lock is released after acpi_ec_gpe_handler() invocation;
         c. There is no code in ec_poll() to clear STS but the GPE can
            still be triggered by the EN=1 write performed in
            acpi_ev_finish_gpe(), this leads to a no-op EC GPE handler
            invocation;
         d. As no-op GPE handler invocations are counted by the EC driver
            to trigger the command storming conditions, the wrong no-op
            GPE handler invocations thus can easily trigger wrong command
            storming conditions.
         Note 1:
         If we removed GPE disabling/enabling code from
         acpi_ev_gpe_dispatch(), we could still see no-op GPE handlers
         triggered by the event arriving after the GPE clearing and before
         the GPE handling on both silicon variation A and B. This can only
         occur if the CPU is very slow (timing slice between STS=0 write
         and EC_SC read should be short enough before hardware sets another
         GPE indication). Thus this is very rare and is not what we need to
         fix.
   B. Silicon variation B:
      On other platforms, GPE may not be triggered due to "writing 1 to EN
      when STS=1". This is because only STS line is wired to the GPE
      trigger line.
      2. Issue 2:
         We can see GPE loss on such platforms. This is because:
         a. event pending B vs. event handling A: An event can arrive after
            ACPICA's GPE handling performed in acpi_ev_gpe_dispatch(), or
            event pending C vs. event handling B: An event can arrive after
            Linux's GPE handling performed in ec_poll(),
            these events may fail to be detected by EC_SC read that is
            performed before their arrival;
         b. The GPE cannot be triggered by EN=1 write performed in
            acpi_ev_finish_gpe();
         c. If no polling mechanism is implemented in the driver for the
            pending event (for example, SCI_EVT), this event is lost due to
            no GPE being triggered.
         Note 2:
         On most platforms, there might be another rule that GPE may not be
         triggered due to "writing 1 to STS when STS=1 and EN=1".
         Then on silicon variation B, an even worse case is if the issue 2
         event loss happens, further events may never trigger GPE again on
         such platforms due to being blocked by the current STS=1. Unless
         someone clears STS, all events have to be polled.
2. There is a race condition due to lacking in GPE status checking in EC
   driver:
     Originally, GPE status is checked in ACPICA core but not checked in
     the GPE handler. Thus since the status checking and handling is not
     locked, it can be interrupted by another handling path.
       =================================================================
       (event pending A)
       =================================================================
       acpi_ev_gpe_detect()        ec_poll()
         if (EN==1 && STS==1)
       *****************************************************************
       (event handling A)
                                     Lock(EC)
                                     advance_transaction()
                                       EC_SC read
                                       EC_SC handled
                                     Unlock(EC)
       *****************************************************************
         acpi_ev_gpe_dispatch()
           EN=0
           STS=0
           acpi_ec_gpe_handler()
       *****************************************************************
       (event handling B)
             Lock(EC)
             advance_transaction()
               EC_SC read
             Unlock(EC)
       *****************************************************************
      3. Issue 3:
         We can see no-op acpi_ec_gpe_handler() invoked on both silicon
         variation A and B. This is because:
         a. event pending A: An event can arrive to trigger an EC GPE and
            ACPICA checks it and is about to invoke the EC GPE handler;
         b. event handling A: The event can be handled in ec_poll() because
            EC lock is not held after the GPE status checking;
         c. event handling B: Then when the EC GPE handler is invoked, it
            becomes a no-op GPE handler invocation.
         d. As no-op GPE handler invocations are counted by the EC driver
            to trigger the command storming conditions, the wrong no-op
            GPE handler invocations thus can easily trigger wrong command
            storming conditions.
      Note 3:
      This no-op GPE handler invocation is rare because the time between
      the IRQ arrival and the acpi_ec_gpe_handler() invocation is less than
      the timeout value waited in ec_poll(). So most of the no-op GPE
      handler invocations are caused by the reason described in issue 1.
3. There is a race condition due to ACPICA internal GPE clearing logic in
   acpi_enable_gpe():
     During runtime, acpi_enable_gpe() can be invoked by the EC storming
     prevention code. When it is invoked, GPE may be flagged (STS=1).
       =================================================================
       (event pending A)
       =================================================================
       acpi_ev_gpe_dispatch()    acpi_ec_transaction()
         EN=0
         STS=0
         acpi_ec_gpe_handler()
       *****************************************************************
       (event handling A)
           Lock(EC)
           advance_transaction()
             EC_SC read
             EC_SC handled
           Unlock(EC)
       *****************************************************************
         EN=1 ?
                                   Lock(EC)
                                   Unlock(EC)
       =================================================================
       (event pending B)
       =================================================================
                                   acpi_enable_gpe()
                                     STS=0
                                     EN=1
    4. Issue 4:
       We can see GPE loss on both silicon variation A and B platforms.
       This is because:
       a. event pending B: An event can arrive right before ACPICA's GPE
          clearing performed in acpi_enable_gpe();
       b. If the GPE is cleared when GPE is disabled, then EN=1 write in
          acpi_enable_gpe() cannot trigger this GPE;
       c. If no polling mechanism is implemented in the driver for this
          event (for example, SCI_EVT), this event is lost due to no GPE
          being triggered.
       Note 4:
       Currently we don't have this issue, but after we switch the EC
       driver into ACPI_GPE_DISPATCH_RAW_HANDLER mode, we need to take care
       of handling this because the EN=1 write in acpi_ev_gpe_dispatch()
       will be abandoned.
There might be more race issues for the current GPE handler usages. This is
because the EC IRQ's enabling/disabling/checking/clearing/handling
operations should be locked by a single lock that is under the EC driver's
control to achieve the serialization. Which means we need to invoke GPE
APIs with EC driver's lock held and all ACPICA internal GPE operations
related to the GPE handler should be abandoned. Invoking GPE APIs inside of
the EC driver lock and bypassing ACPICA internal GPE operations requires
the ACPI_GPE_DISPATCH_RAW_HANDLER mode where the same lock used by the APIs
are released prior than invoking the handlers. Otherwise, we can see dead
locks due to circular locking dependencies (see Reference below).
This patch then switches the EC driver into the
ACPI_GPE_DISPATCH_RAW_HANDLER mode so that it can perform correct GPE
operations using the GPE APIs:
1. Bypasses EN modifications performed in acpi_ev_gpe_dispatch() by
   using acpi_install_gpe_raw_handler() and invoking all GPE APIs with EC
   spin lock held. This can fix issue 1 as it makes a non frequent GPE
   enabling/disabling environment.
2. Bypasses STS clearing performed in acpi_enable_gpe() by replacing
   acpi_enable_gpe()/acpi_disable_gpe() with acpi_set_gpe(). This can fix
   issue 4. And this can also help to fix issue 1 as it makes a no sudden
   GPE clearing environment when GPE is frequently enabled/disabled.
3. Ensures STS acknowledged before handling by invoking acpi_clear_gpe()
   in advance_transaction(). This can finally fix issue 1 even in a
   frequent GPE enabling/disabling environment. And this can also finally
   fix issue 3 when issue 2 is fixed.
   Note 3:
   GPE clearing is edge triggered W1C, which means we can clear it right
   before handling it. Since all EC GPE indications are handled in
   advance_transaction() by previous commits, we can now move GPE clearing
   into it to implement the correct GPE clearing.
   Note 4:
   We can use acpi_set_gpe() which is not shared GPE safer instead of
   acpi_enable_gpe()/acpi_disable_gpe() because EC GPE is not shared by
   other hardware, which is mentioned in the ACPI specification 5.0, 12.6
   Interrupt Model: "OSPM driver treats this as an edge event (the EC SCI
   cannot be shared)". So we can stop using shared GPE safer APIs
   acpi_enable_gpe()/acpi_disable_gpe() in the EC driver. Otherwise
   cleanups need to be made in acpi_ev_enable_gpe() to bypass the GPE
   clearing logic before keeping acpi_enable_gpe().
This patch also invokes advance_transaction() when GPE is re-enabled in the
task context which:
1. Ensures EN=1 can trigger GPE by checking and handling EC status register
   right after EN=1 writes. This can fix issue 2.
After applying this patch, without frequent GPE enablings considered:
       =================================================================
       (event pending A)
       =================================================================
       acpi_ec_gpe_handler()     ec_poll()
       *****************************************************************
       (event handling A)
         Lock(EC)
           advance_transaction()
             if STS==1
               STS=0
             EC_SC read
       =================================================================
       (event pending B)
       =================================================================
             EC_SC handled
         Unlock(EC)
       *****************************************************************
       *****************************************************************
       (event handling B)
                                   Lock(EC)
                                     advance_transaction()
                                       if STS==1
                                         STS=0
                                       EC_SC read
       =================================================================
       (event pending C)
       =================================================================
                                       EC_SC handled
                                   Unlock(EC)
       *****************************************************************
The event pending for issue 1 (event pending B) can arrive as a next GPE
due to the previous IRQ context STS=0 write. And if it is handled by
ec_poll() (event handling B), as it is also acknowledged by ec_poll(), the
event pending for issue 2 (event pending C) can properly arrive as a next
GPE after the task context STS=0 write. So no GPE will be lost and never
triggered due to GPE clearing performed in the wrong position. And since
all GPE handling is performed after a locked GPE status checking, we can
hardly see no-op GPE handler invocations due to issue 1 and 3. We may still
see no-op GPE handler invocations due to "Note 1", but as it is inevitable,
it needn't be fixed.
After applying this patch, with frequent GPE enablings considered:
       =================================================================
       (event pending A)
       =================================================================
       acpi_ec_gpe_handler()     acpi_ec_transaction()
       *****************************************************************
       (event handling A)
         Lock(EC)
           advance_transaction()
             if STS==1
               STS=0
             EC_SC read
       =================================================================
       (event pending B)
       =================================================================
             EC_SC handled
         Unlock(EC)
       *****************************************************************
       *****************************************************************
       (event handling B)
                                   Lock(EC)
                                     EN=1
                                     if STS==1
                                       advance_transaction()
                                         if STS==1
                                           STS=0
                                         EC_SC read
       =================================================================
       (event pending C)
       =================================================================
                                         EC_SC handled
                                   Unlock(EC)
       *****************************************************************
The event pending for issue 2 can be manually handled by
advance_transaction(). And after the STS=0 write performed in the manual
triggered advance_transaction(), GPE can always arrive. So no GPE will be
lost due to frequent GPE disabling/enabling performed in the driver like
issue 4.
Note 5:
It's ideally when EN=1 write occurred, an IRQ thread should be woken up to
handle the GPE when the GPE was raised. But this requires the IRQ thread to
contain the poller code for all EC GPE indications, while currently some of
the indications are handled in the user tasks. It then is very hard for the
code to determine whether a user task should be invoked or the poller work
item should be scheduled. So we have to invoke advance_transaction()
directly now and it leaves us such a restriction for the GPE re-enabling:
it must be performed in the task context to avoid starving the GPEs.
As a conclusion: we can see the EC GPE is always handled in serial after
deploying the raw GPE handler mode:
  Lock(EC)
  if (STS==1)
    STS=0
  EC_SC read
  EC_SC handled
  Unlock(EC)
The EC driver specific lock is responsible to make the EC GPE handling
processes serialized so that EC can handle its GPE from both IRQ and task
contexts and the next IRQ can be ensured to arrive after this process.
Note 6:
We have many EC_FLAGS_MSI qurik users in the current driver. They all seem
to be suffering from unexpected GPE triggering source lost. And they are
false root caused to a timing issue. Since EC communication protocol has
already flow control defined, timing shouldn't be the root cause, while
this fix might be fixing the root cause of the old bugs.
Link: https://lkml.org/lkml/2014/11/4/974
Link: https://lkml.org/lkml/2014/11/18/316
Link: https://www.spinics.net/lists/linux-acpi/msg54340.html
Signed-off-by: Lv Zheng <lv.zheng@intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
											
										 
										
											2015-02-05 16:27:22 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									/*
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									 * By always clearing STS before handling all indications, we can
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									 * ensure a hardware STS 0->1 change after this clearing can always
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									 * trigger a GPE interrupt.
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									 */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									acpi_ec_clear_gpe(ec);
							 | 
						
					
						
							
								
									
										
										
										
											2014-06-15 08:41:17 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									status = acpi_ec_read_status(ec);
							 | 
						
					
						
							
								
									
										
										
										
											2013-11-15 11:41:29 -08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									t = ec->curr;
							 | 
						
					
						
							
								
									
										
										
										
											2012-10-23 01:29:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									if (!t)
							 | 
						
					
						
							
								
									
										
										
										
											2014-06-15 08:41:35 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										goto err;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									if (t->flags & ACPI_EC_COMMAND_POLL) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										if (t->wlen > t->wi) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
											if ((status & ACPI_EC_FLAG_IBF) == 0)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
												acpi_ec_write_data(ec, t->wdata[t->wi++]);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
											else
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
												goto err;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										} else if (t->rlen > t->ri) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
											if ((status & ACPI_EC_FLAG_OBF) == 1) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
												t->rdata[t->ri++] = acpi_ec_read_data(ec);
							 | 
						
					
						
							
								
									
										
										
										
											2014-06-15 08:42:07 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
												if (t->rlen == t->ri) {
							 | 
						
					
						
							
								
									
										
										
										
											2014-06-15 08:41:35 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
													t->flags |= ACPI_EC_COMMAND_COMPLETE;
							 | 
						
					
						
							
								
									
										
										
										
											2014-08-21 14:41:13 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
													if (t->command == ACPI_EC_COMMAND_QUERY)
							 | 
						
					
						
							
								
									
										
										
										
											2014-10-14 14:23:49 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
														pr_debug("***** Command(%s) hardware completion *****\n",
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
															 acpi_ec_cmd_string(t->command));
							 | 
						
					
						
							
								
									
										
										
										
											2014-06-15 08:42:07 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
													wakeup = true;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
												}
							 | 
						
					
						
							
								
									
										
										
										
											2014-06-15 08:41:35 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
											} else
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
												goto err;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										} else if (t->wlen == t->wi &&
							 | 
						
					
						
							
								
									
										
										
										
											2014-06-15 08:42:07 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
											   (status & ACPI_EC_FLAG_IBF) == 0) {
							 | 
						
					
						
							
								
									
										
										
										
											2014-06-15 08:41:35 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
											t->flags |= ACPI_EC_COMMAND_COMPLETE;
							 | 
						
					
						
							
								
									
										
										
										
											2014-06-15 08:42:07 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
											wakeup = true;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										}
							 | 
						
					
						
							
								
									
										
										
										
											2015-01-14 19:28:22 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										goto out;
							 | 
						
					
						
							
								
									
										
										
										
											2014-06-15 08:41:35 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									} else {
							 | 
						
					
						
							
								
									
										
										
										
											2014-10-29 11:33:49 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										if (EC_FLAGS_QUERY_HANDSHAKE &&
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										    !(status & ACPI_EC_FLAG_SCI) &&
							 | 
						
					
						
							
								
									
										
										
										
											2014-08-21 14:41:13 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										    (t->command == ACPI_EC_COMMAND_QUERY)) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
											t->flags |= ACPI_EC_COMMAND_POLL;
							 | 
						
					
						
							
								
									
										
										
										
											2015-02-11 17:35:05 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
											acpi_ec_complete_query(ec);
							 | 
						
					
						
							
								
									
										
										
										
											2014-08-21 14:41:13 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
											t->rdata[t->ri++] = 0x00;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
											t->flags |= ACPI_EC_COMMAND_COMPLETE;
							 | 
						
					
						
							
								
									
										
										
										
											2014-10-14 14:23:49 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
											pr_debug("***** Command(%s) software completion *****\n",
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
												 acpi_ec_cmd_string(t->command));
							 | 
						
					
						
							
								
									
										
										
										
											2014-08-21 14:41:13 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
											wakeup = true;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										} else if ((status & ACPI_EC_FLAG_IBF) == 0) {
							 | 
						
					
						
							
								
									
										
										
										
											2014-06-15 08:41:35 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
											acpi_ec_write_cmd(ec, t->command);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
											t->flags |= ACPI_EC_COMMAND_POLL;
							 | 
						
					
						
							
								
									
										
										
										
											2015-02-11 17:35:05 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
											acpi_ec_complete_query(ec);
							 | 
						
					
						
							
								
									
										
										
										
											2008-09-25 21:00:31 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										} else
							 | 
						
					
						
							
								
									
										
										
										
											2008-11-08 21:42:30 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
											goto err;
							 | 
						
					
						
							
								
									
										
										
										
											2015-01-14 19:28:22 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										goto out;
							 | 
						
					
						
							
								
									
										
										
										
											2014-06-15 08:41:35 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									}
							 | 
						
					
						
							
								
									
										
										
										
											2008-11-08 21:42:30 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								err:
							 | 
						
					
						
							
								
									
										
										
										
											2012-10-23 01:30:12 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									/*
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									 * If SCI bit is set, then don't think it's a false IRQ
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									 * otherwise will take a not handled IRQ as a false one.
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									 */
							 | 
						
					
						
							
								
									
										
										
										
											2014-06-15 08:41:35 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									if (!(status & ACPI_EC_FLAG_SCI)) {
							 | 
						
					
						
							
								
									
										
										
										
											2015-02-06 08:58:05 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										if (in_interrupt() && t) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
											if (t->irq_count < ec_storm_threshold)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
												++t->irq_count;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
											/* Allow triggering on 0 threshold */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
											if (t->irq_count == ec_storm_threshold)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
												acpi_ec_set_storm(ec, EC_FLAGS_COMMAND_STORM);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										}
							 | 
						
					
						
							
								
									
										
										
										
											2014-06-15 08:41:35 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									}
							 | 
						
					
						
							
								
									
										
										
										
											2015-01-14 19:28:22 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								out:
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												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>
											
										 
										
											2015-01-14 19:28:47 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									if (status & ACPI_EC_FLAG_SCI)
							 | 
						
					
						
							
								
									
										
										
										
											2015-02-11 17:35:05 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										acpi_ec_submit_query(ec);
							 | 
						
					
						
							
								
									
										
										
										
											2015-01-14 19:28:22 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									if (wakeup && in_interrupt())
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										wake_up(&ec->wait);
							 | 
						
					
						
							
								
									
										
										
										
											2014-06-15 08:41:35 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							
								
									
										
										
										
											2012-10-23 01:30:12 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2014-06-15 08:41:35 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								static void start_transaction(struct acpi_ec *ec)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									ec->curr->irq_count = ec->curr->wi = ec->curr->ri = 0;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									ec->curr->flags = 0;
							 | 
						
					
						
							
								
									
										
										
										
											2015-02-05 16:27:29 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									ec->curr->timestamp = jiffies;
							 | 
						
					
						
							
								
									
										
										
										
											2015-01-14 19:28:22 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									advance_transaction(ec);
							 | 
						
					
						
							
								
									
										
										
										
											2008-03-21 17:07:03 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							
								
									
										
										
										
											2008-01-23 22:28:34 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-09-25 21:00:31 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								static int ec_poll(struct acpi_ec *ec)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-30 03:06:14 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									unsigned long flags;
							 | 
						
					
						
							
								
									
										
										
										
											2013-05-06 03:23:40 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									int repeat = 5; /* number of command restarts */
							 | 
						
					
						
							
								
									
										
										
										
											2014-10-14 14:24:01 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-30 03:06:14 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									while (repeat--) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										unsigned long delay = jiffies +
							 | 
						
					
						
							
								
									
										
										
										
											2010-10-21 18:24:57 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
											msecs_to_jiffies(ec_delay);
							 | 
						
					
						
							
								
									
										
										
										
											2015-02-05 16:27:29 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										unsigned long usecs = ACPI_EC_UDELAY_POLL;
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-30 03:06:14 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										do {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
											/* don't sleep with disabled interrupts */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
											if (EC_FLAGS_MSI || irqs_disabled()) {
							 | 
						
					
						
							
								
									
										
										
										
											2015-02-05 16:27:29 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
												usecs = ACPI_EC_MSI_UDELAY;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
												udelay(usecs);
							 | 
						
					
						
							
								
									
										
										
										
											2014-06-15 08:41:35 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
												if (ec_transaction_completed(ec))
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-30 03:06:14 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
													return 0;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
											} else {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
												if (wait_event_timeout(ec->wait,
							 | 
						
					
						
							
								
									
										
										
										
											2014-06-15 08:41:35 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
														ec_transaction_completed(ec),
							 | 
						
					
						
							
								
									
										
										
										
											2015-02-05 16:27:29 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
														usecs_to_jiffies(usecs)))
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-30 03:06:14 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
													return 0;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
											}
							 | 
						
					
						
							
								
									
										
										
										
											2014-06-15 08:41:35 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
											spin_lock_irqsave(&ec->lock, flags);
							 | 
						
					
						
							
								
									
										
										
										
											2015-02-05 16:27:29 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
											if (time_after(jiffies,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
													ec->curr->timestamp +
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
													usecs_to_jiffies(usecs)))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
												advance_transaction(ec);
							 | 
						
					
						
							
								
									
										
										
										
											2014-06-15 08:41:35 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
											spin_unlock_irqrestore(&ec->lock, flags);
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-30 03:06:14 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										} while (time_before(jiffies, delay));
							 | 
						
					
						
							
								
									
										
										
										
											2013-09-12 03:32:04 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										pr_debug("controller reset, restart transaction\n");
							 | 
						
					
						
							
								
									
										
										
										
											2012-10-23 01:29:27 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										spin_lock_irqsave(&ec->lock, flags);
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-30 03:06:14 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										start_transaction(ec);
							 | 
						
					
						
							
								
									
										
										
										
											2012-10-23 01:29:27 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										spin_unlock_irqrestore(&ec->lock, flags);
							 | 
						
					
						
							
								
									
										
										
										
											2006-12-07 18:42:16 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									}
							 | 
						
					
						
							
								
									
										
										
										
											2008-03-21 17:07:15 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									return -ETIME;
							 | 
						
					
						
							
								
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-09-26 00:54:28 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								static int acpi_ec_transaction_unlocked(struct acpi_ec *ec,
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-30 03:06:14 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
													struct transaction *t)
							 | 
						
					
						
							
								
									
										
										
										
											2005-07-23 04:08:00 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							
								
									
										
										
										
											2008-09-25 21:00:31 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									unsigned long tmp;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									int ret = 0;
							 | 
						
					
						
							
								
									
										
										
										
											2014-10-14 14:24:01 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-02-21 12:18:13 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									if (EC_FLAGS_MSI)
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-30 03:06:14 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										udelay(ACPI_EC_MSI_UDELAY);
							 | 
						
					
						
							
								
									
										
										
										
											2008-09-25 21:00:31 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									/* start transaction */
							 | 
						
					
						
							
								
									
										
										
										
											2012-10-23 01:29:27 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									spin_lock_irqsave(&ec->lock, tmp);
							 | 
						
					
						
							
								
									
										
										
										
											2015-02-06 08:57:59 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									/* Enable GPE for command processing (IBF=0/OBF=1) */
							 | 
						
					
						
							
								
									
										
										
										
											2015-02-11 17:35:05 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									if (!acpi_ec_submit_flushable_request(ec)) {
							 | 
						
					
						
							
								
									
										
										
										
											2015-02-06 08:57:52 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										ret = -EINVAL;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										goto unlock;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									}
							 | 
						
					
						
							
								
									
										
										
										
											2008-09-25 21:00:31 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									/* following two actions should be kept atomic */
							 | 
						
					
						
							
								
									
										
										
										
											2008-09-26 00:54:28 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									ec->curr = t;
							 | 
						
					
						
							
								
									
										
										
										
											2014-10-14 14:23:49 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									pr_debug("***** Command(%s) started *****\n",
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										 acpi_ec_cmd_string(t->command));
							 | 
						
					
						
							
								
									
										
										
										
											2008-11-12 01:40:19 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									start_transaction(ec);
							 | 
						
					
						
							
								
									
										
										
										
											2014-10-29 11:33:43 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									spin_unlock_irqrestore(&ec->lock, tmp);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									ret = ec_poll(ec);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									spin_lock_irqsave(&ec->lock, tmp);
							 | 
						
					
						
							
								
									
										
										
										
											2015-02-06 08:58:05 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									if (t->irq_count == ec_storm_threshold)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										acpi_ec_clear_storm(ec, EC_FLAGS_COMMAND_STORM);
							 | 
						
					
						
							
								
									
										
										
										
											2014-10-14 14:23:49 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									pr_debug("***** Command(%s) stopped *****\n",
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										 acpi_ec_cmd_string(t->command));
							 | 
						
					
						
							
								
									
										
										
										
											2008-09-26 00:54:28 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									ec->curr = NULL;
							 | 
						
					
						
							
								
									
										
										
										
											2015-02-06 08:57:59 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									/* Disable GPE for command processing (IBF=0/OBF=1) */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									acpi_ec_complete_request(ec);
							 | 
						
					
						
							
								
									
										
										
										
											2015-02-06 08:57:52 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								unlock:
							 | 
						
					
						
							
								
									
										
										
										
											2012-10-23 01:29:27 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									spin_unlock_irqrestore(&ec->lock, tmp);
							 | 
						
					
						
							
								
									
										
										
										
											2008-09-25 21:00:31 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									return ret;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-30 03:06:14 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t)
							 | 
						
					
						
							
								
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							
								
									
										
										
										
											2006-09-05 12:12:24 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									int status;
							 | 
						
					
						
							
								
									
										
										
										
											2005-08-11 17:32:05 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									u32 glk;
							 | 
						
					
						
							
								
									
										
										
										
											2014-10-14 14:24:01 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-09-26 00:54:28 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									if (!ec || (!t) || (t->wlen && !t->wdata) || (t->rlen && !t->rdata))
							 | 
						
					
						
							
								
									
										
										
										
											2006-06-27 00:41:40 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										return -EINVAL;
							 | 
						
					
						
							
								
									
										
										
										
											2008-09-26 00:54:28 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									if (t->rdata)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										memset(t->rdata, 0, t->rlen);
							 | 
						
					
						
							
								
									
										
										
										
											2012-10-23 01:29:27 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									mutex_lock(&ec->mutex);
							 | 
						
					
						
							
								
									
										
										
										
											2006-09-26 19:50:33 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									if (ec->global_lock) {
							 | 
						
					
						
							
								
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
										status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
							 | 
						
					
						
							
								
									
										
										
										
											2007-02-15 23:16:18 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										if (ACPI_FAILURE(status)) {
							 | 
						
					
						
							
								
									
										
										
										
											2008-09-25 21:00:31 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
											status = -ENODEV;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
											goto unlock;
							 | 
						
					
						
							
								
									
										
										
										
											2007-02-15 23:16:18 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										}
							 | 
						
					
						
							
								
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
									}
							 | 
						
					
						
							
								
									
										
										
										
											2009-12-24 11:34:16 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-30 03:06:14 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									status = acpi_ec_transaction_unlocked(ec, t);
							 | 
						
					
						
							
								
									
										
										
										
											2009-12-24 11:34:16 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2015-02-06 08:58:05 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									if (test_bit(EC_FLAGS_COMMAND_STORM, &ec->flags))
							 | 
						
					
						
							
								
									
										
										
										
											2009-12-30 15:53:10 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										msleep(1);
							 | 
						
					
						
							
								
									
										
										
										
											2006-09-26 19:50:33 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									if (ec->global_lock)
							 | 
						
					
						
							
								
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
										acpi_release_global_lock(glk);
							 | 
						
					
						
							
								
									
										
										
										
											2008-09-25 21:00:31 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								unlock:
							 | 
						
					
						
							
								
									
										
										
										
											2012-10-23 01:29:27 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									mutex_unlock(&ec->mutex);
							 | 
						
					
						
							
								
									
										
										
										
											2006-06-27 00:41:40 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									return status;
							 | 
						
					
						
							
								
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-12-09 20:45:30 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								static int acpi_ec_burst_enable(struct acpi_ec *ec)
							 | 
						
					
						
							
								
									
										
										
										
											2007-03-07 22:28:00 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									u8 d;
							 | 
						
					
						
							
								
									
										
										
										
											2008-09-26 00:54:28 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									struct transaction t = {.command = ACPI_EC_BURST_ENABLE,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
												.wdata = NULL, .rdata = &d,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
												.wlen = 0, .rlen = 1};
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-30 03:06:14 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									return acpi_ec_transaction(ec, &t);
							 | 
						
					
						
							
								
									
										
										
										
											2007-03-07 22:28:00 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-12-09 20:45:30 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								static int acpi_ec_burst_disable(struct acpi_ec *ec)
							 | 
						
					
						
							
								
									
										
										
										
											2007-03-07 22:28:00 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							
								
									
										
										
										
											2008-09-26 00:54:28 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									struct transaction t = {.command = ACPI_EC_BURST_DISABLE,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
												.wdata = NULL, .rdata = NULL,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
												.wlen = 0, .rlen = 0};
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-09-25 21:00:31 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									return (acpi_ec_read_status(ec) & ACPI_EC_FLAG_BURST) ?
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-30 03:06:14 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
												acpi_ec_transaction(ec, &t) : 0;
							 | 
						
					
						
							
								
									
										
										
										
											2007-03-07 22:28:00 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2014-10-14 14:24:01 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 *data)
							 | 
						
					
						
							
								
									
										
										
										
											2006-09-26 19:50:33 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									int result;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									u8 d;
							 | 
						
					
						
							
								
									
										
										
										
											2008-09-26 00:54:28 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									struct transaction t = {.command = ACPI_EC_COMMAND_READ,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
												.wdata = &address, .rdata = &d,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
												.wlen = 1, .rlen = 1};
							 | 
						
					
						
							
								
									
										
										
										
											2006-09-26 19:50:33 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-30 03:06:14 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									result = acpi_ec_transaction(ec, &t);
							 | 
						
					
						
							
								
									
										
										
										
											2006-09-26 19:50:33 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									*data = d;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									return result;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							
								
									
										
										
										
											2006-09-26 19:50:33 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2006-09-26 19:50:33 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								static int acpi_ec_write(struct acpi_ec *ec, u8 address, u8 data)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							
								
									
										
										
										
											2006-12-07 18:42:17 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									u8 wdata[2] = { address, data };
							 | 
						
					
						
							
								
									
										
										
										
											2008-09-26 00:54:28 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									struct transaction t = {.command = ACPI_EC_COMMAND_WRITE,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
												.wdata = wdata, .rdata = NULL,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
												.wlen = 2, .rlen = 0};
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-30 03:06:14 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									return acpi_ec_transaction(ec, &t);
							 | 
						
					
						
							
								
									
										
										
										
											2006-09-26 19:50:33 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2012-10-23 01:29:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								int ec_read(u8 addr, u8 *val)
							 | 
						
					
						
							
								
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									int err;
							 | 
						
					
						
							
								
									
										
										
										
											2006-09-26 19:50:33 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									u8 temp_data;
							 | 
						
					
						
							
								
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									if (!first_ec)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										return -ENODEV;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2007-03-07 22:28:00 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									err = acpi_ec_read(first_ec, addr, &temp_data);
							 | 
						
					
						
							
								
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									if (!err) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										*val = temp_data;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										return 0;
							 | 
						
					
						
							
								
									
										
										
										
											2014-10-14 14:24:01 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									return err;
							 | 
						
					
						
							
								
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								EXPORT_SYMBOL(ec_read);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2005-08-11 17:32:05 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								int ec_write(u8 addr, u8 val)
							 | 
						
					
						
							
								
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									int err;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									if (!first_ec)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										return -ENODEV;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2007-03-07 22:28:00 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									err = acpi_ec_write(first_ec, addr, val);
							 | 
						
					
						
							
								
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									return err;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								EXPORT_SYMBOL(ec_write);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-27 01:47:34 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								int ec_transaction(u8 command,
							 | 
						
					
						
							
								
									
										
										
										
											2014-10-14 14:24:01 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										   const u8 *wdata, unsigned wdata_len,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										   u8 *rdata, unsigned rdata_len)
							 | 
						
					
						
							
								
									
										
										
										
											2005-07-23 04:08:00 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							
								
									
										
										
										
											2008-09-26 00:54:28 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									struct transaction t = {.command = command,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
												.wdata = wdata, .rdata = rdata,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
												.wlen = wdata_len, .rlen = rdata_len};
							 | 
						
					
						
							
								
									
										
										
										
											2014-10-14 14:24:01 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2006-09-05 12:12:24 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									if (!first_ec)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										return -ENODEV;
							 | 
						
					
						
							
								
									
										
										
										
											2005-07-23 04:08:00 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-30 03:06:14 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									return acpi_ec_transaction(first_ec, &t);
							 | 
						
					
						
							
								
									
										
										
										
											2005-07-23 04:08:00 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-03 22:49:00 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								EXPORT_SYMBOL(ec_transaction);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2012-01-18 13:44:08 -06:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/* Get the handle to the EC device */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								acpi_handle ec_get_handle(void)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									if (!first_ec)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										return NULL;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									return first_ec->handle;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								EXPORT_SYMBOL(ec_get_handle);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												ACPI / EC: Clear stale EC events on Samsung systems
A number of Samsung notebooks (530Uxx/535Uxx/540Uxx/550Pxx/900Xxx/etc)
continue to log events during sleep (lid open/close, AC plug/unplug,
battery level change), which accumulate in the EC until a buffer fills.
After the buffer is full (tests suggest it holds 8 events), GPEs stop
being triggered for new events. This state persists on wake or even on
power cycle, and prevents new events from being registered until the EC
is manually polled.
This is the root cause of a number of bugs, including AC not being
detected properly, lid close not triggering suspend, and low ambient
light not triggering the keyboard backlight. The bug also seemed to be
responsible for performance issues on at least one user's machine.
Juan Manuel Cabo found the cause of bug and the workaround of polling
the EC manually on wake.
The loop which clears the stale events is based on an earlier patch by
Lan Tianyu (see referenced attachment).
This patch:
 - Adds a function acpi_ec_clear() which polls the EC for stale _Q
   events at most ACPI_EC_CLEAR_MAX (currently 100) times. A warning is
   logged if this limit is reached.
 - Adds a flag EC_FLAGS_CLEAR_ON_RESUME which is set to 1 if the DMI
   system vendor is Samsung. This check could be replaced by several
   more specific DMI vendor/product pairs, but it's likely that the bug
   affects more Samsung products than just the five series mentioned
   above. Further, it should not be harmful to run acpi_ec_clear() on
   systems without the bug; it will return immediately after finding no
   data waiting.
 - Runs acpi_ec_clear() on initialisation (boot), from acpi_ec_add()
 - Runs acpi_ec_clear() on wake, from acpi_ec_unblock_transactions()
References: https://bugzilla.kernel.org/show_bug.cgi?id=44161
References: https://bugzilla.kernel.org/show_bug.cgi?id=45461
References: https://bugzilla.kernel.org/show_bug.cgi?id=57271
References: https://bugzilla.kernel.org/attachment.cgi?id=126801
Suggested-by: Juan Manuel Cabo <juanmanuel.cabo@gmail.com>
Signed-off-by: Kieran Clancy <clancy.kieran@gmail.com>
Reviewed-by: Lan Tianyu <tianyu.lan@intel.com>
Reviewed-by: Dennis Jansen <dennis.jansen@web.de>
Tested-by: Kieran Clancy <clancy.kieran@gmail.com>
Tested-by: Juan Manuel Cabo <juanmanuel.cabo@gmail.com>
Tested-by: Dennis Jansen <dennis.jansen@web.de>
Tested-by: Maurizio D'Addona <mauritiusdadd@gmail.com>
Tested-by: San Zamoyski <san@plusnet.pl>
Cc: All applicable <stable@vger.kernel.org>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
											
										 
										
											2014-03-01 00:42:28 +10:30
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/*
							 | 
						
					
						
							
								
									
										
										
										
											2014-04-30 00:21:20 +09:30
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								 * Process _Q events that might have accumulated in the EC.
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												ACPI / EC: Clear stale EC events on Samsung systems
A number of Samsung notebooks (530Uxx/535Uxx/540Uxx/550Pxx/900Xxx/etc)
continue to log events during sleep (lid open/close, AC plug/unplug,
battery level change), which accumulate in the EC until a buffer fills.
After the buffer is full (tests suggest it holds 8 events), GPEs stop
being triggered for new events. This state persists on wake or even on
power cycle, and prevents new events from being registered until the EC
is manually polled.
This is the root cause of a number of bugs, including AC not being
detected properly, lid close not triggering suspend, and low ambient
light not triggering the keyboard backlight. The bug also seemed to be
responsible for performance issues on at least one user's machine.
Juan Manuel Cabo found the cause of bug and the workaround of polling
the EC manually on wake.
The loop which clears the stale events is based on an earlier patch by
Lan Tianyu (see referenced attachment).
This patch:
 - Adds a function acpi_ec_clear() which polls the EC for stale _Q
   events at most ACPI_EC_CLEAR_MAX (currently 100) times. A warning is
   logged if this limit is reached.
 - Adds a flag EC_FLAGS_CLEAR_ON_RESUME which is set to 1 if the DMI
   system vendor is Samsung. This check could be replaced by several
   more specific DMI vendor/product pairs, but it's likely that the bug
   affects more Samsung products than just the five series mentioned
   above. Further, it should not be harmful to run acpi_ec_clear() on
   systems without the bug; it will return immediately after finding no
   data waiting.
 - Runs acpi_ec_clear() on initialisation (boot), from acpi_ec_add()
 - Runs acpi_ec_clear() on wake, from acpi_ec_unblock_transactions()
References: https://bugzilla.kernel.org/show_bug.cgi?id=44161
References: https://bugzilla.kernel.org/show_bug.cgi?id=45461
References: https://bugzilla.kernel.org/show_bug.cgi?id=57271
References: https://bugzilla.kernel.org/attachment.cgi?id=126801
Suggested-by: Juan Manuel Cabo <juanmanuel.cabo@gmail.com>
Signed-off-by: Kieran Clancy <clancy.kieran@gmail.com>
Reviewed-by: Lan Tianyu <tianyu.lan@intel.com>
Reviewed-by: Dennis Jansen <dennis.jansen@web.de>
Tested-by: Kieran Clancy <clancy.kieran@gmail.com>
Tested-by: Juan Manuel Cabo <juanmanuel.cabo@gmail.com>
Tested-by: Dennis Jansen <dennis.jansen@web.de>
Tested-by: Maurizio D'Addona <mauritiusdadd@gmail.com>
Tested-by: San Zamoyski <san@plusnet.pl>
Cc: All applicable <stable@vger.kernel.org>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
											
										 
										
											2014-03-01 00:42:28 +10:30
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								 * 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++) {
							 | 
						
					
						
							
								
									
										
										
										
											2015-01-14 19:28:53 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										status = acpi_ec_query(ec, &value);
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												ACPI / EC: Clear stale EC events on Samsung systems
A number of Samsung notebooks (530Uxx/535Uxx/540Uxx/550Pxx/900Xxx/etc)
continue to log events during sleep (lid open/close, AC plug/unplug,
battery level change), which accumulate in the EC until a buffer fills.
After the buffer is full (tests suggest it holds 8 events), GPEs stop
being triggered for new events. This state persists on wake or even on
power cycle, and prevents new events from being registered until the EC
is manually polled.
This is the root cause of a number of bugs, including AC not being
detected properly, lid close not triggering suspend, and low ambient
light not triggering the keyboard backlight. The bug also seemed to be
responsible for performance issues on at least one user's machine.
Juan Manuel Cabo found the cause of bug and the workaround of polling
the EC manually on wake.
The loop which clears the stale events is based on an earlier patch by
Lan Tianyu (see referenced attachment).
This patch:
 - Adds a function acpi_ec_clear() which polls the EC for stale _Q
   events at most ACPI_EC_CLEAR_MAX (currently 100) times. A warning is
   logged if this limit is reached.
 - Adds a flag EC_FLAGS_CLEAR_ON_RESUME which is set to 1 if the DMI
   system vendor is Samsung. This check could be replaced by several
   more specific DMI vendor/product pairs, but it's likely that the bug
   affects more Samsung products than just the five series mentioned
   above. Further, it should not be harmful to run acpi_ec_clear() on
   systems without the bug; it will return immediately after finding no
   data waiting.
 - Runs acpi_ec_clear() on initialisation (boot), from acpi_ec_add()
 - Runs acpi_ec_clear() on wake, from acpi_ec_unblock_transactions()
References: https://bugzilla.kernel.org/show_bug.cgi?id=44161
References: https://bugzilla.kernel.org/show_bug.cgi?id=45461
References: https://bugzilla.kernel.org/show_bug.cgi?id=57271
References: https://bugzilla.kernel.org/attachment.cgi?id=126801
Suggested-by: Juan Manuel Cabo <juanmanuel.cabo@gmail.com>
Signed-off-by: Kieran Clancy <clancy.kieran@gmail.com>
Reviewed-by: Lan Tianyu <tianyu.lan@intel.com>
Reviewed-by: Dennis Jansen <dennis.jansen@web.de>
Tested-by: Kieran Clancy <clancy.kieran@gmail.com>
Tested-by: Juan Manuel Cabo <juanmanuel.cabo@gmail.com>
Tested-by: Dennis Jansen <dennis.jansen@web.de>
Tested-by: Maurizio D'Addona <mauritiusdadd@gmail.com>
Tested-by: San Zamoyski <san@plusnet.pl>
Cc: All applicable <stable@vger.kernel.org>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
											
										 
										
											2014-03-01 00:42:28 +10:30
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										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);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2015-02-06 08:57:52 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								static void acpi_ec_start(struct acpi_ec *ec, bool resuming)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									unsigned long flags;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									spin_lock_irqsave(&ec->lock, flags);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									if (!test_and_set_bit(EC_FLAGS_STARTED, &ec->flags)) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										pr_debug("+++++ Starting EC +++++\n");
							 | 
						
					
						
							
								
									
										
										
										
											2015-02-06 08:57:59 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										/* Enable GPE for event processing (SCI_EVT=1) */
							 | 
						
					
						
							
								
									
										
										
										
											2015-02-11 17:33:23 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										if (!resuming)
							 | 
						
					
						
							
								
									
										
										
										
											2015-02-06 08:57:59 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
											acpi_ec_submit_request(ec);
							 | 
						
					
						
							
								
									
										
										
										
											2015-02-06 08:57:52 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										pr_info("+++++ EC started +++++\n");
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									spin_unlock_irqrestore(&ec->lock, flags);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2015-02-06 08:57:59 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								static bool acpi_ec_stopped(struct acpi_ec *ec)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									unsigned long flags;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									bool flushed;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									spin_lock_irqsave(&ec->lock, flags);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									flushed = acpi_ec_flushed(ec);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									spin_unlock_irqrestore(&ec->lock, flags);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									return flushed;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2015-02-06 08:57:52 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								static void acpi_ec_stop(struct acpi_ec *ec, bool suspending)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									unsigned long flags;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									spin_lock_irqsave(&ec->lock, flags);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									if (acpi_ec_started(ec)) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										pr_debug("+++++ Stopping EC +++++\n");
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										set_bit(EC_FLAGS_STOPPED, &ec->flags);
							 | 
						
					
						
							
								
									
										
										
										
											2015-02-06 08:57:59 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										spin_unlock_irqrestore(&ec->lock, flags);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										wait_event(ec->wait, acpi_ec_stopped(ec));
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										spin_lock_irqsave(&ec->lock, flags);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										/* Disable GPE for event processing (SCI_EVT=1) */
							 | 
						
					
						
							
								
									
										
										
										
											2015-02-11 17:33:23 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										if (!suspending)
							 | 
						
					
						
							
								
									
										
										
										
											2015-02-06 08:57:59 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
											acpi_ec_complete_request(ec);
							 | 
						
					
						
							
								
									
										
										
										
											2015-02-06 08:57:52 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										clear_bit(EC_FLAGS_STARTED, &ec->flags);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										clear_bit(EC_FLAGS_STOPPED, &ec->flags);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										pr_info("+++++ EC stopped +++++\n");
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									spin_unlock_irqrestore(&ec->lock, flags);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2010-04-09 01:40:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								void acpi_ec_block_transactions(void)
							 | 
						
					
						
							
								
									
										
										
										
											2010-03-04 01:52:58 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									struct acpi_ec *ec = first_ec;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									if (!ec)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										return;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2012-10-23 01:29:27 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									mutex_lock(&ec->mutex);
							 | 
						
					
						
							
								
									
										
										
										
											2010-03-04 01:52:58 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									/* Prevent transactions from being carried out */
							 | 
						
					
						
							
								
									
										
										
										
											2015-02-06 08:57:52 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									acpi_ec_stop(ec, true);
							 | 
						
					
						
							
								
									
										
										
										
											2012-10-23 01:29:27 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									mutex_unlock(&ec->mutex);
							 | 
						
					
						
							
								
									
										
										
										
											2010-03-04 01:52:58 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2010-04-09 01:40:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								void acpi_ec_unblock_transactions(void)
							 | 
						
					
						
							
								
									
										
										
										
											2010-03-04 01:52:58 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									struct acpi_ec *ec = first_ec;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									if (!ec)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										return;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									/* Allow transactions to be carried out again */
							 | 
						
					
						
							
								
									
										
										
										
											2015-02-06 08:57:52 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									acpi_ec_start(ec, true);
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												ACPI / EC: Clear stale EC events on Samsung systems
A number of Samsung notebooks (530Uxx/535Uxx/540Uxx/550Pxx/900Xxx/etc)
continue to log events during sleep (lid open/close, AC plug/unplug,
battery level change), which accumulate in the EC until a buffer fills.
After the buffer is full (tests suggest it holds 8 events), GPEs stop
being triggered for new events. This state persists on wake or even on
power cycle, and prevents new events from being registered until the EC
is manually polled.
This is the root cause of a number of bugs, including AC not being
detected properly, lid close not triggering suspend, and low ambient
light not triggering the keyboard backlight. The bug also seemed to be
responsible for performance issues on at least one user's machine.
Juan Manuel Cabo found the cause of bug and the workaround of polling
the EC manually on wake.
The loop which clears the stale events is based on an earlier patch by
Lan Tianyu (see referenced attachment).
This patch:
 - Adds a function acpi_ec_clear() which polls the EC for stale _Q
   events at most ACPI_EC_CLEAR_MAX (currently 100) times. A warning is
   logged if this limit is reached.
 - Adds a flag EC_FLAGS_CLEAR_ON_RESUME which is set to 1 if the DMI
   system vendor is Samsung. This check could be replaced by several
   more specific DMI vendor/product pairs, but it's likely that the bug
   affects more Samsung products than just the five series mentioned
   above. Further, it should not be harmful to run acpi_ec_clear() on
   systems without the bug; it will return immediately after finding no
   data waiting.
 - Runs acpi_ec_clear() on initialisation (boot), from acpi_ec_add()
 - Runs acpi_ec_clear() on wake, from acpi_ec_unblock_transactions()
References: https://bugzilla.kernel.org/show_bug.cgi?id=44161
References: https://bugzilla.kernel.org/show_bug.cgi?id=45461
References: https://bugzilla.kernel.org/show_bug.cgi?id=57271
References: https://bugzilla.kernel.org/attachment.cgi?id=126801
Suggested-by: Juan Manuel Cabo <juanmanuel.cabo@gmail.com>
Signed-off-by: Kieran Clancy <clancy.kieran@gmail.com>
Reviewed-by: Lan Tianyu <tianyu.lan@intel.com>
Reviewed-by: Dennis Jansen <dennis.jansen@web.de>
Tested-by: Kieran Clancy <clancy.kieran@gmail.com>
Tested-by: Juan Manuel Cabo <juanmanuel.cabo@gmail.com>
Tested-by: Dennis Jansen <dennis.jansen@web.de>
Tested-by: Maurizio D'Addona <mauritiusdadd@gmail.com>
Tested-by: San Zamoyski <san@plusnet.pl>
Cc: All applicable <stable@vger.kernel.org>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
											
										 
										
											2014-03-01 00:42:28 +10:30
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									if (EC_FLAGS_CLEAR_ON_RESUME)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										acpi_ec_clear(ec);
							 | 
						
					
						
							
								
									
										
										
										
											2010-03-04 01:52:58 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2010-04-09 01:40:38 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								void acpi_ec_unblock_transactions_early(void)
							 | 
						
					
						
							
								
									
										
										
										
											2010-04-09 01:39:40 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									/*
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									 * Allow transactions to happen again (this function is called from
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									 * atomic context during wakeup, so we don't need to acquire the mutex).
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									 */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									if (first_ec)
							 | 
						
					
						
							
								
									
										
										
										
											2015-02-06 08:57:52 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										acpi_ec_start(first_ec, true);
							 | 
						
					
						
							
								
									
										
										
										
											2010-04-09 01:39:40 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								/* --------------------------------------------------------------------------
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                                Event Management
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								   -------------------------------------------------------------------------- */
							 | 
						
					
						
							
								
									
										
										
										
											2015-01-14 19:28:28 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								static struct acpi_ec_query_handler *
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								acpi_ec_get_query_handler(struct acpi_ec_query_handler *handler)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									if (handler)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										kref_get(&handler->kref);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									return handler;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								static void acpi_ec_query_handler_release(struct kref *kref)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									struct acpi_ec_query_handler *handler =
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										container_of(kref, struct acpi_ec_query_handler, kref);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									kfree(handler);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								static void acpi_ec_put_query_handler(struct acpi_ec_query_handler *handler)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									kref_put(&handler->kref, acpi_ec_query_handler_release);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2007-05-29 16:43:02 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
											      acpi_handle handle, acpi_ec_query_func func,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
											      void *data)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									struct acpi_ec_query_handler *handler =
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									    kzalloc(sizeof(struct acpi_ec_query_handler), GFP_KERNEL);
							 | 
						
					
						
							
								
									
										
										
										
											2014-10-14 14:24:01 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2007-05-29 16:43:02 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									if (!handler)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										return -ENOMEM;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									handler->query_bit = query_bit;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									handler->handle = handle;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									handler->func = func;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									handler->data = data;
							 | 
						
					
						
							
								
									
										
										
										
											2012-10-23 01:29:27 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									mutex_lock(&ec->mutex);
							 | 
						
					
						
							
								
									
										
										
										
											2015-01-14 19:28:28 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									kref_init(&handler->kref);
							 | 
						
					
						
							
								
									
										
										
										
											2007-09-26 19:43:22 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									list_add(&handler->node, &ec->list);
							 | 
						
					
						
							
								
									
										
										
										
											2012-10-23 01:29:27 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									mutex_unlock(&ec->mutex);
							 | 
						
					
						
							
								
									
										
										
										
											2007-05-29 16:43:02 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									return 0;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								EXPORT_SYMBOL_GPL(acpi_ec_add_query_handler);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-24 18:26:00 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									struct acpi_ec_query_handler *handler, *tmp;
							 | 
						
					
						
							
								
									
										
										
										
											2015-01-14 19:28:28 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									LIST_HEAD(free_list);
							 | 
						
					
						
							
								
									
										
										
										
											2014-10-14 14:24:01 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2012-10-23 01:29:27 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									mutex_lock(&ec->mutex);
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-24 18:26:00 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									list_for_each_entry_safe(handler, tmp, &ec->list, node) {
							 | 
						
					
						
							
								
									
										
										
										
											2007-05-29 16:43:02 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										if (query_bit == handler->query_bit) {
							 | 
						
					
						
							
								
									
										
										
										
											2015-01-14 19:28:28 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
											list_del_init(&handler->node);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
											list_add(&handler->node, &free_list);
							 | 
						
					
						
							
								
									
										
										
										
											2007-05-29 16:43:02 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									}
							 | 
						
					
						
							
								
									
										
										
										
											2012-10-23 01:29:27 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									mutex_unlock(&ec->mutex);
							 | 
						
					
						
							
								
									
										
										
										
											2015-01-14 19:28:28 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									list_for_each_entry(handler, &free_list, node)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										acpi_ec_put_query_handler(handler);
							 | 
						
					
						
							
								
									
										
										
										
											2007-05-29 16:43:02 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								EXPORT_SYMBOL_GPL(acpi_ec_remove_query_handler);
							 | 
						
					
						
							
								
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-12-24 11:34:16 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								static void acpi_ec_run(void *cxt)
							 | 
						
					
						
							
								
									
										
										
										
											2005-07-23 04:08:00 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							
								
									
										
										
										
											2009-12-24 11:34:16 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									struct acpi_ec_query_handler *handler = cxt;
							 | 
						
					
						
							
								
									
										
										
										
											2014-10-14 14:24:01 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-12-24 11:34:16 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									if (!handler)
							 | 
						
					
						
							
								
									
										
										
										
											2006-12-07 18:42:16 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										return;
							 | 
						
					
						
							
								
									
										
										
										
											2014-10-14 14:23:55 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									pr_debug("##### Query(0x%02x) started #####\n", handler->query_bit);
							 | 
						
					
						
							
								
									
										
										
										
											2009-12-24 11:34:16 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									if (handler->func)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										handler->func(handler->data);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									else if (handler->handle)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										acpi_evaluate_object(handler->handle, NULL, NULL, NULL);
							 | 
						
					
						
							
								
									
										
										
										
											2014-10-14 14:23:55 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									pr_debug("##### Query(0x%02x) stopped #####\n", handler->query_bit);
							 | 
						
					
						
							
								
									
										
										
										
											2015-01-14 19:28:28 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									acpi_ec_put_query_handler(handler);
							 | 
						
					
						
							
								
									
										
										
										
											2009-12-24 11:34:16 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2015-01-14 19:28:53 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								static int acpi_ec_query(struct acpi_ec *ec, u8 *data)
							 | 
						
					
						
							
								
									
										
										
										
											2009-12-24 11:34:16 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									u8 value = 0;
							 | 
						
					
						
							
								
									
										
										
										
											2015-01-14 19:28:33 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									int result;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									acpi_status status;
							 | 
						
					
						
							
								
									
										
										
										
											2015-01-14 19:28:28 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									struct acpi_ec_query_handler *handler;
							 | 
						
					
						
							
								
									
										
										
										
											2015-01-14 19:28:53 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									struct transaction t = {.command = ACPI_EC_COMMAND_QUERY,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
												.wdata = NULL, .rdata = &value,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
												.wlen = 0, .rlen = 1};
							 | 
						
					
						
							
								
									
										
										
										
											2014-04-30 00:21:20 +09:30
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2015-01-14 19:28:53 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									/*
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									 * Query the EC to find out which _Qxx method we need to evaluate.
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									 * Note that successful completion of the query causes the ACPI_EC_SCI
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									 * bit to be cleared (and thus clearing the interrupt source).
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									 */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									result = acpi_ec_transaction(ec, &t);
							 | 
						
					
						
							
								
									
										
										
										
											2015-01-14 19:28:33 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									if (result)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										return result;
							 | 
						
					
						
							
								
									
										
										
										
											2015-01-14 19:28:53 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									if (data)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										*data = value;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									if (!value)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										return -ENODATA;
							 | 
						
					
						
							
								
									
										
										
										
											2014-04-30 00:21:20 +09:30
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2015-01-14 19:28:53 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									mutex_lock(&ec->mutex);
							 | 
						
					
						
							
								
									
										
										
										
											2007-05-29 16:43:02 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									list_for_each_entry(handler, &ec->list, node) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										if (value == handler->query_bit) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
											/* have custom handler for this bit */
							 | 
						
					
						
							
								
									
										
										
										
											2015-01-14 19:28:28 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
											handler = acpi_ec_get_query_handler(handler);
							 | 
						
					
						
							
								
									
										
										
										
											2014-10-14 14:23:55 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
											pr_debug("##### Query(0x%02x) scheduled #####\n",
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
												 handler->query_bit);
							 | 
						
					
						
							
								
									
										
										
										
											2015-01-14 19:28:33 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
											status = acpi_os_execute((handler->func) ?
							 | 
						
					
						
							
								
									
										
										
										
											2009-12-30 15:53:03 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
												OSL_NOTIFY_HANDLER : OSL_GPE_HANDLER,
							 | 
						
					
						
							
								
									
										
										
										
											2015-01-14 19:28:28 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
												acpi_ec_run, handler);
							 | 
						
					
						
							
								
									
										
										
										
											2015-01-14 19:28:33 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
											if (ACPI_FAILURE(status))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
												result = -EBUSY;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
											break;
							 | 
						
					
						
							
								
									
										
										
										
											2007-05-29 16:43:02 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									}
							 | 
						
					
						
							
								
									
										
										
										
											2015-01-14 19:28:53 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									mutex_unlock(&ec->mutex);
							 | 
						
					
						
							
								
									
										
										
										
											2015-01-14 19:28:33 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									return result;
							 | 
						
					
						
							
								
									
										
										
										
											2009-12-24 11:34:16 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												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>
											
										 
										
											2015-01-14 19:28:47 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								static void acpi_ec_gpe_poller(struct work_struct *work)
							 | 
						
					
						
							
								
									
										
										
										
											2009-12-24 11:34:16 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												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>
											
										 
										
											2015-01-14 19:28:47 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									struct acpi_ec *ec = container_of(work, struct acpi_ec, work);
							 | 
						
					
						
							
								
									
										
										
										
											2014-10-14 14:24:01 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2015-01-14 19:28:53 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									acpi_ec_query(ec, NULL);
							 | 
						
					
						
							
								
									
										
										
										
											2005-07-23 04:08:00 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							
								
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2010-12-13 13:38:46 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								static u32 acpi_ec_gpe_handler(acpi_handle gpe_device,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									u32 gpe_number, void *data)
							 | 
						
					
						
							
								
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							
								
									
										
										
										
											2014-06-15 08:41:35 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									unsigned long flags;
							 | 
						
					
						
							
								
									
										
										
										
											2007-03-07 22:28:00 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									struct acpi_ec *ec = data;
							 | 
						
					
						
							
								
									
										
										
										
											2008-09-25 21:00:31 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2014-06-15 08:41:35 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									spin_lock_irqsave(&ec->lock, flags);
							 | 
						
					
						
							
								
									
										
										
										
											2015-01-14 19:28:22 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									advance_transaction(ec);
							 | 
						
					
						
							
								
									
										
										
										
											2014-06-15 08:42:07 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									spin_unlock_irqrestore(&ec->lock, flags);
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												ACPI / EC: Fix several GPE handling issues by deploying ACPI_GPE_DISPATCH_RAW_HANDLER mode.
This patch switches EC driver into ACPI_GPE_DISPATCH_RAW_HANDLER mode where
the GPE lock is not held for acpi_ec_gpe_handler() and the ACPICA internal
GPE enabling/disabling/clearing operations are bypassed so that further
improvements are possible with the GPE APIs.
There are 2 strong reasons for deploying raw GPE handler mode in the EC
driver:
1. Some hardware logics can control their interrupts via their own
   registers, so their interrupts can be disabled/enabled/acknowledged
   without using the super IRQ controller provided functions. While there
   is no mean (EC commands) for the EC driver to achieve this.
2. During suspending, the EC driver is still working for a while to
   complete the platform firmware provided functionailities using ec_poll()
   after all GPEs are disabled (see acpi_ec_block_transactions()), which
   means the EC driver will drive the EC GPE out of the GPE core's control.
Without deploying the raw GPE handler mode, we can see many races between
the EC driver and the GPE core due to the above restrictions:
1. There is a race condition due to ACPICA internal GPE
   disabling/clearing/enabling logics in acpi_ev_gpe_dispatch():
     Orignally EC GPE is disabled (EN=0), cleared (STS=0) before invoking a
     GPE handler and re-enabled (EN=1) after invoking a GPE handler in
     acpi_ev_gpe_dispatch(). When re-enabling appears, GPE may be flagged
     (STS=1).
       =================================================================
       (event pending A)
       =================================================================
       acpi_ev_gpe_dispatch()    ec_poll()
         EN=0
         STS=0
         acpi_ec_gpe_handler()
       *****************************************************************
       (event handling A)
           Lock(EC)
           advance_transaction()
             EC_SC read
       =================================================================
       (event pending B)
       =================================================================
             EC_SC handled
           Unlock(EC)
       *****************************************************************
       *****************************************************************
       (event handling B)
                                   Lock(EC)
                                   advance_transaction()
                                     EC_SC read
       =================================================================
       (event pending C)
       =================================================================
                                     EC_SC handled
                                   Unlock(EC)
       *****************************************************************
           EN=1
   This race condition is the root cause of different issues on different
   silicon variations.
   A. Silicon variation A:
      On some platforms, GPE will be triggered due to "writing 1 to EN when
      STS=1". This is because both EN and STS lines are wired to the GPE
      trigger line.
      1. Issue 1:
         We can see no-op acpi_ec_gpe_handler() invoked on such platforms.
         This is because:
         a. event pending B: An event can arrive after ACPICA's GPE
            clearing performed in acpi_ev_gpe_dispatch(), this event may
            fail to be detected by EC_SC read that is performed before its
            arrival;
         b. event handling B: The event can be handled in ec_poll() because
            EC lock is released after acpi_ec_gpe_handler() invocation;
         c. There is no code in ec_poll() to clear STS but the GPE can
            still be triggered by the EN=1 write performed in
            acpi_ev_finish_gpe(), this leads to a no-op EC GPE handler
            invocation;
         d. As no-op GPE handler invocations are counted by the EC driver
            to trigger the command storming conditions, the wrong no-op
            GPE handler invocations thus can easily trigger wrong command
            storming conditions.
         Note 1:
         If we removed GPE disabling/enabling code from
         acpi_ev_gpe_dispatch(), we could still see no-op GPE handlers
         triggered by the event arriving after the GPE clearing and before
         the GPE handling on both silicon variation A and B. This can only
         occur if the CPU is very slow (timing slice between STS=0 write
         and EC_SC read should be short enough before hardware sets another
         GPE indication). Thus this is very rare and is not what we need to
         fix.
   B. Silicon variation B:
      On other platforms, GPE may not be triggered due to "writing 1 to EN
      when STS=1". This is because only STS line is wired to the GPE
      trigger line.
      2. Issue 2:
         We can see GPE loss on such platforms. This is because:
         a. event pending B vs. event handling A: An event can arrive after
            ACPICA's GPE handling performed in acpi_ev_gpe_dispatch(), or
            event pending C vs. event handling B: An event can arrive after
            Linux's GPE handling performed in ec_poll(),
            these events may fail to be detected by EC_SC read that is
            performed before their arrival;
         b. The GPE cannot be triggered by EN=1 write performed in
            acpi_ev_finish_gpe();
         c. If no polling mechanism is implemented in the driver for the
            pending event (for example, SCI_EVT), this event is lost due to
            no GPE being triggered.
         Note 2:
         On most platforms, there might be another rule that GPE may not be
         triggered due to "writing 1 to STS when STS=1 and EN=1".
         Then on silicon variation B, an even worse case is if the issue 2
         event loss happens, further events may never trigger GPE again on
         such platforms due to being blocked by the current STS=1. Unless
         someone clears STS, all events have to be polled.
2. There is a race condition due to lacking in GPE status checking in EC
   driver:
     Originally, GPE status is checked in ACPICA core but not checked in
     the GPE handler. Thus since the status checking and handling is not
     locked, it can be interrupted by another handling path.
       =================================================================
       (event pending A)
       =================================================================
       acpi_ev_gpe_detect()        ec_poll()
         if (EN==1 && STS==1)
       *****************************************************************
       (event handling A)
                                     Lock(EC)
                                     advance_transaction()
                                       EC_SC read
                                       EC_SC handled
                                     Unlock(EC)
       *****************************************************************
         acpi_ev_gpe_dispatch()
           EN=0
           STS=0
           acpi_ec_gpe_handler()
       *****************************************************************
       (event handling B)
             Lock(EC)
             advance_transaction()
               EC_SC read
             Unlock(EC)
       *****************************************************************
      3. Issue 3:
         We can see no-op acpi_ec_gpe_handler() invoked on both silicon
         variation A and B. This is because:
         a. event pending A: An event can arrive to trigger an EC GPE and
            ACPICA checks it and is about to invoke the EC GPE handler;
         b. event handling A: The event can be handled in ec_poll() because
            EC lock is not held after the GPE status checking;
         c. event handling B: Then when the EC GPE handler is invoked, it
            becomes a no-op GPE handler invocation.
         d. As no-op GPE handler invocations are counted by the EC driver
            to trigger the command storming conditions, the wrong no-op
            GPE handler invocations thus can easily trigger wrong command
            storming conditions.
      Note 3:
      This no-op GPE handler invocation is rare because the time between
      the IRQ arrival and the acpi_ec_gpe_handler() invocation is less than
      the timeout value waited in ec_poll(). So most of the no-op GPE
      handler invocations are caused by the reason described in issue 1.
3. There is a race condition due to ACPICA internal GPE clearing logic in
   acpi_enable_gpe():
     During runtime, acpi_enable_gpe() can be invoked by the EC storming
     prevention code. When it is invoked, GPE may be flagged (STS=1).
       =================================================================
       (event pending A)
       =================================================================
       acpi_ev_gpe_dispatch()    acpi_ec_transaction()
         EN=0
         STS=0
         acpi_ec_gpe_handler()
       *****************************************************************
       (event handling A)
           Lock(EC)
           advance_transaction()
             EC_SC read
             EC_SC handled
           Unlock(EC)
       *****************************************************************
         EN=1 ?
                                   Lock(EC)
                                   Unlock(EC)
       =================================================================
       (event pending B)
       =================================================================
                                   acpi_enable_gpe()
                                     STS=0
                                     EN=1
    4. Issue 4:
       We can see GPE loss on both silicon variation A and B platforms.
       This is because:
       a. event pending B: An event can arrive right before ACPICA's GPE
          clearing performed in acpi_enable_gpe();
       b. If the GPE is cleared when GPE is disabled, then EN=1 write in
          acpi_enable_gpe() cannot trigger this GPE;
       c. If no polling mechanism is implemented in the driver for this
          event (for example, SCI_EVT), this event is lost due to no GPE
          being triggered.
       Note 4:
       Currently we don't have this issue, but after we switch the EC
       driver into ACPI_GPE_DISPATCH_RAW_HANDLER mode, we need to take care
       of handling this because the EN=1 write in acpi_ev_gpe_dispatch()
       will be abandoned.
There might be more race issues for the current GPE handler usages. This is
because the EC IRQ's enabling/disabling/checking/clearing/handling
operations should be locked by a single lock that is under the EC driver's
control to achieve the serialization. Which means we need to invoke GPE
APIs with EC driver's lock held and all ACPICA internal GPE operations
related to the GPE handler should be abandoned. Invoking GPE APIs inside of
the EC driver lock and bypassing ACPICA internal GPE operations requires
the ACPI_GPE_DISPATCH_RAW_HANDLER mode where the same lock used by the APIs
are released prior than invoking the handlers. Otherwise, we can see dead
locks due to circular locking dependencies (see Reference below).
This patch then switches the EC driver into the
ACPI_GPE_DISPATCH_RAW_HANDLER mode so that it can perform correct GPE
operations using the GPE APIs:
1. Bypasses EN modifications performed in acpi_ev_gpe_dispatch() by
   using acpi_install_gpe_raw_handler() and invoking all GPE APIs with EC
   spin lock held. This can fix issue 1 as it makes a non frequent GPE
   enabling/disabling environment.
2. Bypasses STS clearing performed in acpi_enable_gpe() by replacing
   acpi_enable_gpe()/acpi_disable_gpe() with acpi_set_gpe(). This can fix
   issue 4. And this can also help to fix issue 1 as it makes a no sudden
   GPE clearing environment when GPE is frequently enabled/disabled.
3. Ensures STS acknowledged before handling by invoking acpi_clear_gpe()
   in advance_transaction(). This can finally fix issue 1 even in a
   frequent GPE enabling/disabling environment. And this can also finally
   fix issue 3 when issue 2 is fixed.
   Note 3:
   GPE clearing is edge triggered W1C, which means we can clear it right
   before handling it. Since all EC GPE indications are handled in
   advance_transaction() by previous commits, we can now move GPE clearing
   into it to implement the correct GPE clearing.
   Note 4:
   We can use acpi_set_gpe() which is not shared GPE safer instead of
   acpi_enable_gpe()/acpi_disable_gpe() because EC GPE is not shared by
   other hardware, which is mentioned in the ACPI specification 5.0, 12.6
   Interrupt Model: "OSPM driver treats this as an edge event (the EC SCI
   cannot be shared)". So we can stop using shared GPE safer APIs
   acpi_enable_gpe()/acpi_disable_gpe() in the EC driver. Otherwise
   cleanups need to be made in acpi_ev_enable_gpe() to bypass the GPE
   clearing logic before keeping acpi_enable_gpe().
This patch also invokes advance_transaction() when GPE is re-enabled in the
task context which:
1. Ensures EN=1 can trigger GPE by checking and handling EC status register
   right after EN=1 writes. This can fix issue 2.
After applying this patch, without frequent GPE enablings considered:
       =================================================================
       (event pending A)
       =================================================================
       acpi_ec_gpe_handler()     ec_poll()
       *****************************************************************
       (event handling A)
         Lock(EC)
           advance_transaction()
             if STS==1
               STS=0
             EC_SC read
       =================================================================
       (event pending B)
       =================================================================
             EC_SC handled
         Unlock(EC)
       *****************************************************************
       *****************************************************************
       (event handling B)
                                   Lock(EC)
                                     advance_transaction()
                                       if STS==1
                                         STS=0
                                       EC_SC read
       =================================================================
       (event pending C)
       =================================================================
                                       EC_SC handled
                                   Unlock(EC)
       *****************************************************************
The event pending for issue 1 (event pending B) can arrive as a next GPE
due to the previous IRQ context STS=0 write. And if it is handled by
ec_poll() (event handling B), as it is also acknowledged by ec_poll(), the
event pending for issue 2 (event pending C) can properly arrive as a next
GPE after the task context STS=0 write. So no GPE will be lost and never
triggered due to GPE clearing performed in the wrong position. And since
all GPE handling is performed after a locked GPE status checking, we can
hardly see no-op GPE handler invocations due to issue 1 and 3. We may still
see no-op GPE handler invocations due to "Note 1", but as it is inevitable,
it needn't be fixed.
After applying this patch, with frequent GPE enablings considered:
       =================================================================
       (event pending A)
       =================================================================
       acpi_ec_gpe_handler()     acpi_ec_transaction()
       *****************************************************************
       (event handling A)
         Lock(EC)
           advance_transaction()
             if STS==1
               STS=0
             EC_SC read
       =================================================================
       (event pending B)
       =================================================================
             EC_SC handled
         Unlock(EC)
       *****************************************************************
       *****************************************************************
       (event handling B)
                                   Lock(EC)
                                     EN=1
                                     if STS==1
                                       advance_transaction()
                                         if STS==1
                                           STS=0
                                         EC_SC read
       =================================================================
       (event pending C)
       =================================================================
                                         EC_SC handled
                                   Unlock(EC)
       *****************************************************************
The event pending for issue 2 can be manually handled by
advance_transaction(). And after the STS=0 write performed in the manual
triggered advance_transaction(), GPE can always arrive. So no GPE will be
lost due to frequent GPE disabling/enabling performed in the driver like
issue 4.
Note 5:
It's ideally when EN=1 write occurred, an IRQ thread should be woken up to
handle the GPE when the GPE was raised. But this requires the IRQ thread to
contain the poller code for all EC GPE indications, while currently some of
the indications are handled in the user tasks. It then is very hard for the
code to determine whether a user task should be invoked or the poller work
item should be scheduled. So we have to invoke advance_transaction()
directly now and it leaves us such a restriction for the GPE re-enabling:
it must be performed in the task context to avoid starving the GPEs.
As a conclusion: we can see the EC GPE is always handled in serial after
deploying the raw GPE handler mode:
  Lock(EC)
  if (STS==1)
    STS=0
  EC_SC read
  EC_SC handled
  Unlock(EC)
The EC driver specific lock is responsible to make the EC GPE handling
processes serialized so that EC can handle its GPE from both IRQ and task
contexts and the next IRQ can be ensured to arrive after this process.
Note 6:
We have many EC_FLAGS_MSI qurik users in the current driver. They all seem
to be suffering from unexpected GPE triggering source lost. And they are
false root caused to a timing issue. Since EC communication protocol has
already flow control defined, timing shouldn't be the root cause, while
this fix might be fixing the root cause of the old bugs.
Link: https://lkml.org/lkml/2014/11/4/974
Link: https://lkml.org/lkml/2014/11/18/316
Link: https://www.spinics.net/lists/linux-acpi/msg54340.html
Signed-off-by: Lv Zheng <lv.zheng@intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
											
										 
										
											2015-02-05 16:27:22 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									return ACPI_INTERRUPT_HANDLED;
							 | 
						
					
						
							
								
									
										
										
										
											2008-03-21 17:07:03 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								/* --------------------------------------------------------------------------
							 | 
						
					
						
							
								
									
										
										
										
											2014-10-14 14:24:01 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								 *                           Address Space Management
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * -------------------------------------------------------------------------- */
							 | 
						
					
						
							
								
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								static acpi_status
							 | 
						
					
						
							
								
									
										
										
										
											2007-05-29 16:42:52 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								acpi_ec_space_handler(u32 function, acpi_physical_address address,
							 | 
						
					
						
							
								
									
										
										
										
											2010-03-17 13:14:13 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										      u32 bits, u64 *value64,
							 | 
						
					
						
							
								
									
										
										
										
											2005-08-11 17:32:05 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										      void *handler_context, void *region_context)
							 | 
						
					
						
							
								
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							
								
									
										
										
										
											2007-03-07 22:28:00 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									struct acpi_ec *ec = handler_context;
							 | 
						
					
						
							
								
									
										
										
										
											2010-03-17 13:14:13 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									int result = 0, i, bytes = bits / 8;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									u8 *value = (u8 *)value64;
							 | 
						
					
						
							
								
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									if ((address > 0xFF) || !value || !handler_context)
							 | 
						
					
						
							
								
									
										
										
										
											2006-06-27 00:41:40 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										return AE_BAD_PARAMETER;
							 | 
						
					
						
							
								
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2007-05-29 16:42:52 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									if (function != ACPI_READ && function != ACPI_WRITE)
							 | 
						
					
						
							
								
									
										
										
										
											2006-06-27 00:41:40 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										return AE_BAD_PARAMETER;
							 | 
						
					
						
							
								
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2010-03-17 13:14:13 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									if (EC_FLAGS_MSI || bits > 8)
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-28 23:29:44 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										acpi_ec_burst_enable(ec);
							 | 
						
					
						
							
								
									
										
										
										
											2008-01-11 02:42:57 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2010-03-17 13:14:13 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									for (i = 0; i < bytes; ++i, ++address, ++value)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										result = (function == ACPI_READ) ?
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
											acpi_ec_read(ec, address, value) :
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
											acpi_ec_write(ec, address, *value);
							 | 
						
					
						
							
								
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2010-03-17 13:14:13 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									if (EC_FLAGS_MSI || bits > 8)
							 | 
						
					
						
							
								
									
										
										
										
											2009-08-28 23:29:44 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										acpi_ec_burst_disable(ec);
							 | 
						
					
						
							
								
									
										
										
										
											2008-01-11 02:42:57 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
									switch (result) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									case -EINVAL:
							 | 
						
					
						
							
								
									
										
										
										
											2006-06-27 00:41:40 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										return AE_BAD_PARAMETER;
							 | 
						
					
						
							
								
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
									case -ENODEV:
							 | 
						
					
						
							
								
									
										
										
										
											2006-06-27 00:41:40 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										return AE_NOT_FOUND;
							 | 
						
					
						
							
								
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
									case -ETIME:
							 | 
						
					
						
							
								
									
										
										
										
											2006-06-27 00:41:40 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										return AE_TIME;
							 | 
						
					
						
							
								
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
									default:
							 | 
						
					
						
							
								
									
										
										
										
											2006-06-27 00:41:40 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										return AE_OK;
							 | 
						
					
						
							
								
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
									}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								/* --------------------------------------------------------------------------
							 | 
						
					
						
							
								
									
										
										
										
											2014-10-14 14:24:01 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								 *                             Driver Interface
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * -------------------------------------------------------------------------- */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2007-03-07 22:28:00 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								static acpi_status
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								ec_parse_io_ports(struct acpi_resource *resource, void *context);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								static struct acpi_ec *make_acpi_ec(void)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									struct acpi_ec *ec = kzalloc(sizeof(struct acpi_ec), GFP_KERNEL);
							 | 
						
					
						
							
								
									
										
										
										
											2014-10-14 14:24:01 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2007-03-07 22:28:00 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									if (!ec)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										return NULL;
							 | 
						
					
						
							
								
									
										
										
										
											2015-02-11 17:35:05 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									ec->flags = 1 << EC_FLAGS_QUERY_PENDING;
							 | 
						
					
						
							
								
									
										
										
										
											2012-10-23 01:29:27 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									mutex_init(&ec->mutex);
							 | 
						
					
						
							
								
									
										
										
										
											2007-03-07 22:28:00 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									init_waitqueue_head(&ec->wait);
							 | 
						
					
						
							
								
									
										
										
										
											2007-05-29 16:43:02 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									INIT_LIST_HEAD(&ec->list);
							 | 
						
					
						
							
								
									
										
										
										
											2012-10-23 01:29:27 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									spin_lock_init(&ec->lock);
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												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>
											
										 
										
											2015-01-14 19:28:47 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									INIT_WORK(&ec->work, acpi_ec_gpe_poller);
							 | 
						
					
						
							
								
									
										
										
										
											2007-03-07 22:28:00 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									return ec;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							
								
									
										
										
										
											2007-05-29 16:43:02 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2007-08-14 01:03:42 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								static acpi_status
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								acpi_ec_register_query_methods(acpi_handle handle, u32 level,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
											       void *context, void **return_value)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							
								
									
										
										
										
											2008-12-16 16:46:12 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									char node_name[5];
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									struct acpi_buffer buffer = { sizeof(node_name), node_name };
							 | 
						
					
						
							
								
									
										
										
										
											2007-08-14 01:03:42 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									struct acpi_ec *ec = context;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									int value = 0;
							 | 
						
					
						
							
								
									
										
										
										
											2008-12-16 16:46:12 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									acpi_status status;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									status = acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2014-10-14 14:24:01 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									if (ACPI_SUCCESS(status) && sscanf(node_name, "_Q%x", &value) == 1)
							 | 
						
					
						
							
								
									
										
										
										
											2007-08-14 01:03:42 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										acpi_ec_add_query_handler(ec, value, handle, NULL, NULL);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									return AE_OK;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2007-08-03 17:52:48 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								static acpi_status
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval)
							 | 
						
					
						
							
								
									
										
										
										
											2007-05-29 16:43:02 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							
								
									
										
										
										
											2007-08-03 17:52:48 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									acpi_status status;
							 | 
						
					
						
							
								
									
										
										
										
											2008-11-03 14:26:40 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									unsigned long long tmp = 0;
							 | 
						
					
						
							
								
									
										
										
										
											2007-08-03 17:52:48 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									struct acpi_ec *ec = context;
							 | 
						
					
						
							
								
									
										
										
										
											2009-04-01 01:33:15 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									/* clear addr values, ec_parse_io_ports depend on it */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									ec->command_addr = ec->data_addr = 0;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2007-08-03 17:52:48 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									status = acpi_walk_resources(handle, METHOD_NAME__CRS,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
												     ec_parse_io_ports, ec);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									if (ACPI_FAILURE(status))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										return status;
							 | 
						
					
						
							
								
									
										
										
										
											2007-05-29 16:43:02 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									/* Get GPE bit assignment (EC events). */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									/* TODO: Add support for _GPE returning a package */
							 | 
						
					
						
							
								
									
										
										
										
											2008-10-10 02:22:59 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									status = acpi_evaluate_integer(handle, "_GPE", NULL, &tmp);
							 | 
						
					
						
							
								
									
										
										
										
											2007-08-03 17:52:48 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									if (ACPI_FAILURE(status))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										return status;
							 | 
						
					
						
							
								
									
										
										
										
											2008-10-10 02:22:59 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									ec->gpe = tmp;
							 | 
						
					
						
							
								
									
										
										
										
											2007-05-29 16:43:02 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									/* Use the global lock for all EC transactions? */
							 | 
						
					
						
							
								
									
										
										
										
											2008-11-03 14:26:40 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									tmp = 0;
							 | 
						
					
						
							
								
									
										
										
										
											2008-10-10 02:22:59 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									acpi_evaluate_integer(handle, "_GLK", NULL, &tmp);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									ec->global_lock = tmp;
							 | 
						
					
						
							
								
									
										
										
										
											2007-05-29 16:43:02 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									ec->handle = handle;
							 | 
						
					
						
							
								
									
										
										
										
											2007-08-03 17:52:48 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									return AE_CTRL_TERMINATE;
							 | 
						
					
						
							
								
									
										
										
										
											2007-05-29 16:43:02 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-06-22 20:41:30 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								static int ec_install_handlers(struct acpi_ec *ec)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									acpi_status status;
							 | 
						
					
						
							
								
									
										
										
										
											2014-10-14 14:24:01 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-06-22 20:41:30 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									if (test_bit(EC_FLAGS_HANDLERS_INSTALLED, &ec->flags))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										return 0;
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												ACPI / EC: Fix several GPE handling issues by deploying ACPI_GPE_DISPATCH_RAW_HANDLER mode.
This patch switches EC driver into ACPI_GPE_DISPATCH_RAW_HANDLER mode where
the GPE lock is not held for acpi_ec_gpe_handler() and the ACPICA internal
GPE enabling/disabling/clearing operations are bypassed so that further
improvements are possible with the GPE APIs.
There are 2 strong reasons for deploying raw GPE handler mode in the EC
driver:
1. Some hardware logics can control their interrupts via their own
   registers, so their interrupts can be disabled/enabled/acknowledged
   without using the super IRQ controller provided functions. While there
   is no mean (EC commands) for the EC driver to achieve this.
2. During suspending, the EC driver is still working for a while to
   complete the platform firmware provided functionailities using ec_poll()
   after all GPEs are disabled (see acpi_ec_block_transactions()), which
   means the EC driver will drive the EC GPE out of the GPE core's control.
Without deploying the raw GPE handler mode, we can see many races between
the EC driver and the GPE core due to the above restrictions:
1. There is a race condition due to ACPICA internal GPE
   disabling/clearing/enabling logics in acpi_ev_gpe_dispatch():
     Orignally EC GPE is disabled (EN=0), cleared (STS=0) before invoking a
     GPE handler and re-enabled (EN=1) after invoking a GPE handler in
     acpi_ev_gpe_dispatch(). When re-enabling appears, GPE may be flagged
     (STS=1).
       =================================================================
       (event pending A)
       =================================================================
       acpi_ev_gpe_dispatch()    ec_poll()
         EN=0
         STS=0
         acpi_ec_gpe_handler()
       *****************************************************************
       (event handling A)
           Lock(EC)
           advance_transaction()
             EC_SC read
       =================================================================
       (event pending B)
       =================================================================
             EC_SC handled
           Unlock(EC)
       *****************************************************************
       *****************************************************************
       (event handling B)
                                   Lock(EC)
                                   advance_transaction()
                                     EC_SC read
       =================================================================
       (event pending C)
       =================================================================
                                     EC_SC handled
                                   Unlock(EC)
       *****************************************************************
           EN=1
   This race condition is the root cause of different issues on different
   silicon variations.
   A. Silicon variation A:
      On some platforms, GPE will be triggered due to "writing 1 to EN when
      STS=1". This is because both EN and STS lines are wired to the GPE
      trigger line.
      1. Issue 1:
         We can see no-op acpi_ec_gpe_handler() invoked on such platforms.
         This is because:
         a. event pending B: An event can arrive after ACPICA's GPE
            clearing performed in acpi_ev_gpe_dispatch(), this event may
            fail to be detected by EC_SC read that is performed before its
            arrival;
         b. event handling B: The event can be handled in ec_poll() because
            EC lock is released after acpi_ec_gpe_handler() invocation;
         c. There is no code in ec_poll() to clear STS but the GPE can
            still be triggered by the EN=1 write performed in
            acpi_ev_finish_gpe(), this leads to a no-op EC GPE handler
            invocation;
         d. As no-op GPE handler invocations are counted by the EC driver
            to trigger the command storming conditions, the wrong no-op
            GPE handler invocations thus can easily trigger wrong command
            storming conditions.
         Note 1:
         If we removed GPE disabling/enabling code from
         acpi_ev_gpe_dispatch(), we could still see no-op GPE handlers
         triggered by the event arriving after the GPE clearing and before
         the GPE handling on both silicon variation A and B. This can only
         occur if the CPU is very slow (timing slice between STS=0 write
         and EC_SC read should be short enough before hardware sets another
         GPE indication). Thus this is very rare and is not what we need to
         fix.
   B. Silicon variation B:
      On other platforms, GPE may not be triggered due to "writing 1 to EN
      when STS=1". This is because only STS line is wired to the GPE
      trigger line.
      2. Issue 2:
         We can see GPE loss on such platforms. This is because:
         a. event pending B vs. event handling A: An event can arrive after
            ACPICA's GPE handling performed in acpi_ev_gpe_dispatch(), or
            event pending C vs. event handling B: An event can arrive after
            Linux's GPE handling performed in ec_poll(),
            these events may fail to be detected by EC_SC read that is
            performed before their arrival;
         b. The GPE cannot be triggered by EN=1 write performed in
            acpi_ev_finish_gpe();
         c. If no polling mechanism is implemented in the driver for the
            pending event (for example, SCI_EVT), this event is lost due to
            no GPE being triggered.
         Note 2:
         On most platforms, there might be another rule that GPE may not be
         triggered due to "writing 1 to STS when STS=1 and EN=1".
         Then on silicon variation B, an even worse case is if the issue 2
         event loss happens, further events may never trigger GPE again on
         such platforms due to being blocked by the current STS=1. Unless
         someone clears STS, all events have to be polled.
2. There is a race condition due to lacking in GPE status checking in EC
   driver:
     Originally, GPE status is checked in ACPICA core but not checked in
     the GPE handler. Thus since the status checking and handling is not
     locked, it can be interrupted by another handling path.
       =================================================================
       (event pending A)
       =================================================================
       acpi_ev_gpe_detect()        ec_poll()
         if (EN==1 && STS==1)
       *****************************************************************
       (event handling A)
                                     Lock(EC)
                                     advance_transaction()
                                       EC_SC read
                                       EC_SC handled
                                     Unlock(EC)
       *****************************************************************
         acpi_ev_gpe_dispatch()
           EN=0
           STS=0
           acpi_ec_gpe_handler()
       *****************************************************************
       (event handling B)
             Lock(EC)
             advance_transaction()
               EC_SC read
             Unlock(EC)
       *****************************************************************
      3. Issue 3:
         We can see no-op acpi_ec_gpe_handler() invoked on both silicon
         variation A and B. This is because:
         a. event pending A: An event can arrive to trigger an EC GPE and
            ACPICA checks it and is about to invoke the EC GPE handler;
         b. event handling A: The event can be handled in ec_poll() because
            EC lock is not held after the GPE status checking;
         c. event handling B: Then when the EC GPE handler is invoked, it
            becomes a no-op GPE handler invocation.
         d. As no-op GPE handler invocations are counted by the EC driver
            to trigger the command storming conditions, the wrong no-op
            GPE handler invocations thus can easily trigger wrong command
            storming conditions.
      Note 3:
      This no-op GPE handler invocation is rare because the time between
      the IRQ arrival and the acpi_ec_gpe_handler() invocation is less than
      the timeout value waited in ec_poll(). So most of the no-op GPE
      handler invocations are caused by the reason described in issue 1.
3. There is a race condition due to ACPICA internal GPE clearing logic in
   acpi_enable_gpe():
     During runtime, acpi_enable_gpe() can be invoked by the EC storming
     prevention code. When it is invoked, GPE may be flagged (STS=1).
       =================================================================
       (event pending A)
       =================================================================
       acpi_ev_gpe_dispatch()    acpi_ec_transaction()
         EN=0
         STS=0
         acpi_ec_gpe_handler()
       *****************************************************************
       (event handling A)
           Lock(EC)
           advance_transaction()
             EC_SC read
             EC_SC handled
           Unlock(EC)
       *****************************************************************
         EN=1 ?
                                   Lock(EC)
                                   Unlock(EC)
       =================================================================
       (event pending B)
       =================================================================
                                   acpi_enable_gpe()
                                     STS=0
                                     EN=1
    4. Issue 4:
       We can see GPE loss on both silicon variation A and B platforms.
       This is because:
       a. event pending B: An event can arrive right before ACPICA's GPE
          clearing performed in acpi_enable_gpe();
       b. If the GPE is cleared when GPE is disabled, then EN=1 write in
          acpi_enable_gpe() cannot trigger this GPE;
       c. If no polling mechanism is implemented in the driver for this
          event (for example, SCI_EVT), this event is lost due to no GPE
          being triggered.
       Note 4:
       Currently we don't have this issue, but after we switch the EC
       driver into ACPI_GPE_DISPATCH_RAW_HANDLER mode, we need to take care
       of handling this because the EN=1 write in acpi_ev_gpe_dispatch()
       will be abandoned.
There might be more race issues for the current GPE handler usages. This is
because the EC IRQ's enabling/disabling/checking/clearing/handling
operations should be locked by a single lock that is under the EC driver's
control to achieve the serialization. Which means we need to invoke GPE
APIs with EC driver's lock held and all ACPICA internal GPE operations
related to the GPE handler should be abandoned. Invoking GPE APIs inside of
the EC driver lock and bypassing ACPICA internal GPE operations requires
the ACPI_GPE_DISPATCH_RAW_HANDLER mode where the same lock used by the APIs
are released prior than invoking the handlers. Otherwise, we can see dead
locks due to circular locking dependencies (see Reference below).
This patch then switches the EC driver into the
ACPI_GPE_DISPATCH_RAW_HANDLER mode so that it can perform correct GPE
operations using the GPE APIs:
1. Bypasses EN modifications performed in acpi_ev_gpe_dispatch() by
   using acpi_install_gpe_raw_handler() and invoking all GPE APIs with EC
   spin lock held. This can fix issue 1 as it makes a non frequent GPE
   enabling/disabling environment.
2. Bypasses STS clearing performed in acpi_enable_gpe() by replacing
   acpi_enable_gpe()/acpi_disable_gpe() with acpi_set_gpe(). This can fix
   issue 4. And this can also help to fix issue 1 as it makes a no sudden
   GPE clearing environment when GPE is frequently enabled/disabled.
3. Ensures STS acknowledged before handling by invoking acpi_clear_gpe()
   in advance_transaction(). This can finally fix issue 1 even in a
   frequent GPE enabling/disabling environment. And this can also finally
   fix issue 3 when issue 2 is fixed.
   Note 3:
   GPE clearing is edge triggered W1C, which means we can clear it right
   before handling it. Since all EC GPE indications are handled in
   advance_transaction() by previous commits, we can now move GPE clearing
   into it to implement the correct GPE clearing.
   Note 4:
   We can use acpi_set_gpe() which is not shared GPE safer instead of
   acpi_enable_gpe()/acpi_disable_gpe() because EC GPE is not shared by
   other hardware, which is mentioned in the ACPI specification 5.0, 12.6
   Interrupt Model: "OSPM driver treats this as an edge event (the EC SCI
   cannot be shared)". So we can stop using shared GPE safer APIs
   acpi_enable_gpe()/acpi_disable_gpe() in the EC driver. Otherwise
   cleanups need to be made in acpi_ev_enable_gpe() to bypass the GPE
   clearing logic before keeping acpi_enable_gpe().
This patch also invokes advance_transaction() when GPE is re-enabled in the
task context which:
1. Ensures EN=1 can trigger GPE by checking and handling EC status register
   right after EN=1 writes. This can fix issue 2.
After applying this patch, without frequent GPE enablings considered:
       =================================================================
       (event pending A)
       =================================================================
       acpi_ec_gpe_handler()     ec_poll()
       *****************************************************************
       (event handling A)
         Lock(EC)
           advance_transaction()
             if STS==1
               STS=0
             EC_SC read
       =================================================================
       (event pending B)
       =================================================================
             EC_SC handled
         Unlock(EC)
       *****************************************************************
       *****************************************************************
       (event handling B)
                                   Lock(EC)
                                     advance_transaction()
                                       if STS==1
                                         STS=0
                                       EC_SC read
       =================================================================
       (event pending C)
       =================================================================
                                       EC_SC handled
                                   Unlock(EC)
       *****************************************************************
The event pending for issue 1 (event pending B) can arrive as a next GPE
due to the previous IRQ context STS=0 write. And if it is handled by
ec_poll() (event handling B), as it is also acknowledged by ec_poll(), the
event pending for issue 2 (event pending C) can properly arrive as a next
GPE after the task context STS=0 write. So no GPE will be lost and never
triggered due to GPE clearing performed in the wrong position. And since
all GPE handling is performed after a locked GPE status checking, we can
hardly see no-op GPE handler invocations due to issue 1 and 3. We may still
see no-op GPE handler invocations due to "Note 1", but as it is inevitable,
it needn't be fixed.
After applying this patch, with frequent GPE enablings considered:
       =================================================================
       (event pending A)
       =================================================================
       acpi_ec_gpe_handler()     acpi_ec_transaction()
       *****************************************************************
       (event handling A)
         Lock(EC)
           advance_transaction()
             if STS==1
               STS=0
             EC_SC read
       =================================================================
       (event pending B)
       =================================================================
             EC_SC handled
         Unlock(EC)
       *****************************************************************
       *****************************************************************
       (event handling B)
                                   Lock(EC)
                                     EN=1
                                     if STS==1
                                       advance_transaction()
                                         if STS==1
                                           STS=0
                                         EC_SC read
       =================================================================
       (event pending C)
       =================================================================
                                         EC_SC handled
                                   Unlock(EC)
       *****************************************************************
The event pending for issue 2 can be manually handled by
advance_transaction(). And after the STS=0 write performed in the manual
triggered advance_transaction(), GPE can always arrive. So no GPE will be
lost due to frequent GPE disabling/enabling performed in the driver like
issue 4.
Note 5:
It's ideally when EN=1 write occurred, an IRQ thread should be woken up to
handle the GPE when the GPE was raised. But this requires the IRQ thread to
contain the poller code for all EC GPE indications, while currently some of
the indications are handled in the user tasks. It then is very hard for the
code to determine whether a user task should be invoked or the poller work
item should be scheduled. So we have to invoke advance_transaction()
directly now and it leaves us such a restriction for the GPE re-enabling:
it must be performed in the task context to avoid starving the GPEs.
As a conclusion: we can see the EC GPE is always handled in serial after
deploying the raw GPE handler mode:
  Lock(EC)
  if (STS==1)
    STS=0
  EC_SC read
  EC_SC handled
  Unlock(EC)
The EC driver specific lock is responsible to make the EC GPE handling
processes serialized so that EC can handle its GPE from both IRQ and task
contexts and the next IRQ can be ensured to arrive after this process.
Note 6:
We have many EC_FLAGS_MSI qurik users in the current driver. They all seem
to be suffering from unexpected GPE triggering source lost. And they are
false root caused to a timing issue. Since EC communication protocol has
already flow control defined, timing shouldn't be the root cause, while
this fix might be fixing the root cause of the old bugs.
Link: https://lkml.org/lkml/2014/11/4/974
Link: https://lkml.org/lkml/2014/11/18/316
Link: https://www.spinics.net/lists/linux-acpi/msg54340.html
Signed-off-by: Lv Zheng <lv.zheng@intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
											
										 
										
											2015-02-05 16:27:22 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									status = acpi_install_gpe_raw_handler(NULL, ec->gpe,
							 | 
						
					
						
							
								
									
										
										
										
											2009-06-22 20:41:30 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
												  ACPI_GPE_EDGE_TRIGGERED,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
												  &acpi_ec_gpe_handler, ec);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									if (ACPI_FAILURE(status))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										return -ENODEV;
							 | 
						
					
						
							
								
									
										
										
										
											2010-02-17 23:41:07 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2015-02-06 08:57:52 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									acpi_ec_start(ec, false);
							 | 
						
					
						
							
								
									
										
										
										
											2009-06-22 20:41:30 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									status = acpi_install_address_space_handler(ec->handle,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
														    ACPI_ADR_SPACE_EC,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
														    &acpi_ec_space_handler,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
														    NULL, ec);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									if (ACPI_FAILURE(status)) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										if (status == AE_NOT_FOUND) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
											/*
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
											 * Maybe OS fails in evaluating the _REG object.
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
											 * The AE_NOT_FOUND error will be ignored and OS
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
											 * continue to initialize EC.
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
											 */
							 | 
						
					
						
							
								
									
										
										
										
											2013-09-12 03:32:04 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
											pr_err("Fail in evaluating the _REG object"
							 | 
						
					
						
							
								
									
										
										
										
											2009-06-22 20:41:30 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
												" of EC device. Broken bios is suspected.\n");
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										} else {
							 | 
						
					
						
							
								
									
										
										
										
											2015-02-06 08:57:52 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
											acpi_ec_stop(ec, false);
							 | 
						
					
						
							
								
									
										
										
										
											2009-06-22 20:41:30 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
											acpi_remove_gpe_handler(NULL, ec->gpe,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
												&acpi_ec_gpe_handler);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
											return -ENODEV;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									set_bit(EC_FLAGS_HANDLERS_INSTALLED, &ec->flags);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									return 0;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2007-09-05 19:56:38 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								static void ec_remove_handlers(struct acpi_ec *ec)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							
								
									
										
										
										
											2014-12-15 08:47:52 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									if (!test_bit(EC_FLAGS_HANDLERS_INSTALLED, &ec->flags))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										return;
							 | 
						
					
						
							
								
									
										
										
										
											2015-02-06 08:57:52 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									acpi_ec_stop(ec, false);
							 | 
						
					
						
							
								
									
										
										
										
											2007-09-05 19:56:38 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									if (ACPI_FAILURE(acpi_remove_address_space_handler(ec->handle,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
												ACPI_ADR_SPACE_EC, &acpi_ec_space_handler)))
							 | 
						
					
						
							
								
									
										
										
										
											2013-09-12 03:32:04 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										pr_err("failed to remove space handler\n");
							 | 
						
					
						
							
								
									
										
										
										
											2007-09-05 19:56:38 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									if (ACPI_FAILURE(acpi_remove_gpe_handler(NULL, ec->gpe,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
												&acpi_ec_gpe_handler)))
							 | 
						
					
						
							
								
									
										
										
										
											2013-09-12 03:32:04 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										pr_err("failed to remove gpe handler\n");
							 | 
						
					
						
							
								
									
										
										
										
											2008-09-25 21:00:31 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									clear_bit(EC_FLAGS_HANDLERS_INSTALLED, &ec->flags);
							 | 
						
					
						
							
								
									
										
										
										
											2007-09-05 19:56:38 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2006-09-26 19:50:33 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								static int acpi_ec_add(struct acpi_device *device)
							 | 
						
					
						
							
								
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							
								
									
										
										
										
											2006-09-26 19:50:33 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									struct acpi_ec *ec = NULL;
							 | 
						
					
						
							
								
									
										
										
										
											2009-06-22 20:41:35 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									int ret;
							 | 
						
					
						
							
								
									
										
										
										
											2005-07-23 04:08:00 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2007-03-07 22:28:00 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									strcpy(acpi_device_name(device), ACPI_EC_DEVICE_NAME);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									strcpy(acpi_device_class(device), ACPI_EC_CLASS);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2007-09-05 19:56:38 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									/* Check for boot EC */
							 | 
						
					
						
							
								
									
										
										
										
											2008-03-24 23:22:36 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									if (boot_ec &&
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									    (boot_ec->handle == device->handle ||
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									     boot_ec->handle == ACPI_ROOT_OBJECT)) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										ec = boot_ec;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										boot_ec = NULL;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									} else {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										ec = make_acpi_ec();
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										if (!ec)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
											return -ENOMEM;
							 | 
						
					
						
							
								
									
										
										
										
											2009-04-01 01:33:15 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									if (ec_parse_device(device->handle, 0, ec, NULL) !=
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										AE_CTRL_TERMINATE) {
							 | 
						
					
						
							
								
									
										
										
										
											2008-03-24 23:22:36 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
											kfree(ec);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
											return -EINVAL;
							 | 
						
					
						
							
								
									
										
										
										
											2007-09-05 19:56:38 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-03-24 23:22:36 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									/* Find and register all query methods */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									acpi_walk_namespace(ACPI_TYPE_METHOD, ec->handle, 1,
							 | 
						
					
						
							
								
									
										
										
										
											2009-11-13 10:06:08 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
											    acpi_ec_register_query_methods, NULL, ec, NULL);
							 | 
						
					
						
							
								
									
										
										
										
											2008-03-24 23:22:36 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2007-09-05 19:56:38 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									if (!first_ec)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										first_ec = ec;
							 | 
						
					
						
							
								
									
										
										
										
											2008-09-22 14:37:34 -07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									device->driver_data = ec;
							 | 
						
					
						
							
								
									
										
										
										
											2010-07-29 22:08:44 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2012-02-06 08:17:08 -08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									ret = !!request_region(ec->data_addr, 1, "EC data");
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									WARN(!ret, "Could not request EC data io port 0x%lx", ec->data_addr);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									ret = !!request_region(ec->command_addr, 1, "EC cmd");
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									WARN(!ret, "Could not request EC cmd io port 0x%lx", ec->command_addr);
							 | 
						
					
						
							
								
									
										
										
										
											2010-07-29 22:08:44 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2013-09-12 03:32:04 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									pr_info("GPE = 0x%lx, I/O: command/status = 0x%lx, data = 0x%lx\n",
							 | 
						
					
						
							
								
									
										
										
										
											2007-09-05 19:56:38 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
											  ec->gpe, ec->command_addr, ec->data_addr);
							 | 
						
					
						
							
								
									
										
										
										
											2009-06-22 20:41:30 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									ret = ec_install_handlers(ec);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									/* EC is fully operational, allow queries */
							 | 
						
					
						
							
								
									
										
										
										
											2015-02-11 17:35:05 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags);
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												ACPI / EC: Clear stale EC events on Samsung systems
A number of Samsung notebooks (530Uxx/535Uxx/540Uxx/550Pxx/900Xxx/etc)
continue to log events during sleep (lid open/close, AC plug/unplug,
battery level change), which accumulate in the EC until a buffer fills.
After the buffer is full (tests suggest it holds 8 events), GPEs stop
being triggered for new events. This state persists on wake or even on
power cycle, and prevents new events from being registered until the EC
is manually polled.
This is the root cause of a number of bugs, including AC not being
detected properly, lid close not triggering suspend, and low ambient
light not triggering the keyboard backlight. The bug also seemed to be
responsible for performance issues on at least one user's machine.
Juan Manuel Cabo found the cause of bug and the workaround of polling
the EC manually on wake.
The loop which clears the stale events is based on an earlier patch by
Lan Tianyu (see referenced attachment).
This patch:
 - Adds a function acpi_ec_clear() which polls the EC for stale _Q
   events at most ACPI_EC_CLEAR_MAX (currently 100) times. A warning is
   logged if this limit is reached.
 - Adds a flag EC_FLAGS_CLEAR_ON_RESUME which is set to 1 if the DMI
   system vendor is Samsung. This check could be replaced by several
   more specific DMI vendor/product pairs, but it's likely that the bug
   affects more Samsung products than just the five series mentioned
   above. Further, it should not be harmful to run acpi_ec_clear() on
   systems without the bug; it will return immediately after finding no
   data waiting.
 - Runs acpi_ec_clear() on initialisation (boot), from acpi_ec_add()
 - Runs acpi_ec_clear() on wake, from acpi_ec_unblock_transactions()
References: https://bugzilla.kernel.org/show_bug.cgi?id=44161
References: https://bugzilla.kernel.org/show_bug.cgi?id=45461
References: https://bugzilla.kernel.org/show_bug.cgi?id=57271
References: https://bugzilla.kernel.org/attachment.cgi?id=126801
Suggested-by: Juan Manuel Cabo <juanmanuel.cabo@gmail.com>
Signed-off-by: Kieran Clancy <clancy.kieran@gmail.com>
Reviewed-by: Lan Tianyu <tianyu.lan@intel.com>
Reviewed-by: Dennis Jansen <dennis.jansen@web.de>
Tested-by: Kieran Clancy <clancy.kieran@gmail.com>
Tested-by: Juan Manuel Cabo <juanmanuel.cabo@gmail.com>
Tested-by: Dennis Jansen <dennis.jansen@web.de>
Tested-by: Maurizio D'Addona <mauritiusdadd@gmail.com>
Tested-by: San Zamoyski <san@plusnet.pl>
Cc: All applicable <stable@vger.kernel.org>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
											
										 
										
											2014-03-01 00:42:28 +10:30
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									/* Clear stale _Q events if hardware might require that */
							 | 
						
					
						
							
								
									
										
										
										
											2015-01-14 19:28:53 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									if (EC_FLAGS_CLEAR_ON_RESUME)
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												ACPI / EC: Clear stale EC events on Samsung systems
A number of Samsung notebooks (530Uxx/535Uxx/540Uxx/550Pxx/900Xxx/etc)
continue to log events during sleep (lid open/close, AC plug/unplug,
battery level change), which accumulate in the EC until a buffer fills.
After the buffer is full (tests suggest it holds 8 events), GPEs stop
being triggered for new events. This state persists on wake or even on
power cycle, and prevents new events from being registered until the EC
is manually polled.
This is the root cause of a number of bugs, including AC not being
detected properly, lid close not triggering suspend, and low ambient
light not triggering the keyboard backlight. The bug also seemed to be
responsible for performance issues on at least one user's machine.
Juan Manuel Cabo found the cause of bug and the workaround of polling
the EC manually on wake.
The loop which clears the stale events is based on an earlier patch by
Lan Tianyu (see referenced attachment).
This patch:
 - Adds a function acpi_ec_clear() which polls the EC for stale _Q
   events at most ACPI_EC_CLEAR_MAX (currently 100) times. A warning is
   logged if this limit is reached.
 - Adds a flag EC_FLAGS_CLEAR_ON_RESUME which is set to 1 if the DMI
   system vendor is Samsung. This check could be replaced by several
   more specific DMI vendor/product pairs, but it's likely that the bug
   affects more Samsung products than just the five series mentioned
   above. Further, it should not be harmful to run acpi_ec_clear() on
   systems without the bug; it will return immediately after finding no
   data waiting.
 - Runs acpi_ec_clear() on initialisation (boot), from acpi_ec_add()
 - Runs acpi_ec_clear() on wake, from acpi_ec_unblock_transactions()
References: https://bugzilla.kernel.org/show_bug.cgi?id=44161
References: https://bugzilla.kernel.org/show_bug.cgi?id=45461
References: https://bugzilla.kernel.org/show_bug.cgi?id=57271
References: https://bugzilla.kernel.org/attachment.cgi?id=126801
Suggested-by: Juan Manuel Cabo <juanmanuel.cabo@gmail.com>
Signed-off-by: Kieran Clancy <clancy.kieran@gmail.com>
Reviewed-by: Lan Tianyu <tianyu.lan@intel.com>
Reviewed-by: Dennis Jansen <dennis.jansen@web.de>
Tested-by: Kieran Clancy <clancy.kieran@gmail.com>
Tested-by: Juan Manuel Cabo <juanmanuel.cabo@gmail.com>
Tested-by: Dennis Jansen <dennis.jansen@web.de>
Tested-by: Maurizio D'Addona <mauritiusdadd@gmail.com>
Tested-by: San Zamoyski <san@plusnet.pl>
Cc: All applicable <stable@vger.kernel.org>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
											
										 
										
											2014-03-01 00:42:28 +10:30
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										acpi_ec_clear(ec);
							 | 
						
					
						
							
								
									
										
										
										
											2009-06-22 20:41:30 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									return ret;
							 | 
						
					
						
							
								
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2013-01-24 00:24:48 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								static int acpi_ec_remove(struct acpi_device *device)
							 | 
						
					
						
							
								
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							
								
									
										
										
										
											2007-03-07 22:28:00 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									struct acpi_ec *ec;
							 | 
						
					
						
							
								
									
										
										
										
											2007-07-29 17:00:37 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									struct acpi_ec_query_handler *handler, *tmp;
							 | 
						
					
						
							
								
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									if (!device)
							 | 
						
					
						
							
								
									
										
										
										
											2006-06-27 00:41:40 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										return -EINVAL;
							 | 
						
					
						
							
								
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									ec = acpi_driver_data(device);
							 | 
						
					
						
							
								
									
										
										
										
											2009-06-22 20:41:40 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									ec_remove_handlers(ec);
							 | 
						
					
						
							
								
									
										
										
										
											2012-10-23 01:29:27 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									mutex_lock(&ec->mutex);
							 | 
						
					
						
							
								
									
										
										
										
											2007-07-29 17:00:37 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									list_for_each_entry_safe(handler, tmp, &ec->list, node) {
							 | 
						
					
						
							
								
									
										
										
										
											2007-05-29 16:43:02 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										list_del(&handler->node);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										kfree(handler);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									}
							 | 
						
					
						
							
								
									
										
										
										
											2012-10-23 01:29:27 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									mutex_unlock(&ec->mutex);
							 | 
						
					
						
							
								
									
										
										
										
											2010-07-29 22:08:44 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									release_region(ec->data_addr, 1);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									release_region(ec->command_addr, 1);
							 | 
						
					
						
							
								
									
										
										
										
											2008-09-22 14:37:34 -07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									device->driver_data = NULL;
							 | 
						
					
						
							
								
									
										
										
										
											2007-03-07 22:28:00 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									if (ec == first_ec)
							 | 
						
					
						
							
								
									
										
										
										
											2007-03-07 22:28:00 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										first_ec = NULL;
							 | 
						
					
						
							
								
									
										
										
										
											2007-09-05 19:56:38 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									kfree(ec);
							 | 
						
					
						
							
								
									
										
										
										
											2006-06-27 00:41:40 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									return 0;
							 | 
						
					
						
							
								
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								static acpi_status
							 | 
						
					
						
							
								
									
										
										
										
											2007-03-07 22:28:00 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								ec_parse_io_ports(struct acpi_resource *resource, void *context)
							 | 
						
					
						
							
								
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							
								
									
										
										
										
											2007-03-07 22:28:00 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									struct acpi_ec *ec = context;
							 | 
						
					
						
							
								
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2007-03-07 22:28:00 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									if (resource->type != ACPI_RESOURCE_TYPE_IO)
							 | 
						
					
						
							
								
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
										return AE_OK;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									/*
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									 * The first address region returned is the data port, and
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									 * the second address region returned is the status/command
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									 * port.
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									 */
							 | 
						
					
						
							
								
									
										
										
										
											2010-07-29 22:08:44 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									if (ec->data_addr == 0)
							 | 
						
					
						
							
								
									
										
										
										
											2006-09-26 19:50:33 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										ec->data_addr = resource->data.io.minimum;
							 | 
						
					
						
							
								
									
										
										
										
											2010-07-29 22:08:44 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									else if (ec->command_addr == 0)
							 | 
						
					
						
							
								
									
										
										
										
											2006-09-26 19:50:33 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										ec->command_addr = resource->data.io.minimum;
							 | 
						
					
						
							
								
									
										
										
										
											2007-03-07 22:28:00 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									else
							 | 
						
					
						
							
								
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
										return AE_CTRL_TERMINATE;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									return AE_OK;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-01-01 14:12:55 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								int __init acpi_boot_ec_enable(void)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							
								
									
										
										
										
											2008-09-25 21:00:31 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									if (!boot_ec || test_bit(EC_FLAGS_HANDLERS_INSTALLED, &boot_ec->flags))
							 | 
						
					
						
							
								
									
										
										
										
											2008-01-01 14:12:55 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										return 0;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									if (!ec_install_handlers(boot_ec)) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										first_ec = boot_ec;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										return 0;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									return -EFAULT;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-03-21 17:07:21 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								static const struct acpi_device_id ec_device_ids[] = {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									{"PNP0C09", 0},
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									{"", 0},
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								};
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-10-02 20:21:40 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/* Some BIOS do not survive early DSDT scan, skip it */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								static int ec_skip_dsdt_scan(const struct dmi_system_id *id)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									EC_FLAGS_SKIP_DSDT_SCAN = 1;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									return 0;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-10-02 20:21:33 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/* ASUStek often supplies us with broken ECDT, validate it */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								static int ec_validate_ecdt(const struct dmi_system_id *id)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									EC_FLAGS_VALIDATE_ECDT = 1;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									return 0;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								/* MSI EC needs special treatment, enable it */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								static int ec_flag_msi(const struct dmi_system_id *id)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							
								
									
										
										
										
											2013-09-12 03:32:04 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									pr_debug("Detected MSI hardware, enabling workarounds.\n");
							 | 
						
					
						
							
								
									
										
										
										
											2009-10-02 20:21:33 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									EC_FLAGS_MSI = 1;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									EC_FLAGS_VALIDATE_ECDT = 1;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									return 0;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2012-09-28 15:22:01 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/*
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * Clevo M720 notebook actually works ok with IRQ mode, if we lifted
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * the GPE storm threshold back to 20
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								static int ec_enlarge_storm_threshold(const struct dmi_system_id *id)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									pr_debug("Setting the EC GPE storm threshold to 20\n");
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									ec_storm_threshold  = 20;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									return 0;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2014-10-29 11:33:49 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/*
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * Acer EC firmware refuses to respond QR_EC when SCI_EVT is not set, for
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * which case, we complete the QR_EC without issuing it to the firmware.
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * https://bugzilla.kernel.org/show_bug.cgi?id=86211
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								static int ec_flag_query_handshake(const struct dmi_system_id *id)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									pr_debug("Detected the EC firmware requiring QR_EC issued when SCI_EVT set\n");
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									EC_FLAGS_QUERY_HANDSHAKE = 1;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									return 0;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												ACPI / EC: Clear stale EC events on Samsung systems
A number of Samsung notebooks (530Uxx/535Uxx/540Uxx/550Pxx/900Xxx/etc)
continue to log events during sleep (lid open/close, AC plug/unplug,
battery level change), which accumulate in the EC until a buffer fills.
After the buffer is full (tests suggest it holds 8 events), GPEs stop
being triggered for new events. This state persists on wake or even on
power cycle, and prevents new events from being registered until the EC
is manually polled.
This is the root cause of a number of bugs, including AC not being
detected properly, lid close not triggering suspend, and low ambient
light not triggering the keyboard backlight. The bug also seemed to be
responsible for performance issues on at least one user's machine.
Juan Manuel Cabo found the cause of bug and the workaround of polling
the EC manually on wake.
The loop which clears the stale events is based on an earlier patch by
Lan Tianyu (see referenced attachment).
This patch:
 - Adds a function acpi_ec_clear() which polls the EC for stale _Q
   events at most ACPI_EC_CLEAR_MAX (currently 100) times. A warning is
   logged if this limit is reached.
 - Adds a flag EC_FLAGS_CLEAR_ON_RESUME which is set to 1 if the DMI
   system vendor is Samsung. This check could be replaced by several
   more specific DMI vendor/product pairs, but it's likely that the bug
   affects more Samsung products than just the five series mentioned
   above. Further, it should not be harmful to run acpi_ec_clear() on
   systems without the bug; it will return immediately after finding no
   data waiting.
 - Runs acpi_ec_clear() on initialisation (boot), from acpi_ec_add()
 - Runs acpi_ec_clear() on wake, from acpi_ec_unblock_transactions()
References: https://bugzilla.kernel.org/show_bug.cgi?id=44161
References: https://bugzilla.kernel.org/show_bug.cgi?id=45461
References: https://bugzilla.kernel.org/show_bug.cgi?id=57271
References: https://bugzilla.kernel.org/attachment.cgi?id=126801
Suggested-by: Juan Manuel Cabo <juanmanuel.cabo@gmail.com>
Signed-off-by: Kieran Clancy <clancy.kieran@gmail.com>
Reviewed-by: Lan Tianyu <tianyu.lan@intel.com>
Reviewed-by: Dennis Jansen <dennis.jansen@web.de>
Tested-by: Kieran Clancy <clancy.kieran@gmail.com>
Tested-by: Juan Manuel Cabo <juanmanuel.cabo@gmail.com>
Tested-by: Dennis Jansen <dennis.jansen@web.de>
Tested-by: Maurizio D'Addona <mauritiusdadd@gmail.com>
Tested-by: San Zamoyski <san@plusnet.pl>
Cc: All applicable <stable@vger.kernel.org>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
											
										 
										
											2014-03-01 00:42:28 +10:30
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/*
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * 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;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2013-08-07 17:16:55 +05:30
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								static struct dmi_system_id ec_dmi_table[] __initdata = {
							 | 
						
					
						
							
								
									
										
										
										
											2009-10-02 20:21:40 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									{
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									ec_skip_dsdt_scan, "Compal JFL92", {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									DMI_MATCH(DMI_BIOS_VENDOR, "COMPAL"),
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									DMI_MATCH(DMI_BOARD_NAME, "JFL92") }, NULL},
							 | 
						
					
						
							
								
									
										
										
										
											2009-10-02 20:21:33 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									{
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									ec_flag_msi, "MSI hardware", {
							 | 
						
					
						
							
								
									
										
										
										
											2009-12-22 02:42:52 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									DMI_MATCH(DMI_BIOS_VENDOR, "Micro-Star")}, NULL},
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									{
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									ec_flag_msi, "MSI hardware", {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star")}, NULL},
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									{
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									ec_flag_msi, "MSI hardware", {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									DMI_MATCH(DMI_CHASSIS_VENDOR, "MICRO-Star")}, NULL},
							 | 
						
					
						
							
								
									
										
										
										
											2009-10-02 20:21:33 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									{
							 | 
						
					
						
							
								
									
										
										
										
											2010-12-09 17:07:54 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									ec_flag_msi, "MSI hardware", {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									DMI_MATCH(DMI_CHASSIS_VENDOR, "MICRO-STAR")}, NULL},
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									{
							 | 
						
					
						
							
								
									
										
										
										
											2011-04-26 16:30:02 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									ec_flag_msi, "Quanta hardware", {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									DMI_MATCH(DMI_SYS_VENDOR, "Quanta"),
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									DMI_MATCH(DMI_PRODUCT_NAME, "TW8/SW8/DW8"),}, NULL},
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									{
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									ec_flag_msi, "Quanta hardware", {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									DMI_MATCH(DMI_SYS_VENDOR, "Quanta"),
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									DMI_MATCH(DMI_PRODUCT_NAME, "TW9/SW9"),}, NULL},
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									{
							 | 
						
					
						
							
								
									
										
										
										
											2014-08-29 10:50:08 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									ec_flag_msi, "Clevo W350etq", {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									DMI_MATCH(DMI_SYS_VENDOR, "CLEVO CO."),
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									DMI_MATCH(DMI_PRODUCT_NAME, "W35_37ET"),}, NULL},
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									{
							 | 
						
					
						
							
								
									
										
										
										
											2009-10-02 20:21:33 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									ec_validate_ecdt, "ASUS hardware", {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									DMI_MATCH(DMI_BIOS_VENDOR, "ASUS") }, NULL},
							 | 
						
					
						
							
								
									
										
										
										
											2011-04-24 22:09:32 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									{
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									ec_validate_ecdt, "ASUS hardware", {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer Inc.") }, NULL},
							 | 
						
					
						
							
								
									
										
										
										
											2012-09-28 15:22:01 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									{
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									ec_enlarge_storm_threshold, "CLEVO hardware", {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									DMI_MATCH(DMI_SYS_VENDOR, "CLEVO Co."),
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									DMI_MATCH(DMI_PRODUCT_NAME, "M720T/M730T"),}, NULL},
							 | 
						
					
						
							
								
									
										
										
										
											2013-06-05 02:27:51 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									{
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									ec_skip_dsdt_scan, "HP Folio 13", {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									DMI_MATCH(DMI_PRODUCT_NAME, "HP Folio 13"),}, NULL},
							 | 
						
					
						
							
								
									
										
										
										
											2013-08-26 10:19:18 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									{
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									ec_validate_ecdt, "ASUS hardware", {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									DMI_MATCH(DMI_SYS_VENDOR, "ASUSTek Computer Inc."),
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									DMI_MATCH(DMI_PRODUCT_NAME, "L4R"),}, NULL},
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												ACPI / EC: Clear stale EC events on Samsung systems
A number of Samsung notebooks (530Uxx/535Uxx/540Uxx/550Pxx/900Xxx/etc)
continue to log events during sleep (lid open/close, AC plug/unplug,
battery level change), which accumulate in the EC until a buffer fills.
After the buffer is full (tests suggest it holds 8 events), GPEs stop
being triggered for new events. This state persists on wake or even on
power cycle, and prevents new events from being registered until the EC
is manually polled.
This is the root cause of a number of bugs, including AC not being
detected properly, lid close not triggering suspend, and low ambient
light not triggering the keyboard backlight. The bug also seemed to be
responsible for performance issues on at least one user's machine.
Juan Manuel Cabo found the cause of bug and the workaround of polling
the EC manually on wake.
The loop which clears the stale events is based on an earlier patch by
Lan Tianyu (see referenced attachment).
This patch:
 - Adds a function acpi_ec_clear() which polls the EC for stale _Q
   events at most ACPI_EC_CLEAR_MAX (currently 100) times. A warning is
   logged if this limit is reached.
 - Adds a flag EC_FLAGS_CLEAR_ON_RESUME which is set to 1 if the DMI
   system vendor is Samsung. This check could be replaced by several
   more specific DMI vendor/product pairs, but it's likely that the bug
   affects more Samsung products than just the five series mentioned
   above. Further, it should not be harmful to run acpi_ec_clear() on
   systems without the bug; it will return immediately after finding no
   data waiting.
 - Runs acpi_ec_clear() on initialisation (boot), from acpi_ec_add()
 - Runs acpi_ec_clear() on wake, from acpi_ec_unblock_transactions()
References: https://bugzilla.kernel.org/show_bug.cgi?id=44161
References: https://bugzilla.kernel.org/show_bug.cgi?id=45461
References: https://bugzilla.kernel.org/show_bug.cgi?id=57271
References: https://bugzilla.kernel.org/attachment.cgi?id=126801
Suggested-by: Juan Manuel Cabo <juanmanuel.cabo@gmail.com>
Signed-off-by: Kieran Clancy <clancy.kieran@gmail.com>
Reviewed-by: Lan Tianyu <tianyu.lan@intel.com>
Reviewed-by: Dennis Jansen <dennis.jansen@web.de>
Tested-by: Kieran Clancy <clancy.kieran@gmail.com>
Tested-by: Juan Manuel Cabo <juanmanuel.cabo@gmail.com>
Tested-by: Dennis Jansen <dennis.jansen@web.de>
Tested-by: Maurizio D'Addona <mauritiusdadd@gmail.com>
Tested-by: San Zamoyski <san@plusnet.pl>
Cc: All applicable <stable@vger.kernel.org>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
											
										 
										
											2014-03-01 00:42:28 +10:30
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									{
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									ec_clear_on_resume, "Samsung hardware", {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD.")}, NULL},
							 | 
						
					
						
							
								
									
										
										
										
											2014-10-29 11:33:49 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									{
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									ec_flag_query_handshake, "Acer hardware", {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									DMI_MATCH(DMI_SYS_VENDOR, "Acer"), }, NULL},
							 | 
						
					
						
							
								
									
										
										
										
											2009-10-02 20:21:33 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									{},
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								};
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2007-03-07 22:28:00 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								int __init acpi_ec_ecdt_probe(void)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									acpi_status status;
							 | 
						
					
						
							
								
									
										
										
										
											2009-01-14 02:57:53 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									struct acpi_ec *saved_ec = NULL;
							 | 
						
					
						
							
								
									
										
										
										
											2005-08-11 17:32:05 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									struct acpi_table_ecdt *ecdt_ptr;
							 | 
						
					
						
							
								
									
										
										
										
											2005-07-23 04:08:00 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2007-03-07 22:28:00 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									boot_ec = make_acpi_ec();
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									if (!boot_ec)
							 | 
						
					
						
							
								
									
										
										
										
											2007-03-07 22:28:00 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										return -ENOMEM;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									/*
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									 * Generate a boot ec context
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									 */
							 | 
						
					
						
							
								
									
										
										
										
											2009-10-02 20:21:33 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									dmi_check_system(ec_dmi_table);
							 | 
						
					
						
							
								
									
										
										
										
											2007-02-02 19:48:22 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									status = acpi_get_table(ACPI_SIG_ECDT, 1,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
												(struct acpi_table_header **)&ecdt_ptr);
							 | 
						
					
						
							
								
									
										
										
										
											2007-08-03 17:52:48 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									if (ACPI_SUCCESS(status)) {
							 | 
						
					
						
							
								
									
										
										
										
											2013-09-12 03:32:04 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										pr_info("EC description table is found, configuring boot EC\n");
							 | 
						
					
						
							
								
									
										
										
										
											2007-08-03 17:52:48 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										boot_ec->command_addr = ecdt_ptr->control.address;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										boot_ec->data_addr = ecdt_ptr->data.address;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										boot_ec->gpe = ecdt_ptr->gpe;
							 | 
						
					
						
							
								
									
										
										
										
											2008-03-11 00:27:16 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										boot_ec->handle = ACPI_ROOT_OBJECT;
							 | 
						
					
						
							
								
									
										
										
										
											2014-10-14 14:24:01 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										acpi_get_handle(ACPI_ROOT_OBJECT, ecdt_ptr->id,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
												&boot_ec->handle);
							 | 
						
					
						
							
								
									
										
										
										
											2009-01-14 02:57:53 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										/* Don't trust ECDT, which comes from ASUSTek */
							 | 
						
					
						
							
								
									
										
										
										
											2009-10-02 20:21:33 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										if (!EC_FLAGS_VALIDATE_ECDT)
							 | 
						
					
						
							
								
									
										
										
										
											2008-11-26 17:11:53 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
											goto install;
							 | 
						
					
						
							
								
									
										
										
										
											2010-05-15 23:16:21 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										saved_ec = kmemdup(boot_ec, sizeof(struct acpi_ec), GFP_KERNEL);
							 | 
						
					
						
							
								
									
										
										
										
											2009-01-14 02:57:53 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										if (!saved_ec)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
											return -ENOMEM;
							 | 
						
					
						
							
								
									
										
										
										
											2008-11-26 17:11:53 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									/* fall through */
							 | 
						
					
						
							
								
									
										
										
										
											2007-08-03 17:52:48 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									}
							 | 
						
					
						
							
								
									
										
										
										
											2009-10-02 20:21:33 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2014-07-03 00:35:09 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									if (EC_FLAGS_SKIP_DSDT_SCAN) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										kfree(saved_ec);
							 | 
						
					
						
							
								
									
										
										
										
											2009-10-02 20:21:40 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										return -ENODEV;
							 | 
						
					
						
							
								
									
										
										
										
											2014-07-03 00:35:09 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									}
							 | 
						
					
						
							
								
									
										
										
										
											2009-10-02 20:21:40 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-11-26 17:11:53 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									/* This workaround is needed only on some broken machines,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									 * which require early EC, but fail to provide ECDT */
							 | 
						
					
						
							
								
									
										
										
										
											2013-09-12 03:32:04 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									pr_debug("Look up EC in DSDT\n");
							 | 
						
					
						
							
								
									
										
										
										
											2008-11-26 17:11:53 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									status = acpi_get_devices(ec_device_ids[0].id, ec_parse_device,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
													boot_ec, NULL);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									/* Check that acpi_get_devices actually find something */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									if (ACPI_FAILURE(status) || !boot_ec->handle)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										goto error;
							 | 
						
					
						
							
								
									
										
										
										
											2009-01-14 02:57:53 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									if (saved_ec) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										/* try to find good ECDT from ASUSTek */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										if (saved_ec->command_addr != boot_ec->command_addr ||
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										    saved_ec->data_addr != boot_ec->data_addr ||
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										    saved_ec->gpe != boot_ec->gpe ||
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										    saved_ec->handle != boot_ec->handle)
							 | 
						
					
						
							
								
									
										
										
										
											2013-09-12 03:32:04 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
											pr_info("ASUSTek keeps feeding us with broken "
							 | 
						
					
						
							
								
									
										
										
										
											2009-01-14 02:57:53 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
											"ECDT tables, which are very hard to workaround. "
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
											"Trying to use DSDT EC info instead. Please send "
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
											"output of acpidump to linux-acpi@vger.kernel.org\n");
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										kfree(saved_ec);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										saved_ec = NULL;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									} else {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										/* We really need to limit this workaround, the only ASUS,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										* which needs it, has fake EC._INI method, so use it as flag.
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										* Keep boot_ec struct as it will be needed soon.
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										*/
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										if (!dmi_name_in_vendors("ASUS") ||
							 | 
						
					
						
							
								
									
										
										
										
											2013-06-29 00:24:38 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										    !acpi_has_method(boot_ec->handle, "_INI"))
							 | 
						
					
						
							
								
									
										
										
										
											2009-01-14 02:57:53 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
											return -ENODEV;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									}
							 | 
						
					
						
							
								
									
										
										
										
											2008-11-26 17:11:53 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								install:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									if (!ec_install_handlers(boot_ec)) {
							 | 
						
					
						
							
								
									
										
										
										
											2007-03-07 22:28:00 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										first_ec = boot_ec;
							 | 
						
					
						
							
								
									
										
										
										
											2007-03-07 22:28:00 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										return 0;
							 | 
						
					
						
							
								
									
										
										
										
											2007-03-07 22:28:00 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									}
							 | 
						
					
						
							
								
									
										
										
										
											2008-11-26 17:11:53 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								error:
							 | 
						
					
						
							
								
									
										
										
										
											2007-03-07 22:28:00 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									kfree(boot_ec);
							 | 
						
					
						
							
								
									
										
										
										
											2014-07-03 00:35:09 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									kfree(saved_ec);
							 | 
						
					
						
							
								
									
										
										
										
											2007-03-07 22:28:00 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									boot_ec = NULL;
							 | 
						
					
						
							
								
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
									return -ENODEV;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-03-21 17:07:21 +03:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								static struct acpi_driver acpi_ec_driver = {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									.name = "ec",
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									.class = ACPI_EC_CLASS,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									.ids = ec_device_ids,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									.ops = {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										.add = acpi_ec_add,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										.remove = acpi_ec_remove,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										},
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								};
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2009-03-24 16:49:48 -06:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								int __init acpi_ec_init(void)
							 | 
						
					
						
							
								
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							
								
									
										
										
										
											2005-08-11 17:32:05 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									int result = 0;
							 | 
						
					
						
							
								
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									/* Now register the driver for the EC */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									result = acpi_bus_register_driver(&acpi_ec_driver);
							 | 
						
					
						
							
								
									
										
										
										
											2010-07-16 13:11:34 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									if (result < 0)
							 | 
						
					
						
							
								
									
										
										
										
											2006-06-27 00:41:40 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										return -ENODEV;
							 | 
						
					
						
							
								
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2006-06-27 00:41:40 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									return result;
							 | 
						
					
						
							
								
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								/* EC driver currently not unloadable */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								#if 0
							 | 
						
					
						
							
								
									
										
										
										
											2005-08-11 17:32:05 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								static void __exit acpi_ec_exit(void)
							 | 
						
					
						
							
								
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									acpi_bus_unregister_driver(&acpi_ec_driver);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							
								
									
										
										
										
											2007-10-22 14:18:43 +04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								#endif	/* 0 */
							 |