wifi: rtw89: support for processing P2P power saving
authorDian-Syuan Yang <dian_syuan0116@realtek.com>
Thu, 22 Sep 2022 01:04:35 +0000 (09:04 +0800)
committerKalle Valo <kvalo@kernel.org>
Sat, 24 Sep 2022 12:36:28 +0000 (15:36 +0300)
Support P2P client to process Notice of Absence (NoA) mechanism when it
connects with P2P GO applying an NoA schedule. We define some action
types including init, update, remove and terminate in h2c function to
enable/disable NoA schedule.

Signed-off-by: Dian-Syuan Yang <dian_syuan0116@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/20220922010435.12167-6-pkshih@realtek.com
drivers/net/wireless/realtek/rtw89/core.h
drivers/net/wireless/realtek/rtw89/fw.c
drivers/net/wireless/realtek/rtw89/fw.h
drivers/net/wireless/realtek/rtw89/mac.c
drivers/net/wireless/realtek/rtw89/mac.h
drivers/net/wireless/realtek/rtw89/mac80211.c
drivers/net/wireless/realtek/rtw89/ps.c
drivers/net/wireless/realtek/rtw89/ps.h

index 3b184e3031d48990082593d4639fe06b6c6f36b8..c0f798ad60c2a6f128ab5612ab80c7b6d685758a 100644 (file)
@@ -2205,6 +2205,8 @@ struct rtw89_phy_rate_pattern {
        bool enable;
 };
 
+#define RTW89_P2P_MAX_NOA_NUM 2
+
 struct rtw89_vif {
        struct list_head list;
        struct rtw89_dev *rtwdev;
@@ -2220,6 +2222,7 @@ struct rtw89_vif {
        u8 wmm;
        u8 bcn_hit_cond;
        u8 hit_rule;
+       u8 last_noa_nr;
        bool trigger;
        bool lsig_txop;
        u8 tgt_ind;
index e4b12cdeb2de6b2e3963c7a84c29e090b3c73042..d57e3610fb88ec8735fa4cb97805ee59aff4b95b 100644 (file)
@@ -931,6 +931,58 @@ fail:
        return ret;
 }
 
+#define H2C_P2P_ACT_LEN 20
+int rtw89_fw_h2c_p2p_act(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif,
+                        struct ieee80211_p2p_noa_desc *desc,
+                        u8 act, u8 noa_id)
+{
+       struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
+       bool p2p_type_gc = rtwvif->wifi_role == RTW89_WIFI_ROLE_P2P_CLIENT;
+       u8 ctwindow_oppps = vif->bss_conf.p2p_noa_attr.oppps_ctwindow;
+       struct sk_buff *skb;
+       u8 *cmd;
+       int ret;
+
+       skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_P2P_ACT_LEN);
+       if (!skb) {
+               rtw89_err(rtwdev, "failed to alloc skb for h2c p2p act\n");
+               return -ENOMEM;
+       }
+       skb_put(skb, H2C_P2P_ACT_LEN);
+       cmd = skb->data;
+
+       RTW89_SET_FWCMD_P2P_MACID(cmd, rtwvif->mac_id);
+       RTW89_SET_FWCMD_P2P_P2PID(cmd, 0);
+       RTW89_SET_FWCMD_P2P_NOAID(cmd, noa_id);
+       RTW89_SET_FWCMD_P2P_ACT(cmd, act);
+       RTW89_SET_FWCMD_P2P_TYPE(cmd, p2p_type_gc);
+       RTW89_SET_FWCMD_P2P_ALL_SLEP(cmd, 0);
+       if (desc) {
+               RTW89_SET_FWCMD_NOA_START_TIME(cmd, desc->start_time);
+               RTW89_SET_FWCMD_NOA_INTERVAL(cmd, desc->interval);
+               RTW89_SET_FWCMD_NOA_DURATION(cmd, desc->duration);
+               RTW89_SET_FWCMD_NOA_COUNT(cmd, desc->count);
+               RTW89_SET_FWCMD_NOA_CTWINDOW(cmd, ctwindow_oppps);
+       }
+
+       rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
+                             H2C_CAT_MAC, H2C_CL_MAC_PS,
+                             H2C_FUNC_P2P_ACT, 0, 0,
+                             H2C_P2P_ACT_LEN);
+
+       ret = rtw89_h2c_tx(rtwdev, skb, false);
+       if (ret) {
+               rtw89_err(rtwdev, "failed to send h2c\n");
+               goto fail;
+       }
+
+       return 0;
+fail:
+       dev_kfree_skb_any(skb);
+
+       return ret;
+}
+
 static void __rtw89_fw_h2c_set_tx_path(struct rtw89_dev *rtwdev,
                                       struct sk_buff *skb)
 {
@@ -1447,6 +1499,46 @@ fail:
        return ret;
 }
 
+#define H2C_TSF32_TOGL_LEN 4
+int rtw89_fw_h2c_tsf32_toggle(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
+                             bool en)
+{
+       struct sk_buff *skb;
+       u16 early_us = en ? 2000 : 0;
+       u8 *cmd;
+       int ret;
+
+       skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_TSF32_TOGL_LEN);
+       if (!skb) {
+               rtw89_err(rtwdev, "failed to alloc skb for h2c p2p act\n");
+               return -ENOMEM;
+       }
+       skb_put(skb, H2C_TSF32_TOGL_LEN);
+       cmd = skb->data;
+
+       RTW89_SET_FWCMD_TSF32_TOGL_BAND(cmd, rtwvif->mac_idx);
+       RTW89_SET_FWCMD_TSF32_TOGL_EN(cmd, en);
+       RTW89_SET_FWCMD_TSF32_TOGL_PORT(cmd, rtwvif->port);
+       RTW89_SET_FWCMD_TSF32_TOGL_EARLY(cmd, early_us);
+
+       rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
+                             H2C_CAT_MAC, H2C_CL_MAC_FW_OFLD,
+                             H2C_FUNC_TSF32_TOGL, 0, 0,
+                             H2C_TSF32_TOGL_LEN);
+
+       ret = rtw89_h2c_tx(rtwdev, skb, false);
+       if (ret) {
+               rtw89_err(rtwdev, "failed to send h2c\n");
+               goto fail;
+       }
+
+       return 0;
+fail:
+       dev_kfree_skb_any(skb);
+
+       return ret;
+}
+
 #define H2C_OFLD_CFG_LEN 8
 int rtw89_fw_h2c_set_ofld_cfg(struct rtw89_dev *rtwdev)
 {
index 249a46340853488834a00c0a715f56e96e273bd5..0047d5d0e9b193a90ddd727dc532cdb005799be0 100644 (file)
@@ -155,6 +155,13 @@ enum rtw89_chan_type {
        RTW89_CHAN_DFS,
 };
 
+enum rtw89_p2pps_action {
+       RTW89_P2P_ACT_INIT = 0,
+       RTW89_P2P_ACT_UPDATE = 1,
+       RTW89_P2P_ACT_REMOVE = 2,
+       RTW89_P2P_ACT_TERMINATE = 3,
+};
+
 #define FWDL_SECTION_MAX_NUM 10
 #define FWDL_SECTION_CHKSUM_LEN        8
 #define FWDL_SECTION_PER_PKT_LEN 2020
@@ -2442,6 +2449,86 @@ static inline void RTW89_SET_FWCMD_SCANOFLD_TSF_SLOW(void *cmd, u32 val)
        le32p_replace_bits((__le32 *)((u8 *)(cmd) + 16), val, GENMASK(31, 0));
 }
 
+static inline void RTW89_SET_FWCMD_P2P_MACID(void *cmd, u32 val)
+{
+       le32p_replace_bits((__le32 *)cmd, val, GENMASK(7, 0));
+}
+
+static inline void RTW89_SET_FWCMD_P2P_P2PID(void *cmd, u32 val)
+{
+       le32p_replace_bits((__le32 *)cmd, val, GENMASK(11, 8));
+}
+
+static inline void RTW89_SET_FWCMD_P2P_NOAID(void *cmd, u32 val)
+{
+       le32p_replace_bits((__le32 *)cmd, val, GENMASK(15, 12));
+}
+
+static inline void RTW89_SET_FWCMD_P2P_ACT(void *cmd, u32 val)
+{
+       le32p_replace_bits((__le32 *)cmd, val, GENMASK(19, 16));
+}
+
+static inline void RTW89_SET_FWCMD_P2P_TYPE(void *cmd, u32 val)
+{
+       le32p_replace_bits((__le32 *)cmd, val, BIT(20));
+}
+
+static inline void RTW89_SET_FWCMD_P2P_ALL_SLEP(void *cmd, u32 val)
+{
+       le32p_replace_bits((__le32 *)cmd, val, BIT(21));
+}
+
+static inline void RTW89_SET_FWCMD_NOA_START_TIME(void *cmd, __le32 val)
+{
+       *((__le32 *)cmd + 1) = val;
+}
+
+static inline void RTW89_SET_FWCMD_NOA_INTERVAL(void *cmd, __le32 val)
+{
+       *((__le32 *)cmd + 2) = val;
+}
+
+static inline void RTW89_SET_FWCMD_NOA_DURATION(void *cmd, __le32 val)
+{
+       *((__le32 *)cmd + 3) = val;
+}
+
+static inline void RTW89_SET_FWCMD_NOA_COUNT(void *cmd, u32 val)
+{
+       le32p_replace_bits((__le32 *)(cmd) + 4, val, GENMASK(7, 0));
+}
+
+static inline void RTW89_SET_FWCMD_NOA_CTWINDOW(void *cmd, u32 val)
+{
+       u8 ctwnd;
+
+       if (!(val & IEEE80211_P2P_OPPPS_ENABLE_BIT))
+               return;
+       ctwnd = FIELD_GET(IEEE80211_P2P_OPPPS_CTWINDOW_MASK, val);
+       le32p_replace_bits((__le32 *)(cmd) + 4, ctwnd, GENMASK(23, 8));
+}
+
+static inline void RTW89_SET_FWCMD_TSF32_TOGL_BAND(void *cmd, u32 val)
+{
+       le32p_replace_bits((__le32 *)cmd, val, BIT(0));
+}
+
+static inline void RTW89_SET_FWCMD_TSF32_TOGL_EN(void *cmd, u32 val)
+{
+       le32p_replace_bits((__le32 *)cmd, val, BIT(1));
+}
+
+static inline void RTW89_SET_FWCMD_TSF32_TOGL_PORT(void *cmd, u32 val)
+{
+       le32p_replace_bits((__le32 *)cmd, val, GENMASK(4, 2));
+}
+
+static inline void RTW89_SET_FWCMD_TSF32_TOGL_EARLY(void *cmd, u32 val)
+{
+       le32p_replace_bits((__le32 *)cmd, val, GENMASK(31, 16));
+}
+
 #define RTW89_C2H_HEADER_LEN 8
 
 #define RTW89_GET_C2H_CATEGORY(c2h) \
@@ -2592,6 +2679,7 @@ struct rtw89_fw_h2c_rf_reg_info {
 /* CLASS 2 - PS */
 #define H2C_CL_MAC_PS                  0x2
 #define H2C_FUNC_MAC_LPS_PARM          0x0
+#define H2C_FUNC_P2P_ACT               0x1
 
 /* CLASS 3 - FW download */
 #define H2C_CL_MAC_FWDL                0x3
@@ -2618,6 +2706,7 @@ struct rtw89_fw_h2c_rf_reg_info {
 #define H2C_FUNC_PACKET_OFLD           0x1
 #define H2C_FUNC_MAC_MACID_PAUSE       0x8
 #define H2C_FUNC_USR_EDCA              0xF
+#define H2C_FUNC_TSF32_TOGL            0x10
 #define H2C_FUNC_OFLD_CFG              0x14
 #define H2C_FUNC_ADD_SCANOFLD_CH       0x16
 #define H2C_FUNC_SCANOFLD              0x17
@@ -2751,6 +2840,11 @@ void rtw89_hw_scan_abort(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif);
 int rtw89_fw_h2c_trigger_cpu_exception(struct rtw89_dev *rtwdev);
 int rtw89_fw_h2c_pkt_drop(struct rtw89_dev *rtwdev,
                          const struct rtw89_pkt_drop_params *params);
+int rtw89_fw_h2c_p2p_act(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif,
+                        struct ieee80211_p2p_noa_desc *desc,
+                        u8 act, u8 noa_id);
+int rtw89_fw_h2c_tsf32_toggle(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
+                             bool en);
 
 static inline void rtw89_fw_h2c_init_ba_cam(struct rtw89_dev *rtwdev)
 {
index dad55952e6bdcfe3eee9652ebead855e28ac3beb..d5a2e30a4ba0de213a0764d09ad531a7b5258c4f 100644 (file)
@@ -3843,6 +3843,12 @@ rtw89_mac_c2h_pkt_ofld_rsp(struct rtw89_dev *rtwdev, struct sk_buff *c2h,
 {
 }
 
+static void
+rtw89_mac_c2h_tsf32_toggle_rpt(struct rtw89_dev *rtwdev, struct sk_buff *c2h,
+                              u32 len)
+{
+}
+
 static
 void (* const rtw89_mac_c2h_ofld_handler[])(struct rtw89_dev *rtwdev,
                                            struct sk_buff *c2h, u32 len) = {
@@ -3852,6 +3858,7 @@ void (* const rtw89_mac_c2h_ofld_handler[])(struct rtw89_dev *rtwdev,
        [RTW89_MAC_C2H_FUNC_BCN_RESEND] = NULL,
        [RTW89_MAC_C2H_FUNC_MACID_PAUSE] = rtw89_mac_c2h_macid_pause,
        [RTW89_MAC_C2H_FUNC_SCANOFLD_RSP] = rtw89_mac_c2h_scanofld_rsp,
+       [RTW89_MAC_C2H_FUNC_TSF32_TOGL_RPT] = rtw89_mac_c2h_tsf32_toggle_rpt,
 };
 
 static
index 22db80716b56077a3613507d1f5ca3b120da99b7..9cb5d20e6e33a0c45850d0f8bcbf4de76bb7800a 100644 (file)
@@ -306,6 +306,7 @@ enum rtw89_mac_c2h_ofld_func {
        RTW89_MAC_C2H_FUNC_PKT_OFLD_RSP,
        RTW89_MAC_C2H_FUNC_BCN_RESEND,
        RTW89_MAC_C2H_FUNC_MACID_PAUSE,
+       RTW89_MAC_C2H_FUNC_TSF32_TOGL_RPT = 0x6,
        RTW89_MAC_C2H_FUNC_SCANOFLD_RSP = 0x9,
        RTW89_MAC_C2H_FUNC_OFLD_MAX,
 };
index 70f555887c6eace70c8fd2de3ac2d0a96ff22dcf..cf70570087bf80fc5d1e7c5eae107256c25b1751 100644 (file)
@@ -407,6 +407,9 @@ static void rtw89_ops_bss_info_changed(struct ieee80211_hw *hw,
        if (changed & BSS_CHANGED_MU_GROUPS)
                rtw89_mac_bf_set_gid_table(rtwdev, vif, conf);
 
+       if (changed & BSS_CHANGED_P2P_PS)
+               rtw89_process_p2p_ps(rtwdev, vif);
+
        mutex_unlock(&rtwdev->mutex);
 }
 
index 3c56a5ef40f841ed8a60d77216cab8db9bffe291..bf41a1141679291748b275f7a9bcb13b7e87c545 100644 (file)
@@ -183,3 +183,64 @@ void rtw89_set_coex_ctrl_lps(struct rtw89_dev *rtwdev, bool btc_ctrl)
        if (btc_ctrl)
                rtw89_leave_lps(rtwdev);
 }
+
+static void rtw89_tsf32_toggle(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
+                              enum rtw89_p2pps_action act)
+{
+       if (act == RTW89_P2P_ACT_UPDATE || act == RTW89_P2P_ACT_REMOVE)
+               return;
+
+       if (act == RTW89_P2P_ACT_INIT)
+               rtw89_fw_h2c_tsf32_toggle(rtwdev, rtwvif, true);
+       else if (act == RTW89_P2P_ACT_TERMINATE)
+               rtw89_fw_h2c_tsf32_toggle(rtwdev, rtwvif, false);
+}
+
+static void rtw89_p2p_disable_all_noa(struct rtw89_dev *rtwdev,
+                                     struct ieee80211_vif *vif)
+{
+       struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
+       enum rtw89_p2pps_action act;
+       u8 noa_id;
+
+       if (rtwvif->last_noa_nr == 0)
+               return;
+
+       for (noa_id = 0; noa_id < rtwvif->last_noa_nr; noa_id++) {
+               if (noa_id == rtwvif->last_noa_nr - 1)
+                       act = RTW89_P2P_ACT_TERMINATE;
+               else
+                       act = RTW89_P2P_ACT_REMOVE;
+               rtw89_tsf32_toggle(rtwdev, rtwvif, act);
+               rtw89_fw_h2c_p2p_act(rtwdev, vif, NULL, act, noa_id);
+       }
+}
+
+static void rtw89_p2p_update_noa(struct rtw89_dev *rtwdev,
+                                struct ieee80211_vif *vif)
+{
+       struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
+       struct ieee80211_p2p_noa_desc *desc;
+       enum rtw89_p2pps_action act;
+       u8 noa_id;
+
+       for (noa_id = 0; noa_id < RTW89_P2P_MAX_NOA_NUM; noa_id++) {
+               desc = &vif->bss_conf.p2p_noa_attr.desc[noa_id];
+               if (!desc->count || !desc->duration)
+                       break;
+
+               if (noa_id == 0)
+                       act = RTW89_P2P_ACT_INIT;
+               else
+                       act = RTW89_P2P_ACT_UPDATE;
+               rtw89_tsf32_toggle(rtwdev, rtwvif, act);
+               rtw89_fw_h2c_p2p_act(rtwdev, vif, desc, act, noa_id);
+       }
+       rtwvif->last_noa_nr = noa_id;
+}
+
+void rtw89_process_p2p_ps(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif)
+{
+       rtw89_p2p_disable_all_noa(rtwdev, vif);
+       rtw89_p2p_update_noa(rtwdev, vif);
+}
index 7d371293d6bc9ca295436762be5dbdf8f6d02e53..0feae39916238a6b17202b6446f0b57022737664 100644 (file)
@@ -12,5 +12,6 @@ void rtw89_leave_ps_mode(struct rtw89_dev *rtwdev);
 void rtw89_enter_ips(struct rtw89_dev *rtwdev);
 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);
 
 #endif