summaryrefslogtreecommitdiffstats
path: root/drivers/thunderbolt/ctl.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-10-03 08:42:54 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2026-10-03 08:42:54 -0700
commit903e23eda5af2a5491e698838645f84a8f90379b (patch)
tree9d6001d74e512aea4fe4dbaf5b236050e224e11d /drivers/thunderbolt/ctl.c
parent8623551a424d34a311bab3fb9243535c98e08c26 (diff)
parenta93862fa670a9c99fd9a24fb2ef69e4f948d9bd5 (diff)
downloadlinux-stable-903e23eda5af2a5491e698838645f84a8f90379b.tar.gz
linux-stable-903e23eda5af2a5491e698838645f84a8f90379b.zip
Merge tag 'usb-7.3-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb
Pull USB/Thunderbolt fixes from Greg KH: "Here is a big set of USB and Thunderbolt driver fixes for 7.3-rc6. They were delayed on my side due to conference travel, not the fault of the submitters at all. Included in here are: - lots of small thunderbolt fixes for reported issues due to more testing and devices and a few reverts as well based on that work - more usb-serial device ids added - usb-serial and cdc-acm driver hangup and other fixes - dwc3 driver fixes for reported problems - lots of usb gadget driver fixes as people again fuzz these drivers and send in fixes, which is nice to finally see - typec driver fixes for reported problems - octeon-hcd driver fixes for reported problems - more usb-storage quirks added - other small USB driver bugs resolved for reported problems All of these have been in linux-next without any reported issues" * tag 'usb-7.3-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (63 commits) usb: dwc3: gadget: fix IRQ storm on invalid event buffer count Revert "usb: dwc3: gadget: fix IRQ storm on invalid event buffer count" USB: gadget: dummy-hcd: Fix wait for outstanding request completions usb: typec: port-mapper: Only match USB4 port if host interface is available usb: cdns3: Fix NULL pointer dereference in cdns3_pci_probe usb: dwc3: gadget: fix IRQ storm on invalid event buffer count usb: typec: ucsi: Get the connector fwnode based on reg value usb: gadget: f_uac1_legacy: validate bRequest index in generic_{set,get}_cmd usb: core: clear both ep_in and ep_out for non-ep0 control endpoints USB: cdc-acm: skip URB restart in port_shutdown if disconnected usb: gadget: f_fs: Fix NULL pointer dereference in FUNCTIONFS_ENDPOINT_DESC usb: gadget: aspeed-vhub: cancel wake work on device removal thunderbolt: Disable CL states for the Anker Prime TB5 dock thunderbolt: stream: Announce support for FMODE_NOWAIT usb: typec: ucsi: displayport: Current CAM OOB index fixup usb: ohci-st: disable controller wakeup on removal usb: ohci-spear: disable controller wakeup on removal usb: ohci-s3c2410: disable controller wakeup on removal usb: ohci-da8xx: disable controller wakeup on cleanup usb: cdns3: fix use-after-free in cdns3_gadget_exit() ...
Diffstat (limited to 'drivers/thunderbolt/ctl.c')
-rw-r--r--drivers/thunderbolt/ctl.c63
1 files changed, 31 insertions, 32 deletions
diff --git a/drivers/thunderbolt/ctl.c b/drivers/thunderbolt/ctl.c
index cd47b627f..965988b18 100644
--- a/drivers/thunderbolt/ctl.c
+++ b/drivers/thunderbolt/ctl.c
@@ -73,7 +73,6 @@ struct tb_ctl {
#define tb_ctl_dbg_once(ctl, format, arg...) \
dev_dbg_once((ctl)->nhi->dev, format, ## arg)
-static DECLARE_WAIT_QUEUE_HEAD(tb_cfg_request_cancel_queue);
/* Serializes access to request kref_get/put */
static DEFINE_MUTEX(tb_cfg_request_lock);
@@ -133,41 +132,42 @@ void tb_cfg_request_put(struct tb_cfg_request *req)
static int tb_cfg_request_enqueue(struct tb_ctl *ctl,
struct tb_cfg_request *req)
{
+ tb_cfg_request_get(req);
+
WARN_ON(test_bit(TB_CFG_REQUEST_ACTIVE, &req->flags));
WARN_ON(req->ctl);
- mutex_lock(&ctl->request_queue_lock);
+ guard(mutex)(&ctl->request_queue_lock);
if (!ctl->running) {
- mutex_unlock(&ctl->request_queue_lock);
+ tb_cfg_request_put(req);
return -ENOTCONN;
}
req->ctl = ctl;
list_add_tail(&req->list, &ctl->request_queue);
set_bit(TB_CFG_REQUEST_ACTIVE, &req->flags);
- mutex_unlock(&ctl->request_queue_lock);
return 0;
}
-static void tb_cfg_request_dequeue(struct tb_cfg_request *req)
+static bool tb_cfg_request_is_active(struct tb_cfg_request *req)
{
- struct tb_ctl *ctl = req->ctl;
-
- mutex_lock(&ctl->request_queue_lock);
- if (!test_bit(TB_CFG_REQUEST_ACTIVE, &req->flags)) {
- mutex_unlock(&ctl->request_queue_lock);
- return;
- }
+ return test_bit(TB_CFG_REQUEST_ACTIVE, &req->flags);
+}
- list_del(&req->list);
- clear_bit(TB_CFG_REQUEST_ACTIVE, &req->flags);
- if (test_bit(TB_CFG_REQUEST_CANCELED, &req->flags))
- wake_up(&tb_cfg_request_cancel_queue);
- mutex_unlock(&ctl->request_queue_lock);
+static bool tb_cfg_request_is_canceled(struct tb_cfg_request *req)
+{
+ return test_bit(TB_CFG_REQUEST_CANCELED, &req->flags);
}
-static bool tb_cfg_request_is_active(struct tb_cfg_request *req)
+static void tb_cfg_request_dequeue(struct tb_cfg_request *req)
{
- return test_bit(TB_CFG_REQUEST_ACTIVE, &req->flags);
+ struct tb_ctl *ctl = req->ctl;
+
+ guard(mutex)(&ctl->request_queue_lock);
+ if (tb_cfg_request_is_active(req)) {
+ list_del(&req->list);
+ clear_bit(TB_CFG_REQUEST_ACTIVE, &req->flags);
+ tb_cfg_request_put(req);
+ }
}
static struct tb_cfg_request *
@@ -178,7 +178,7 @@ tb_cfg_request_find(struct tb_ctl *ctl, struct ctl_pkg *pkg)
mutex_lock(&pkg->ctl->request_queue_lock);
list_for_each_entry(iter, &pkg->ctl->request_queue, list) {
tb_cfg_request_get(iter);
- if (iter->match(iter, pkg)) {
+ if (!tb_cfg_request_is_canceled(iter) && iter->match(iter, pkg)) {
req = iter;
break;
}
@@ -512,8 +512,11 @@ static void tb_ctl_rx_callback(struct tb_ring *ring, struct ring_frame *frame,
trace_tb_rx(pkg->ctl->index, frame->eof, pkg->buffer, frame->size, !req);
if (req) {
- if (req->copy(req, pkg))
- schedule_work(&req->work);
+ scoped_guard(mutex, &pkg->ctl->request_queue_lock) {
+ if (!tb_cfg_request_is_canceled(req) &&
+ req->copy(req, pkg))
+ schedule_work(&req->work);
+ }
tb_cfg_request_put(req);
}
@@ -525,11 +528,10 @@ static void tb_cfg_request_work(struct work_struct *work)
{
struct tb_cfg_request *req = container_of(work, typeof(*req), work);
- if (!test_bit(TB_CFG_REQUEST_CANCELED, &req->flags))
+ if (!tb_cfg_request_is_canceled(req))
req->callback(req->callback_data);
tb_cfg_request_dequeue(req);
- tb_cfg_request_put(req);
}
/**
@@ -555,10 +557,9 @@ int tb_cfg_request(struct tb_ctl *ctl, struct tb_cfg_request *req,
INIT_WORK(&req->work, tb_cfg_request_work);
INIT_LIST_HEAD(&req->list);
- tb_cfg_request_get(req);
ret = tb_cfg_request_enqueue(ctl, req);
if (ret)
- goto err_put;
+ return ret;
ret = tb_ctl_tx(ctl, req->request, req->request_size,
req->request_type);
@@ -572,9 +573,6 @@ int tb_cfg_request(struct tb_ctl *ctl, struct tb_cfg_request *req,
err_dequeue:
tb_cfg_request_dequeue(req);
-err_put:
- tb_cfg_request_put(req);
-
return ret;
}
@@ -588,9 +586,10 @@ err_put:
*/
void tb_cfg_request_cancel(struct tb_cfg_request *req, int err)
{
- set_bit(TB_CFG_REQUEST_CANCELED, &req->flags);
- schedule_work(&req->work);
- wait_event(tb_cfg_request_cancel_queue, !tb_cfg_request_is_active(req));
+ scoped_guard(mutex, &req->ctl->request_queue_lock)
+ set_bit(TB_CFG_REQUEST_CANCELED, &req->flags);
+ cancel_work_sync(&req->work);
+ tb_cfg_request_dequeue(req);
req->result.err = err;
}