1: 30e20dd7bb70 = 1: 45002c9f6709 wifi: rtl8xxxu: free RX skb when URB submission fails 2: 18f59df2e3ef ! 2: 2cb012ff6b4d wifi: rtl8xxxu: unwind incomplete receive startup @@ Commit message Keep the allocation loop in a small helper so the setup and error paths in start remain easy to follow.  + On an RTL8192EU, I exercised every error exit in rtl8xxxu_start() + except interrupt-URB allocation and submission failures, which this + adapter does not use. + Fixes: 26f1fad29ad9 ("New driver: rtl8xxxu (mac80211)") Assisted-by: GPT-6 Astra + Reviewed-by: Ping-Ke Shih  Signed-off-by: Kim Wooseok <5mghybrid@khu.ac.kr>  ## drivers/net/wireless/realtek/rtl8xxxu/core.c ## @@ drivers/net/wireless/realtek/rtl8xxxu/core.c: static void rtl8xxxu_free_rx_resou  + usb_init_urb(&rx_urb->urb);  + INIT_LIST_HEAD(&rx_urb->list);  + rx_urb->hw = priv->hw; ++  + list_add_tail(&rx_urb->list, &priv->rx_urb_pending_list);  + priv->rx_urb_pending_count++;  + } @@ drivers/net/wireless/realtek/rtl8xxxu/core.c: static void rtl8xxxu_rx_urb_work(s  +  +static void rtl8xxxu_rx_urb_work(struct work_struct *work)  +{ -+ struct rtl8xxxu_priv *priv; ++ struct rtl8xxxu_priv *priv = container_of(work, struct rtl8xxxu_priv, rx_urb_wq);  + -+ priv = container_of(work, struct rtl8xxxu_priv, rx_urb_wq);  + rtl8xxxu_submit_rx_urbs(priv, false); }  3: f1665d1690cb ! 3: 13e9f49194f7 wifi: rtl8xxxu: preserve RX requests across recoverable transfer errors @@ drivers/net/wireless/realtek/rtl8xxxu/core.c: static int rtl8xxxu_alloc_rx_urbs(  static void rtl8xxxu_queue_rx_urb(struct rtl8xxxu_priv *priv,  - struct rtl8xxxu_rx_urb *rx_urb) -+ struct rtl8xxxu_rx_urb *rx_urb, bool retry) ++ struct rtl8xxxu_rx_urb *rx_urb, bool defer_schedule) {  - struct sk_buff *skb; unsigned long flags; @@ drivers/net/wireless/realtek/rtl8xxxu/core.c: static void rtl8xxxu_queue_rx_urb(  - if (priv->rx_urb_pending_count > RTL8XXXU_RX_URB_PENDING_WATER)  - schedule_work(&priv->rx_urb_wq);  + /* Serialize scheduling with the shutdown check and cancellation. */ -+ if (retry) -+ queue_delayed_work(system_wq, &priv->rx_urb_wq, -+ msecs_to_jiffies(RTL8XXXU_RX_URB_RETRY_DELAY_MS)); ++ if (defer_schedule) ++ schedule_delayed_work(&priv->rx_urb_wq, ++ msecs_to_jiffies(RTL8XXXU_RX_URB_RETRY_DELAY_MS));  + else if (priv->rx_urb_pending_count > RTL8XXXU_RX_URB_PENDING_WATER) -+ mod_delayed_work(system_wq, &priv->rx_urb_wq, 0); ++ mod_delayed_work(system_percpu_wq, &priv->rx_urb_wq, 0); } else {  - skb = (struct sk_buff *)rx_urb->urb.context;  - dev_kfree_skb_irq(skb); @@ drivers/net/wireless/realtek/rtl8xxxu/core.c: static int rtl8xxxu_submit_rx_urbs break; default: usb_free_urb(&rx_urb->urb); -@@ drivers/net/wireless/realtek/rtl8xxxu/core.c: static void rtl8xxxu_rx_urb_work(struct work_struct *work) +@@ drivers/net/wireless/realtek/rtl8xxxu/core.c: static int rtl8xxxu_submit_rx_urbs(struct rtl8xxxu_priv *priv, bool startup) +  + static void rtl8xxxu_rx_urb_work(struct work_struct *work) { - struct rtl8xxxu_priv *priv; +- struct rtl8xxxu_priv *priv = container_of(work, struct rtl8xxxu_priv, rx_urb_wq); ++ struct rtl8xxxu_priv *priv = container_of(to_delayed_work(work), ++ struct rtl8xxxu_priv, rx_urb_wq);  -- priv = container_of(work, struct rtl8xxxu_priv, rx_urb_wq); -+ priv = container_of(to_delayed_work(work), struct rtl8xxxu_priv, -+ rx_urb_wq); rtl8xxxu_submit_rx_urbs(priv, false); } -   @@ drivers/net/wireless/realtek/rtl8xxxu/core.c: static void rtl8xxxu_rx_complete(struct urb *urb)  skb = NULL; @@ drivers/net/wireless/realtek/rtl8xxxu/core.c: static void rtl8xxxu_rx_complete(s } else { dev_dbg(dev, "%s: status %i\n", __func__, urb->status);  - goto cleanup; ++  + switch (urb->status) {  + case -EPROTO:  + case -EILSEQ: