wifi: rtw89: add handling of mlo_link_cfg H2C command and C2H event

The mlo_link_cfg H2C command is used to tell FW to enter/leave PS mode
on a given link. And, need to wait for status of C2H event to ensure if
FW deals with it successfully.

Signed-off-by: Po-Hao Huang <phhuang@realtek.com>
Signed-off-by: Zong-Zhe Yang <kevin_yang@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
Link: https://patch.msgid.link/20250505072440.45113-6-pkshih@realtek.com
This commit is contained in:
Zong-Zhe Yang 2025-05-05 15:24:34 +08:00 committed by Ping-Ke Shih
parent 5b6247de57
commit c3dba0653b
6 changed files with 147 additions and 0 deletions

View File

@ -4945,6 +4945,7 @@ int rtw89_core_init(struct rtw89_dev *rtwdev)
rtwdev->total_sta_assoc = 0;
rtw89_init_wait(&rtwdev->mcc.wait);
rtw89_init_wait(&rtwdev->mlo.wait);
rtw89_init_wait(&rtwdev->mac.fw_ofld_wait);
rtw89_init_wait(&rtwdev->wow.wait);
rtw89_init_wait(&rtwdev->mac.ps_wait);

View File

@ -5738,6 +5738,10 @@ struct rtw89_mcc_info {
struct rtw89_mcc_config config;
};
struct rtw89_mlo_info {
struct rtw89_wait_info wait;
};
struct rtw89_dev {
struct ieee80211_hw *hw;
struct device *dev;
@ -5753,6 +5757,7 @@ struct rtw89_dev {
const struct rtw89_rfe_parms *rfe_parms;
struct rtw89_hal hal;
struct rtw89_mcc_info mcc;
struct rtw89_mlo_info mlo;
struct rtw89_mac_info mac;
struct rtw89_fw_info fw;
struct rtw89_hci_info hci;

View File

@ -8956,6 +8956,47 @@ int rtw89_fw_h2c_ap_info_refcount(struct rtw89_dev *rtwdev, bool en)
return 0;
}
int rtw89_fw_h2c_mlo_link_cfg(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link,
bool enable)
{
struct rtw89_wait_info *wait = &rtwdev->mlo.wait;
struct rtw89_h2c_mlo_link_cfg *h2c;
u8 mac_id = rtwvif_link->mac_id;
u32 len = sizeof(*h2c);
struct sk_buff *skb;
unsigned int cond;
int ret;
skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len);
if (!skb) {
rtw89_err(rtwdev, "failed to alloc skb for mlo link cfg\n");
return -ENOMEM;
}
skb_put(skb, len);
h2c = (struct rtw89_h2c_mlo_link_cfg *)skb->data;
h2c->w0 = le32_encode_bits(mac_id, RTW89_H2C_MLO_LINK_CFG_W0_MACID) |
le32_encode_bits(enable, RTW89_H2C_MLO_LINK_CFG_W0_OPTION);
rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
H2C_CAT_MAC,
H2C_CL_MLO,
H2C_FUNC_MLO_LINK_CFG, 0, 0,
len);
cond = RTW89_MLO_WAIT_COND(mac_id, H2C_FUNC_MLO_LINK_CFG);
ret = rtw89_h2c_tx_and_wait(rtwdev, skb, wait, cond);
if (ret) {
rtw89_err(rtwdev, "mlo link cfg (%s link id %u) failed: %d\n",
str_enable_disable(enable), rtwvif_link->link_id, ret);
return ret;
}
return 0;
}
static bool __fw_txpwr_entry_zero_ext(const void *ext_ptr, u8 ext_len)
{
static const u8 zeros[U8_MAX] = {};

View File

@ -2865,6 +2865,13 @@ struct rtw89_h2c_fwips {
#define RTW89_H2C_FW_IPS_W0_MACID GENMASK(7, 0)
#define RTW89_H2C_FW_IPS_W0_ENABLE BIT(8)
struct rtw89_h2c_mlo_link_cfg {
__le32 w0;
};
#define RTW89_H2C_MLO_LINK_CFG_W0_MACID GENMASK(15, 0)
#define RTW89_H2C_MLO_LINK_CFG_W0_OPTION GENMASK(19, 16)
static inline void RTW89_SET_FWCMD_P2P_MACID(void *cmd, u32 val)
{
le32p_replace_bits((__le32 *)cmd, val, GENMASK(7, 0));
@ -3733,6 +3740,25 @@ static_assert(sizeof(struct rtw89_mac_mcc_tsf_rpt) <= RTW89_COMPLETION_BUF_SIZE)
#define RTW89_GET_MAC_C2H_MCC_STATUS_RPT_TSF_HIGH(c2h) \
le32_get_bits(*((const __le32 *)(c2h) + 4), GENMASK(31, 0))
struct rtw89_c2h_mlo_link_cfg_rpt {
struct rtw89_c2h_hdr hdr;
__le32 w2;
} __packed;
#define RTW89_C2H_MLO_LINK_CFG_RPT_W2_MACID GENMASK(15, 0)
#define RTW89_C2H_MLO_LINK_CFG_RPT_W2_STATUS GENMASK(19, 16)
enum rtw89_c2h_mlo_link_status {
RTW89_C2H_MLO_LINK_CFG_IDLE = 0,
RTW89_C2H_MLO_LINK_CFG_DONE = 1,
RTW89_C2H_MLO_LINK_CFG_ISSUE_NULL_FAIL = 2,
RTW89_C2H_MLO_LINK_CFG_TX_NULL_FAIL = 3,
RTW89_C2H_MLO_LINK_CFG_ROLE_NOT_EXIST = 4,
RTW89_C2H_MLO_LINK_CFG_NULL_1_TIMEOUT = 5,
RTW89_C2H_MLO_LINK_CFG_NULL_0_TIMEOUT = 6,
RTW89_C2H_MLO_LINK_CFG_RUNNING = 0xff,
};
struct rtw89_mac_mrc_tsf_rpt {
unsigned int num;
u64 tsfs[RTW89_MAC_MRC_MAX_REQ_TSF_NUM];
@ -4252,6 +4278,26 @@ enum rtw89_mcc_h2c_func {
#define RTW89_MCC_WAIT_COND(group, func) \
((group) * NUM_OF_RTW89_MCC_H2C_FUNC + (func))
/* CLASS 20 - MLO */
#define H2C_CL_MLO 0x14
enum rtw89_mlo_h2c_func {
H2C_FUNC_MLO_TBL_CFG = 0x0,
H2C_FUNC_MLO_STA_CFG = 0x1,
H2C_FUNC_MLO_TTLM = 0x2,
H2C_FUNC_MLO_DM_CFG = 0x3,
H2C_FUNC_MLO_EMLSR_STA_CFG = 0x4,
H2C_FUNC_MLO_MCMLO_RELINK_DROP = 0x5,
H2C_FUNC_MLO_MCMLO_SN_SYNC = 0x6,
H2C_FUNC_MLO_RELINK = 0x7,
H2C_FUNC_MLO_LINK_CFG = 0x8,
H2C_FUNC_MLO_DM_DBG = 0x9,
NUM_OF_RTW89_MLO_H2C_FUNC,
};
#define RTW89_MLO_WAIT_COND(macid, func) \
((macid) * NUM_OF_RTW89_MLO_H2C_FUNC + (func))
/* CLASS 24 - MRC */
#define H2C_CL_MRC 0x18
enum rtw89_mrc_h2c_func {
@ -4829,6 +4875,8 @@ int rtw89_fw_h2c_mrc_sync(struct rtw89_dev *rtwdev,
int rtw89_fw_h2c_mrc_upd_duration(struct rtw89_dev *rtwdev,
const struct rtw89_fw_mrc_upd_duration_arg *arg);
int rtw89_fw_h2c_ap_info_refcount(struct rtw89_dev *rtwdev, bool en);
int rtw89_fw_h2c_mlo_link_cfg(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link,
bool enable);
static inline void rtw89_fw_h2c_init_ba_cam(struct rtw89_dev *rtwdev)
{

View File

@ -5408,6 +5408,27 @@ rtw89_mac_c2h_wow_aoac_rpt(struct rtw89_dev *rtwdev, struct sk_buff *skb, u32 le
rtw89_complete_cond(wait, RTW89_WOW_WAIT_COND_AOAC, &data);
}
static void
rtw89_mac_c2h_mlo_link_cfg_stat(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len)
{
const struct rtw89_c2h_mlo_link_cfg_rpt *c2h_rpt;
struct rtw89_wait_info *wait = &rtwdev->mlo.wait;
struct rtw89_completion_data data = {};
unsigned int cond;
u16 mac_id;
u8 status;
c2h_rpt = (const struct rtw89_c2h_mlo_link_cfg_rpt *)c2h->data;
mac_id = le32_get_bits(c2h_rpt->w2, RTW89_C2H_MLO_LINK_CFG_RPT_W2_MACID);
status = le32_get_bits(c2h_rpt->w2, RTW89_C2H_MLO_LINK_CFG_RPT_W2_STATUS);
data.err = status == RTW89_C2H_MLO_LINK_CFG_ROLE_NOT_EXIST ||
status == RTW89_C2H_MLO_LINK_CFG_RUNNING;
cond = RTW89_MLO_WAIT_COND(mac_id, H2C_FUNC_MLO_LINK_CFG);
rtw89_complete_cond(wait, cond, &data);
}
static void
rtw89_mac_c2h_mrc_status_rpt(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len)
{
@ -5562,6 +5583,18 @@ void (* const rtw89_mac_c2h_mcc_handler[])(struct rtw89_dev *rtwdev,
[RTW89_MAC_C2H_FUNC_MCC_STATUS_RPT] = rtw89_mac_c2h_mcc_status_rpt,
};
static
void (* const rtw89_mac_c2h_mlo_handler[])(struct rtw89_dev *rtwdev,
struct sk_buff *c2h, u32 len) = {
[RTW89_MAC_C2H_FUNC_MLO_GET_TBL] = NULL,
[RTW89_MAC_C2H_FUNC_MLO_EMLSR_TRANS_DONE] = NULL,
[RTW89_MAC_C2H_FUNC_MLO_EMLSR_STA_CFG_DONE] = NULL,
[RTW89_MAC_C2H_FUNC_MCMLO_RELINK_RPT] = NULL,
[RTW89_MAC_C2H_FUNC_MCMLO_SN_SYNC_RPT] = NULL,
[RTW89_MAC_C2H_FUNC_MLO_LINK_CFG_STAT] = rtw89_mac_c2h_mlo_link_cfg_stat,
[RTW89_MAC_C2H_FUNC_MLO_DM_DBG_DUMP] = NULL,
};
static
void (* const rtw89_mac_c2h_mrc_handler[])(struct rtw89_dev *rtwdev,
struct sk_buff *c2h, u32 len) = {
@ -5631,6 +5664,8 @@ bool rtw89_mac_c2h_chk_atomic(struct rtw89_dev *rtwdev, struct sk_buff *c2h,
}
case RTW89_MAC_C2H_CLASS_MCC:
return true;
case RTW89_MAC_C2H_CLASS_MLO:
return true;
case RTW89_MAC_C2H_CLASS_MRC:
return true;
case RTW89_MAC_C2H_CLASS_WOW:
@ -5664,6 +5699,10 @@ void rtw89_mac_c2h_handle(struct rtw89_dev *rtwdev, struct sk_buff *skb,
if (func < NUM_OF_RTW89_MAC_C2H_FUNC_MCC)
handler = rtw89_mac_c2h_mcc_handler[func];
break;
case RTW89_MAC_C2H_CLASS_MLO:
if (func < NUM_OF_RTW89_MAC_C2H_FUNC_MLO)
handler = rtw89_mac_c2h_mlo_handler[func];
break;
case RTW89_MAC_C2H_CLASS_MRC:
if (func < NUM_OF_RTW89_MAC_C2H_FUNC_MRC)
handler = rtw89_mac_c2h_mrc_handler[func];

View File

@ -427,6 +427,18 @@ enum rtw89_mac_c2h_mcc_func {
NUM_OF_RTW89_MAC_C2H_FUNC_MCC,
};
enum rtw89_mac_c2h_mlo_func {
RTW89_MAC_C2H_FUNC_MLO_GET_TBL = 0x0,
RTW89_MAC_C2H_FUNC_MLO_EMLSR_TRANS_DONE = 0x1,
RTW89_MAC_C2H_FUNC_MLO_EMLSR_STA_CFG_DONE = 0x2,
RTW89_MAC_C2H_FUNC_MCMLO_RELINK_RPT = 0x3,
RTW89_MAC_C2H_FUNC_MCMLO_SN_SYNC_RPT = 0x4,
RTW89_MAC_C2H_FUNC_MLO_LINK_CFG_STAT = 0x5,
RTW89_MAC_C2H_FUNC_MLO_DM_DBG_DUMP = 0x6,
NUM_OF_RTW89_MAC_C2H_FUNC_MLO,
};
enum rtw89_mac_c2h_mrc_func {
RTW89_MAC_C2H_FUNC_MRC_TSF_RPT = 0,
RTW89_MAC_C2H_FUNC_MRC_STATUS_RPT = 1,
@ -453,6 +465,7 @@ enum rtw89_mac_c2h_class {
RTW89_MAC_C2H_CLASS_WOW = 0x3,
RTW89_MAC_C2H_CLASS_MCC = 0x4,
RTW89_MAC_C2H_CLASS_FWDBG = 0x5,
RTW89_MAC_C2H_CLASS_MLO = 0xc,
RTW89_MAC_C2H_CLASS_MRC = 0xe,
RTW89_MAC_C2H_CLASS_AP = 0x18,
RTW89_MAC_C2H_CLASS_MAX,