wifi: rtw89: pci: validate RX tag for RXQ and RPQ
authorPing-Ke Shih <pkshih@realtek.com>
Sun, 21 Jan 2024 07:18:25 +0000 (15:18 +0800)
committerKalle Valo <kvalo@kernel.org>
Thu, 1 Feb 2024 10:15:42 +0000 (12:15 +0200)
PCI RX ring is a kind of read/write index ring, and DMA and ring index are
asynchronous, so suddenly driver gets newer index ahead before DMA. To
resolve this rare situation, we use a RX tag as helpers to make sure DMA
is done.

The RX tag is a 13-bit value, and range is from 1 ~ 0x1FFF, but 0 isn't
used so should be skipped.

Only enable this validation to coming WiFi 7 chips, because existing
chips use different design and don't really meet this situation.

Add missed rx_ring_eq_is_full for 8851BE by the way.

Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
Signed-off-by: Kalle Valo <kvalo@kernel.org>
Link: https://msgid.link/20240121071826.10159-4-pkshih@realtek.com
drivers/net/wireless/realtek/rtw89/pci.c
drivers/net/wireless/realtek/rtw89/pci.h
drivers/net/wireless/realtek/rtw89/rtw8851be.c
drivers/net/wireless/realtek/rtw89/rtw8852ae.c
drivers/net/wireless/realtek/rtw89/rtw8852be.c
drivers/net/wireless/realtek/rtw89/rtw8852ce.c
drivers/net/wireless/realtek/rtw89/rtw8922ae.c

index 8227dc5..b51ec3c 100644 (file)
@@ -155,8 +155,8 @@ static void rtw89_pci_sync_skb_for_device(struct rtw89_dev *rtwdev,
                                   DMA_FROM_DEVICE);
 }
 
-static int rtw89_pci_rxbd_info_update(struct rtw89_dev *rtwdev,
-                                     struct sk_buff *skb)
+static void rtw89_pci_rxbd_info_update(struct rtw89_dev *rtwdev,
+                                      struct sk_buff *skb)
 {
        struct rtw89_pci_rxbd_info *rxbd_info;
        struct rtw89_pci_rx_info *rx_info = RTW89_PCI_RX_SKB_CB(skb);
@@ -166,10 +166,58 @@ static int rtw89_pci_rxbd_info_update(struct rtw89_dev *rtwdev,
        rx_info->ls = le32_get_bits(rxbd_info->dword, RTW89_PCI_RXBD_LS);
        rx_info->len = le32_get_bits(rxbd_info->dword, RTW89_PCI_RXBD_WRITE_SIZE);
        rx_info->tag = le32_get_bits(rxbd_info->dword, RTW89_PCI_RXBD_TAG);
+}
+
+static int rtw89_pci_validate_rx_tag(struct rtw89_dev *rtwdev,
+                                    struct rtw89_pci_rx_ring *rx_ring,
+                                    struct sk_buff *skb)
+{
+       struct rtw89_pci_rx_info *rx_info = RTW89_PCI_RX_SKB_CB(skb);
+       const struct rtw89_pci_info *info = rtwdev->pci_info;
+       u32 target_rx_tag;
+
+       if (!info->check_rx_tag)
+               return 0;
+
+       /* valid range is 1 ~ 0x1FFF */
+       if (rx_ring->target_rx_tag == 0)
+               target_rx_tag = 1;
+       else
+               target_rx_tag = rx_ring->target_rx_tag;
+
+       if (rx_info->tag != target_rx_tag) {
+               rtw89_debug(rtwdev, RTW89_DBG_UNEXP, "mismatch RX tag 0x%x 0x%x\n",
+                           rx_info->tag, target_rx_tag);
+               return -EAGAIN;
+       }
 
        return 0;
 }
 
+static
+int rtw89_pci_sync_skb_for_device_and_validate_rx_info(struct rtw89_dev *rtwdev,
+                                                      struct rtw89_pci_rx_ring *rx_ring,
+                                                      struct sk_buff *skb)
+{
+       struct rtw89_pci_rx_info *rx_info = RTW89_PCI_RX_SKB_CB(skb);
+       int rx_tag_retry = 100;
+       int ret;
+
+       do {
+               rtw89_pci_sync_skb_for_cpu(rtwdev, skb);
+               rtw89_pci_rxbd_info_update(rtwdev, skb);
+
+               ret = rtw89_pci_validate_rx_tag(rtwdev, rx_ring, skb);
+               if (ret != -EAGAIN)
+                       break;
+       } while (rx_tag_retry--);
+
+       /* update target rx_tag for next RX */
+       rx_ring->target_rx_tag = rx_info->tag + 1;
+
+       return ret;
+}
+
 static void rtw89_pci_ctrl_txdma_ch_pcie(struct rtw89_dev *rtwdev, bool enable)
 {
        const struct rtw89_pci_info *info = rtwdev->pci_info;
@@ -259,9 +307,8 @@ static u32 rtw89_pci_rxbd_deliver_skbs(struct rtw89_dev *rtwdev,
 
        skb_idx = rtw89_pci_get_rx_skb_idx(rtwdev, bd_ring);
        skb = rx_ring->buf[skb_idx];
-       rtw89_pci_sync_skb_for_cpu(rtwdev, skb);
 
-       ret = rtw89_pci_rxbd_info_update(rtwdev, skb);
+       ret = rtw89_pci_sync_skb_for_device_and_validate_rx_info(rtwdev, rx_ring, skb);
        if (ret) {
                rtw89_err(rtwdev, "failed to update %d RXBD info: %d\n",
                          bd_ring->wp, ret);
@@ -549,9 +596,8 @@ static u32 rtw89_pci_release_tx_skbs(struct rtw89_dev *rtwdev,
 
        skb_idx = rtw89_pci_get_rx_skb_idx(rtwdev, bd_ring);
        skb = rx_ring->buf[skb_idx];
-       rtw89_pci_sync_skb_for_cpu(rtwdev, skb);
 
-       ret = rtw89_pci_rxbd_info_update(rtwdev, skb);
+       ret = rtw89_pci_sync_skb_for_device_and_validate_rx_info(rtwdev, rx_ring, skb);
        if (ret) {
                rtw89_err(rtwdev, "failed to update %d RXBD info: %d\n",
                          bd_ring->wp, ret);
@@ -1550,6 +1596,7 @@ static void rtw89_pci_reset_trx_rings(struct rtw89_dev *rtwdev)
                bd_ring->rp = 0;
                rx_ring->diliver_skb = NULL;
                rx_ring->diliver_desc.ready = false;
+               rx_ring->target_rx_tag = 0;
 
                rtw89_write16(rtwdev, addr_num, bd_ring->len);
                rtw89_write32(rtwdev, addr_desa_l, bd_ring->dma);
@@ -3213,6 +3260,7 @@ static int rtw89_pci_alloc_rx_ring(struct rtw89_dev *rtwdev,
        rx_ring->buf_sz = buf_sz;
        rx_ring->diliver_skb = NULL;
        rx_ring->diliver_desc.ready = false;
+       rx_ring->target_rx_tag = 0;
 
        for (i = 0; i < len; i++) {
                skb = dev_alloc_skb(buf_sz);
index 1fb7c20..0543221 100644 (file)
@@ -1235,6 +1235,7 @@ struct rtw89_pci_info {
        enum mac_ax_pcie_func_ctrl io_rcy_en;
        enum mac_ax_io_rcy_tmr io_rcy_tmr;
        bool rx_ring_eq_is_full;
+       bool check_rx_tag;
 
        u32 init_cfg_reg;
        u32 txhci_en_bit;
@@ -1277,7 +1278,7 @@ struct rtw89_pci_tx_data {
 
 struct rtw89_pci_rx_info {
        dma_addr_t dma;
-       u32 fs:1, ls:1, tag:11, len:14;
+       u32 fs:1, ls:1, tag:13, len:14;
 };
 
 #define RTW89_PCI_TXBD_OPTION_LS       BIT(14)
@@ -1406,6 +1407,7 @@ struct rtw89_pci_rx_ring {
        u32 buf_sz;
        struct sk_buff *diliver_skb;
        struct rtw89_rx_desc_info diliver_desc;
+       u32 target_rx_tag:13;
 };
 
 struct rtw89_pci_isrs {
index ade69bd..ca1374a 100644 (file)
@@ -25,6 +25,8 @@ static const struct rtw89_pci_info rtw8851b_pci_info = {
        .autok_en               = MAC_AX_PCIE_DISABLE,
        .io_rcy_en              = MAC_AX_PCIE_DISABLE,
        .io_rcy_tmr             = MAC_AX_IO_RCY_ANA_TMR_6MS,
+       .rx_ring_eq_is_full     = false,
+       .check_rx_tag           = false,
 
        .init_cfg_reg           = R_AX_PCIE_INIT_CFG1,
        .txhci_en_bit           = B_AX_TXHCI_EN,
index f1e890b..7c6ffed 100644 (file)
@@ -26,6 +26,7 @@ static const struct rtw89_pci_info rtw8852a_pci_info = {
        .io_rcy_en              = MAC_AX_PCIE_DISABLE,
        .io_rcy_tmr             = MAC_AX_IO_RCY_ANA_TMR_6MS,
        .rx_ring_eq_is_full     = false,
+       .check_rx_tag           = false,
 
        .init_cfg_reg           = R_AX_PCIE_INIT_CFG1,
        .txhci_en_bit           = B_AX_TXHCI_EN,
index 920b20b..ed71364 100644 (file)
@@ -26,6 +26,7 @@ static const struct rtw89_pci_info rtw8852b_pci_info = {
        .io_rcy_en              = MAC_AX_PCIE_DISABLE,
        .io_rcy_tmr             = MAC_AX_IO_RCY_ANA_TMR_6MS,
        .rx_ring_eq_is_full     = false,
+       .check_rx_tag           = false,
 
        .init_cfg_reg           = R_AX_PCIE_INIT_CFG1,
        .txhci_en_bit           = B_AX_TXHCI_EN,
index 4592de3..583ea67 100644 (file)
@@ -35,6 +35,7 @@ static const struct rtw89_pci_info rtw8852c_pci_info = {
        .io_rcy_en              = MAC_AX_PCIE_ENABLE,
        .io_rcy_tmr             = MAC_AX_IO_RCY_ANA_TMR_6MS,
        .rx_ring_eq_is_full     = false,
+       .check_rx_tag           = false,
 
        .init_cfg_reg           = R_AX_HAXI_INIT_CFG1,
        .txhci_en_bit           = B_AX_TXHCI_EN_V1,
index 7b3d98d..9f46fb1 100644 (file)
@@ -26,6 +26,7 @@ static const struct rtw89_pci_info rtw8922a_pci_info = {
        .io_rcy_en              = MAC_AX_PCIE_ENABLE,
        .io_rcy_tmr             = MAC_AX_IO_RCY_ANA_TMR_DEF,
        .rx_ring_eq_is_full     = true,
+       .check_rx_tag           = true,
 
        .init_cfg_reg           = R_BE_HAXI_INIT_CFG1,
        .txhci_en_bit           = B_BE_TXDMA_EN,