Merge branches 'acpi-ec' and 'acpi-button'
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>
Fri, 5 Aug 2016 14:04:49 +0000 (16:04 +0200)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Fri, 5 Aug 2016 14:04:49 +0000 (16:04 +0200)
* acpi-ec:
  ACPI / EC: Work around method reentrancy limit in ACPICA for _Qxx

* acpi-button:
  ACPI / button: remove pointer to old lid_sysfs on unbind

drivers/acpi/button.c
drivers/acpi/ec.c

index 148f4e5..31abb0b 100644 (file)
@@ -232,8 +232,10 @@ remove_dev_dir:
        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;
 }
 
@@ -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;
 }
index 999a109..e7bd57c 100644 (file)
@@ -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 */
@@ -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");
@@ -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 */
@@ -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;
        }
@@ -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;
 }
 
@@ -1678,5 +1710,6 @@ static void __exit acpi_ec_exit(void)
 {
 
        acpi_bus_unregister_driver(&acpi_ec_driver);
+       acpi_ec_query_exit();
 }
 #endif /* 0 */