Commit 0524b422 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'acpi-extra-4.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm

Pull more ACPI updates from Rafael Wysocki:
 "Two more fixes in ACPI drivers, one in the ACPI EC driver
  (stable-candidate) and one in the ACPI button driver.

  Specifics:

   - An ACPI EC driver fix from the 4.3 cycle may cause the ACPICA's
     method reentrancy limit to be exceeded for a _Qxx method due to a
     large number of concurrent EC operations, so prevent that from
     happening by moving the EC handling into a separate workqueue with
     a limit on the number of concurrently executed work items (Lv
     Zheng)

   - Fix the cleanup code in the ACPI button driver that forgets to
     clear two variables on exit which causes an error to occur on the
     next attmpt to load the driver (Benjamin Tissoires)"

* tag 'acpi-extra-4.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm:
  ACPI / EC: Work around method reentrancy limit in ACPICA for _Qxx
  ACPI / button: remove pointer to old lid_sysfs on unbind
parents 11d8ec40 4dc14b34
...@@ -232,8 +232,10 @@ static int acpi_button_add_fs(struct acpi_device *device) ...@@ -232,8 +232,10 @@ static int acpi_button_add_fs(struct acpi_device *device)
acpi_device_dir(device) = NULL; acpi_device_dir(device) = NULL;
remove_lid_dir: remove_lid_dir:
remove_proc_entry(ACPI_BUTTON_SUBCLASS_LID, acpi_button_dir); remove_proc_entry(ACPI_BUTTON_SUBCLASS_LID, acpi_button_dir);
acpi_lid_dir = NULL;
remove_button_dir: remove_button_dir:
remove_proc_entry(ACPI_BUTTON_CLASS, acpi_root_dir); remove_proc_entry(ACPI_BUTTON_CLASS, acpi_root_dir);
acpi_button_dir = NULL;
goto done; goto done;
} }
...@@ -250,7 +252,9 @@ static int acpi_button_remove_fs(struct acpi_device *device) ...@@ -250,7 +252,9 @@ static int acpi_button_remove_fs(struct acpi_device *device)
acpi_lid_dir); acpi_lid_dir);
acpi_device_dir(device) = NULL; acpi_device_dir(device) = NULL;
remove_proc_entry(ACPI_BUTTON_SUBCLASS_LID, acpi_button_dir); remove_proc_entry(ACPI_BUTTON_SUBCLASS_LID, acpi_button_dir);
acpi_lid_dir = NULL;
remove_proc_entry(ACPI_BUTTON_CLASS, acpi_root_dir); remove_proc_entry(ACPI_BUTTON_CLASS, acpi_root_dir);
acpi_button_dir = NULL;
return 0; return 0;
} }
......
...@@ -101,6 +101,7 @@ enum ec_command { ...@@ -101,6 +101,7 @@ enum ec_command {
#define ACPI_EC_UDELAY_POLL 550 /* Wait 1ms for EC transaction polling */ #define ACPI_EC_UDELAY_POLL 550 /* Wait 1ms for EC transaction polling */
#define ACPI_EC_CLEAR_MAX 100 /* Maximum number of events to query #define ACPI_EC_CLEAR_MAX 100 /* Maximum number of events to query
* when trying to clear the EC */ * when trying to clear the EC */
#define ACPI_EC_MAX_QUERIES 16 /* Maximum number of parallel queries */
enum { enum {
EC_FLAGS_QUERY_PENDING, /* Query is pending */ EC_FLAGS_QUERY_PENDING, /* Query is pending */
...@@ -121,6 +122,10 @@ static unsigned int ec_delay __read_mostly = ACPI_EC_DELAY; ...@@ -121,6 +122,10 @@ static unsigned int ec_delay __read_mostly = ACPI_EC_DELAY;
module_param(ec_delay, uint, 0644); module_param(ec_delay, uint, 0644);
MODULE_PARM_DESC(ec_delay, "Timeout(ms) waited until an EC command completes"); MODULE_PARM_DESC(ec_delay, "Timeout(ms) waited until an EC command completes");
static unsigned int ec_max_queries __read_mostly = ACPI_EC_MAX_QUERIES;
module_param(ec_max_queries, uint, 0644);
MODULE_PARM_DESC(ec_max_queries, "Maximum parallel _Qxx evaluations");
static bool ec_busy_polling __read_mostly; static bool ec_busy_polling __read_mostly;
module_param(ec_busy_polling, bool, 0644); module_param(ec_busy_polling, bool, 0644);
MODULE_PARM_DESC(ec_busy_polling, "Use busy polling to advance EC transaction"); MODULE_PARM_DESC(ec_busy_polling, "Use busy polling to advance EC transaction");
...@@ -174,6 +179,7 @@ static void acpi_ec_event_processor(struct work_struct *work); ...@@ -174,6 +179,7 @@ static void acpi_ec_event_processor(struct work_struct *work);
struct acpi_ec *boot_ec, *first_ec; struct acpi_ec *boot_ec, *first_ec;
EXPORT_SYMBOL(first_ec); EXPORT_SYMBOL(first_ec);
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_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 */
...@@ -1098,7 +1104,7 @@ static int acpi_ec_query(struct acpi_ec *ec, u8 *data) ...@@ -1098,7 +1104,7 @@ static int acpi_ec_query(struct acpi_ec *ec, u8 *data)
* work queue execution. * work queue execution.
*/ */
ec_dbg_evt("Query(0x%02x) scheduled", value); ec_dbg_evt("Query(0x%02x) scheduled", value);
if (!schedule_work(&q->work)) { if (!queue_work(ec_query_wq, &q->work)) {
ec_dbg_evt("Query(0x%02x) overlapped", value); ec_dbg_evt("Query(0x%02x) overlapped", value);
result = -EBUSY; result = -EBUSY;
} }
...@@ -1660,15 +1666,41 @@ static struct acpi_driver acpi_ec_driver = { ...@@ -1660,15 +1666,41 @@ static struct acpi_driver acpi_ec_driver = {
}, },
}; };
static inline int acpi_ec_query_init(void)
{
if (!ec_query_wq) {
ec_query_wq = alloc_workqueue("kec_query", 0,
ec_max_queries);
if (!ec_query_wq)
return -ENODEV;
}
return 0;
}
static inline void acpi_ec_query_exit(void)
{
if (ec_query_wq) {
destroy_workqueue(ec_query_wq);
ec_query_wq = NULL;
}
}
int __init acpi_ec_init(void) int __init acpi_ec_init(void)
{ {
int result = 0; int result;
/* register workqueue for _Qxx evaluations */
result = acpi_ec_query_init();
if (result)
goto err_exit;
/* Now register the driver for the EC */ /* Now register the driver for the EC */
result = acpi_bus_register_driver(&acpi_ec_driver); result = acpi_bus_register_driver(&acpi_ec_driver);
if (result < 0) if (result)
return -ENODEV; goto err_exit;
err_exit:
if (result)
acpi_ec_query_exit();
return result; return result;
} }
...@@ -1678,5 +1710,6 @@ static void __exit acpi_ec_exit(void) ...@@ -1678,5 +1710,6 @@ static void __exit acpi_ec_exit(void)
{ {
acpi_bus_unregister_driver(&acpi_ec_driver); acpi_bus_unregister_driver(&acpi_ec_driver);
acpi_ec_query_exit();
} }
#endif /* 0 */ #endif /* 0 */
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