Commit f4a43c3b authored by Dian-Syuan Yang's avatar Dian-Syuan Yang Committed by Kalle Valo

wifi: rtw89: support for processing P2P power saving

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: default avatarDian-Syuan Yang <dian_syuan0116@realtek.com>
Signed-off-by: default avatarPing-Ke Shih <pkshih@realtek.com>
Signed-off-by: default avatarKalle Valo <kvalo@kernel.org>
Link: https://lore.kernel.org/r/20220922010435.12167-6-pkshih@realtek.com
parent 71392bb2
......@@ -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;
......
......@@ -931,6 +931,58 @@ int rtw89_fw_h2c_lps_parm(struct rtw89_dev *rtwdev,
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 @@ int rtw89_fw_h2c_set_edca(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
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)
{
......
......@@ -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)
{
......
......@@ -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
......
......@@ -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,
};
......
......@@ -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);
}
......
......@@ -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);
}
......@@ -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
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment