summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/realtek/rtw89/fw.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/realtek/rtw89/fw.c')
-rw-r--r--drivers/net/wireless/realtek/rtw89/fw.c301
1 files changed, 231 insertions, 70 deletions
diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c
index 6deaf8eec6b4..4718aced1428 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.c
+++ b/drivers/net/wireless/realtek/rtw89/fw.c
@@ -10,31 +10,33 @@
#include "phy.h"
#include "reg.h"
-static struct sk_buff *rtw89_fw_h2c_alloc_skb(u32 len, bool header)
+static struct sk_buff *rtw89_fw_h2c_alloc_skb(struct rtw89_dev *rtwdev, u32 len,
+ bool header)
{
struct sk_buff *skb;
u32 header_len = 0;
+ u32 h2c_desc_size = rtwdev->chip->h2c_desc_size;
if (header)
header_len = H2C_HEADER_LEN;
- skb = dev_alloc_skb(len + header_len + 24);
+ skb = dev_alloc_skb(len + header_len + h2c_desc_size);
if (!skb)
return NULL;
- skb_reserve(skb, header_len + 24);
+ skb_reserve(skb, header_len + h2c_desc_size);
memset(skb->data, 0, len);
return skb;
}
-struct sk_buff *rtw89_fw_h2c_alloc_skb_with_hdr(u32 len)
+struct sk_buff *rtw89_fw_h2c_alloc_skb_with_hdr(struct rtw89_dev *rtwdev, u32 len)
{
- return rtw89_fw_h2c_alloc_skb(len, true);
+ return rtw89_fw_h2c_alloc_skb(rtwdev, len, true);
}
-struct sk_buff *rtw89_fw_h2c_alloc_skb_no_hdr(u32 len)
+struct sk_buff *rtw89_fw_h2c_alloc_skb_no_hdr(struct rtw89_dev *rtwdev, u32 len)
{
- return rtw89_fw_h2c_alloc_skb(len, false);
+ return rtw89_fw_h2c_alloc_skb(rtwdev, len, false);
}
static u8 _fw_get_rdy(struct rtw89_dev *rtwdev)
@@ -193,22 +195,56 @@ int __rtw89_fw_recognize(struct rtw89_dev *rtwdev, enum rtw89_fw_type type)
return 0;
}
+#define __DEF_FW_FEAT_COND(__cond, __op) \
+static bool __fw_feat_cond_ ## __cond(u32 suit_ver_code, u32 comp_ver_code) \
+{ \
+ return suit_ver_code __op comp_ver_code; \
+}
+
+__DEF_FW_FEAT_COND(ge, >=); /* greater or equal */
+__DEF_FW_FEAT_COND(le, <=); /* less or equal */
+
+struct __fw_feat_cfg {
+ enum rtw89_core_chip_id chip_id;
+ enum rtw89_fw_feature feature;
+ u32 ver_code;
+ bool (*cond)(u32 suit_ver_code, u32 comp_ver_code);
+};
+
+#define __CFG_FW_FEAT(_chip, _cond, _maj, _min, _sub, _idx, _feat) \
+ { \
+ .chip_id = _chip, \
+ .feature = RTW89_FW_FEATURE_ ## _feat, \
+ .ver_code = RTW89_FW_VER_CODE(_maj, _min, _sub, _idx), \
+ .cond = __fw_feat_cond_ ## _cond, \
+ }
+
+static const struct __fw_feat_cfg fw_feat_tbl[] = {
+ __CFG_FW_FEAT(RTL8852A, le, 0, 13, 29, 0, OLD_HT_RA_FORMAT),
+ __CFG_FW_FEAT(RTL8852A, ge, 0, 13, 35, 0, SCAN_OFFLOAD),
+ __CFG_FW_FEAT(RTL8852A, ge, 0, 13, 35, 0, TX_WAKE),
+ __CFG_FW_FEAT(RTL8852A, ge, 0, 13, 36, 0, CRASH_TRIGGER),
+};
+
static void rtw89_fw_recognize_features(struct rtw89_dev *rtwdev)
{
const struct rtw89_chip_info *chip = rtwdev->chip;
- struct rtw89_fw_suit *fw_suit = rtw89_fw_suit_get(rtwdev, RTW89_FW_NORMAL);
+ const struct __fw_feat_cfg *ent;
+ const struct rtw89_fw_suit *fw_suit;
+ u32 suit_ver_code;
+ int i;
- if (chip->chip_id == RTL8852A &&
- RTW89_FW_SUIT_VER_CODE(fw_suit) <= RTW89_FW_VER_CODE(0, 13, 29, 0))
- rtwdev->fw.old_ht_ra_format = true;
+ fw_suit = rtw89_fw_suit_get(rtwdev, RTW89_FW_NORMAL);
+ suit_ver_code = RTW89_FW_SUIT_VER_CODE(fw_suit);
- if (chip->chip_id == RTL8852A &&
- RTW89_FW_SUIT_VER_CODE(fw_suit) >= RTW89_FW_VER_CODE(0, 13, 35, 0))
- rtwdev->fw.scan_offload = true;
+ for (i = 0; i < ARRAY_SIZE(fw_feat_tbl); i++) {
+ ent = &fw_feat_tbl[i];
+ if (chip->chip_id != ent->chip_id)
+ continue;
- if (chip->chip_id == RTL8852A &&
- RTW89_FW_SUIT_VER_CODE(fw_suit) >= RTW89_FW_VER_CODE(0, 13, 35, 0))
- rtwdev->fw.tx_wake = true;
+ if (ent->cond(suit_ver_code, ent->ver_code))
+ RTW89_SET_FW_FEATURE(ent->feature, &rtwdev->fw);
+ }
}
int rtw89_fw_recognize(struct rtw89_dev *rtwdev)
@@ -275,7 +311,7 @@ static int __rtw89_fw_download_hdr(struct rtw89_dev *rtwdev, const u8 *fw, u32 l
struct sk_buff *skb;
u32 ret = 0;
- skb = rtw89_fw_h2c_alloc_skb_with_hdr(len);
+ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len);
if (!skb) {
rtw89_err(rtwdev, "failed to alloc skb for fw hdr dl\n");
return -ENOMEM;
@@ -341,7 +377,7 @@ static int __rtw89_fw_download_main(struct rtw89_dev *rtwdev,
else
pkt_len = residue_len;
- skb = rtw89_fw_h2c_alloc_skb_no_hdr(pkt_len);
+ skb = rtw89_fw_h2c_alloc_skb_no_hdr(rtwdev, pkt_len);
if (!skb) {
rtw89_err(rtwdev, "failed to alloc skb for fw dl\n");
return -ENOMEM;
@@ -536,7 +572,7 @@ int rtw89_fw_h2c_cam(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
{
struct sk_buff *skb;
- skb = rtw89_fw_h2c_alloc_skb_with_hdr(H2C_CAM_LEN);
+ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_CAM_LEN);
if (!skb) {
rtw89_err(rtwdev, "failed to alloc skb for fw dl\n");
return -ENOMEM;
@@ -563,6 +599,41 @@ fail:
return -EBUSY;
}
+#define H2C_DCTL_SEC_CAM_LEN 68
+int rtw89_fw_h2c_dctl_sec_cam_v1(struct rtw89_dev *rtwdev,
+ struct rtw89_vif *rtwvif,
+ struct rtw89_sta *rtwsta)
+{
+ struct sk_buff *skb;
+
+ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_DCTL_SEC_CAM_LEN);
+ if (!skb) {
+ rtw89_err(rtwdev, "failed to alloc skb for dctl sec cam\n");
+ return -ENOMEM;
+ }
+ skb_put(skb, H2C_DCTL_SEC_CAM_LEN);
+
+ rtw89_cam_fill_dctl_sec_cam_info_v1(rtwdev, rtwvif, rtwsta, skb->data);
+
+ rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
+ H2C_CAT_MAC,
+ H2C_CL_MAC_FR_EXCHG,
+ H2C_FUNC_MAC_DCTLINFO_UD_V1, 0, 0,
+ H2C_DCTL_SEC_CAM_LEN);
+
+ if (rtw89_h2c_tx(rtwdev, skb, false)) {
+ rtw89_err(rtwdev, "failed to send h2c\n");
+ goto fail;
+ }
+
+ return 0;
+fail:
+ dev_kfree_skb_any(skb);
+
+ return -EBUSY;
+}
+EXPORT_SYMBOL(rtw89_fw_h2c_dctl_sec_cam_v1);
+
#define H2C_BA_CAM_LEN 8
int rtw89_fw_h2c_ba_cam(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta,
bool valid, struct ieee80211_ampdu_params *params)
@@ -585,7 +656,7 @@ int rtw89_fw_h2c_ba_cam(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta,
return 0;
}
- skb = rtw89_fw_h2c_alloc_skb_with_hdr(H2C_BA_CAM_LEN);
+ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_BA_CAM_LEN);
if (!skb) {
rtw89_err(rtwdev, "failed to alloc skb for h2c ba cam\n");
return -ENOMEM;
@@ -631,7 +702,7 @@ int rtw89_fw_h2c_fw_log(struct rtw89_dev *rtwdev, bool enable)
u32 comp = enable ? BIT(RTW89_FW_LOG_COMP_INIT) | BIT(RTW89_FW_LOG_COMP_TASK) |
BIT(RTW89_FW_LOG_COMP_PS) | BIT(RTW89_FW_LOG_COMP_ERROR) : 0;
- skb = rtw89_fw_h2c_alloc_skb_with_hdr(H2C_LOG_CFG_LEN);
+ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_LOG_CFG_LEN);
if (!skb) {
rtw89_err(rtwdev, "failed to alloc skb for fw log cfg\n");
return -ENOMEM;
@@ -667,7 +738,7 @@ int rtw89_fw_h2c_general_pkt(struct rtw89_dev *rtwdev, u8 macid)
{
struct sk_buff *skb;
- skb = rtw89_fw_h2c_alloc_skb_with_hdr(H2C_GENERAL_PKT_LEN);
+ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_GENERAL_PKT_LEN);
if (!skb) {
rtw89_err(rtwdev, "failed to alloc skb for fw dl\n");
return -ENOMEM;
@@ -704,7 +775,7 @@ int rtw89_fw_h2c_lps_parm(struct rtw89_dev *rtwdev,
{
struct sk_buff *skb;
- skb = rtw89_fw_h2c_alloc_skb_with_hdr(H2C_LPS_PARM_LEN);
+ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_LPS_PARM_LEN);
if (!skb) {
rtw89_err(rtwdev, "failed to alloc skb for fw dl\n");
return -ENOMEM;
@@ -744,13 +815,14 @@ fail:
int rtw89_fw_h2c_default_cmac_tbl(struct rtw89_dev *rtwdev,
struct rtw89_vif *rtwvif)
{
+ const struct rtw89_chip_info *chip = rtwdev->chip;
struct rtw89_hal *hal = &rtwdev->hal;
struct sk_buff *skb;
u8 ntx_path = hal->antenna_tx ? hal->antenna_tx : RF_B;
u8 map_b = hal->antenna_tx == RF_AB ? 1 : 0;
u8 macid = rtwvif->mac_id;
- skb = rtw89_fw_h2c_alloc_skb_with_hdr(H2C_CMC_TBL_LEN);
+ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_CMC_TBL_LEN);
if (!skb) {
rtw89_err(rtwdev, "failed to alloc skb for fw dl\n");
return -ENOMEM;
@@ -758,16 +830,18 @@ int rtw89_fw_h2c_default_cmac_tbl(struct rtw89_dev *rtwdev,
skb_put(skb, H2C_CMC_TBL_LEN);
SET_CTRL_INFO_MACID(skb->data, macid);
SET_CTRL_INFO_OPERATION(skb->data, 1);
- SET_CMC_TBL_TXPWR_MODE(skb->data, 0);
- SET_CMC_TBL_NTX_PATH_EN(skb->data, ntx_path);
- SET_CMC_TBL_PATH_MAP_A(skb->data, 0);
- SET_CMC_TBL_PATH_MAP_B(skb->data, map_b);
- SET_CMC_TBL_PATH_MAP_C(skb->data, 0);
- SET_CMC_TBL_PATH_MAP_D(skb->data, 0);
- SET_CMC_TBL_ANTSEL_A(skb->data, 0);
- SET_CMC_TBL_ANTSEL_B(skb->data, 0);
- SET_CMC_TBL_ANTSEL_C(skb->data, 0);
- SET_CMC_TBL_ANTSEL_D(skb->data, 0);
+ if (chip->h2c_cctl_func_id == H2C_FUNC_MAC_CCTLINFO_UD) {
+ SET_CMC_TBL_TXPWR_MODE(skb->data, 0);
+ SET_CMC_TBL_NTX_PATH_EN(skb->data, ntx_path);
+ SET_CMC_TBL_PATH_MAP_A(skb->data, 0);
+ SET_CMC_TBL_PATH_MAP_B(skb->data, map_b);
+ SET_CMC_TBL_PATH_MAP_C(skb->data, 0);
+ SET_CMC_TBL_PATH_MAP_D(skb->data, 0);
+ SET_CMC_TBL_ANTSEL_A(skb->data, 0);
+ SET_CMC_TBL_ANTSEL_B(skb->data, 0);
+ SET_CMC_TBL_ANTSEL_C(skb->data, 0);
+ SET_CMC_TBL_ANTSEL_D(skb->data, 0);
+ }
SET_CMC_TBL_DOPPLER_CTRL(skb->data, 0);
SET_CMC_TBL_TXPWR_TOLERENCE(skb->data, 0);
if (rtwvif->net_type == RTW89_NET_TYPE_AP_MODE)
@@ -775,7 +849,7 @@ int rtw89_fw_h2c_default_cmac_tbl(struct rtw89_dev *rtwdev,
rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
H2C_CAT_MAC, H2C_CL_MAC_FR_EXCHG,
- H2C_FUNC_MAC_CCTLINFO_UD, 0, 1,
+ chip->h2c_cctl_func_id, 0, 1,
H2C_CMC_TBL_LEN);
if (rtw89_h2c_tx(rtwdev, skb, false)) {
@@ -795,26 +869,28 @@ static void __get_sta_he_pkt_padding(struct rtw89_dev *rtwdev,
{
bool ppe_th;
u8 ppe16, ppe8;
- u8 nss = min(sta->rx_nss, rtwdev->hal.tx_nss) - 1;
- u8 ppe_thres_hdr = sta->he_cap.ppe_thres[0];
+ u8 nss = min(sta->deflink.rx_nss, rtwdev->hal.tx_nss) - 1;
+ u8 ppe_thres_hdr = sta->deflink.he_cap.ppe_thres[0];
u8 ru_bitmap;
u8 n, idx, sh;
u16 ppe;
int i;
- if (!sta->he_cap.has_he)
+ if (!sta->deflink.he_cap.has_he)
return;
ppe_th = FIELD_GET(IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT,
- sta->he_cap.he_cap_elem.phy_cap_info[6]);
+ sta->deflink.he_cap.he_cap_elem.phy_cap_info[6]);
if (!ppe_th) {
u8 pad;
pad = FIELD_GET(IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_MASK,
- sta->he_cap.he_cap_elem.phy_cap_info[9]);
+ sta->deflink.he_cap.he_cap_elem.phy_cap_info[9]);
for (i = 0; i < RTW89_PPE_BW_NUM; i++)
pads[i] = pad;
+
+ return;
}
ru_bitmap = FIELD_GET(IEEE80211_PPE_THRES_RU_INDEX_BITMASK_MASK, ppe_thres_hdr);
@@ -831,7 +907,7 @@ static void __get_sta_he_pkt_padding(struct rtw89_dev *rtwdev,
sh = n & 7;
n += IEEE80211_PPE_THRES_INFO_PPET_SIZE * 2;
- ppe = le16_to_cpu(*((__le16 *)&sta->he_cap.ppe_thres[idx]));
+ ppe = le16_to_cpu(*((__le16 *)&sta->deflink.he_cap.ppe_thres[idx]));
ppe16 = (ppe >> sh) & IEEE80211_PPE_THRES_NSS_MASK;
sh += IEEE80211_PPE_THRES_INFO_PPET_SIZE;
ppe8 = (ppe >> sh) & IEEE80211_PPE_THRES_NSS_MASK;
@@ -849,6 +925,7 @@ int rtw89_fw_h2c_assoc_cmac_tbl(struct rtw89_dev *rtwdev,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta)
{
+ const struct rtw89_chip_info *chip = rtwdev->chip;
struct rtw89_hal *hal = &rtwdev->hal;
struct rtw89_sta *rtwsta = sta_to_rtwsta_safe(sta);
struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
@@ -860,7 +937,7 @@ int rtw89_fw_h2c_assoc_cmac_tbl(struct rtw89_dev *rtwdev,
if (sta)
__get_sta_he_pkt_padding(rtwdev, sta, pads);
- skb = rtw89_fw_h2c_alloc_skb_with_hdr(H2C_CMC_TBL_LEN);
+ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_CMC_TBL_LEN);
if (!skb) {
rtw89_err(rtwdev, "failed to alloc skb for fw dl\n");
return -ENOMEM;
@@ -881,17 +958,26 @@ int rtw89_fw_h2c_assoc_cmac_tbl(struct rtw89_dev *rtwdev,
else
SET_CMC_TBL_ULDL(skb->data, 0);
SET_CMC_TBL_MULTI_PORT_ID(skb->data, rtwvif->port);
- SET_CMC_TBL_NOMINAL_PKT_PADDING(skb->data, pads[RTW89_CHANNEL_WIDTH_20]);
- SET_CMC_TBL_NOMINAL_PKT_PADDING40(skb->data, pads[RTW89_CHANNEL_WIDTH_40]);
- SET_CMC_TBL_NOMINAL_PKT_PADDING80(skb->data, pads[RTW89_CHANNEL_WIDTH_80]);
+ if (chip->h2c_cctl_func_id == H2C_FUNC_MAC_CCTLINFO_UD_V1) {
+ SET_CMC_TBL_NOMINAL_PKT_PADDING_V1(skb->data, pads[RTW89_CHANNEL_WIDTH_20]);
+ SET_CMC_TBL_NOMINAL_PKT_PADDING40_V1(skb->data, pads[RTW89_CHANNEL_WIDTH_40]);
+ SET_CMC_TBL_NOMINAL_PKT_PADDING80_V1(skb->data, pads[RTW89_CHANNEL_WIDTH_80]);
+ SET_CMC_TBL_NOMINAL_PKT_PADDING160_V1(skb->data, pads[RTW89_CHANNEL_WIDTH_160]);
+ } else if (chip->h2c_cctl_func_id == H2C_FUNC_MAC_CCTLINFO_UD) {
+ SET_CMC_TBL_NOMINAL_PKT_PADDING(skb->data, pads[RTW89_CHANNEL_WIDTH_20]);
+ SET_CMC_TBL_NOMINAL_PKT_PADDING40(skb->data, pads[RTW89_CHANNEL_WIDTH_40]);
+ SET_CMC_TBL_NOMINAL_PKT_PADDING80(skb->data, pads[RTW89_CHANNEL_WIDTH_80]);
+ SET_CMC_TBL_NOMINAL_PKT_PADDING160(skb->data, pads[RTW89_CHANNEL_WIDTH_160]);
+ }
if (sta)
- SET_CMC_TBL_BSR_QUEUE_SIZE_FORMAT(skb->data, sta->he_cap.has_he);
+ SET_CMC_TBL_BSR_QUEUE_SIZE_FORMAT(skb->data,
+ sta->deflink.he_cap.has_he);
if (rtwvif->net_type == RTW89_NET_TYPE_AP_MODE)
SET_CMC_TBL_DATA_DCM(skb->data, 0);
rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
H2C_CAT_MAC, H2C_CL_MAC_FR_EXCHG,
- H2C_FUNC_MAC_CCTLINFO_UD, 0, 1,
+ chip->h2c_cctl_func_id, 0, 1,
H2C_CMC_TBL_LEN);
if (rtw89_h2c_tx(rtwdev, skb, false)) {
@@ -909,9 +995,10 @@ fail:
int rtw89_fw_h2c_txtime_cmac_tbl(struct rtw89_dev *rtwdev,
struct rtw89_sta *rtwsta)
{
+ const struct rtw89_chip_info *chip = rtwdev->chip;
struct sk_buff *skb;
- skb = rtw89_fw_h2c_alloc_skb_with_hdr(H2C_CMC_TBL_LEN);
+ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_CMC_TBL_LEN);
if (!skb) {
rtw89_err(rtwdev, "failed to alloc skb for fw dl\n");
return -ENOMEM;
@@ -930,7 +1017,7 @@ int rtw89_fw_h2c_txtime_cmac_tbl(struct rtw89_dev *rtwdev,
rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
H2C_CAT_MAC, H2C_CL_MAC_FR_EXCHG,
- H2C_FUNC_MAC_CCTLINFO_UD, 0, 1,
+ chip->h2c_cctl_func_id, 0, 1,
H2C_CMC_TBL_LEN);
if (rtw89_h2c_tx(rtwdev, skb, false)) {
@@ -963,7 +1050,7 @@ int rtw89_fw_h2c_update_beacon(struct rtw89_dev *rtwdev,
}
bcn_total_len = H2C_BCN_BASE_LEN + skb_beacon->len;
- skb = rtw89_fw_h2c_alloc_skb_with_hdr(bcn_total_len);
+ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, bcn_total_len);
if (!skb) {
rtw89_err(rtwdev, "failed to alloc skb for fw dl\n");
dev_kfree_skb_any(skb_beacon);
@@ -1017,7 +1104,7 @@ int rtw89_fw_h2c_role_maintain(struct rtw89_dev *rtwdev,
self_role = rtwvif->self_role;
}
- skb = rtw89_fw_h2c_alloc_skb_with_hdr(H2C_ROLE_MAINTAIN_LEN);
+ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_ROLE_MAINTAIN_LEN);
if (!skb) {
rtw89_err(rtwdev, "failed to alloc skb for h2c join\n");
return -ENOMEM;
@@ -1059,7 +1146,7 @@ int rtw89_fw_h2c_join_info(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
net_type = dis_conn ? RTW89_NET_TYPE_NO_LINK : net_type;
}
- skb = rtw89_fw_h2c_alloc_skb_with_hdr(H2C_JOIN_INFO_LEN);
+ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_JOIN_INFO_LEN);
if (!skb) {
rtw89_err(rtwdev, "failed to alloc skb for h2c join\n");
return -ENOMEM;
@@ -1103,7 +1190,7 @@ int rtw89_fw_h2c_macid_pause(struct rtw89_dev *rtwdev, u8 sh, u8 grp,
u8 len = sizeof(struct rtw89_fw_macid_pause_grp);
struct sk_buff *skb;
- skb = rtw89_fw_h2c_alloc_skb_with_hdr(H2C_JOIN_INFO_LEN);
+ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_JOIN_INFO_LEN);
if (!skb) {
rtw89_err(rtwdev, "failed to alloc skb for h2c join\n");
return -ENOMEM;
@@ -1136,7 +1223,7 @@ int rtw89_fw_h2c_set_edca(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
{
struct sk_buff *skb;
- skb = rtw89_fw_h2c_alloc_skb_with_hdr(H2C_EDCA_LEN);
+ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_EDCA_LEN);
if (!skb) {
rtw89_err(rtwdev, "failed to alloc skb for h2c edca\n");
return -ENOMEM;
@@ -1171,7 +1258,7 @@ int rtw89_fw_h2c_set_ofld_cfg(struct rtw89_dev *rtwdev)
static const u8 cfg[] = {0x09, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00};
struct sk_buff *skb;
- skb = rtw89_fw_h2c_alloc_skb_with_hdr(H2C_OFLD_CFG_LEN);
+ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_OFLD_CFG_LEN);
if (!skb) {
rtw89_err(rtwdev, "failed to alloc skb for h2c ofld\n");
return -ENOMEM;
@@ -1201,7 +1288,7 @@ int rtw89_fw_h2c_ra(struct rtw89_dev *rtwdev, struct rtw89_ra_info *ra, bool csi
struct sk_buff *skb;
u8 *cmd;
- skb = rtw89_fw_h2c_alloc_skb_with_hdr(H2C_RA_LEN);
+ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_RA_LEN);
if (!skb) {
rtw89_err(rtwdev, "failed to alloc skb for h2c join\n");
return -ENOMEM;
@@ -1272,7 +1359,7 @@ int rtw89_fw_h2c_cxdrv_init(struct rtw89_dev *rtwdev)
struct sk_buff *skb;
u8 *cmd;
- skb = rtw89_fw_h2c_alloc_skb_with_hdr(H2C_LEN_CXDRVINFO_INIT);
+ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_LEN_CXDRVINFO_INIT);
if (!skb) {
rtw89_err(rtwdev, "failed to alloc skb for h2c cxdrv_init\n");
return -ENOMEM;
@@ -1331,7 +1418,7 @@ int rtw89_fw_h2c_cxdrv_role(struct rtw89_dev *rtwdev)
u8 *cmd;
int i;
- skb = rtw89_fw_h2c_alloc_skb_with_hdr(H2C_LEN_CXDRVINFO_ROLE);
+ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_LEN_CXDRVINFO_ROLE);
if (!skb) {
rtw89_err(rtwdev, "failed to alloc skb for h2c cxdrv_role\n");
return -ENOMEM;
@@ -1399,7 +1486,7 @@ int rtw89_fw_h2c_cxdrv_ctrl(struct rtw89_dev *rtwdev)
struct sk_buff *skb;
u8 *cmd;
- skb = rtw89_fw_h2c_alloc_skb_with_hdr(H2C_LEN_CXDRVINFO_CTRL);
+ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_LEN_CXDRVINFO_CTRL);
if (!skb) {
rtw89_err(rtwdev, "failed to alloc skb for h2c cxdrv_ctrl\n");
return -ENOMEM;
@@ -1441,7 +1528,7 @@ int rtw89_fw_h2c_cxdrv_rfk(struct rtw89_dev *rtwdev)
struct sk_buff *skb;
u8 *cmd;
- skb = rtw89_fw_h2c_alloc_skb_with_hdr(H2C_LEN_CXDRVINFO_RFK);
+ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_LEN_CXDRVINFO_RFK);
if (!skb) {
rtw89_err(rtwdev, "failed to alloc skb for h2c cxdrv_ctrl\n");
return -ENOMEM;
@@ -1481,7 +1568,7 @@ int rtw89_fw_h2c_del_pkt_offload(struct rtw89_dev *rtwdev, u8 id)
struct sk_buff *skb;
u8 *cmd;
- skb = rtw89_fw_h2c_alloc_skb_with_hdr(H2C_LEN_PKT_OFLD);
+ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_LEN_PKT_OFLD);
if (!skb) {
rtw89_err(rtwdev, "failed to alloc skb for h2c pkt offload\n");
return -ENOMEM;
@@ -1523,7 +1610,7 @@ int rtw89_fw_h2c_add_pkt_offload(struct rtw89_dev *rtwdev, u8 *id,
*id = alloc_id;
- skb = rtw89_fw_h2c_alloc_skb_with_hdr(H2C_LEN_PKT_OFLD + skb_ofld->len);
+ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_LEN_PKT_OFLD + skb_ofld->len);
if (!skb) {
rtw89_err(rtwdev, "failed to alloc skb for h2c pkt offload\n");
return -ENOMEM;
@@ -1562,7 +1649,7 @@ int rtw89_fw_h2c_scan_list_offload(struct rtw89_dev *rtwdev, int len,
int skb_len = H2C_LEN_SCAN_LIST_OFFLOAD + len * RTW89_MAC_CHINFO_SIZE;
u8 *cmd;
- skb = rtw89_fw_h2c_alloc_skb_with_hdr(skb_len);
+ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, skb_len);
if (!skb) {
rtw89_err(rtwdev, "failed to alloc skb for h2c scan list\n");
return -ENOMEM;
@@ -1626,7 +1713,7 @@ int rtw89_fw_h2c_scan_offload(struct rtw89_dev *rtwdev,
struct sk_buff *skb;
u8 *cmd;
- skb = rtw89_fw_h2c_alloc_skb_with_hdr(H2C_LEN_SCAN_OFFLOAD);
+ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_LEN_SCAN_OFFLOAD);
if (!skb) {
rtw89_err(rtwdev, "failed to alloc skb for h2c scan offload\n");
return -ENOMEM;
@@ -1675,7 +1762,7 @@ int rtw89_fw_h2c_rf_reg(struct rtw89_dev *rtwdev,
u8 class = info->rf_path == RF_PATH_A ?
H2C_CL_OUTSRC_RF_REG_A : H2C_CL_OUTSRC_RF_REG_B;
- skb = rtw89_fw_h2c_alloc_skb_with_hdr(len);
+ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len);
if (!skb) {
rtw89_err(rtwdev, "failed to alloc skb for h2c rf reg\n");
return -ENOMEM;
@@ -1698,13 +1785,52 @@ fail:
return -EBUSY;
}
+int rtw89_fw_h2c_rf_ntfy_mcc(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_mcc_info *mcc_info = &rtwdev->mcc;
+ struct rtw89_fw_h2c_rf_get_mccch *mccch;
+ struct sk_buff *skb;
+
+ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, sizeof(*mccch));
+ if (!skb) {
+ rtw89_err(rtwdev, "failed to alloc skb for h2c cxdrv_ctrl\n");
+ return -ENOMEM;
+ }
+ skb_put(skb, sizeof(*mccch));
+ mccch = (struct rtw89_fw_h2c_rf_get_mccch *)skb->data;
+
+ mccch->ch_0 = cpu_to_le32(mcc_info->ch[0]);
+ mccch->ch_1 = cpu_to_le32(mcc_info->ch[1]);
+ mccch->band_0 = cpu_to_le32(mcc_info->band[0]);
+ mccch->band_1 = cpu_to_le32(mcc_info->band[1]);
+ mccch->current_channel = cpu_to_le32(rtwdev->hal.current_channel);
+ mccch->current_band_type = cpu_to_le32(rtwdev->hal.current_band_type);
+
+ rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
+ H2C_CAT_OUTSRC, H2C_CL_OUTSRC_RF_FW_NOTIFY,
+ H2C_FUNC_OUTSRC_RF_GET_MCCCH, 0, 0,
+ sizeof(*mccch));
+
+ if (rtw89_h2c_tx(rtwdev, skb, false)) {
+ rtw89_err(rtwdev, "failed to send h2c\n");
+ goto fail;
+ }
+
+ return 0;
+fail:
+ dev_kfree_skb_any(skb);
+
+ return -EBUSY;
+}
+EXPORT_SYMBOL(rtw89_fw_h2c_rf_ntfy_mcc);
+
int rtw89_fw_h2c_raw_with_hdr(struct rtw89_dev *rtwdev,
u8 h2c_class, u8 h2c_func, u8 *buf, u16 len,
bool rack, bool dack)
{
struct sk_buff *skb;
- skb = rtw89_fw_h2c_alloc_skb_with_hdr(len);
+ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len);
if (!skb) {
rtw89_err(rtwdev, "failed to alloc skb for raw with hdr\n");
return -ENOMEM;
@@ -1731,7 +1857,7 @@ int rtw89_fw_h2c_raw(struct rtw89_dev *rtwdev, const u8 *buf, u16 len)
{
struct sk_buff *skb;
- skb = rtw89_fw_h2c_alloc_skb_no_hdr(len);
+ skb = rtw89_fw_h2c_alloc_skb_no_hdr(rtwdev, len);
if (!skb) {
rtw89_err(rtwdev, "failed to alloc skb for h2c raw\n");
return -ENOMEM;
@@ -1942,7 +2068,7 @@ static void rtw89_release_pkt_list(struct rtw89_dev *rtwdev)
struct rtw89_pktofld_info *info, *tmp;
u8 idx;
- for (idx = RTW89_BAND_2G; idx < NUM_NL80211_BANDS; idx++) {
+ for (idx = NL80211_BAND_2GHZ; idx < NUM_NL80211_BANDS; idx++) {
if (!(rtwdev->chip->support_bands & BIT(idx)))
continue;
@@ -2065,7 +2191,7 @@ static void rtw89_hw_scan_add_chan(struct rtw89_dev *rtwdev, int chan_type,
ch_info->num_pkt = 0;
break;
case RTW89_CHAN_DFS:
- ch_info->period = min_t(u8, ch_info->period,
+ ch_info->period = max_t(u8, ch_info->period,
RTW89_DFS_CHAN_TIME);
ch_info->dwell_time = RTW89_DWELL_TIME;
break;
@@ -2254,3 +2380,38 @@ void rtw89_store_op_chan(struct rtw89_dev *rtwdev)
scan_info->op_bw = hal->current_band_width;
scan_info->op_band = hal->current_band_type;
}
+
+#define H2C_FW_CPU_EXCEPTION_LEN 4
+#define H2C_FW_CPU_EXCEPTION_TYPE_DEF 0x5566
+int rtw89_fw_h2c_trigger_cpu_exception(struct rtw89_dev *rtwdev)
+{
+ struct sk_buff *skb;
+
+ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_FW_CPU_EXCEPTION_LEN);
+ if (!skb) {
+ rtw89_err(rtwdev,
+ "failed to alloc skb for fw cpu exception\n");
+ return -ENOMEM;
+ }
+
+ skb_put(skb, H2C_FW_CPU_EXCEPTION_LEN);
+ RTW89_SET_FWCMD_CPU_EXCEPTION_TYPE(skb->data,
+ H2C_FW_CPU_EXCEPTION_TYPE_DEF);
+
+ rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
+ H2C_CAT_TEST,
+ H2C_CL_FW_STATUS_TEST,
+ H2C_FUNC_CPU_EXCEPTION, 0, 0,
+ H2C_FW_CPU_EXCEPTION_LEN);
+
+ if (rtw89_h2c_tx(rtwdev, skb, false)) {
+ rtw89_err(rtwdev, "failed to send h2c\n");
+ goto fail;
+ }
+
+ return 0;
+
+fail:
+ dev_kfree_skb_any(skb);
+ return -EBUSY;
+}