|
Takashi Iwai |
475cb5 |
From 18abf874367456540846319574864e6ff32752e2 Mon Sep 17 00:00:00 2001
|
|
Takashi Iwai |
475cb5 |
From: Oliver Neukum <oneukum@suse.com>
|
|
Takashi Iwai |
475cb5 |
Date: Mon, 26 Apr 2021 11:26:22 +0200
|
|
Takashi Iwai |
475cb5 |
Subject: [PATCH] cdc-wdm: untangle a circular dependency between callback and softint
|
|
Takashi Iwai |
475cb5 |
Git-commit: 18abf874367456540846319574864e6ff32752e2
|
|
Takashi Iwai |
475cb5 |
Patch-mainline: v5.13-rc2
|
|
Takashi Iwai |
475cb5 |
References: git-fixes
|
|
Takashi Iwai |
475cb5 |
|
|
Takashi Iwai |
475cb5 |
We have a cycle of callbacks scheduling works which submit
|
|
Takashi Iwai |
475cb5 |
URBs with those callbacks. This needs to be blocked, stopped
|
|
Takashi Iwai |
475cb5 |
and unblocked to untangle the circle.
|
|
Takashi Iwai |
475cb5 |
|
|
Takashi Iwai |
475cb5 |
Signed-off-by: Oliver Neukum <oneukum@suse.com>
|
|
Takashi Iwai |
475cb5 |
Link: https://lore.kernel.org/r/20210426092622.20433-1-oneukum@suse.com
|
|
Takashi Iwai |
475cb5 |
Cc: stable <stable@vger.kernel.org>
|
|
Takashi Iwai |
475cb5 |
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
|
Takashi Iwai |
475cb5 |
Acked-by: Takashi Iwai <tiwai@suse.de>
|
|
Takashi Iwai |
475cb5 |
|
|
Takashi Iwai |
475cb5 |
---
|
|
Takashi Iwai |
475cb5 |
drivers/usb/class/cdc-wdm.c | 30 ++++++++++++++++++++++--------
|
|
Takashi Iwai |
475cb5 |
1 file changed, 22 insertions(+), 8 deletions(-)
|
|
Takashi Iwai |
475cb5 |
|
|
Takashi Iwai |
475cb5 |
diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c
|
|
Takashi Iwai |
475cb5 |
index 508b1c3f8b73..d1e4a7379beb 100644
|
|
Takashi Iwai |
475cb5 |
--- a/drivers/usb/class/cdc-wdm.c
|
|
Takashi Iwai |
475cb5 |
+++ b/drivers/usb/class/cdc-wdm.c
|
|
Takashi Iwai |
475cb5 |
@@ -321,12 +321,23 @@ static void wdm_int_callback(struct urb *urb)
|
|
Takashi Iwai |
475cb5 |
|
|
Takashi Iwai |
475cb5 |
}
|
|
Takashi Iwai |
475cb5 |
|
|
Takashi Iwai |
475cb5 |
-static void kill_urbs(struct wdm_device *desc)
|
|
Takashi Iwai |
475cb5 |
+static void poison_urbs(struct wdm_device *desc)
|
|
Takashi Iwai |
475cb5 |
{
|
|
Takashi Iwai |
475cb5 |
/* the order here is essential */
|
|
Takashi Iwai |
475cb5 |
- usb_kill_urb(desc->command);
|
|
Takashi Iwai |
475cb5 |
- usb_kill_urb(desc->validity);
|
|
Takashi Iwai |
475cb5 |
- usb_kill_urb(desc->response);
|
|
Takashi Iwai |
475cb5 |
+ usb_poison_urb(desc->command);
|
|
Takashi Iwai |
475cb5 |
+ usb_poison_urb(desc->validity);
|
|
Takashi Iwai |
475cb5 |
+ usb_poison_urb(desc->response);
|
|
Takashi Iwai |
475cb5 |
+}
|
|
Takashi Iwai |
475cb5 |
+
|
|
Takashi Iwai |
475cb5 |
+static void unpoison_urbs(struct wdm_device *desc)
|
|
Takashi Iwai |
475cb5 |
+{
|
|
Takashi Iwai |
475cb5 |
+ /*
|
|
Takashi Iwai |
475cb5 |
+ * the order here is not essential
|
|
Takashi Iwai |
475cb5 |
+ * it is symmetrical just to be nice
|
|
Takashi Iwai |
475cb5 |
+ */
|
|
Takashi Iwai |
475cb5 |
+ usb_unpoison_urb(desc->response);
|
|
Takashi Iwai |
475cb5 |
+ usb_unpoison_urb(desc->validity);
|
|
Takashi Iwai |
475cb5 |
+ usb_unpoison_urb(desc->command);
|
|
Takashi Iwai |
475cb5 |
}
|
|
Takashi Iwai |
475cb5 |
|
|
Takashi Iwai |
475cb5 |
static void free_urbs(struct wdm_device *desc)
|
|
Takashi Iwai |
475cb5 |
@@ -741,11 +752,12 @@ static int wdm_release(struct inode *inode, struct file *file)
|
|
Takashi Iwai |
475cb5 |
if (!desc->count) {
|
|
Takashi Iwai |
475cb5 |
if (!test_bit(WDM_DISCONNECTING, &desc->flags)) {
|
|
Takashi Iwai |
475cb5 |
dev_dbg(&desc->intf->dev, "wdm_release: cleanup\n");
|
|
Takashi Iwai |
475cb5 |
- kill_urbs(desc);
|
|
Takashi Iwai |
475cb5 |
+ poison_urbs(desc);
|
|
Takashi Iwai |
475cb5 |
spin_lock_irq(&desc->iuspin);
|
|
Takashi Iwai |
475cb5 |
desc->resp_count = 0;
|
|
Takashi Iwai |
475cb5 |
spin_unlock_irq(&desc->iuspin);
|
|
Takashi Iwai |
475cb5 |
desc->manage_power(desc->intf, 0);
|
|
Takashi Iwai |
475cb5 |
+ unpoison_urbs(desc);
|
|
Takashi Iwai |
475cb5 |
} else {
|
|
Takashi Iwai |
475cb5 |
/* must avoid dev_printk here as desc->intf is invalid */
|
|
Takashi Iwai |
475cb5 |
pr_debug(KBUILD_MODNAME " %s: device gone - cleaning up\n", __func__);
|
|
Takashi Iwai |
475cb5 |
@@ -1037,9 +1049,9 @@ static void wdm_disconnect(struct usb_interface *intf)
|
|
Takashi Iwai |
475cb5 |
wake_up_all(&desc->wait);
|
|
Takashi Iwai |
475cb5 |
mutex_lock(&desc->rlock);
|
|
Takashi Iwai |
475cb5 |
mutex_lock(&desc->wlock);
|
|
Takashi Iwai |
475cb5 |
+ poison_urbs(desc);
|
|
Takashi Iwai |
475cb5 |
cancel_work_sync(&desc->rxwork);
|
|
Takashi Iwai |
475cb5 |
cancel_work_sync(&desc->service_outs_intr);
|
|
Takashi Iwai |
475cb5 |
- kill_urbs(desc);
|
|
Takashi Iwai |
475cb5 |
mutex_unlock(&desc->wlock);
|
|
Takashi Iwai |
475cb5 |
mutex_unlock(&desc->rlock);
|
|
Takashi Iwai |
475cb5 |
|
|
Takashi Iwai |
475cb5 |
@@ -1080,9 +1092,10 @@ static int wdm_suspend(struct usb_interface *intf, pm_message_t message)
|
|
Takashi Iwai |
475cb5 |
set_bit(WDM_SUSPENDING, &desc->flags);
|
|
Takashi Iwai |
475cb5 |
spin_unlock_irq(&desc->iuspin);
|
|
Takashi Iwai |
475cb5 |
/* callback submits work - order is essential */
|
|
Takashi Iwai |
475cb5 |
- kill_urbs(desc);
|
|
Takashi Iwai |
475cb5 |
+ poison_urbs(desc);
|
|
Takashi Iwai |
475cb5 |
cancel_work_sync(&desc->rxwork);
|
|
Takashi Iwai |
475cb5 |
cancel_work_sync(&desc->service_outs_intr);
|
|
Takashi Iwai |
475cb5 |
+ unpoison_urbs(desc);
|
|
Takashi Iwai |
475cb5 |
}
|
|
Takashi Iwai |
475cb5 |
if (!PMSG_IS_AUTO(message)) {
|
|
Takashi Iwai |
475cb5 |
mutex_unlock(&desc->wlock);
|
|
Takashi Iwai |
475cb5 |
@@ -1140,7 +1153,7 @@ static int wdm_pre_reset(struct usb_interface *intf)
|
|
Takashi Iwai |
475cb5 |
wake_up_all(&desc->wait);
|
|
Takashi Iwai |
475cb5 |
mutex_lock(&desc->rlock);
|
|
Takashi Iwai |
475cb5 |
mutex_lock(&desc->wlock);
|
|
Takashi Iwai |
475cb5 |
- kill_urbs(desc);
|
|
Takashi Iwai |
475cb5 |
+ poison_urbs(desc);
|
|
Takashi Iwai |
475cb5 |
cancel_work_sync(&desc->rxwork);
|
|
Takashi Iwai |
475cb5 |
cancel_work_sync(&desc->service_outs_intr);
|
|
Takashi Iwai |
475cb5 |
return 0;
|
|
Takashi Iwai |
475cb5 |
@@ -1151,6 +1164,7 @@ static int wdm_post_reset(struct usb_interface *intf)
|
|
Takashi Iwai |
475cb5 |
struct wdm_device *desc = wdm_find_device(intf);
|
|
Takashi Iwai |
475cb5 |
int rv;
|
|
Takashi Iwai |
475cb5 |
|
|
Takashi Iwai |
475cb5 |
+ unpoison_urbs(desc);
|
|
Takashi Iwai |
475cb5 |
clear_bit(WDM_OVERFLOW, &desc->flags);
|
|
Takashi Iwai |
475cb5 |
clear_bit(WDM_RESETTING, &desc->flags);
|
|
Takashi Iwai |
475cb5 |
rv = recover_from_urb_loss(desc);
|
|
Takashi Iwai |
475cb5 |
--
|
|
Takashi Iwai |
475cb5 |
2.26.2
|
|
Takashi Iwai |
475cb5 |
|