diff options
Diffstat (limited to 'drivers/net/wireless/realtek/rtw89/fw.c')
-rw-r--r-- | drivers/net/wireless/realtek/rtw89/fw.c | 448 |
1 files changed, 396 insertions, 52 deletions
diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index fbe08c162b93..47aa365991c1 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -670,6 +670,10 @@ static const struct __fw_feat_cfg fw_feat_tbl[] = { __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 26, 0, TX_WAKE), __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 29, 0, CRASH_TRIGGER), __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 29, 0, SCAN_OFFLOAD), + __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 74, 0, NO_LPS_PG), + __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 74, 0, TX_WAKE), + __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 90, 0, CRASH_TRIGGER), + __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 91, 0, SCAN_OFFLOAD), __CFG_FW_FEAT(RTL8852C, le, 0, 27, 33, 0, NO_DEEP_PS), __CFG_FW_FEAT(RTL8852C, ge, 0, 27, 34, 0, TX_WAKE), __CFG_FW_FEAT(RTL8852C, ge, 0, 27, 36, 0, SCAN_OFFLOAD), @@ -679,8 +683,10 @@ static const struct __fw_feat_cfg fw_feat_tbl[] = { __CFG_FW_FEAT(RTL8922A, ge, 0, 34, 30, 0, CRASH_TRIGGER), __CFG_FW_FEAT(RTL8922A, ge, 0, 34, 11, 0, MACID_PAUSE_SLEEP), __CFG_FW_FEAT(RTL8922A, ge, 0, 34, 35, 0, SCAN_OFFLOAD), + __CFG_FW_FEAT(RTL8922A, lt, 0, 35, 21, 0, SCAN_OFFLOAD_BE_V0), __CFG_FW_FEAT(RTL8922A, ge, 0, 35, 12, 0, BEACON_FILTER), __CFG_FW_FEAT(RTL8922A, ge, 0, 35, 22, 0, WOW_REASON_V1), + __CFG_FW_FEAT(RTL8922A, lt, 0, 35, 31, 0, RFK_PRE_NOTIFY_V0), }; static void rtw89_fw_iterate_feature_cfg(struct rtw89_fw_info *fw, @@ -2491,7 +2497,7 @@ fail: int rtw89_fw_h2c_lps_ch_info(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) { const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, - rtwvif->sub_entity_idx); + rtwvif->chanctx_idx); const struct rtw89_chip_info *chip = rtwdev->chip; struct rtw89_h2c_lps_ch_info *h2c; u32 len = sizeof(*h2c); @@ -2810,7 +2816,7 @@ int rtw89_fw_h2c_assoc_cmac_tbl(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta = sta_to_rtwsta_safe(sta); struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, - rtwvif->sub_entity_idx); + rtwvif->chanctx_idx); struct sk_buff *skb; u8 pads[RTW89_PPE_BW_NUM]; u8 mac_id = rtwsta ? rtwsta->mac_id : rtwvif->mac_id; @@ -2943,9 +2949,9 @@ int rtw89_fw_h2c_assoc_cmac_tbl_g7(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { - const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; struct rtw89_sta *rtwsta = sta_to_rtwsta_safe(sta); + const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, rtwvif->chanctx_idx); u8 mac_id = rtwsta ? rtwsta->mac_id : rtwvif->mac_id; struct rtw89_h2c_cctlinfo_ud_g7 *h2c; u8 pads[RTW89_PPE_BW_NUM]; @@ -3206,7 +3212,7 @@ int rtw89_fw_h2c_update_beacon(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) { const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, - rtwvif->sub_entity_idx); + rtwvif->chanctx_idx); struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); struct rtw89_h2c_bcn_upd *h2c; struct sk_buff *skb_beacon; @@ -3285,7 +3291,7 @@ EXPORT_SYMBOL(rtw89_fw_h2c_update_beacon); int rtw89_fw_h2c_update_beacon_be(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) { - const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); + const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, rtwvif->chanctx_idx); struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); struct rtw89_h2c_bcn_upd_be *h2c; struct sk_buff *skb_beacon; @@ -4802,16 +4808,20 @@ int rtw89_fw_h2c_scan_list_offload_be(struct rtw89_dev *rtwdev, int ch_num, return 0; } -int rtw89_fw_h2c_scan_offload(struct rtw89_dev *rtwdev, - struct rtw89_scan_option *option, - struct rtw89_vif *rtwvif) +#define RTW89_SCAN_DELAY_TSF_UNIT 104800 +int rtw89_fw_h2c_scan_offload_ax(struct rtw89_dev *rtwdev, + struct rtw89_scan_option *option, + struct rtw89_vif *rtwvif, + bool wowlan) { struct rtw89_wait_info *wait = &rtwdev->mac.fw_ofld_wait; struct rtw89_chan *op = &rtwdev->scan_info.op_chan; + enum rtw89_scan_mode scan_mode = RTW89_SCAN_IMMEDIATE; struct rtw89_h2c_scanofld *h2c; u32 len = sizeof(*h2c); struct sk_buff *skb; unsigned int cond; + u64 tsf = 0; int ret; skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); @@ -4822,6 +4832,17 @@ int rtw89_fw_h2c_scan_offload(struct rtw89_dev *rtwdev, skb_put(skb, len); h2c = (struct rtw89_h2c_scanofld *)skb->data; + if (option->delay) { + ret = rtw89_mac_port_get_tsf(rtwdev, rtwvif, &tsf); + if (ret) { + rtw89_warn(rtwdev, "NLO failed to get port tsf: %d\n", ret); + scan_mode = RTW89_SCAN_IMMEDIATE; + } else { + scan_mode = RTW89_SCAN_DELAY; + tsf += option->delay * RTW89_SCAN_DELAY_TSF_UNIT; + } + } + h2c->w0 = le32_encode_bits(rtwvif->mac_id, RTW89_H2C_SCANOFLD_W0_MACID) | le32_encode_bits(rtwvif->port, RTW89_H2C_SCANOFLD_W0_PORT_ID) | le32_encode_bits(RTW89_PHY_0, RTW89_H2C_SCANOFLD_W0_BAND) | @@ -4830,9 +4851,11 @@ int rtw89_fw_h2c_scan_offload(struct rtw89_dev *rtwdev, h2c->w1 = le32_encode_bits(true, RTW89_H2C_SCANOFLD_W1_NOTIFY_END) | le32_encode_bits(option->target_ch_mode, RTW89_H2C_SCANOFLD_W1_TARGET_CH_MODE) | - le32_encode_bits(RTW89_SCAN_IMMEDIATE, - RTW89_H2C_SCANOFLD_W1_START_MODE) | - le32_encode_bits(RTW89_SCAN_ONCE, RTW89_H2C_SCANOFLD_W1_SCAN_TYPE); + le32_encode_bits(scan_mode, RTW89_H2C_SCANOFLD_W1_START_MODE) | + le32_encode_bits(option->repeat, RTW89_H2C_SCANOFLD_W1_SCAN_TYPE); + + h2c->w2 = le32_encode_bits(option->norm_pd, RTW89_H2C_SCANOFLD_W2_NORM_PD) | + le32_encode_bits(option->slow_pd, RTW89_H2C_SCANOFLD_W2_SLOW_PD); if (option->target_ch_mode) { h2c->w1 |= le32_encode_bits(op->band_width, @@ -4845,6 +4868,11 @@ int rtw89_fw_h2c_scan_offload(struct rtw89_dev *rtwdev, RTW89_H2C_SCANOFLD_W0_TARGET_CH_BAND); } + h2c->tsf_high = le32_encode_bits(upper_32_bits(tsf), + RTW89_H2C_SCANOFLD_W3_TSF_HIGH); + h2c->tsf_low = le32_encode_bits(lower_32_bits(tsf), + RTW89_H2C_SCANOFLD_W4_TSF_LOW); + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, H2C_CAT_MAC, H2C_CL_MAC_FW_OFLD, H2C_FUNC_SCANOFLD, 1, 1, @@ -4888,7 +4916,8 @@ static void rtw89_scan_get_6g_disabled_chan(struct rtw89_dev *rtwdev, int rtw89_fw_h2c_scan_offload_be(struct rtw89_dev *rtwdev, struct rtw89_scan_option *option, - struct rtw89_vif *rtwvif) + struct rtw89_vif *rtwvif, + bool wowlan) { struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info; struct rtw89_wait_info *wait = &rtwdev->mac.fw_ofld_wait; @@ -4902,6 +4931,7 @@ int rtw89_fw_h2c_scan_offload_be(struct rtw89_dev *rtwdev, u8 macc_role_size = sizeof(*macc_role) * option->num_macc_role; u8 opch_size = sizeof(*opch) * option->num_opch; u8 probe_id[NUM_NL80211_BANDS]; + u8 cfg_len = sizeof(*h2c); unsigned int cond; void *ptr; int ret; @@ -4910,7 +4940,7 @@ int rtw89_fw_h2c_scan_offload_be(struct rtw89_dev *rtwdev, rtw89_scan_get_6g_disabled_chan(rtwdev, option); - len = sizeof(*h2c) + macc_role_size + opch_size; + len = cfg_len + macc_role_size + opch_size; skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); if (!skb) { rtw89_err(rtwdev, "failed to alloc skb for h2c scan offload\n"); @@ -4923,11 +4953,13 @@ int rtw89_fw_h2c_scan_offload_be(struct rtw89_dev *rtwdev, memset(probe_id, RTW89_SCANOFLD_PKT_NONE, sizeof(probe_id)); - list_for_each_entry(pkt_info, &scan_info->pkt_list[NL80211_BAND_6GHZ], list) { - if (pkt_info->wildcard_6ghz) { - /* Provide wildcard as template */ - probe_id[NL80211_BAND_6GHZ] = pkt_info->id; - break; + if (!wowlan) { + list_for_each_entry(pkt_info, &scan_info->pkt_list[NL80211_BAND_6GHZ], list) { + if (pkt_info->wildcard_6ghz) { + /* Provide wildcard as template */ + probe_id[NL80211_BAND_6GHZ] = pkt_info->id; + break; + } } } @@ -4958,7 +4990,7 @@ int rtw89_fw_h2c_scan_offload_be(struct rtw89_dev *rtwdev, RTW89_H2C_SCANOFLD_BE_W4_PROBE_5G) | le32_encode_bits(probe_id[NL80211_BAND_6GHZ], RTW89_H2C_SCANOFLD_BE_W4_PROBE_6G) | - le32_encode_bits(0, RTW89_H2C_SCANOFLD_BE_W4_DELAY_START); + le32_encode_bits(option->delay, RTW89_H2C_SCANOFLD_BE_W4_DELAY_START); h2c->w5 = le32_encode_bits(option->mlo_mode, RTW89_H2C_SCANOFLD_BE_W5_MLO_MODE); @@ -4966,7 +4998,7 @@ int rtw89_fw_h2c_scan_offload_be(struct rtw89_dev *rtwdev, RTW89_H2C_SCANOFLD_BE_W6_CHAN_PROHIB_LOW); h2c->w7 = le32_encode_bits(option->prohib_chan >> 32, RTW89_H2C_SCANOFLD_BE_W7_CHAN_PROHIB_HIGH); - if (req->no_cck) { + if (!wowlan && req->no_cck) { h2c->w0 |= le32_encode_bits(true, RTW89_H2C_SCANOFLD_BE_W0_PROBE_WITH_RATE); h2c->w8 = le32_encode_bits(RTW89_HW_RATE_OFDM6, RTW89_H2C_SCANOFLD_BE_W8_PROBE_RATE_2GHZ) | @@ -4975,10 +5007,24 @@ int rtw89_fw_h2c_scan_offload_be(struct rtw89_dev *rtwdev, le32_encode_bits(RTW89_HW_RATE_OFDM6, RTW89_H2C_SCANOFLD_BE_W8_PROBE_RATE_6GHZ); } - ptr += sizeof(*h2c); + + if (RTW89_CHK_FW_FEATURE(SCAN_OFFLOAD_BE_V0, &rtwdev->fw)) { + cfg_len = offsetofend(typeof(*h2c), w8); + goto flex_member; + } + + h2c->w9 = le32_encode_bits(sizeof(*h2c) / sizeof(h2c->w0), + RTW89_H2C_SCANOFLD_BE_W9_SIZE_CFG) | + le32_encode_bits(sizeof(*macc_role) / sizeof(macc_role->w0), + RTW89_H2C_SCANOFLD_BE_W9_SIZE_MACC) | + le32_encode_bits(sizeof(*opch) / sizeof(opch->w0), + RTW89_H2C_SCANOFLD_BE_W9_SIZE_OP); + +flex_member: + ptr += cfg_len; for (i = 0; i < option->num_macc_role; i++) { - macc_role = (struct rtw89_h2c_scanofld_be_macc_role *)&h2c->role[i]; + macc_role = ptr; macc_role->w0 = le32_encode_bits(0, RTW89_H2C_SCANOFLD_BE_MACC_ROLE_W0_BAND) | le32_encode_bits(0, RTW89_H2C_SCANOFLD_BE_MACC_ROLE_W0_PORT) | @@ -5132,14 +5178,21 @@ int rtw89_fw_h2c_rf_pre_ntfy(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) { struct rtw89_rfk_mcc_info *rfk_mcc = &rtwdev->rfk_mcc; + struct rtw89_fw_h2c_rfk_pre_info_v0 *h2c_v0; struct rtw89_fw_h2c_rfk_pre_info *h2c; u8 tbl_sel = rfk_mcc->table_idx; u32 len = sizeof(*h2c); struct sk_buff *skb; + u8 ver = U8_MAX; u8 tbl, path; u32 val32; int ret; + if (RTW89_CHK_FW_FEATURE(RFK_PRE_NOTIFY_V0, &rtwdev->fw)) { + len = sizeof(*h2c_v0); + ver = 0; + } + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); if (!skb) { rtw89_err(rtwdev, "failed to alloc skb for h2c rfk_pre_ntfy\n"); @@ -5148,41 +5201,53 @@ int rtw89_fw_h2c_rf_pre_ntfy(struct rtw89_dev *rtwdev, skb_put(skb, len); h2c = (struct rtw89_fw_h2c_rfk_pre_info *)skb->data; - h2c->mlo_mode = cpu_to_le32(rtwdev->mlo_dbcc_mode); + h2c->common.mlo_mode = cpu_to_le32(rtwdev->mlo_dbcc_mode); BUILD_BUG_ON(NUM_OF_RTW89_FW_RFK_TBL > RTW89_RFK_CHS_NR); for (tbl = 0; tbl < NUM_OF_RTW89_FW_RFK_TBL; tbl++) { for (path = 0; path < NUM_OF_RTW89_FW_RFK_PATH; path++) { - h2c->dbcc.ch[path][tbl] = cpu_to_le32(rfk_mcc->ch[tbl]); - h2c->dbcc.band[path][tbl] = cpu_to_le32(rfk_mcc->band[tbl]); + h2c->common.dbcc.ch[path][tbl] = + cpu_to_le32(rfk_mcc->ch[tbl]); + h2c->common.dbcc.band[path][tbl] = + cpu_to_le32(rfk_mcc->band[tbl]); } } for (path = 0; path < NUM_OF_RTW89_FW_RFK_PATH; path++) { - h2c->tbl.cur_ch[path] = cpu_to_le32(rfk_mcc->ch[tbl_sel]); - h2c->tbl.cur_band[path] = cpu_to_le32(rfk_mcc->band[tbl_sel]); + h2c->common.tbl.cur_ch[path] = cpu_to_le32(rfk_mcc->ch[tbl_sel]); + h2c->common.tbl.cur_band[path] = cpu_to_le32(rfk_mcc->band[tbl_sel]); } - h2c->phy_idx = cpu_to_le32(phy_idx); - h2c->cur_band = cpu_to_le32(rfk_mcc->band[tbl_sel]); - h2c->cur_bw = cpu_to_le32(rfk_mcc->bw[tbl_sel]); - h2c->cur_center_ch = cpu_to_le32(rfk_mcc->ch[tbl_sel]); - - val32 = rtw89_phy_read32_mask(rtwdev, R_COEF_SEL, B_COEF_SEL_IQC_V1); - h2c->ktbl_sel0 = cpu_to_le32(val32); - val32 = rtw89_phy_read32_mask(rtwdev, R_COEF_SEL_C1, B_COEF_SEL_IQC_V1); - h2c->ktbl_sel1 = cpu_to_le32(val32); - val32 = rtw89_read_rf(rtwdev, RF_PATH_A, RR_CFGCH, RFREG_MASK); - h2c->rfmod0 = cpu_to_le32(val32); - val32 = rtw89_read_rf(rtwdev, RF_PATH_B, RR_CFGCH, RFREG_MASK); - h2c->rfmod1 = cpu_to_le32(val32); + h2c->common.phy_idx = cpu_to_le32(phy_idx); - if (rtw89_is_mlo_1_1(rtwdev)) - h2c->mlo_1_1 = cpu_to_le32(1); + if (ver == 0) { /* RFK_PRE_NOTIFY_V0 */ + h2c_v0 = (struct rtw89_fw_h2c_rfk_pre_info_v0 *)skb->data; + + h2c_v0->cur_band = cpu_to_le32(rfk_mcc->band[tbl_sel]); + h2c_v0->cur_bw = cpu_to_le32(rfk_mcc->bw[tbl_sel]); + h2c_v0->cur_center_ch = cpu_to_le32(rfk_mcc->ch[tbl_sel]); + + val32 = rtw89_phy_read32_mask(rtwdev, R_COEF_SEL, B_COEF_SEL_IQC_V1); + h2c_v0->ktbl_sel0 = cpu_to_le32(val32); + val32 = rtw89_phy_read32_mask(rtwdev, R_COEF_SEL_C1, B_COEF_SEL_IQC_V1); + h2c_v0->ktbl_sel1 = cpu_to_le32(val32); + val32 = rtw89_read_rf(rtwdev, RF_PATH_A, RR_CFGCH, RFREG_MASK); + h2c_v0->rfmod0 = cpu_to_le32(val32); + val32 = rtw89_read_rf(rtwdev, RF_PATH_B, RR_CFGCH, RFREG_MASK); + h2c_v0->rfmod1 = cpu_to_le32(val32); + + if (rtw89_is_mlo_1_1(rtwdev)) + h2c_v0->mlo_1_1 = cpu_to_le32(1); - h2c->rfe_type = cpu_to_le32(rtwdev->efuse.rfe_type); + h2c_v0->rfe_type = cpu_to_le32(rtwdev->efuse.rfe_type); + goto done; + } + + if (rtw89_is_mlo_1_1(rtwdev)) + h2c->mlo_1_1 = cpu_to_le32(1); +done: rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, H2C_CAT_OUTSRC, H2C_CL_OUTSRC_RF_FW_RFK, H2C_FUNC_RFK_PRE_NOTIFY, 0, 0, @@ -5205,7 +5270,7 @@ int rtw89_fw_h2c_rf_tssi(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, enum rtw89_tssi_mode tssi_mode) { const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, - RTW89_SUB_ENTITY_0); + RTW89_CHANCTX_0); struct rtw89_hal *hal = &rtwdev->hal; struct rtw89_h2c_rf_tssi *h2c; u32 len = sizeof(*h2c); @@ -5287,7 +5352,7 @@ fail: int rtw89_fw_h2c_rf_dpk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) { const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, - RTW89_SUB_ENTITY_0); + RTW89_CHANCTX_0); struct rtw89_h2c_rf_dpk *h2c; u32 len = sizeof(*h2c); struct sk_buff *skb; @@ -5330,7 +5395,7 @@ fail: int rtw89_fw_h2c_rf_txgapk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) { const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, - RTW89_SUB_ENTITY_0); + RTW89_CHANCTX_0); struct rtw89_hal *hal = &rtwdev->hal; struct rtw89_h2c_rf_txgapk *h2c; u32 len = sizeof(*h2c); @@ -5410,7 +5475,7 @@ fail: int rtw89_fw_h2c_rf_rxdck(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) { const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, - RTW89_SUB_ENTITY_0); + RTW89_CHANCTX_0); struct rtw89_h2c_rf_rxdck *h2c; u32 len = sizeof(*h2c); struct sk_buff *skb; @@ -5926,6 +5991,56 @@ out: return ret; } +static void rtw89_pno_scan_add_chan_ax(struct rtw89_dev *rtwdev, + int chan_type, int ssid_num, + struct rtw89_mac_chinfo *ch_info) +{ + struct rtw89_wow_param *rtw_wow = &rtwdev->wow; + struct rtw89_pktofld_info *info; + u8 probe_count = 0; + + ch_info->notify_action = RTW89_SCANOFLD_DEBUG_MASK; + ch_info->dfs_ch = chan_type == RTW89_CHAN_DFS; + ch_info->bw = RTW89_SCAN_WIDTH; + ch_info->tx_pkt = true; + ch_info->cfg_tx_pwr = false; + ch_info->tx_pwr_idx = 0; + ch_info->tx_null = false; + ch_info->pause_data = false; + ch_info->probe_id = RTW89_SCANOFLD_PKT_NONE; + + if (ssid_num) { + list_for_each_entry(info, &rtw_wow->pno_pkt_list, list) { + if (info->channel_6ghz && + ch_info->pri_ch != info->channel_6ghz) + continue; + else if (info->channel_6ghz && probe_count != 0) + ch_info->period += RTW89_CHANNEL_TIME_6G; + + if (info->wildcard_6ghz) + continue; + + ch_info->pkt_id[probe_count++] = info->id; + if (probe_count >= RTW89_SCANOFLD_MAX_SSID) + break; + } + ch_info->num_pkt = probe_count; + } + + switch (chan_type) { + case RTW89_CHAN_DFS: + if (ch_info->ch_band != RTW89_BAND_6G) + ch_info->period = max_t(u8, ch_info->period, + RTW89_DFS_CHAN_TIME); + ch_info->dwell_time = RTW89_DWELL_TIME; + break; + case RTW89_CHAN_ACTIVE: + break; + default: + rtw89_err(rtwdev, "Channel type out of bound\n"); + } +} + static void rtw89_hw_scan_add_chan(struct rtw89_dev *rtwdev, int chan_type, int ssid_num, struct rtw89_mac_chinfo *ch_info) @@ -6004,6 +6119,45 @@ static void rtw89_hw_scan_add_chan(struct rtw89_dev *rtwdev, int chan_type, } } +static void rtw89_pno_scan_add_chan_be(struct rtw89_dev *rtwdev, int chan_type, + int ssid_num, + struct rtw89_mac_chinfo_be *ch_info) +{ + struct rtw89_wow_param *rtw_wow = &rtwdev->wow; + struct rtw89_pktofld_info *info; + u8 probe_count = 0, i; + + ch_info->notify_action = RTW89_SCANOFLD_DEBUG_MASK; + ch_info->dfs_ch = chan_type == RTW89_CHAN_DFS; + ch_info->bw = RTW89_SCAN_WIDTH; + ch_info->tx_null = false; + ch_info->pause_data = false; + ch_info->probe_id = RTW89_SCANOFLD_PKT_NONE; + + if (ssid_num) { + list_for_each_entry(info, &rtw_wow->pno_pkt_list, list) { + ch_info->pkt_id[probe_count++] = info->id; + if (probe_count >= RTW89_SCANOFLD_MAX_SSID) + break; + } + } + + for (i = probe_count; i < RTW89_SCANOFLD_MAX_SSID; i++) + ch_info->pkt_id[i] = RTW89_SCANOFLD_PKT_NONE; + + switch (chan_type) { + case RTW89_CHAN_DFS: + ch_info->period = max_t(u8, ch_info->period, RTW89_DFS_CHAN_TIME); + ch_info->dwell_time = RTW89_DWELL_TIME; + break; + case RTW89_CHAN_ACTIVE: + break; + default: + rtw89_warn(rtwdev, "Channel type out of bound\n"); + break; + } +} + static void rtw89_hw_scan_add_chan_be(struct rtw89_dev *rtwdev, int chan_type, int ssid_num, struct rtw89_mac_chinfo_be *ch_info) @@ -6066,8 +6220,58 @@ static void rtw89_hw_scan_add_chan_be(struct rtw89_dev *rtwdev, int chan_type, } } -int rtw89_hw_scan_add_chan_list(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, bool connected) +int rtw89_pno_scan_add_chan_list_ax(struct rtw89_dev *rtwdev, + struct rtw89_vif *rtwvif) +{ + struct rtw89_wow_param *rtw_wow = &rtwdev->wow; + struct cfg80211_sched_scan_request *nd_config = rtw_wow->nd_config; + struct rtw89_mac_chinfo *ch_info, *tmp; + struct ieee80211_channel *channel; + struct list_head chan_list; + int list_len; + enum rtw89_chan_type type; + int ret = 0; + u32 idx; + + INIT_LIST_HEAD(&chan_list); + for (idx = 0, list_len = 0; + idx < nd_config->n_channels && list_len < RTW89_SCAN_LIST_LIMIT; + idx++, list_len++) { + channel = nd_config->channels[idx]; + ch_info = kzalloc(sizeof(*ch_info), GFP_KERNEL); + if (!ch_info) { + ret = -ENOMEM; + goto out; + } + + ch_info->period = RTW89_CHANNEL_TIME; + ch_info->ch_band = rtw89_nl80211_to_hw_band(channel->band); + ch_info->central_ch = channel->hw_value; + ch_info->pri_ch = channel->hw_value; + ch_info->is_psc = cfg80211_channel_is_psc(channel); + + if (channel->flags & + (IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IR)) + type = RTW89_CHAN_DFS; + else + type = RTW89_CHAN_ACTIVE; + + rtw89_pno_scan_add_chan_ax(rtwdev, type, nd_config->n_match_sets, ch_info); + list_add_tail(&ch_info->list, &chan_list); + } + ret = rtw89_fw_h2c_scan_list_offload(rtwdev, list_len, &chan_list); + +out: + list_for_each_entry_safe(ch_info, tmp, &chan_list, list) { + list_del(&ch_info->list); + kfree(ch_info); + } + + return ret; +} + +int rtw89_hw_scan_add_chan_list_ax(struct rtw89_dev *rtwdev, + struct rtw89_vif *rtwvif, bool connected) { struct cfg80211_scan_request *req = rtwvif->scan_req; struct rtw89_mac_chinfo *ch_info, *tmp; @@ -6143,6 +6347,58 @@ out: return ret; } +int rtw89_pno_scan_add_chan_list_be(struct rtw89_dev *rtwdev, + struct rtw89_vif *rtwvif) +{ + struct rtw89_wow_param *rtw_wow = &rtwdev->wow; + struct cfg80211_sched_scan_request *nd_config = rtw_wow->nd_config; + struct rtw89_mac_chinfo_be *ch_info, *tmp; + struct ieee80211_channel *channel; + struct list_head chan_list; + enum rtw89_chan_type type; + int list_len, ret; + u32 idx; + + INIT_LIST_HEAD(&chan_list); + + for (idx = 0, list_len = 0; + idx < nd_config->n_channels && list_len < RTW89_SCAN_LIST_LIMIT; + idx++, list_len++) { + channel = nd_config->channels[idx]; + ch_info = kzalloc(sizeof(*ch_info), GFP_KERNEL); + if (!ch_info) { + ret = -ENOMEM; + goto out; + } + + ch_info->period = RTW89_CHANNEL_TIME; + ch_info->ch_band = rtw89_nl80211_to_hw_band(channel->band); + ch_info->central_ch = channel->hw_value; + ch_info->pri_ch = channel->hw_value; + ch_info->is_psc = cfg80211_channel_is_psc(channel); + + if (channel->flags & + (IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IR)) + type = RTW89_CHAN_DFS; + else + type = RTW89_CHAN_ACTIVE; + + rtw89_pno_scan_add_chan_be(rtwdev, type, + nd_config->n_match_sets, ch_info); + list_add_tail(&ch_info->list, &chan_list); + } + + ret = rtw89_fw_h2c_scan_list_offload_be(rtwdev, list_len, &chan_list); + +out: + list_for_each_entry_safe(ch_info, tmp, &chan_list, list) { + list_del(&ch_info->list); + kfree(ch_info); + } + + return ret; +} + int rtw89_hw_scan_add_chan_list_be(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, bool connected) { @@ -6352,7 +6608,7 @@ int rtw89_hw_scan_offload(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, opt.opch_end = connected ? 0 : RTW89_CHAN_INVALID; } - ret = mac->scan_offload(rtwdev, &opt, rtwvif); + ret = mac->scan_offload(rtwdev, &opt, rtwvif, false); out: return ret; } @@ -6602,6 +6858,57 @@ fail: return ret; } +int rtw89_fw_h2c_cfg_pno(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, + bool enable) +{ + struct rtw89_wow_param *rtw_wow = &rtwdev->wow; + struct cfg80211_sched_scan_request *nd_config = rtw_wow->nd_config; + struct rtw89_h2c_cfg_nlo *h2c; + u32 len = sizeof(*h2c); + struct sk_buff *skb; + int ret, i; + + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); + if (!skb) { + rtw89_err(rtwdev, "failed to alloc skb for nlo\n"); + return -ENOMEM; + } + + skb_put(skb, len); + h2c = (struct rtw89_h2c_cfg_nlo *)skb->data; + + h2c->w0 = le32_encode_bits(enable, RTW89_H2C_NLO_W0_ENABLE) | + le32_encode_bits(enable, RTW89_H2C_NLO_W0_IGNORE_CIPHER) | + le32_encode_bits(rtwvif->mac_id, RTW89_H2C_NLO_W0_MACID); + + if (enable) { + h2c->nlo_cnt = nd_config->n_match_sets; + for (i = 0 ; i < nd_config->n_match_sets; i++) { + h2c->ssid_len[i] = nd_config->match_sets[i].ssid.ssid_len; + memcpy(h2c->ssid[i], nd_config->match_sets[i].ssid.ssid, + nd_config->match_sets[i].ssid.ssid_len); + } + } + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_MAC, + H2C_CL_MAC_WOW, + H2C_FUNC_NLO, 0, 1, + 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; +} + int rtw89_fw_h2c_wow_global(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, bool enable) { @@ -6816,7 +7123,43 @@ hdr: goto fail; } return 0; +fail: + dev_kfree_skb_any(skb); + + return ret; +} + +int rtw89_fw_h2c_fwips(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, + bool enable) +{ + struct rtw89_h2c_fwips *h2c; + u32 len = sizeof(*h2c); + struct sk_buff *skb; + int ret; + + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); + if (!skb) { + rtw89_err(rtwdev, "failed to alloc skb for fw ips\n"); + return -ENOMEM; + } + skb_put(skb, len); + h2c = (struct rtw89_h2c_fwips *)skb->data; + + h2c->w0 = le32_encode_bits(rtwvif->mac_id, RTW89_H2C_FW_IPS_W0_MACID) | + le32_encode_bits(enable, RTW89_H2C_FW_IPS_W0_ENABLE); + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_MAC, + H2C_CL_MAC_PS, + H2C_FUNC_IPS_CFG, 0, 1, + 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); @@ -7341,7 +7684,7 @@ int rtw89_fw_h2c_mrc_start(struct rtw89_dev *rtwdev, return rtw89_h2c_tx_and_wait(rtwdev, skb, wait, cond); } -int rtw89_fw_h2c_mrc_del(struct rtw89_dev *rtwdev, u8 sch_idx) +int rtw89_fw_h2c_mrc_del(struct rtw89_dev *rtwdev, u8 sch_idx, u8 slot_idx) { struct rtw89_wait_info *wait = &rtwdev->mcc.wait; struct rtw89_h2c_mrc_del *h2c; @@ -7358,7 +7701,8 @@ int rtw89_fw_h2c_mrc_del(struct rtw89_dev *rtwdev, u8 sch_idx) skb_put(skb, len); h2c = (struct rtw89_h2c_mrc_del *)skb->data; - h2c->w0 = le32_encode_bits(sch_idx, RTW89_H2C_MRC_DEL_W0_SCH_IDX); + h2c->w0 = le32_encode_bits(sch_idx, RTW89_H2C_MRC_DEL_W0_SCH_IDX) | + le32_encode_bits(slot_idx, RTW89_H2C_MRC_DEL_W0_STOP_SLOT_IDX); rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, H2C_CAT_MAC, |