Patch "wifi: rtw88: sdio: Check the HISR RX_REQUEST bit in rtw_sdio_rx_isr()" has been added to the 6.4-stable tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is a note to let you know that I've just added the patch titled

    wifi: rtw88: sdio: Check the HISR RX_REQUEST bit in rtw_sdio_rx_isr()

to the 6.4-stable tree which can be found at:
    http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     wifi-rtw88-sdio-check-the-hisr-rx_request-bit-in-rtw.patch
and it can be found in the queue-6.4 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@xxxxxxxxxxxxxxx> know about it.



commit 4357179094d447fe2d49c33c6de95fab7905d53f
Author: Martin Blumenstingl <martin.blumenstingl@xxxxxxxxxxxxxx>
Date:   Mon May 22 22:24:22 2023 +0200

    wifi: rtw88: sdio: Check the HISR RX_REQUEST bit in rtw_sdio_rx_isr()
    
    [ Upstream commit e967229ead0e6c5047a1cfd5a0db58ceb930800b ]
    
    rtw_sdio_rx_isr() is responsible for receiving data from the wifi chip
    and is called from the SDIO interrupt handler when the interrupt status
    register (HISR) has the RX_REQUEST bit set. After the first batch of
    data has been processed by the driver the wifi chip may have more data
    ready to be read, which is managed by a loop in rtw_sdio_rx_isr().
    
    It turns out that there are cases where the RX buffer length (from the
    REG_SDIO_RX0_REQ_LEN register) does not match the data we receive. The
    following two cases were observed with a RTL8723DS card:
    - RX length is smaller than the total packet length including overhead
      and actual data bytes (whose length is part of the buffer we read from
      the wifi chip and is stored in rtw_rx_pkt_stat.pkt_len). This can
      result in errors like:
        skbuff: skb_over_panic: text:ffff8000011924ac len:3341 put:3341
      (one case observed was: RX buffer length = 1536 bytes but
       rtw_rx_pkt_stat.pkt_len = 1546 bytes, this is not valid as it means
       we need to read beyond the end of the buffer)
    - RX length looks valid but rtw_rx_pkt_stat.pkt_len is zero
    
    Check if the RX_REQUEST is set in the HISR register for each iteration
    inside rtw_sdio_rx_isr(). This mimics what the RTL8723DS vendor driver
    does and makes the driver only read more data if the RX_REQUEST bit is
    set (which seems to be a way for the card's hardware or firmware to
    tell the host that data is ready to be processed).
    
    For RTW_WCPU_11AC chips this check is not needed. The RTL8822BS vendor
    driver for example states that this check is unnecessary (but still uses
    it) and the RTL8822CS drops this check entirely.
    
    Reviewed-by: Ping-Ke Shih <pkshih@xxxxxxxxxxx>
    Signed-off-by: Martin Blumenstingl <martin.blumenstingl@xxxxxxxxxxxxxx>
    Signed-off-by: Kalle Valo <kvalo@xxxxxxxxxx>
    Link: https://lore.kernel.org/r/20230522202425.1827005-2-martin.blumenstingl@xxxxxxxxxxxxxx
    Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>

diff --git a/drivers/net/wireless/realtek/rtw88/sdio.c b/drivers/net/wireless/realtek/rtw88/sdio.c
index 06fce7c3addaa..2c1fb2dabd40a 100644
--- a/drivers/net/wireless/realtek/rtw88/sdio.c
+++ b/drivers/net/wireless/realtek/rtw88/sdio.c
@@ -998,9 +998,9 @@ static void rtw_sdio_rxfifo_recv(struct rtw_dev *rtwdev, u32 rx_len)
 
 static void rtw_sdio_rx_isr(struct rtw_dev *rtwdev)
 {
-	u32 rx_len, total_rx_bytes = 0;
+	u32 rx_len, hisr, total_rx_bytes = 0;
 
-	while (total_rx_bytes < SZ_64K) {
+	do {
 		if (rtw_chip_wcpu_11n(rtwdev))
 			rx_len = rtw_read16(rtwdev, REG_SDIO_RX0_REQ_LEN);
 		else
@@ -1012,7 +1012,25 @@ static void rtw_sdio_rx_isr(struct rtw_dev *rtwdev)
 		rtw_sdio_rxfifo_recv(rtwdev, rx_len);
 
 		total_rx_bytes += rx_len;
-	}
+
+		if (rtw_chip_wcpu_11n(rtwdev)) {
+			/* Stop if no more RX requests are pending, even if
+			 * rx_len could be greater than zero in the next
+			 * iteration. This is needed because the RX buffer may
+			 * already contain data while either HW or FW are not
+			 * done filling that buffer yet. Still reading the
+			 * buffer can result in packets where
+			 * rtw_rx_pkt_stat.pkt_len is zero or points beyond the
+			 * end of the buffer.
+			 */
+			hisr = rtw_read32(rtwdev, REG_SDIO_HISR);
+		} else {
+			/* RTW_WCPU_11AC chips have improved hardware or
+			 * firmware and can use rx_len unconditionally.
+			 */
+			hisr = REG_SDIO_HISR_RX_REQUEST;
+		}
+	} while (total_rx_bytes < SZ_64K && hisr & REG_SDIO_HISR_RX_REQUEST);
 }
 
 static void rtw_sdio_handle_interrupt(struct sdio_func *sdio_func)



[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux