1: 958c667dcf4d ! 1: 9d61753fe26a wifi: rtw88: sdio: Handle allocation and read errors in rtw_sdio_rxfifo_recv @@ Commit message Cc: stable@vger.kernel.org Assisted-by: LLM Acked-by: Ping-Ke Shih  + Reviewed-by: Luka Gejak  Signed-off-by: Alastair D'Silva   ## drivers/net/wireless/realtek/rtw88/sdio.c ## 2: 94d131f86bca ! 2: d4854e18c586 wifi: rtw88: sdio: Track running state and cancel TX worker on stop @@ drivers/net/wireless/realtek/rtw88/sdio.c: static void rtw_sdio_init(struct rtw_ if (rtw_is_8723bs(rtwdev)) rtwsdio->irq_mask = REG_SDIO_HIMR_RX_REQUEST; else -@@ drivers/net/wireless/realtek/rtw88/sdio.c: static void rtw_sdio_init(struct rtw_dev *rtwdev) - REG_SDIO_HIMR_CPWM1; - } -  -+static void rtw_sdio_deinit(struct rtw_dev *rtwdev) -+{ -+ struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv; -+ -+ mutex_destroy(&rtwsdio->irq_lock); -+} -+ - static void rtw_sdio_enable_rx_aggregation(struct rtw_dev *rtwdev) - { - u8 size, timeout;  @@ drivers/net/wireless/realtek/rtw88/sdio.c: static int rtw_sdio_8723bs_check_rqpn(struct rtw_dev *rtwdev)  static int rtw_sdio_start(struct rtw_dev *rtwdev) @@ drivers/net/wireless/realtek/rtw88/sdio.c: static void rtw_sdio_tx_handler(struc if (!rtw_fw_feature_check(&rtwdev->fw, FW_FEATURE_TX_WAKE)) rtw_sdio_deep_ps_leave(rtwdev);  -@@ drivers/net/wireless/realtek/rtw88/sdio.c: int rtw_sdio_probe(struct sdio_func *sdio_func, - ret = rtw_sdio_init_tx(rtwdev); - if (ret) { - rtw_err(rtwdev, "failed to init SDIO TX queue\n"); -- goto err_sdio_declaim; -+ goto err_deinit; - } -  - ret = rtw_chip_info_setup(rtwdev); -@@ drivers/net/wireless/realtek/rtw88/sdio.c: int rtw_sdio_probe(struct sdio_func *sdio_func, - rtw_sdio_free_irq(rtwdev, sdio_func); - err_destroy_txwq: - rtw_sdio_deinit_tx(rtwdev); --err_sdio_declaim: -+err_deinit: -+ rtw_sdio_deinit(rtwdev); - rtw_sdio_declaim(rtwdev, sdio_func); - err_deinit_core: - rtw_core_deinit(rtwdev); -@@ drivers/net/wireless/realtek/rtw88/sdio.c: void rtw_sdio_remove(struct sdio_func *sdio_func) - rtw_sdio_free_irq(rtwdev, sdio_func); - rtw_sdio_declaim(rtwdev, sdio_func); - rtw_sdio_deinit_tx(rtwdev); -+ rtw_sdio_deinit(rtwdev); - rtw_core_deinit(rtwdev); - ieee80211_free_hw(hw); - }  ## drivers/net/wireless/realtek/rtw88/sdio.h ##  @@ drivers/net/wireless/realtek/rtw88/sdio.h: struct rtw_sdio { @@ drivers/net/wireless/realtek/rtw88/sdio.h: struct rtw_sdio {  void *irq_thread;  + bool running; -+ /* protect running state and interrupt mask */ ++ /* protect running state and enabling interrupts */  + struct mutex irq_lock;  struct workqueue_struct *txwq; 3: 5543b4c96c93 ! 3: e068bfea6332 wifi: rtw88: sdio: Fix unhandled RX request interrupt storm @@ Commit message once the buffer is empty, and software must not clear it.  Split rtw_sdio_handle_interrupt() into separate 8051 and 3081 handlers. - For 3081, disable interrupts via HIMR, acknowledge pending status bits - via W1C writeback, service pending events, and re-enable interrupts under - irq_lock if still running. For 8051 chips, preserve the existing behavior. + For 3081, disable interrupts via HIMR, acknowledge all pending status + bits via W1C writeback (preserving the existing full status word + writeback used on non-RTL8723BS chips, now including + REG_SDIO_HISR_RX_REQUEST), service pending events, and re-enable + interrupts under irq_lock if still running. + + On 3081 hardware, REG_SDIO_HISR_RX_REQUEST is level-sensitive to FIFO + occupancy: if unread packets remain in the FIFO when interrupts are + re-enabled (or if new packets arrived), the chip re-asserts + REG_SDIO_HISR_RX_REQUEST and re-triggers the IRQ line. For 8051 chips, + preserve the existing behavior.  Fixes: 65371a3f14e7 ("wifi: rtw88: sdio: Add HCI implementation for SDIO based chipsets") Cc: stable@vger.kernel.org @@ drivers/net/wireless/realtek/rtw88/sdio.c: static void rtw_sdio_rx_isr(struct rt  + struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv;  +  + rtw_sdio_disable_interrupt(rtwdev); ++ ++ /* ++ * Acknowledge all pending status bits via W1C writeback. Unlike 8051, ++ * 3081 requires REG_SDIO_HISR_RX_REQUEST to be explicitly cleared by ++ * software. ++ */  + rtw_write32(rtwdev, REG_SDIO_HISR, hisr);  +  + if (hisr & REG_SDIO_HISR_TXERR) @@ drivers/net/wireless/realtek/rtw88/sdio.c: static void rtw_sdio_rx_isr(struct rt  + if (hisr & REG_SDIO_HISR_RX_REQUEST)  + rtw_sdio_rx_isr(rtwdev);  + -+ /* Unmasking HIMR re-asserts the IRQ line if new packets arrived */ ++ /* ++ * Unmasking HIMR re-asserts the IRQ line if new packets arrived or if ++ * unread data remains in the RX FIFO (e.g. if the 64KB budget was ++ * reached or an RX error occurred). On 3081 hardware, ++ * REG_SDIO_HISR_RX_REQUEST is level-sensitive to FIFO occupancy: ++ * although cleared by the W1C writeback above, the chip automatically ++ * re-asserts REG_SDIO_HISR_RX_REQUEST as long as the RX buffer is ++ * non-empty, re-triggering the interrupt when unmasked. ++ */  + scoped_guard(mutex, &rtwsdio->irq_lock) {  + if (rtwsdio->running)  + rtw_sdio_enable_interrupt(rtwdev); @@ drivers/net/wireless/realtek/rtw88/sdio.c: static void rtw_sdio_handle_interrupt rtwsdio->irq_thread = current;  hisr = rtw_read32(rtwdev, REG_SDIO_HISR); -+ if (!hisr) -+ goto out; -  +-  - if (hisr & REG_SDIO_HISR_TXERR)  - rtw_sdio_tx_err_isr(rtwdev);  - if (hisr & REG_SDIO_HISR_RX_REQUEST) {  - hisr &= ~REG_SDIO_HISR_RX_REQUEST;  - rtw_sdio_rx_isr(rtwdev); -- } -- ++ if (hisr) { ++ if (rtw_chip_wcpu_8051(rtwdev)) ++ rtw_sdio_handle_interrupt_8051(rtwdev, hisr); ++ else ++ rtw_sdio_handle_interrupt_3081(rtwdev, hisr); + } +   - /*  - * RTL8723BS keeps raising the interrupt after resume if undefined  - * status bits are written back, so acknowledge only the bits this @@ drivers/net/wireless/realtek/rtw88/sdio.c: static void rtw_sdio_handle_interrupt  - hisr &= RTW_SDIO_HISR_CLEAR_MASK;  -  - rtw_write32(rtwdev, REG_SDIO_HISR, hisr); -+ if (rtw_chip_wcpu_8051(rtwdev)) -+ rtw_sdio_handle_interrupt_8051(rtwdev, hisr); -+ else -+ rtw_sdio_handle_interrupt_3081(rtwdev, hisr); -  -+out: +- rtwsdio->irq_thread = NULL; }  4: d774798f92bb ! 4: 12b781872120 wifi: rtw88: sdio: Split rtw_sdio_rx_isr into 8051 and 3081 variants @@ Commit message  Assisted-by: LLM Acked-by: Ping-Ke Shih  + Reviewed-by: Luka Gejak  Signed-off-by: Alastair D'Silva   ## drivers/net/wireless/realtek/rtw88/sdio.c ## @@ drivers/net/wireless/realtek/rtw88/sdio.c: static void rtw_sdio_handle_interrupt  - rtw_sdio_rx_isr(rtwdev);  + rtw_sdio_rx_isr_3081(rtwdev);  - /* Unmasking HIMR re-asserts the IRQ line if new packets arrived */ - scoped_guard(mutex, &rtwsdio->irq_lock) { + /* + * Unmasking HIMR re-asserts the IRQ line if new packets arrived or if