[RFC PATCH v6 0/3] ACPI / EC: Tune the timing of EC events arrival during S3-exit

2017-09-28 Thread Lv Zheng
If EC events occurred during BIOS S3-exit and early OS S3-exit steps can
be detected by OS earlier, then there can be less driver order issues
between acpi_ec_resume() and some other drivers' .resume() hook (e.x.
acpi_button_resume()).

However there are known facts that EC FW does drop EC events during S3,
and it takes time for EC FW to initialize (maximum 1.4 observed) while
Windows acts normally, so detecting EC event earlier might just be a
workaround for other drivers (they should be aware of this order issue and
deal with it themselves). As such, this patchset is marked as an RFC.

If Linux EC driver started to detect events during early OS S3-exit, it
need to timely poll EC events during noirq stages as in this stage there is
no EC event triggering source.

This patchset implements earlier EC event handling for Linux.

Lv Zheng (3):
  ACPI / EC: Fix possible driver order issue by moving EC event handling
earlier
  ACPI / EC: Add event detection support for noirq stages
  ACPI / EC: Enable noirq stage event detection

 drivers/acpi/ec.c   | 128 +++-
 drivers/acpi/internal.h |   1 +
 2 files changed, 118 insertions(+), 11 deletions(-)

-- 
2.7.4



[RFC PATCH v6 1/3] ACPI / EC: Fix possible driver order issue by moving EC event handling earlier

2017-09-28 Thread Lv Zheng
This patch tries to detect EC events earlier after resume, so that if an
event occurred before invoking acpi_ec_unblock_transactions(), it could be
detected by acpi_ec_unblock_transactions() which is the earliest EC driver
call after resume.

However after the noirq stage, if an event ocurred after
acpi_ec_unblock_transactions() and before acpi_ec_resume(), there was no
mean to detect and trigger it right then, but can only detect it and handle
it after acpi_ec_resume().

Now the final logic is:
1. If ec_freeze_events=Y, event handling is stopped in acpi_ec_suspend(),
   restarted in acpi_ec_resume();
2. If ec_freeze_events=N, event handling is stopped in
   acpi_ec_block_transactions(), restarted in
   acpi_ec_unblock_transactions();
3. In order to handling the conflict of the edge-trigger nature of EC IRQ
   and the Linux noirq stage, advance_transaction() is invoked where the
   event handling is enabled and the noirq stage is ended.

Known issue:
1. Event ocurred between acpi_ec_unblock_transactions() and
   acpi_ec_resume() may still lead to the order issue. This can only be
   fixed by adding a periodic detection mechanism during the noirq stage.

Signed-off-by: Lv Zheng 
Tested-by: Tomislav Ivek 
Tested-by: Luya Tshimbalanga 
---
 drivers/acpi/ec.c | 35 ++-
 1 file changed, 26 insertions(+), 9 deletions(-)

diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index df84246..f1f320b 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -249,6 +249,11 @@ static bool acpi_ec_started(struct acpi_ec *ec)
   !test_bit(EC_FLAGS_STOPPED, &ec->flags);
 }
 
+static bool acpi_ec_no_sleep_events(void)
+{
+   return acpi_sleep_no_ec_events() && ec_freeze_events;
+}
+
 static bool acpi_ec_event_enabled(struct acpi_ec *ec)
 {
/*
@@ -260,14 +265,14 @@ static bool acpi_ec_event_enabled(struct acpi_ec *ec)
return false;
/*
 * However, disabling the event handling is experimental for late
-* stage (suspend), and is controlled by the boot parameter of
-* "ec_freeze_events":
+* stage (suspend), and is controlled by
+* "acpi_ec_no_sleep_events()":
 * 1. true:  The EC event handling is disabled before entering
 *   the noirq stage.
 * 2. false: The EC event handling is automatically disabled as
 *   soon as the EC driver is stopped.
 */
-   if (ec_freeze_events)
+   if (acpi_ec_no_sleep_events())
return acpi_ec_started(ec);
else
return test_bit(EC_FLAGS_STARTED, &ec->flags);
@@ -524,8 +529,8 @@ static bool acpi_ec_query_flushed(struct acpi_ec *ec)
 static void __acpi_ec_flush_event(struct acpi_ec *ec)
 {
/*
-* When ec_freeze_events is true, we need to flush events in
-* the proper position before entering the noirq stage.
+* When acpi_ec_no_sleep_events() is true, we need to flush events
+* in the proper position before entering the noirq stage.
 */
wait_event(ec->wait, acpi_ec_query_flushed(ec));
if (ec_query_wq)
@@ -948,7 +953,8 @@ static void acpi_ec_start(struct acpi_ec *ec, bool resuming)
if (!resuming) {
acpi_ec_submit_request(ec);
ec_dbg_ref(ec, "Increase driver");
-   }
+   } else if (!acpi_ec_no_sleep_events())
+   __acpi_ec_enable_event(ec);
ec_log_drv("EC started");
}
spin_unlock_irqrestore(&ec->lock, flags);
@@ -980,7 +986,7 @@ static void acpi_ec_stop(struct acpi_ec *ec, bool 
suspending)
if (!suspending) {
acpi_ec_complete_request(ec);
ec_dbg_ref(ec, "Decrease driver");
-   } else if (!ec_freeze_events)
+   } else if (!acpi_ec_no_sleep_events())
__acpi_ec_disable_event(ec);
clear_bit(EC_FLAGS_STARTED, &ec->flags);
clear_bit(EC_FLAGS_STOPPED, &ec->flags);
@@ -1910,7 +1916,7 @@ static int acpi_ec_suspend(struct device *dev)
struct acpi_ec *ec =
acpi_driver_data(to_acpi_device(dev));
 
-   if (acpi_sleep_no_ec_events() && ec_freeze_events)
+   if (acpi_ec_no_sleep_events())
acpi_ec_disable_event(ec);
return 0;
 }
@@ -1946,7 +1952,18 @@ static int acpi_ec_resume(struct device *dev)
struct acpi_ec *ec =
acpi_driver_data(to_acpi_device(dev));
 
-   acpi_ec_enable_event(ec);
+   if (acpi_ec_no_sleep_events())
+   acpi_ec_enable_event(ec);
+   else {
+   /*
+* Though whether there is an event pending has been
+* checked in acpi_ec_unblock_transactions() when
+* acpi_ec_no_sleep_events

[RFC PATCH v6 2/3] ACPI / EC: Add event detection support for noirq stages

2017-09-28 Thread Lv Zheng
This patch adds a timer to poll EC events:
1. between acpi_ec_suspend() and acpi_ec_block_transactions(),
2. between acpi_ec_unblock_transactions() and acpi_ec_resume().
During these periods, if an EC event occurred, we have not mean to detect
it. Thus the events occurred in late S3-entry could be dropped, and the
events occurred in early S3-exit could be deferred to acpi_ec_resume().

This patch solves event losses in S3-entry and resume order in S3-exit by
timely polling EC events during these periods.

Link: https://bugzilla.kernel.org/show_bug.cgi?id=196129 [#1]
Signed-off-by: Lv Zheng 
Tested-by: Tomislav Ivek 
---
 drivers/acpi/ec.c   | 93 +++--
 drivers/acpi/internal.h |  1 +
 2 files changed, 92 insertions(+), 2 deletions(-)

diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index f1f320b..389c499 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -40,6 +40,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 
 #include "internal.h"
@@ -102,6 +103,7 @@ enum ec_command {
 #define ACPI_EC_CLEAR_MAX  100 /* Maximum number of events to query
 * when trying to clear the EC */
 #define ACPI_EC_MAX_QUERIES16  /* Maximum number of parallel queries */
+#define ACPI_EC_EVENT_INTERVAL 500 /* Detecting event every 500ms */
 
 enum {
EC_FLAGS_QUERY_ENABLED, /* Query is enabled */
@@ -113,6 +115,7 @@ enum {
EC_FLAGS_STARTED,   /* Driver is started */
EC_FLAGS_STOPPED,   /* Driver is stopped */
EC_FLAGS_GPE_MASKED,/* GPE masked */
+   EC_FLAGS_GPE_POLLING,   /* GPE polling is enabled */
 };
 
 #define ACPI_EC_COMMAND_POLL   0x01 /* Available for command byte */
@@ -154,6 +157,15 @@ static bool ec_no_wakeup __read_mostly;
 module_param(ec_no_wakeup, bool, 0644);
 MODULE_PARM_DESC(ec_no_wakeup, "Do not wake up from suspend-to-idle");
 
+static bool ec_detect_noirq_events __read_mostly;
+module_param(ec_detect_noirq_events, bool, 0644);
+MODULE_PARM_DESC(ec_detect_noirq_events, "Enabling event detection during 
noirq stage");
+
+static unsigned int
+ec_detect_noirq_interval __read_mostly = ACPI_EC_EVENT_INTERVAL;
+module_param(ec_detect_noirq_interval, uint, 0644);
+MODULE_PARM_DESC(ec_detect_noirq_interval, "Event detection interval(ms) 
during noirq stage");
+
 struct acpi_ec_query_handler {
struct list_head node;
acpi_ec_query_func func;
@@ -358,6 +370,48 @@ static inline bool acpi_ec_is_gpe_raised(struct acpi_ec 
*ec)
return (gpe_status & ACPI_EVENT_FLAG_STATUS_SET) ? true : false;
 }
 
+static void acpi_ec_gpe_tick(struct acpi_ec *ec)
+{
+   mod_timer(&ec->timer,
+ jiffies + msecs_to_jiffies(ec_detect_noirq_interval));
+}
+
+static void ec_start_gpe_poller(struct acpi_ec *ec)
+{
+   unsigned long flags;
+   bool start_tick = false;
+
+   if (!acpi_ec_no_sleep_events() || !ec_detect_noirq_events)
+   return;
+   spin_lock_irqsave(&ec->lock, flags);
+   if (!test_and_set_bit(EC_FLAGS_GPE_POLLING, &ec->flags)) {
+   ec_log_drv("GPE poller started");
+   start_tick = true;
+   /* kick off GPE polling without delay */
+   advance_transaction(ec);
+   }
+   spin_unlock_irqrestore(&ec->lock, flags);
+   if (start_tick)
+   acpi_ec_gpe_tick(ec);
+}
+
+static void ec_stop_gpe_poller(struct acpi_ec *ec)
+{
+   unsigned long flags;
+   bool stop_tick = false;
+
+   if (!acpi_ec_no_sleep_events() || !ec_detect_noirq_events)
+   return;
+   spin_lock_irqsave(&ec->lock, flags);
+   if (test_and_clear_bit(EC_FLAGS_GPE_POLLING, &ec->flags))
+   stop_tick = true;
+   spin_unlock_irqrestore(&ec->lock, flags);
+   if (stop_tick) {
+   del_timer_sync(&ec->timer);
+   ec_log_drv("GPE poller stopped");
+   }
+}
+
 static inline void acpi_ec_enable_gpe(struct acpi_ec *ec, bool open)
 {
if (open)
@@ -1017,6 +1071,12 @@ static void acpi_ec_leave_noirq(struct acpi_ec *ec)
spin_unlock_irqrestore(&ec->lock, flags);
 }
 
+/*
+ * Note: this API is prepared for tuning the order of the ACPI
+ * suspend/resume steps as the last entry of EC during suspend, thus it
+ * must be invoked after acpi_ec_suspend() or everything should be done in
+ * acpi_ec_suspend().
+ */
 void acpi_ec_block_transactions(void)
 {
struct acpi_ec *ec = first_ec;
@@ -1028,16 +1088,28 @@ void acpi_ec_block_transactions(void)
/* Prevent transactions from being carried out */
acpi_ec_stop(ec, true);
mutex_unlock(&ec->mutex);
+   ec_stop_gpe_poller(ec);
 }
 
+/*
+ * Note: this API is prepared for tuning the order of the ACPI
+ * suspend/re

[RFC PATCH v6 3/3] ACPI / EC: Enable noirq stage event detection

2017-09-28 Thread Lv Zheng
This patch enables noirq stage event detection for the EC driver.

EC is a very special driver, required to detecting events throughout the
entire suspend/resume process. Thus this patch enables event detection for
EC during noirq stages to meet this requirement. This is done by making
sure that the EC sleep APIs:
  acpi_ec_block_transactions()
  acpi_ec_unblock_transactions()
rather than the EC driver suspend/resume hooks:
  acpi_ec_suspend()
  acpi_ec_resume()
are the boundary of the EC event handling during suspend/resume, so that
the ACPI sleep core can tune their invocation timing to handle special BIOS
requirements.

If this commit is bisected to be a regression culprit, please report this
to bugzilla.kernel.org for further investigation.

Link: https://bugzilla.kernel.org/show_bug.cgi?id=196129
Signed-off-by: Lv Zheng 
Tested-by: Tomislav Ivek 
---
 drivers/acpi/ec.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 389c499..a48a2b3 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -157,7 +157,7 @@ static bool ec_no_wakeup __read_mostly;
 module_param(ec_no_wakeup, bool, 0644);
 MODULE_PARM_DESC(ec_no_wakeup, "Do not wake up from suspend-to-idle");
 
-static bool ec_detect_noirq_events __read_mostly;
+static bool ec_detect_noirq_events __read_mostly = true;
 module_param(ec_detect_noirq_events, bool, 0644);
 MODULE_PARM_DESC(ec_detect_noirq_events, "Enabling event detection during 
noirq stage");
 
-- 
2.7.4



[PATCH 2/2] ACPI / EC: Fix a regression related to the PM ops support of ECDT device

2017-09-26 Thread Lv Zheng
On platforms (ASUS X550ZE and possibly all ASUS X series) with valid ECDT
EC but invalid DSDT EC, EC PM ops won't be invoked as ECDT EC is not an
ACPI device. Thus the following commit actually removed post-resume
acpi_ec_enable_event() invocation for such platforms, and triggered a
regression on them that after being resumed, EC (actually should be ECDT)
driver stops handling EC events:
 Commit: c2b46d679b30c5c0d7eb47a21085943242bdd8dc
 Subject: ACPI / EC: Add PM operations to improve event handling for resume 
process
Notice that the root cause actually is "ECDT is not an ACPI device" rather
than "the timing of acpi_ec_enable_event() invocation", this patch fixes
this issue by enumerating ECDT EC as an ACPI device. Due to the existence
of the noirq stage, the ability of tuning the timing of
acpi_ec_enable_event() invocation is still meaningful.

This patch is a little bit different from the posted fix by moving
acpi_config_boot_ec() from acpi_ec_ecdt_start() to acpi_ec_add() to make
sure that EC event handling won't be stopped as long as the ACPI EC driver
is bound. Thus the following sequence shouldn't disable EC event handling:
unbind,suspend,resume,bind.

Fixes: c2b46d679b30 (ACPI / EC: Add PM operations to improve event handling for 
resume process)
Link: https://bugzilla.kernel.org/show_bug.cgi?id=196847
Reported-by: Luya Tshimbalanga 
Tested-by: Luya Tshimbalanga 
Cc: 4.9+  # 4.9+
Signed-off-by: Lv Zheng 
---
 drivers/acpi/ec.c   | 69 +
 drivers/acpi/internal.h |  1 +
 drivers/acpi/scan.c | 21 ++
 include/acpi/acpi_bus.h |  1 +
 include/acpi/acpi_drivers.h |  1 +
 5 files changed, 69 insertions(+), 24 deletions(-)

diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 82b3ce5..df84246 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -1597,32 +1597,41 @@ static int acpi_ec_add(struct acpi_device *device)
 {
struct acpi_ec *ec = NULL;
int ret;
+   bool is_ecdt = false;
+   acpi_status status;
 
strcpy(acpi_device_name(device), ACPI_EC_DEVICE_NAME);
strcpy(acpi_device_class(device), ACPI_EC_CLASS);
 
-   ec = acpi_ec_alloc();
-   if (!ec)
-   return -ENOMEM;
-   if (ec_parse_device(device->handle, 0, ec, NULL) !=
-   AE_CTRL_TERMINATE) {
+   if (!strcmp(acpi_device_hid(device), ACPI_ECDT_HID)) {
+   is_ecdt = true;
+   ec = boot_ec;
+   } else {
+   ec = acpi_ec_alloc();
+   if (!ec)
+   return -ENOMEM;
+   status = ec_parse_device(device->handle, 0, ec, NULL);
+   if (status != AE_CTRL_TERMINATE) {
ret = -EINVAL;
goto err_alloc;
+   }
}
 
if (acpi_is_boot_ec(ec)) {
-   boot_ec_is_ecdt = false;
-   /*
-* Trust PNP0C09 namespace location rather than ECDT ID.
-*
-* But trust ECDT GPE rather than _GPE because of ASUS quirks,
-* so do not change boot_ec->gpe to ec->gpe.
-*/
-   boot_ec->handle = ec->handle;
-   acpi_handle_debug(ec->handle, "duplicated.\n");
-   acpi_ec_free(ec);
-   ec = boot_ec;
-   ret = acpi_config_boot_ec(ec, ec->handle, true, false);
+   boot_ec_is_ecdt = is_ecdt;
+   if (!is_ecdt) {
+   /*
+* Trust PNP0C09 namespace location rather than
+* ECDT ID. But trust ECDT GPE rather than _GPE
+* because of ASUS quirks, so do not change
+* boot_ec->gpe to ec->gpe.
+*/
+   boot_ec->handle = ec->handle;
+   acpi_handle_debug(ec->handle, "duplicated.\n");
+   acpi_ec_free(ec);
+   ec = boot_ec;
+   }
+   ret = acpi_config_boot_ec(ec, ec->handle, true, is_ecdt);
} else
ret = acpi_ec_setup(ec, true);
if (ret)
@@ -1635,8 +1644,10 @@ static int acpi_ec_add(struct acpi_device *device)
ret = !!request_region(ec->command_addr, 1, "EC cmd");
WARN(!ret, "Could not request EC cmd io port 0x%lx", ec->command_addr);
 
-   /* Reprobe devices depending on the EC */
-   acpi_walk_dep_device_list(ec->handle);
+   if (!is_ecdt) {
+   /* Reprobe devices depending on the EC */
+   acpi_walk_dep_device_list(ec->handle);
+   }
acpi_handle_debug(ec->handle, "enumerated.\n");
return 0;
 
@@ -1692,6 +1703,7 @@ ec_parse_io_ports(struct acpi_resource *resource, void 
*context)
 
 static const struct acpi_devi

[PATCH 1/2] ACPI / EC: Fix a regression related to the triggering source of the EC event handling

2017-09-26 Thread Lv Zheng
Originally the Samsung quirks removed by commit 4c237371 can be covered by
commit e923e8e7 and ec_freeze_events=Y mode. But commit 9c40f956 changed
ec_freeze_events=Y back to N, making this problem re-surfaced.
Actually, if commit e923e8e7 is robust enough, we can freely change
ec_freeze_events mode, so this patch fixes the issue by improving
commit e923e8e7.

Related commits listed in the merged order:
 Commit: e923e8e79e18fd6be9162f1be6b99a002e9df2cb
 Subject: ACPI / EC: Fix an issue that SCI_EVT cannot be detected after
  event is enabled
 Commit: 4c237371f290d1ed3b2071dd43554362137b1cce
 Subject: ACPI / EC: Remove old CLEAR_ON_RESUME quirk
 Commit: 9c40f956ce9b331493347d1b3cb7e384f7dc0581
 Subject: Revert "ACPI / EC: Enable event freeze mode..." to fix a
  regression

This patch not only fixes the reported post-resume EC event triggering
source issue, but also fixes an unreported similar issue related to the
driver bind by adding EC event triggering source in ec_install_handlers().

Fixes: e923e8e79e18 (ACPI / EC: Fix an issue that SCI_EVT cannot be detected 
after event is enabled)
Fixes: 4c237371f290 (ACPI / EC: Remove old CLEAR_ON_RESUME quirk)
Fixes: 9c40f956ce9b (Revert "ACPI / EC: Enable event freeze mode..." to fix a 
regression)
Link: https://bugzilla.kernel.org/show_bug.cgi?id=196833
Signed-off-by: Lv Zheng 
Reported-by: Alistair Hamilton 
Tested-by: Alistair Hamilton 
Cc: 4.11+  # 4.11+
---
 drivers/acpi/ec.c | 12 +++-
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 236b143..82b3ce5 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -486,8 +486,11 @@ static inline void __acpi_ec_enable_event(struct acpi_ec 
*ec)
 {
if (!test_and_set_bit(EC_FLAGS_QUERY_ENABLED, &ec->flags))
ec_log_drv("event unblocked");
-   if (!test_bit(EC_FLAGS_QUERY_PENDING, &ec->flags))
-   advance_transaction(ec);
+   /*
+* Unconditionally invoke this once after enabling the event
+* handling mechanism to detect the pending events.
+*/
+   advance_transaction(ec);
 }
 
 static inline void __acpi_ec_disable_event(struct acpi_ec *ec)
@@ -1456,11 +1459,10 @@ static int ec_install_handlers(struct acpi_ec *ec, bool 
handle_events)
if (test_bit(EC_FLAGS_STARTED, &ec->flags) &&
ec->reference_count >= 1)
acpi_ec_enable_gpe(ec, true);
-
-   /* EC is fully operational, allow queries */
-   acpi_ec_enable_event(ec);
}
}
+   /* EC is fully operational, allow queries */
+   acpi_ec_enable_event(ec);
 
return 0;
 }
-- 
2.7.4



[PATCH 0/2] ACPI / EC: EC regression fixes related to EC event stuck

2017-09-26 Thread Lv Zheng
There are 2 regressions reported on bugzilla.
 Link: https://bugzilla.kernel.org/show_bug.cgi?id=196847 [#1]
 Link: https://bugzilla.kernel.org/show_bug.cgi?id=196833 [#2]
It looks they are related to the modification against the timing of
acpi_ec_enable_event() invocation, but they are all due to different root
causes.

For link 1, its root cause is: we rely on acpi_ec_suspend/resume() to
control the timing of EC event handling enablement, but ECDT is not an
ACPI device, thus the PM hooks are not invoked for it.
For link 2, reporter seems to favor a fix that can fix both of the
problems:
1. EC event can stuck if there is no triggering source.
2. Post-resume enabling of EC event handling may be too late.
But actually the report is only against problem 1 which is known to have a
very low and accepted reproduce ratio.

For problem 2, it should has a sympton related to the driver resume order
rather than EC event stuck. And its fix should be acpi.ec_freeze_events=Y
related. Note acpi.ec_freeze_events=Y is a feature we need to keep for
now as:
1. It's reasonable for EC driver to act as an agent for EC event
   handling while EC transaction is handled by ACPI core handler, thus
   1.1. unbind/suspend means suspending EC event handling;
   1.2. bind/resume means resuming EC event handling.
2. According to the known EC FW facts, it takes time for EC FW to
   initialize after boot/resume.

This patchset fixes the root causes of the 2 regressions and keeps the
possibility of tuning acpi.ec_freeze_events=Y. Note that PATCH 02
depends on PATCH 01 to be safe for driver unbind.

Lv Zheng (2):
  ACPI / EC: Fix a regression related to the triggering source of the EC
event handling
  ACPI / EC: Fix a regression related to the PM ops support of ECDT
device

 drivers/acpi/ec.c   | 81 +
 drivers/acpi/internal.h |  1 +
 drivers/acpi/scan.c | 21 
 include/acpi/acpi_bus.h |  1 +
 include/acpi/acpi_drivers.h |  1 +
 5 files changed, 76 insertions(+), 29 deletions(-)

-- 
2.7.4



[PATCH] tools/power/acpi: Add multi-threading test facility

2017-09-07 Thread Lv Zheng
This script extends testability of the Linux ACPI subsystem.

It is reported by QA teams that using the known validation tools, there are
still modules in the ACPI subsystem have low test coverage.

We confirmed that the coverage can be increased by doing more following
tests:
1. dynamic module load/unload, and
2. sysfs/proc_fs file accesses, and
3. etc.
Actually, performing such stuffs once or single-threaded won't prove
quality status to us, multi-threading testability is needed for these
validations.

This patch adds a test facility so that validators can use it to
launch multi-threading ACPI transactions to test Linux ACPI subsystem
viability under a stressed multi-threading environment.

The following commands demonstrate possible multi-threading tests:
1. Test dynamic load of button driver:
  sudo tools/power/acpi/acpimt.sh \
-t 10 \
-d tools/power/acpi/acpidbg \
-e _SB.PCI0.SBRG.LID0._LID \
-f /proc/acpi/button/lid/LID0/state \
-m button
2. Test method customization:
  sudo tools/power/acpi/acpimt.sh \
-t 10 \
-d tools/power/acpi/acpidbg \
-e _SB.PCI0.SBRG.LID0._LID \
-c oem1.aml
3. Stress ACPI EC loads:
  sudo tools/power/acpi/acpimt.sh \
-t 10 \
-d tools/power/acpi/acpidbg \
-f /proc/acpi/button/lid/LID0/state \
-f /sys/class/power_supply/AC0/online \
-f /sys/class/power_supply/BAT0/status

Signed-off-by: Lv Zheng 
---
 tools/power/acpi/acpimt.sh | 337 +
 1 file changed, 337 insertions(+)
 create mode 100755 tools/power/acpi/acpimt.sh

diff --git a/tools/power/acpi/acpimt.sh b/tools/power/acpi/acpimt.sh
new file mode 100755
index 000..3491dd7
--- /dev/null
+++ b/tools/power/acpi/acpimt.sh
@@ -0,0 +1,337 @@
+#!/bin/bash
+#
+# Copyright (C) 2017 Intel Corporation
+# Author: 2017 Lv Zheng 
+#
+# NAME:
+# acpimt.sh - launch multi-threads running Linux kernel ACPI
+# transactions
+#
+# SYNOPSIS:
+# acpimt.sh [-c amlfile]
+#   [-e acpiname]
+#   [-f acpifile]
+#   [-m kernel_module]
+#   [-d acpidbg] [-t seconds]
+#
+# DESCRIPTION:
+# This program is used as a test facility validating multi-thread
+# support in Linux ACPI subsystem. It can launch ACPI transactions
+# as test cases using child processes and executes them in parallel
+# endlessly. Test processes can be terminated by Ctrl-C.
+#
+# The launchable tests can be:
+#  -c: Use /sys/kernel/debug/acpi/custom_method to customize
+#  control methods (CONFIG_ACPI_CUSTOM_METHOD) repeatedly.
+#  -e: Use acpidbg to evaluate a named object w/o arguments
+#  (CONFIG_ACPI_DEBUGGER_USER) repeatedly.
+#  -f: Use cat to read a sysfs/procfs file repeatedly.
+#  -m: Use modprobe to load/unload a module repeatedly.
+#
+# Options:
+#  -d: Full path to acpidbg (in case it cannot be reached via
+#  %PATH%.
+#  -t: Seconds to sleep between test operations.
+
+
+# Global Settings
+
+SLEEPSEC=10
+TEMPFILE=`mktemp`
+ACPIDBG=acpidbg
+ACPINAMES=
+ACPIFILES=
+AMLFILES=
+KERNMODS=
+
+
+# Usages
+
+usage() {
+   echo "Usage: `basename $0` [-d acpidbg] [-t second]"
+   echo " [-c amlfile]"
+   echo " [-e acpiname]"
+   echo " [-f acpifile]"
+   echo " [-m kernel_module]"
+   echo ""
+   echo "This program is used as a test facility validating multi-thread"
+   echo "support in Linux ACPI subsystem. It can launch ACPI transactions"
+   echo "as test cases using child processes and executes them in parallel"
+   echo "endlessly. Test processes can be terminated by Ctrl-C."
+   echo ""
+   echo "Test cases are:"
+   echo "-c: Use /sys/kernel/debug/acpi/custom_method to customize"
+   echo "control methods (CONFIG_ACPI_CUSTOM_METHOD) repeatedly."
+   echo "-e: Use acpidbg to evaluate a named object w/o arguments"
+   echo "(CONFIG_ACPI_DEBUGGER_USER) repeatedly."
+   echo "-f: Use cat to read a sysfs/procfs file repeatedly."
+   echo "-m: Use modprobe to load/unload a module repeatedly."
+   echo ""
+   echo "Options are:"
+   echo "-d: Full path to acpidbg (in case it cannot be reached via"
+   echo "  

[PATCH v4 2/3] ACPI / EC: Add event detection support for noirq stages

2017-08-31 Thread Lv Zheng
1. Problems: Cannot detect EC event in noirq stages.
EC IRQs contain transaction IRQs (OBF/IBF) and event IRQ (SCI_EVT).
Transactions are initiated by hosts. The earliest OSPMs execution of EC
transactions is from acpi_ec_transaction(), where the common EC IRQ
handling procedure - advance_transaction() - is initiated from the task
context.
Events are initiated by targets. The earliest OSPMs execution of EC events
is from acpi_ec_gpe_handler(), where the common EC IRQ handling procedure -
advance_transaction() - is initiated from the IRQ context.
During suspend/resume noirq stage, IRQ is disabled, advance_transaction()
which detects SCI_EVT can only be invoked from task context - ec_poll().
Thus if there is no EC transaction occurring in this stage, EC driver
cannot detect SCI_EVT. And the worst case is if there is no EC transaction
after resume, EC event handling will stuck (FW flags SCI_EVT, but there is
no triggering source for OS to detect it).
Note that in noirq stage if there is an EC transaction pending,
advance_transaction() invoked because of the EC transaction can also help
to detect SCI_EVT and initiate the handling of the EC events. That's why
real reports related to this problem are rare and unreproducible as whether
there is an EC transaction occurred after an undetectable EC events during
noirq stages is random.

2. Old assumption and solution:
In order to solve the above issue, "ec_freeze_events" is implemented to:
stop handling SCI_EVT before suspend noirq stage and restart handling
SCI_EVT after resume noirq stage.
We assumed that detecting SCI_EVT in noirq stage is useless because there
are other conflict issues related to the EC event handling actually making
it not fully functioning during suspend/resume.
This assumption and the solution efficiently solves all issues.
Finally, the EC event handling is namely "frozen" for a specific period
during suspend/resume and "ec_freeze_events" controls the timing of the
"begin/end of the freeze". If freezing event handling earlier could work,
we shouldn't be required to implement event detection in noirq stages.

3. New facts and new problems:
Recently, some bug reports (see Link #1) revealed that we shouldn't
"freeze" EC event handling too early during these system suspend/resume
procedures.
Also enabling EC event handling too late surely changes the event
triggering timing, and may leave driver order issues during resume.
The previous commit in the same series resumes EC event handling earlier in
acpi_ec_unblock_transactions(), but that still leaves another problem to us
that we still cannot detect SCI_EVT occurred after
acpi_ec_unblock_transactions() and before acpi_ec_resume(). In order to
solve the final gap, we need to implement event detection in noirq stages.

4. New solution:
This patch adds a timer to poll EC events timely (0.5s) during system
suspend/resume noirq stages.
This patch has been validated to be able to improve situation related to
the reported bug (see Link #1) which requires to handle EC GPEs longer
during suspend.
With this patch applied, ACPI sleep core may still need to tune the order
of sleep steps by tuning the timing of invoking
acpi_ec_block/unblock_transactions() to fully solve the reported issue.
Actually ec_detect_noirq_events should always be true when ec_freeze_events
is false. But since there could be no noirq stage affection, this patch
introduces a separate runtime configurable option for it so that we can
disable it when there is no affection of the noirq stage.

Link: https://bugzilla.kernel.org/show_bug.cgi?id=196129 [#1]
Signed-off-by: Lv Zheng 
Tested-by: Tomislav Ivek 
---
 drivers/acpi/ec.c   | 93 +++--
 drivers/acpi/internal.h |  1 +
 2 files changed, 92 insertions(+), 2 deletions(-)

diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 3dc4205..9363656 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -40,6 +40,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 
 #include "internal.h"
@@ -102,6 +103,7 @@ enum ec_command {
 #define ACPI_EC_CLEAR_MAX  100 /* Maximum number of events to query
 * when trying to clear the EC */
 #define ACPI_EC_MAX_QUERIES16  /* Maximum number of parallel queries */
+#define ACPI_EC_EVENT_INTERVAL 500 /* Detecting event every 500ms */
 
 enum {
EC_FLAGS_QUERY_ENABLED, /* Query is enabled */
@@ -113,6 +115,7 @@ enum {
EC_FLAGS_STARTED,   /* Driver is started */
EC_FLAGS_STOPPED,   /* Driver is stopped */
EC_FLAGS_GPE_MASKED,/* GPE masked */
+   EC_FLAGS_GPE_POLLING,   /* GPE polling is enabled */
 };
 
 #define ACPI_EC_COMMAND_POLL   0x01 /* Available for command byte */
@@ -154,6 +157,15 @@ static bool ec_no_wakeup __read_mostly;
 module_param(ec_no_wakeup, bool, 

[PATCH v4 3/3] ACPI / EC: Enable noirq stage event detection

2017-08-31 Thread Lv Zheng
This patch enables noirq stage event detection for the EC driver.

EC is a very special driver, required to detecting events throughout the
entire suspend/resume process. Thus this patch enables event detection for
EC during noirq stages to meet this requirement. This is done by making
sure that the EC sleep APIs:
  acpi_ec_block_transactions()
  acpi_ec_unblock_transactions()
rather than the EC driver suspend/resume hooks:
  acpi_ec_suspend()
  acpi_ec_resume()
are the boundary of the EC event handling during suspend/resume, so that
the ACPI sleep core can tune their invocation timing to handle special BIOS
requirements.

If this commit is bisected to be a regression culprit, please report this
to bugzilla.kernel.org for further investigation.

Link: https://bugzilla.kernel.org/show_bug.cgi?id=196129
Signed-off-by: Lv Zheng 
Tested-by: Tomislav Ivek 
---
 drivers/acpi/ec.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 9363656..36ce5e7 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -157,7 +157,7 @@ static bool ec_no_wakeup __read_mostly;
 module_param(ec_no_wakeup, bool, 0644);
 MODULE_PARM_DESC(ec_no_wakeup, "Do not wake up from suspend-to-idle");
 
-static bool ec_detect_noirq_events __read_mostly;
+static bool ec_detect_noirq_events __read_mostly = true;
 module_param(ec_detect_noirq_events, bool, 0644);
 MODULE_PARM_DESC(ec_detect_noirq_events, "Enabling event detection during 
noirq stage");
 
-- 
2.7.4



[PATCH v4 1/3] ACPI / EC: Fix possible driver order issue by moving EC event handling earlier

2017-08-31 Thread Lv Zheng
This patch tries to detect EC events earlier after resume, so that if an
event occurred before invoking acpi_ec_unblock_transactions(), it could be
detected by acpi_ec_unblock_transactions() which is the earliest EC driver
call after resume.

However after the noirq stage, if an event ocurred after
acpi_ec_unblock_transactions() and before acpi_ec_resume(), there was no
mean to detect and trigger it, finally it could cause EC event handling
stuck. Thus this patch also adds a detection in acpi_ec_resume(), trying to
recover from the affection of the noirq stage.

The background of the affection:
  EC IRQs contain transaction IRQs (OBF/IBF) and event IRQ (SCI_EVT).
  1. Transactions are initiated by hosts. The earliest OSPMs execution of
 EC transactions is from acpi_ec_transaction(), where the common EC IRQ
 handling procedure - advance_transaction() - is initiated from the
 task context.
  2. Events are initiated by targets. The earliest OSPMs execution of EC
 events is from acpi_ec_gpe_handler(), where the common EC IRQ handling
 procedure - advance_transaction() - is initiated from the IRQ context.
  During suspend/resume noirq stage, IRQ is disabled, advance_transaction()
  which detects SCI_EVT can only be invoked from task context - ec_poll().
  Thus if there is no EC transaction occurring in this stage, EC driver
  cannot detect SCI_EVT. And the worst case is if there is no EC
  transaction after resume, EC event handling will stuck (FW flags SCI_EVT,
  but there is no triggering source for OS SW to detect it).

Now the final logic is:
1. If ec_freeze_events=Y, event handling is stopped in acpi_ec_suspend(),
   restarted in acpi_ec_resume();
2. If ec_freeze_events=N, event handling is stopped in
   acpi_ec_block_transactions(), restarted in
   acpi_ec_unblock_transactions();
3. In order to handling the conflict of the edge-trigger nature of EC IRQ
   and the Linux noirq stage, advance_transaction() is invoked where the
   event handling is enabled and the noirq stage is ended.

Known issue:
1. Event ocurred between acpi_ec_unblock_transactions() and
   acpi_ec_resume() may still lead to the order issue. This can only be
   fixed by adding a periodic detection mechanism during the noirq stage.

Signed-off-by: Lv Zheng 
Tested-by: Tomislav Ivek 
---
 drivers/acpi/ec.c | 23 +++
 1 file changed, 19 insertions(+), 4 deletions(-)

diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index fdfae6f..3dc4205 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -486,8 +486,11 @@ static inline void __acpi_ec_enable_event(struct acpi_ec 
*ec)
 {
if (!test_and_set_bit(EC_FLAGS_QUERY_ENABLED, &ec->flags))
ec_log_drv("event unblocked");
-   if (!test_bit(EC_FLAGS_QUERY_PENDING, &ec->flags))
-   advance_transaction(ec);
+   /*
+* Unconditionally invoke this once after enabling the event
+* handling mechanism to detect the pending events.
+*/
+   advance_transaction(ec);
 }
 
 static inline void __acpi_ec_disable_event(struct acpi_ec *ec)
@@ -945,7 +948,8 @@ static void acpi_ec_start(struct acpi_ec *ec, bool resuming)
if (!resuming) {
acpi_ec_submit_request(ec);
ec_dbg_ref(ec, "Increase driver");
-   }
+   } else if (!ec_freeze_events)
+   __acpi_ec_enable_event(ec);
ec_log_drv("EC started");
}
spin_unlock_irqrestore(&ec->lock, flags);
@@ -1929,7 +1933,18 @@ static int acpi_ec_resume(struct device *dev)
struct acpi_ec *ec =
acpi_driver_data(to_acpi_device(dev));
 
-   acpi_ec_enable_event(ec);
+   if (ec_freeze_events)
+   acpi_ec_enable_event(ec);
+   else {
+   /*
+* Though whether there is an event pending has been
+* checked in acpi_ec_unblock_transactions() when
+* ec_freeze_events=N, check it one more time after noirq
+* stage to detect events occurred after
+* acpi_ec_unblock_transactions().
+*/
+   advance_transaction(ec);
+   }
return 0;
 }
 #endif
-- 
2.7.4



[PATCH v4 0/3] ACPI / EC: Fix EC event handling issues

2017-08-31 Thread Lv Zheng
EC events are special, required to be handled during suspend/resume. But
there are special logics in Linux causing several issues related to the EC
event handling:
1. During noirq stage, Linux cannot detect EC events which are target
   driven.
2. When EC event handling is enabled later than the other drivers, order
   problem could be observed.
When fixing these problems, care should be taken to not to trigger
regressions to the following problem which has alredy been fixed using
different approach):
3. When EC event handling is enabled before the end of the noirq stage,
   EC event handling may stuck.
This patchset fixes these issues.

v4 of this patch series re-orders the fixes so that the fix of the problem
2 could be independent against the fix of the problem 1, this is done by
refining the fix of the problem 2, making it immune to the problem 3.

Lv Zheng (3):
  ACPI / EC: Fix possible driver order issue by moving EC event handling
earlier
  ACPI / EC: Add event detection support for noirq stages
  ACPI / EC: Enable noirq stage event detection

 drivers/acpi/ec.c   | 116 +---
 drivers/acpi/internal.h |   1 +
 2 files changed, 111 insertions(+), 6 deletions(-)

-- 
2.7.4



[PATCH v3 4/4] ACPI / EC: Enable noirq stage GPE polling

2017-08-10 Thread Lv Zheng
This patch enables noirq stage GPE polling for the EC driver.

EC is a very special driver, required to work throughout the entire
suspend/resume process. Thus this patch enables IRQ polling for EC during
noirq stages to avoid all kinds of possible issues.

If this commit is bisected to be a regression culprit, please report this
to bugzilla.kernel.org for further investigation.

Link: https://bugzilla.kernel.org/show_bug.cgi?id=196129
Signed-off-by: Lv Zheng 
Tested-by: Tomislav Ivek 
---
 drivers/acpi/ec.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 396e81d..8bba317 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -164,7 +164,7 @@ module_param(ec_polling_guard, uint, 0644);
 MODULE_PARM_DESC(ec_polling_guard, "Guard time(us) between EC accesses in 
polling modes");
 
 static unsigned int ec_event_clearing __read_mostly = ACPI_EC_EVT_TIMING_QUERY;
-static unsigned int ec_gpe_polling __read_mostly = ACPI_EC_GPE_POLL_NONE;
+static unsigned int ec_gpe_polling __read_mostly = ACPI_EC_GPE_POLL_RESUME;
 
 /*
  * If the number of false interrupts per one transaction exceeds
-- 
2.7.4



[PATCH v3 2/4] ACPI / EC: Add IRQ polling support for noirq stages

2017-08-10 Thread Lv Zheng
1. Problems:
1.1. Problem 1: Cannot detect EC event in noirq stages.
EC IRQs contain transaction IRQs (OBF/IBF) and event IRQ (SCI_EVT).

Transactions are initiated by hosts. The earliest OSPMs execution of EC
transactions is from acpi_ec_transaction(), where the common EC IRQ
handling procedure - advance_transaction() - is initiated from the task
context.
Events are initiated by targets. The earliest OSPMs execution of EC events
is from acpi_ec_gpe_handler(), where the common EC IRQ handling procedure -
advance_transaction() - is initiated from the IRQ context.

During suspend/resume noirq stage, IRQ is disabled, advance_transaction()
which detects SCI_EVT can only be invoked from task context - ec_poll().
Thus if there is no EC transaction occurring in this stage, EC driver
cannot detect SCI_EVT.

Note that in noirq stage if there is an EC transaction pending,
advance_transaction() invoked because of the EC transaction can also help
to detect SCI_EVT and initiate the handling of the EC events. That's why
real reports related to this problem are rare and unreproducible as whether
there is an EC transaction occurred after an undetectable EC events during
noirq stages is random.

1.2. Problem 2: Handling of EC events may stuck for some GPE chips.
When IRQ already occurred in the underlying hardware and flagged the IRQ
status bit, enabling IRQ by flagging the IRQ enable bit may not be
sufficient to trigger edge-triggered IRQs on some IRQ silicons (let me
call these IRQ silicons as buggy to make description simpler).

Then, when EC GPE events already occurred in resume noirq stage leaving GPE
STS bit set, EC GPE may not be delivered to the CPU when EC driver
re-enables EC GPE by flagging GPE EN bit. And even worse, after this
enabling, if there is no EC transaction occurred, EC events can never be
detected again, and handling of EC events "stucks".

Note that if the upper layer IRQ silicons (APIC and etc.) and GPE IRQ
silicons are not buggy, we needn't worry about this problem. That's why the
real reports related to this problem are rare and always platform specific.

2. Old assumption and solution:
In order to solve the above issues, "ec_freeze_events" is implemented to:
A. Stop handling SCI_EVT before suspend noirq stage:
   As EC driver actually has never been fully able to handle EC events
   during noirq stages, we assumed that detecting such events in noirq
   stage is useless and thus we needn't worry about problem 1.
B. Re-start handling SCI_EVT after resume noirq stage:
   By always setting EN after resume noirq stage, it is ensured that:
   a. whatever upper layer IRQ silicons (APIC and etc.) are buggy or not,
  they won't cause problem 2, and
   b. non buggy GPE IRQ silicons won't cause problem 2, but buggy GPE IRQ
  silicons may still cause problem 2.
By narrowing down the EC event handling period during suspend/resume, we
can see that the occurring ratio of problem 2 can be reduced, only buggy
GPE IRQ silicons can still trigger problem 2.

Finally, the EC event handling is namely "frozen" for a specific period
during suspend/resume and "ec_freeze_events" controls the timing of the
"begin/end of the freeze". If freezing event handling earlier could work,
we shouldn't be required to implement GPE polling in noirq stages.

Note that this solution cannot fully solve problem 2 and solves problem 1
with assumptions.

3. New facts and solution:
Recently, some bug reports (see Link #1) revealed that we shouldn't
"freeze" EC event handling too early during these system suspend/resume
procedures.
Also enabling EC event handling too late surely changes the event
triggering timing, and may leave driver order issues during resume.

Based on these facts, we should detect SCI_EVT during noirq stage, this
left us no other choice than implementing IRQ polling for SCI_EVT in noirq
stages.

This patch adds a timer to poll EC events timely (0.5s) during system
suspend/resume noirq stages. To be regression safer, this patch also
prepares an option to make this behavior configurable.

Note that this solution can perfectly solve problem 1 and problem 2.

This patch has been validated to be able to improve situation related to
the reported bug (see Link #1) which requires to handle EC GPEs longer
during suspend.

Link: https://bugzilla.kernel.org/show_bug.cgi?id=196129 [#1]
Signed-off-by: Lv Zheng 
Tested-by: Tomislav Ivek 
---
 drivers/acpi/ec.c   | 130 
 drivers/acpi/internal.h |   1 +
 2 files changed, 131 insertions(+)

diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index d338f40..5be62933 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -40,6 +40,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 
 #include "internal.h"
@@ -87,6 +88,31 @@
 #define ACPI_EC_EVT_TIMING_QUERY   0x01
 #define ACPI_EC_EVT_TIMING_EVENT

[PATCH v3 0/4] ACPI / EC: Poll more EC events during suspend/resume

2017-08-10 Thread Lv Zheng
EC events are special, required to be handled during suspend/resume. But
there is a problem preventing EC events from being detected during noirq
stages.
This patchset fixes this issue by polling EC IRQs timely during
suspend/resume noirq stages.
With this issue fixed, we should be able to handler EC events earlier
during resume, and have great opportunities to fix some driver order
issues caused by the deferred detected EC events.

v3 of this patch series only contains patch description updates.

Lv Zheng (4):
  ACPI / EC: Cleanup EC GPE mask flag
  ACPI / EC: Add IRQ polling support for noirq stages
  ACPI / EC: Add support to handle EC events earlier
  ACPI / EC: Enable noirq stage GPE polling

 drivers/acpi/ec.c   | 157 
 drivers/acpi/internal.h |   1 +
 2 files changed, 145 insertions(+), 13 deletions(-)

-- 
2.7.4



[PATCH v3 3/4] ACPI / EC: Add support to handle EC events earlier

2017-08-10 Thread Lv Zheng
Now as GPE poller is implemented, EC driver is able to detect EC events
during suspend/resume noirq stages, we can try to move EC event handling
earlier without being worried about post-resume event stuck. This may help
to solve driver order issues during resume.

Signed-off-by: Lv Zheng 
Tested-by: Tomislav Ivek 
---
 drivers/acpi/ec.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 5be62933..396e81d 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -1016,7 +1016,9 @@ static void acpi_ec_start(struct acpi_ec *ec, bool 
resuming)
if (!resuming) {
acpi_ec_submit_request(ec);
ec_dbg_ref(ec, "Increase driver");
-   }
+   } else if (!ec_freeze_events &&
+  ec_gpe_polling == ACPI_EC_GPE_POLL_RESUME)
+   __acpi_ec_enable_event(ec);
ec_log_drv("EC started");
}
spin_unlock_irqrestore(&ec->lock, flags);
-- 
2.7.4



[PATCH v3 1/4] ACPI / EC: Cleanup EC GPE mask flag

2017-08-10 Thread Lv Zheng
EC_FLAGS_COMMAND_STORM is actually used to mask GPE during IRQ processing.
This patch cleans it up using more readable flag/function names.

Signed-off-by: Lv Zheng 
Tested-by: Tomislav Ivek 
---
 drivers/acpi/ec.c | 23 +++
 1 file changed, 11 insertions(+), 12 deletions(-)

diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 62068a5..d338f40 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -112,8 +112,7 @@ enum {
EC_FLAGS_EVT_HANDLER_INSTALLED, /* _Qxx handlers installed */
EC_FLAGS_STARTED,   /* Driver is started */
EC_FLAGS_STOPPED,   /* Driver is stopped */
-   EC_FLAGS_COMMAND_STORM, /* GPE storms occurred to the
-* current command processing */
+   EC_FLAGS_GPE_MASKED,/* GPE masked */
 };
 
 #define ACPI_EC_COMMAND_POLL   0x01 /* Available for command byte */
@@ -425,19 +424,19 @@ static void acpi_ec_complete_request(struct acpi_ec *ec)
wake_up(&ec->wait);
 }
 
-static void acpi_ec_set_storm(struct acpi_ec *ec, u8 flag)
+static void acpi_ec_mask_gpe(struct acpi_ec *ec)
 {
-   if (!test_bit(flag, &ec->flags)) {
+   if (!test_bit(EC_FLAGS_GPE_MASKED, &ec->flags)) {
acpi_ec_disable_gpe(ec, false);
ec_dbg_drv("Polling enabled");
-   set_bit(flag, &ec->flags);
+   set_bit(EC_FLAGS_GPE_MASKED, &ec->flags);
}
 }
 
-static void acpi_ec_clear_storm(struct acpi_ec *ec, u8 flag)
+static void acpi_ec_unmask_gpe(struct acpi_ec *ec)
 {
-   if (test_bit(flag, &ec->flags)) {
-   clear_bit(flag, &ec->flags);
+   if (test_bit(EC_FLAGS_GPE_MASKED, &ec->flags)) {
+   clear_bit(EC_FLAGS_GPE_MASKED, &ec->flags);
acpi_ec_enable_gpe(ec, false);
ec_dbg_drv("Polling disabled");
}
@@ -464,7 +463,7 @@ static bool acpi_ec_submit_flushable_request(struct acpi_ec 
*ec)
 
 static void acpi_ec_submit_query(struct acpi_ec *ec)
 {
-   acpi_ec_set_storm(ec, EC_FLAGS_COMMAND_STORM);
+   acpi_ec_mask_gpe(ec);
if (!acpi_ec_event_enabled(ec))
return;
if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) {
@@ -480,7 +479,7 @@ static void acpi_ec_complete_query(struct acpi_ec *ec)
if (test_and_clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags))
ec_dbg_evt("Command(%s) unblocked",
   acpi_ec_cmd_string(ACPI_EC_COMMAND_QUERY));
-   acpi_ec_clear_storm(ec, EC_FLAGS_COMMAND_STORM);
+   acpi_ec_unmask_gpe(ec);
 }
 
 static inline void __acpi_ec_enable_event(struct acpi_ec *ec)
@@ -700,7 +699,7 @@ static void advance_transaction(struct acpi_ec *ec)
++t->irq_count;
/* Allow triggering on 0 threshold */
if (t->irq_count == ec_storm_threshold)
-   acpi_ec_set_storm(ec, EC_FLAGS_COMMAND_STORM);
+   acpi_ec_mask_gpe(ec);
}
}
 out:
@@ -798,7 +797,7 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec,
 
spin_lock_irqsave(&ec->lock, tmp);
if (t->irq_count == ec_storm_threshold)
-   acpi_ec_clear_storm(ec, EC_FLAGS_COMMAND_STORM);
+   acpi_ec_unmask_gpe(ec);
ec_dbg_req("Command(%s) stopped", acpi_ec_cmd_string(t->command));
ec->curr = NULL;
/* Disable GPE for command processing (IBF=0/OBF=1) */
-- 
2.7.4



[PATCH 2/2] ACPICA: Events: Dispatch GPEs after enabling for the first time

2017-08-10 Thread Lv Zheng
After being enabled for the first time, the GPEs may have STS bits already
set. Setting EN bits is not sufficient to trigger the GPEs again, so this
patch polls GPEs after enabling them for the first time.
This is a simpler version on top of the "GPE clear" fix generated according
to Mika's report and Rafael's original Linux based fix. Based on Linux
commit originated from Rafael J. Wysocki, fixed by Lv Zheng, tested by Mika
Westerberg.

Original-by: Rafael J. Wysocki 
Signed-off-by: Lv Zheng 
Tested-by: Mika Westerberg 
---
 drivers/acpi/acpica/evxfgpe.c | 22 ++
 1 file changed, 22 insertions(+)

diff --git a/drivers/acpi/acpica/evxfgpe.c b/drivers/acpi/acpica/evxfgpe.c
index 57718a3..d8be21d 100644
--- a/drivers/acpi/acpica/evxfgpe.c
+++ b/drivers/acpi/acpica/evxfgpe.c
@@ -97,6 +97,14 @@ acpi_status acpi_update_all_gpes(void)
 unlock_and_exit:
(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
 
+   /*
+* Poll GPEs to handle already triggered events.
+* It is not sufficient to trigger edge-triggered GPE with specific
+* GPE chips, software need to poll once after enabling.
+*/
+   if (acpi_gbl_all_gpes_initialized) {
+   acpi_ev_gpe_detect(acpi_gbl_gpe_xrupt_list_head);
+   }
return_ACPI_STATUS(status);
 }
 
@@ -120,6 +128,7 @@ acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 
gpe_number)
acpi_status status = AE_BAD_PARAMETER;
struct acpi_gpe_event_info *gpe_event_info;
acpi_cpu_flags flags;
+   u8 poll_gpes = FALSE;
 
ACPI_FUNCTION_TRACE(acpi_enable_gpe);
 
@@ -135,12 +144,25 @@ acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 
gpe_number)
if (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) !=
ACPI_GPE_DISPATCH_NONE) {
status = acpi_ev_add_gpe_reference(gpe_event_info);
+   if (ACPI_SUCCESS(status) &&
+   gpe_event_info->runtime_count == 1) {
+   poll_gpes = TRUE;
+   }
} else {
status = AE_NO_HANDLER;
}
}
 
acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
+
+   /*
+* Poll GPEs to handle already triggered events.
+* It is not sufficient to trigger edge-triggered GPE with specific
+* GPE chips, software need to poll once after enabling.
+*/
+   if (poll_gpes && acpi_gbl_all_gpes_initialized) {
+   acpi_ev_gpe_detect(acpi_gbl_gpe_xrupt_list_head);
+   }
return_ACPI_STATUS(status);
 }
 ACPI_EXPORT_SYMBOL(acpi_enable_gpe)
-- 
2.7.4



[PATCH 0/2] ACPICA: Events: Fix GPE enabling issues related to edge-triggered GPEs

2017-08-10 Thread Lv Zheng
There are 2 issues related to the enabling of GPEs:
1. Currently, our code clears GPE before enabling it. In case of edge
   triggered GPEs, doing this risks GPE losses.
2. For edge-triggered GPEs, enabling it is not sufficiently to trigger an
   already triggered GPE, we need to poll the GPE once it is enabled.
This patchset fixes these 2 problems.

Lv Zheng (2):
  ACPICA: Events: Stop unconditionally clearing ACPI IRQs during
suspend/resume
  ACPICA: Events: Dispatch GPEs after enabling for the first time

 drivers/acpi/acpica/evgpe.c |  7 ---
 drivers/acpi/acpica/evxfgpe.c   | 22 ++
 drivers/acpi/acpica/hwgpe.c |  1 -
 drivers/acpi/acpica/hwsleep.c   | 11 ++-
 drivers/acpi/acpica/hwxfsleep.c |  2 +-
 5 files changed, 25 insertions(+), 18 deletions(-)

-- 
2.7.4



[PATCH 1/2] ACPICA: Events: Stop unconditionally clearing ACPI IRQs during suspend/resume

2017-08-10 Thread Lv Zheng
Unconditionally clearing ACPI IRQs during suspend/resume can lead to
unexpected IRQ losts. This patch fixes this issue by removing such IRQ
clearing code.

If this patch triggers regression, the regression should be in the GPE
handlers that cannot correctly determine some spurious triggered events as
no-ops. Please report any regression related to this commit to the ACPI
component on kernel bugzilla. Reported by Eric Bakula-Davis, fixed by Lv
Zheng.

Link: https://bugzilla.kernel.org/show_bug.cgi?id=196249
Signed-off-by: Lv Zheng 
Reported-and-tested-by: Eric Bakula-Davis 
Tested-by: Mika Westerberg 
---
 drivers/acpi/acpica/evgpe.c |  7 ---
 drivers/acpi/acpica/hwgpe.c |  1 -
 drivers/acpi/acpica/hwsleep.c   | 11 ++-
 drivers/acpi/acpica/hwxfsleep.c |  2 +-
 4 files changed, 3 insertions(+), 18 deletions(-)

diff --git a/drivers/acpi/acpica/evgpe.c b/drivers/acpi/acpica/evgpe.c
index 2293820..390a5ce 100644
--- a/drivers/acpi/acpica/evgpe.c
+++ b/drivers/acpi/acpica/evgpe.c
@@ -115,13 +115,6 @@ acpi_status acpi_ev_enable_gpe(struct acpi_gpe_event_info 
*gpe_event_info)
 
ACPI_FUNCTION_TRACE(ev_enable_gpe);
 
-   /* Clear the GPE (of stale events) */
-
-   status = acpi_hw_clear_gpe(gpe_event_info);
-   if (ACPI_FAILURE(status)) {
-   return_ACPI_STATUS(status);
-   }
-
/* Enable the requested GPE */
 
status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_ENABLE);
diff --git a/drivers/acpi/acpica/hwgpe.c b/drivers/acpi/acpica/hwgpe.c
index 5eb11b3..e004d5f 100644
--- a/drivers/acpi/acpica/hwgpe.c
+++ b/drivers/acpi/acpica/hwgpe.c
@@ -497,7 +497,6 @@ acpi_status acpi_hw_disable_all_gpes(void)
ACPI_FUNCTION_TRACE(hw_disable_all_gpes);
 
status = acpi_ev_walk_gpe_list(acpi_hw_disable_gpe_block, NULL);
-   status = acpi_ev_walk_gpe_list(acpi_hw_clear_gpe_block, NULL);
return_ACPI_STATUS(status);
 }
 
diff --git a/drivers/acpi/acpica/hwsleep.c b/drivers/acpi/acpica/hwsleep.c
index 1fe7387..8f54af6 100644
--- a/drivers/acpi/acpica/hwsleep.c
+++ b/drivers/acpi/acpica/hwsleep.c
@@ -85,15 +85,8 @@ acpi_status acpi_hw_legacy_sleep(u8 sleep_state)
return_ACPI_STATUS(status);
}
 
-   /* Clear all fixed and general purpose status bits */
-
-   status = acpi_hw_clear_acpi_status();
-   if (ACPI_FAILURE(status)) {
-   return_ACPI_STATUS(status);
-   }
-
/*
-* 1) Disable/Clear all GPEs
+* 1) Disable all GPEs
 * 2) Enable all wakeup GPEs
 */
status = acpi_hw_disable_all_gpes();
@@ -299,7 +292,7 @@ acpi_status acpi_hw_legacy_wake(u8 sleep_state)
 * might get fired there
 *
 * Restore the GPEs:
-* 1) Disable/Clear all GPEs
+* 1) Disable all GPEs
 * 2) Enable all runtime GPEs
 */
status = acpi_hw_disable_all_gpes();
diff --git a/drivers/acpi/acpica/hwxfsleep.c b/drivers/acpi/acpica/hwxfsleep.c
index 7ef1393..1888107 100644
--- a/drivers/acpi/acpica/hwxfsleep.c
+++ b/drivers/acpi/acpica/hwxfsleep.c
@@ -206,7 +206,7 @@ acpi_status acpi_enter_sleep_state_s4bios(void)
}
 
/*
-* 1) Disable/Clear all GPEs
+* 1) Disable all GPEs
 * 2) Enable all wakeup GPEs
 */
status = acpi_hw_disable_all_gpes();
-- 
2.7.4



[PATCH v2 4/4] ACPI / EC: Enable noirq stage GPE polling

2017-07-30 Thread Lv Zheng
This patch enables noirq stage GPE polling for the EC driver.

EC is a very special driver, required to work throughout the entire
suspend/resume process. Thus this patch enables IRQ polling for EC during
noirq stages to avoid all kinds of possible issues.

If this commit is bisected to be a regression culprit, please report this
to bugzilla.kernel.org for further investigation.

Signed-off-by: Lv Zheng 
---
 drivers/acpi/ec.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 5f951ba..f5d629b 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -164,7 +164,7 @@ module_param(ec_polling_guard, uint, 0644);
 MODULE_PARM_DESC(ec_polling_guard, "Guard time(us) between EC accesses in 
polling modes");
 
 static unsigned int ec_event_clearing __read_mostly = ACPI_EC_EVT_TIMING_QUERY;
-static unsigned int ec_gpe_polling __read_mostly = ACPI_EC_GPE_POLL_NONE;
+static unsigned int ec_gpe_polling __read_mostly = ACPI_EC_GPE_POLL_RESUME;
 
 /*
  * If the number of false interrupts per one transaction exceeds
-- 
2.7.4



[PATCH v2 3/4] ACPI / EC: Add support to handle EC events earlier

2017-07-30 Thread Lv Zheng
Now as GPE poller is implemented, EC driver is able to detect EC events
during suspend/resume noirq stages, we can try to move EC event handling
earlier without being worried about post-resume event stuck.

Signed-off-by: Lv Zheng 
---
 drivers/acpi/ec.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index f1cffd4..5f951ba 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -1004,7 +1004,9 @@ static void acpi_ec_start(struct acpi_ec *ec, bool 
resuming)
if (!resuming) {
acpi_ec_submit_request(ec);
ec_dbg_ref(ec, "Increase driver");
-   }
+   } else if (!ec_freeze_events &&
+  ec_gpe_polling == ACPI_EC_GPE_POLL_RESUME)
+   __acpi_ec_enable_event(ec);
ec_log_drv("EC started");
}
spin_unlock_irqrestore(&ec->lock, flags);
-- 
2.7.4



[PATCH v2 2/4] ACPI / EC: Add IRQ polling support for noirq stages

2017-07-30 Thread Lv Zheng
1. Problems:
EC IRQs contain transaction IRQs (OBF/IBF) and event IRQ (SCI_EVT).

Transactions are initiated by hosts. The earliest OSPMs execution of EC
transactions is from acpi_ec_transaction(), where the common EC IRQ
handling procedure - advance_transaction() - is initiated from the task
context.
Events are initiated by targets. The earliest OSPMs execution of EC events
is from acpi_ec_gpe_handler(), where the common EC IRQ handling procedure -
advance_transaction() - is initiated from the IRQ context.

1.1. Problem 1: Cannot detect EC event in noirq stages.
There is a noirq stage during system suspend/resume procedures. We can see
that during this stage, advance_transaction() which monitors SCI_EVT can
only be invoked from ec_poll().  Thus if there is no EC transaction
occurring in this stage, EC driver cannot detect SCI_EVT.

Note that in noirq stage if there is an EC transaction pending,
advance_transaction() invoked because of the EC transaction can also help
to detect SCI_EVT and initiate the handling of the EC events. That's why
real reports related to this problem are rare and unreproducible as whether
there is an EC transaction occurred after an undetectable EC events during
noirq stages is random.

1.2. Problem 2: Handling of EC events may stuck for some GPE chips.
Normally, when STS is set, GPE IRQs can be triggered by GPE chips when EN
bit is set. Thus it is ensured that handling of the EC events triggered in
suspend noirq stage is just deferred to resume stage and there won't be EC
event losts.

But there might be chips do not contain AND logic betwee STS and EN to
trigger GPE. In such worst case, EC events may risk lost, handling of the
lost EC events can only start when there is an EC transaction occurred.
Thus if there is no EC transaction, handling of EC events may "stuck"
after resume in such worst case.

2. Old assumption and solution:
Originally, as EC driver actually has never been fully able to handle EC
events during noirq stages, we assumed that detecting such events in noirq
stage is useless and implemented "ec_freeze_events" to stop handling
SCI_EVT earlier after suspend and re-start handling SCI_EVT after resume.
The EC event handling is namely "frozen" during suspend/resume and
"ec_freeze_events" controls the timing of the "freeze". If this could work,
we shouldn't be required to implement GPE polling in noirq stage.

Note that this solution cannot solve problem 2.

3. New fact and solution:
Recently, some bug reports (see Link #1) revealed that we shouldn't
"freeze" EC event handling too early during these system suspend/resume
procedures. Based on this fact, we should detect SCI_EVT during noirq
stage, this left us no other choice than implementing IRQ polling for
SCI_EVT in this stage.

This patch adds a timer to poll EC events timely (0.5s) during system
suspend/resume noirq stages. As the bug reports may not be root caused,
and most of the platforms may not require this, this patch prepares an
option to make this behavior configurable.

Note that this solution can also solve problem 2.

Link: https://bugzilla.kernel.org/show_bug.cgi?id=196129 [#1]
Signed-off-by: Lv Zheng 
---
 drivers/acpi/ec.c   | 130 
 drivers/acpi/internal.h |   1 +
 2 files changed, 131 insertions(+)

diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 54879c7..f1cffd4 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -40,6 +40,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 
 #include "internal.h"
@@ -87,6 +88,31 @@
 #define ACPI_EC_EVT_TIMING_QUERY   0x01
 #define ACPI_EC_EVT_TIMING_EVENT   0x02
 
+/*
+ * There is a noirq stage during suspend/resume and EC firmware may
+ * require OS to handle EC events (SCI_EVT) during this stage.
+ * If there is no EC transactions during this stage, SCI_EVT cannot be
+ * detected. In order to still detect SCI_EVT, IRQ must be polled by the
+ * EC GPE poller. There are 3 configurable modes implemented for the EC
+ * GPE poller:
+ * NONE:Do not enable noirq stage GPE poller.
+ * SUSPEND: Enable GPE poller for suspend noirq stage.
+ *  This mode detects SCI_EVT in suspend noirq stage, making sure
+ *  that all pre-suspend firmware events are handled before
+ *  entering a low power state. Some buggy EC firmware may require
+ *  this, otherwise some unknown firmware issues can be seen on
+ *  such platforms:
+ *  Link: https://bugzilla.kernel.org/show_bug.cgi?id=196129
+ * RESUME:  Enable GPE poller for suspend/resume noirq stages.
+ *  This mode detects SCI_EVT in both suspend and resume noirq
+ *  stages, making sure that all post-resume firmware events are
+ *  handled as early as possible. This mode might be able to solve
+ *  some unknown driver timing issues.
+ */
+#define ACPI_EC_GPE_POLL_NONE  

[PATCH v2 1/4] ACPI / EC: Cleanup EC GPE mask flag

2017-07-30 Thread Lv Zheng
EC_FLAGS_COMMAND_STORM is actually used to mask GPE during IRQ processing.
This patch cleans it up using more readable flag/function names.

Signed-off-by: Lv Zheng 
---
 drivers/acpi/ec.c | 23 +++
 1 file changed, 11 insertions(+), 12 deletions(-)

diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index ddb01e9..54879c7 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -112,8 +112,7 @@ enum {
EC_FLAGS_EVT_HANDLER_INSTALLED, /* _Qxx handlers installed */
EC_FLAGS_STARTED,   /* Driver is started */
EC_FLAGS_STOPPED,   /* Driver is stopped */
-   EC_FLAGS_COMMAND_STORM, /* GPE storms occurred to the
-* current command processing */
+   EC_FLAGS_GPE_MASKED,/* GPE masked */
 };
 
 #define ACPI_EC_COMMAND_POLL   0x01 /* Available for command byte */
@@ -421,19 +420,19 @@ static void acpi_ec_complete_request(struct acpi_ec *ec)
wake_up(&ec->wait);
 }
 
-static void acpi_ec_set_storm(struct acpi_ec *ec, u8 flag)
+static void acpi_ec_mask_gpe(struct acpi_ec *ec)
 {
-   if (!test_bit(flag, &ec->flags)) {
+   if (!test_bit(EC_FLAGS_GPE_MASKED, &ec->flags)) {
acpi_ec_disable_gpe(ec, false);
ec_dbg_drv("Polling enabled");
-   set_bit(flag, &ec->flags);
+   set_bit(EC_FLAGS_GPE_MASKED, &ec->flags);
}
 }
 
-static void acpi_ec_clear_storm(struct acpi_ec *ec, u8 flag)
+static void acpi_ec_unmask_gpe(struct acpi_ec *ec)
 {
-   if (test_bit(flag, &ec->flags)) {
-   clear_bit(flag, &ec->flags);
+   if (test_bit(EC_FLAGS_GPE_MASKED, &ec->flags)) {
+   clear_bit(EC_FLAGS_GPE_MASKED, &ec->flags);
acpi_ec_enable_gpe(ec, false);
ec_dbg_drv("Polling disabled");
}
@@ -460,7 +459,7 @@ static bool acpi_ec_submit_flushable_request(struct acpi_ec 
*ec)
 
 static void acpi_ec_submit_query(struct acpi_ec *ec)
 {
-   acpi_ec_set_storm(ec, EC_FLAGS_COMMAND_STORM);
+   acpi_ec_mask_gpe(ec);
if (!acpi_ec_event_enabled(ec))
return;
if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) {
@@ -476,7 +475,7 @@ static void acpi_ec_complete_query(struct acpi_ec *ec)
if (test_and_clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags))
ec_dbg_evt("Command(%s) unblocked",
   acpi_ec_cmd_string(ACPI_EC_COMMAND_QUERY));
-   acpi_ec_clear_storm(ec, EC_FLAGS_COMMAND_STORM);
+   acpi_ec_unmask_gpe(ec);
 }
 
 static inline void __acpi_ec_enable_event(struct acpi_ec *ec)
@@ -688,7 +687,7 @@ static void advance_transaction(struct acpi_ec *ec)
++t->irq_count;
/* Allow triggering on 0 threshold */
if (t->irq_count == ec_storm_threshold)
-   acpi_ec_set_storm(ec, EC_FLAGS_COMMAND_STORM);
+   acpi_ec_mask_gpe(ec);
}
}
 out:
@@ -786,7 +785,7 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec,
 
spin_lock_irqsave(&ec->lock, tmp);
if (t->irq_count == ec_storm_threshold)
-   acpi_ec_clear_storm(ec, EC_FLAGS_COMMAND_STORM);
+   acpi_ec_unmask_gpe(ec);
ec_dbg_req("Command(%s) stopped", acpi_ec_cmd_string(t->command));
ec->curr = NULL;
/* Disable GPE for command processing (IBF=0/OBF=1) */
-- 
2.7.4



[PATCH v2 0/4] ACPI / EC: Solve EC event handling issues

2017-07-30 Thread Lv Zheng
There is a known issue in EC event handling. This patchset tries to handle
noirq stage EC event polling to fix this known issue.

In the very early version, the EC event polling mechanism is implemented by
a kernel thread to poll EC events. Now the mechanism is implemented by a
timer ticked in noirq stage to poll EC GPEs. In this newest timer version,
timer running period is shortened and thus is safer for s2idle mode.

After adding such a mechanism, we can try to handle EC events earlier after
resume, this may be able to solve some driver order issues.

Lv Zheng (4):
  ACPI / EC: Cleanup EC GPE mask flag
  ACPI / EC: Add IRQ polling support for noirq stages
  ACPI / EC: Add support to handle EC events earlier
  ACPI / EC: Enable noirq stage GPE polling

 drivers/acpi/ec.c   | 157 
 drivers/acpi/internal.h |   1 +
 2 files changed, 145 insertions(+), 13 deletions(-)

-- 
2.7.4



[PATCH 3/3] ACPI: EC: Enable noirq stage GPE polling

2017-07-27 Thread Lv Zheng
This patch enables noirq stage GPE polling for the EC driver.

EC is a very special driver, required to work throughout the entire
suspend/resume process. Thus this patch enables IRQ polling for EC during
noirq stages to avoid all kinds of possible issues.

If this commit is bisected to be a regression culprit, please report this
to bugzilla.kernel.org for further investigation.

Signed-off-by: Lv Zheng 
---
 drivers/acpi/ec.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 47f900c..12e0c8a 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -164,7 +164,7 @@ module_param(ec_polling_guard, uint, 0644);
 MODULE_PARM_DESC(ec_polling_guard, "Guard time(us) between EC accesses in 
polling modes");
 
 static unsigned int ec_event_clearing __read_mostly = ACPI_EC_EVT_TIMING_QUERY;
-static unsigned int ec_gpe_polling __read_mostly = ACPI_EC_GPE_POLL_NONE;
+static unsigned int ec_gpe_polling __read_mostly = ACPI_EC_GPE_POLL_RESUME;
 
 /*
  * If the number of false interrupts per one transaction exceeds
-- 
2.7.4



[PATCH 1/3] ACPI / EC: Cleanup EC GPE mask flag

2017-07-27 Thread Lv Zheng
EC_FLAGS_COMMAND_STORM is actually used to mask GPE during IRQ processing.
This patch cleans it up using more readable flag/function names.

Signed-off-by: Lv Zheng 
---
 drivers/acpi/ec.c | 23 +++
 1 file changed, 11 insertions(+), 12 deletions(-)

diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index ddb01e9..54879c7 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -112,8 +112,7 @@ enum {
EC_FLAGS_EVT_HANDLER_INSTALLED, /* _Qxx handlers installed */
EC_FLAGS_STARTED,   /* Driver is started */
EC_FLAGS_STOPPED,   /* Driver is stopped */
-   EC_FLAGS_COMMAND_STORM, /* GPE storms occurred to the
-* current command processing */
+   EC_FLAGS_GPE_MASKED,/* GPE masked */
 };
 
 #define ACPI_EC_COMMAND_POLL   0x01 /* Available for command byte */
@@ -421,19 +420,19 @@ static void acpi_ec_complete_request(struct acpi_ec *ec)
wake_up(&ec->wait);
 }
 
-static void acpi_ec_set_storm(struct acpi_ec *ec, u8 flag)
+static void acpi_ec_mask_gpe(struct acpi_ec *ec)
 {
-   if (!test_bit(flag, &ec->flags)) {
+   if (!test_bit(EC_FLAGS_GPE_MASKED, &ec->flags)) {
acpi_ec_disable_gpe(ec, false);
ec_dbg_drv("Polling enabled");
-   set_bit(flag, &ec->flags);
+   set_bit(EC_FLAGS_GPE_MASKED, &ec->flags);
}
 }
 
-static void acpi_ec_clear_storm(struct acpi_ec *ec, u8 flag)
+static void acpi_ec_unmask_gpe(struct acpi_ec *ec)
 {
-   if (test_bit(flag, &ec->flags)) {
-   clear_bit(flag, &ec->flags);
+   if (test_bit(EC_FLAGS_GPE_MASKED, &ec->flags)) {
+   clear_bit(EC_FLAGS_GPE_MASKED, &ec->flags);
acpi_ec_enable_gpe(ec, false);
ec_dbg_drv("Polling disabled");
}
@@ -460,7 +459,7 @@ static bool acpi_ec_submit_flushable_request(struct acpi_ec 
*ec)
 
 static void acpi_ec_submit_query(struct acpi_ec *ec)
 {
-   acpi_ec_set_storm(ec, EC_FLAGS_COMMAND_STORM);
+   acpi_ec_mask_gpe(ec);
if (!acpi_ec_event_enabled(ec))
return;
if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) {
@@ -476,7 +475,7 @@ static void acpi_ec_complete_query(struct acpi_ec *ec)
if (test_and_clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags))
ec_dbg_evt("Command(%s) unblocked",
   acpi_ec_cmd_string(ACPI_EC_COMMAND_QUERY));
-   acpi_ec_clear_storm(ec, EC_FLAGS_COMMAND_STORM);
+   acpi_ec_unmask_gpe(ec);
 }
 
 static inline void __acpi_ec_enable_event(struct acpi_ec *ec)
@@ -688,7 +687,7 @@ static void advance_transaction(struct acpi_ec *ec)
++t->irq_count;
/* Allow triggering on 0 threshold */
if (t->irq_count == ec_storm_threshold)
-   acpi_ec_set_storm(ec, EC_FLAGS_COMMAND_STORM);
+   acpi_ec_mask_gpe(ec);
}
}
 out:
@@ -786,7 +785,7 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec,
 
spin_lock_irqsave(&ec->lock, tmp);
if (t->irq_count == ec_storm_threshold)
-   acpi_ec_clear_storm(ec, EC_FLAGS_COMMAND_STORM);
+   acpi_ec_unmask_gpe(ec);
ec_dbg_req("Command(%s) stopped", acpi_ec_cmd_string(t->command));
ec->curr = NULL;
/* Disable GPE for command processing (IBF=0/OBF=1) */
-- 
2.7.4



[PATCH 2/3] ACPI: EC: Add IRQ polling support for noirq stages

2017-07-27 Thread Lv Zheng
EC IRQs contain transaction IRQs (OBF/IBF) and event IRQ (SCI_EVT).

Transactions are initiated by hosts. The earliest OSPMs execution of EC
transactions is from acpi_ec_transaction(), where the common EC IRQ
handling procedure - advance_transaction() - is initiated from the task
context.
Events are initiated by targets. The earliest OSPMs execution of EC events
is from acpi_ec_gpe_handler(), where the common EC IRQ handling procedure -
advance_transaction() - is initiated from the IRQ context. However if
there is an EC transaction pending, advance_transaction() invoked from the
task context can also help to detect SCI_EVT and initiate the handling of
the EC events.

There is a noirq stage during system suspend/resume procedures. We can see
that during this stage, advance_transaction() which monitors SCI_EVT can
only be invoked from ec_poll().  Thus if there is no EC transaction
occuring in this stage, EC driver cannot detect SCI_EVT.

Note that such event IRQs may risk lost. Normally, when GPE is enabled and
GPE is flagged, IRQ can be triggered and such events thus can be detected
in the IRQ handler. But there might be GPE chips not capable of triggering
IRQs upon enabling. Thus originally we tried to use "ec_freeze_events" to
stop handling SCI_EVT earlier after suspend and re-start handling SCI_EVT
after resume to avoid such IRQ lost. The EC event handling is namely
paused during suspend/resume and "ec_freeze_events" controls the timing of
the pause.

Recently, some bug reports (see Link #1) revealed that we shouldn't pause
EC event handling too early during these system suspend/resume procedures.
Based on this fact, we should detect SCI_EVT during noirq stage, this left
us no other choice than implementing IRQ polling for SCI_EVT in this stage.

This patch adds a timer to poll EC events timely (0.5s) during system
suspend/resume noirq stages. As the bug reports may not be root caused,
and most of the platforms may not require this, this patch prepares an
option to make this behavior configurable.

Link: https://bugzilla.kernel.org/show_bug.cgi?id=196129 [#1]
Signed-off-by: Lv Zheng 
---
 drivers/acpi/ec.c   | 135 
 drivers/acpi/internal.h |   1 +
 2 files changed, 136 insertions(+)

diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 54879c7..47f900c 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -40,6 +40,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 
 #include "internal.h"
@@ -87,6 +88,31 @@
 #define ACPI_EC_EVT_TIMING_QUERY   0x01
 #define ACPI_EC_EVT_TIMING_EVENT   0x02
 
+/*
+ * There is a noirq stage during suspend/resume and EC firmware may
+ * require OS to handle EC events (SCI_EVT) during this stage.
+ * If there is no EC transactions during this stage, SCI_EVT cannot be
+ * detected. In order to still detect SCI_EVT, IRQ must be polled by the
+ * EC GPE poller. There are 3 configurable modes implemented for the EC
+ * GPE poller:
+ * NONE:Do not enable noirq stage GPE poller.
+ * SUSPEND: GPE poller is disabled at the end of the suspend.
+ *  This mode detects SCI_EVT in suspend noirq stage, making sure
+ *  that all pre-suspend firmware events are handled before
+ *  entering a low power state. Some buggy EC firmware may require
+ *  this, otherwise some unknown firmware issues can be seen on
+ *  such platforms:
+ *  Link: https://bugzilla.kernel.org/show_bug.cgi?id=196129
+ * RESUME:  GPE poller is disabled at the begining of the resume.
+ *  This mode detects SCI_EVT in both suspend and resume noirq
+ *  stages, making sure that all post-resume firmware events are
+ *  handled as early as possible. This mode might be able to solve
+ *  some unknown driver timing issues.
+ */
+#define ACPI_EC_GPE_POLL_NONE  0x00
+#define ACPI_EC_GPE_POLL_SUSPEND   0x01
+#define ACPI_EC_GPE_POLL_RESUME0x02
+
 /* EC commands */
 enum ec_command {
ACPI_EC_COMMAND_READ = 0x80,
@@ -102,6 +128,7 @@ enum ec_command {
 #define ACPI_EC_CLEAR_MAX  100 /* Maximum number of events to query
 * when trying to clear the EC */
 #define ACPI_EC_MAX_QUERIES16  /* Maximum number of parallel queries */
+#define ACPI_EC_POLL_INTERVAL  500 /* Polling event every 500ms */
 
 enum {
EC_FLAGS_QUERY_ENABLED, /* Query is enabled */
@@ -113,6 +140,7 @@ enum {
EC_FLAGS_STARTED,   /* Driver is started */
EC_FLAGS_STOPPED,   /* Driver is stopped */
EC_FLAGS_GPE_MASKED,/* GPE masked */
+   EC_FLAGS_GPE_POLLING,   /* GPE polling is enabled */
 };
 
 #define ACPI_EC_COMMAND_POLL   0x01 /* Available for command byte */
@@ -136,6 +164,7 @@ module_param(ec_polling_guard, uint, 0644);
 MODULE_PARM_DESC(ec_polling_guard, "Guard time(u

[PATCH 2/2] ACPI: EC: Revert "ACPI / EC: Enable event freeze mode..." to fix a regression

2017-07-11 Thread Lv Zheng
On Lenovo ThinkPad X1 Carbon - the 5th Generation, enabling an earlier EC
event freezing timing causes acpitz-virtual-0 to report a stucked 48C
temparature. And with EC firmware revisioned as 1.14, without reverting
back to old EC event freezing timing, the fan still blows up after a system
resume (see comment 168 on link #1).

This reverts the culprit change so that the regression can be fixed without
upgrading the EC firmware.

Fixes: d30283057ecd ("ACPI / EC: Enable event freeze mode to improve event 
handling")
Link: https://bugzilla.kernel.org/show_bug.cgi?id=191181 [#1]
Tested-by: Damjan Georgievski 
Signed-off-by: Lv Zheng 
Cc: Stable  # 4.9+
---
 drivers/acpi/ec.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 05e4eb5..ddb01e9 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -147,7 +147,7 @@ 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");
 
-static bool ec_freeze_events __read_mostly = true;
+static bool ec_freeze_events __read_mostly = false;
 module_param(ec_freeze_events, bool, 0644);
 MODULE_PARM_DESC(ec_freeze_events, "Disabling event handling during 
suspend/resume");
 
-- 
2.7.4



[PATCH 1/2] ACPI: EC: Drop EC noirq hooks to fix a regression

2017-07-11 Thread Lv Zheng
According to the bug report, though the busy polling mode can make noirq
stages executed faster, it causes abnormal fan blowing up after a system
resume (see link #1 for a video demonstration) on Lenovo ThinkPad X1 Carbon
 - the 5th Generation. The problem can be fixed by an upgraded EC firmware.

However many reporters can also confirm that the problem can be fixed by
stopping busy polling during suspend/resume.

This patch drops noirq stage hooks so that the regression can be fixed
without upgrading the EC firmware.

Fixes: c3a696b6e8f8 ("ACPI / EC: Use busy polling mode when GPE is not enabled")
Link: https://youtu.be/9NQ9x-Jm99Q   [#1]
Link: https://bugzilla.kernel.org/show_bug.cgi?id=196129
Reported-by: Andreas Lindhe 
Tested-by: Gjorgji Jankovski 
Tested-by: Damjan Georgievski 
Tested-by: Fernando Chaves 
Tested-by: Tomislav Ivek 
Tested-by: Denis P. 
Signed-off-by: Lv Zheng 
Cc: Stable  # all applicable
---
 drivers/acpi/ec.c | 19 ---
 1 file changed, 19 deletions(-)

diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 854d428..05e4eb5 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -1870,24 +1870,6 @@ int __init acpi_ec_ecdt_probe(void)
 }
 
 #ifdef CONFIG_PM_SLEEP
-static int acpi_ec_suspend_noirq(struct device *dev)
-{
-   struct acpi_ec *ec =
-   acpi_driver_data(to_acpi_device(dev));
-
-   acpi_ec_enter_noirq(ec);
-   return 0;
-}
-
-static int acpi_ec_resume_noirq(struct device *dev)
-{
-   struct acpi_ec *ec =
-   acpi_driver_data(to_acpi_device(dev));
-
-   acpi_ec_leave_noirq(ec);
-   return 0;
-}
-
 static int acpi_ec_suspend(struct device *dev)
 {
struct acpi_ec *ec =
@@ -1909,7 +1891,6 @@ static int acpi_ec_resume(struct device *dev)
 #endif
 
 static const struct dev_pm_ops acpi_ec_pm = {
-   SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(acpi_ec_suspend_noirq, 
acpi_ec_resume_noirq)
SET_SYSTEM_SLEEP_PM_OPS(acpi_ec_suspend, acpi_ec_resume)
 };
 
-- 
2.7.4



[RFC PATCH v6 4/5] ACPI: button: extract input creation/destruction helpers

2017-06-21 Thread Lv Zheng
From: Benjamin Tissoires 

When the LID switch ACPI implementation is unreliable, we might want
to remove the device when we are not sure about the state. This should
prevent any suspend/resume loops given that in that case, there will be
no more LID switch input node.

This patch prepares the dynamic creation/destruction of the input node.

Signed-off-by: Benjamin Tissoires 
Signed-off-by: Lv Zheng 
---
 drivers/acpi/button.c | 86 +++
 1 file changed, 53 insertions(+), 33 deletions(-)

diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c
index 1256a8c..91c9989 100644
--- a/drivers/acpi/button.c
+++ b/drivers/acpi/button.c
@@ -302,6 +302,54 @@ int acpi_lid_open(void)
 }
 EXPORT_SYMBOL(acpi_lid_open);
 
+static void acpi_button_remove_input(struct acpi_device *device)
+{
+   struct acpi_button *button = acpi_driver_data(device);
+
+   input_unregister_device(button->input);
+   button->input = NULL;
+}
+
+static int acpi_button_add_input(struct acpi_device *device)
+{
+   struct acpi_button *button = acpi_driver_data(device);
+   struct input_dev *input;
+   int error;
+
+   input = input_allocate_device();
+   if (!input) {
+   error = -ENOMEM;
+   goto err;
+   }
+
+   input->name = acpi_device_name(device);
+   input->phys = button->phys;
+   input->id.bustype = BUS_HOST;
+   input->id.product = button->type;
+   input->dev.parent = &device->dev;
+   switch (button->type) {
+   case ACPI_BUTTON_TYPE_POWER:
+   input_set_capability(input, EV_KEY, KEY_POWER);
+   break;
+   case ACPI_BUTTON_TYPE_SLEEP:
+   input_set_capability(input, EV_KEY, KEY_SLEEP);
+   break;
+   case ACPI_BUTTON_TYPE_LID:
+   input_set_capability(input, EV_SW, SW_LID);
+   break;
+   }
+
+   error = input_register_device(input);
+   if (error)
+   goto err;
+
+   button->input = input;
+   return 0;
+ err:
+   input_free_device(input);
+   return error;
+}
+
 static int acpi_lid_update_state(struct acpi_device *device)
 {
int state;
@@ -414,7 +462,6 @@ static int acpi_button_resume(struct device *dev)
 static int acpi_button_add(struct acpi_device *device)
 {
struct acpi_button *button;
-   struct input_dev *input;
const char *hid = acpi_device_hid(device);
char *name, *class;
int error;
@@ -425,12 +472,6 @@ static int acpi_button_add(struct acpi_device *device)
 
device->driver_data = button;
 
-   button->input = input = input_allocate_device();
-   if (!input) {
-   error = -ENOMEM;
-   goto err_free_button;
-   }
-
name = acpi_device_name(device);
class = acpi_device_class(device);
 
@@ -457,38 +498,19 @@ static int acpi_button_add(struct acpi_device *device)
} else {
printk(KERN_ERR PREFIX "Unsupported hid [%s]\n", hid);
error = -ENODEV;
-   goto err_free_input;
+   goto err_free_button;
}
 
error = acpi_button_add_fs(device);
if (error)
-   goto err_free_input;
+   goto err_free_button;
 
snprintf(button->phys, sizeof(button->phys), "%s/button/input0", hid);
 
-   input->name = name;
-   input->phys = button->phys;
-   input->id.bustype = BUS_HOST;
-   input->id.product = button->type;
-   input->dev.parent = &device->dev;
-
-   switch (button->type) {
-   case ACPI_BUTTON_TYPE_POWER:
-   input_set_capability(input, EV_KEY, KEY_POWER);
-   break;
-
-   case ACPI_BUTTON_TYPE_SLEEP:
-   input_set_capability(input, EV_KEY, KEY_SLEEP);
-   break;
-
-   case ACPI_BUTTON_TYPE_LID:
-   input_set_capability(input, EV_SW, SW_LID);
-   break;
-   }
-
-   error = input_register_device(input);
+   error = acpi_button_add_input(device);
if (error)
goto err_remove_fs;
+
if (button->type == ACPI_BUTTON_TYPE_LID) {
/*
 * This assumes there's only one lid device, or if there are
@@ -507,8 +529,6 @@ static int acpi_button_add(struct acpi_device *device)
 
  err_remove_fs:
acpi_button_remove_fs(device);
- err_free_input:
-   input_free_device(input);
  err_free_button:
kfree(button);
return error;
@@ -521,7 +541,7 @@ static int acpi_button_remove(struct acpi_device *device)
acpi_button_remove_fs(device);
if (button->type == ACPI_BUTTON_TYPE_LID)
del_timer_sync(&button->lid_timer);
-   input_unregister_device(button->input);
+   acpi_button_remove_input(device);
kfree(button);
return 0;
 }
-- 
2.7.4



[RFC PATCH v6 3/5] ACPI: button: Rework lid_init_state=ignore mode

2017-06-21 Thread Lv Zheng
There are platform variations implementing ACPI lid device in different
ways:
1. Some platforms send "open" events to OS and the events arrive before
   button driver is resumed;
2. Some platforms send "open" events to OS, but the events arrive after
   button driver is resumed, ex., Samsung N210+;
3. Some platforms never send "open" events to OS, but send "open" events to
   update the cached _LID return value, and the update events arrive before
   button driver is resumed;
4. Some platforms never send "open" events to OS, but send "open" events to
   update the cached _LID return value, but the update events arrive after
   button driver is resumed, ex., Surface Pro 3;
5. Some platforms never send "open" events, _LID returns value sticks to
   "close", ex., Surface Pro 1.
Currently, all cases work find with systemd 233, but only case 1,2,3,4 work
fine with systemd 229.

After fixing all the other issues for old userspace programs, case 5 is the
only case that the exported input node is still not fully compliant to
SW_LID ABI and thus needs quirks or ABI changes.

The original button.lid_init_state=ignore ABI change solution is now too
complicated if its purpose is to only solve this final incompliant use
case. This patch re-works it by unconditionally prepending "open"
complement events.

Cc: 
Cc: Benjamin Tissoires 
Cc: Peter Hutterer 
Signed-off-by: Lv Zheng 
---
 drivers/acpi/button.c | 85 +++
 1 file changed, 5 insertions(+), 80 deletions(-)

diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c
index a8b119e..1256a8c 100644
--- a/drivers/acpi/button.c
+++ b/drivers/acpi/button.c
@@ -109,8 +109,6 @@ struct acpi_button {
struct timer_list lid_timer;
char phys[32];  /* for input device */
unsigned long pushed;
-   int last_state;
-   ktime_t last_time;
bool suspended;
 };
 
@@ -118,10 +116,6 @@ static BLOCKING_NOTIFIER_HEAD(acpi_lid_notifier);
 static struct acpi_device *lid_device;
 static u8 lid_init_state = ACPI_BUTTON_LID_INIT_METHOD;
 
-static unsigned long lid_report_interval __read_mostly = 500;
-module_param(lid_report_interval, ulong, 0644);
-MODULE_PARM_DESC(lid_report_interval, "Interval (ms) between lid key events");
-
 static unsigned long lid_notify_timeout __read_mostly = 10;
 module_param(lid_notify_timeout, ulong, 0644);
 MODULE_PARM_DESC(lid_notify_timeout, "Timeout (s) before receiving lid 
notification");
@@ -157,79 +151,12 @@ static int acpi_lid_notify_state(struct acpi_device 
*device, int state)
 {
struct acpi_button *button = acpi_driver_data(device);
int ret;
-   ktime_t next_report;
-   bool do_update;
-
-   /*
-* In lid_init_state=ignore mode, if user opens/closes lid
-* frequently with "open" missing, and "last_time" is also updated
-* frequently, "close" cannot be delivered to the userspace.
-* So "last_time" is only updated after a timeout or an actual
-* switch.
-*/
-   if (lid_init_state != ACPI_BUTTON_LID_INIT_IGNORE ||
-   button->last_state != !!state)
-   do_update = true;
-   else
-   do_update = false;
-
-   next_report = ktime_add(button->last_time,
-   ms_to_ktime(lid_report_interval));
-   if (button->last_state == !!state &&
-   ktime_after(ktime_get(), next_report)) {
-   /* Complain the buggy firmware */
-   pr_warn_once("The lid device is not compliant to SW_LID.\n");
 
-   /*
-* Send the unreliable complement switch event:
-*
-* On most platforms, the lid device is reliable. However
-* there are exceptions:
-* 1. Platforms returning initial lid state as "close" by
-*default after booting/resuming:
-* https://bugzilla.kernel.org/show_bug.cgi?id=89211
-* https://bugzilla.kernel.org/show_bug.cgi?id=106151
-* 2. Platforms never reporting "open" events:
-* https://bugzilla.kernel.org/show_bug.cgi?id=106941
-* On these buggy platforms, the usage model of the ACPI
-* lid device actually is:
-* 1. The initial returning value of _LID may not be
-*reliable.
-* 2. The open event may not be reliable.
-* 3. The close event is reliable.
-*
-* But SW_LID is typed as input switch event, the input
-* layer checks if the event is redundant. Hence if the
-* state is not switched, the userspace cannot see this
-* 

[RFC PATCH v6 5/5] ACPI: button: Add an optional workaround to fix a persistent close issue for old userspace

2017-06-21 Thread Lv Zheng
From: Benjamin Tissoires 

Because of the variation of firmware implementation, there is a chance
the LID state is unknown:
1. Some platforms send "open" ACPI notification to the OS and the event
   arrive before the button driver is resumed;
2. Some platforms send "open" ACPI notification to the OS, but the
event
   arrives after the button driver is resumed, ex., Samsung N210+;
3. Some platforms never send an "open" ACPI notification to the OS, but
   update the cached _LID return value to "open", and this update
arrives
   before the button driver is resumed;
4. Some platforms never send an "open" ACPI notification to the OS, but
   update the cached _LID return value to "open", but this update
arrives
   after the button driver is resumed, ex., Surface Pro 3;
5. Some platforms never send an "open" ACPI notification to the OS, and
   _LID ACPI method returns a value which stays to "close", ex.,
   Surface Pro 1.
Currently, all cases work find with systemd 233, but only case 1,2,3,4 work
fine with old userspace.

After fixing all the other issues for old userspace programs, case 5 is the
only case that the exported input node is still not fully compliant to
SW_LID ABI and thus needs quirks or ABI changes.

This patch provides a dynamic SW_LID input node solution to make sure we do
not export an input node with an unknown state to prevent suspend loops.

The database of unreliable devices is left to userspace to handle with a
hwdb file and a udev rule.

Reworked by Lv to make this solution optional, code based on top of old
"ignore" mode and make lid_reliable configurable to all lid devices to
eliminate the difficulties of synchronously handling global lid_device.

Signed-off-by: Benjamin Tissoires 
Signed-off-by: Lv Zheng 
---
 drivers/acpi/button.c | 96 ++-
 1 file changed, 88 insertions(+), 8 deletions(-)

diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c
index 91c9989..f11045d 100644
--- a/drivers/acpi/button.c
+++ b/drivers/acpi/button.c
@@ -107,11 +107,13 @@ struct acpi_button {
unsigned int type;
struct input_dev *input;
struct timer_list lid_timer;
+   bool lid_reliable;
char phys[32];  /* for input device */
unsigned long pushed;
bool suspended;
 };
 
+static DEFINE_MUTEX(lid_input_lock);
 static BLOCKING_NOTIFIER_HEAD(acpi_lid_notifier);
 static struct acpi_device *lid_device;
 static u8 lid_init_state = ACPI_BUTTON_LID_INIT_METHOD;
@@ -128,6 +130,10 @@ static unsigned long lid_update_interval __read_mostly = 1 
* MSEC_PER_SEC;
 module_param(lid_update_interval, ulong, 0644);
 MODULE_PARM_DESC(lid_update_interval, "Interval (ms) between lid periodic 
updates");
 
+static bool lid_unreliable __read_mostly = false;
+module_param(lid_unreliable, bool, 0644);
+MODULE_PARM_DESC(lid_unreliable, "Dynamically adding/removing input node for 
unreliable lids");
+
 /* --
   FS Interface (/proc)
-- 
*/
@@ -152,6 +158,9 @@ static int acpi_lid_notify_state(struct acpi_device 
*device, int state)
struct acpi_button *button = acpi_driver_data(device);
int ret;
 
+   if (!button->input)
+   return -EINVAL;
+
if (lid_init_state == ACPI_BUTTON_LID_INIT_IGNORE)
input_report_switch(button->input, SW_LID, 0);
 
@@ -306,6 +315,8 @@ static void acpi_button_remove_input(struct acpi_device 
*device)
 {
struct acpi_button *button = acpi_driver_data(device);
 
+   if (!button->input)
+   return;
input_unregister_device(button->input);
button->input = NULL;
 }
@@ -316,6 +327,9 @@ static int acpi_button_add_input(struct acpi_device *device)
struct input_dev *input;
int error;
 
+   if (button->input)
+   return 0;
+
input = input_allocate_device();
if (!input) {
error = -ENOMEM;
@@ -378,8 +392,10 @@ static void acpi_lid_initialize_state(struct acpi_device 
*device)
break;
case ACPI_BUTTON_LID_INIT_METHOD:
(void)acpi_lid_update_state(device);
+   mutex_unlock(&lid_input_lock);
if (lid_periodic_update)
acpi_lid_start_timer(device, lid_update_interval);
+   mutex_lock(&lid_input_lock);
break;
case ACPI_BUTTON_LID_INIT_IGNORE:
default:
@@ -391,7 +407,9 @@ static void acpi_lid_timeout(ulong arg)
 {
struct acpi_device *device = (struct acpi_device *)arg;
 
+   mutex_lock(&lid_input_lock);
acpi_lid_initialize_state(device);
+   mutex_unlock(&lid_input_lock);
 }
 
 static void acpi

[RFC PATCH v6 2/5] ACPI: button: Add an optional workaround to fix an event missing issue for old userspace

2017-06-21 Thread Lv Zheng
There are platform variations implementing ACPI lid device in different
ways:
1. Some platforms send "open" events to OS and the events arrive before
   button driver is resumed;
2. Some platforms send "open" events to OS, but the events arrive after
   button driver is resumed, ex., Samsung N210+;
3. Some platforms never send "open" events to OS, but send "open" events to
   update the cached _LID return value, and the update events arrive before
   button driver is resumed;
4. Some platforms never send "open" events to OS, but send "open" events to
   update the cached _LID return value, but the update events arrive after
   button driver is resumed, ex., Surface Pro 3;
5. Some platforms never send "open" events, _LID returns value sticks to
   "close", ex., Surface Pro 1.
Currently, all cases work fine with systemd 233, but only case 1,2 work
fine with systemd 229.

Case 3,4 can be treated as an event missing issue:
   After seeing a LID "close" event, systemd 229 will wait several seconds
   (HoldoffTimeoutSec) before suspending the platform. Thus on case 4
   platforms, if users close lid, and re-open it during the
   HoldoffTimeoutSec period, there is still no "open" events seen by the
   userspace. Thus systemd still considers the last state as "close" and
   suspends the platform after the HoldoffTimeoutSec times out.

Note that not only systemd 229, desktop managers (ex.,
gnome-settings-daemon) also suffer from this issue.

This patch tries to fix this issue by periodically sending _LID return
value to userspace, which ensures to trigger a SW_LID event when the
underlying hardware state has changed. As adding a periodic timer is not a
power friendly way, this patch prepares an option for users to enable on
failure platforms for old userspace programs.

Users can configure update interval via button.lid_update_interval.
This should be configured to a smaller value than HoldoffTimeoutSec in
/etc/systemd/logind.conf.

Cc: 
Cc: Benjamin Tissoires 
Cc: Peter Hutterer 
Signed-off-by: Lv Zheng 
---
 drivers/acpi/button.c | 17 +++--
 1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c
index 67a0d78..a8b119e 100644
--- a/drivers/acpi/button.c
+++ b/drivers/acpi/button.c
@@ -126,6 +126,14 @@ static unsigned long lid_notify_timeout __read_mostly = 10;
 module_param(lid_notify_timeout, ulong, 0644);
 MODULE_PARM_DESC(lid_notify_timeout, "Timeout (s) before receiving lid 
notification");
 
+static bool lid_periodic_update __read_mostly = false;
+module_param(lid_periodic_update, bool, 0644);
+MODULE_PARM_DESC(lid_periodic_update, "Periodically sending lid state 
updates");
+
+static unsigned long lid_update_interval __read_mostly = 1 * MSEC_PER_SEC;
+module_param(lid_update_interval, ulong, 0644);
+MODULE_PARM_DESC(lid_update_interval, "Interval (ms) between lid periodic 
updates");
+
 /* --
   FS Interface (/proc)
-- 
*/
@@ -395,6 +403,8 @@ static void acpi_lid_initialize_state(struct acpi_device 
*device)
break;
case ACPI_BUTTON_LID_INIT_METHOD:
(void)acpi_lid_update_state(device);
+   if (lid_periodic_update)
+   acpi_lid_start_timer(device, lid_update_interval);
break;
case ACPI_BUTTON_LID_INIT_IGNORE:
default:
@@ -560,8 +570,11 @@ static int acpi_button_add(struct acpi_device *device)
 * more we only care about the last one...
 */
lid_device = device;
-   acpi_lid_start_timer(device,
-   lid_notify_timeout * MSEC_PER_SEC);
+   if (lid_periodic_update)
+   acpi_lid_initialize_state(device);
+   else
+   acpi_lid_start_timer(device,
+   lid_notify_timeout * MSEC_PER_SEC);
}
 
printk(KERN_INFO PREFIX "%s [%s]\n", name, acpi_device_bid(device));
-- 
2.7.4



[RFC PATCH v6 1/5] ACPI: button: Add a workaround to fix an order issue for old userspace

2017-06-21 Thread Lv Zheng
There are platform variations implementing ACPI lid device in different
ways:
1. Some platforms send "open" events to OS and the events arrive before
   button driver is resumed;
2. Some platforms send "open" events to OS, but the events arrive after
   button driver is resumed, ex., Samsung N210+;
3. Some platforms never send "open" events to OS, but send "open" events to
   update the cached _LID return value, and the update events arrive before
   button driver is resumed;
4. Some platforms never send "open" events to OS, but send "open" events to
   update the cached _LID return value, but the update events arrive after
   button driver is resumed, ex., Surface Pro 3;
5. Some platforms never send "open" events, _LID returns value sticks to
   "close", ex., Surface Pro 1.
Currently, all cases work find with systemd 233, but only case 1 works fine
with systemd 229.

Case 2,4 can be treated as an order issue:
   If the button driver always evaluates _LID after seeing a LID
   notification, there shouldn't be such a problem.

Note that this order issue cannot be fixed by sorting OS drivers' resume
code:
1. When acpi.ec_freeze_events=Y, the order depends on whether PNP0C0D(LID)
   or PNP0C09(EC) appears first in the namespace (probe order).
2. Even when acpi.ec_freeze_events=N, which forces OS to handle EC events
   as early as possible, the order issue can still be reproduced due to
   platform delays (reproduce ratio is lower than case 1).
3. Some platform simply has a very big delay for LID open events.

This patch tries to fix this issue for systemd 229 by defer sending initial
lid state 10 seconds later after resume, which ensures EC events can always
arrive before button driver evaluates _LID. It finally only fixes case 2
platforms as fixing case 4 platforms needs additional efforts (see known
issue below).

The users can configure wait timeout via button.lid_notify_timeout.

Known issu:
1. systemd/logind 229 still mis-bahaves with case 3,4 platforms
   After seeing a LID "close" event, systemd 229 will wait several seconds
   (HoldoffTimeoutSec) before suspending the platform. Thus on case 4
   platforms, if users close lid, and re-open it during the
   HoldoffTimeoutSec period, there is still no "open" events seen by the
   userspace. Thus systemd still considers the last state as "close" and
   suspends the platform after the HoldoffTimeoutSec times out.

Cc: 
Cc: Benjamin Tissoires 
Cc: Peter Hutterer 
Signed-off-by: Lv Zheng 
---
 drivers/acpi/button.c | 36 ++--
 1 file changed, 34 insertions(+), 2 deletions(-)

diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c
index e19f530..67a0d78 100644
--- a/drivers/acpi/button.c
+++ b/drivers/acpi/button.c
@@ -28,6 +28,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -79,6 +80,7 @@ MODULE_DEVICE_TABLE(acpi, button_device_ids);
 static int acpi_button_add(struct acpi_device *device);
 static int acpi_button_remove(struct acpi_device *device);
 static void acpi_button_notify(struct acpi_device *device, u32 event);
+static void acpi_lid_timeout(ulong arg);
 
 #ifdef CONFIG_PM_SLEEP
 static int acpi_button_suspend(struct device *dev);
@@ -104,6 +106,7 @@ static struct acpi_driver acpi_button_driver = {
 struct acpi_button {
unsigned int type;
struct input_dev *input;
+   struct timer_list lid_timer;
char phys[32];  /* for input device */
unsigned long pushed;
int last_state;
@@ -119,6 +122,10 @@ static unsigned long lid_report_interval __read_mostly = 
500;
 module_param(lid_report_interval, ulong, 0644);
 MODULE_PARM_DESC(lid_report_interval, "Interval (ms) between lid key events");
 
+static unsigned long lid_notify_timeout __read_mostly = 10;
+module_param(lid_notify_timeout, ulong, 0644);
+MODULE_PARM_DESC(lid_notify_timeout, "Timeout (s) before receiving lid 
notification");
+
 /* --
   FS Interface (/proc)
-- 
*/
@@ -371,6 +378,15 @@ static int acpi_lid_update_state(struct acpi_device 
*device)
return acpi_lid_notify_state(device, state);
 }
 
+static void acpi_lid_start_timer(struct acpi_device *device,
+unsigned long msecs)
+{
+   struct acpi_button *button = acpi_driver_data(device);
+
+   mod_timer(&button->lid_timer,
+ jiffies + msecs_to_jiffies(msecs));
+}
+
 static void acpi_lid_initialize_state(struct acpi_device *device)
 {
switch (lid_init_state) {
@@ -386,6 +402,13 @@ static void acpi_lid_initialize_state(struct acpi_device 
*device)
}
 }
 
+static void acpi_lid_timeout(ulong arg)
+{
+   struct acpi_device *de

[RFC PATCH v6 0/5] ACPI: button: Fix button.lid_init_state=method mode

2017-06-21 Thread Lv Zheng
There are platform variations implementing ACPI lid device in different
way:
1. Some platforms send "open" events to OS and the events arrive before
   button driver is resumed;
2. Some platforms send "open" events to OS, but the events arrive after
   button driver is resumed, ex., Samsung N210+;
3. Some platforms never send "open" events to OS, but send "open" events to
   update the cached _LID return value, and the update events arrive before
   button driver is resumed;
4. Some platforms never send "open" events to OS, but send "open" events to
   update the cached _LID return value, but the update events arrive after
   button driver is resumed, ex., Surface Pro 3;
5. Some platforms never send "open" events, _LID returns value sticks to
   "close", ex., Surface Pro 1.

This series tries to provide solutions to fix all cases for old userspace
programs. These solutions include:
1. Fix order issue in case 2,4. Enabled by default.
2. Fix event missing issue in case 3,4. As newer systemd doesn't require
   this fix, and this fix is not power friendly, it is not enabled by
   default, but can be enabled by:
   2.1. button.lid_periodic_update=1: periodically sends _LID value to
the input layer.
3. Fix persistate close issue in case 5, as newer systemd doesn't require
   this fix, it is not enabled by default, but can be enabled in 2 means:
   3.1. button.lid_init_state=ignore: only adds complement open events.
   3.2. lid_unreliable=1: dymamically adds/removes input node.

Benjamin Tissoires (2):
  ACPI: button: extract input creation/destruction helpers
  ACPI: button: Add an optional workaround to fix a persistent close
issue for old userspace

Lv Zheng (3):
  ACPI: button: Add a workaround to fix an order issue for old userspace
  ACPI: button: Add an optional workaround to fix an event missing issue
for old userspace
  ACPI: button: Rework lid_init_state=ignore mode

 drivers/acpi/button.c | 302 +++---
 1 file changed, 186 insertions(+), 116 deletions(-)

-- 
2.7.4



[PATCH v3 2/4] ACPI / EC: Add support to skip boot stage DSDT probe

2017-06-14 Thread Lv Zheng
We prepared _INI/_STA methods for \_SB, \_SB.PCI0, \_SB.LID0 and \_SB.EC,
_HID(PNP0C09)/_CRS/_GPE for \_SB.EC to poke Windows behavior with qemu, we
got the following execution sequence:
 \_SB._INI
 \_SB.PCI0._STA
 \_SB.LID0._STA
 \_SB.EC._STA
 \_SB.PCI0._INI
 \_SB.LID0._INI
 \_SB.EC._INI
There is no extra DSDT EC device enumeration process occurring before the
main ACPI device enumeration process. That means acpi_ec_dsdt_probe() is
not a Windows compliant approach, it's just a linux workaround.

Tracking back, we can see a long time ago, Linux EC driver won't probe DSDT
EC during boot. It was added by the following commit (see link #1 for bug
report):
  Commit: c5279dee26c0e8d7c4200993bfc4b540d2469598
  Subject: ACPI: EC: Add some basic check for ECDT data
This commit simply drivers Linux EC driver to a wrong direction.

Why we shouldn't enumerate DSDT EC before the main ACPI device enumeration?
The only way to know if the DSDT EC is valid is to evaluate its _STA
control method, but it's not proper to evaluate this control method that
early and out of the ACPI enumeration process because _STA may contain
other devices' initialization code and such devices may not have been
initialized before OSPM starts to enumerate them via the main ACPI device
enumeration.

But after we reverted back to the expected behavior, someone reported a
regression (see link #2 for reference). On that platform, there is no ECDT,
but the platform control methods access EC operation region earlier than
Linux expects, causing some ACPI method execution errors. According to the
regression rule, we just revert back to old behavior to still probe DSDT EC
as boot EC.

Now we've been reported 3rd functional breakage (link #3). In order to
handle both issues (link #2 and link #3), we could just skip boot stage
DSDT probe when ECDT exists so that a later quirk can always use correct
ECDT GPE setting.

Link: http://bugzilla.kernel.org/show_bug.cgi?id=11880 [#1]
Link: http://bugzilla.kernel.org/show_bug.cgi?id=119261 [#2]
Link: http://bugzilla.kernel.org/show_bug.cgi?id=195651 [#3]
Tested-by: Daniel Drake 
Signed-off-by: Lv Zheng 
---
 drivers/acpi/ec.c | 22 ++
 1 file changed, 22 insertions(+)

diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index c1f480b..44b973e 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -1667,12 +1667,34 @@ static const struct acpi_device_id ec_device_ids[] = {
{"", 0},
 };
 
+/*
+ * This function is not Windows compliant as Windows never enumerates the
+ * namespace EC before the main ACPI device enumeration process. This
+ * function is kept for historical reason and will be deprecated in the
+ * future.
+ *
+ * It's added due to a non-root-caused bug fix:
+ *  http://bugzilla.kernel.org/show_bug.cgi?id=11880
+ * But removing it now unfortunately triggers user noticable regression:
+ *  http://bugzilla.kernel.org/show_bug.cgi?id=119261
+ */
 int __init acpi_ec_dsdt_probe(void)
 {
acpi_status status;
struct acpi_ec *ec;
int ret;
 
+   /*
+* If a platform has ECDT, there is no need to proceed as the
+* following probe is not a part of the ACPI device enumeration,
+* executing _STA is not safe, and thus this probe may risk of
+* picking up an invalid EC device.
+* So we should catch any possible chance to avoid applying this
+* quirk.
+*/
+   if (boot_ec)
+   return -ENODEV;
+
ec = acpi_ec_alloc();
if (!ec)
return -ENOMEM;
-- 
2.7.4



[PATCH v3 3/4] ACPI / EC: Fix media keys not working problem on some Asus laptops

2017-06-14 Thread Lv Zheng
From: Chris Chiu 

Some Asus laptops (verified on X550VXK/FX502VD/FX502VE) get no
interrupts when pressing media keys thus the corresponding functions
are not invoked. It's due to the _GPE defines in DSDT for EC returns
differnt value compared to the GPE Number in ECDT. Confirmed with Asus
that the vale in ECDT is the correct one. This commit uses DMI quirks
to prevent calling _GPE when doing ec_parse_device() and keep the ECDT
GPE number setting for the EC device.

With previous commit, it is ensured that if there is an ECDT, it can always
be kept as boot_ec, this patch thus can implement the quirk on top of the
determined ECDT boot_ec.

Link: https://phabricator.endlessm.com/T16033
  https://phabricator.endlessm.com/T16722
Link: https://bugzilla.kernel.org/show_bug.cgi?id=195651
Tested-by: Daniel Drake 
Signed-off-by: Chris Chiu 
Signed-off-by: Carlo Caione 
Signed-off-by: Lv Zheng 

Signed-off-by: Lv Zheng 
---
 drivers/acpi/ec.c | 49 +++--
 1 file changed, 43 insertions(+), 6 deletions(-)

diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 44b973e..2189048 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -190,6 +190,7 @@ static struct workqueue_struct *ec_query_wq;
 
 static int EC_FLAGS_QUERY_HANDSHAKE; /* Needs QR_EC issued when SCI_EVT set */
 static int EC_FLAGS_CORRECT_ECDT; /* Needs ECDT port address correction */
+static int EC_FLAGS_IGNORE_DSDT_GPE; /* Needs ECDT GPE as correction setting */
 
 /* --
  *   Logging/Debugging
@@ -1365,12 +1366,20 @@ ec_parse_device(acpi_handle handle, u32 Level, void 
*context, void **retval)
if (ec->data_addr == 0 || ec->command_addr == 0)
return AE_OK;
 
-   /* Get GPE bit assignment (EC events). */
-   /* TODO: Add support for _GPE returning a package */
-   status = acpi_evaluate_integer(handle, "_GPE", NULL, &tmp);
-   if (ACPI_FAILURE(status))
-   return status;
-   ec->gpe = tmp;
+   if (boot_ec && boot_ec_is_ecdt && EC_FLAGS_IGNORE_DSDT_GPE) {
+   /*
+* Always inherit the GPE number setting from the ECDT
+* EC.
+*/
+   ec->gpe = boot_ec->gpe;
+   } else {
+   /* Get GPE bit assignment (EC events). */
+   /* TODO: Add support for _GPE returning a package */
+   status = acpi_evaluate_integer(handle, "_GPE", NULL, &tmp);
+   if (ACPI_FAILURE(status))
+   return status;
+   ec->gpe = tmp;
+   }
/* Use the global lock for all EC transactions? */
tmp = 0;
acpi_evaluate_integer(handle, "_GLK", NULL, &tmp);
@@ -1777,11 +1786,39 @@ static int ec_correct_ecdt(const struct dmi_system_id 
*id)
return 0;
 }
 
+/*
+ * Some DSDTs contain wrong GPE setting.
+ * Asus FX502VD/VE, X550VXK, X580VD
+ * https://bugzilla.kernel.org/show_bug.cgi?id=195651
+ */
+static int ec_honor_ecdt_gpe(const struct dmi_system_id *id)
+{
+   pr_debug("Detected system needing ignore DSDT GPE setting.\n");
+   EC_FLAGS_IGNORE_DSDT_GPE = 1;
+   return 0;
+}
+
 static struct dmi_system_id ec_dmi_table[] __initdata = {
{
ec_correct_ecdt, "MSI MS-171F", {
DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star"),
DMI_MATCH(DMI_PRODUCT_NAME, "MS-171F"),}, NULL},
+   {
+   ec_honor_ecdt_gpe, "ASUS FX502VD", {
+   DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+   DMI_MATCH(DMI_PRODUCT_NAME, "FX502VD"),}, NULL},
+   {
+   ec_honor_ecdt_gpe, "ASUS FX502VE", {
+   DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+   DMI_MATCH(DMI_PRODUCT_NAME, "FX502VE"),}, NULL},
+   {
+   ec_honor_ecdt_gpe, "ASUS X550VXK", {
+   DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+   DMI_MATCH(DMI_PRODUCT_NAME, "X550VXK"),}, NULL},
+   {
+   ec_honor_ecdt_gpe, "ASUS X580VD", {
+   DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+   DMI_MATCH(DMI_PRODUCT_NAME, "X580VD"),}, NULL},
{},
 };
 
-- 
2.7.4



[PATCH v3 4/4] ACPI / EC: Add quirk for GL720VMK

2017-06-14 Thread Lv Zheng
From: Carlo Caione 

ASUS GL720VMK is also affected by the EC GPE preference issue.

Signed-off-by: Carlo Caione 
Signed-off-by: Lv Zheng 
---
 drivers/acpi/ec.c | 6 +-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 2189048..ab04f0c 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -1788,7 +1788,7 @@ static int ec_correct_ecdt(const struct dmi_system_id *id)
 
 /*
  * Some DSDTs contain wrong GPE setting.
- * Asus FX502VD/VE, X550VXK, X580VD
+ * Asus FX502VD/VE, GL702VMK, X550VXK, X580VD
  * https://bugzilla.kernel.org/show_bug.cgi?id=195651
  */
 static int ec_honor_ecdt_gpe(const struct dmi_system_id *id)
@@ -1812,6 +1812,10 @@ static struct dmi_system_id ec_dmi_table[] __initdata = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "FX502VE"),}, NULL},
{
+   ec_honor_ecdt_gpe, "ASUS GL702VMK", {
+   DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+   DMI_MATCH(DMI_PRODUCT_NAME, "GL702VMK"),}, NULL},
+   {
ec_honor_ecdt_gpe, "ASUS X550VXK", {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "X550VXK"),}, NULL},
-- 
2.7.4



[PATCH v3 1/4] ACPI / EC: Enhance boot EC sanity check

2017-06-14 Thread Lv Zheng
It's reported that some buggy BIOS tables can contain 2 DSDT ECs, one of
them is invalid but acpi_ec_dsdt_probe() fails to pick the valid one.
This patch simply enhances sanity checks in ec_parse_device() as a
workaround to skip probing wrong namespace ECs.

Link: https://bugzilla.kernel.org/show_bug.cgi?id=195651
Tested-by: Daniel Drake 
Signed-off-by: Lv Zheng 
---
 drivers/acpi/ec.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index c24235d..c1f480b 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -1362,6 +1362,8 @@ ec_parse_device(acpi_handle handle, u32 Level, void 
*context, void **retval)
 ec_parse_io_ports, ec);
if (ACPI_FAILURE(status))
return status;
+   if (ec->data_addr == 0 || ec->command_addr == 0)
+   return AE_OK;
 
/* Get GPE bit assignment (EC events). */
/* TODO: Add support for _GPE returning a package */
-- 
2.7.4



[PATCH v3 0/4] ACPI / EC: Add quirk modes for boot EC support

2017-06-14 Thread Lv Zheng
It's reported that Asus laptop X580VD/X550VXK/GL720VMK/FX502VD/FX502VE have
a BIOS bug where the ECDT correctly states that EC events trigger GPE 0x23,
but the DSDT _GPE method incorrectly returns GPE 0x33.

This patchset fixes this issue.

Link: https://www.spinics.net/lists/linux-acpi/msg73763.html
  https://bugzilla.kernel.org/show_bug.cgi?id=195651

v2: Stops doing craps related to EC_ID (it's already too complicated), and
reduces one unnecessary boot parameter. For the final bug fix, prefers
the fix from endlessm.com developers.
v3: Removes improper statments related to _STA as acpi_get_devices() has
executed _STA before invoking ec_parse_device() adds detailed
explanation for why acpi_ec_dsdt_probe() is a wrong approach.
Carlo Caione helps to add a new quirk for GL720VMK.

Carlo Caione (1):
  ACPI / EC: Add quirk for GL720VMK

Chris Chiu (1):
  ACPI / EC: Fix media keys not working problem on some Asus laptops

Lv Zheng (2):
  ACPI / EC: Enhance boot EC sanity check
  ACPI / EC: Add support to skip boot stage DSDT probe

 drivers/acpi/ec.c | 77 ++-
 1 file changed, 71 insertions(+), 6 deletions(-)

-- 
2.7.4



[PATCH 2/3] ACPI: EC: Fix EC command visibility for dynamic debug

2017-06-13 Thread Lv Zheng
acpi_ec_cmd_string() currently is only enabled for "DEBUG" macro, but users
trend to use CONFIG_DYNAMIC_DEBUG and enable ec.c pr_debug() print-outs by
"dyndbg='file ec.c +p'". In this use case, all command names are turned
into UNDEF and the log is confusing. This affects bugzilla triage work.

This patch fixes this issue by enabling acpi_ec_cmd_string() for
CONFIG_DYNAMIC_DEBUG.

Tested-by: Wang Wendy 
Tested-by: Feng Chenzhou 
Signed-off-by: Lv Zheng 
---
 drivers/acpi/ec.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 30d7f82..f3ff591 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -316,7 +316,7 @@ static inline void acpi_ec_write_data(struct acpi_ec *ec, 
u8 data)
ec->timestamp = jiffies;
 }
 
-#ifdef DEBUG
+#if defined(DEBUG) || defined(CONFIG_DYNAMIC_DEBUG)
 static const char *acpi_ec_cmd_string(u8 cmd)
 {
switch (cmd) {
-- 
2.7.4



[PATCH 3/3] ACPI: EC: Change EC noirq tuning to be an optional behavior

2017-06-13 Thread Lv Zheng
According to the bug report, though the busy polling mode can make noirq
stages executed faster, it causes abnormal fan blowing in noirq stages.

This patch prepares an option so that the automatic busy polling mode
switching for noirq stages can be enabled by who wants to tune it, not all
users.
Noticed that the new global option cannot be changed during noirq stages.
There is no need to lock its value changes to sync with polling mode
settings switches.

For reporters and testers in the thread, as there are too many reporters
on the bug link, this patch only picks names from most active commenters.
Sorry for the neglet.

Link: https://bugzilla.kernel.org/show_bug.cgi?id=191181
Reported-by: Tatsuyuki Ishi 
Reported-by: Claudio Sacerdoti Coen 
Tested-by: Nicolo' 
Reported-by: Jens Axboe 
Tested-by: Gjorgji Jankovski 
Tested-by: Damjan Georgievski 
Tested-by: Fernando Chaves 
Signed-off-by: Lv Zheng 
---
 drivers/acpi/ec.c | 20 ++--
 1 file changed, 14 insertions(+), 6 deletions(-)

diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index f3ff591..de5dde6 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -151,6 +151,10 @@ static bool ec_freeze_events __read_mostly = true;
 module_param(ec_freeze_events, bool, 0644);
 MODULE_PARM_DESC(ec_freeze_events, "Disabling event handling during 
suspend/resume");
 
+static bool ec_tune_noirq __read_mostly = false;
+module_param(ec_tune_noirq, bool, 0644);
+MODULE_PARM_DESC(ec_tune_noirq, "Automatic enabling busy polling to tune noirq 
stages faster");
+
 struct acpi_ec_query_handler {
struct list_head node;
acpi_ec_query_func func;
@@ -979,9 +983,11 @@ static void acpi_ec_enter_noirq(struct acpi_ec *ec)
unsigned long flags;
 
spin_lock_irqsave(&ec->lock, flags);
-   ec->busy_polling = true;
-   ec->polling_guard = 0;
-   ec_log_drv("interrupt blocked");
+   if (ec_tune_noirq) {
+   ec->busy_polling = true;
+   ec->polling_guard = 0;
+   ec_log_drv("interrupt blocked");
+   }
spin_unlock_irqrestore(&ec->lock, flags);
 }
 
@@ -990,9 +996,11 @@ static void acpi_ec_leave_noirq(struct acpi_ec *ec)
unsigned long flags;
 
spin_lock_irqsave(&ec->lock, flags);
-   ec->busy_polling = ec_busy_polling;
-   ec->polling_guard = ec_polling_guard;
-   ec_log_drv("interrupt unblocked");
+   if (ec_tune_noirq) {
+   ec->busy_polling = ec_busy_polling;
+   ec->polling_guard = ec_polling_guard;
+   ec_log_drv("interrupt unblocked");
+   }
spin_unlock_irqrestore(&ec->lock, flags);
 }
 
-- 
2.7.4



[PATCH 1/3] ACPI: EC: Fix an EC event IRQ storming issue

2017-06-13 Thread Lv Zheng
The EC event IRQ (SCI_EVT) can only be handled by submitting QR_EC. As the
EC driver handles SCI_EVT in a workqueue, after SCI_EVT is flagged and
before QR_EC is submitted, there is a period risking IRQ storming. EC IRQ
must be masked for this period but linux EC driver never does so.

No end user notices the IRQ storming and no developer fixes this known
issue because:
1. the EC IRQ is always edge triggered GPE, and
2. the kernel can execute no-op EC IRQ handler very fast.
For edge triggered EC GPE platforms, it is only reported of post-resume EC
event lost issues, there won't be an IRQ storming. For level triggered EC
GPE platforms, fortunately the kernel is always fast enough to execute such
a no-op EC IRQ handler so that the IRQ handler won't be accumulated to
starve the task contexts, causing a real IRQ storming.

But the IRQ storming actually can still happen when:
1. the EC IRQ performs like level triggered GPE, and
2. the kernel EC debugging log is turned on but the console is slow enough.
There are more and more platforms using EC GPE as wake GPE where the EC GPE
is likely designed as level triggered. Then when EC debugging log is
enabled, the EC IRQ handler is no longer a no-op but dumps IRQ status to
the consoles. If the consoles are slow enough, the EC IRQs can arrive much
faster than executing the handler. Finally the accumulated EC event IRQ
handlers starve the task contexts, causing the IRQ storming to occur, and
the kernel hangs can be observed during boot/resume.

See link #1 for reference, however the bug link can only be accessed by
priviledged Intel users.

This patch fixes this issue by masking EC IRQ for this period:
1. begins when there is an SCI_EVT IRQ pending, and
2. ends when there is a QR_EC completed (SCI_EVT acknowledged).

Link: https://jira01.devtools.intel.com/browse/LCK-4004 [#1]
Tested-by: Wang Wendy 
Tested-by: Feng Chenzhou 
Signed-off-by: Lv Zheng 
---
 drivers/acpi/ec.c | 11 ++-
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index c24235d..30d7f82 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -459,8 +459,10 @@ static bool acpi_ec_submit_flushable_request(struct 
acpi_ec *ec)
 
 static void acpi_ec_submit_query(struct acpi_ec *ec)
 {
-   if (acpi_ec_event_enabled(ec) &&
-   !test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) {
+   acpi_ec_set_storm(ec, EC_FLAGS_COMMAND_STORM);
+   if (!acpi_ec_event_enabled(ec))
+   return;
+   if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) {
ec_dbg_evt("Command(%s) submitted/blocked",
   acpi_ec_cmd_string(ACPI_EC_COMMAND_QUERY));
ec->nr_pending_queries++;
@@ -470,11 +472,10 @@ static void acpi_ec_submit_query(struct acpi_ec *ec)
 
 static void acpi_ec_complete_query(struct acpi_ec *ec)
 {
-   if (test_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) {
-   clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags);
+   if (test_and_clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags))
ec_dbg_evt("Command(%s) unblocked",
   acpi_ec_cmd_string(ACPI_EC_COMMAND_QUERY));
-   }
+   acpi_ec_clear_storm(ec, EC_FLAGS_COMMAND_STORM);
 }
 
 static inline void __acpi_ec_enable_event(struct acpi_ec *ec)
-- 
2.7.4



[RFC PATCH v5 1/2] ACPI: button: Fix issue that button notify cannot report stateful SW_LID state

2017-06-07 Thread Lv Zheng
There are platform variations implementing ACPI lid device in different
ways:
1. Some platforms send "open" events to OS and the events arrive before
   button driver is resumed;
2. Some platforms send "open" events to OS, but the events arrive after
   button driver is resumed, ex., Samsung N210+;
3. Some platforms never send "open" events to OS, but send "open" events to
   update the cached _LID return value, and the update events arrive before
   button driver is resumed;
4. Some platforms never send "open" events to OS, but send "open" events to
   update the cached _LID return value, but the update events arrive after
   button driver is resumed, ex., Surface Pro 3;
5. Some platforms never send "open" events, _LID returns value sticks to
   "close", ex., Surface Pro 1.
Currently, only case 1,3 works fine with systemd 229.

Case 2,4 can be treated as an order issue. This patch first fixes this
issue by defer sending initial lid state 10 seconds later after resume,
which ensures acpi_ec_resume() is always invoked before
acpi_button_resume().

However we can see different problems due to systemd bugs:
  systemd won't suspend right after seeing "close" event, it has a timeout,
  within the timeout, user may opens lid again. But even lid
  firmware/driver properly deliver this "open" to user space, when the
  timeout tickes, systemd still suspends the platform.
  Then user has to close/open again to wake the system up. Noticing that
  the first close event will remain in firmware, after resume, user space
  can still see a "close" followed by "open", and nothing can stop systemd
  from suspending again.
This problem can only be fixed by continously updating lid state. Thus
this patch doesn't kill the timer after seeing the BIOS notification, but
continously sending _LID return value to the input layer for
button.lid_init_state=method mode.

The users can configure update interval via button.lid_update_interval.

Cc: 
Cc: Benjamin Tissoires 
Cc: Peter Hutterer 
Signed-off-by: Lv Zheng 
---
 drivers/acpi/button.c | 36 +---
 1 file changed, 29 insertions(+), 7 deletions(-)

diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c
index e19f530..fd8eff6 100644
--- a/drivers/acpi/button.c
+++ b/drivers/acpi/button.c
@@ -28,6 +28,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -79,6 +80,7 @@ MODULE_DEVICE_TABLE(acpi, button_device_ids);
 static int acpi_button_add(struct acpi_device *device);
 static int acpi_button_remove(struct acpi_device *device);
 static void acpi_button_notify(struct acpi_device *device, u32 event);
+static void acpi_lid_timeout(ulong arg);
 
 #ifdef CONFIG_PM_SLEEP
 static int acpi_button_suspend(struct device *dev);
@@ -104,6 +106,7 @@ static struct acpi_driver acpi_button_driver = {
 struct acpi_button {
unsigned int type;
struct input_dev *input;
+   struct timer_list lid_timer;
char phys[32];  /* for input device */
unsigned long pushed;
int last_state;
@@ -119,6 +122,10 @@ static unsigned long lid_report_interval __read_mostly = 
500;
 module_param(lid_report_interval, ulong, 0644);
 MODULE_PARM_DESC(lid_report_interval, "Interval (ms) between lid key events");
 
+static unsigned long lid_update_interval __read_mostly = 10 * MSEC_PER_SEC;
+module_param(lid_update_interval, ulong, 0644);
+MODULE_PARM_DESC(lid_update_interval, "Interval (ms) between lid state 
updates");
+
 /* --
   FS Interface (/proc)
-- 
*/
@@ -371,17 +378,25 @@ static int acpi_lid_update_state(struct acpi_device 
*device)
return acpi_lid_notify_state(device, state);
 }
 
-static void acpi_lid_initialize_state(struct acpi_device *device)
+static void acpi_lid_tick(struct acpi_device *device)
+{
+   struct acpi_button *button = acpi_driver_data(device);
+
+   mod_timer(&button->lid_timer,
+ jiffies + msecs_to_jiffies(lid_update_interval));
+}
+
+static void acpi_lid_timeout(ulong arg)
 {
+   struct acpi_device *device = (struct acpi_device *)arg;
+
switch (lid_init_state) {
case ACPI_BUTTON_LID_INIT_OPEN:
(void)acpi_lid_notify_state(device, 1);
break;
case ACPI_BUTTON_LID_INIT_METHOD:
-   (void)acpi_lid_update_state(device);
-   break;
-   case ACPI_BUTTON_LID_INIT_IGNORE:
-   default:
+   acpi_lid_update_state(device);
+   acpi_lid_tick(device);
break;
}
 }
@@ -432,6 +447,8 @@ static int acpi_button_suspend(struct device *dev)
struct acpi_device *device = to_acpi_device(dev);
  

[RFC PATCH v5 2/2] ACPI: button: Add a quirk mode for Surface Pro 1 like laptop

2017-06-07 Thread Lv Zheng
Some platforms never send "open" events, _LID returns value sticks to
"close", ex., Surface Pro 1.

Such platforms cannot work well with systemd 229 in
button.lid_init_state=method mode, but button.lid_init_state=open
workaround is available for them to work with systemd 229 and they can work
perfectly with systemd 233 in button.lid_init_state=ignore mode.

This patch introduces a boot parameter to mark such platform lid device as
unreliable to replace old button.lid_init_state=ignore mode. So that users
can use this quirk to make such platforms working with systemd 233. Since
such platform only sends "close", old complicated "open" complement event
mechanism is replaced by a simpler one of always prepending "open" before
any events.

Cc: 
Cc: Benjamin Tissoires 
Cc: Peter Hutterer 
Signed-off-by: Lv Zheng 
---
 drivers/acpi/button.c | 164 --
 1 file changed, 66 insertions(+), 98 deletions(-)

diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c
index fd8eff6..02b85c1 100644
--- a/drivers/acpi/button.c
+++ b/drivers/acpi/button.c
@@ -56,9 +56,8 @@
 #define ACPI_BUTTON_DEVICE_NAME_LID"Lid Switch"
 #define ACPI_BUTTON_TYPE_LID   0x05
 
-#define ACPI_BUTTON_LID_INIT_IGNORE0x00
+#define ACPI_BUTTON_LID_INIT_METHOD0x00
 #define ACPI_BUTTON_LID_INIT_OPEN  0x01
-#define ACPI_BUTTON_LID_INIT_METHOD0x02
 
 #define _COMPONENT ACPI_BUTTON_COMPONENT
 ACPI_MODULE_NAME("button");
@@ -109,23 +108,20 @@ struct acpi_button {
struct timer_list lid_timer;
char phys[32];  /* for input device */
unsigned long pushed;
-   int last_state;
-   ktime_t last_time;
bool suspended;
 };
 
+static DEFINE_MUTEX(lid_device_lock);
 static BLOCKING_NOTIFIER_HEAD(acpi_lid_notifier);
 static struct acpi_device *lid_device;
 static u8 lid_init_state = ACPI_BUTTON_LID_INIT_METHOD;
 
-static unsigned long lid_report_interval __read_mostly = 500;
-module_param(lid_report_interval, ulong, 0644);
-MODULE_PARM_DESC(lid_report_interval, "Interval (ms) between lid key events");
-
 static unsigned long lid_update_interval __read_mostly = 10 * MSEC_PER_SEC;
 module_param(lid_update_interval, ulong, 0644);
 MODULE_PARM_DESC(lid_update_interval, "Interval (ms) between lid state 
updates");
 
+static bool lid_unreliable __read_mostly = false;
+
 /* --
   FS Interface (/proc)
-- 
*/
@@ -149,79 +145,12 @@ static int acpi_lid_notify_state(struct acpi_device 
*device, int state)
 {
struct acpi_button *button = acpi_driver_data(device);
int ret;
-   ktime_t next_report;
-   bool do_update;
-
-   /*
-* In lid_init_state=ignore mode, if user opens/closes lid
-* frequently with "open" missing, and "last_time" is also updated
-* frequently, "close" cannot be delivered to the userspace.
-* So "last_time" is only updated after a timeout or an actual
-* switch.
-*/
-   if (lid_init_state != ACPI_BUTTON_LID_INIT_IGNORE ||
-   button->last_state != !!state)
-   do_update = true;
-   else
-   do_update = false;
-
-   next_report = ktime_add(button->last_time,
-   ms_to_ktime(lid_report_interval));
-   if (button->last_state == !!state &&
-   ktime_after(ktime_get(), next_report)) {
-   /* Complain the buggy firmware */
-   pr_warn_once("The lid device is not compliant to SW_LID.\n");
 
-   /*
-* Send the unreliable complement switch event:
-*
-* On most platforms, the lid device is reliable. However
-* there are exceptions:
-* 1. Platforms returning initial lid state as "close" by
-*default after booting/resuming:
-* https://bugzilla.kernel.org/show_bug.cgi?id=89211
-* https://bugzilla.kernel.org/show_bug.cgi?id=106151
-* 2. Platforms never reporting "open" events:
-* https://bugzilla.kernel.org/show_bug.cgi?id=106941
-* On these buggy platforms, the usage model of the ACPI
-* lid device actually is:
-* 1. The initial returning value of _LID may not be
-*reliable.
-* 2. The open event may not be reliable.
-* 3. The close event is reliable.
-*
-* But SW_LID is typed as input switch event, the input
-* layer checks if the event is redundant. Hence if the
- 

[RFC PATCH 0/2] ACPI: button: Fix button.lid_init_state=method mode

2017-06-07 Thread Lv Zheng
The following approach fixes button.lid_init_state=method mode for
systemd 233:
 https://patchwork.kernel.org/patch/9756457/
 https://patchwork.kernel.org/patch/9756467/
But it is not working well with old systemd 229. This solution tries to
make a more comfortable approach for systemd 229.

There are platform variations implementing ACPI lid device in different
way:
1. Some platforms send "open" events to OS and the events arrive before
   button driver is resumed;
2. Some platforms send "open" events to OS, but the events arrive after
   button driver is resumed, ex., Samsung N210+;
3. Some platforms never send "open" events to OS, but send "open" events to
   update the cached _LID return value, and the update events arrive before
   button driver is resumed;
4. Some platforms never send "open" events to OS, but send "open" events to
   update the cached _LID return value, but the update events arrive after
   button driver is resumed, ex., Surface Pro 3;
5. Some platforms never send "open" events, _LID returns value sticks to
   "close", ex., Surface Pro 1.

[PATCH 1] tries to fix case 2,4, making them working with any systemd.
[PATCH 2] tries to fix case 5, making it working with systemd 233.
  This is also a replacement of the following solution:
   https://patchwork.kernel.org/patch/9760867/
  It seems adding/removing input node and requesting systemd to
  change again is unnecessary for such platforms, so this patch
  simply converts "lid_unreliable" into
  "button.lid_init_state=ignore".

This material is just sent to demonstrate solutions and issues, the
final solution is not determined yet. So marking them as RFC.

Lv Zheng (2):
  ACPI: button: Fix issue that button notify cannot report stateful
SW_LID state
  ACPI: button: Add a quirk mode for Surface Pro 1 like laptop

 drivers/acpi/button.c | 188 --
 1 file changed, 89 insertions(+), 99 deletions(-)

-- 
2.7.4



[PATCH v5] ACPICA: Tables: Add mechanism to allow to balance late stage acpi_get_table() independently

2017-06-06 Thread Lv Zheng
Considering this case:
1. A program opens a sysfs table file 65535 times, it can increase
   validation_count and first increment cause the table to be mapped:
validation_count = 65535
2. AML execution causes "Load" to be executed on the same table, this time
   it cannot increase validation_count, so validation_count remains:
validation_count = 65535
3. The program closes sysfs table file 65535 times, it can decrease
   validation_count and the last decrement cause the table to be unmapped:
validation_count = 0
4. AML code still accessing the loaded table, kernel crash can be observed.

This is because orginally ACPICA doesn't support unmapping tables during
OS late stage. So the current code only allows unmapping tables during OS
early stage, and for late stage, no acpi_put_table() clones should be
invoked, especially cases that can trigger frequent invocations of
acpi_get_table()/acpi_put_table() are forbidden:
1. sysfs table accesses
2. dynamic Load/Unload opcode executions
3. acpi_load_table()
4. etc.
Such frequent acpi_put_table() balance changes have to be done altogether.

This philosophy is not convenient for Linux driver writers. Since the API
is just there, developers will start to use acpi_put_table() during late
stage. So we need to consider a better mechanism to allow them to safely
invoke acpi_put_table().

This patch provides such a mechanism by adding a validation_count
threashold. When it is reached, the validation_count can no longer be
incremented/decremented to invalidate the table descriptor (means
preventing table unmappings) so that acpi_put_table() balance changes can be
done independently to each others.

Note: code added in acpi_tb_put_table() is actually a no-op but changes the
warning message into a warning once message. Lv Zheng.

Signed-off-by: Lv Zheng 
---
 drivers/acpi/acpica/tbutils.c | 36 +++-
 include/acpi/actbl.h  | 13 +
 2 files changed, 40 insertions(+), 9 deletions(-)

diff --git a/drivers/acpi/acpica/tbutils.c b/drivers/acpi/acpica/tbutils.c
index cd96026..4048523 100644
--- a/drivers/acpi/acpica/tbutils.c
+++ b/drivers/acpi/acpica/tbutils.c
@@ -416,9 +416,19 @@ acpi_tb_get_table(struct acpi_table_desc *table_desc,
}
}
 
-   table_desc->validation_count++;
-   if (table_desc->validation_count == 0) {
-   table_desc->validation_count--;
+   if (table_desc->validation_count < ACPI_MAX_TABLE_VALIDATIONS) {
+   table_desc->validation_count++;
+
+   /*
+* Ensure the warning message can only be displayed once. The
+* warning message occurs when the "get" operations are 
performed
+* more than "put" operations, causing count overflow.
+*/
+   if (table_desc->validation_count >= ACPI_MAX_TABLE_VALIDATIONS) 
{
+   ACPI_WARNING((AE_INFO,
+ "Table %p, Validation count overflows\n",
+ table_desc));
+   }
}
 
*out_table = table_desc->pointer;
@@ -445,13 +455,21 @@ void acpi_tb_put_table(struct acpi_table_desc *table_desc)
 
ACPI_FUNCTION_TRACE(acpi_tb_put_table);
 
-   if (table_desc->validation_count == 0) {
-   ACPI_WARNING((AE_INFO,
- "Table %p, Validation count is zero before 
decrement\n",
- table_desc));
-   return_VOID;
+   if (table_desc->validation_count < ACPI_MAX_TABLE_VALIDATIONS) {
+   table_desc->validation_count--;
+
+   /*
+* Ensure the warning message can only be displayed once. The
+* warning message occurs when the "put" operations are 
performed
+* more than "get" operations, causing count underflow.
+*/
+   if (table_desc->validation_count >= ACPI_MAX_TABLE_VALIDATIONS) 
{
+   ACPI_WARNING((AE_INFO,
+ "Table %p, Validation count underflows\n",
+ table_desc));
+   return_VOID;
+   }
}
-   table_desc->validation_count--;
 
if (table_desc->validation_count == 0) {
 
diff --git a/include/acpi/actbl.h b/include/acpi/actbl.h
index d92543f..f42e6d5 100644
--- a/include/acpi/actbl.h
+++ b/include/acpi/actbl.h
@@ -374,6 +374,19 @@ struct acpi_table_desc {
u16 validation_count;
 };
 
+/*
+ * Maximum validation count, when it is reached, validation count can no
+ * longer be changed. Which means, the table can no longer be invalidated.
+ * This mechanism is implemented for backward compatibility, where in OS
+ * late stage, old drivers are not facilitated with pa

[RFC PATCH v4 5/5] ACPI: button: Cleanup lid notification logics

2017-05-31 Thread Lv Zheng
Both nouveau and i915, the only 2 kernel space lid notification listeners,
invoke acpi_lid_open() API to obtain _LID returning value instead of using
the notified value. So kernel graphics drivers are only interested in _LID
return value, hence this patch makes this logic explicit in button driver.

However the preference may because kernel graphics drivers do not want to
receive non-bios notifications. Thus this patch also adds a global variable
to allow button driver to stop notifying non-bios notifications.

This is a no-op cleanup as the default behaviors are kept unchanged, but
may:
1. improve button.lid_init_state=method by introducing a possibility to
   allow kernel graphics driver to reduce redundant _LID evaluations, and
2. improve button.lid_init_state=open/method by introducing a possibility
   to stop notifying faked non bios events.

Cc: Benjamin Tissoires 
Cc: Peter Hutterer 
Signed-off-by: Lv Zheng 
---
 drivers/acpi/button.c | 17 ++---
 1 file changed, 14 insertions(+), 3 deletions(-)

Index: linux-acpica/drivers/acpi/button.c
===
--- linux-acpica.orig/drivers/acpi/button.c
+++ linux-acpica/drivers/acpi/button.c
@@ -119,6 +119,7 @@ static u8 lid_init_state = ACPI_BUTTON_L
 static unsigned long lid_report_interval __read_mostly = 500;
 module_param(lid_report_interval, ulong, 0644);
 MODULE_PARM_DESC(lid_report_interval, "Interval (ms) between lid key events");
+static bool lid_notify_non_bios_events = true;
 
 /* --
   FS Interface (/proc)
@@ -224,7 +225,17 @@ static void acpi_lid_notify_state(struct
if (state)
pm_wakeup_hard_event(&device->dev);
 
-   acpi_lid_notifier_call(device, state);
+   if (is_bios_event || lid_notify_non_bios_events) {
+   /*
+* The kernel drivers are only interested in the _LID
+* return value. But there are cases "state" is not a _LID
+* return value, so correct it before notifying.
+*/
+   if (!is_bios_event &&
+   lid_init_state != ACPI_BUTTON_LID_INIT_METHOD)
+   state = acpi_lid_evaluate_state(device);
+   acpi_lid_notifier_call(device, state);
+   }
 }
 
 static int acpi_button_state_seq_show(struct seq_file *seq, void *offset)
@@ -573,13 +584,13 @@ static int param_set_lid_init_state(cons
 
if (!strncmp(val, "open", sizeof("open") - 1)) {
lid_init_state = ACPI_BUTTON_LID_INIT_OPEN;
-   pr_info("Notify initial lid state as open\n");
+   pr_info("Report initial lid state as open to input layer\n");
} else if (!strncmp(val, "method", sizeof("method") - 1)) {
lid_init_state = ACPI_BUTTON_LID_INIT_METHOD;
-   pr_info("Notify initial lid state with _LID return value\n");
+   pr_info("Report initial lid state with _LID return value to 
input layer\n");
} else if (!strncmp(val, "ignore", sizeof("ignore") - 1)) {
lid_init_state = ACPI_BUTTON_LID_INIT_IGNORE;
-   pr_info("Do not notify initial lid state\n");
+   pr_info("Do not report initial lid state to input layer\n");
} else
result = -EINVAL;
return result;


[RFC PATCH v4 2/5] ACPI: button: Extends complement switch event support for all modes

2017-05-31 Thread Lv Zheng
Surface Pro 3 is a typical platform where suspend/resume loop problem
can be seen.

The problem is due to a systemd 229 bug:
1. "ignore": always can trigger endless suspend/resume loop
2. "open": sometimes suspend/resume loop can be stopped
3. "method": always can trigger endless susped/resume loop
The buggy systemd unexpectedly waits for an explicit "open" event after
boot/resume or it will suspends. However even when kernel can send a
faked "open" to it, its state machine is still wrong, systemd may not
respond "close" events arrived after "open" or may suddenly suspend
without seeing any instant events.

Recent systemd 233 has fixed this issue:
1. "ignore": everything works fine;
2. "open": no suspend/resume cycle, but sometimes cannot suspend the
   platform again after the first resume;
3. "method": no suspend/resume cycle, but always cannot suspend the
 platform again after the first resume.
The conclusion is: for suspend/resume cycle issue, "ignore" mode fixes
everything, but current "method" mode is still buggy.
The differences are due to button driver only implements complement switch
events for "ignore" mode. Without complement switch events, firmware
triggered "close" cannot be delivered to userspace (confirmed by
evemu-record).

The root cause of the lid state issues is the variation of the platform
firmware implementations:
1. Some platforms send "open" events to OS and the events arrive before
   button driver is resumed;
2. Some platforms send "open" events to OS, but the events arrive after
   button driver is resumed, ex., Samsung N210+;
3. Some platforms never send "open" events to OS, but send "open" events to
   update the cached _LID return value, and the update events arrive before
   button driver is resumed;
4. Some platforms never send "open" events to OS, but send "open" events to
   update the cached _LID return value, but the update events arrive after
   button driver is resumed, ex., Surface Pro 3;
5. Some platforms never send "open" events, _LID returns value sticks to
   "close", ex., Surface Pro 1.

Let's check the docking external display issues (see links below):
1. For case 1, both "method"/"ignore" modes can work correctly;
2. For case 2/4/5, both "method"/"ignore" modes cannot work correctly;
3. For case 3, "method" can work correctly while "ignore" mode cannot.
The conclusion is: for docking external display issue, though the issue
still needs graphics layer (graphics drivers or desktop managers) to be
improved to ensure no breakages for case 2/4/5 platforms, there is a case
where "method" mode plays better.

Thus ACPI subsystem has been pushed to revert back to "method" mode due to
regression rule and case 3 (platforms reported on the links should all be
case 3 platforms), and libinput developers have volunteered to help to
provide workarounds when graphics layer is not fixed or systemd is not
updated.

Thus this patch extends the complement switch event support to other modes
using new indication: generating complement switch event for BIOS notified
"close". So that when button driver is reverted back to "method" mode, it
won't act worse than "ignore" mode on fixed systemd.

Tested with systemd 233, all modes worked fine (no suspend/resume loop and
can suspend any times) after applying this patch.

Link: https://bugzilla.kernel.org/show_bug.cgi?id=195455
  https://bugzilla.redhat.com/show_bug.cgi?id=1430259

Cc: 
Cc: Benjamin Tissoires 
Cc: Peter Hutterer 
Signed-off-by: Lv Zheng 
---
 drivers/acpi/button.c | 116 +-
 1 file changed, 57 insertions(+), 59 deletions(-)

diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c
index 725a15a..36485cf 100644
--- a/drivers/acpi/button.c
+++ b/drivers/acpi/button.c
@@ -108,6 +108,7 @@ struct acpi_button {
unsigned long pushed;
int last_state;
ktime_t last_time;
+   bool last_is_bios;
bool suspended;
 };
 
@@ -144,78 +145,71 @@ static int acpi_lid_notify_state(struct acpi_device 
*device,
struct acpi_button *button = acpi_driver_data(device);
int ret;
ktime_t next_report;
-   bool do_update;
 
/*
-* In lid_init_state=ignore mode, if user opens/closes lid
-* frequently with "open" missing, and "last_time" is also updated
-* frequently, "close" cannot be delivered to the userspace.
-* So "last_time" is only updated after a timeout or an actual
-* switch.
+* Ignore frequently replayed switch events.
+*
+* AML tables can put Notify(LID, xxx) in 

[RFC PATCH v4 4/5] ACPI: button: Fix lid notification locks

2017-05-31 Thread Lv Zheng
In acpi_lid_notify_state(), it now contains logic to avoid frequently
replayed events which originally was ensured by using blocking notifier.
On the contrary, using blocking notifier is wrong as it could keep on
returning NOTIFY_DONE, causing events lost.

This patch thus changes lid notification to raw notifier in order not to
have events lost.

Cc: Peter Hutterer 
Cc: Benjamin Tissoires 
Signed-off-by: Lv Zheng 
---
 drivers/acpi/button.c | 53 ---
 1 file changed, 29 insertions(+), 24 deletions(-)

diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c
index 13b75e6..a64b3f8 100644
--- a/drivers/acpi/button.c
+++ b/drivers/acpi/button.c
@@ -112,7 +112,7 @@ struct acpi_button {
bool suspended;
 };
 
-static BLOCKING_NOTIFIER_HEAD(acpi_lid_notifier);
+static RAW_NOTIFIER_HEAD(acpi_lid_notifier);
 static struct acpi_device *lid_device;
 static u8 lid_init_state = ACPI_BUTTON_LID_INIT_METHOD;
 
@@ -139,11 +139,16 @@ static int acpi_lid_evaluate_state(struct acpi_device 
*device)
return lid_state ? 1 : 0;
 }
 
-static int acpi_lid_notify_state(struct acpi_device *device,
+static inline void acpi_lid_notifier_call(struct acpi_device *device,
+ int state)
+{
+   (void)raw_notifier_call_chain(&acpi_lid_notifier, state, device);
+}
+
+static void acpi_lid_notify_state(struct acpi_device *device,
 int state, bool is_bios_event)
 {
struct acpi_button *button = acpi_driver_data(device);
-   int ret;
ktime_t next_report;
 
/*
@@ -161,7 +166,7 @@ static int acpi_lid_notify_state(struct acpi_device *device,
ms_to_ktime(lid_report_interval));
if (button->last_is_bios && button->last_state == !!state &&
!ktime_after(ktime_get(), next_report))
-   return 0;
+   return;
 
/*
 * Send the unreliable complement switch event:
@@ -219,18 +224,7 @@ static int acpi_lid_notify_state(struct acpi_device 
*device,
if (state)
pm_wakeup_hard_event(&device->dev);
 
-   ret = blocking_notifier_call_chain(&acpi_lid_notifier, state, device);
-   if (ret == NOTIFY_DONE)
-   ret = blocking_notifier_call_chain(&acpi_lid_notifier, state,
-  device);
-   if (ret == NOTIFY_DONE || ret == NOTIFY_OK) {
-   /*
-* It is also regarded as success if the notifier_chain
-* returns NOTIFY_OK or NOTIFY_DONE.
-*/
-   ret = 0;
-   }
-   return ret;
+   acpi_lid_notifier_call(device, state);
 }
 
 static int acpi_button_state_seq_show(struct seq_file *seq, void *offset)
@@ -341,13 +335,24 @@ static int acpi_button_remove_fs(struct acpi_device 
*device)
-- 
*/
 int acpi_lid_notifier_register(struct notifier_block *nb)
 {
-   return blocking_notifier_chain_register(&acpi_lid_notifier, nb);
+   return raw_notifier_chain_register(&acpi_lid_notifier, nb);
 }
 EXPORT_SYMBOL(acpi_lid_notifier_register);
 
+static inline int __acpi_lid_notifier_unregister(struct notifier_block *nb,
+bool sync)
+{
+   int ret;
+
+   ret = raw_notifier_chain_unregister(&acpi_lid_notifier, nb);
+   if (sync)
+   synchronize_rcu();
+   return ret;
+}
+
 int acpi_lid_notifier_unregister(struct notifier_block *nb)
 {
-   return blocking_notifier_chain_unregister(&acpi_lid_notifier, nb);
+   return __acpi_lid_notifier_unregister(nb, false);
 }
 EXPORT_SYMBOL(acpi_lid_notifier_unregister);
 
@@ -360,26 +365,26 @@ int acpi_lid_open(void)
 }
 EXPORT_SYMBOL(acpi_lid_open);
 
-static int acpi_lid_update_state(struct acpi_device *device,
-bool is_bios_event)
+static void acpi_lid_update_state(struct acpi_device *device,
+ bool is_bios_event)
 {
int state;
 
state = acpi_lid_evaluate_state(device);
if (state < 0)
-   return state;
+   return;
 
-   return acpi_lid_notify_state(device, state, is_bios_event);
+   acpi_lid_notify_state(device, state, is_bios_event);
 }
 
 static void acpi_lid_initialize_state(struct acpi_device *device)
 {
switch (lid_init_state) {
case ACPI_BUTTON_LID_INIT_OPEN:
-   (void)acpi_lid_notify_state(device, 1, false);
+   acpi_lid_notify_state(device, 1, false);
break;
case ACPI_BUTTON_LID_INIT_METHOD:
-   (void)acpi_lid_update_state(device, false);
+   acpi_lid_update_state(device, false);
break;
case ACPI_BUTTON_LID_INIT_IGNORE:
default:
-- 
2.7.4



[RFC PATCH v4 3/5] ACPI: button: Add lid event type debugging messages

2017-05-31 Thread Lv Zheng
This patch adds very useful debugging information to lid events.
These messages and with ec_log_drv() can be used to demonstrate the order
between acpi_ec_resume() and acpi_button_resume().

Cc: Benjamin Tissoires 
Cc: Peter Hutterer 
Signed-off-by: Lv Zheng 
---
 drivers/acpi/button.c | 5 +
 1 file changed, 5 insertions(+)

diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c
index 36485cf..13b75e6 100644
--- a/drivers/acpi/button.c
+++ b/drivers/acpi/button.c
@@ -201,12 +201,17 @@ static int acpi_lid_notify_state(struct acpi_device 
*device,
if (!state) {
input_report_switch(button->input, SW_LID, state);
input_sync(button->input);
+   pr_debug("faked open complement event.\n");
}
}
 
/* Send the platform triggered reliable event */
input_report_switch(button->input, SW_LID, !state);
input_sync(button->input);
+   if (is_bios_event)
+   pr_debug("notified %s event.\n", state ? "open" : "close");
+   else
+   pr_debug("faked %s event.\n", state ? "open" : "close");
button->last_state = !!state;
button->last_time = ktime_get();
button->last_is_bios = is_bios_event;
-- 
2.7.4



[RFC PATCH v4 1/5] ACPI: button: Add indication of BIOS notification and faked events

2017-05-31 Thread Lv Zheng
This patch adds a parameter to acpi_lid_notify_state() so that it can act
differently against BIOS notification and kernel faked events.

Cc: 
Cc: Benjamin Tissoires 
Cc: Peter Hutterer 
Signed-off-by: Lv Zheng 
---
 drivers/acpi/button.c | 14 --
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c
index 9ad8cdb..725a15a 100644
--- a/drivers/acpi/button.c
+++ b/drivers/acpi/button.c
@@ -138,7 +138,8 @@ static int acpi_lid_evaluate_state(struct acpi_device 
*device)
return lid_state ? 1 : 0;
 }
 
-static int acpi_lid_notify_state(struct acpi_device *device, int state)
+static int acpi_lid_notify_state(struct acpi_device *device,
+int state, bool is_bios_event)
 {
struct acpi_button *button = acpi_driver_data(device);
int ret;
@@ -360,7 +361,8 @@ int acpi_lid_open(void)
 }
 EXPORT_SYMBOL(acpi_lid_open);
 
-static int acpi_lid_update_state(struct acpi_device *device)
+static int acpi_lid_update_state(struct acpi_device *device,
+bool is_bios_event)
 {
int state;
 
@@ -368,17 +370,17 @@ static int acpi_lid_update_state(struct acpi_device 
*device)
if (state < 0)
return state;
 
-   return acpi_lid_notify_state(device, state);
+   return acpi_lid_notify_state(device, state, is_bios_event);
 }
 
 static void acpi_lid_initialize_state(struct acpi_device *device)
 {
switch (lid_init_state) {
case ACPI_BUTTON_LID_INIT_OPEN:
-   (void)acpi_lid_notify_state(device, 1);
+   (void)acpi_lid_notify_state(device, 1, false);
break;
case ACPI_BUTTON_LID_INIT_METHOD:
-   (void)acpi_lid_update_state(device);
+   (void)acpi_lid_update_state(device, false);
break;
case ACPI_BUTTON_LID_INIT_IGNORE:
default:
@@ -398,7 +400,7 @@ static void acpi_button_notify(struct acpi_device *device, 
u32 event)
case ACPI_BUTTON_NOTIFY_STATUS:
input = button->input;
if (button->type == ACPI_BUTTON_TYPE_LID) {
-   acpi_lid_update_state(device);
+   acpi_lid_update_state(device, true);
} else {
int keycode;
 
-- 
2.7.4



[RFC PATCH v3 1/5] ACPI: button: Add indication of BIOS notification and faked events

2017-05-26 Thread Lv Zheng
This patch adds a parameter to acpi_lid_notify_state() so that it can act
differently against BIOS notification and kernel faked events.

Cc: 
Cc: Benjamin Tissoires 
Cc: Peter Hutterer 
Signed-off-by: Lv Zheng 
---
 drivers/acpi/button.c | 14 --
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c
index 6d5a8c1..874ba60 100644
--- a/drivers/acpi/button.c
+++ b/drivers/acpi/button.c
@@ -138,7 +138,8 @@ static int acpi_lid_evaluate_state(struct acpi_device 
*device)
return lid_state ? 1 : 0;
 }
 
-static int acpi_lid_notify_state(struct acpi_device *device, int state)
+static int acpi_lid_notify_state(struct acpi_device *device,
+int state, bool bios_notify)
 {
struct acpi_button *button = acpi_driver_data(device);
int ret;
@@ -360,7 +361,8 @@ int acpi_lid_open(void)
 }
 EXPORT_SYMBOL(acpi_lid_open);
 
-static int acpi_lid_update_state(struct acpi_device *device)
+static int acpi_lid_update_state(struct acpi_device *device,
+bool bios_notify)
 {
int state;
 
@@ -368,17 +370,17 @@ static int acpi_lid_update_state(struct acpi_device 
*device)
if (state < 0)
return state;
 
-   return acpi_lid_notify_state(device, state);
+   return acpi_lid_notify_state(device, state, bios_notify);
 }
 
 static void acpi_lid_initialize_state(struct acpi_device *device)
 {
switch (lid_init_state) {
case ACPI_BUTTON_LID_INIT_OPEN:
-   (void)acpi_lid_notify_state(device, 1);
+   (void)acpi_lid_notify_state(device, 1, false);
break;
case ACPI_BUTTON_LID_INIT_METHOD:
-   (void)acpi_lid_update_state(device);
+   (void)acpi_lid_update_state(device, false);
break;
case ACPI_BUTTON_LID_INIT_IGNORE:
default:
@@ -398,7 +400,7 @@ static void acpi_button_notify(struct acpi_device *device, 
u32 event)
case ACPI_BUTTON_NOTIFY_STATUS:
input = button->input;
if (button->type == ACPI_BUTTON_TYPE_LID) {
-   acpi_lid_update_state(device);
+   acpi_lid_update_state(device, true);
} else {
int keycode;
 
-- 
2.7.4



[RFC PATCH v3 2/5] ACPI: button: Extends complement switch event support for all modes

2017-05-26 Thread Lv Zheng
Surface Pro 3 is a typical platform where suspend/resume loop problem
can be seen.

The problem is due to a systemd 229 bug:
1. "ignore": always can trigger endless suspend/resume loop
2. "open": sometimes suspend/resume loop can be stopped
3. "method": always can trigger endless susped/resume loop
The buggy systemd unexpectedly waits for an explicit "open" event after
boot/resume or it will suspends. However even when kernel can send a
faked "open" to it, its state machine is still wrong, systemd may not
respond "close" events arrived after "open" or may suddenly suspend
without seeing any instant events.

Recent systemd 233 has fixed this issue:
1. "ignore": everything works fine;
2. "open": no suspend/resume cycle, but sometimes cannot suspend the
   platform again after the first resume;
3. "method": no suspend/resume cycle, but always cannot suspend the
 platform again after the first resume.
The conclusion is: for suspend/resume cycle issue, "ignore" mode fixes
everything, but current "method" mode is still buggy.
Differences are because button driver only implements complement switch
events for "ignore" mode. Without complement switch events, firmware
triggered "close" cannot be delivered to userspace (confirmed by
evemu-record).

The root cause of the lid state issues is the variation of the platform
firmware implementations:
1. Some platforms send "open" events to OS and the events arrive before
   button driver is resumed;
2. Some platforms send "open" events to OS, but the events arrive after
   button driver is resumed, ex., Samsung N210+;
3. Some platforms never send "open" events to OS, but send "open" events to
   update the cached _LID return value, and the update events arrive before
   button driver is resumed;
4. Some platforms never send "open" events to OS, but send "open" events to
   update the cached _LID return value, but the update events arrive after
   button driver is resumed, ex., Surface Pro 3;
5. Some platforms never send "open" events, _LID returns value sticks to
   "close", ex., Surface Pro 1.

Let's check the docking external display issues (see links below):
1. For case 1, both "method"/"ignore" modes can work correctly;
2. For case 2/4/5, both "method"/"ignore" modes cannot work correctly;
3. For case 3, "method" can work correctly while "ignore" mode cannot.
The conclusion is: for docking external display issue, though the issue
still needs graphics layer (graphics drivers or desktop managers) to be
improved to ensure no breakages for case 2/4/5 platforms, there is a case
where "method" mode plays better.

Thus ACPI subsystem has been pushed to revert back to "method" mode due to
regression rule and case 3 (platforms reported on the links should all be
case 3 platforms), and libinput developers have volunteered to help to
provide workarounds when graphics layer is not fixed or systemd is not
updated.

Thus this patch extends the complement switch event support to other modes
using new indication: generating complement switch event for BIOS notified
"close". So that when button driver is reverted back to "method" mode, it
won't act worse than "ignore" mode on fixed systemd.

Tested with systemd 233, all modes worked fine (no suspend/resume loop and
can suspend any times) after applying this patch.

Link: https://bugzilla.kernel.org/show_bug.cgi?id=195455
  https://bugzilla.redhat.com/show_bug.cgi?id=1430259
Cc: 
Cc: Benjamin Tissoires 
Cc: Peter Hutterer 
Signed-off-by: Lv Zheng 

Signed-off-by: Lv Zheng 
---
 drivers/acpi/button.c | 116 +-
 1 file changed, 57 insertions(+), 59 deletions(-)

diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c
index 874ba60..a72f5bf 100644
--- a/drivers/acpi/button.c
+++ b/drivers/acpi/button.c
@@ -108,6 +108,7 @@ struct acpi_button {
unsigned long pushed;
int last_state;
ktime_t last_time;
+   bool last_is_bios;
bool suspended;
 };
 
@@ -144,78 +145,71 @@ static int acpi_lid_notify_state(struct acpi_device 
*device,
struct acpi_button *button = acpi_driver_data(device);
int ret;
ktime_t next_report;
-   bool do_update;
 
/*
-* In lid_init_state=ignore mode, if user opens/closes lid
-* frequently with "open" missing, and "last_time" is also updated
-* frequently, "close" cannot be delivered to the userspace.
-* So "last_time" is only updated after a timeout or an actual
-* switch.
+* Ignore frequently replayed switch events.
+*
+* AML tables can p

[RFC PATCH v3 4/5] ACPI: button: Fix lid notification

2017-05-26 Thread Lv Zheng
In acpi_lid_notify_state(), it now contains logic to avoid frequently
replayed events which originally was ensured by using blocking notifier.
On the contrary, using blocking notifier is wrong as it could keep on
returning NOTIFY_DONE, causing events lost.

This patch thus changes lid notification to raw notifier in order not to
have events lost.

Cc: Peter Hutterer 
Cc: Benjamin Tissoires 
Signed-off-by: Lv Zheng 
---
 drivers/acpi/button.c | 53 ---
 1 file changed, 29 insertions(+), 24 deletions(-)

diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c
index d3f90c6..4abf8ae 100644
--- a/drivers/acpi/button.c
+++ b/drivers/acpi/button.c
@@ -112,7 +112,7 @@ struct acpi_button {
bool suspended;
 };
 
-static BLOCKING_NOTIFIER_HEAD(acpi_lid_notifier);
+static RAW_NOTIFIER_HEAD(acpi_lid_notifier);
 static struct acpi_device *lid_device;
 static u8 lid_init_state = ACPI_BUTTON_LID_INIT_OPEN;
 
@@ -139,11 +139,16 @@ static int acpi_lid_evaluate_state(struct acpi_device 
*device)
return lid_state ? 1 : 0;
 }
 
-static int acpi_lid_notify_state(struct acpi_device *device,
+static inline void acpi_lid_notifier_call(struct acpi_device *device,
+ int state)
+{
+   (void)raw_notifier_call_chain(&acpi_lid_notifier, state, device);
+}
+
+static void acpi_lid_notify_state(struct acpi_device *device,
 int state, bool bios_notify)
 {
struct acpi_button *button = acpi_driver_data(device);
-   int ret;
ktime_t next_report;
 
/*
@@ -161,7 +166,7 @@ static int acpi_lid_notify_state(struct acpi_device *device,
ms_to_ktime(lid_report_interval));
if (button->last_is_bios && button->last_state == !!state &&
!ktime_after(ktime_get(), next_report))
-   return 0;
+   return;
 
/*
 * Send the unreliable complement switch event:
@@ -219,18 +224,7 @@ static int acpi_lid_notify_state(struct acpi_device 
*device,
if (state)
pm_wakeup_event(&device->dev, 0);
 
-   ret = blocking_notifier_call_chain(&acpi_lid_notifier, state, device);
-   if (ret == NOTIFY_DONE)
-   ret = blocking_notifier_call_chain(&acpi_lid_notifier, state,
-  device);
-   if (ret == NOTIFY_DONE || ret == NOTIFY_OK) {
-   /*
-* It is also regarded as success if the notifier_chain
-* returns NOTIFY_OK or NOTIFY_DONE.
-*/
-   ret = 0;
-   }
-   return ret;
+   acpi_lid_notifier_call(device, state);
 }
 
 static int acpi_button_state_seq_show(struct seq_file *seq, void *offset)
@@ -341,13 +335,24 @@ static int acpi_button_remove_fs(struct acpi_device 
*device)
-- 
*/
 int acpi_lid_notifier_register(struct notifier_block *nb)
 {
-   return blocking_notifier_chain_register(&acpi_lid_notifier, nb);
+   return raw_notifier_chain_register(&acpi_lid_notifier, nb);
 }
 EXPORT_SYMBOL(acpi_lid_notifier_register);
 
+static inline int __acpi_lid_notifier_unregister(struct notifier_block *nb,
+bool sync)
+{
+   int ret;
+
+   ret = raw_notifier_chain_unregister(&acpi_lid_notifier, nb);
+   if (sync)
+   synchronize_rcu();
+   return ret;
+}
+
 int acpi_lid_notifier_unregister(struct notifier_block *nb)
 {
-   return blocking_notifier_chain_unregister(&acpi_lid_notifier, nb);
+   return __acpi_lid_notifier_unregister(nb, false);
 }
 EXPORT_SYMBOL(acpi_lid_notifier_unregister);
 
@@ -360,26 +365,26 @@ int acpi_lid_open(void)
 }
 EXPORT_SYMBOL(acpi_lid_open);
 
-static int acpi_lid_update_state(struct acpi_device *device,
-bool bios_notify)
+static void acpi_lid_update_state(struct acpi_device *device,
+ bool bios_notify)
 {
int state;
 
state = acpi_lid_evaluate_state(device);
if (state < 0)
-   return state;
+   return;
 
-   return acpi_lid_notify_state(device, state, bios_notify);
+   acpi_lid_notify_state(device, state, bios_notify);
 }
 
 static void acpi_lid_initialize_state(struct acpi_device *device)
 {
switch (lid_init_state) {
case ACPI_BUTTON_LID_INIT_OPEN:
-   (void)acpi_lid_notify_state(device, 1, false);
+   acpi_lid_notify_state(device, 1, false);
break;
case ACPI_BUTTON_LID_INIT_METHOD:
-   (void)acpi_lid_update_state(device, false);
+   acpi_lid_update_state(device, false);
break;
case ACPI_BUTTON_LID_INIT_IGNORE:
default:
-- 
2.7.4



[RFC PATCH v3 5/5] ACPI: button: Always notify kernel space using _LID returning value

2017-05-26 Thread Lv Zheng
Both nouveau and i915, the only 2 kernel space lid notification listeners,
invoke acpi_lid_open() API to obtain _LID returning value instead of using
the notified value.

So this patch moves this logic from listeners to lid driver, always notify
kernel space listeners using _LID returning value.

This is a no-op cleanup, but facilitates administrators to configure to
notify kernel drivers with faked lid init states via command line
"button.lid_notify_init_state=Y".

Cc: 
Cc: 
Cc: Benjamin Tissoires 
Cc: Peter Hutterer 
Signed-off-by: Lv Zheng 
---
 drivers/acpi/button.c | 16 ++--
 drivers/gpu/drm/i915/intel_lvds.c |  2 +-
 2 files changed, 15 insertions(+), 3 deletions(-)

diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c
index 4abf8ae..e047d34 100644
--- a/drivers/acpi/button.c
+++ b/drivers/acpi/button.c
@@ -119,6 +119,9 @@ static u8 lid_init_state = ACPI_BUTTON_LID_INIT_OPEN;
 static unsigned long lid_report_interval __read_mostly = 500;
 module_param(lid_report_interval, ulong, 0644);
 MODULE_PARM_DESC(lid_report_interval, "Interval (ms) between lid key events");
+static bool lid_notify_init_state __read_mostly = false;
+module_param(lid_notify_init_state, bool, 0644);
+MODULE_PARM_DESC(lid_notify_init_state, "Notify init lid state to kernel 
drivers after boot/resume");
 
 /* --
   FS Interface (/proc)
@@ -224,6 +227,15 @@ static void acpi_lid_notify_state(struct acpi_device 
*device,
if (state)
pm_wakeup_event(&device->dev, 0);
 
+   if (!lid_notify_init_state) {
+   /*
+* There are cases "state" is not a _LID return value, so
+* correct it before notification.
+*/
+   if (!bios_notify &&
+   lid_init_state != ACPI_BUTTON_LID_INIT_METHOD)
+   state = acpi_lid_evaluate_state(device);
+   }
acpi_lid_notifier_call(device, state);
 }
 
@@ -572,10 +584,10 @@ static int param_set_lid_init_state(const char *val, 
struct kernel_param *kp)
 
if (!strncmp(val, "open", sizeof("open") - 1)) {
lid_init_state = ACPI_BUTTON_LID_INIT_OPEN;
-   pr_info("Notify initial lid state as open\n");
+   pr_info("Notify initial lid state to users space as open and 
kernel drivers with _LID return value\n");
} else if (!strncmp(val, "method", sizeof("method") - 1)) {
lid_init_state = ACPI_BUTTON_LID_INIT_METHOD;
-   pr_info("Notify initial lid state with _LID return value\n");
+   pr_info("Notify initial lid state to user/kernel space with 
_LID return value\n");
} else if (!strncmp(val, "ignore", sizeof("ignore") - 1)) {
lid_init_state = ACPI_BUTTON_LID_INIT_IGNORE;
pr_info("Do not notify initial lid state\n");
diff --git a/drivers/gpu/drm/i915/intel_lvds.c 
b/drivers/gpu/drm/i915/intel_lvds.c
index 9ca4dc4..8ca9080 100644
--- a/drivers/gpu/drm/i915/intel_lvds.c
+++ b/drivers/gpu/drm/i915/intel_lvds.c
@@ -548,7 +548,7 @@ static int intel_lid_notify(struct notifier_block *nb, 
unsigned long val,
/* Don't force modeset on machines where it causes a GPU lockup */
if (dmi_check_system(intel_no_modeset_on_lid))
goto exit;
-   if (!acpi_lid_open()) {
+   if (!val) {
/* do modeset on next lid open event */
dev_priv->modeset_restore = MODESET_ON_LID_OPEN;
goto exit;
-- 
2.7.4



[RFC PATCH v3 3/5] ACPI: button: Add lid event type debugging messages

2017-05-26 Thread Lv Zheng
This patch adds very useful debugging information to lid events.
These messages and with ec_log_drv() can be used to demonstrate the order
between acpi_ec_resume() and acpi_button_resume().

Cc: Benjamin Tissoires 
Cc: Peter Hutterer 
Signed-off-by: Lv Zheng 
---
 drivers/acpi/button.c | 5 +
 1 file changed, 5 insertions(+)

diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c
index a72f5bf..d3f90c6 100644
--- a/drivers/acpi/button.c
+++ b/drivers/acpi/button.c
@@ -201,12 +201,17 @@ static int acpi_lid_notify_state(struct acpi_device 
*device,
if (!state) {
input_report_switch(button->input, SW_LID, state);
input_sync(button->input);
+   pr_debug("faked open complement event.\n");
}
}
 
/* Send the platform triggered reliable event */
input_report_switch(button->input, SW_LID, !state);
input_sync(button->input);
+   if (bios_notify)
+   pr_debug("notified %s event.\n", state ? "open" : "close");
+   else
+   pr_debug("faked %s event.\n", state ? "open" : "close");
button->last_state = !!state;
button->last_time = ktime_get();
button->last_is_bios = bios_notify;
-- 
2.7.4



[PATCH v2 3/3] ACPI / EC: Fix media keys not working problem on some Asus laptops

2017-05-19 Thread Lv Zheng
From: Chris Chiu 

Some Asus laptops (verified on X550VXK/FX502VD/FX502VE) get no
interrupts when pressing media keys thus the corresponding functions
are not invoked. It's due to the _GPE defines in DSDT for EC returns
differnt value compared to the GPE Number in ECDT. Confirmed with Asus
that the vale in ECDT is the correct one. This commit use a DMI quirk
to prevent calling _GPE when doing ec_parse_device() and keep the ECDT
GPE number setting for the EC device.

Link: https://phabricator.endlessm.com/T16033
  https://phabricator.endlessm.com/T16722
Link: https://bugzilla.kernel.org/show_bug.cgi?id=195651
Tested-by: Daniel Drake 
Signed-off-by: Chris Chiu 
Signed-off-by: Lv Zheng 
---
 drivers/acpi/ec.c | 50 --
 1 file changed, 44 insertions(+), 6 deletions(-)

diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index e232a1c..b6d28ef 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -190,6 +190,7 @@ static struct workqueue_struct *ec_query_wq;
 
 static int EC_FLAGS_QUERY_HANDSHAKE; /* Needs QR_EC issued when SCI_EVT set */
 static int EC_FLAGS_CORRECT_ECDT; /* Needs ECDT port address correction */
+static int EC_FLAGS_IGNORE_DSDT_GPE; /* Needs ECDT GPE as correction setting */
 
 /* --
  *   Logging/Debugging
@@ -1371,12 +1372,21 @@ ec_parse_device(acpi_handle handle, u32 Level, void 
*context, void **retval)
if (ec->data_addr == 0 || ec->command_addr == 0)
return AE_OK;
 
-   /* Get GPE bit assignment (EC events). */
-   /* TODO: Add support for _GPE returning a package */
-   status = acpi_evaluate_integer(handle, "_GPE", NULL, &tmp);
-   if (ACPI_FAILURE(status))
-   return status;
-   ec->gpe = tmp;
+   if (boot_ec && EC_FLAGS_IGNORE_DSDT_GPE) {
+   /*
+* First boot_ec is always ECDT EC.
+* Always inherit the GPE number setting from the first
+* boot_ec.
+*/
+   ec->gpe = boot_ec->gpe;
+   } else {
+   /* Get GPE bit assignment (EC events). */
+   /* TODO: Add support for _GPE returning a package */
+   status = acpi_evaluate_integer(handle, "_GPE", NULL, &tmp);
+   if (ACPI_FAILURE(status))
+   return status;
+   ec->gpe = tmp;
+   }
/* Use the global lock for all EC transactions? */
tmp = 0;
acpi_evaluate_integer(handle, "_GLK", NULL, &tmp);
@@ -1769,11 +1779,39 @@ static int ec_correct_ecdt(const struct dmi_system_id 
*id)
return 0;
 }
 
+/*
+ * Some DSDTs contain wrong GPE setting.
+ * Asus FX502VD/VE, X550VXK, X580VD
+ * Link: https://bugzilla.kernel.org/show_bug.cgi?id=195651
+ */
+static int ec_honor_ecdt_gpe(const struct dmi_system_id *id)
+{
+   pr_debug("Detected system needing ignore DSDT GPE setting.\n");
+   EC_FLAGS_IGNORE_DSDT_GPE = 1;
+   return 0;
+}
+
 static struct dmi_system_id ec_dmi_table[] __initdata = {
{
ec_correct_ecdt, "MSI MS-171F", {
DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star"),
DMI_MATCH(DMI_PRODUCT_NAME, "MS-171F"),}, NULL},
+   {
+   ec_honor_ecdt_gpe, "ASUS FX502VD", {
+   DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+   DMI_MATCH(DMI_PRODUCT_NAME, "FX502VD"),}, NULL},
+   {
+   ec_honor_ecdt_gpe, "ASUS FX502VE", {
+   DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+   DMI_MATCH(DMI_PRODUCT_NAME, "FX502VE"),}, NULL},
+   {
+   ec_honor_ecdt_gpe, "ASUS X550VXK", {
+   DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+   DMI_MATCH(DMI_PRODUCT_NAME, "X550VXK"),}, NULL},
+   {
+   ec_honor_ecdt_gpe, "ASUS X580VD", {
+   DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+   DMI_MATCH(DMI_PRODUCT_NAME, "X580VD"),}, NULL},
{},
 };
 
-- 
2.7.4



[PATCH v2 2/3] ACPI / EC: Add support to skip boot stage DSDT probe

2017-05-19 Thread Lv Zheng
Long time ago, Linux EC driver won't probe DSDT EC during boot. It was
added by the following commit (see link #1 for bug report):
  Commit: c5279dee26c0e8d7c4200993bfc4b540d2469598
  Subject: ACPI: EC: Add some basic check for ECDT data
This is wrong as the only way to know if the DSDT EC is valid is to
evaluate its _STA control method, but it's not proper to evaluate this
control method that early and out of the ACPI enumeration process.

But after we reverted back to the expected behavior, someone reported a
regression (see link #2 for reference). On that platform, there is no ECDT,
but the platform control methds access EC operation region earlier than
Linux expects. Without knowing the exact device enumeration order on
Windows, we in fact cannot conclude anything but can just follow the
regression rule to revert to old wrong behavior to probe DSDT EC at the old
position.

Now we've been reported 3rd functional breakage (link #3). The safest way
of solving it includes evaluating _STA. Due to the reason above, it is not
such safe to evaluate _STA in acpi_ec_dsdt_probe(). In order to handle both
issues (link #2 and link #3), we could just skip boot stage DSDT probe when
ECDT exists.

Note this change doesn't solve the reported problem, it can only be
resolved by a GPE setting quirk, and without this commit but with only the
GPE setting quirk, the reported problem can be solved. However, this commit
can improve our code quality by making unexpected behavior less effective.

Link: http://bugzilla.kernel.org/show_bug.cgi?id=11880 [#1]
Link: http://bugzilla.kernel.org/show_bug.cgi?id=119261 [#2]
Link: http://bugzilla.kernel.org/show_bug.cgi?id=195651 [#3]
Tested-by: Daniel Drake 
Signed-off-by: Lv Zheng 
---
 drivers/acpi/ec.c | 8 
 1 file changed, 8 insertions(+)

diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index a920db6..e232a1c 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -1679,6 +1679,14 @@ int __init acpi_ec_dsdt_probe(void)
struct acpi_ec *ec;
int ret;
 
+   /*
+* If a platform has ECDT, there is no need to proceed as the
+* following unsafe probe is not a part of ACPI device enumeration,
+* and hence _STA is not executed.
+*/
+   if (boot_ec)
+   return -ENODEV;
+
ec = acpi_ec_alloc();
if (!ec)
return -ENOMEM;
-- 
2.7.4



[PATCH v2 0/3] ACPI / EC: Add quirk modes for boot EC support

2017-05-19 Thread Lv Zheng
It's reported that Asus laptop X580VD/X550VXK/FX502VD/FX502VE have a BIOS
bug where the ECDT correctly states that EC events trigger GPE 0x23, but
the DSDT _GPE method incorrectly returns GPE 0x33.

This patchset fixes this issue.

Link: https://www.spinics.net/lists/linux-acpi/msg73763.html
  https://bugzilla.kernel.org/show_bug.cgi?id=195651

v2: Stops doing craps related to EC_ID (it's already too complicated), and
reduces one unnecessary boot parameter. For the final bug fix, prefers
the fix from endlessm.com developers.

Chris Chiu (1):
  ACPI / EC: Fix media keys not working problem on some Asus laptops

Lv Zheng (2):
  ACPI / EC: Enhance boot EC sanity check
  ACPI / EC: Add support to skip boot stage DSDT probe

 drivers/acpi/ec.c | 66 ++-
 1 file changed, 60 insertions(+), 6 deletions(-)

-- 
2.7.4



[PATCH v2 1/3] ACPI / EC: Enhance boot EC sanity check

2017-05-19 Thread Lv Zheng
It's reported that some buggy BIOS tables can contain 2 DSDT ECs and one of
them is invalid. As we shouldn't evaluate _STA from acpi_ec_dsdt_probe()
due to the unknown Windows enumeration order, this patch simply enhances
sanity checks in ec_parse_device() as a workaround to skip probing wrong
namespace ECs.

Link: https://bugzilla.kernel.org/show_bug.cgi?id=195651
Tested-by: Daniel Drake 
Signed-off-by: Lv Zheng 
---
 drivers/acpi/ec.c | 8 
 1 file changed, 8 insertions(+)

diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index c24235d..a920db6 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -1362,6 +1362,14 @@ ec_parse_device(acpi_handle handle, u32 Level, void 
*context, void **retval)
 ec_parse_io_ports, ec);
if (ACPI_FAILURE(status))
return status;
+   /*
+* It's better to evaluate _STA to determine if the device is
+* valid. But that could potentially trigger issues related to
+* the unknown orders of _INI/_STA evaluations.
+* However we can abort due to invalid _CRS information here.
+*/
+   if (ec->data_addr == 0 || ec->command_addr == 0)
+   return AE_OK;
 
/* Get GPE bit assignment (EC events). */
/* TODO: Add support for _GPE returning a package */
-- 
2.7.4



[PATCH v4 2/4] ACPICA: Tables: Add mechanism to allow to balance late stage acpi_get_table() independently

2017-05-08 Thread Lv Zheng
For all frequent late stage acpi_get_table() clone invocations, we should
only change them altogether, otherwise, excessive acpi_put_table() could
unexpectedly unmap the table used by the other users. Thus the current plan
is to change all acpi_get_table() clones together or to change none of
them. However in practical, this is not convenient as this can prevent
kernel developers' efforts of improving the late stage code quality before
waiting for the ACPICA upstream to improve first.

This patch adds a validation count threashold, when it is reached, the
validation count can no longer be incremented/decremented to invalidate the
table descriptor (means preventing table unmappings) so that acpi_put_table()
balance changes can be done independently to each others. Lv Zheng.

Cc: Dan Williams 
Signed-off-by: Lv Zheng 
---
 drivers/acpi/acpica/tbutils.c | 24 +++-
 include/acpi/actbl.h  |  9 +
 2 files changed, 24 insertions(+), 9 deletions(-)

diff --git a/drivers/acpi/acpica/tbutils.c b/drivers/acpi/acpica/tbutils.c
index 7abe665..04beafc 100644
--- a/drivers/acpi/acpica/tbutils.c
+++ b/drivers/acpi/acpica/tbutils.c
@@ -416,9 +416,13 @@ acpi_tb_get_table(struct acpi_table_desc *table_desc,
}
}
 
-   table_desc->validation_count++;
-   if (table_desc->validation_count == 0) {
-   table_desc->validation_count--;
+   if (table_desc->validation_count < ACPI_MAX_TABLE_VALIDATIONS) {
+   table_desc->validation_count++;
+   if (table_desc->validation_count >= ACPI_MAX_TABLE_VALIDATIONS) 
{
+   ACPI_WARNING((AE_INFO,
+ "Table %p, Validation count overflows\n",
+ table_desc));
+   }
}
 
*out_table = table_desc->pointer;
@@ -445,13 +449,15 @@ void acpi_tb_put_table(struct acpi_table_desc *table_desc)
 
ACPI_FUNCTION_TRACE(acpi_tb_put_table);
 
-   if (table_desc->validation_count == 0) {
-   ACPI_WARNING((AE_INFO,
- "Table %p, Validation count is zero before 
decrement\n",
- table_desc));
-   return_VOID;
+   if (table_desc->validation_count < ACPI_MAX_TABLE_VALIDATIONS) {
+   table_desc->validation_count--;
+   if (table_desc->validation_count >= ACPI_MAX_TABLE_VALIDATIONS) 
{
+   ACPI_WARNING((AE_INFO,
+ "Table %p, Validation count underflows\n",
+ table_desc));
+   return_VOID;
+   }
}
-   table_desc->validation_count--;
 
if (table_desc->validation_count == 0) {
 
diff --git a/include/acpi/actbl.h b/include/acpi/actbl.h
index d92543f..8e1bff8 100644
--- a/include/acpi/actbl.h
+++ b/include/acpi/actbl.h
@@ -374,6 +374,15 @@ struct acpi_table_desc {
u16 validation_count;
 };
 
+/*
+ * Maximum validation count, when it is reached, validation count can no
+ * longer be changed. Which means, the table can no longer be invalidated.
+ * This mechanism is implemented for backward compatibility, where in OS
+ * late stage, old drivers are not facilitated with paired validations and
+ * invalidations.
+ */
+#define ACPI_MAX_TABLE_VALIDATIONS  5
+
 /* Masks for Flags field above */
 
 #define ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL  (0)/* Virtual address, 
external maintained */
-- 
2.7.4



[PATCH v4 3/4] ACPI: sysfs: Fix acpi_get_table() leak

2017-05-08 Thread Lv Zheng
From: Dan Williams 

Reading an ACPI table through the /sys/firmware/acpi/tables interface
more than 65,536 times leads to the following log message:

 ACPI Error: Table 88033595eaa8, Validation count is zero after
increment
  (20170119/tbutils-423)

Add the missing acpi_put_table() so the table ->validation_count is
decremented after each read.

Reported-by: Anush Seetharaman 
Signed-off-by: Dan Williams 
Signed-off-by: Lv Zheng 
---
 drivers/acpi/sysfs.c | 7 +--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c
index 1b5ee1e..2bbf722 100644
--- a/drivers/acpi/sysfs.c
+++ b/drivers/acpi/sysfs.c
@@ -333,14 +333,17 @@ static ssize_t acpi_table_show(struct file *filp, struct 
kobject *kobj,
container_of(bin_attr, struct acpi_table_attr, attr);
struct acpi_table_header *table_header = NULL;
acpi_status status;
+   ssize_t len;
 
status = acpi_get_table(table_attr->name, table_attr->instance,
&table_header);
if (ACPI_FAILURE(status))
return -ENODEV;
 
-   return memory_read_from_buffer(buf, count, &offset,
-  table_header, table_header->length);
+   len = memory_read_from_buffer(buf, count, &offset,
+ table_header, table_header->length);
+   acpi_put_table(table_header);
+   return len;
 }
 
 static int acpi_table_attr_init(struct kobject *tables_obj,
-- 
2.7.4



[PATCH v4 4/4] ACPI: Fix memory mapping leaks in current sysfs dumpable ACPI tables support

2017-05-08 Thread Lv Zheng
This patch adds acpi_put_table() to make all acpi_get_table() clone
invocations balanced for sysfs ACPI table dump code.

Since Linux does not use all of the tables, this can help to reduce some
usless memory mappings.

While originally, all tables will be remained to be mapped after a
userspace acpidump execution, potentially causing problem on server
platforms. With the new APIs, it is possible to release such useless table
mappings.

Signed-off-by: Lv Zheng 
---
 drivers/acpi/sysfs.c | 41 +++--
 1 file changed, 31 insertions(+), 10 deletions(-)

diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c
index 2bbf722..14425dc 100644
--- a/drivers/acpi/sysfs.c
+++ b/drivers/acpi/sysfs.c
@@ -346,11 +346,22 @@ static ssize_t acpi_table_show(struct file *filp, struct 
kobject *kobj,
return len;
 }
 
+static bool acpi_table_has_multiple_instances(char *signature)
+{
+   acpi_status status;
+   struct acpi_table_header *header;
+
+   status = acpi_get_table(signature, 2, &header);
+   if (ACPI_FAILURE(status))
+   return false;
+   acpi_put_table(header);
+   return true;
+}
+
 static int acpi_table_attr_init(struct kobject *tables_obj,
struct acpi_table_attr *table_attr,
struct acpi_table_header *table_header)
 {
-   struct acpi_table_header *header = NULL;
struct acpi_table_attr *attr = NULL;
char instance_str[ACPI_INST_SIZE];
 
@@ -371,9 +382,9 @@ static int acpi_table_attr_init(struct kobject *tables_obj,
 
ACPI_MOVE_NAME(table_attr->filename, table_header->signature);
table_attr->filename[ACPI_NAME_SIZE] = '\0';
-   if (table_attr->instance > 1 || (table_attr->instance == 1 &&
-!acpi_get_table
-(table_header->signature, 2, 
&header))) {
+   if (table_attr->instance > 1 ||
+   (table_attr->instance == 1 &&
+acpi_table_has_multiple_instances(table_header->signature))) {
snprintf(instance_str, sizeof(instance_str), "%u",
 table_attr->instance);
strcat(table_attr->filename, instance_str);
@@ -422,11 +433,11 @@ acpi_status acpi_sysfs_table_handler(u32 event, void 
*table, void *context)
 
 static int acpi_tables_sysfs_init(void)
 {
-   struct acpi_table_attr *table_attr;
+   struct acpi_table_attr *table_attr = NULL;
struct acpi_table_header *table_header = NULL;
int table_index;
acpi_status status;
-   int ret;
+   int ret = 0;
 
tables_kobj = kobject_create_and_add("tables", acpi_kobj);
if (!tables_kobj)
@@ -446,16 +457,26 @@ static int acpi_tables_sysfs_init(void)
continue;
 
table_attr = kzalloc(sizeof(*table_attr), GFP_KERNEL);
-   if (!table_attr)
-   return -ENOMEM;
+   if (!table_attr) {
+   ret = -ENOMEM;
+   goto next_table;
+   }
 
ret = acpi_table_attr_init(tables_kobj,
   table_attr, table_header);
+   if (ret)
+   goto next_table;
+   list_add_tail(&table_attr->node, &acpi_table_attr_list);
+
+next_table:
+   acpi_put_table(table_header);
if (ret) {
-   kfree(table_attr);
+   if (table_attr) {
+   kfree(table_attr);
+   table_attr = NULL;
+   }
return ret;
}
-   list_add_tail(&table_attr->node, &acpi_table_attr_list);
}
 
kobject_uevent(tables_kobj, KOBJ_ADD);
-- 
2.7.4



[PATCH v4 1/4] ACPICA: Tables: Fix regression introduced by a too early mechanism enabling

2017-05-08 Thread Lv Zheng
In the Linux kernel side, acpi_get_table() clones haven't been fully
balanced by acpi_put_table() invocations. In ACPICA side, due to the design
change, there are also unbalanced acpi_get_table_by_index() invocations
requiring special care.

So it is not a good timing to report acpi_get_table() counting errors. The
strict balanced validation count check should only be enabled after
confirming that all invocations are safe and compliant to their designed
purposes.

Thus this patch removes the fatal error along with the error report to
fix this issue. Reported by Dan Williams, fixed by Lv Zheng.

Fixes: 174cc7187e6f ("ACPICA: Tables: Back port acpi_get_table_with_size() and 
early_acpi_os_unmap_memory() from Linux kernel")
Cc: 
Reported-by: Anush Seetharaman 
Reported-by: Dan Williams 
Cc: Anush Seetharaman 
Cc: Dan Williams 
Signed-off-by: Lv Zheng 
---
 drivers/acpi/acpica/tbutils.c | 4 
 1 file changed, 4 deletions(-)

diff --git a/drivers/acpi/acpica/tbutils.c b/drivers/acpi/acpica/tbutils.c
index 5a968a7..7abe665 100644
--- a/drivers/acpi/acpica/tbutils.c
+++ b/drivers/acpi/acpica/tbutils.c
@@ -418,11 +418,7 @@ acpi_tb_get_table(struct acpi_table_desc *table_desc,
 
table_desc->validation_count++;
if (table_desc->validation_count == 0) {
-   ACPI_ERROR((AE_INFO,
-   "Table %p, Validation count is zero after 
increment\n",
-   table_desc));
table_desc->validation_count--;
-   return_ACPI_STATUS(AE_LIMIT);
}
 
*out_table = table_desc->pointer;
-- 
2.7.4




[PATCH v3 4/4] ACPI: Fix memory mapping leaks in current sysfs dumpable ACPI tables support

2017-04-27 Thread Lv Zheng
This patch adds acpi_put_table() to make all acpi_get_table() clone
invocations balanced for sysfs ACPI table dump code.

Since Linux does not use all of the tables, this can help to reduce some
usless memory mappings.

While originally, all tables will be remained to be mapped after a
userspace acpidump execution, potentially causing problem on server
platforms. With the new APIs, it is possible to release such useless table
mappings.

Signed-off-by: Lv Zheng 
---
 drivers/acpi/sysfs.c | 41 +++--
 1 file changed, 31 insertions(+), 10 deletions(-)

diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c
index 2bbf722..14425dc 100644
--- a/drivers/acpi/sysfs.c
+++ b/drivers/acpi/sysfs.c
@@ -346,11 +346,22 @@ static ssize_t acpi_table_show(struct file *filp, struct 
kobject *kobj,
return len;
 }
 
+static bool acpi_table_has_multiple_instances(char *signature)
+{
+   acpi_status status;
+   struct acpi_table_header *header;
+
+   status = acpi_get_table(signature, 2, &header);
+   if (ACPI_FAILURE(status))
+   return false;
+   acpi_put_table(header);
+   return true;
+}
+
 static int acpi_table_attr_init(struct kobject *tables_obj,
struct acpi_table_attr *table_attr,
struct acpi_table_header *table_header)
 {
-   struct acpi_table_header *header = NULL;
struct acpi_table_attr *attr = NULL;
char instance_str[ACPI_INST_SIZE];
 
@@ -371,9 +382,9 @@ static int acpi_table_attr_init(struct kobject *tables_obj,
 
ACPI_MOVE_NAME(table_attr->filename, table_header->signature);
table_attr->filename[ACPI_NAME_SIZE] = '\0';
-   if (table_attr->instance > 1 || (table_attr->instance == 1 &&
-!acpi_get_table
-(table_header->signature, 2, 
&header))) {
+   if (table_attr->instance > 1 ||
+   (table_attr->instance == 1 &&
+acpi_table_has_multiple_instances(table_header->signature))) {
snprintf(instance_str, sizeof(instance_str), "%u",
 table_attr->instance);
strcat(table_attr->filename, instance_str);
@@ -422,11 +433,11 @@ acpi_status acpi_sysfs_table_handler(u32 event, void 
*table, void *context)
 
 static int acpi_tables_sysfs_init(void)
 {
-   struct acpi_table_attr *table_attr;
+   struct acpi_table_attr *table_attr = NULL;
struct acpi_table_header *table_header = NULL;
int table_index;
acpi_status status;
-   int ret;
+   int ret = 0;
 
tables_kobj = kobject_create_and_add("tables", acpi_kobj);
if (!tables_kobj)
@@ -446,16 +457,26 @@ static int acpi_tables_sysfs_init(void)
continue;
 
table_attr = kzalloc(sizeof(*table_attr), GFP_KERNEL);
-   if (!table_attr)
-   return -ENOMEM;
+   if (!table_attr) {
+   ret = -ENOMEM;
+   goto next_table;
+   }
 
ret = acpi_table_attr_init(tables_kobj,
   table_attr, table_header);
+   if (ret)
+   goto next_table;
+   list_add_tail(&table_attr->node, &acpi_table_attr_list);
+
+next_table:
+   acpi_put_table(table_header);
if (ret) {
-   kfree(table_attr);
+   if (table_attr) {
+   kfree(table_attr);
+   table_attr = NULL;
+   }
return ret;
}
-   list_add_tail(&table_attr->node, &acpi_table_attr_list);
}
 
kobject_uevent(tables_kobj, KOBJ_ADD);
-- 
2.7.4



[PATCH v3 1/4] ACPICA: Tables: Fix regression introduced by a too early mechanism enabling

2017-04-27 Thread Lv Zheng
In the Linux kernel side, acpi_get_table() clones haven't been fully
balanced by acpi_put_table() invocations. In ACPICA side, due to the design
change, there are also unbalanced acpi_get_table_by_index() invocations
requiring special care.

So it is not a good timing to report acpi_get_table() counting errors. The
strict balanced validation count check should only be enabled after
confirming that all invocations are safe and compliant to their designed
purposes.

Thus this patch removes the fatal error along with the error report to
fix this issue. Reported by Dan Williams, fixed by Lv Zheng.

Fixes: 174cc7187e6f ("ACPICA: Tables: Back port acpi_get_table_with_size() and 
early_acpi_os_unmap_memory() from Linux kernel")
Cc: Anush Seetharaman 
Cc: Dan Williams 
Reported-by: Anush Seetharaman 
Reported-by: Dan Williams 
Signed-off-by: Lv Zheng 
---
 drivers/acpi/acpica/tbutils.c | 4 
 1 file changed, 4 deletions(-)

diff --git a/drivers/acpi/acpica/tbutils.c b/drivers/acpi/acpica/tbutils.c
index 5a968a7..7abe665 100644
--- a/drivers/acpi/acpica/tbutils.c
+++ b/drivers/acpi/acpica/tbutils.c
@@ -418,11 +418,7 @@ acpi_tb_get_table(struct acpi_table_desc *table_desc,
 
table_desc->validation_count++;
if (table_desc->validation_count == 0) {
-   ACPI_ERROR((AE_INFO,
-   "Table %p, Validation count is zero after 
increment\n",
-   table_desc));
table_desc->validation_count--;
-   return_ACPI_STATUS(AE_LIMIT);
}
 
*out_table = table_desc->pointer;
-- 
2.7.4



[PATCH v3 2/4] ACPICA: Tables: Add mechanism to allow to balance late stage acpi_get_table() independently

2017-04-27 Thread Lv Zheng
For all frequent late stage acpi_get_table() clone invocations, we should
only fix them altogether, otherwise, excessive acpi_put_table() could
unexpectedly unmap the table used by the other users. Thus the current plan
is to fix all acpi_get_table() clones together or to fix none of them. This
prevents kernel developers from improving the late stage code quality
without waiting for the ACPICA upstream to improve first.

This patch adds a mechanism to stop decrementing validation count to
prevent the table unmapping operations so that acpi_put_table() balance
fixes can be done independently to each others.

Cc: Dan Williams 
Signed-off-by: Lv Zheng 
---
 drivers/acpi/acpica/tbutils.c | 10 --
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/drivers/acpi/acpica/tbutils.c b/drivers/acpi/acpica/tbutils.c
index 7abe665..b517bd0 100644
--- a/drivers/acpi/acpica/tbutils.c
+++ b/drivers/acpi/acpica/tbutils.c
@@ -445,12 +445,18 @@ void acpi_tb_put_table(struct acpi_table_desc *table_desc)
 
ACPI_FUNCTION_TRACE(acpi_tb_put_table);
 
-   if (table_desc->validation_count == 0) {
+   if ((table_desc->validation_count + 1) == 0) {
ACPI_WARNING((AE_INFO,
- "Table %p, Validation count is zero before 
decrement\n",
+ "Table %p, Validation count is about to expire, 
decrement is unsafe\n",
  table_desc));
return_VOID;
}
+   if (table_desc->validation_count == 0) {
+   ACPI_ERROR((AE_INFO,
+  "Table %p, Validation count is zero before 
decrement\n",
+  table_desc));
+   return_VOID;
+   }
table_desc->validation_count--;
 
if (table_desc->validation_count == 0) {
-- 
2.7.4



[PATCH v3 3/4] ACPI: sysfs: Fix acpi_get_table() leak

2017-04-27 Thread Lv Zheng
From: Dan Williams 

Reading an ACPI table through the /sys/firmware/acpi/tables interface
more than 65,536 times leads to the following log message:

 ACPI Error: Table 88033595eaa8, Validation count is zero after
increment
  (20170119/tbutils-423)

Add the missing acpi_put_table() so the table ->validation_count is
decremented after each read.

Reported-by: Anush Seetharaman 
Signed-off-by: Dan Williams 
Signed-off-by: Lv Zheng 
---
 drivers/acpi/sysfs.c | 7 +--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c
index 1b5ee1e..2bbf722 100644
--- a/drivers/acpi/sysfs.c
+++ b/drivers/acpi/sysfs.c
@@ -333,14 +333,17 @@ static ssize_t acpi_table_show(struct file *filp, struct 
kobject *kobj,
container_of(bin_attr, struct acpi_table_attr, attr);
struct acpi_table_header *table_header = NULL;
acpi_status status;
+   ssize_t len;
 
status = acpi_get_table(table_attr->name, table_attr->instance,
&table_header);
if (ACPI_FAILURE(status))
return -ENODEV;
 
-   return memory_read_from_buffer(buf, count, &offset,
-  table_header, table_header->length);
+   len = memory_read_from_buffer(buf, count, &offset,
+ table_header, table_header->length);
+   acpi_put_table(table_header);
+   return len;
 }
 
 static int acpi_table_attr_init(struct kobject *tables_obj,
-- 
2.7.4



[PATCH v2 1/4] ACPICA: Tables: Fix regression introduced by a too early mechanism enabling

2017-04-27 Thread Lv Zheng
In the Linux kernel side, acpi_get_table() clones haven't been fully
balanced by acpi_put_table() invocations. In ACPICA side, due to the design
change, there are also unbalanced acpi_get_table_by_index() invocations
requiring special care.

So it is not a good timing to report acpi_get_table() counting errors. The
strict balanced validation count check should only be enabled after
confirming that all invocations are safe and compliant to their designed
purposes.

Thus this patch removes the fatal error along with the error report to
fix this issue. Reported by Dan Williams, fixed by Lv Zheng.

Fixes: 174cc7187e6f ("ACPICA: Tables: Back port acpi_get_table_with_size() and 
early_acpi_os_unmap_memory() from Linux kernel")
Cc: Dan Williams 
Reported-by: Anush Seetharaman 
Reported-by: Dan Williams 
Signed-off-by: Lv Zheng 
---
 drivers/acpi/acpica/tbutils.c | 4 
 1 file changed, 4 deletions(-)

diff --git a/drivers/acpi/acpica/tbutils.c b/drivers/acpi/acpica/tbutils.c
index 5a968a7..7abe665 100644
--- a/drivers/acpi/acpica/tbutils.c
+++ b/drivers/acpi/acpica/tbutils.c
@@ -418,11 +418,7 @@ acpi_tb_get_table(struct acpi_table_desc *table_desc,
 
table_desc->validation_count++;
if (table_desc->validation_count == 0) {
-   ACPI_ERROR((AE_INFO,
-   "Table %p, Validation count is zero after 
increment\n",
-   table_desc));
table_desc->validation_count--;
-   return_ACPI_STATUS(AE_LIMIT);
}
 
*out_table = table_desc->pointer;
-- 
2.7.4



[PATCH v2 2/2] ACPI: Fix memory mapping leaks in current sysfs dumpable ACPI tables support.

2017-04-27 Thread Lv Zheng
This patch adds balanced acpi_get_table()/acpi_put_table() support for
sysfs table dumping code so that no need to call
acpi_get_validated_table().

Since ACPICA does not use all of the tables, this can help to reduce some
usless memory mappings by utilizing the new table handling APIs.

The original sysfs dumpable ACPI table implementation forces tables to be
mapped after a read operation and never unmaps them again whatever there
are no users in the kernel interested in these tables.  With new balanced
table handling APIs, tables are unmapped after the read operation.

Signed-off-by: Lv Zheng 
---
 drivers/acpi/sysfs.c | 51 ---
 1 file changed, 36 insertions(+), 15 deletions(-)

diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c
index 1b5ee1e..c3bb6ce 100644
--- a/drivers/acpi/sysfs.c
+++ b/drivers/acpi/sysfs.c
@@ -333,21 +333,34 @@ static ssize_t acpi_table_show(struct file *filp, struct 
kobject *kobj,
container_of(bin_attr, struct acpi_table_attr, attr);
struct acpi_table_header *table_header = NULL;
acpi_status status;
+   ssize_t len;
 
status = acpi_get_table(table_attr->name, table_attr->instance,
&table_header);
if (ACPI_FAILURE(status))
return -ENODEV;
+   len = memory_read_from_buffer(buf, count, &offset,
+ table_header, table_header->length);
+   acpi_put_table(table_header);
+   return len;
+}
+
+static bool acpi_table_has_multiple_instances(char *signature)
+{
+   acpi_status status;
+   struct acpi_table_header *header;
 
-   return memory_read_from_buffer(buf, count, &offset,
-  table_header, table_header->length);
+   status = acpi_get_table(signature, 2, &header);
+   if (ACPI_FAILURE(status))
+   return false;
+   acpi_put_table(header);
+   return true;
 }
 
 static int acpi_table_attr_init(struct kobject *tables_obj,
struct acpi_table_attr *table_attr,
struct acpi_table_header *table_header)
 {
-   struct acpi_table_header *header = NULL;
struct acpi_table_attr *attr = NULL;
char instance_str[ACPI_INST_SIZE];
 
@@ -368,9 +381,9 @@ static int acpi_table_attr_init(struct kobject *tables_obj,
 
ACPI_MOVE_NAME(table_attr->filename, table_header->signature);
table_attr->filename[ACPI_NAME_SIZE] = '\0';
-   if (table_attr->instance > 1 || (table_attr->instance == 1 &&
-!acpi_get_table
-(table_header->signature, 2, 
&header))) {
+   if (table_attr->instance > 1 ||
+   (table_attr->instance == 1 &&
+acpi_table_has_multiple_instances(table_header->signature))) {
snprintf(instance_str, sizeof(instance_str), "%u",
 table_attr->instance);
strcat(table_attr->filename, instance_str);
@@ -419,11 +432,11 @@ acpi_status acpi_sysfs_table_handler(u32 event, void 
*table, void *context)
 
 static int acpi_tables_sysfs_init(void)
 {
-   struct acpi_table_attr *table_attr;
+   struct acpi_table_attr *table_attr = NULL;
struct acpi_table_header *table_header = NULL;
int table_index;
acpi_status status;
-   int ret;
+   int ret = 0;
 
tables_kobj = kobject_create_and_add("tables", acpi_kobj);
if (!tables_kobj)
@@ -435,24 +448,32 @@ static int acpi_tables_sysfs_init(void)
 
for (table_index = 0;; table_index++) {
status = acpi_get_table_by_index(table_index, &table_header);
-
if (status == AE_BAD_PARAMETER)
break;
-
if (ACPI_FAILURE(status))
-   continue;
+   goto next_table;
 
table_attr = kzalloc(sizeof(*table_attr), GFP_KERNEL);
-   if (!table_attr)
-   return -ENOMEM;
+   if (!table_attr) {
+   ret = -ENOMEM;
+   goto next_table;
+   }
 
ret = acpi_table_attr_init(tables_kobj,
   table_attr, table_header);
+   if (ret)
+   goto next_table;
+   list_add_tail(&table_attr->node, &acpi_table_attr_list);
+
+next_table:
+   acpi_put_table(table_header);
if (ret) {
-   kfree(table_attr);
+   if (table_attr) {
+   kfree(table_attr);
+   table_attr = NULL;
+   }
return ret;
}
-   list_add_tail(&table_attr->node, &acpi_table_attr_list);
}
 
kobject_uevent(tables_kobj, KOBJ_ADD);
-- 
2.7.4



[PATCH v2 1/2] ACPICA: Tables: Fix regression introduced by a too early mechanism enabling

2017-04-27 Thread Lv Zheng
In the Linux kernel side, acpi_get_table() clones haven't been fully
balanced by acpi_put_table() invocations. In ACPICA side, due to the design
change, there are also unbalanced acpi_get_table_by_index() invocations
requiring special care to be cleaned up.

So it is not a good timing to report acpi_get_table() counting errors for
this period. The strict balanced validation count check should only be
enabled after confirming that all invocations are safe and compliant to
their designed purposes.

Thus this patch removes the fatal error along with lthe error report to
fix this issue. Reported by Dan Williams, fixed by Lv Zheng.

Fixes: 174cc7187e6f ("ACPICA: Tables: Back port acpi_get_table_with_size() and 
early_acpi_os_unmap_memory() from Linux kernel")
Reported-by: Dan Williams 
Signed-off-by: Lv Zheng 
---
 drivers/acpi/acpica/tbutils.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/acpi/acpica/tbutils.c b/drivers/acpi/acpica/tbutils.c
index 5a968a7..8175c70 100644
--- a/drivers/acpi/acpica/tbutils.c
+++ b/drivers/acpi/acpica/tbutils.c
@@ -418,11 +418,13 @@ acpi_tb_get_table(struct acpi_table_desc *table_desc,
 
table_desc->validation_count++;
if (table_desc->validation_count == 0) {
+   table_desc->validation_count--;
+#if 0
ACPI_ERROR((AE_INFO,
"Table %p, Validation count is zero after 
increment\n",
table_desc));
-   table_desc->validation_count--;
return_ACPI_STATUS(AE_LIMIT);
+#endif
}
 
*out_table = table_desc->pointer;
-- 
2.7.4



[RFC PATCH] ACPICA: Tables: Fix regression introduced by a too early mechanism enabling

2017-04-25 Thread Lv Zheng
In the Linux kernel side, acpi_get_table() hasn't been fully balanced by
acpi_put_table() invocations. So it is not a good timing to report errors.
The strict balanced validation count check should only be enabled after
confirming that all kernel side invocations are safe.

Thus this patch removes the fatal error but leaves the error report to
indicate the leak so that developers can notice the required engineering
change. Reported by Dan Williams, fixed by Lv Zheng.

Reported-by: Dan Williams 
Signed-off-by: Lv Zheng 
---
 drivers/acpi/acpica/tbutils.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/acpi/acpica/tbutils.c b/drivers/acpi/acpica/tbutils.c
index 5a968a7..9e7d95cf 100644
--- a/drivers/acpi/acpica/tbutils.c
+++ b/drivers/acpi/acpica/tbutils.c
@@ -422,7 +422,6 @@ acpi_tb_get_table(struct acpi_table_desc *table_desc,
"Table %p, Validation count is zero after 
increment\n",
table_desc));
table_desc->validation_count--;
-   return_ACPI_STATUS(AE_LIMIT);
}
 
*out_table = table_desc->pointer;
-- 
2.7.4



[PATCH 1/4] ACPICA: Linuxize: Restore and fix intel compiler build

2017-02-07 Thread Lv Zheng
ACPICA commit b59347d0b8b676cb555fe8da5cad08fcd4eeb0d3

The following commit cleans up compiler specific inclusions:
  Commit: 9fa1cebdbfff3db8953cebca8ee327d75edefc40
  Subject: ACPICA: OSL: Cleanup the inclusion order of the
   compiler-specific headers
But breaks one thing due to the following old issue:
 Buidling Linux kernel with Intel compiler originally depends on acgcc.h
 not acintel.h.
So after making Intel compiler build working in ACPICA upstream by
correctly using acintel.h, it becomes unable to build Linux kernel using
Intel compiler as there is no acintel.h in the kernel source tree.

This patch releases acintel.h to Linux kernel and fixes its inclusion in
acenv.h.

Fixes: 9fa1cebdbfff ("ACPICA: OSL: Cleanup the inclusion order of the 
compiler-specific headers")
Cc: sta...@vger.kernel.org # 4.9+
Link: https://github.com/acpica/acpica/commit/b59347d0
Tested-by: Stepan M Mishura 
Signed-off-by: Lv Zheng 
---
 include/acpi/platform/acenv.h   |  2 +-
 include/acpi/platform/acintel.h | 87 +
 2 files changed, 88 insertions(+), 1 deletion(-)
 create mode 100644 include/acpi/platform/acintel.h

diff --git a/include/acpi/platform/acenv.h b/include/acpi/platform/acenv.h
index 926efe9..6fa9c52 100644
--- a/include/acpi/platform/acenv.h
+++ b/include/acpi/platform/acenv.h
@@ -178,7 +178,7 @@
 #include "acmsvc.h"
 
 #elif defined(__INTEL_COMPILER)
-#include "acintel.h"
+#include 
 
 #endif
 
diff --git a/include/acpi/platform/acintel.h b/include/acpi/platform/acintel.h
new file mode 100644
index 000..17bd3b7
--- /dev/null
+++ b/include/acpi/platform/acintel.h
@@ -0,0 +1,87 @@
+/**
+ *
+ * Name: acintel.h - VC specific defines, etc.
+ *
+ */
+
+/*
+ * Copyright (C) 2000 - 2017, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *notice, this list of conditions, and the following disclaimer,
+ *without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *substantially similar to the "NO WARRANTY" disclaimer below
+ *("Disclaimer") and any redistribution must be conditioned upon
+ *including a substantially similar Disclaimer requirement for further
+ *binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *of any contributors may be used to endorse or promote products derived
+ *from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#ifndef __ACINTEL_H__
+#define __ACINTEL_H__
+
+/*
+ * Use compiler specific  is a good practice for even when
+ * -nostdinc is specified (i.e., ACPI_USE_STANDARD_HEADERS undefined.
+ */
+#include 
+
+/* Configuration specific to Intel 64-bit C compiler */
+
+#define COMPILER_DEPENDENT_INT64__int64
+#define COMPILER_DEPENDENT_UINT64   unsigned __int64
+#define ACPI_INLINE __inline
+
+/*
+ * Calling conventions:
+ *
+ * ACPI_SYSTEM_XFACE- Interfaces to host OS (handlers, threads)
+ * ACPI_EXTERNAL_XFACE  - External ACPI interfaces
+ * ACPI_INTERNAL_XFACE  - Internal ACPI interfaces
+ * ACPI_INTERNAL_VAR_XFACE  - Internal variable-parameter list interfaces
+ */
+#define ACPI_SYSTEM_XFACE
+#define ACPI_EXTERNAL_XFACE
+#define ACPI_INTERNAL_XFACE
+#define ACPI_INTERNAL_VAR_XFACE
+
+/* remark 981 - operands evaluated in no particular order */
+#pragma warning(disable:981)
+
+/* warn C4100: unreferenced formal parameter */
+#pragma warning(disable:4100)
+
+/* warn C4127: conditional expression is constant */
+#pragma warning(disable:4127)
+
+/* warn C4706: assignment within conditio

[PATCH 4/4] ACPICA: Update version to 20170119

2017-02-07 Thread Lv Zheng
From: Bob Moore 

ACPICA commit 711a8c19d3c646fdc069c38912d9037c7fa5e718

Version 20170119.

Link: https://github.com/acpica/acpica/commit/711a8c19
Signed-off-by: Bob Moore 
Signed-off-by: Lv Zheng 
---
 include/acpi/acpixf.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h
index bb23cf7..3795386 100644
--- a/include/acpi/acpixf.h
+++ b/include/acpi/acpixf.h
@@ -46,7 +46,7 @@
 
 /* Current ACPICA subsystem version in MMDD format */
 
-#define ACPI_CA_VERSION 0x20161222
+#define ACPI_CA_VERSION 0x20170119
 
 #include 
 #include 
-- 
2.7.4



[PATCH 3/4] ACPICA: Tools: Update common signon, remove compilation bit width

2017-02-07 Thread Lv Zheng
From: Bob Moore 

ACPICA commit 43e04e75a9849072a1557b674004d8093bddb9ef

Remove the bit width of the compiler that generated the tool
from the tool signon. This was confusing and unnecessary.

Changed the iASL signon to add "disassembler" to the name.

Link: https://github.com/acpica/acpica/commit/43e04e75
Signed-off-by: Bob Moore 
Signed-off-by: Lv Zheng 
---
 drivers/acpi/acpica/acapps.h | 10 +-
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/drivers/acpi/acpica/acapps.h b/drivers/acpi/acpica/acapps.h
index c32bbe4..b65f273 100644
--- a/drivers/acpi/acpica/acapps.h
+++ b/drivers/acpi/acpica/acapps.h
@@ -54,23 +54,23 @@
 #define ACPICA_COPYRIGHT"Copyright (c) 2000 - 2017 Intel 
Corporation"
 
 #if ACPI_MACHINE_WIDTH == 64
-#define ACPI_WIDTH  "-64"
+#define ACPI_WIDTH  " (64-bit version)"
 
 #elif ACPI_MACHINE_WIDTH == 32
-#define ACPI_WIDTH  "-32"
+#define ACPI_WIDTH  " (32-bit version)"
 
 #else
 #error unknown ACPI_MACHINE_WIDTH
-#define ACPI_WIDTH  "-??"
+#define ACPI_WIDTH  " (unknown bit width, not 32 or 64)"
 
 #endif
 
 /* Macros for signons and file headers */
 
 #define ACPI_COMMON_SIGNON(utility_name) \
-   "\n%s\n%s version %8.8X%s\n%s\n\n", \
+   "\n%s\n%s version %8.8X\n%s\n\n", \
ACPICA_NAME, \
-   utility_name, ((u32) ACPI_CA_VERSION), ACPI_WIDTH, \
+   utility_name, ((u32) ACPI_CA_VERSION), \
ACPICA_COPYRIGHT
 
 #define ACPI_COMMON_HEADER(utility_name, prefix) \
-- 
2.7.4



[PATCH 2/4] ACPICA: Source tree: Update copyright notices to 2017

2017-02-07 Thread Lv Zheng
From: Bob Moore 

ACPICA commit 16577e5265923f4999b4d2c0addb2343b18135e1

Affects all files.

Link: https://github.com/acpica/acpica/commit/16577e52
Signed-off-by: Bob Moore 
Signed-off-by: Lv Zheng 
---
 drivers/acpi/acpica/acapps.h | 4 ++--
 drivers/acpi/acpica/accommon.h   | 2 +-
 drivers/acpi/acpica/acdebug.h| 2 +-
 drivers/acpi/acpica/acdispat.h   | 2 +-
 drivers/acpi/acpica/acevents.h   | 2 +-
 drivers/acpi/acpica/acglobal.h   | 2 +-
 drivers/acpi/acpica/achware.h| 2 +-
 drivers/acpi/acpica/acinterp.h   | 2 +-
 drivers/acpi/acpica/aclocal.h| 2 +-
 drivers/acpi/acpica/acmacros.h   | 2 +-
 drivers/acpi/acpica/acnamesp.h   | 2 +-
 drivers/acpi/acpica/acobject.h   | 2 +-
 drivers/acpi/acpica/acopcode.h   | 2 +-
 drivers/acpi/acpica/acparser.h   | 2 +-
 drivers/acpi/acpica/acpredef.h   | 2 +-
 drivers/acpi/acpica/acresrc.h| 2 +-
 drivers/acpi/acpica/acstruct.h   | 2 +-
 drivers/acpi/acpica/actables.h   | 2 +-
 drivers/acpi/acpica/acutils.h| 2 +-
 drivers/acpi/acpica/amlcode.h| 2 +-
 drivers/acpi/acpica/amlresrc.h   | 2 +-
 drivers/acpi/acpica/dbcmds.c | 2 +-
 drivers/acpi/acpica/dbconvert.c  | 2 +-
 drivers/acpi/acpica/dbdisply.c   | 2 +-
 drivers/acpi/acpica/dbexec.c | 2 +-
 drivers/acpi/acpica/dbfileio.c   | 2 +-
 drivers/acpi/acpica/dbhistry.c   | 2 +-
 drivers/acpi/acpica/dbinput.c| 2 +-
 drivers/acpi/acpica/dbmethod.c   | 2 +-
 drivers/acpi/acpica/dbnames.c| 2 +-
 drivers/acpi/acpica/dbobject.c   | 2 +-
 drivers/acpi/acpica/dbstats.c| 2 +-
 drivers/acpi/acpica/dbtest.c | 2 +-
 drivers/acpi/acpica/dbutils.c| 2 +-
 drivers/acpi/acpica/dbxface.c| 2 +-
 drivers/acpi/acpica/dsargs.c | 2 +-
 drivers/acpi/acpica/dscontrol.c  | 2 +-
 drivers/acpi/acpica/dsdebug.c| 2 +-
 drivers/acpi/acpica/dsfield.c| 2 +-
 drivers/acpi/acpica/dsinit.c | 2 +-
 drivers/acpi/acpica/dsmethod.c   | 2 +-
 drivers/acpi/acpica/dsmthdat.c   | 2 +-
 drivers/acpi/acpica/dsobject.c   | 2 +-
 drivers/acpi/acpica/dsopcode.c   | 2 +-
 drivers/acpi/acpica/dsutils.c| 2 +-
 drivers/acpi/acpica/dswexec.c| 2 +-
 drivers/acpi/acpica/dswload.c| 2 +-
 drivers/acpi/acpica/dswload2.c   | 2 +-
 drivers/acpi/acpica/dswscope.c   | 2 +-
 drivers/acpi/acpica/dswstate.c   | 2 +-
 drivers/acpi/acpica/evevent.c| 2 +-
 drivers/acpi/acpica/evglock.c| 2 +-
 drivers/acpi/acpica/evgpe.c  | 2 +-
 drivers/acpi/acpica/evgpeblk.c   | 2 +-
 drivers/acpi/acpica/evgpeinit.c  | 2 +-
 drivers/acpi/acpica/evgpeutil.c  | 2 +-
 drivers/acpi/acpica/evhandler.c  | 2 +-
 drivers/acpi/acpica/evmisc.c | 2 +-
 drivers/acpi/acpica/evregion.c   | 2 +-
 drivers/acpi/acpica/evrgnini.c   | 2 +-
 drivers/acpi/acpica/evsci.c  | 2 +-
 drivers/acpi/acpica/evxface.c| 2 +-
 drivers/acpi/acpica/evxfevnt.c   | 2 +-
 drivers/acpi/acpica/evxfgpe.c| 2 +-
 drivers/acpi/acpica/evxfregn.c   | 2 +-
 drivers/acpi/acpica/exconcat.c   | 2 +-
 drivers/acpi/acpica/exconfig.c   | 2 +-
 drivers/acpi/acpica/exconvrt.c   | 2 +-
 drivers/acpi/acpica/excreate.c   | 2 +-
 drivers/acpi/acpica/exdebug.c| 2 +-
 drivers/acpi/acpica/exdump.c | 2 +-
 drivers/acpi/acpica/exfield.c| 2 +-
 drivers/acpi/acpica/exfldio.c| 2 +-
 drivers/acpi/acpica/exmisc.c

[PATCH 0/4] ACPICA 20170119 Release

2017-02-07 Thread Lv Zheng
The 20170119 ACPICA kernel-resident subsystem updates are linuxized based
on the linux-pm/linux-next branch.

The patchset has passed the following build/boot tests.
Build tests are performed as follows:
1. i386 + allyes
2. i386 + allno
3. i386 + default + ACPI_DEBUGGER=y
4. i386 + default + ACPI_DEBUGGER=n + ACPI_DEBUG=y
5. i386 + default + ACPI_DEBUG=n + ACPI=y
6. i386 + default + ACPI=n
7. x86_64 + allyes
8. x86_64 + allno
9. x86_64 + default + ACPI_DEBUGGER=y
10.x86_64 + default + ACPI_DEBUGGER=n + ACPI_DEBUG=y
11.x86_64 + default + ACPI_DEBUG=n + ACPI=y
12.x86_64 + default + ACPI=n
Boot tests are performed as follows:
1. x86_64 + default + ACPI_DEBUGGER=y
Where:
1. i386: machine named as "Dell Inspiron Mini 1010"
2. x86_64: machine named as "Microsoft Surface Pro 3"
3. default: kernel configuration with following items enabled:
   All hardware drivers related to the machines of i386/x86_64
   All "drivers/acpi" configurations
   All "drivers/platform" drivers
   All other drivers that link the APIs provided by ACPICA subsystem

The divergences checking result:
Before applying (20161222 Release):
  369 lines
After applying (20170119 Release):
  369 lines

Bob Moore (3):
  ACPICA: Source tree: Update copyright notices to 2017
  ACPICA: Tools: Update common signon, remove compilation bit width
  ACPICA: Update version to 20170119

Lv Zheng (1):
  ACPICA: Linuxize: Restore and fix intel compiler build

 drivers/acpi/acpica/acapps.h   | 14 ++--
 drivers/acpi/acpica/accommon.h |  2 +-
 drivers/acpi/acpica/acdebug.h  |  2 +-
 drivers/acpi/acpica/acdispat.h |  2 +-
 drivers/acpi/acpica/acevents.h |  2 +-
 drivers/acpi/acpica/acglobal.h |  2 +-
 drivers/acpi/acpica/achware.h  |  2 +-
 drivers/acpi/acpica/acinterp.h |  2 +-
 drivers/acpi/acpica/aclocal.h  |  2 +-
 drivers/acpi/acpica/acmacros.h |  2 +-
 drivers/acpi/acpica/acnamesp.h |  2 +-
 drivers/acpi/acpica/acobject.h |  2 +-
 drivers/acpi/acpica/acopcode.h |  2 +-
 drivers/acpi/acpica/acparser.h |  2 +-
 drivers/acpi/acpica/acpredef.h |  2 +-
 drivers/acpi/acpica/acresrc.h  |  2 +-
 drivers/acpi/acpica/acstruct.h |  2 +-
 drivers/acpi/acpica/actables.h |  2 +-
 drivers/acpi/acpica/acutils.h  |  2 +-
 drivers/acpi/acpica/amlcode.h  |  2 +-
 drivers/acpi/acpica/amlresrc.h |  2 +-
 drivers/acpi/acpica/dbcmds.c   |  2 +-
 drivers/acpi/acpica/dbconvert.c|  2 +-
 drivers/acpi/acpica/dbdisply.c |  2 +-
 drivers/acpi/acpica/dbexec.c   |  2 +-
 drivers/acpi/acpica/dbfileio.c |  2 +-
 drivers/acpi/acpica/dbhistry.c |  2 +-
 drivers/acpi/acpica/dbinput.c  |  2 +-
 drivers/acpi/acpica/dbmethod.c |  2 +-
 drivers/acpi/acpica/dbnames.c  |  2 +-
 drivers/acpi/acpica/dbobject.c |  2 +-
 drivers/acpi/acpica/dbstats.c  |  2 +-
 drivers/acpi/acpica/dbtest.c   |  2 +-
 drivers/acpi/acpica/dbutils.c  |  2 +-
 drivers/acpi/acpica/dbxface.c  |  2 +-
 drivers/acpi/acpica/dsargs.c   |  2 +-
 drivers/acpi/acpica/dscontrol.c|  2 +-
 drivers/acpi/acpica/dsdebug.c  |  2 +-
 drivers/acpi/acpica/dsfield.c  |  2 +-
 drivers/acpi/acpica/dsinit.c   |  2 +-
 drivers/acpi/acpica/dsmethod.c |  2 +-
 drivers/acpi/acpica/dsmthdat.c |  2 +-
 drivers/acpi/acpica/dsobject.c |  2 +-
 drivers/acpi/acpica/dsopcode.c |  2 +-
 drivers/acpi/acpica/dsutils.c  |  2 +-
 drivers/acpi/acpica/dswexec.c  |  2 +-
 drivers/acpi/acpica/dswload.c  |  2 +-
 drivers/acpi/acpica/dswload2.c |  2 +-
 drivers/acpi/acpica/dswscope.c |  2 +-
 drivers/acpi/acpica/dswstate.c |  2 +-
 drivers/acpi/acpica/evevent.c  |  2 +-
 drivers/acpi/acpica/evglock.c  |  2 +-
 drivers/acpi/acpica/evgpe.c|  2 +-
 drivers/acpi/acpica/evgpeblk.c |  2 +-
 drivers/acpi/acpica/evgpeinit.c|  2 +-
 drivers/acpi/acpica/evgpeutil.c|  2 +-
 drivers/acpi/acpica/evhandler.c|  2 +-
 drivers/acpi/acpica/evmisc.c   |  2 +-
 drivers/acpi/acpica/evregion.c 

[PATCH] ACPI / OSL: Fix rcu synchronization logic

2017-01-09 Thread Lv Zheng
The rcu synchronization logic is originally provided to protect
apei_read()/apei_write() as in the APEI drivers, there is NMI event source
requiring non spinlock based synchronization mechanism.

After that, ACPI developers think FADT registers may also require same
facility, so they moved the RCU stuffs to generic ACPI layer.

So now non-task-context ACPI map lookup is only protected by RCU.

This triggers problem as acpi_os_map_memory()/acpi_os_unmap_memory() can be
used to map/unmap tables as long as to map/unmap ACPI registers. When it is
used for the ACPI tables, the caller could invoke this very early. When it
is invoked earlier than workqueue_init() and later than
check_early_ioremp_leak(), invoking synchronize_rcu_expedited() can cause a
kernel hang.

Actually this facility is only used to protect non-task-context ACPI map
lookup, and such mappings are only introduced by
acpi_os_map_generic_address(). So before it is invoked, there is no need to
invoke synchronize_rcu_expedited().

Suggested-by: Huang Ying 
Signed-off-by: Lv Zheng 
Cc: Huang Ying 
Cc: Borislav Petkov 
---
 drivers/acpi/osl.c |5 -
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index a404ff4..3d93633 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -77,6 +77,7 @@ static int (*__acpi_os_prepare_extended_sleep)(u8 
sleep_state, u32 val_a,
 static bool acpi_os_initialized;
 unsigned int acpi_sci_irq = INVALID_ACPI_IRQ;
 bool acpi_permanent_mmap = false;
+bool acpi_synchronize_rcu = false;
 
 /*
  * This list of permanent mappings is for memory that may be accessed from
@@ -378,7 +379,8 @@ static void acpi_os_drop_map_ref(struct acpi_ioremap *map)
 static void acpi_os_map_cleanup(struct acpi_ioremap *map)
 {
if (!map->refcount) {
-   synchronize_rcu_expedited();
+   if (acpi_synchronize_rcu)
+   synchronize_rcu_expedited();
acpi_unmap(map->phys, map->virt);
kfree(map);
}
@@ -444,6 +446,7 @@ int acpi_os_map_generic_address(struct acpi_generic_address 
*gas)
if (!virt)
return -EIO;
 
+   acpi_synchronize_rcu = true;
return 0;
 }
 EXPORT_SYMBOL(acpi_os_map_generic_address);
-- 
1.7.10



[PATCH] ACPI / EC: Remove old CLEAR_ON_RESUME quirk

2017-01-03 Thread Lv Zheng
IRQ polling logic has been implemented to drain the post-boot/resume EC
events:
1. Triggered by the following code, invoked from acpi_ec_enable_event():
if (!test_bit(EC_FLAGS_QUERY_PENDING, &ec->flags))
advance_transaction(ec);
2. Drained by the following code, invoked after acpi_ec_complete_query():
if (status & ACPI_EC_FLAG_SCI)
acpi_ec_submit_query(ec);
This facility is safer than the old CLEAR_ON_RESUME quirk as the
CLEAR_ON_RESUME quirk sends EC query commands unconditionally. The
behavior is apparently not suitable for firmware that requires
QUERY_HANDSHAKE quirk. Though the QUERY_HANDSHAKE quirk isn't used now
because of the improvement done in the EC transaction state machine
(ec_event_clearing=QUERY), it is the proof that we cannot send EC query
command unconditionally.

So it's time to delete the out-dated CLEAR_ON_RESUME quirk to let the users
to try the newer approach.

More statements can be found at Link #1.

Link: https://bugzilla.kernel.org/show_bug.cgi?id=191211 [#1]
Signed-off-by: Lv Zheng 
---
 drivers/acpi/ec.c | 53 -
 1 file changed, 53 deletions(-)

diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 48e19d0..6a32cd4 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -188,7 +188,6 @@ EXPORT_SYMBOL(first_ec);
 static bool boot_ec_is_ecdt = false;
 static struct workqueue_struct *ec_query_wq;
 
-static int EC_FLAGS_CLEAR_ON_RESUME; /* Needs acpi_ec_clear() on boot/resume */
 static int EC_FLAGS_QUERY_HANDSHAKE; /* Needs QR_EC issued when SCI_EVT set */
 static int EC_FLAGS_CORRECT_ECDT; /* Needs ECDT port address correction */
 
@@ -492,26 +491,6 @@ static inline void __acpi_ec_disable_event(struct acpi_ec 
*ec)
ec_log_drv("event blocked");
 }
 
-/*
- * Process _Q events that might have accumulated in the EC.
- * Run with locked ec mutex.
- */
-static void acpi_ec_clear(struct acpi_ec *ec)
-{
-   int i, status;
-   u8 value = 0;
-
-   for (i = 0; i < ACPI_EC_CLEAR_MAX; i++) {
-   status = acpi_ec_query(ec, &value);
-   if (status || !value)
-   break;
-   }
-   if (unlikely(i == ACPI_EC_CLEAR_MAX))
-   pr_warn("Warning: Maximum of %d stale EC events cleared\n", i);
-   else
-   pr_info("%d stale EC events cleared\n", i);
-}
-
 static void acpi_ec_enable_event(struct acpi_ec *ec)
 {
unsigned long flags;
@@ -520,10 +499,6 @@ static void acpi_ec_enable_event(struct acpi_ec *ec)
if (acpi_ec_started(ec))
__acpi_ec_enable_event(ec);
spin_unlock_irqrestore(&ec->lock, flags);
-
-   /* Drain additional events if hardware requires that */
-   if (EC_FLAGS_CLEAR_ON_RESUME)
-   acpi_ec_clear(ec);
 }
 
 #ifdef CONFIG_PM_SLEEP
@@ -1741,31 +1716,6 @@ static int ec_flag_query_handshake(const struct 
dmi_system_id *id)
 #endif
 
 /*
- * On some hardware it is necessary to clear events accumulated by the EC 
during
- * sleep. These ECs stop reporting GPEs until they are manually polled, if too
- * many events are accumulated. (e.g. Samsung Series 5/9 notebooks)
- *
- * https://bugzilla.kernel.org/show_bug.cgi?id=44161
- *
- * Ideally, the EC should also be instructed NOT to accumulate events during
- * sleep (which Windows seems to do somehow), but the interface to control this
- * behaviour is not known at this time.
- *
- * Models known to be affected are Samsung 530Uxx/535Uxx/540Uxx/550Pxx/900Xxx,
- * however it is very likely that other Samsung models are affected.
- *
- * On systems which don't accumulate _Q events during sleep, this extra check
- * should be harmless.
- */
-static int ec_clear_on_resume(const struct dmi_system_id *id)
-{
-   pr_debug("Detected system needing EC poll on resume.\n");
-   EC_FLAGS_CLEAR_ON_RESUME = 1;
-   ec_event_clearing = ACPI_EC_EVT_TIMING_STATUS;
-   return 0;
-}
-
-/*
  * Some ECDTs contain wrong register addresses.
  * MSI MS-171F
  * https://bugzilla.kernel.org/show_bug.cgi?id=12461
@@ -1782,9 +1732,6 @@ static struct dmi_system_id ec_dmi_table[] __initdata = {
ec_correct_ecdt, "MSI MS-171F", {
DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star"),
DMI_MATCH(DMI_PRODUCT_NAME, "MS-171F"),}, NULL},
-   {
-   ec_clear_on_resume, "Samsung hardware", {
-   DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD.")}, NULL},
{},
 };
 
-- 
2.7.4



[PATCH 01/18] ACPICA: Debugger: Rename debugger OSL names

2016-12-28 Thread Lv Zheng
ACPICA commit e76eb8b36ace880e4d475880db1128a206e57b6f

This linuxized ACPICA commit is a back port result of the following
linux commit:
  Commit: f8d31489629c125806ce4bf587c0c5c284d6d113
  Subject: ACPICA: Debugger: Convert some mechanisms to OSPM specific
During the back porting, it is requested by ACPICA to use expected OSL
names. Suggested by Bob Moore, Fixed by Lv Zheng.

Linux is not affected by this patch.

Link: https://github.com/acpica/acpica/commit/e76eb8b3
Signed-off-by: Lv Zheng 
Signed-off-by: Bob Moore 
---
 drivers/acpi/acpica/dbxface.c | 4 ++--
 include/acpi/acpiosxf.h   | 8 
 include/acpi/platform/aclinux.h   | 4 ++--
 include/acpi/platform/aclinuxex.h | 4 ++--
 4 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/drivers/acpi/acpica/dbxface.c b/drivers/acpi/acpica/dbxface.c
index 124db23..5b8cae1 100644
--- a/drivers/acpi/acpica/dbxface.c
+++ b/drivers/acpi/acpica/dbxface.c
@@ -430,7 +430,7 @@ acpi_status acpi_initialize_debugger(void)
 
/* These were created with one unit, grab it */
 
-   status = acpi_os_initialize_command_signals();
+   status = acpi_os_initialize_debugger();
if (ACPI_FAILURE(status)) {
acpi_os_printf("Could not get debugger mutex\n");
return_ACPI_STATUS(status);
@@ -482,7 +482,7 @@ void acpi_terminate_debugger(void)
acpi_os_sleep(100);
}
 
-   acpi_os_terminate_command_signals();
+   acpi_os_terminate_debugger();
}
 
if (acpi_gbl_db_buffer) {
diff --git a/include/acpi/acpiosxf.h b/include/acpi/acpiosxf.h
index f3414c8..42ab9b3 100644
--- a/include/acpi/acpiosxf.h
+++ b/include/acpi/acpiosxf.h
@@ -355,12 +355,12 @@ void acpi_os_redirect_output(void *destination);
 acpi_status acpi_os_get_line(char *buffer, u32 buffer_length, u32 *bytes_read);
 #endif
 
-#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_initialize_command_signals
-acpi_status acpi_os_initialize_command_signals(void);
+#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_initialize_debugger
+acpi_status acpi_os_initialize_debugger(void);
 #endif
 
-#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_terminate_command_signals
-void acpi_os_terminate_command_signals(void);
+#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_terminate_debugger
+void acpi_os_terminate_debugger(void);
 #endif
 
 #ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_wait_command_ready
diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h
index e861a24..af588e0 100644
--- a/include/acpi/platform/aclinux.h
+++ b/include/acpi/platform/aclinux.h
@@ -156,8 +156,8 @@
  */
 #define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_readable
 #define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_writable
-#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_initialize_command_signals
-#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_terminate_command_signals
+#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_initialize_debugger
+#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_terminate_debugger
 
 /*
  * OSL interfaces used by utilities
diff --git a/include/acpi/platform/aclinuxex.h 
b/include/acpi/platform/aclinuxex.h
index 7dbb114..de7648b 100644
--- a/include/acpi/platform/aclinuxex.h
+++ b/include/acpi/platform/aclinuxex.h
@@ -129,12 +129,12 @@ static inline u8 acpi_os_readable(void *pointer, 
acpi_size length)
return TRUE;
 }
 
-static inline acpi_status acpi_os_initialize_command_signals(void)
+static inline acpi_status acpi_os_initialize_debugger(void)
 {
return AE_OK;
 }
 
-static inline void acpi_os_terminate_command_signals(void)
+static inline void acpi_os_terminate_debugger(void)
 {
return;
 }
-- 
2.7.4



[PATCH 02/18] ACPICA: Hardware: Remove bit_offset masking support

2016-12-27 Thread Lv Zheng
ACPICA commit bc7c5291865e099ce01f345d0265f0eba6997e23

This linuxized ACPICA commit is a back port result of the following
Linux commit:
  Commit c3bc26d4b4e36f0dc458eea8b1f722d8a8d9addd
  Subject: ACPICA: ACPI 2.0, Hardware: Add access_width/bit_offset
   support in acpi_hw_read()

The commit was in ACPICA and Linux upstream, after reversion and
re-integration, it is designed not to do bit_offset masking (bit_offset is
only used to determine the boundary of the register) inside of the ACPICA
APIs, but let the callers to do that as:
1. Register can have different masking schemes (W1C, W0C);
2. Normally a mask value will be provided for region format GAS.
So actually the callers are the only ones having the knowledge of masking
the register values. Suggested by Bob Moore, Fixed by Lv Zheng.

Link: https://github.com/acpica/acpica/commit/bc7c5291
Signed-off-by: Lv Zheng 
Signed-off-by: Bob Moore 
---
 drivers/acpi/acpica/hwregs.c | 14 --
 1 file changed, 14 deletions(-)

diff --git a/drivers/acpi/acpica/hwregs.c b/drivers/acpi/acpica/hwregs.c
index 3b7fb99..115c223 100644
--- a/drivers/acpi/acpica/hwregs.c
+++ b/drivers/acpi/acpica/hwregs.c
@@ -252,20 +252,6 @@ acpi_status acpi_hw_read(u32 *value, struct 
acpi_generic_address *reg)
   &value32,
   access_width);
}
-
-   /*
-* Use offset style bit masks because:
-* bit_offset < access_width/bit_width < access_width, 
and
-* access_width is ensured to be less than 32-bits by
-* acpi_hw_validate_register().
-*/
-   if (bit_offset) {
-   value32 &= ACPI_MASK_BITS_BELOW(bit_offset);
-   bit_offset = 0;
-   }
-   if (bit_width < access_width) {
-   value32 &= ACPI_MASK_BITS_ABOVE(bit_width);
-   }
}
 
/*
-- 
2.7.4



[PATCH 08/18] ACPICA: Linux-specific header: Add support for s390x compilation.

2016-12-27 Thread Lv Zheng
From: Colin Ian King 

ACPICA commit ecac9504e32d3b501c8cb021afb253b4a83fc82f

Adds s390x as a 64-bit architecture.

Link: https://github.com/acpica/acpica/commit/ecac9504
Signed-off-by: Colin Ian King 
Signed-off-by: Bob Moore 
Signed-off-by: Lv Zheng 
---
 include/acpi/platform/aclinux.h | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h
index af588e0..252359e 100644
--- a/include/acpi/platform/aclinux.h
+++ b/include/acpi/platform/aclinux.h
@@ -201,7 +201,8 @@
 #define ACPI_CAST_PTHREAD_T(pthread) ((acpi_thread_id) (pthread))
 
 #if defined(__ia64__)|| defined(__x86_64__) ||\
-   defined(__aarch64__) || defined(__PPC64__)
+   defined(__aarch64__) || defined(__PPC64__) ||\
+   defined(__s390x__)
 #define ACPI_MACHINE_WIDTH  64
 #define COMPILER_DEPENDENT_INT64long
 #define COMPILER_DEPENDENT_UINT64   unsigned long
-- 
2.7.4



[PATCH 06/18] ACPICA: Macro header: Fix some typos in comments. No functional change

2016-12-27 Thread Lv Zheng
From: Bob Moore 

ACPICA commit efc97d1d209947d6990ec81a192c6b2589d3e368

Link: https://github.com/acpica/acpica/commit/efc97d1
Signed-off-by: Bob Moore 
Signed-off-by: Lv Zheng 
---
 drivers/acpi/acpica/acmacros.h | 14 --
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/drivers/acpi/acpica/acmacros.h b/drivers/acpi/acpica/acmacros.h
index 6537cbd..31b61a0 100644
--- a/drivers/acpi/acpica/acmacros.h
+++ b/drivers/acpi/acpica/acmacros.h
@@ -46,7 +46,7 @@
 
 /*
  * Extract data using a pointer. Any more than a byte and we
- * get into potential aligment issues -- see the STORE macros below.
+ * get into potential alignment issues -- see the STORE macros below.
  * Use with care.
  */
 #define ACPI_CAST8(ptr) ACPI_CAST_PTR (u8, (ptr))
@@ -63,7 +63,7 @@
 #define ACPI_SET64(ptr, val)(*ACPI_CAST64 (ptr) = (u64) (val))
 
 /*
- * printf() format helper. This macros is a workaround for the difficulties
+ * printf() format helper. This macro is a workaround for the difficulties
  * with emitting 64-bit integers and 64-bit pointers with the same code
  * for both 32-bit and 64-bit hosts.
  */
@@ -260,7 +260,7 @@
 
 #define ACPI_IS_MISALIGNED(value)   (((acpi_size) value) & 
(sizeof(acpi_size)-1))
 
-/* Generic (power-of-two) rounding */
+/* Generic bit manipulation */
 
 #ifndef ACPI_USE_NATIVE_BIT_FINDER
 
@@ -310,6 +310,8 @@
 
 #endif /* ACPI_USE_NATIVE_BIT_FINDER */
 
+/* Generic (power-of-two) rounding */
+
 #define ACPI_ROUND_UP_POWER_OF_TWO_8(a) ((u8) \

(((u16) 1) <<  ACPI_FIND_LAST_BIT_8  ((a)  - 1)))
 #define ACPI_ROUND_DOWN_POWER_OF_TWO_8(a)   ((u8) \
@@ -330,8 +332,8 @@
  * Bit positions start at zero.
  * MASK_BITS_ABOVE creates a mask starting AT the position and above
  * MASK_BITS_BELOW creates a mask starting one bit BELOW the position
- * MASK_BITS_ABOVE/BELOW accpets a bit offset to create a mask
- * MASK_BITS_ABOVE/BELOW_32/64 accpets a bit width to create a mask
+ * MASK_BITS_ABOVE/BELOW accepts a bit offset to create a mask
+ * MASK_BITS_ABOVE/BELOW_32/64 accepts a bit width to create a mask
  * Note: The ACPI_INTEGER_BIT_SIZE check is used to bypass compiler
  * differences with the shift operator
  */
@@ -449,7 +451,7 @@
  */
 #ifndef ACPI_NO_ERROR_MESSAGES
 /*
- * Error reporting. Callers module and line number are inserted by AE_INFO,
+ * Error reporting. The callers module and line number are inserted by AE_INFO,
  * the plist contains a set of parens to allow variable-length lists.
  * These macros are used for both the debug and non-debug versions of the code.
  */
-- 
2.7.4



[PATCH 05/18] ACPICA: Hardware: Sort access bit width algorithm

2016-12-27 Thread Lv Zheng
ACPICA commit 365b321a31cb701957c055cae2d2161577147252

GAS can be in register or register region format, so we need to improve our
"register" format detection code in order not to regress.

Such detection may be still experimental, and is generated according to the
current known facts. Lv Zheng.

Link: https://github.com/acpica/acpica/commit/365b321a
Link: https://bugzilla.kernel.org/show_bug.cgi?id=151501
Reported-and-tested-by: Andrey Skvortsov 
Signed-off-by: Lv Zheng 
Signed-off-by: Bob Moore 
---
 drivers/acpi/acpica/hwregs.c | 79 
 1 file changed, 57 insertions(+), 22 deletions(-)

diff --git a/drivers/acpi/acpica/hwregs.c b/drivers/acpi/acpica/hwregs.c
index 2bc3425..50b9070 100644
--- a/drivers/acpi/acpica/hwregs.c
+++ b/drivers/acpi/acpica/hwregs.c
@@ -52,7 +52,8 @@ ACPI_MODULE_NAME("hwregs")
 #if (!ACPI_REDUCED_HARDWARE)
 /* Local Prototypes */
 static u8
-acpi_hw_get_access_bit_width(struct acpi_generic_address *reg,
+acpi_hw_get_access_bit_width(u64 address,
+struct acpi_generic_address *reg,
 u8 max_bit_width);
 
 static acpi_status
@@ -71,7 +72,8 @@ acpi_hw_write_multiple(u32 value,
  *
  * FUNCTION:acpi_hw_get_access_bit_width
  *
- * PARAMETERS:  reg - GAS register structure
+ * PARAMETERS:  address - GAS register address
+ *  reg - GAS register structure
  *  max_bit_width   - Max bit_width supported (32 or 64)
  *
  * RETURN:  Status
@@ -81,27 +83,59 @@ acpi_hw_write_multiple(u32 value,
  
**/
 
 static u8
-acpi_hw_get_access_bit_width(struct acpi_generic_address *reg, u8 
max_bit_width)
+acpi_hw_get_access_bit_width(u64 address,
+struct acpi_generic_address *reg, u8 max_bit_width)
 {
-   if (!reg->access_width) {
-   if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_IO) {
-   max_bit_width = 32;
-   }
+   u8 access_bit_width;
 
-   /*
-* Detect old register descriptors where only the bit_width 
field
-* makes senses.
-*/
-   if (reg->bit_width < max_bit_width &&
-   !reg->bit_offset && reg->bit_width &&
-   ACPI_IS_POWER_OF_TWO(reg->bit_width) &&
-   ACPI_IS_ALIGNED(reg->bit_width, 8)) {
-   return (reg->bit_width);
-   }
-   return (max_bit_width);
+   /*
+* GAS format "register", used by FADT:
+*  1. Detected if bit_offset is 0 and bit_width is 8/16/32/64;
+*  2. access_size field is ignored and bit_width field is used for
+* determining the boundary of the IO accesses.
+* GAS format "region", used by APEI registers:
+*  1. Detected if bit_offset is not 0 or bit_width is not 8/16/32/64;
+*  2. access_size field is used for determining the boundary of the
+* IO accesses;
+*  3. bit_offset/bit_width fields are used to describe the "region".
+*
+* Note: This algorithm assumes that the "Address" fields should always
+*   contain aligned values.
+*/
+   if (!reg->bit_offset && reg->bit_width &&
+   ACPI_IS_POWER_OF_TWO(reg->bit_width) &&
+   ACPI_IS_ALIGNED(reg->bit_width, 8)) {
+   access_bit_width = reg->bit_width;
+   } else if (reg->access_width) {
+   access_bit_width = (1 << (reg->access_width + 2));
} else {
-   return (1 << (reg->access_width + 2));
+   access_bit_width =
+   ACPI_ROUND_UP_POWER_OF_TWO_8(reg->bit_offset +
+reg->bit_width);
+   if (access_bit_width <= 8) {
+   access_bit_width = 8;
+   } else {
+   while (!ACPI_IS_ALIGNED(address, access_bit_width >> 
3)) {
+   access_bit_width >>= 1;
+   }
+   }
+   }
+
+   /* Maximum IO port access bit width is 32 */
+
+   if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_IO) {
+   max_bit_width = 32;
+   }
+
+   /*
+* Return access width according to the requested maximum access bit 
width,
+* as the caller should know the format of the register and may enforce
+* a 32-bit accesses.
+*/
+   if (access_bit_width < max_bit_width) {
+   return (access_bit_width);
}
+   return (max_bit_width);
 }
 
 /

[PATCH 04/18] ACPICA: Utilities: Add power of two rounding support

2016-12-27 Thread Lv Zheng
ACPICA commit cbb0294649cbd7e8bd6107e4329461a6a7a0d967

This patch adds power of two rounding support up to 32 bits.

The result of the shift operations rearching to the boundary of the cpu
word is unpredicatable, so 64-bit roundings are not supported in order to
make sure no rounded shift-overs.
This support may not be performance friendly, so the APIs might be
overridden by the hosts implementations with ACPI_USE_NATIVE_BIT_FINDER
defined. Lv Zheng.

Link: https://github.com/acpica/acpica/commit/cbb02946
Signed-off-by: Lv Zheng 
Signed-off-by: Bob Moore 
---
 drivers/acpi/acpica/acmacros.h | 60 ++
 1 file changed, 60 insertions(+)

diff --git a/drivers/acpi/acpica/acmacros.h b/drivers/acpi/acpica/acmacros.h
index a3b9543..6537cbd 100644
--- a/drivers/acpi/acpica/acmacros.h
+++ b/drivers/acpi/acpica/acmacros.h
@@ -262,6 +262,66 @@
 
 /* Generic (power-of-two) rounding */
 
+#ifndef ACPI_USE_NATIVE_BIT_FINDER
+
+#define __ACPI_FIND_LAST_BIT_2(a, r)u8)  (a)) & 0x02) ? (r)+1 : 
(r))
+#define __ACPI_FIND_LAST_BIT_4(a, r)u8)  (a)) & 0x0C) ? \
+   
 __ACPI_FIND_LAST_BIT_2  ((a)>>2,  (r)+2) : \
+   
 __ACPI_FIND_LAST_BIT_2  ((a), (r)))
+#define __ACPI_FIND_LAST_BIT_8(a, r)u8)  (a)) & 0xF0) ? \
+   
 __ACPI_FIND_LAST_BIT_4  ((a)>>4,  (r)+4) : \
+   
 __ACPI_FIND_LAST_BIT_4  ((a), (r)))
+#define __ACPI_FIND_LAST_BIT_16(a, r)   u16) (a)) & 0xFF00) ? \
+   
 __ACPI_FIND_LAST_BIT_8  ((a)>>8,  (r)+8) : \
+   
 __ACPI_FIND_LAST_BIT_8  ((a), (r)))
+#define __ACPI_FIND_LAST_BIT_32(a, r)   u32) (a)) & 0x) ? \
+   
 __ACPI_FIND_LAST_BIT_16 ((a)>>16, (r)+16) : \
+   
 __ACPI_FIND_LAST_BIT_16 ((a), (r)))
+#define __ACPI_FIND_LAST_BIT_64(a, r)   u64) (a)) & 
0x) ? \
+   
 __ACPI_FIND_LAST_BIT_32 ((a)>>32, (r)+32) : \
+   
 __ACPI_FIND_LAST_BIT_32 ((a), (r)))
+
+#define ACPI_FIND_LAST_BIT_8(a) ((a) ? __ACPI_FIND_LAST_BIT_8 (a, 
1) : 0)
+#define ACPI_FIND_LAST_BIT_16(a)((a) ? __ACPI_FIND_LAST_BIT_16 (a, 
1) : 0)
+#define ACPI_FIND_LAST_BIT_32(a)((a) ? __ACPI_FIND_LAST_BIT_32 (a, 
1) : 0)
+#define ACPI_FIND_LAST_BIT_64(a)((a) ? __ACPI_FIND_LAST_BIT_64 (a, 
1) : 0)
+
+#define __ACPI_FIND_FIRST_BIT_2(a, r)   u8) (a)) & 0x01) ? (r) : (r)+1)
+#define __ACPI_FIND_FIRST_BIT_4(a, r)   u8) (a)) & 0x03) ? \
+   
 __ACPI_FIND_FIRST_BIT_2  ((a), (r)) : \
+   
 __ACPI_FIND_FIRST_BIT_2  ((a)>>2, (r)+2))
+#define __ACPI_FIND_FIRST_BIT_8(a, r)   u8) (a)) & 0x0F) ? \
+   
 __ACPI_FIND_FIRST_BIT_4  ((a), (r)) : \
+   
 __ACPI_FIND_FIRST_BIT_4  ((a)>>4, (r)+4))
+#define __ACPI_FIND_FIRST_BIT_16(a, r)  u16) (a)) & 0x00FF) ? \
+   
 __ACPI_FIND_FIRST_BIT_8  ((a), (r)) : \
+   
 __ACPI_FIND_FIRST_BIT_8  ((a)>>8, (r)+8))
+#define __ACPI_FIND_FIRST_BIT_32(a, r)  u32) (a)) & 0x) ? \
+   
 __ACPI_FIND_FIRST_BIT_16 ((a), (r)) : \
+   
 __ACPI_FIND_FIRST_BIT_16 ((a)>>16, (r)+16))
+#define __ACPI_FIND_FIRST_BIT_64(a, r)  u64) (a)) & 
0x) ? \
+   
 __ACPI_FIND_FIRST_BIT_32 ((a), (r)) : \
+   
 __ACPI_FIND_FIRST_BIT_32 ((a)>>32, (r)+32))
+
+#define ACPI_

[PATCH 16/18] ACPICA: Fix a problem with recent extra support for control method invocations

2016-12-27 Thread Lv Zheng
From: Bob Moore 

ACPICA commit b7dae343fbb8c392999a66f5e08be5744a5d07e2

This change fixes a problem with the recent support that enables
control method invocations as Target operands to many ASL
operators. Eliminates errors similar to:

Needed type [Reference], found [Processor]

Link: https://github.com/acpica/acpica/commit/b7dae343
Signed-off-by: Bob Moore 
Signed-off-by: Lv Zheng 
---
 drivers/acpi/acpica/psargs.c | 25 -
 1 file changed, 24 insertions(+), 1 deletion(-)

diff --git a/drivers/acpi/acpica/psargs.c b/drivers/acpi/acpica/psargs.c
index 4e1065e..b0e55a7 100644
--- a/drivers/acpi/acpica/psargs.c
+++ b/drivers/acpi/acpica/psargs.c
@@ -269,6 +269,20 @@ acpi_ps_get_next_namepath(struct acpi_walk_state 
*walk_state,
 */
if (ACPI_SUCCESS(status) &&
possible_method_call && (node->type == ACPI_TYPE_METHOD)) {
+   if ((GET_CURRENT_ARG_TYPE(walk_state->arg_types) ==
+ARGP_SUPERNAME)
+   || (GET_CURRENT_ARG_TYPE(walk_state->arg_types) ==
+   ARGP_TARGET)) {
+   /*
+* acpi_ps_get_next_namestring has increased the AML 
pointer past
+* the method invocation namestring, so we need to 
restore the
+* saved AML pointer back to the original method 
invocation
+* namestring.
+*/
+   walk_state->parser_state.aml = start;
+   walk_state->arg_count = 1;
+   acpi_ps_init_op(arg, AML_INT_METHODCALL_OP);
+   }
 
/* This name is actually a control method invocation */
 
@@ -833,7 +847,10 @@ acpi_ps_get_next_arg(struct acpi_walk_state *walk_state,
  arg_type));
 
subop = acpi_ps_peek_opcode(parser_state);
-   if (subop == 0) {
+   if (subop == 0 ||
+   acpi_ps_is_leading_char(subop) ||
+   ACPI_IS_ROOT_PREFIX(subop) ||
+   ACPI_IS_PARENT_PREFIX(subop)) {
 
/* NULL target (zero). Convert to a NULL namepath */
 
@@ -848,6 +865,12 @@ acpi_ps_get_next_arg(struct acpi_walk_state *walk_state,
acpi_ps_get_next_namepath(walk_state, parser_state,
  arg,
  
ACPI_POSSIBLE_METHOD_CALL);
+
+   if (arg->common.aml_opcode == AML_INT_METHODCALL_OP) {
+   acpi_ps_free_op(arg);
+   arg = NULL;
+   walk_state->arg_count = 1;
+   }
} else {
/* Single complex argument, nothing returned */
 
-- 
2.7.4



[PATCH 09/18] ACPICA: MSVC: Fix MSVC6 build issues

2016-12-27 Thread Lv Zheng
ACPICA commit fa0680030a2969e1085563da633713e1c321637c

Build environment has changed because of new improvements:
1. New files are split
2. New inclusion order
This patch updates MSVC project files accordingly.

Linux is not affected by this patch.

Link: https://github.com/acpica/acpica/commit/fa068003
Signed-off-by: Lv Zheng 
Signed-off-by: Bob Moore 
---
 include/acpi/platform/acenv.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/include/acpi/platform/acenv.h b/include/acpi/platform/acenv.h
index 34cce72..cf93b66 100644
--- a/include/acpi/platform/acenv.h
+++ b/include/acpi/platform/acenv.h
@@ -357,7 +357,7 @@
 #include 
 #include 
 #include 
-#ifdef ACPI_APPLICATION
+#if defined (ACPI_APPLICATION) || defined(ACPI_LIBRARY)
 #include 
 #include 
 #include 
-- 
2.7.4



[PATCH 07/18] ACPICA: Hardware: Add sleep register hooks

2016-12-27 Thread Lv Zheng
ACPICA commit ba665dc8e20d9f7730466a659564dd6c557a6cbc

In Linux, para-virtualization implmentation hooks critical register writes
to prevent real hardware operations. This increases divergences when the
sleep registers are cracked in Linux resident ACPICA. This patch tries to
introduce a single OSL to reduce the divergences. Lv Zheng.

Link: https://github.com/acpica/acpica/commit/ba665dc8
Signed-off-by: Lv Zheng 
Signed-off-by: Bob Moore 
---
 drivers/acpi/acpica/hwesleep.c | 35 ++
 drivers/acpi/acpica/hwsleep.c  | 11 +++
 drivers/acpi/osl.c | 27 +++--
 include/acpi/acexcep.h |  9 ++
 include/acpi/acpiosxf.h|  4 +++
 .../acpi/os_specific/service_layers/osunixxf.c | 22 ++
 6 files changed, 76 insertions(+), 32 deletions(-)

diff --git a/drivers/acpi/acpica/hwesleep.c b/drivers/acpi/acpica/hwesleep.c
index 3f2fb4b..9023a1b 100644
--- a/drivers/acpi/acpica/hwesleep.c
+++ b/drivers/acpi/acpica/hwesleep.c
@@ -43,7 +43,6 @@
  */
 
 #include 
-#include 
 #include "accommon.h"
 
 #define _COMPONENT  ACPI_HARDWARE
@@ -103,7 +102,7 @@ void acpi_hw_execute_sleep_method(char *method_pathname, 
u32 integer_argument)
 acpi_status acpi_hw_extended_sleep(u8 sleep_state)
 {
acpi_status status;
-   u8 sleep_type_value;
+   u8 sleep_control;
u64 sleep_status;
 
ACPI_FUNCTION_TRACE(hw_extended_sleep);
@@ -125,18 +124,6 @@ acpi_status acpi_hw_extended_sleep(u8 sleep_state)
 
acpi_gbl_system_awake_and_running = FALSE;
 
-   /* Flush caches, as per ACPI specification */
-
-   ACPI_FLUSH_CPU_CACHE();
-
-   status = acpi_os_prepare_extended_sleep(sleep_state,
-   acpi_gbl_sleep_type_a,
-   acpi_gbl_sleep_type_b);
-   if (ACPI_SKIP(status))
-   return_ACPI_STATUS(AE_OK);
-   if (ACPI_FAILURE(status))
-   return_ACPI_STATUS(status);
-
/*
 * Set the SLP_TYP and SLP_EN bits.
 *
@@ -146,12 +133,22 @@ acpi_status acpi_hw_extended_sleep(u8 sleep_state)
ACPI_DEBUG_PRINT((ACPI_DB_INIT,
  "Entering sleep state [S%u]\n", sleep_state));
 
-   sleep_type_value =
-   ((acpi_gbl_sleep_type_a << ACPI_X_SLEEP_TYPE_POSITION) &
-ACPI_X_SLEEP_TYPE_MASK);
+   sleep_control = ((acpi_gbl_sleep_type_a << ACPI_X_SLEEP_TYPE_POSITION) &
+ACPI_X_SLEEP_TYPE_MASK) | ACPI_X_SLEEP_ENABLE;
+
+   /* Flush caches, as per ACPI specification */
+
+   ACPI_FLUSH_CPU_CACHE();
+
+   status = acpi_os_enter_sleep(sleep_state, sleep_control, 0);
+   if (status == AE_CTRL_TERMINATE) {
+   return_ACPI_STATUS(AE_OK);
+   }
+   if (ACPI_FAILURE(status)) {
+   return_ACPI_STATUS(status);
+   }
 
-   status = acpi_write((u64)(sleep_type_value | ACPI_X_SLEEP_ENABLE),
-   &acpi_gbl_FADT.sleep_control);
+   status = acpi_write((u64)sleep_control, &acpi_gbl_FADT.sleep_control);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/acpica/hwsleep.c b/drivers/acpi/acpica/hwsleep.c
index d00c981..563c5d9 100644
--- a/drivers/acpi/acpica/hwsleep.c
+++ b/drivers/acpi/acpica/hwsleep.c
@@ -43,7 +43,6 @@
  */
 
 #include 
-#include 
 #include "accommon.h"
 
 #define _COMPONENT  ACPI_HARDWARE
@@ -152,12 +151,14 @@ acpi_status acpi_hw_legacy_sleep(u8 sleep_state)
 
ACPI_FLUSH_CPU_CACHE();
 
-   status = acpi_os_prepare_sleep(sleep_state, pm1a_control,
-  pm1b_control);
-   if (ACPI_SKIP(status))
+   status = acpi_os_enter_sleep(sleep_state, pm1a_control, pm1b_control);
+   if (status == AE_CTRL_TERMINATE) {
return_ACPI_STATUS(AE_OK);
-   if (ACPI_FAILURE(status))
+   }
+   if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
+   }
+
/* Write #2: Write both SLP_TYP + SLP_EN */
 
status = acpi_hw_write_pm1_control(pm1a_control, pm1b_control);
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index a404ff4..82285c0 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -1686,7 +1686,7 @@ acpi_status acpi_os_prepare_sleep(u8 sleep_state, u32 
pm1a_control,
if (rc < 0)
return AE_ERROR;
else if (rc > 0)
-   return AE_CTRL_SKIP;
+   return AE_CTRL_TERMINATE;
 
return AE_OK;
 }
@@ -1697,6 +1697,7 @@ void acpi_os_set_prepare_sleep(int (*func)(u8 sleep_state,
__acpi_os_prepare_sleep = func;
 }
 
+#if (ACPI_REDUCED_HARDWARE)
 acpi_status acpi_os_prepare_extended_sleep(u8 sleep_state, u32 val_a,
   

[PATCH 00/18] ACPICA 20161222 Release

2016-12-27 Thread Lv Zheng
The 20161222 ACPICA kernel-resident subsystem updates are linuxized based
on the linux-pm/linux-next branch.

The patchset has passed the following build/boot tests.
Build tests are performed as follows:
1. i386 + allyes
2. i386 + allno
3. i386 + default + ACPI_DEBUGGER=y
4. i386 + default + ACPI_DEBUGGER=n + ACPI_DEBUG=y
5. i386 + default + ACPI_DEBUG=n + ACPI=y
6. i386 + default + ACPI=n
7. x86_64 + allyes
8. x86_64 + allno
9. x86_64 + default + ACPI_DEBUGGER=y
10.x86_64 + default + ACPI_DEBUGGER=n + ACPI_DEBUG=y
11.x86_64 + default + ACPI_DEBUG=n + ACPI=y
12.x86_64 + default + ACPI=n
Boot tests are performed as follows:
1. x86_64 + default + ACPI_DEBUGGER=y
Where:
1. i386: machine named as "Dell Inspiron Mini 1010"
2. x86_64: machine named as "Microsoft Surface Pro 3"
3. default: kernel configuration with following items enabled:
   All hardware drivers related to the machines of i386/x86_64
   All "drivers/acpi" configurations
   All "drivers/platform" drivers
   All other drivers that link the APIs provided by ACPICA subsystem

The divergences checking result:
Before applying (20161117 Release):
  467 lines
After applying (20161222 Release):
  369 lines

Bob Moore (8):
  ACPICA: Macro header: Fix some typos in comments. No functional change
  ACPICA: Utilities: Update debug output
  ACPICA: Resources: Not a valid resource if buffer length too long
  ACPICA: Fix for implicit result conversion for the To functions
  ACPICA: Parser: Allow method invocations as target operands
  ACPICA: Fix a problem with recent extra support for control method
invocations
  ACPICA: Parser: Update parse info table for some operators
  ACPICA: Update version to 20161222

Colin Ian King (1):
  ACPICA: Linux-specific header: Add support for s390x compilation.

David E. Box (1):
  ACPICA: Disassembler: Add Switch/Case disassembly support

Lv Zheng (8):
  ACPICA: Debugger: Rename debugger OSL names
  ACPICA: Hardware: Remove bit_offset masking support
  ACPICA: Hardware: Add access_width/bit_offset support in
acpi_hw_write()
  ACPICA: Utilities: Add power of two rounding support
  ACPICA: Hardware: Sort access bit width algorithm
  ACPICA: Hardware: Add sleep register hooks
  ACPICA: MSVC: Fix MSVC6 build issues
  ACPICA: EFI: Add efihello demo application

 drivers/acpi/acpica/aclocal.h  |   7 +-
 drivers/acpi/acpica/acmacros.h |  72 +-
 drivers/acpi/acpica/acopcode.h |  22 +--
 drivers/acpi/acpica/amlcode.h  |  20 ++-
 drivers/acpi/acpica/dbxface.c  |   4 +-
 drivers/acpi/acpica/exconvrt.c |   1 -
 drivers/acpi/acpica/exresop.c  |   1 -
 drivers/acpi/acpica/hwesleep.c |  35 +++--
 drivers/acpi/acpica/hwregs.c   | 153 +++--
 drivers/acpi/acpica/hwsleep.c  |  11 +-
 drivers/acpi/acpica/psargs.c   |  97 +
 drivers/acpi/acpica/psloop.c   |   4 +
 drivers/acpi/acpica/psobject.c |  10 +-
 drivers/acpi/acpica/pstree.c   |  10 +-
 drivers/acpi/acpica/utdecode.c |   4 +-
 drivers/acpi/acpica/utdelete.c |   6 +-
 drivers/acpi/acpica/utresrc.c  |  17 ++-
 drivers/acpi/osl.c |  27 +++-
 include/acpi/acexcep.h |   9 +-
 include/acpi/acpiosxf.h|  12 +-
 include/acpi/acpixf.h  |   2 +-
 include/acpi/platform/acenv.h  |   5 +-
 include/acpi/platform/aclinux.h|   7 +-
 include/acpi/platform/aclinuxex.h  |   4 +-
 .../acpi/os_specific/service_layers/osunixxf.c |  22 +++
 25 files changed, 405 insertions(+), 157 deletions(-)

-- 
2.7.4



[PATCH 03/18] ACPICA: Hardware: Add access_width/bit_offset support in acpi_hw_write()

2016-12-27 Thread Lv Zheng
ACPICA commit 1ecab20bbe69a176dfb6da7210fe77aa6b3ad680

This patch adds access_width/bit_offset support in acpi_hw_write().
Lv Zheng.

Link: https://github.com/acpica/acpica/commit/1ecab20b
Signed-off-by: Lv Zheng 
Signed-off-by: Bob Moore 
---
 drivers/acpi/acpica/hwregs.c | 62 +---
 1 file changed, 53 insertions(+), 9 deletions(-)

diff --git a/drivers/acpi/acpica/hwregs.c b/drivers/acpi/acpica/hwregs.c
index 115c223..2bc3425 100644
--- a/drivers/acpi/acpica/hwregs.c
+++ b/drivers/acpi/acpica/hwregs.c
@@ -292,6 +292,12 @@ acpi_status acpi_hw_read(u32 *value, struct 
acpi_generic_address *reg)
 acpi_status acpi_hw_write(u32 value, struct acpi_generic_address *reg)
 {
u64 address;
+   u8 access_width;
+   u32 bit_width;
+   u8 bit_offset;
+   u64 value64;
+   u32 value32;
+   u8 index;
acpi_status status;
 
ACPI_FUNCTION_NAME(hw_write);
@@ -303,23 +309,61 @@ acpi_status acpi_hw_write(u32 value, struct 
acpi_generic_address *reg)
return (status);
}
 
+   /* Convert access_width into number of bits based */
+
+   access_width = acpi_hw_get_access_bit_width(reg, 32);
+   bit_width = reg->bit_offset + reg->bit_width;
+   bit_offset = reg->bit_offset;
+
/*
 * Two address spaces supported: Memory or IO. PCI_Config is
 * not supported here because the GAS structure is insufficient
 */
-   if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
-   status = acpi_os_write_memory((acpi_physical_address)
- address, (u64)value,
- reg->bit_width);
-   } else {/* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier 
*/
-
-   status = acpi_hw_write_port((acpi_io_address)
-   address, value, reg->bit_width);
+   index = 0;
+   while (bit_width) {
+   /*
+* Use offset style bit reads because "Index * AccessWidth" is
+* ensured to be less than 32-bits by 
acpi_hw_validate_register().
+*/
+   value32 = ACPI_GET_BITS(&value, index * access_width,
+   ACPI_MASK_BITS_ABOVE_32(access_width));
+
+   if (bit_offset >= access_width) {
+   bit_offset -= access_width;
+   } else {
+   if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
+   value64 = (u64)value32;
+   status =
+   acpi_os_write_memory((acpi_physical_address)
+address +
+index *
+ACPI_DIV_8
+(access_width),
+value64, access_width);
+   } else {/* ACPI_ADR_SPACE_SYSTEM_IO, validated 
earlier */
+
+   status = acpi_hw_write_port((acpi_io_address)
+   address +
+   index *
+   ACPI_DIV_8
+   (access_width),
+   value32,
+   access_width);
+   }
+   }
+
+   /*
+* Index * access_width is ensured to be less than 32-bits by
+* acpi_hw_validate_register().
+*/
+   bit_width -=
+   bit_width > access_width ? access_width : bit_width;
+   index++;
}
 
ACPI_DEBUG_PRINT((ACPI_DB_IO,
  "Wrote: %8.8X width %2d   to %8.8X%8.8X (%s)\n",
- value, reg->bit_width, ACPI_FORMAT_UINT64(address),
+ value, access_width, ACPI_FORMAT_UINT64(address),
  acpi_ut_get_region_name(reg->space_id)));
 
return (status);
-- 
2.7.4



[PATCH 18/18] ACPICA: Update version to 20161222

2016-12-27 Thread Lv Zheng
From: Bob Moore 

ACPICA commit 0d5a056877c2e37e0bfce8d262cec339dc8d55fd
ACPICA commit 5bea13a9e1eb2a0da99600d181afbc5fa075a9eb

Version 20161222

Link: https://github.com/acpica/acpica/commit/0d5a0568
Link: https://github.com/acpica/acpica/commit/5bea13a9
Signed-off-by: Bob Moore 
Signed-off-by: Lv Zheng 
---
 include/acpi/acpixf.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h
index f5e10dd..12f4266 100644
--- a/include/acpi/acpixf.h
+++ b/include/acpi/acpixf.h
@@ -46,7 +46,7 @@
 
 /* Current ACPICA subsystem version in MMDD format */
 
-#define ACPI_CA_VERSION 0x20160930
+#define ACPI_CA_VERSION 0x20161222
 
 #include 
 #include 
-- 
2.7.4



[PATCH 15/18] ACPICA: Parser: Allow method invocations as target operands

2016-12-27 Thread Lv Zheng
From: Bob Moore 

ACPICA commit a6cca7a4786cdbfd29cea67e84b5b01a8ae6ff1c

Method invocations as target operands are allowed as target
operands in the ASL grammar. This change implements support
for this. Method must return a reference for this to work
properly at runtime, however.

Link: https://github.com/acpica/acpica/commit/a6cca7a4
Signed-off-by: Bob Moore 
Signed-off-by: Lv Zheng 
---
 drivers/acpi/acpica/psargs.c   | 86 --
 drivers/acpi/acpica/psloop.c   |  4 ++
 drivers/acpi/acpica/psobject.c | 10 -
 drivers/acpi/acpica/pstree.c   | 10 +++--
 4 files changed, 69 insertions(+), 41 deletions(-)

diff --git a/drivers/acpi/acpica/psargs.c b/drivers/acpi/acpica/psargs.c
index c29c930..4e1065e 100644
--- a/drivers/acpi/acpica/psargs.c
+++ b/drivers/acpi/acpica/psargs.c
@@ -269,23 +269,13 @@ acpi_ps_get_next_namepath(struct acpi_walk_state 
*walk_state,
 */
if (ACPI_SUCCESS(status) &&
possible_method_call && (node->type == ACPI_TYPE_METHOD)) {
-   if (walk_state->opcode == AML_UNLOAD_OP) {
-   /*
-* acpi_ps_get_next_namestring has increased the AML 
pointer,
-* so we need to restore the saved AML pointer for 
method call.
-*/
-   walk_state->parser_state.aml = start;
-   walk_state->arg_count = 1;
-   acpi_ps_init_op(arg, AML_INT_METHODCALL_OP);
-   return_ACPI_STATUS(AE_OK);
-   }
 
/* This name is actually a control method invocation */
 
method_desc = acpi_ns_get_attached_object(node);
ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
- "Control Method - %p Desc %p Path=%p\n", node,
- method_desc, path));
+ "Control Method invocation %4.4s - %p Desc %p 
Path=%p\n",
+ node->name.ascii, node, method_desc, path));
 
name_op = acpi_ps_alloc_op(AML_INT_NAMEPATH_OP, start);
if (!name_op) {
@@ -719,6 +709,10 @@ acpi_ps_get_next_arg(struct acpi_walk_state *walk_state,
 
ACPI_FUNCTION_TRACE_PTR(ps_get_next_arg, parser_state);
 
+   ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
+ "Expected argument type ARGP: %s (%2.2X)\n",
+ acpi_ut_get_argument_type_name(arg_type), arg_type));
+
switch (arg_type) {
case ARGP_BYTEDATA:
case ARGP_WORDDATA:
@@ -796,11 +790,14 @@ acpi_ps_get_next_arg(struct acpi_walk_state *walk_state,
}
break;
 
-   case ARGP_TARGET:
-   case ARGP_SUPERNAME:
case ARGP_SIMPLENAME:
case ARGP_NAME_OR_REF:
 
+   ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
+ " SimpleName/NameOrRef: %s (%2.2X)\n",
+ acpi_ut_get_argument_type_name(arg_type),
+ arg_type));
+
subop = acpi_ps_peek_opcode(parser_state);
if (subop == 0 ||
acpi_ps_is_leading_char(subop) ||
@@ -816,29 +813,41 @@ acpi_ps_get_next_arg(struct acpi_walk_state *walk_state,
return_ACPI_STATUS(AE_NO_MEMORY);
}
 
-   /* To support super_name arg of Unload */
-
-   if (walk_state->opcode == AML_UNLOAD_OP) {
-   status =
-   acpi_ps_get_next_namepath(walk_state,
- parser_state, arg,
- 
ACPI_POSSIBLE_METHOD_CALL);
-
-   /*
-* If the super_name argument is a method call, 
we have
-* already restored the AML pointer, just free 
this Arg
-*/
-   if (arg->common.aml_opcode ==
-   AML_INT_METHODCALL_OP) {
-   acpi_ps_free_op(arg);
-   arg = NULL;
-   }
-   } else {
-   status =
-   acpi_ps_get_next_namepath(walk_state,
- parser_state, arg,
- 
ACPI_NOT_METHOD_CALL);
+   status =
+   acpi_ps_get_next_namepath(walk_state, parser_state,
+ arg,
+ ACPI_NOT_METHOD_CALL)

[PATCH 17/18] ACPICA: Parser: Update parse info table for some operators

2016-12-27 Thread Lv Zheng
From: Bob Moore 

ACPICA commit b90e39948954ff400cff1a3f8effddb67f15460b

Operand for deref_of should not have been a term_arg, should be super_name.
Rename NAME_OR_REF to SIMPLENAME.

Link: https://github.com/acpica/acpica/commit/b90e3994
Signed-off-by: Bob Moore 
Signed-off-by: Lv Zheng 
---
 drivers/acpi/acpica/acopcode.h | 8 
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/acpi/acpica/acopcode.h b/drivers/acpi/acpica/acopcode.h
index 84d611b..245c1da 100644
--- a/drivers/acpi/acpica/acopcode.h
+++ b/drivers/acpi/acpica/acopcode.h
@@ -92,7 +92,7 @@
 #define ARGP_BYTELIST_OPARGP_LIST1 (ARGP_NAMESTRING)
 #define ARGP_CONCAT_OP  ARGP_LIST3 (ARGP_TERMARG,
ARGP_TERMARG,   ARGP_TARGET)
 #define ARGP_CONCAT_RES_OP  ARGP_LIST3 (ARGP_TERMARG,
ARGP_TERMARG,   ARGP_TARGET)
-#define ARGP_COND_REF_OF_OP ARGP_LIST2 
(ARGP_NAME_OR_REF,ARGP_TARGET)
+#define ARGP_COND_REF_OF_OP ARGP_LIST2 (ARGP_SIMPLENAME, 
ARGP_TARGET)
 #define ARGP_CONNECTFIELD_OPARGP_LIST1 (ARGP_NAMESTRING)
 #define ARGP_CONTINUE_OPARG_NONE
 #define ARGP_COPY_OPARGP_LIST2 (ARGP_TERMARG,
ARGP_SIMPLENAME)
@@ -105,7 +105,7 @@
 #define ARGP_DATA_REGION_OP ARGP_LIST4 (ARGP_NAME,   
ARGP_TERMARG,   ARGP_TERMARG,   ARGP_TERMARG)
 #define ARGP_DEBUG_OP   ARG_NONE
 #define ARGP_DECREMENT_OP   ARGP_LIST1 (ARGP_SUPERNAME)
-#define ARGP_DEREF_OF_OPARGP_LIST1 (ARGP_TERMARG)
+#define ARGP_DEREF_OF_OPARGP_LIST1 (ARGP_SUPERNAME)
 #define ARGP_DEVICE_OP  ARGP_LIST3 (ARGP_PKGLENGTH,  
ARGP_NAME,  ARGP_OBJLIST)
 #define ARGP_DIVIDE_OP  ARGP_LIST4 (ARGP_TERMARG,
ARGP_TERMARG,   ARGP_TARGET,ARGP_TARGET)
 #define ARGP_DWORD_OP   ARGP_LIST1 (ARGP_DWORDDATA)
@@ -152,14 +152,14 @@
 #define ARGP_NAMEPATH_OPARGP_LIST1 (ARGP_NAMESTRING)
 #define ARGP_NOOP_OPARG_NONE
 #define ARGP_NOTIFY_OP  ARGP_LIST2 (ARGP_SUPERNAME,  
ARGP_TERMARG)
-#define ARGP_OBJECT_TYPE_OP ARGP_LIST1 (ARGP_NAME_OR_REF)
+#define ARGP_OBJECT_TYPE_OP ARGP_LIST1 (ARGP_SIMPLENAME)
 #define ARGP_ONE_OP ARG_NONE
 #define ARGP_ONES_OPARG_NONE
 #define ARGP_PACKAGE_OP ARGP_LIST3 (ARGP_PKGLENGTH,  
ARGP_BYTEDATA,  ARGP_DATAOBJLIST)
 #define ARGP_POWER_RES_OP   ARGP_LIST5 (ARGP_PKGLENGTH,  
ARGP_NAME,  ARGP_BYTEDATA,  ARGP_WORDDATA,  ARGP_OBJLIST)
 #define ARGP_PROCESSOR_OP   ARGP_LIST6 (ARGP_PKGLENGTH,  
ARGP_NAME,  ARGP_BYTEDATA,  ARGP_DWORDDATA, ARGP_BYTEDATA,  
ARGP_OBJLIST)
 #define ARGP_QWORD_OP   ARGP_LIST1 (ARGP_QWORDDATA)
-#define ARGP_REF_OF_OP  ARGP_LIST1 (ARGP_NAME_OR_REF)
+#define ARGP_REF_OF_OP  ARGP_LIST1 (ARGP_SIMPLENAME)
 #define ARGP_REGION_OP  ARGP_LIST4 (ARGP_NAME,   
ARGP_BYTEDATA,  ARGP_TERMARG,   ARGP_TERMARG)
 #define ARGP_RELEASE_OP ARGP_LIST1 (ARGP_SUPERNAME)
 #define ARGP_RESERVEDFIELD_OP   ARGP_LIST1 (ARGP_NAMESTRING)
-- 
2.7.4



[PATCH 13/18] ACPICA: Resources: Not a valid resource if buffer length too long

2016-12-27 Thread Lv Zheng
From: Bob Moore 

ACPICA commit 9f76de2d249b18804e35fb55d14b1c2604d627a1
ACPICA commit b2e89d72ef1e9deefd63c3fd1dee90f893575b3a
ACPICA commit 23b5bbe6d78afd3c5abf3adb91a1b098a3000b2e

The declared buffer length must be the same as the length of the
byte initializer list, otherwise not a valid resource descriptor.

Link: https://github.com/acpica/acpica/commit/9f76de2d
Link: https://github.com/acpica/acpica/commit/b2e89d72
Link: https://github.com/acpica/acpica/commit/23b5bbe6
Signed-off-by: Bob Moore 
Signed-off-by: Lv Zheng 
---
 drivers/acpi/acpica/utresrc.c | 17 -
 1 file changed, 12 insertions(+), 5 deletions(-)

diff --git a/drivers/acpi/acpica/utresrc.c b/drivers/acpi/acpica/utresrc.c
index 1de3376..2ad99ea 100644
--- a/drivers/acpi/acpica/utresrc.c
+++ b/drivers/acpi/acpica/utresrc.c
@@ -421,8 +421,10 @@ acpi_ut_walk_aml_resources(struct acpi_walk_state 
*walk_state,
 
ACPI_FUNCTION_TRACE(ut_walk_aml_resources);
 
-   /* The absolute minimum resource template is one end_tag descriptor */
-
+   /*
+* The absolute minimum resource template is one end_tag descriptor.
+* However, we will treat a lone end_tag as just a simple buffer.
+*/
if (aml_length < sizeof(struct aml_resource_end_tag)) {
return_ACPI_STATUS(AE_AML_NO_RESOURCE_END_TAG);
}
@@ -454,9 +456,8 @@ acpi_ut_walk_aml_resources(struct acpi_walk_state 
*walk_state,
/* Invoke the user function */
 
if (user_function) {
-   status =
-   user_function(aml, length, offset, resource_index,
- context);
+   status = user_function(aml, length, offset,
+  resource_index, context);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
@@ -480,6 +481,12 @@ acpi_ut_walk_aml_resources(struct acpi_walk_state 
*walk_state,
*context = aml;
}
 
+   /* Check if buffer is defined to be longer than the 
resource length */
+
+   if (aml_length > (offset + length)) {
+   return_ACPI_STATUS(AE_AML_NO_RESOURCE_END_TAG);
+   }
+
/* Normal exit */
 
return_ACPI_STATUS(AE_OK);
-- 
2.7.4



[PATCH 12/18] ACPICA: Utilities: Update debug output

2016-12-27 Thread Lv Zheng
From: Bob Moore 

ACPICA commit 082b5b3ee31f74735e166858eeda025288604a5a

Enhancement of miscellaneous debug output.

Link: https://github.com/acpica/acpica/commit/082b5b3e
Signed-off-by: Bob Moore 
Signed-off-by: Lv Zheng 
---
 drivers/acpi/acpica/utdecode.c | 4 ++--
 drivers/acpi/acpica/utdelete.c | 6 --
 2 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/drivers/acpi/acpica/utdecode.c b/drivers/acpi/acpica/utdecode.c
index b3d8421..c6f2ce1 100644
--- a/drivers/acpi/acpica/utdecode.c
+++ b/drivers/acpi/acpica/utdecode.c
@@ -238,7 +238,7 @@ const char *acpi_ut_get_object_type_name(union 
acpi_operand_object *obj_desc)
 
if (!obj_desc) {
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Null Object Descriptor\n"));
-   return_PTR("[NULL Object Descriptor]");
+   return_STR("[NULL Object Descriptor]");
}
 
/* These descriptor types share a common area */
@@ -251,7 +251,7 @@ const char *acpi_ut_get_object_type_name(union 
acpi_operand_object *obj_desc)
  acpi_ut_get_descriptor_name(obj_desc),
  obj_desc));
 
-   return_PTR("Invalid object");
+   return_STR("Invalid object");
}
 
return_STR(acpi_ut_get_type_name(obj_desc->common.type));
diff --git a/drivers/acpi/acpica/utdelete.c b/drivers/acpi/acpica/utdelete.c
index 529d6c3..5cdd707 100644
--- a/drivers/acpi/acpica/utdelete.c
+++ b/drivers/acpi/acpica/utdelete.c
@@ -421,8 +421,10 @@ acpi_ut_update_ref_count(union acpi_operand_object 
*object, u32 action)
}
 
ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS,
- "Obj %p Type %.2X Refs %.2X [Incremented]\n",
- object, object->common.type, new_count));
+ "Obj %p Type %.2X [%s] Refs %.2X 
[Incremented]\n",
+ object, object->common.type,
+ acpi_ut_get_object_type_name(object),
+ new_count));
break;
 
case REF_DECREMENT:
-- 
2.7.4



[PATCH 10/18] ACPICA: EFI: Add efihello demo application

2016-12-27 Thread Lv Zheng
ACPICA commit 3fcc59f4755607dd066ac8ef869f0aa95e871b84

This patch adds a demo EFI application for stdin/stdout testing. This
utility can be used to narrow down root causes of porting issues. Lv Zheng.

Linux is not affected by this patch.

Link: https://github.com/acpica/acpica/commit/3fcc59f4
Signed-off-by: Lv Zheng 
Signed-off-by: Bob Moore 
---
 include/acpi/platform/acenv.h | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/include/acpi/platform/acenv.h b/include/acpi/platform/acenv.h
index cf93b66..926efe9 100644
--- a/include/acpi/platform/acenv.h
+++ b/include/acpi/platform/acenv.h
@@ -75,7 +75,8 @@
(defined ACPI_NAMES_APP)|| \
(defined ACPI_SRC_APP)  || \
(defined ACPI_XTRACT_APP)   || \
-   (defined ACPI_EXAMPLE_APP)
+   (defined ACPI_EXAMPLE_APP)  || \
+   (defined ACPI_EFI_HELLO)
 #define ACPI_APPLICATION
 #define ACPI_SINGLE_THREADED
 #define USE_NATIVE_ALLOCATE_ZEROED
-- 
2.7.4



[PATCH 11/18] ACPICA: Disassembler: Add Switch/Case disassembly support

2016-12-27 Thread Lv Zheng
From: "David E. Box" 

ACPICA commit 0f6cc80e8af519a3c31184367b0a9be7a399cf53

iasl compiles Switch/Case statements into a single iteration While
loop with If/Else statements. This patch adds support to recognize
this generated compiler output and disassemble it back to the original
Switch statement.

Linux kernel is not affected by this patch.

Link: https://github.com/acpica/acpica/commit/0f6cc80e
Signed-off-by: David E. Box 
Signed-off-by: Bob Moore 
Signed-off-by: Lv Zheng 
---
 drivers/acpi/acpica/aclocal.h | 7 +--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h
index 7926600..7b97801 100644
--- a/drivers/acpi/acpica/aclocal.h
+++ b/drivers/acpi/acpica/aclocal.h
@@ -770,7 +770,7 @@ union acpi_parse_value {
char*operator_symbol;/* Used for C-style 
operator name strings */\
charaml_op_name[16])/* Op name 
(debug only) */
 
-/* Flags for disasm_flags field above */
+/* Internal opcodes for disasm_opcode field above */
 
 #define ACPI_DASM_BUFFER0x00   /* Buffer is a simple data 
buffer */
 #define ACPI_DASM_RESOURCE  0x01   /* Buffer is a Resource 
Descriptor */
@@ -783,7 +783,10 @@ union acpi_parse_value {
 #define ACPI_DASM_LNOT_PREFIX   0x08   /* Start of a Lnot_equal (etc.) 
pair of opcodes */
 #define ACPI_DASM_LNOT_SUFFIX   0x09   /* End  of a Lnot_equal (etc.) 
pair of opcodes */
 #define ACPI_DASM_HID_STRING0x0A   /* String is a _HID or _CID */
-#define ACPI_DASM_IGNORE0x0B   /* Not used at this time */
+#define ACPI_DASM_IGNORE_SINGLE 0x0B   /* Ignore the opcode but not 
it's children */
+#define ACPI_DASM_SWITCH_PREDICATE  0x0C   /* Object is a predicate for a 
Switch or Case block */
+#define ACPI_DASM_CASE  0x0D   /* If/Else is a Case in a 
Switch/Case block */
+#define ACPI_DASM_DEFAULT   0x0E   /* Else is a Default in a 
Switch/Case block */
 
 /*
  * Generic operation (for example:  If, While, Store)
-- 
2.7.4



[PATCH] ACPI / OSL: Fix a regression by returning table size via acpi_get_table_with_size()

2016-12-08 Thread Lv Zheng
The returned size is still used by the drivers.

Reported-by: Dan Williams 
Cc: Dan Williams 
Signed-off-by: Lv Zheng 
---
 drivers/acpi/osl.c |8 ++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 5bef0f65..adf1ec4 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -445,8 +445,12 @@ void __ref acpi_os_unmap_memory(void *virt, acpi_size size)
 
status = acpi_get_table(signature, instance, out_table);
if (ACPI_SUCCESS(status)) {
-   /* No longer used by early_acpi_os_unmap_memory() */
-   *tbl_size = 0;
+   /*
+* No longer used by early_acpi_os_unmap_memory(), but still
+* used by the ACPI table drivers.
+*/
+   if (*out_table)
+   *tbl_size = (*out_table)->length;
}
 
return (status);
-- 
1.7.10



  1   2   3   4   5   6   7   8   9   10   >