Skip to contentSkip to conversation

USB: chipidea: fix interrupt deadlock

PATCH In review Johan Hovold 2 participants 2 messages Nov 15, 2021

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 USB: chipidea: fix interrupt deadlock

commit 9aaa81c3366e8393a62374e3a1c67c69edc07b8a upstream.

Chipidea core was calling the interrupt handler from non-IRQ context with interrupts enabled, something which can lead to a deadlock if there's an actual interrupt trying to take a lock that's already held (e.g. the controller lock in udc_irq()).

Add a wrapper that can be used to fake interrupts instead of calling the handler directly.

Fixes 3ecb3e09b042 ("usb: chipidea: Use extcon framework for VBUS and ID detect")
Fixes 876d4e1e8298 ("usb: chipidea: core: add wakeup support for extcon")
Cc Peter Chen <[email protected]>
[ johan: backport to 4.9; adjust context ]

---

This one should apply to 4.4 as well.

Johan

 drivers/usb/chipidea/core.c | 21 +++++++++++++++------
 1 file changed, 15 insertions(+), 6 deletions(-)
drivers/usb/chipidea/core.c +15 -6
index 6062a5d816a6..f4b13f0637ea 100644
@@ -516,7 +516,7 @@ int hw_device_reset(struct ci_hdrc *ci)
 	return 0;
 }
 
-static irqreturn_t ci_irq(int irq, void *data)
+static irqreturn_t ci_irq_handler(int irq, void *data)
 {
 	struct ci_hdrc *ci = data;
 	irqreturn_t ret = IRQ_NONE;
@@ -569,6 +569,15 @@ static irqreturn_t ci_irq(int irq, void *data)
 	return ret;
 }
 
+static void ci_irq(struct ci_hdrc *ci)
+{
+	unsigned long flags;
+
+	local_irq_save(flags);
+	ci_irq_handler(ci->irq, ci);
+	local_irq_restore(flags);
+}
+
 static int ci_vbus_notifier(struct notifier_block *nb, unsigned long event,
 			    void *ptr)
 {
@@ -582,7 +591,7 @@ static int ci_vbus_notifier(struct notifier_block *nb, unsigned long event,
 
 	vbus->changed = true;
 
-	ci_irq(ci->irq, ci);
+	ci_irq(ci);
 	return NOTIFY_DONE;
 }
 
@@ -599,7 +608,7 @@ static int ci_id_notifier(struct notifier_block *nb, unsigned long event,
 
 	id->changed = true;
 
-	ci_irq(ci->irq, ci);
+	ci_irq(ci);
 	return NOTIFY_DONE;
 }
 
@@ -1011,7 +1020,7 @@ static int ci_hdrc_probe(struct platform_device *pdev)
 	}
 
 	platform_set_drvdata(pdev, ci);
-	ret = devm_request_irq(dev, ci->irq, ci_irq, IRQF_SHARED,
+	ret = devm_request_irq(dev, ci->irq, ci_irq_handler, IRQF_SHARED,
 			ci->platdata->name, ci);
 	if (ret)
 		goto stop;
@@ -1126,11 +1135,11 @@ static void ci_extcon_wakeup_int(struct ci_hdrc *ci)
 
 	if (!IS_ERR(cable_id->edev) && ci->is_otg &&
 		(otgsc & OTGSC_IDIE) && (otgsc & OTGSC_IDIS))
-		ci_irq(ci->irq, ci);
+		ci_irq(ci);
 
 	if (!IS_ERR(cable_vbus->edev) && ci->is_otg &&
 		(otgsc & OTGSC_BSVIE) && (otgsc & OTGSC_BSVIS))
-		ci_irq(ci->irq, ci);
+		ci_irq(ci);
 }
 
 static int ci_controller_resume(struct device *dev)
Signature · 1 line
2.32.0
#1 lore raw
Quoted 19 lines · Johan Hovold

commit 9aaa81c3366e8393a62374e3a1c67c69edc07b8a upstream.

Chipidea core was calling the interrupt handler from non-IRQ context with interrupts enabled, something which can lead to a deadlock if there's an actual interrupt trying to take a lock that's already held (e.g. the controller lock in udc_irq()).

Add a wrapper that can be used to fake interrupts instead of calling the handler directly.

Fixes 3ecb3e09b042 ("usb: chipidea: Use extcon framework for VBUS and ID detect")
Fixes 876d4e1e8298 ("usb: chipidea: core: add wakeup support for extcon")
Cc Peter Chen <[email protected]>
[ johan: backport to 4.9; adjust context ]
Quoted 3 lines

---

This one should apply to 4.4 as well.

All now queued up, thanks.

greg k-h