]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
wifi: rtw89: add handling of mlo_link_cfg H2C command and C2H event
authorZong-Zhe Yang <kevin_yang@realtek.com>
Mon, 5 May 2025 07:24:34 +0000 (15:24 +0800)
committerPing-Ke Shih <pkshih@realtek.com>
Sat, 10 May 2025 00:54:05 +0000 (08:54 +0800)
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
drivers/net/wireless/realtek/rtw89/core.c
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

index 1546e3d8e2e076cb0d55f5d92e633b6c09026166..b7b2670cbc887f4c7a205ad9aac7756150f74b51 100644 (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);
index 4e44cbd6cc53675426c879d49aad88756c8b5059..86bbe8cf8cc0b16fd79cba17e4d1d85a2fbb8809 100644 (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;
index 23f4dea64dc6517eabfa633c4a8408af7859e213..aa748fe3f39eea1acf5d2824903f4e47fafc37e8 100644 (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] = {};
index 559f3f6190ebde6bc843c8c64f590a69eed9b3ef..207ec88ea45624cff11fb282fbcb81613ebc36a7 100644 (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)
 {
index 449865f7b7a95c275b505bee7b287cfa3d81903c..e3976ba6dda253f7a02754d7c56776fdf440d472 100644 (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];
index 47d655fbf2ca43c1d766a71aa48531e60087c5e0..e1083b0f81369b7ce09e02bbf3ae8ef5119efac7 100644 (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,