Skip to content

Commit

Permalink
Merge tag 'acpi-extra-4.8-rc1' of git://git.kernel.org/pub/scm/linux/…
Browse files Browse the repository at this point in the history
…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
  • Loading branch information
torvalds committed Aug 6, 2016
2 parents 11d8ec4 + 4dc14b3 commit 0524b42
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 4 deletions.
4 changes: 4 additions & 0 deletions drivers/acpi/button.c
Original file line number Diff line number Diff line change
Expand Up @@ -232,8 +232,10 @@ static int acpi_button_add_fs(struct acpi_device *device)
acpi_device_dir(device) = NULL;
remove_lid_dir:
remove_proc_entry(ACPI_BUTTON_SUBCLASS_LID, acpi_button_dir);
acpi_lid_dir = NULL;
remove_button_dir:
remove_proc_entry(ACPI_BUTTON_CLASS, acpi_root_dir);
acpi_button_dir = NULL;
goto done;
}

Expand All @@ -250,7 +252,9 @@ static int acpi_button_remove_fs(struct acpi_device *device)
acpi_lid_dir);
acpi_device_dir(device) = NULL;
remove_proc_entry(ACPI_BUTTON_SUBCLASS_LID, acpi_button_dir);
acpi_lid_dir = NULL;
remove_proc_entry(ACPI_BUTTON_CLASS, acpi_root_dir);
acpi_button_dir = NULL;

return 0;
}
Expand Down
41 changes: 37 additions & 4 deletions drivers/acpi/ec.c
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ enum ec_command {
#define ACPI_EC_UDELAY_POLL 550 /* Wait 1ms for EC transaction polling */
#define ACPI_EC_CLEAR_MAX 100 /* Maximum number of events to query
* when trying to clear the EC */
#define ACPI_EC_MAX_QUERIES 16 /* Maximum number of parallel queries */

enum {
EC_FLAGS_QUERY_PENDING, /* Query is pending */
Expand All @@ -121,6 +122,10 @@ static unsigned int ec_delay __read_mostly = ACPI_EC_DELAY;
module_param(ec_delay, uint, 0644);
MODULE_PARM_DESC(ec_delay, "Timeout(ms) waited until an EC command completes");

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;
module_param(ec_busy_polling, bool, 0644);
MODULE_PARM_DESC(ec_busy_polling, "Use busy polling to advance EC transaction");
Expand Down Expand Up @@ -174,6 +179,7 @@ static void acpi_ec_event_processor(struct work_struct *work);

struct acpi_ec *boot_ec, *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_QUERY_HANDSHAKE; /* Needs QR_EC issued when SCI_EVT set */
Expand Down Expand Up @@ -1098,7 +1104,7 @@ static int acpi_ec_query(struct acpi_ec *ec, u8 *data)
* work queue execution.
*/
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);
result = -EBUSY;
}
Expand Down Expand Up @@ -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 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 */
result = acpi_bus_register_driver(&acpi_ec_driver);
if (result < 0)
return -ENODEV;
if (result)
goto err_exit;

err_exit:
if (result)
acpi_ec_query_exit();
return result;
}

Expand All @@ -1678,5 +1710,6 @@ static void __exit acpi_ec_exit(void)
{

acpi_bus_unregister_driver(&acpi_ec_driver);
acpi_ec_query_exit();
}
#endif /* 0 */

0 comments on commit 0524b42

Please sign in to comment.