From f9c29ef20932a40203cc4fb485f41ab88e91ed3b Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Fri, 6 Nov 2020 10:10:58 +0100 Subject: [PATCH] Fix CDC ACM error recovery in Raspberry Pi kernels as well (#940) (#962) Backport fixes for CDC ACM error recovery path. --- ...based-AKMs-in-brcmf_set_key_mgmt-for.patch | 8 +- ...CM-heed-quirk-also-in-error-handling.patch | 39 ++++++ ...3-usb-cdc-acm-fix-cooldown-mechanism.patch | 130 ++++++++++++++++++ 3 files changed, 173 insertions(+), 4 deletions(-) create mode 100644 buildroot-external/board/raspberrypi/patches/linux/0002-CDC-ACM-heed-quirk-also-in-error-handling.patch create mode 100644 buildroot-external/board/raspberrypi/patches/linux/0003-usb-cdc-acm-fix-cooldown-mechanism.patch diff --git a/buildroot-external/board/raspberrypi/patches/linux/0001-brcmfmac-add-FT-based-AKMs-in-brcmf_set_key_mgmt-for.patch b/buildroot-external/board/raspberrypi/patches/linux/0001-brcmfmac-add-FT-based-AKMs-in-brcmf_set_key_mgmt-for.patch index d3bc877ee..dba55f5b5 100644 --- a/buildroot-external/board/raspberrypi/patches/linux/0001-brcmfmac-add-FT-based-AKMs-in-brcmf_set_key_mgmt-for.patch +++ b/buildroot-external/board/raspberrypi/patches/linux/0001-brcmfmac-add-FT-based-AKMs-in-brcmf_set_key_mgmt-for.patch @@ -1,9 +1,9 @@ From d6fc5f89ac905cb3efc9c61ce79dbfad5d91883b Mon Sep 17 00:00:00 2001 -Message-Id: +Message-Id: From: Chung-Hsien Hsu Date: Wed, 15 Aug 2018 05:32:39 -0500 -Subject: [PATCH] brcmfmac: add FT-based AKMs in brcmf_set_key_mgmt() for FT - support +Subject: [PATCH 1/3] brcmfmac: add FT-based AKMs in brcmf_set_key_mgmt() for + FT support Add WLAN_AKM_SUITE_FT_8021X and WLAN_AKM_SUITE_FT_PSK in brcmf_set_key_mgmt() for FT support. @@ -46,5 +46,5 @@ index 75b2a0438cfa..dddebaa60352 100644 #define DOT11_DEFAULT_RTS_LEN 2347 -- -2.28.0 +2.29.1 diff --git a/buildroot-external/board/raspberrypi/patches/linux/0002-CDC-ACM-heed-quirk-also-in-error-handling.patch b/buildroot-external/board/raspberrypi/patches/linux/0002-CDC-ACM-heed-quirk-also-in-error-handling.patch new file mode 100644 index 000000000..006327615 --- /dev/null +++ b/buildroot-external/board/raspberrypi/patches/linux/0002-CDC-ACM-heed-quirk-also-in-error-handling.patch @@ -0,0 +1,39 @@ +From 1eaf50e14dfdda654e6acb2a1ee4c18cff346064 Mon Sep 17 00:00:00 2001 +Message-Id: <1eaf50e14dfdda654e6acb2a1ee4c18cff346064.1604607313.git.stefan@agner.ch> +In-Reply-To: +References: +From: Oliver Neukum +Date: Tue, 26 May 2020 14:44:20 +0200 +Subject: [PATCH 2/3] CDC-ACM: heed quirk also in error handling + +commit 97fe809934dd2b0b37dfef3a2fc70417f485d7af upstream. + +If buffers are iterated over in the error case, the lower limits +for quirky devices must be heeded. + +Signed-off-by: Oliver Neukum +Reported-by: Jean Rene Dawin +Fixes: a4e7279cd1d19 ("cdc-acm: introduce a cool down") +Cc: stable +Link: https://lore.kernel.org/r/20200526124420.22160-1-oneukum@suse.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/class/cdc-acm.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c +index 10ba1b4f0dbf..e8b9b27937ed 100644 +--- a/drivers/usb/class/cdc-acm.c ++++ b/drivers/usb/class/cdc-acm.c +@@ -590,7 +590,7 @@ static void acm_softint(struct work_struct *work) + } + + if (test_and_clear_bit(ACM_ERROR_DELAY, &acm->flags)) { +- for (i = 0; i < ACM_NR; i++) ++ for (i = 0; i < acm->rx_buflimit; i++) + if (test_and_clear_bit(i, &acm->urbs_in_error_delay)) + acm_submit_read_urb(acm, i, GFP_NOIO); + } +-- +2.29.1 + diff --git a/buildroot-external/board/raspberrypi/patches/linux/0003-usb-cdc-acm-fix-cooldown-mechanism.patch b/buildroot-external/board/raspberrypi/patches/linux/0003-usb-cdc-acm-fix-cooldown-mechanism.patch new file mode 100644 index 000000000..71a0434ba --- /dev/null +++ b/buildroot-external/board/raspberrypi/patches/linux/0003-usb-cdc-acm-fix-cooldown-mechanism.patch @@ -0,0 +1,130 @@ +From 930c59eeae2bdd02fa1327a69e4df70105f672e4 Mon Sep 17 00:00:00 2001 +Message-Id: <930c59eeae2bdd02fa1327a69e4df70105f672e4.1604607313.git.stefan@agner.ch> +In-Reply-To: +References: +From: Jerome Brunet +Date: Mon, 19 Oct 2020 19:07:02 +0200 +Subject: [PATCH 3/3] usb: cdc-acm: fix cooldown mechanism + +Commit a4e7279cd1d1 ("cdc-acm: introduce a cool down") is causing +regression if there is some USB error, such as -EPROTO. + +This has been reported on some samples of the Odroid-N2 using the Combee II +Zibgee USB dongle. + +> struct acm *acm = container_of(work, struct acm, work) + +is incorrect in case of a delayed work and causes warnings, usually from +the workqueue: + +> WARNING: CPU: 0 PID: 0 at kernel/workqueue.c:1474 __queue_work+0x480/0x528. + +When this happens, USB eventually stops working completely after a while. +Also the ACM_ERROR_DELAY bit is never set, so the cooldown mechanism +previously introduced cannot be triggered and acm_submit_read_urb() is +never called. + +This changes makes the cdc-acm driver use a single delayed work, fixing the +pointer arithmetic in acm_softint() and set the ACM_ERROR_DELAY when the +cooldown mechanism appear to be needed. + +Fixes: a4e7279cd1d1 ("cdc-acm: introduce a cool down") +Cc: Oliver Neukum +Reported-by: Pascal Vizeli +Acked-by: Oliver Neukum +Signed-off-by: Jerome Brunet +Link: https://lore.kernel.org/r/20201019170702.150534-1-jbrunet@baylibre.com +Cc: stable +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/class/cdc-acm.c | 12 +++++------- + drivers/usb/class/cdc-acm.h | 3 +-- + 2 files changed, 6 insertions(+), 9 deletions(-) + +diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c +index e8b9b27937ed..4b543aa0030d 100644 +--- a/drivers/usb/class/cdc-acm.c ++++ b/drivers/usb/class/cdc-acm.c +@@ -510,6 +510,7 @@ static void acm_read_bulk_callback(struct urb *urb) + "%s - cooling babbling device\n", __func__); + usb_mark_last_busy(acm->dev); + set_bit(rb->index, &acm->urbs_in_error_delay); ++ set_bit(ACM_ERROR_DELAY, &acm->flags); + cooldown = true; + break; + default: +@@ -535,7 +536,7 @@ static void acm_read_bulk_callback(struct urb *urb) + + if (stopped || stalled || cooldown) { + if (stalled) +- schedule_work(&acm->work); ++ schedule_delayed_work(&acm->dwork, 0); + else if (cooldown) + schedule_delayed_work(&acm->dwork, HZ / 2); + return; +@@ -570,13 +571,13 @@ static void acm_write_bulk(struct urb *urb) + acm_write_done(acm, wb); + spin_unlock_irqrestore(&acm->write_lock, flags); + set_bit(EVENT_TTY_WAKEUP, &acm->flags); +- schedule_work(&acm->work); ++ schedule_delayed_work(&acm->dwork, 0); + } + + static void acm_softint(struct work_struct *work) + { + int i; +- struct acm *acm = container_of(work, struct acm, work); ++ struct acm *acm = container_of(work, struct acm, dwork.work); + + if (test_bit(EVENT_RX_STALL, &acm->flags)) { + smp_mb(); /* against acm_suspend() */ +@@ -592,7 +593,7 @@ static void acm_softint(struct work_struct *work) + if (test_and_clear_bit(ACM_ERROR_DELAY, &acm->flags)) { + for (i = 0; i < acm->rx_buflimit; i++) + if (test_and_clear_bit(i, &acm->urbs_in_error_delay)) +- acm_submit_read_urb(acm, i, GFP_NOIO); ++ acm_submit_read_urb(acm, i, GFP_KERNEL); + } + + if (test_and_clear_bit(EVENT_TTY_WAKEUP, &acm->flags)) +@@ -1386,7 +1387,6 @@ static int acm_probe(struct usb_interface *intf, + acm->ctrlsize = ctrlsize; + acm->readsize = readsize; + acm->rx_buflimit = num_rx_buf; +- INIT_WORK(&acm->work, acm_softint); + INIT_DELAYED_WORK(&acm->dwork, acm_softint); + init_waitqueue_head(&acm->wioctl); + spin_lock_init(&acm->write_lock); +@@ -1596,7 +1596,6 @@ static void acm_disconnect(struct usb_interface *intf) + } + + acm_kill_urbs(acm); +- cancel_work_sync(&acm->work); + cancel_delayed_work_sync(&acm->dwork); + + tty_unregister_device(acm_tty_driver, acm->minor); +@@ -1639,7 +1638,6 @@ static int acm_suspend(struct usb_interface *intf, pm_message_t message) + return 0; + + acm_kill_urbs(acm); +- cancel_work_sync(&acm->work); + cancel_delayed_work_sync(&acm->dwork); + acm->urbs_in_error_delay = 0; + +diff --git a/drivers/usb/class/cdc-acm.h b/drivers/usb/class/cdc-acm.h +index 30380d28a504..d8f8651425c4 100644 +--- a/drivers/usb/class/cdc-acm.h ++++ b/drivers/usb/class/cdc-acm.h +@@ -111,8 +111,7 @@ struct acm { + # define ACM_ERROR_DELAY 3 + unsigned long urbs_in_error_delay; /* these need to be restarted after a delay */ + struct usb_cdc_line_coding line; /* bits, stop, parity */ +- struct work_struct work; /* work queue entry for various purposes*/ +- struct delayed_work dwork; /* for cool downs needed in error recovery */ ++ struct delayed_work dwork; /* work queue entry for various purposes */ + unsigned int ctrlin; /* input control lines (DCD, DSR, RI, break, overruns) */ + unsigned int ctrlout; /* output control lines (DTR, RTS) */ + struct async_icount iocount; /* counters for control line changes */ +-- +2.29.1 +