Skip to content

Commit 0524b42

Browse files
committed
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
2 parents 11d8ec4 + 4dc14b3 commit 0524b42

File tree

2 files changed

+41
-4
lines changed

2 files changed

+41
-4
lines changed

drivers/acpi/button.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,8 +232,10 @@ static int acpi_button_add_fs(struct acpi_device *device)
232232
acpi_device_dir(device) = NULL;
233233
remove_lid_dir:
234234
remove_proc_entry(ACPI_BUTTON_SUBCLASS_LID, acpi_button_dir);
235+
acpi_lid_dir = NULL;
235236
remove_button_dir:
236237
remove_proc_entry(ACPI_BUTTON_CLASS, acpi_root_dir);
238+
acpi_button_dir = NULL;
237239
goto done;
238240
}
239241

@@ -250,7 +252,9 @@ static int acpi_button_remove_fs(struct acpi_device *device)
250252
acpi_lid_dir);
251253
acpi_device_dir(device) = NULL;
252254
remove_proc_entry(ACPI_BUTTON_SUBCLASS_LID, acpi_button_dir);
255+
acpi_lid_dir = NULL;
253256
remove_proc_entry(ACPI_BUTTON_CLASS, acpi_root_dir);
257+
acpi_button_dir = NULL;
254258

255259
return 0;
256260
}

drivers/acpi/ec.c

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ enum ec_command {
101101
#define ACPI_EC_UDELAY_POLL 550 /* Wait 1ms for EC transaction polling */
102102
#define ACPI_EC_CLEAR_MAX 100 /* Maximum number of events to query
103103
* when trying to clear the EC */
104+
#define ACPI_EC_MAX_QUERIES 16 /* Maximum number of parallel queries */
104105

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

125+
static unsigned int ec_max_queries __read_mostly = ACPI_EC_MAX_QUERIES;
126+
module_param(ec_max_queries, uint, 0644);
127+
MODULE_PARM_DESC(ec_max_queries, "Maximum parallel _Qxx evaluations");
128+
124129
static bool ec_busy_polling __read_mostly;
125130
module_param(ec_busy_polling, bool, 0644);
126131
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);
174179

175180
struct acpi_ec *boot_ec, *first_ec;
176181
EXPORT_SYMBOL(first_ec);
182+
static struct workqueue_struct *ec_query_wq;
177183

178184
static int EC_FLAGS_CLEAR_ON_RESUME; /* Needs acpi_ec_clear() on boot/resume */
179185
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)
10981104
* work queue execution.
10991105
*/
11001106
ec_dbg_evt("Query(0x%02x) scheduled", value);
1101-
if (!schedule_work(&q->work)) {
1107+
if (!queue_work(ec_query_wq, &q->work)) {
11021108
ec_dbg_evt("Query(0x%02x) overlapped", value);
11031109
result = -EBUSY;
11041110
}
@@ -1660,15 +1666,41 @@ static struct acpi_driver acpi_ec_driver = {
16601666
},
16611667
};
16621668

1669+
static inline int acpi_ec_query_init(void)
1670+
{
1671+
if (!ec_query_wq) {
1672+
ec_query_wq = alloc_workqueue("kec_query", 0,
1673+
ec_max_queries);
1674+
if (!ec_query_wq)
1675+
return -ENODEV;
1676+
}
1677+
return 0;
1678+
}
1679+
1680+
static inline void acpi_ec_query_exit(void)
1681+
{
1682+
if (ec_query_wq) {
1683+
destroy_workqueue(ec_query_wq);
1684+
ec_query_wq = NULL;
1685+
}
1686+
}
1687+
16631688
int __init acpi_ec_init(void)
16641689
{
1665-
int result = 0;
1690+
int result;
16661691

1692+
/* register workqueue for _Qxx evaluations */
1693+
result = acpi_ec_query_init();
1694+
if (result)
1695+
goto err_exit;
16671696
/* Now register the driver for the EC */
16681697
result = acpi_bus_register_driver(&acpi_ec_driver);
1669-
if (result < 0)
1670-
return -ENODEV;
1698+
if (result)
1699+
goto err_exit;
16711700

1701+
err_exit:
1702+
if (result)
1703+
acpi_ec_query_exit();
16721704
return result;
16731705
}
16741706

@@ -1678,5 +1710,6 @@ static void __exit acpi_ec_exit(void)
16781710
{
16791711

16801712
acpi_bus_unregister_driver(&acpi_ec_driver);
1713+
acpi_ec_query_exit();
16811714
}
16821715
#endif /* 0 */

0 commit comments

Comments
 (0)