]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
wifi: rtw89: usb: anchor TX URBs
authorFedor Pchelkin <pchelkin@ispras.ru>
Tue, 4 Nov 2025 13:57:14 +0000 (16:57 +0300)
committerPing-Ke Shih <pkshih@realtek.com>
Thu, 6 Nov 2025 06:32:03 +0000 (14:32 +0800)
During HCI reset all pending TX URBs should be canceled.  Use anchor to
keep track of them and have an ability to cancel them synchronously.

Note however that canceling RX URBs can't be done here in
rtw89_usb_ops_reset() as it breaks driver initialization.

Found by Linux Verification Center (linuxtesting.org).

Acked-by: Ping-Ke Shih <pkshih@realtek.com>
Signed-off-by: Fedor Pchelkin <pchelkin@ispras.ru>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
Link: https://patch.msgid.link/20251104135720.321110-8-pchelkin@ispras.ru
drivers/net/wireless/realtek/rtw89/usb.c
drivers/net/wireless/realtek/rtw89/usb.h

index 59cdee54feef138913187b3689e424d339f630e8..b7b981bac7bfbbe70712459d35676ec88b6db7b9 100644 (file)
@@ -221,7 +221,6 @@ static void rtw89_usb_write_port_complete(struct urb *urb)
        }
 
        kfree(txcb);
-       usb_free_urb(urb);
 }
 
 static int rtw89_usb_write_port(struct rtw89_dev *rtwdev, u8 ch_dma,
@@ -247,10 +246,17 @@ static int rtw89_usb_write_port(struct rtw89_dev *rtwdev, u8 ch_dma,
        usb_fill_bulk_urb(urb, usbd, pipe, data, len,
                          rtw89_usb_write_port_complete, context);
        urb->transfer_flags |= URB_ZERO_PACKET;
-       ret = usb_submit_urb(urb, GFP_ATOMIC);
+       usb_anchor_urb(urb, &rtwusb->tx_submitted);
 
+       ret = usb_submit_urb(urb, GFP_ATOMIC);
        if (ret)
-               usb_free_urb(urb);
+               usb_unanchor_urb(urb);
+
+       /* release our reference to this URB, USB core will eventually free it
+        * on its own after the completion callback finishes (or URB is
+        * immediately freed here if its submission has failed)
+        */
+       usb_free_urb(urb);
 
        if (ret == -ENODEV)
                set_bit(RTW89_FLAG_UNPLUGGED, rtwdev->flags);
@@ -557,6 +563,11 @@ static void rtw89_usb_cancel_rx_bufs(struct rtw89_usb *rtwusb)
        }
 }
 
+static void rtw89_usb_cancel_tx_bufs(struct rtw89_usb *rtwusb)
+{
+       usb_kill_anchored_urbs(&rtwusb->tx_submitted);
+}
+
 static void rtw89_usb_free_rx_bufs(struct rtw89_usb *rtwusb)
 {
        struct rtw89_usb_rx_ctrl_block *rxcb;
@@ -658,7 +669,9 @@ static void rtw89_usb_deinit_tx(struct rtw89_dev *rtwdev)
 
 static void rtw89_usb_ops_reset(struct rtw89_dev *rtwdev)
 {
-       /* TODO: anything to do here? */
+       struct rtw89_usb *rtwusb = rtw89_usb_priv(rtwdev);
+
+       rtw89_usb_cancel_tx_bufs(rtwusb);
 }
 
 static int rtw89_usb_ops_start(struct rtw89_dev *rtwdev)
@@ -895,6 +908,8 @@ static int rtw89_usb_intf_init(struct rtw89_dev *rtwdev,
        struct rtw89_usb *rtwusb = rtw89_usb_priv(rtwdev);
        int ret;
 
+       init_usb_anchor(&rtwusb->tx_submitted);
+
        ret = rtw89_usb_parse(rtwdev, intf);
        if (ret)
                return ret;
@@ -1021,6 +1036,7 @@ void rtw89_usb_disconnect(struct usb_interface *intf)
        rtwusb = rtw89_usb_priv(rtwdev);
 
        rtw89_usb_cancel_rx_bufs(rtwusb);
+       rtw89_usb_cancel_tx_bufs(rtwusb);
 
        rtw89_core_unregister(rtwdev);
        rtw89_core_deinit(rtwdev);
index 32cdbf5128e45629ac33021720484650bd50d233..203ec8e993e9ffd9b8779e8550866ea4c716cd0c 100644 (file)
@@ -60,6 +60,7 @@ struct rtw89_usb {
        struct sk_buff_head rx_free_queue;
        struct work_struct rx_work;
        struct work_struct rx_urb_work;
+       struct usb_anchor tx_submitted;
 
        struct sk_buff_head tx_queue[RTW89_TXCH_NUM];
 };