wifi: rtw88: Fix AP mode incorrect DTIM behavior
authorPo-Hao Huang <phhuang@realtek.com>
Fri, 16 Jun 2023 12:55:36 +0000 (20:55 +0800)
committerKalle Valo <kvalo@kernel.org>
Wed, 21 Jun 2023 09:41:45 +0000 (12:41 +0300)
Broadcast and multicast packets in high queue should be transmitted
all at once during DTIM. But without proper settings, hardware fails
to recognize that there are multiple packets and fetches only one.
Fix this by signaling hardware with more data bit set when there are
packets in the high queue.

Signed-off-by: Po-Hao Huang <phhuang@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
Signed-off-by: Kalle Valo <kvalo@kernel.org>
Link: https://lore.kernel.org/r/20230616125540.36877-3-pkshih@realtek.com
drivers/net/wireless/realtek/rtw88/mac80211.c
drivers/net/wireless/realtek/rtw88/reg.h
drivers/net/wireless/realtek/rtw88/tx.c
drivers/net/wireless/realtek/rtw88/tx.h
drivers/net/wireless/realtek/rtw88/usb.c

index 4241027902832892e577151a951325927000a97b..aacea2098df85ae8f7d6b5ccfd2a10366cafbede 100644 (file)
@@ -453,6 +453,7 @@ static int rtw_ops_start_ap(struct ieee80211_hw *hw,
        const struct rtw_chip_info *chip = rtwdev->chip;
 
        mutex_lock(&rtwdev->mutex);
+       rtw_write32_set(rtwdev, REG_TCR, BIT_TCR_UPDATE_HGQMD);
        rtwdev->ap_active = true;
        rtw_store_op_chan(rtwdev, true);
        chip->ops->phy_calibration(rtwdev);
@@ -468,6 +469,7 @@ static void rtw_ops_stop_ap(struct ieee80211_hw *hw,
        struct rtw_dev *rtwdev = hw->priv;
 
        mutex_lock(&rtwdev->mutex);
+       rtw_write32_clr(rtwdev, REG_TCR, BIT_TCR_UPDATE_HGQMD);
        rtwdev->ap_active = false;
        if (!rtw_core_check_sta_active(rtwdev))
                rtw_clear_op_chan(rtwdev);
index 2a2ae2081f34747643dd3b17fb289a19af6ad00e..60de9de1cc7a83cc5bd8eff95462422029cee2b1 100644 (file)
 #define REG_TCR                        0x0604
 #define BIT_PWRMGT_HWDATA_EN   BIT(7)
 #define BIT_TCR_UPDATE_TIMIE   BIT(5)
+#define BIT_TCR_UPDATE_HGQMD   BIT(4)
 #define REG_RCR                        0x0608
 #define BIT_APP_FCS            BIT(31)
 #define BIT_APP_MIC            BIT(30)
index c34f53890fe6537d0952d893d460964f6cfcb8fb..2821119dc9308e4ff8e9d8d5d0b655e7c7c69b0d 100644 (file)
@@ -35,6 +35,10 @@ void rtw_tx_stats(struct rtw_dev *rtwdev, struct ieee80211_vif *vif,
 void rtw_tx_fill_tx_desc(struct rtw_tx_pkt_info *pkt_info, struct sk_buff *skb)
 {
        struct rtw_tx_desc *tx_desc = (struct rtw_tx_desc *)skb->data;
+       bool more_data = false;
+
+       if (pkt_info->qsel == TX_DESC_QSEL_HIGH)
+               more_data = true;
 
        tx_desc->w0 = le32_encode_bits(pkt_info->tx_pkt_size, RTW_TX_DESC_W0_TXPKTSIZE) |
                      le32_encode_bits(pkt_info->offset, RTW_TX_DESC_W0_OFFSET) |
@@ -45,7 +49,8 @@ void rtw_tx_fill_tx_desc(struct rtw_tx_pkt_info *pkt_info, struct sk_buff *skb)
        tx_desc->w1 = le32_encode_bits(pkt_info->qsel, RTW_TX_DESC_W1_QSEL) |
                      le32_encode_bits(pkt_info->rate_id, RTW_TX_DESC_W1_RATE_ID) |
                      le32_encode_bits(pkt_info->sec_type, RTW_TX_DESC_W1_SEC_TYPE) |
-                     le32_encode_bits(pkt_info->pkt_offset, RTW_TX_DESC_W1_PKT_OFFSET);
+                     le32_encode_bits(pkt_info->pkt_offset, RTW_TX_DESC_W1_PKT_OFFSET) |
+                     le32_encode_bits(more_data, RTW_TX_DESC_W1_MORE_DATA);
 
        tx_desc->w2 = le32_encode_bits(pkt_info->ampdu_en, RTW_TX_DESC_W2_AGG_EN) |
                      le32_encode_bits(pkt_info->report, RTW_TX_DESC_W2_SPE_RPT) |
index 75cde861e924879d73616e38093b165e54c816e6..3241896062577ba771cc6225ae503c273856ada7 100644 (file)
@@ -31,6 +31,7 @@ struct rtw_tx_desc {
 #define RTW_TX_DESC_W1_RATE_ID GENMASK(20, 16)
 #define RTW_TX_DESC_W1_SEC_TYPE GENMASK(23, 22)
 #define RTW_TX_DESC_W1_PKT_OFFSET GENMASK(28, 24)
+#define RTW_TX_DESC_W1_MORE_DATA BIT(29)
 #define RTW_TX_DESC_W2_AGG_EN BIT(12)
 #define RTW_TX_DESC_W2_SPE_RPT BIT(19)
 #define RTW_TX_DESC_W2_AMPDU_DEN GENMASK(22, 20)
index 0529ae24f53b0426de6c3352a2b34d71a752db5d..4a57efdba97bbf3f9a79ae9b38f911934f20136a 100644 (file)
@@ -469,6 +469,9 @@ static u8 rtw_usb_tx_queue_mapping_to_qsel(struct sk_buff *skb)
 
        if (unlikely(ieee80211_is_mgmt(fc) || ieee80211_is_ctl(fc)))
                qsel = TX_DESC_QSEL_MGMT;
+       else if (is_broadcast_ether_addr(hdr->addr1) ||
+                is_multicast_ether_addr(hdr->addr1))
+               qsel = TX_DESC_QSEL_HIGH;
        else if (skb_get_queue_mapping(skb) <= IEEE80211_AC_BK)
                qsel = skb->priority;
        else