Commit ac18c0c4 authored by Rafael J. Wysocki's avatar Rafael J. Wysocki

Merge branches 'acpi-ec', 'acpi-button' and 'acpi-apei'

* acpi-ec:
  ACPI / EC: Use busy polling mode when GPE is not enabled
  ACPI / EC: Remove old CLEAR_ON_RESUME quirk

* acpi-button:
  ACPI / button: Remove lid_init_state=method mode
  ACPI / button: Change default behavior to lid_init_state=open

* acpi-apei:
  ACPI, APEI, EINJ: fix malformed newline escape
...@@ -59,28 +59,20 @@ button driver uses the following 3 modes in order not to trigger issues. ...@@ -59,28 +59,20 @@ button driver uses the following 3 modes in order not to trigger issues.
If the userspace hasn't been prepared to ignore the unreliable "opened" If the userspace hasn't been prepared to ignore the unreliable "opened"
events and the unreliable initial state notification, Linux users can use events and the unreliable initial state notification, Linux users can use
the following kernel parameters to handle the possible issues: the following kernel parameters to handle the possible issues:
A. button.lid_init_state=method: A. button.lid_init_state=open:
When this option is specified, the ACPI button driver reports the
initial lid state using the returning value of the _LID control method
and whether the "opened"/"closed" events are paired fully relies on the
firmware implementation.
This option can be used to fix some platforms where the returning value
of the _LID control method is reliable but the initial lid state
notification is missing.
This option is the default behavior during the period the userspace
isn't ready to handle the buggy AML tables.
B. button.lid_init_state=open:
When this option is specified, the ACPI button driver always reports the When this option is specified, the ACPI button driver always reports the
initial lid state as "opened" and whether the "opened"/"closed" events initial lid state as "opened" and whether the "opened"/"closed" events
are paired fully relies on the firmware implementation. are paired fully relies on the firmware implementation.
This may fix some platforms where the returning value of the _LID This may fix some platforms where the returning value of the _LID
control method is not reliable and the initial lid state notification is control method is not reliable and the initial lid state notification is
missing. missing.
This option is the default behavior during the period the userspace
isn't ready to handle the buggy AML tables.
If the userspace has been prepared to ignore the unreliable "opened" events If the userspace has been prepared to ignore the unreliable "opened" events
and the unreliable initial state notification, Linux users should always and the unreliable initial state notification, Linux users should always
use the following kernel parameter: use the following kernel parameter:
C. button.lid_init_state=ignore: B. button.lid_init_state=ignore:
When this option is specified, the ACPI button driver never reports the When this option is specified, the ACPI button driver never reports the
initial lid state and there is a compensation mechanism implemented to initial lid state and there is a compensation mechanism implemented to
ensure that the reliable "closed" notifications can always be delievered ensure that the reliable "closed" notifications can always be delievered
......
...@@ -711,7 +711,7 @@ static int __init einj_init(void) ...@@ -711,7 +711,7 @@ static int __init einj_init(void)
rc = einj_check_table(einj_tab); rc = einj_check_table(einj_tab);
if (rc) { if (rc) {
pr_warn(FW_BUG "Invalid EINJ table.n"); pr_warn(FW_BUG "Invalid EINJ table.\n");
return -EINVAL; return -EINVAL;
} }
......
...@@ -57,7 +57,6 @@ ...@@ -57,7 +57,6 @@
#define ACPI_BUTTON_LID_INIT_IGNORE 0x00 #define ACPI_BUTTON_LID_INIT_IGNORE 0x00
#define ACPI_BUTTON_LID_INIT_OPEN 0x01 #define ACPI_BUTTON_LID_INIT_OPEN 0x01
#define ACPI_BUTTON_LID_INIT_METHOD 0x02
#define _COMPONENT ACPI_BUTTON_COMPONENT #define _COMPONENT ACPI_BUTTON_COMPONENT
ACPI_MODULE_NAME("button"); ACPI_MODULE_NAME("button");
...@@ -113,7 +112,7 @@ struct acpi_button { ...@@ -113,7 +112,7 @@ struct acpi_button {
static BLOCKING_NOTIFIER_HEAD(acpi_lid_notifier); static BLOCKING_NOTIFIER_HEAD(acpi_lid_notifier);
static struct acpi_device *lid_device; static struct acpi_device *lid_device;
static u8 lid_init_state = ACPI_BUTTON_LID_INIT_METHOD; static u8 lid_init_state = ACPI_BUTTON_LID_INIT_OPEN;
static unsigned long lid_report_interval __read_mostly = 500; static unsigned long lid_report_interval __read_mostly = 500;
module_param(lid_report_interval, ulong, 0644); module_param(lid_report_interval, ulong, 0644);
...@@ -377,9 +376,6 @@ static void acpi_lid_initialize_state(struct acpi_device *device) ...@@ -377,9 +376,6 @@ static void acpi_lid_initialize_state(struct acpi_device *device)
case ACPI_BUTTON_LID_INIT_OPEN: case ACPI_BUTTON_LID_INIT_OPEN:
(void)acpi_lid_notify_state(device, 1); (void)acpi_lid_notify_state(device, 1);
break; break;
case ACPI_BUTTON_LID_INIT_METHOD:
(void)acpi_lid_update_state(device);
break;
case ACPI_BUTTON_LID_INIT_IGNORE: case ACPI_BUTTON_LID_INIT_IGNORE:
default: default:
break; break;
...@@ -563,9 +559,6 @@ static int param_set_lid_init_state(const char *val, struct kernel_param *kp) ...@@ -563,9 +559,6 @@ static int param_set_lid_init_state(const char *val, struct kernel_param *kp)
if (!strncmp(val, "open", sizeof("open") - 1)) { if (!strncmp(val, "open", sizeof("open") - 1)) {
lid_init_state = ACPI_BUTTON_LID_INIT_OPEN; lid_init_state = ACPI_BUTTON_LID_INIT_OPEN;
pr_info("Notify initial lid state as open\n"); pr_info("Notify initial lid state as open\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");
} else if (!strncmp(val, "ignore", sizeof("ignore") - 1)) { } else if (!strncmp(val, "ignore", sizeof("ignore") - 1)) {
lid_init_state = ACPI_BUTTON_LID_INIT_IGNORE; lid_init_state = ACPI_BUTTON_LID_INIT_IGNORE;
pr_info("Do not notify initial lid state\n"); pr_info("Do not notify initial lid state\n");
...@@ -579,8 +572,6 @@ static int param_get_lid_init_state(char *buffer, struct kernel_param *kp) ...@@ -579,8 +572,6 @@ static int param_get_lid_init_state(char *buffer, struct kernel_param *kp)
switch (lid_init_state) { switch (lid_init_state) {
case ACPI_BUTTON_LID_INIT_OPEN: case ACPI_BUTTON_LID_INIT_OPEN:
return sprintf(buffer, "open"); return sprintf(buffer, "open");
case ACPI_BUTTON_LID_INIT_METHOD:
return sprintf(buffer, "method");
case ACPI_BUTTON_LID_INIT_IGNORE: case ACPI_BUTTON_LID_INIT_IGNORE:
return sprintf(buffer, "ignore"); return sprintf(buffer, "ignore");
default: default:
......
...@@ -188,7 +188,6 @@ EXPORT_SYMBOL(first_ec); ...@@ -188,7 +188,6 @@ EXPORT_SYMBOL(first_ec);
static bool boot_ec_is_ecdt = false; static bool boot_ec_is_ecdt = false;
static struct workqueue_struct *ec_query_wq; 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_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_CORRECT_ECDT; /* Needs ECDT port address correction */
...@@ -492,26 +491,6 @@ static inline void __acpi_ec_disable_event(struct acpi_ec *ec) ...@@ -492,26 +491,6 @@ static inline void __acpi_ec_disable_event(struct acpi_ec *ec)
ec_log_drv("event blocked"); 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) static void acpi_ec_enable_event(struct acpi_ec *ec)
{ {
unsigned long flags; unsigned long flags;
...@@ -520,10 +499,6 @@ static void acpi_ec_enable_event(struct acpi_ec *ec) ...@@ -520,10 +499,6 @@ static void acpi_ec_enable_event(struct acpi_ec *ec)
if (acpi_ec_started(ec)) if (acpi_ec_started(ec))
__acpi_ec_enable_event(ec); __acpi_ec_enable_event(ec);
spin_unlock_irqrestore(&ec->lock, flags); 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 #ifdef CONFIG_PM_SLEEP
...@@ -729,12 +704,12 @@ static void start_transaction(struct acpi_ec *ec) ...@@ -729,12 +704,12 @@ static void start_transaction(struct acpi_ec *ec)
static int ec_guard(struct acpi_ec *ec) static int ec_guard(struct acpi_ec *ec)
{ {
unsigned long guard = usecs_to_jiffies(ec_polling_guard); unsigned long guard = usecs_to_jiffies(ec->polling_guard);
unsigned long timeout = ec->timestamp + guard; unsigned long timeout = ec->timestamp + guard;
/* Ensure guarding period before polling EC status */ /* Ensure guarding period before polling EC status */
do { do {
if (ec_busy_polling) { if (ec->busy_polling) {
/* Perform busy polling */ /* Perform busy polling */
if (ec_transaction_completed(ec)) if (ec_transaction_completed(ec))
return 0; return 0;
...@@ -998,6 +973,28 @@ static void acpi_ec_stop(struct acpi_ec *ec, bool suspending) ...@@ -998,6 +973,28 @@ static void acpi_ec_stop(struct acpi_ec *ec, bool suspending)
spin_unlock_irqrestore(&ec->lock, flags); spin_unlock_irqrestore(&ec->lock, flags);
} }
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");
spin_unlock_irqrestore(&ec->lock, flags);
}
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");
spin_unlock_irqrestore(&ec->lock, flags);
}
void acpi_ec_block_transactions(void) void acpi_ec_block_transactions(void)
{ {
struct acpi_ec *ec = first_ec; struct acpi_ec *ec = first_ec;
...@@ -1278,7 +1275,7 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address, ...@@ -1278,7 +1275,7 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address,
if (function != ACPI_READ && function != ACPI_WRITE) if (function != ACPI_READ && function != ACPI_WRITE)
return AE_BAD_PARAMETER; return AE_BAD_PARAMETER;
if (ec_busy_polling || bits > 8) if (ec->busy_polling || bits > 8)
acpi_ec_burst_enable(ec); acpi_ec_burst_enable(ec);
for (i = 0; i < bytes; ++i, ++address, ++value) for (i = 0; i < bytes; ++i, ++address, ++value)
...@@ -1286,7 +1283,7 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address, ...@@ -1286,7 +1283,7 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address,
acpi_ec_read(ec, address, value) : acpi_ec_read(ec, address, value) :
acpi_ec_write(ec, address, *value); acpi_ec_write(ec, address, *value);
if (ec_busy_polling || bits > 8) if (ec->busy_polling || bits > 8)
acpi_ec_burst_disable(ec); acpi_ec_burst_disable(ec);
switch (result) { switch (result) {
...@@ -1329,6 +1326,8 @@ static struct acpi_ec *acpi_ec_alloc(void) ...@@ -1329,6 +1326,8 @@ static struct acpi_ec *acpi_ec_alloc(void)
spin_lock_init(&ec->lock); spin_lock_init(&ec->lock);
INIT_WORK(&ec->work, acpi_ec_event_handler); INIT_WORK(&ec->work, acpi_ec_event_handler);
ec->timestamp = jiffies; ec->timestamp = jiffies;
ec->busy_polling = true;
ec->polling_guard = 0;
return ec; return ec;
} }
...@@ -1390,6 +1389,7 @@ static int ec_install_handlers(struct acpi_ec *ec, bool handle_events) ...@@ -1390,6 +1389,7 @@ static int ec_install_handlers(struct acpi_ec *ec, bool handle_events)
acpi_ec_start(ec, false); acpi_ec_start(ec, false);
if (!test_bit(EC_FLAGS_EC_HANDLER_INSTALLED, &ec->flags)) { if (!test_bit(EC_FLAGS_EC_HANDLER_INSTALLED, &ec->flags)) {
acpi_ec_enter_noirq(ec);
status = acpi_install_address_space_handler(ec->handle, status = acpi_install_address_space_handler(ec->handle,
ACPI_ADR_SPACE_EC, ACPI_ADR_SPACE_EC,
&acpi_ec_space_handler, &acpi_ec_space_handler,
...@@ -1429,6 +1429,7 @@ static int ec_install_handlers(struct acpi_ec *ec, bool handle_events) ...@@ -1429,6 +1429,7 @@ static int ec_install_handlers(struct acpi_ec *ec, bool handle_events)
/* This is not fatal as we can poll EC events */ /* This is not fatal as we can poll EC events */
if (ACPI_SUCCESS(status)) { if (ACPI_SUCCESS(status)) {
set_bit(EC_FLAGS_GPE_HANDLER_INSTALLED, &ec->flags); set_bit(EC_FLAGS_GPE_HANDLER_INSTALLED, &ec->flags);
acpi_ec_leave_noirq(ec);
if (test_bit(EC_FLAGS_STARTED, &ec->flags) && if (test_bit(EC_FLAGS_STARTED, &ec->flags) &&
ec->reference_count >= 1) ec->reference_count >= 1)
acpi_ec_enable_gpe(ec, true); acpi_ec_enable_gpe(ec, true);
...@@ -1740,31 +1741,6 @@ static int ec_flag_query_handshake(const struct dmi_system_id *id) ...@@ -1740,31 +1741,6 @@ static int ec_flag_query_handshake(const struct dmi_system_id *id)
} }
#endif #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. * Some ECDTs contain wrong register addresses.
* MSI MS-171F * MSI MS-171F
...@@ -1782,9 +1758,6 @@ static struct dmi_system_id ec_dmi_table[] __initdata = { ...@@ -1782,9 +1758,6 @@ static struct dmi_system_id ec_dmi_table[] __initdata = {
ec_correct_ecdt, "MSI MS-171F", { ec_correct_ecdt, "MSI MS-171F", {
DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star"), DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star"),
DMI_MATCH(DMI_PRODUCT_NAME, "MS-171F"),}, NULL}, DMI_MATCH(DMI_PRODUCT_NAME, "MS-171F"),}, NULL},
{
ec_clear_on_resume, "Samsung hardware", {
DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD.")}, NULL},
{}, {},
}; };
...@@ -1839,34 +1812,6 @@ int __init acpi_ec_ecdt_probe(void) ...@@ -1839,34 +1812,6 @@ int __init acpi_ec_ecdt_probe(void)
} }
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
static void acpi_ec_enter_noirq(struct acpi_ec *ec)
{
unsigned long flags;
if (ec == first_ec) {
spin_lock_irqsave(&ec->lock, flags);
ec->saved_busy_polling = ec_busy_polling;
ec->saved_polling_guard = ec_polling_guard;
ec_busy_polling = true;
ec_polling_guard = 0;
ec_log_drv("interrupt blocked");
spin_unlock_irqrestore(&ec->lock, flags);
}
}
static void acpi_ec_leave_noirq(struct acpi_ec *ec)
{
unsigned long flags;
if (ec == first_ec) {
spin_lock_irqsave(&ec->lock, flags);
ec_busy_polling = ec->saved_busy_polling;
ec_polling_guard = ec->saved_polling_guard;
ec_log_drv("interrupt unblocked");
spin_unlock_irqrestore(&ec->lock, flags);
}
}
static int acpi_ec_suspend_noirq(struct device *dev) static int acpi_ec_suspend_noirq(struct device *dev)
{ {
struct acpi_ec *ec = struct acpi_ec *ec =
......
...@@ -172,8 +172,8 @@ struct acpi_ec { ...@@ -172,8 +172,8 @@ struct acpi_ec {
struct work_struct work; struct work_struct work;
unsigned long timestamp; unsigned long timestamp;
unsigned long nr_pending_queries; unsigned long nr_pending_queries;
bool saved_busy_polling; bool busy_polling;
unsigned int saved_polling_guard; unsigned int polling_guard;
}; };
extern struct acpi_ec *first_ec; extern struct acpi_ec *first_ec;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment