[PATCH] extcon: sm5502: synchronize work teardown

Hongyan Xu posted 1 patch 5 days, 12 hours ago
drivers/extcon/extcon-sm5502.c | 45 ++++++++++++++++++++--------------
1 file changed, 26 insertions(+), 19 deletions(-)
[PATCH] extcon: sm5502: synchronize work teardown
Posted by Hongyan Xu 5 days, 12 hours ago
Nested IRQ handlers schedule irq_work and probe queues wq_detcable.
Neither work item is cancelled when probe unwinds or the I2C device is
detached, so devres can release info while a callback is pending.

Register automatic work cancellation before requesting the nested IRQs.
Reverse-order devres teardown then frees all IRQ producers before
cancelling the work and releasing its dependencies.

Signed-off-by: Hongyan Xu <getshell@seu.edu.cn>
---
 drivers/extcon/extcon-sm5502.c | 45 ++++++++++++++++++++--------------
 1 file changed, 26 insertions(+), 19 deletions(-)

diff --git a/drivers/extcon/extcon-sm5502.c b/drivers/extcon/extcon-sm5502.c
index c8c4b9e..50e6783 100644
--- a/drivers/extcon/extcon-sm5502.c
+++ b/drivers/extcon/extcon-sm5502.c
@@ -6,6 +6,7 @@
  * Author: Chanwoo Choi <cw00.choi@samsung.com>
  */
 
+#include <linux/devm-helpers.h>
 #include <linux/err.h>
 #include <linux/i2c.h>
 #include <linux/interrupt.h>
@@ -699,8 +700,6 @@ static int sm5022_muic_i2c_probe(struct i2c_client *i2c)
 
 	mutex_init(&info->mutex);
 
-	INIT_WORK(&info->irq_work, sm5502_muic_irq_work);
-
 	info->regmap = devm_regmap_init_i2c(i2c, &sm5502_muic_regmap_config);
 	if (IS_ERR(info->regmap)) {
 		ret = PTR_ERR(info->regmap);
@@ -720,6 +719,29 @@ static int sm5022_muic_i2c_probe(struct i2c_client *i2c)
 		return ret;
 	}
 
+	/* Allocate extcon device */
+	info->edev = devm_extcon_dev_allocate(info->dev, sm5502_extcon_cable);
+	if (IS_ERR(info->edev)) {
+		dev_err(info->dev, "failed to allocate memory for extcon\n");
+		return -ENOMEM;
+	}
+
+	/* Register extcon device */
+	ret = devm_extcon_dev_register(info->dev, info->edev);
+	if (ret) {
+		dev_err(info->dev, "failed to register extcon device\n");
+		return ret;
+	}
+
+	ret = devm_work_autocancel(info->dev, &info->irq_work,
+				   sm5502_muic_irq_work);
+	if (ret)
+		return ret;
+	ret = devm_delayed_work_autocancel(info->dev, &info->wq_detcable,
+					   sm5502_muic_detect_cable_wq);
+	if (ret)
+		return ret;
+
 	for (i = 0; i < info->type->num_muic_irqs; i++) {
 		struct muic_irq *muic_irq = &info->type->muic_irqs[i];
 		int virq = 0;
@@ -741,19 +763,8 @@ static int sm5022_muic_i2c_probe(struct i2c_client *i2c)
 		}
 	}
 
-	/* Allocate extcon device */
-	info->edev = devm_extcon_dev_allocate(info->dev, sm5502_extcon_cable);
-	if (IS_ERR(info->edev)) {
-		dev_err(info->dev, "failed to allocate memory for extcon\n");
-		return -ENOMEM;
-	}
-
-	/* Register extcon device */
-	ret = devm_extcon_dev_register(info->dev, info->edev);
-	if (ret) {
-		dev_err(info->dev, "failed to register extcon device\n");
-		return ret;
-	}
+	/* Initialize SM5502 device and print vendor id and version id */
+	sm5502_init_dev_type(info);
 
 	/*
 	 * Detect accessory after completing the initialization of platform
@@ -763,13 +774,9 @@ static int sm5022_muic_i2c_probe(struct i2c_client *i2c)
 	 * After completing the booting of platform, the extcon provider
 	 * driver should notify cable state to upper layer.
 	 */
-	INIT_DELAYED_WORK(&info->wq_detcable, sm5502_muic_detect_cable_wq);
 	queue_delayed_work(system_power_efficient_wq, &info->wq_detcable,
 			msecs_to_jiffies(DELAY_MS_DEFAULT));
 
-	/* Initialize SM5502 device and print vendor id and version id */
-	sm5502_init_dev_type(info);
-
 	return 0;
 }
 
-- 
2.50.1.windows.1