wifi: rtw89: provide functions to configure NoA for beacon update
authorZong-Zhe Yang <kevin_yang@realtek.com>
Wed, 16 Aug 2023 08:21:32 +0000 (16:21 +0800)
committerKalle Valo <kvalo@kernel.org>
Fri, 25 Aug 2023 09:58:29 +0000 (12:58 +0300)
Callers call renew function when wanting to generate a new P2P NoA
information element, and call append function to append NoA attribute
one by one. Then, updating beacon work will fetch the P2P NoA information
element configured by callers and add it to beacon.

The use case of MCC (multi-channel concurrent) <GO + STA> for example:
* start MCC - GO part
renew P2P NoA
append period NoA after calculation
* download beacon for GO
fetch P2P NoA and add to beacon content
* stop MCC - GO part
renew P2P NoA (reset)

Signed-off-by: Zong-Zhe Yang <kevin_yang@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/20230816082133.57474-6-pkshih@realtek.com
drivers/net/wireless/realtek/rtw89/core.h
drivers/net/wireless/realtek/rtw89/fw.c
drivers/net/wireless/realtek/rtw89/ps.c
drivers/net/wireless/realtek/rtw89/ps.h

index 257582fc39ea59fc7553830ed0d5b23c9457373b..431b0d3daa2a29a5be0d2af292567e4630744de3 100644 (file)
@@ -2896,6 +2896,32 @@ struct rtw89_roc {
 
 #define RTW89_P2P_MAX_NOA_NUM 2
 
+struct rtw89_p2p_ie_head {
+       u8 eid;
+       u8 ie_len;
+       u8 oui[3];
+       u8 oui_type;
+} __packed;
+
+struct rtw89_noa_attr_head {
+       u8 attr_type;
+       __le16 attr_len;
+       u8 index;
+       u8 oppps_ctwindow;
+} __packed;
+
+struct rtw89_p2p_noa_ie {
+       struct rtw89_p2p_ie_head p2p_head;
+       struct rtw89_noa_attr_head noa_head;
+       struct ieee80211_p2p_noa_desc noa_desc[RTW89_P2P_MAX_NOA_NUM];
+} __packed;
+
+struct rtw89_p2p_noa_setter {
+       struct rtw89_p2p_noa_ie ie;
+       u8 noa_count;
+       u8 noa_index;
+};
+
 struct rtw89_vif {
        struct list_head list;
        struct rtw89_dev *rtwdev;
@@ -2938,6 +2964,7 @@ struct rtw89_vif {
        struct cfg80211_scan_request *scan_req;
        struct ieee80211_scan_ies *scan_ies;
        struct list_head general_pkt_list;
+       struct rtw89_p2p_noa_setter p2p_noa;
 };
 
 enum rtw89_lv1_rcvy_step {
index 4c044dbc90b6d5ffcae6edb551c562a35e5ef40c..772b0f107f40edf770ca71f40e9becfb45a33d6f 100644 (file)
@@ -9,6 +9,7 @@
 #include "fw.h"
 #include "mac.h"
 #include "phy.h"
+#include "ps.h"
 #include "reg.h"
 #include "util.h"
 
@@ -1923,6 +1924,8 @@ int rtw89_fw_h2c_update_beacon(struct rtw89_dev *rtwdev,
        u16 tim_offset;
        int bcn_total_len;
        u16 beacon_rate;
+       void *noa_data;
+       u8 noa_len;
        int ret;
 
        if (vif->p2p)
@@ -1939,6 +1942,13 @@ int rtw89_fw_h2c_update_beacon(struct rtw89_dev *rtwdev,
                return -ENOMEM;
        }
 
+       noa_len = rtw89_p2p_noa_fetch(rtwvif, &noa_data);
+       if (noa_len &&
+           (noa_len <= skb_tailroom(skb_beacon) ||
+            pskb_expand_head(skb_beacon, 0, noa_len, GFP_KERNEL) == 0)) {
+               skb_put_data(skb_beacon, noa_data, noa_len);
+       }
+
        bcn_total_len = H2C_BCN_BASE_LEN + skb_beacon->len;
        skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, bcn_total_len);
        if (!skb) {
index 84201ef19c176c9426ac2cbeb3bbbc7a760d83a5..b98ec178abe123ecd5b12e7a7bfee53418dc9a95 100644 (file)
@@ -278,3 +278,64 @@ void rtw89_recalc_lps(struct rtw89_dev *rtwdev)
                rtwdev->lps_enabled = false;
        }
 }
+
+void rtw89_p2p_noa_renew(struct rtw89_vif *rtwvif)
+{
+       struct rtw89_p2p_noa_setter *setter = &rtwvif->p2p_noa;
+       struct rtw89_p2p_noa_ie *ie = &setter->ie;
+       struct rtw89_p2p_ie_head *p2p_head = &ie->p2p_head;
+       struct rtw89_noa_attr_head *noa_head = &ie->noa_head;
+
+       if (setter->noa_count) {
+               setter->noa_index++;
+               setter->noa_count = 0;
+       }
+
+       memset(ie, 0, sizeof(*ie));
+
+       p2p_head->eid = WLAN_EID_VENDOR_SPECIFIC;
+       p2p_head->ie_len = 4 + sizeof(*noa_head);
+       p2p_head->oui[0] = (WLAN_OUI_WFA >> 16) & 0xff;
+       p2p_head->oui[1] = (WLAN_OUI_WFA >> 8) & 0xff;
+       p2p_head->oui[2] = (WLAN_OUI_WFA >> 0) & 0xff;
+       p2p_head->oui_type = WLAN_OUI_TYPE_WFA_P2P;
+
+       noa_head->attr_type = IEEE80211_P2P_ATTR_ABSENCE_NOTICE;
+       noa_head->attr_len = cpu_to_le16(2);
+       noa_head->index = setter->noa_index;
+       noa_head->oppps_ctwindow = 0;
+}
+
+void rtw89_p2p_noa_append(struct rtw89_vif *rtwvif,
+                         const struct ieee80211_p2p_noa_desc *desc)
+{
+       struct rtw89_p2p_noa_setter *setter = &rtwvif->p2p_noa;
+       struct rtw89_p2p_noa_ie *ie = &setter->ie;
+       struct rtw89_p2p_ie_head *p2p_head = &ie->p2p_head;
+       struct rtw89_noa_attr_head *noa_head = &ie->noa_head;
+
+       if (!desc->count || !desc->duration)
+               return;
+
+       if (setter->noa_count >= RTW89_P2P_MAX_NOA_NUM)
+               return;
+
+       p2p_head->ie_len += sizeof(*desc);
+       le16_add_cpu(&noa_head->attr_len, sizeof(*desc));
+
+       ie->noa_desc[setter->noa_count++] = *desc;
+}
+
+u8 rtw89_p2p_noa_fetch(struct rtw89_vif *rtwvif, void **data)
+{
+       struct rtw89_p2p_noa_setter *setter = &rtwvif->p2p_noa;
+       struct rtw89_p2p_noa_ie *ie = &setter->ie;
+       void *tail;
+
+       if (!setter->noa_count)
+               return 0;
+
+       *data = ie;
+       tail = ie->noa_desc + setter->noa_count;
+       return tail - *data;
+}
index 4c18f49204b285aaaf2ce3a7cf6ea57b0622163e..aff0fba71cb0b73a83c8b28c191c64594f6a2709 100644 (file)
@@ -16,6 +16,10 @@ void rtw89_leave_ips(struct rtw89_dev *rtwdev);
 void rtw89_set_coex_ctrl_lps(struct rtw89_dev *rtwdev, bool btc_ctrl);
 void rtw89_process_p2p_ps(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif);
 void rtw89_recalc_lps(struct rtw89_dev *rtwdev);
+void rtw89_p2p_noa_renew(struct rtw89_vif *rtwvif);
+void rtw89_p2p_noa_append(struct rtw89_vif *rtwvif,
+                         const struct ieee80211_p2p_noa_desc *desc);
+u8 rtw89_p2p_noa_fetch(struct rtw89_vif *rtwvif, void **data);
 
 static inline void rtw89_leave_ips_by_hwflags(struct rtw89_dev *rtwdev)
 {