* [PATCH rtw-next 00/11] wifi: rtw89: support MLO feature
@ 2025-05-05 7:24 Ping-Ke Shih
2025-05-05 7:24 ` [PATCH rtw-next 01/11] wifi: rtw89: extract link part from core tx write function Ping-Ke Shih
` (10 more replies)
0 siblings, 11 replies; 13+ messages in thread
From: Ping-Ke Shih @ 2025-05-05 7:24 UTC (permalink / raw)
To: linux-wireless; +Cc: phhuang, kevin_yang
After adjusting code to control two HWs and TX/RX path, declaring MLO
capabilities and so on, start to support MLO feature by this patchset.
Currently only support MLSR with a simple rule to switch link. To test
and debug the flow to switch link, add a debugfs interface as a helper.
Po-Hao Huang (6):
wifi: rtw89: allow driver to do specific band TX for MLO
wifi: rtw89: send nullfunc based on the given link
wifi: rtw89: add MLO track for MLSR switch decision
wifi: rtw89: debug: extend dbgfs for MLO
wifi: rtw89: debug: add MLD table dump
wifi: rtw89: debug: add FW log component for MLO
Zong-Zhe Yang (5):
wifi: rtw89: extract link part from core tx write function
wifi: rtw89: chan: re-calculate MLO DBCC mode during setting channel
wifi: rtw89: add handling of mlo_link_cfg H2C command and C2H event
wifi: rtw89: debug: add mlo_mode dbgfs
wifi: rtw89: declare MLO support if prerequisites are met
drivers/net/wireless/realtek/rtw89/chan.c | 32 +++
drivers/net/wireless/realtek/rtw89/core.c | 260 +++++++++++++++---
drivers/net/wireless/realtek/rtw89/core.h | 17 ++
drivers/net/wireless/realtek/rtw89/debug.c | 138 +++++++++-
drivers/net/wireless/realtek/rtw89/fw.c | 47 +++-
drivers/net/wireless/realtek/rtw89/fw.h | 49 ++++
drivers/net/wireless/realtek/rtw89/mac.c | 39 +++
drivers/net/wireless/realtek/rtw89/mac.h | 14 +
drivers/net/wireless/realtek/rtw89/mac80211.c | 2 +
drivers/net/wireless/realtek/rtw89/mac_be.c | 1 +
10 files changed, 556 insertions(+), 43 deletions(-)
--
2.25.1
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH rtw-next 01/11] wifi: rtw89: extract link part from core tx write function
2025-05-05 7:24 [PATCH rtw-next 00/11] wifi: rtw89: support MLO feature Ping-Ke Shih
@ 2025-05-05 7:24 ` Ping-Ke Shih
2025-05-10 1:06 ` Ping-Ke Shih
2025-05-05 7:24 ` [PATCH rtw-next 02/11] wifi: rtw89: allow driver to do specific band TX for MLO Ping-Ke Shih
` (9 subsequent siblings)
10 siblings, 1 reply; 13+ messages in thread
From: Ping-Ke Shih @ 2025-05-05 7:24 UTC (permalink / raw)
To: linux-wireless; +Cc: phhuang, kevin_yang
From: Zong-Zhe Yang <kevin_yang@realtek.com>
Extract core_tx_write_link from core_tx_write to accept given links as
parameters. To make the follow-up changes of TX description more clear,
tweak SW functions to split things ahead.
(don't change logic at all)
Signed-off-by: Zong-Zhe Yang <kevin_yang@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
drivers/net/wireless/realtek/rtw89/core.c | 58 ++++++++++++++---------
1 file changed, 35 insertions(+), 23 deletions(-)
diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c
index e681e8abc20d..0fd902eef05b 100644
--- a/drivers/net/wireless/realtek/rtw89/core.c
+++ b/drivers/net/wireless/realtek/rtw89/core.c
@@ -1123,32 +1123,17 @@ int rtw89_h2c_tx(struct rtw89_dev *rtwdev,
return 0;
}
-int rtw89_core_tx_write(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif,
- struct ieee80211_sta *sta, struct sk_buff *skb, int *qsel)
+static int rtw89_core_tx_write_link(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_sta_link *rtwsta_link,
+ struct sk_buff *skb, int *qsel)
{
- struct rtw89_sta *rtwsta = sta_to_rtwsta_safe(sta);
- struct rtw89_vif *rtwvif = vif_to_rtwvif(vif);
- struct rtw89_core_tx_request tx_req = {0};
- struct rtw89_sta_link *rtwsta_link = NULL;
- struct rtw89_vif_link *rtwvif_link;
+ struct ieee80211_sta *sta = rtwsta_link_to_sta_safe(rtwsta_link);
+ struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link);
+ struct rtw89_vif *rtwvif = rtwvif_link->rtwvif;
+ struct rtw89_core_tx_request tx_req = {};
int ret;
- if (rtwsta) {
- rtwsta_link = rtw89_get_designated_link(rtwsta);
- if (unlikely(!rtwsta_link)) {
- rtw89_err(rtwdev, "tx: find no sta designated link\n");
- return -ENOLINK;
- }
-
- rtwvif_link = rtwsta_link->rtwvif_link;
- } else {
- rtwvif_link = rtw89_get_designated_link(rtwvif);
- if (unlikely(!rtwvif_link)) {
- rtw89_err(rtwdev, "tx: find no vif designated link\n");
- return -ENOLINK;
- }
- }
-
tx_req.skb = skb;
tx_req.vif = vif;
tx_req.sta = sta;
@@ -1172,6 +1157,33 @@ int rtw89_core_tx_write(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif,
return 0;
}
+int rtw89_core_tx_write(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta, struct sk_buff *skb, int *qsel)
+{
+ struct rtw89_sta *rtwsta = sta_to_rtwsta_safe(sta);
+ struct rtw89_vif *rtwvif = vif_to_rtwvif(vif);
+ struct rtw89_sta_link *rtwsta_link = NULL;
+ struct rtw89_vif_link *rtwvif_link;
+
+ if (rtwsta) {
+ rtwsta_link = rtw89_get_designated_link(rtwsta);
+ if (unlikely(!rtwsta_link)) {
+ rtw89_err(rtwdev, "tx: find no sta designated link\n");
+ return -ENOLINK;
+ }
+
+ rtwvif_link = rtwsta_link->rtwvif_link;
+ } else {
+ rtwvif_link = rtw89_get_designated_link(rtwvif);
+ if (unlikely(!rtwvif_link)) {
+ rtw89_err(rtwdev, "tx: find no vif designated link\n");
+ return -ENOLINK;
+ }
+ }
+
+ return rtw89_core_tx_write_link(rtwdev, rtwvif_link, rtwsta_link, skb, qsel);
+}
+
static __le32 rtw89_build_txwd_body0(struct rtw89_tx_desc_info *desc_info)
{
u32 dword = FIELD_PREP(RTW89_TXWD_BODY0_WP_OFFSET, desc_info->wp_offset) |
--
2.25.1
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH rtw-next 02/11] wifi: rtw89: allow driver to do specific band TX for MLO
2025-05-05 7:24 [PATCH rtw-next 00/11] wifi: rtw89: support MLO feature Ping-Ke Shih
2025-05-05 7:24 ` [PATCH rtw-next 01/11] wifi: rtw89: extract link part from core tx write function Ping-Ke Shih
@ 2025-05-05 7:24 ` Ping-Ke Shih
2025-05-05 7:24 ` [PATCH rtw-next 03/11] wifi: rtw89: send nullfunc based on the given link Ping-Ke Shih
` (8 subsequent siblings)
10 siblings, 0 replies; 13+ messages in thread
From: Ping-Ke Shih @ 2025-05-05 7:24 UTC (permalink / raw)
To: linux-wireless; +Cc: phhuang, kevin_yang
From: Po-Hao Huang <phhuang@realtek.com>
For data packets that can be sent on any band, fill in main mac_id
and let HW decide. For packets that we wish to transmit on specific
band, fill in sw_mld field so HW would only send it on that band.
Main mac_id is the corresponding mac_id on band 0.
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>
---
drivers/net/wireless/realtek/rtw89/core.c | 17 ++++++++++++++---
drivers/net/wireless/realtek/rtw89/core.h | 1 +
2 files changed, 15 insertions(+), 3 deletions(-)
diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c
index 0fd902eef05b..c8b00f790829 100644
--- a/drivers/net/wireless/realtek/rtw89/core.c
+++ b/drivers/net/wireless/realtek/rtw89/core.c
@@ -658,9 +658,17 @@ static u16 rtw89_core_get_mgmt_rate(struct rtw89_dev *rtwdev,
static u8 rtw89_core_tx_get_mac_id(struct rtw89_dev *rtwdev,
struct rtw89_core_tx_request *tx_req)
{
+ struct rtw89_tx_desc_info *desc_info = &tx_req->desc_info;
struct rtw89_vif_link *rtwvif_link = tx_req->rtwvif_link;
struct rtw89_sta_link *rtwsta_link = tx_req->rtwsta_link;
+ if (desc_info->mlo && !desc_info->sw_mld) {
+ if (rtwsta_link)
+ return rtw89_sta_get_main_macid(rtwsta_link->rtwsta);
+ else
+ return rtw89_vif_get_main_macid(rtwvif_link->rtwvif);
+ }
+
if (!rtwsta_link)
return rtwvif_link->mac_id;
@@ -1126,7 +1134,7 @@ int rtw89_h2c_tx(struct rtw89_dev *rtwdev,
static int rtw89_core_tx_write_link(struct rtw89_dev *rtwdev,
struct rtw89_vif_link *rtwvif_link,
struct rtw89_sta_link *rtwsta_link,
- struct sk_buff *skb, int *qsel)
+ struct sk_buff *skb, int *qsel, bool sw_mld)
{
struct ieee80211_sta *sta = rtwsta_link_to_sta_safe(rtwsta_link);
struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link);
@@ -1139,6 +1147,7 @@ static int rtw89_core_tx_write_link(struct rtw89_dev *rtwdev,
tx_req.sta = sta;
tx_req.rtwvif_link = rtwvif_link;
tx_req.rtwsta_link = rtwsta_link;
+ tx_req.desc_info.sw_mld = sw_mld;
rtw89_traffic_stats_accu(rtwdev, &rtwdev->stats, skb, true);
rtw89_traffic_stats_accu(rtwdev, &rtwvif->stats, skb, true);
@@ -1181,7 +1190,7 @@ int rtw89_core_tx_write(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif,
}
}
- return rtw89_core_tx_write_link(rtwdev, rtwvif_link, rtwsta_link, skb, qsel);
+ return rtw89_core_tx_write_link(rtwdev, rtwvif_link, rtwsta_link, skb, qsel, false);
}
static __le32 rtw89_build_txwd_body0(struct rtw89_tx_desc_info *desc_info)
@@ -1411,7 +1420,9 @@ static __le32 rtw89_build_txwd_body2_v2(struct rtw89_tx_desc_info *desc_info)
static __le32 rtw89_build_txwd_body3_v2(struct rtw89_tx_desc_info *desc_info)
{
- u32 dword = FIELD_PREP(BE_TXD_BODY3_WIFI_SEQ, desc_info->seq);
+ u32 dword = FIELD_PREP(BE_TXD_BODY3_WIFI_SEQ, desc_info->seq) |
+ FIELD_PREP(BE_TXD_BODY3_MLO_FLAG, desc_info->mlo) |
+ FIELD_PREP(BE_TXD_BODY3_IS_MLD_SW_EN, desc_info->sw_mld);
return cpu_to_le32(dword);
}
diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h
index dfc578ad8c64..4e44cbd6cc53 100644
--- a/drivers/net/wireless/realtek/rtw89/core.h
+++ b/drivers/net/wireless/realtek/rtw89/core.h
@@ -1175,6 +1175,7 @@ struct rtw89_tx_desc_info {
bool ldpc;
bool upd_wlan_hdr;
bool mlo;
+ bool sw_mld;
};
struct rtw89_core_tx_request {
--
2.25.1
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH rtw-next 03/11] wifi: rtw89: send nullfunc based on the given link
2025-05-05 7:24 [PATCH rtw-next 00/11] wifi: rtw89: support MLO feature Ping-Ke Shih
2025-05-05 7:24 ` [PATCH rtw-next 01/11] wifi: rtw89: extract link part from core tx write function Ping-Ke Shih
2025-05-05 7:24 ` [PATCH rtw-next 02/11] wifi: rtw89: allow driver to do specific band TX for MLO Ping-Ke Shih
@ 2025-05-05 7:24 ` Ping-Ke Shih
2025-05-05 7:24 ` [PATCH rtw-next 04/11] wifi: rtw89: chan: re-calculate MLO DBCC mode during setting channel Ping-Ke Shih
` (7 subsequent siblings)
10 siblings, 0 replies; 13+ messages in thread
From: Ping-Ke Shih @ 2025-05-05 7:24 UTC (permalink / raw)
To: linux-wireless; +Cc: phhuang, kevin_yang
From: Po-Hao Huang <phhuang@realtek.com>
The nullfunc sender function is link specific. Use core_tx_write_link
with sw_mld flag to TX the nullfunc via the given link.
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>
---
drivers/net/wireless/realtek/rtw89/core.c | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c
index c8b00f790829..c5bb3452946e 100644
--- a/drivers/net/wireless/realtek/rtw89/core.c
+++ b/drivers/net/wireless/realtek/rtw89/core.c
@@ -3335,8 +3335,10 @@ static int rtw89_core_send_nullfunc(struct rtw89_dev *rtwdev,
{
struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link);
int link_id = ieee80211_vif_is_mld(vif) ? rtwvif_link->link_id : -1;
+ struct rtw89_sta_link *rtwsta_link;
struct ieee80211_sta *sta;
struct ieee80211_hdr *hdr;
+ struct rtw89_sta *rtwsta;
struct sk_buff *skb;
int ret, qsel;
@@ -3349,6 +3351,7 @@ static int rtw89_core_send_nullfunc(struct rtw89_dev *rtwdev,
ret = -EINVAL;
goto out;
}
+ rtwsta = sta_to_rtwsta(sta);
skb = ieee80211_nullfunc_get(rtwdev->hw, vif, link_id, qos);
if (!skb) {
@@ -3360,7 +3363,13 @@ static int rtw89_core_send_nullfunc(struct rtw89_dev *rtwdev,
if (ps)
hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM);
- ret = rtw89_core_tx_write(rtwdev, vif, sta, skb, &qsel);
+ rtwsta_link = rtwsta->links[rtwvif_link->link_id];
+ if (unlikely(!rtwsta_link)) {
+ ret = -ENOLINK;
+ goto out;
+ }
+
+ ret = rtw89_core_tx_write_link(rtwdev, rtwvif_link, rtwsta_link, skb, &qsel, true);
if (ret) {
rtw89_warn(rtwdev, "nullfunc transmit failed: %d\n", ret);
dev_kfree_skb_any(skb);
--
2.25.1
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH rtw-next 04/11] wifi: rtw89: chan: re-calculate MLO DBCC mode during setting channel
2025-05-05 7:24 [PATCH rtw-next 00/11] wifi: rtw89: support MLO feature Ping-Ke Shih
` (2 preceding siblings ...)
2025-05-05 7:24 ` [PATCH rtw-next 03/11] wifi: rtw89: send nullfunc based on the given link Ping-Ke Shih
@ 2025-05-05 7:24 ` Ping-Ke Shih
2025-05-05 7:24 ` [PATCH rtw-next 05/11] wifi: rtw89: add handling of mlo_link_cfg H2C command and C2H event Ping-Ke Shih
` (6 subsequent siblings)
10 siblings, 0 replies; 13+ messages in thread
From: Ping-Ke Shih @ 2025-05-05 7:24 UTC (permalink / raw)
To: linux-wireless; +Cc: phhuang, kevin_yang
From: Zong-Zhe Yang <kevin_yang@realtek.com>
Wi-Fi 7 chips have dual HW bands. After impending MLO support, they
can work with HW-[0] / HW-[1] / HW-[0,1] according to active links.
So, during setting channel, also re-calculate the MLO DBCC mode flag.
Then, leaf chip functions of setting channel can configure with HWs
based on current case.
Besides, tweak the initial and idle MLO DBCC mode of Wi-Fi 7 chips to
MLO_1_PLUS_1_1RF to work with dual HW bands. And, after disconnecting,
due to no active links, MLO DBCC mode will re-calculate to idle case,
i.e. MLO_1_PLUS_1_1RF.
Signed-off-by: Zong-Zhe Yang <kevin_yang@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
drivers/net/wireless/realtek/rtw89/chan.c | 32 +++++++++++++++++++++++
drivers/net/wireless/realtek/rtw89/core.c | 2 +-
2 files changed, 33 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/realtek/rtw89/chan.c b/drivers/net/wireless/realtek/rtw89/chan.c
index 4fec61ed3454..871befa63889 100644
--- a/drivers/net/wireless/realtek/rtw89/chan.c
+++ b/drivers/net/wireless/realtek/rtw89/chan.c
@@ -359,12 +359,41 @@ const struct rtw89_chan *__rtw89_mgnt_chan_get(struct rtw89_dev *rtwdev,
}
EXPORT_SYMBOL(__rtw89_mgnt_chan_get);
+static enum rtw89_mlo_dbcc_mode
+rtw89_entity_sel_mlo_dbcc_mode(struct rtw89_dev *rtwdev, u8 active_hws)
+{
+ if (rtwdev->chip->chip_gen != RTW89_CHIP_BE)
+ return MLO_DBCC_NOT_SUPPORT;
+
+ switch (active_hws) {
+ case BIT(0):
+ return MLO_2_PLUS_0_1RF;
+ case BIT(1):
+ return MLO_0_PLUS_2_1RF;
+ case BIT(0) | BIT(1):
+ default:
+ return MLO_1_PLUS_1_1RF;
+ }
+}
+
+static
+void rtw89_entity_recalc_mlo_dbcc_mode(struct rtw89_dev *rtwdev, u8 active_hws)
+{
+ enum rtw89_mlo_dbcc_mode mode;
+
+ mode = rtw89_entity_sel_mlo_dbcc_mode(rtwdev, active_hws);
+ rtwdev->mlo_dbcc_mode = mode;
+
+ rtw89_debug(rtwdev, RTW89_DBG_STATE, "recalc mlo dbcc mode to %d\n", mode);
+}
+
static void rtw89_entity_recalc_mgnt_roles(struct rtw89_dev *rtwdev)
{
struct rtw89_hal *hal = &rtwdev->hal;
struct rtw89_entity_mgnt *mgnt = &hal->entity_mgnt;
struct rtw89_vif_link *link;
struct rtw89_vif *role;
+ u8 active_hws = 0;
u8 pos = 0;
int i, j;
@@ -413,10 +442,13 @@ static void rtw89_entity_recalc_mgnt_roles(struct rtw89_dev *rtwdev)
continue;
mgnt->chanctx_tbl[pos][i] = link->chanctx_idx;
+ active_hws |= BIT(i);
}
mgnt->active_roles[pos++] = role;
}
+
+ rtw89_entity_recalc_mlo_dbcc_mode(rtwdev, active_hws);
}
enum rtw89_entity_mode rtw89_entity_recalc(struct rtw89_dev *rtwdev)
diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c
index c5bb3452946e..1546e3d8e2e0 100644
--- a/drivers/net/wireless/realtek/rtw89/core.c
+++ b/drivers/net/wireless/realtek/rtw89/core.c
@@ -4966,7 +4966,7 @@ int rtw89_core_init(struct rtw89_dev *rtwdev)
if (rtwdev->chip->chip_gen == RTW89_CHIP_BE) {
rtwdev->dbcc_en = true;
rtwdev->mac.qta_mode = RTW89_QTA_DBCC;
- rtwdev->mlo_dbcc_mode = MLO_2_PLUS_0_1RF;
+ rtwdev->mlo_dbcc_mode = MLO_1_PLUS_1_1RF;
}
rtwdev->bbs[RTW89_PHY_0].phy_idx = RTW89_PHY_0;
--
2.25.1
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH rtw-next 05/11] wifi: rtw89: add handling of mlo_link_cfg H2C command and C2H event
2025-05-05 7:24 [PATCH rtw-next 00/11] wifi: rtw89: support MLO feature Ping-Ke Shih
` (3 preceding siblings ...)
2025-05-05 7:24 ` [PATCH rtw-next 04/11] wifi: rtw89: chan: re-calculate MLO DBCC mode during setting channel Ping-Ke Shih
@ 2025-05-05 7:24 ` Ping-Ke Shih
2025-05-05 7:24 ` [PATCH rtw-next 06/11] wifi: rtw89: add MLO track for MLSR switch decision Ping-Ke Shih
` (5 subsequent siblings)
10 siblings, 0 replies; 13+ messages in thread
From: Ping-Ke Shih @ 2025-05-05 7:24 UTC (permalink / raw)
To: linux-wireless; +Cc: phhuang, kevin_yang
From: Zong-Zhe Yang <kevin_yang@realtek.com>
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>
---
drivers/net/wireless/realtek/rtw89/core.c | 1 +
drivers/net/wireless/realtek/rtw89/core.h | 5 +++
drivers/net/wireless/realtek/rtw89/fw.c | 41 +++++++++++++++++++
drivers/net/wireless/realtek/rtw89/fw.h | 48 +++++++++++++++++++++++
drivers/net/wireless/realtek/rtw89/mac.c | 39 ++++++++++++++++++
drivers/net/wireless/realtek/rtw89/mac.h | 13 ++++++
6 files changed, 147 insertions(+)
diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c
index 1546e3d8e2e0..b7b2670cbc88 100644
--- a/drivers/net/wireless/realtek/rtw89/core.c
+++ b/drivers/net/wireless/realtek/rtw89/core.c
@@ -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);
diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h
index 4e44cbd6cc53..86bbe8cf8cc0 100644
--- a/drivers/net/wireless/realtek/rtw89/core.h
+++ b/drivers/net/wireless/realtek/rtw89/core.h
@@ -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;
diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c
index 23f4dea64dc6..aa748fe3f39e 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.c
+++ b/drivers/net/wireless/realtek/rtw89/fw.c
@@ -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] = {};
diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h
index 559f3f6190eb..207ec88ea456 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.h
+++ b/drivers/net/wireless/realtek/rtw89/fw.h
@@ -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)
{
diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c
index 449865f7b7a9..e3976ba6dda2 100644
--- a/drivers/net/wireless/realtek/rtw89/mac.c
+++ b/drivers/net/wireless/realtek/rtw89/mac.c
@@ -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];
diff --git a/drivers/net/wireless/realtek/rtw89/mac.h b/drivers/net/wireless/realtek/rtw89/mac.h
index 47d655fbf2ca..e1083b0f8136 100644
--- a/drivers/net/wireless/realtek/rtw89/mac.h
+++ b/drivers/net/wireless/realtek/rtw89/mac.h
@@ -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,
--
2.25.1
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH rtw-next 06/11] wifi: rtw89: add MLO track for MLSR switch decision
2025-05-05 7:24 [PATCH rtw-next 00/11] wifi: rtw89: support MLO feature Ping-Ke Shih
` (4 preceding siblings ...)
2025-05-05 7:24 ` [PATCH rtw-next 05/11] wifi: rtw89: add handling of mlo_link_cfg H2C command and C2H event Ping-Ke Shih
@ 2025-05-05 7:24 ` Ping-Ke Shih
2025-05-05 7:24 ` [PATCH rtw-next 07/11] wifi: rtw89: debug: extend dbgfs for MLO Ping-Ke Shih
` (4 subsequent siblings)
10 siblings, 0 replies; 13+ messages in thread
From: Ping-Ke Shih @ 2025-05-05 7:24 UTC (permalink / raw)
To: linux-wireless; +Cc: phhuang, kevin_yang
From: Po-Hao Huang <phhuang@realtek.com>
Add MLSR switch mechanism based on tracking RSSI. Switch to a 2 GHz link
(if any) when average RSSI is lower than threshold -53. And, switch out
from a 2 GHz link when average RSSI is larger than threshold -38.
The sequence of MLSR switch handling is like the following.
1. initialize target link and configure to PS mode
2. configure current designated link to PS mode
3. configure target link to non-PS mode
4. deinitialize currently active links except target link
The above flow also implies that target link becomes new designated link.
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>
---
drivers/net/wireless/realtek/rtw89/core.c | 159 ++++++++++++++++++
drivers/net/wireless/realtek/rtw89/core.h | 10 ++
drivers/net/wireless/realtek/rtw89/fw.c | 4 +-
drivers/net/wireless/realtek/rtw89/mac80211.c | 2 +
4 files changed, 174 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c
index b7b2670cbc88..95bdd46376bf 100644
--- a/drivers/net/wireless/realtek/rtw89/core.c
+++ b/drivers/net/wireless/realtek/rtw89/core.c
@@ -3638,6 +3638,94 @@ void rtw89_traffic_stats_init(struct rtw89_dev *rtwdev,
ewma_tp_init(&stats->rx_ewma_tp);
}
+#define RTW89_MLSR_GOTO_2GHZ_THRESHOLD -53
+#define RTW89_MLSR_EXIT_2GHZ_THRESHOLD -38
+static void rtw89_core_mlsr_link_decision(struct rtw89_dev *rtwdev,
+ struct rtw89_vif *rtwvif)
+{
+ unsigned int sel_link_id = IEEE80211_MLD_MAX_NUM_LINKS;
+ struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif);
+ struct rtw89_vif_link *rtwvif_link;
+ const struct rtw89_chan *chan;
+ unsigned long usable_links;
+ unsigned int link_id;
+ u8 decided_bands;
+ u8 rssi;
+
+ rssi = ewma_rssi_read(&rtwdev->phystat.bcn_rssi);
+ if (unlikely(!rssi))
+ return;
+
+ if (RTW89_RSSI_RAW_TO_DBM(rssi) >= RTW89_MLSR_EXIT_2GHZ_THRESHOLD)
+ decided_bands = BIT(RTW89_BAND_5G) | BIT(RTW89_BAND_6G);
+ else if (RTW89_RSSI_RAW_TO_DBM(rssi) <= RTW89_MLSR_GOTO_2GHZ_THRESHOLD)
+ decided_bands = BIT(RTW89_BAND_2G);
+ else
+ return;
+
+ usable_links = ieee80211_vif_usable_links(vif);
+
+ rtwvif_link = rtw89_get_designated_link(rtwvif);
+ if (unlikely(!rtwvif_link))
+ goto select;
+
+ chan = rtw89_chan_get(rtwdev, rtwvif_link->chanctx_idx);
+ if (decided_bands & BIT(chan->band_type))
+ return;
+
+ usable_links &= ~BIT(rtwvif_link->link_id);
+
+select:
+ rcu_read_lock();
+
+ for_each_set_bit(link_id, &usable_links, IEEE80211_MLD_MAX_NUM_LINKS) {
+ struct ieee80211_bss_conf *link_conf;
+ struct ieee80211_channel *channel;
+ enum rtw89_band band;
+
+ link_conf = rcu_dereference(vif->link_conf[link_id]);
+ if (unlikely(!link_conf))
+ continue;
+
+ channel = link_conf->chanreq.oper.chan;
+ if (unlikely(!channel))
+ continue;
+
+ band = rtw89_nl80211_to_hw_band(channel->band);
+ if (decided_bands & BIT(band)) {
+ sel_link_id = link_id;
+ break;
+ }
+ }
+
+ rcu_read_unlock();
+
+ if (sel_link_id == IEEE80211_MLD_MAX_NUM_LINKS)
+ return;
+
+ rtw89_core_mlsr_switch(rtwdev, rtwvif, sel_link_id);
+}
+
+static void rtw89_core_mlo_track(struct rtw89_dev *rtwdev)
+{
+ struct ieee80211_vif *vif;
+ struct rtw89_vif *rtwvif;
+
+ rtw89_for_each_rtwvif(rtwdev, rtwvif) {
+ vif = rtwvif_to_vif(rtwvif);
+ if (!vif->cfg.assoc || !ieee80211_vif_is_mld(vif))
+ continue;
+
+ switch (rtwvif->mlo_mode) {
+ case RTW89_MLO_MODE_MLSR:
+ rtw89_core_mlsr_link_decision(rtwdev, rtwvif);
+ break;
+ default:
+ break;
+ }
+ }
+}
+
static void rtw89_track_work(struct wiphy *wiphy, struct wiphy_work *work)
{
struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev,
@@ -3679,6 +3767,7 @@ static void rtw89_track_work(struct wiphy *wiphy, struct wiphy_work *work)
rtw89_sar_track(rtwdev);
rtw89_chanctx_track(rtwdev);
rtw89_core_rfkill_poll(rtwdev, false);
+ rtw89_core_mlo_track(rtwdev);
if (rtwdev->lps_enabled && !rtwdev->btc.lps)
rtw89_enter_lps_track(rtwdev);
@@ -5125,6 +5214,76 @@ static void rtw89_core_setup_rfe_parms(struct rtw89_dev *rtwdev)
rtw89_load_txpwr_table(rtwdev, rtwdev->rfe_parms->byr_tbl);
}
+int rtw89_core_mlsr_switch(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
+ unsigned int link_id)
+{
+ struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif);
+ u16 usable_links = ieee80211_vif_usable_links(vif);
+ u16 active_links = vif->active_links;
+ struct rtw89_vif_link *target, *cur;
+ int ret;
+
+ lockdep_assert_wiphy(rtwdev->hw->wiphy);
+
+ if (unlikely(!ieee80211_vif_is_mld(vif)))
+ return -EOPNOTSUPP;
+
+ if (unlikely(!(usable_links & BIT(link_id)))) {
+ rtw89_warn(rtwdev, "%s: link id %u is not usable\n", __func__,
+ link_id);
+ return -ENOLINK;
+ }
+
+ if (active_links == BIT(link_id))
+ return 0;
+
+ rtw89_debug(rtwdev, RTW89_DBG_STATE, "%s: switch to link id %u MLSR\n",
+ __func__, link_id);
+
+ rtw89_leave_lps(rtwdev);
+
+ ieee80211_stop_queues(rtwdev->hw);
+ flush_work(&rtwdev->txq_work);
+
+ cur = rtw89_get_designated_link(rtwvif);
+
+ ret = ieee80211_set_active_links(vif, active_links | BIT(link_id));
+ if (ret) {
+ rtw89_err(rtwdev, "%s: failed to activate link id %u\n",
+ __func__, link_id);
+ goto wake_queue;
+ }
+
+ target = rtwvif->links[link_id];
+ if (unlikely(!target)) {
+ rtw89_err(rtwdev, "%s: failed to confirm link id %u\n",
+ __func__, link_id);
+
+ ieee80211_set_active_links(vif, active_links);
+ ret = -EFAULT;
+ goto wake_queue;
+ }
+
+ if (likely(cur))
+ rtw89_fw_h2c_mlo_link_cfg(rtwdev, cur, false);
+
+ rtw89_fw_h2c_mlo_link_cfg(rtwdev, target, true);
+
+ ret = ieee80211_set_active_links(vif, BIT(link_id));
+ if (ret)
+ rtw89_err(rtwdev, "%s: failed to inactivate links 0x%x\n",
+ __func__, active_links);
+
+ rtw89_chip_rfk_channel(rtwdev, target);
+
+ rtwvif->mlo_mode = RTW89_MLO_MODE_MLSR;
+
+wake_queue:
+ ieee80211_wake_queues(rtwdev->hw);
+
+ return ret;
+}
+
static int rtw89_chip_efuse_info_setup(struct rtw89_dev *rtwdev)
{
const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h
index 86bbe8cf8cc0..a432dd846a1f 100644
--- a/drivers/net/wireless/realtek/rtw89/core.h
+++ b/drivers/net/wireless/realtek/rtw89/core.h
@@ -5738,6 +5738,12 @@ struct rtw89_mcc_info {
struct rtw89_mcc_config config;
};
+enum rtw89_mlo_mode {
+ RTW89_MLO_MODE_MLSR = 0,
+
+ NUM_OF_RTW89_MLO_MODE,
+};
+
struct rtw89_mlo_info {
struct rtw89_wait_info wait;
};
@@ -5894,6 +5900,8 @@ struct rtw89_vif {
struct rtw89_roc roc;
bool offchan;
+ enum rtw89_mlo_mode mlo_mode;
+
struct list_head dlink_pool;
u8 links_inst_valid_num;
DECLARE_BITMAP(links_inst_map, __RTW89_MLD_MAX_LINK_NUM);
@@ -7312,5 +7320,7 @@ void rtw89_core_update_p2p_ps(struct rtw89_dev *rtwdev,
struct rtw89_vif_link *rtwvif_link,
struct ieee80211_bss_conf *bss_conf);
void rtw89_core_ntfy_btc_event(struct rtw89_dev *rtwdev, enum rtw89_btc_hmsg event);
+int rtw89_core_mlsr_switch(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
+ unsigned int link_id);
#endif
diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c
index aa748fe3f39e..deb4fb21d0e0 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.c
+++ b/drivers/net/wireless/realtek/rtw89/fw.c
@@ -4043,6 +4043,7 @@ int rtw89_fw_h2c_join_info(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwv
bool format_v1 = false;
struct sk_buff *skb;
u8 main_mac_id;
+ bool init_ps;
int ret;
if (rtwdev->chip->chip_gen == RTW89_CHIP_BE) {
@@ -4084,6 +4085,7 @@ int rtw89_fw_h2c_join_info(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwv
h2c_v1 = (struct rtw89_h2c_join_v1 *)skb->data;
sta_type = rtw89_fw_get_sta_type(rtwdev, rtwvif_link, rtwsta_link);
+ init_ps = rtwvif_link != rtw89_get_designated_link(rtwvif_link->rtwvif);
if (rtwsta_link)
main_mac_id = rtw89_sta_get_main_macid(rtwsta_link->rtwsta);
@@ -4097,7 +4099,7 @@ int rtw89_fw_h2c_join_info(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwv
RTW89_H2C_JOININFO_W1_MLO_MODE) |
le32_encode_bits(0, RTW89_H2C_JOININFO_W1_EMLSR_CAB) |
le32_encode_bits(0, RTW89_H2C_JOININFO_W1_NSTR_EN) |
- le32_encode_bits(0, RTW89_H2C_JOININFO_W1_INIT_PWR_STATE) |
+ le32_encode_bits(init_ps, RTW89_H2C_JOININFO_W1_INIT_PWR_STATE) |
le32_encode_bits(IEEE80211_EML_CAP_EMLSR_PADDING_DELAY_256US,
RTW89_H2C_JOININFO_W1_EMLSR_PADDING) |
le32_encode_bits(IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY_256US,
diff --git a/drivers/net/wireless/realtek/rtw89/mac80211.c b/drivers/net/wireless/realtek/rtw89/mac80211.c
index 182a952127c4..22d13a0d5b8a 100644
--- a/drivers/net/wireless/realtek/rtw89/mac80211.c
+++ b/drivers/net/wireless/realtek/rtw89/mac80211.c
@@ -481,6 +481,8 @@ static int __rtw89_ops_sta_add(struct rtw89_dev *rtwdev,
int i;
if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) {
+ rtwvif->mlo_mode = RTW89_MLO_MODE_MLSR;
+
/* for station mode, assign the mac_id from itself */
macid = rtw89_vif_get_main_macid(rtwvif);
} else {
--
2.25.1
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH rtw-next 07/11] wifi: rtw89: debug: extend dbgfs for MLO
2025-05-05 7:24 [PATCH rtw-next 00/11] wifi: rtw89: support MLO feature Ping-Ke Shih
` (5 preceding siblings ...)
2025-05-05 7:24 ` [PATCH rtw-next 06/11] wifi: rtw89: add MLO track for MLSR switch decision Ping-Ke Shih
@ 2025-05-05 7:24 ` Ping-Ke Shih
2025-05-05 7:24 ` [PATCH rtw-next 08/11] wifi: rtw89: debug: add MLD table dump Ping-Ke Shih
` (3 subsequent siblings)
10 siblings, 0 replies; 13+ messages in thread
From: Ping-Ke Shih @ 2025-05-05 7:24 UTC (permalink / raw)
To: linux-wireless; +Cc: phhuang, kevin_yang
From: Po-Hao Huang <phhuang@realtek.com>
Extend dbgfs vif/sta info to show current designated link.
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>
---
drivers/net/wireless/realtek/rtw89/debug.c | 24 ++++++++++++++++------
1 file changed, 18 insertions(+), 6 deletions(-)
diff --git a/drivers/net/wireless/realtek/rtw89/debug.c b/drivers/net/wireless/realtek/rtw89/debug.c
index 10e011827379..5442e3c9cbb7 100644
--- a/drivers/net/wireless/realtek/rtw89/debug.c
+++ b/drivers/net/wireless/realtek/rtw89/debug.c
@@ -3971,14 +3971,16 @@ static int rtw89_dump_pkt_offload(char *buf, size_t bufsz, struct list_head *pkt
static int rtw89_vif_link_ids_get(struct rtw89_dev *rtwdev,
char *buf, size_t bufsz, u8 *mac,
- struct rtw89_vif_link *rtwvif_link)
+ struct rtw89_vif_link *rtwvif_link,
+ bool designated)
{
struct rtw89_bssid_cam_entry *bssid_cam = &rtwvif_link->bssid_cam;
char *p = buf, *end = buf + bufsz;
p += scnprintf(p, end - p, " [%u] %pM\n", rtwvif_link->mac_id,
rtwvif_link->mac_addr);
- p += scnprintf(p, end - p, "\tlink_id=%u\n", rtwvif_link->link_id);
+ p += scnprintf(p, end - p, "\tlink_id=%u%s\n", rtwvif_link->link_id,
+ designated ? " (*)" : "");
p += scnprintf(p, end - p, "\tbssid_cam_idx=%u\n",
bssid_cam->bssid_cam_idx);
p += rtw89_dump_addr_cam(rtwdev, p, end - p, &rtwvif_link->addr_cam);
@@ -3995,15 +3997,19 @@ void rtw89_vif_ids_get_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
(struct rtw89_debugfs_iter_data *)data;
struct rtw89_vif *rtwvif = vif_to_rtwvif(vif);
struct rtw89_dev *rtwdev = rtwvif->rtwdev;
+ struct rtw89_vif_link *designated_link;
struct rtw89_vif_link *rtwvif_link;
size_t bufsz = iter_data->bufsz;
char *buf = iter_data->buf;
char *p = buf, *end = buf + bufsz;
unsigned int link_id;
+ designated_link = rtw89_get_designated_link(rtwvif);
+
p += scnprintf(p, end - p, "VIF %pM\n", rtwvif->mac_addr);
rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id)
- p += rtw89_vif_link_ids_get(rtwdev, p, end - p, mac, rtwvif_link);
+ p += rtw89_vif_link_ids_get(rtwdev, p, end - p, mac, rtwvif_link,
+ rtwvif_link == designated_link);
rtw89_debugfs_iter_data_next(iter_data, p, end - p, p - buf);
}
@@ -4033,7 +4039,8 @@ static int rtw89_dump_ba_cam(struct rtw89_dev *rtwdev,
static int rtw89_sta_link_ids_get(struct rtw89_dev *rtwdev,
char *buf, size_t bufsz,
- struct rtw89_sta_link *rtwsta_link)
+ struct rtw89_sta_link *rtwsta_link,
+ bool designated)
{
struct ieee80211_link_sta *link_sta;
char *p = buf, *end = buf + bufsz;
@@ -4047,7 +4054,8 @@ static int rtw89_sta_link_ids_get(struct rtw89_dev *rtwdev,
rcu_read_unlock();
- p += scnprintf(p, end - p, "\tlink_id=%u\n", rtwsta_link->link_id);
+ p += scnprintf(p, end - p, "\tlink_id=%u%s\n", rtwsta_link->link_id,
+ designated ? " (*)" : "");
p += rtw89_dump_addr_cam(rtwdev, p, end - p, &rtwsta_link->addr_cam);
p += rtw89_dump_ba_cam(rtwdev, p, end - p, rtwsta_link);
@@ -4060,16 +4068,20 @@ static void rtw89_sta_ids_get_iter(void *data, struct ieee80211_sta *sta)
(struct rtw89_debugfs_iter_data *)data;
struct rtw89_sta *rtwsta = sta_to_rtwsta(sta);
struct rtw89_dev *rtwdev = rtwsta->rtwdev;
+ struct rtw89_sta_link *designated_link;
struct rtw89_sta_link *rtwsta_link;
size_t bufsz = iter_data->bufsz;
char *buf = iter_data->buf;
char *p = buf, *end = buf + bufsz;
unsigned int link_id;
+ designated_link = rtw89_get_designated_link(rtwsta);
+
p += scnprintf(p, end - p, "STA %pM %s\n", sta->addr,
sta->tdls ? "(TDLS)" : "");
rtw89_sta_for_each_link(rtwsta, rtwsta_link, link_id)
- p += rtw89_sta_link_ids_get(rtwdev, p, end - p, rtwsta_link);
+ p += rtw89_sta_link_ids_get(rtwdev, p, end - p, rtwsta_link,
+ rtwsta_link == designated_link);
rtw89_debugfs_iter_data_next(iter_data, p, end - p, p - buf);
}
--
2.25.1
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH rtw-next 08/11] wifi: rtw89: debug: add MLD table dump
2025-05-05 7:24 [PATCH rtw-next 00/11] wifi: rtw89: support MLO feature Ping-Ke Shih
` (6 preceding siblings ...)
2025-05-05 7:24 ` [PATCH rtw-next 07/11] wifi: rtw89: debug: extend dbgfs for MLO Ping-Ke Shih
@ 2025-05-05 7:24 ` Ping-Ke Shih
2025-05-05 7:24 ` [PATCH rtw-next 09/11] wifi: rtw89: debug: add FW log component for MLO Ping-Ke Shih
` (2 subsequent siblings)
10 siblings, 0 replies; 13+ messages in thread
From: Ping-Ke Shih @ 2025-05-05 7:24 UTC (permalink / raw)
To: linux-wireless; +Cc: phhuang, kevin_yang
From: Po-Hao Huang <phhuang@realtek.com>
Add definition for MLD table dump, this is for debug purpose only.
Signed-off-by: Po-Hao Huang <phhuang@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
drivers/net/wireless/realtek/rtw89/mac.h | 1 +
drivers/net/wireless/realtek/rtw89/mac_be.c | 1 +
2 files changed, 2 insertions(+)
diff --git a/drivers/net/wireless/realtek/rtw89/mac.h b/drivers/net/wireless/realtek/rtw89/mac.h
index e1083b0f8136..8013c852d5be 100644
--- a/drivers/net/wireless/realtek/rtw89/mac.h
+++ b/drivers/net/wireless/realtek/rtw89/mac.h
@@ -370,6 +370,7 @@ enum rtw89_mac_mem_sel {
RTW89_MAC_MEM_TXD_FIFO_0_V1,
RTW89_MAC_MEM_TXD_FIFO_1_V1,
RTW89_MAC_MEM_WD_PAGE,
+ RTW89_MAC_MEM_MLD_TBL,
/* keep last */
RTW89_MAC_MEM_NUM,
diff --git a/drivers/net/wireless/realtek/rtw89/mac_be.c b/drivers/net/wireless/realtek/rtw89/mac_be.c
index a1ba6ca431d7..8c9d326dc907 100644
--- a/drivers/net/wireless/realtek/rtw89/mac_be.c
+++ b/drivers/net/wireless/realtek/rtw89/mac_be.c
@@ -29,6 +29,7 @@ static const u32 rtw89_mac_mem_base_addrs_be[RTW89_MAC_MEM_NUM] = {
[RTW89_MAC_MEM_CPU_LOCAL] = CPU_LOCAL_BASE_ADDR_BE,
[RTW89_MAC_MEM_BSSID_CAM] = BSSID_CAM_BASE_ADDR_BE,
[RTW89_MAC_MEM_WD_PAGE] = WD_PAGE_BASE_ADDR_BE,
+ [RTW89_MAC_MEM_MLD_TBL] = MLD_TBL_BASE_ADDR_BE,
};
static const struct rtw89_port_reg rtw89_port_base_be = {
--
2.25.1
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH rtw-next 09/11] wifi: rtw89: debug: add FW log component for MLO
2025-05-05 7:24 [PATCH rtw-next 00/11] wifi: rtw89: support MLO feature Ping-Ke Shih
` (7 preceding siblings ...)
2025-05-05 7:24 ` [PATCH rtw-next 08/11] wifi: rtw89: debug: add MLD table dump Ping-Ke Shih
@ 2025-05-05 7:24 ` Ping-Ke Shih
2025-05-05 7:24 ` [PATCH rtw-next 10/11] wifi: rtw89: debug: add mlo_mode dbgfs Ping-Ke Shih
2025-05-05 7:24 ` [PATCH rtw-next 11/11] wifi: rtw89: declare MLO support if prerequisites are met Ping-Ke Shih
10 siblings, 0 replies; 13+ messages in thread
From: Ping-Ke Shih @ 2025-05-05 7:24 UTC (permalink / raw)
To: linux-wireless; +Cc: phhuang, kevin_yang
From: Po-Hao Huang <phhuang@realtek.com>
This allows showing MLO related logs when FW debug mode is on.
Signed-off-by: Po-Hao Huang <phhuang@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
drivers/net/wireless/realtek/rtw89/fw.c | 2 +-
drivers/net/wireless/realtek/rtw89/fw.h | 1 +
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c
index deb4fb21d0e0..76350351dfb2 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.c
+++ b/drivers/net/wireless/realtek/rtw89/fw.c
@@ -2510,7 +2510,7 @@ int rtw89_fw_h2c_fw_log(struct rtw89_dev *rtwdev, bool enable)
if (enable)
comp = BIT(RTW89_FW_LOG_COMP_INIT) | BIT(RTW89_FW_LOG_COMP_TASK) |
BIT(RTW89_FW_LOG_COMP_PS) | BIT(RTW89_FW_LOG_COMP_ERROR) |
- BIT(RTW89_FW_LOG_COMP_SCAN);
+ BIT(RTW89_FW_LOG_COMP_MLO) | BIT(RTW89_FW_LOG_COMP_SCAN);
skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_LOG_CFG_LEN);
if (!skb) {
diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h
index 207ec88ea456..0fcc824e41be 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.h
+++ b/drivers/net/wireless/realtek/rtw89/fw.h
@@ -199,6 +199,7 @@ enum rtw89_fw_log_comp {
RTW89_FW_LOG_COMP_TWT,
RTW89_FW_LOG_COMP_RF,
RTW89_FW_LOG_COMP_MCC = 20,
+ RTW89_FW_LOG_COMP_MLO = 26,
RTW89_FW_LOG_COMP_SCAN = 28,
};
--
2.25.1
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH rtw-next 10/11] wifi: rtw89: debug: add mlo_mode dbgfs
2025-05-05 7:24 [PATCH rtw-next 00/11] wifi: rtw89: support MLO feature Ping-Ke Shih
` (8 preceding siblings ...)
2025-05-05 7:24 ` [PATCH rtw-next 09/11] wifi: rtw89: debug: add FW log component for MLO Ping-Ke Shih
@ 2025-05-05 7:24 ` Ping-Ke Shih
2025-05-05 7:24 ` [PATCH rtw-next 11/11] wifi: rtw89: declare MLO support if prerequisites are met Ping-Ke Shih
10 siblings, 0 replies; 13+ messages in thread
From: Ping-Ke Shih @ 2025-05-05 7:24 UTC (permalink / raw)
To: linux-wireless; +Cc: phhuang, kevin_yang
From: Zong-Zhe Yang <kevin_yang@realtek.com>
Add an dbgfs mlo_mode to get/set MLO mode. And, support to trigger MLSR
switching. Setting it will automatically disable MLO Dynamic Mechanism
(DM). Then MLO things can follow commands via dbgfs mlo_mode instead of
MLO DM. The disabled DM(s) can be checked/cleared via dbgfs disable_dm.
The following is an use example.
Read it to show current MLD status.
$ cat mlo_mode
MLD(s) status: (MLO DM: enable)
#0: MLO mode 0, valid 0x6, active 0x2
Write it to switch to MLSR on link id 2.
$ echo 0 2 > mlo_mode
$ cat mlo_mode
MLD(s) status: (MLO DM: disable)
#0: MLO mode 0, valid 0x6, active 0x4
Besides, to be safer, add RWLOCK attribute to dbgfs disable_dm.
Signed-off-by: Zong-Zhe Yang <kevin_yang@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
drivers/net/wireless/realtek/rtw89/core.c | 4 +
drivers/net/wireless/realtek/rtw89/core.h | 1 +
drivers/net/wireless/realtek/rtw89/debug.c | 114 ++++++++++++++++++++-
3 files changed, 116 insertions(+), 3 deletions(-)
diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c
index 95bdd46376bf..22a0c54de716 100644
--- a/drivers/net/wireless/realtek/rtw89/core.c
+++ b/drivers/net/wireless/realtek/rtw89/core.c
@@ -3708,9 +3708,13 @@ static void rtw89_core_mlsr_link_decision(struct rtw89_dev *rtwdev,
static void rtw89_core_mlo_track(struct rtw89_dev *rtwdev)
{
+ struct rtw89_hal *hal = &rtwdev->hal;
struct ieee80211_vif *vif;
struct rtw89_vif *rtwvif;
+ if (hal->disabled_dm_bitmap & BIT(RTW89_DM_MLO))
+ return;
+
rtw89_for_each_rtwvif(rtwdev, rtwvif) {
vif = rtwvif_to_vif(rtwvif);
if (!vif->cfg.assoc || !ieee80211_vif_is_mld(vif))
diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h
index a432dd846a1f..c0f2b62bc43b 100644
--- a/drivers/net/wireless/realtek/rtw89/core.h
+++ b/drivers/net/wireless/realtek/rtw89/core.h
@@ -4842,6 +4842,7 @@ enum rtw89_dm_type {
RTW89_DM_DYNAMIC_EDCCA,
RTW89_DM_THERMAL_PROTECT,
RTW89_DM_TAS,
+ RTW89_DM_MLO,
};
#define RTW89_THERMAL_PROT_LV_MAX 5
diff --git a/drivers/net/wireless/realtek/rtw89/debug.c b/drivers/net/wireless/realtek/rtw89/debug.c
index 5442e3c9cbb7..d6016fa107fb 100644
--- a/drivers/net/wireless/realtek/rtw89/debug.c
+++ b/drivers/net/wireless/realtek/rtw89/debug.c
@@ -85,6 +85,7 @@ struct rtw89_debugfs {
struct rtw89_debugfs_priv phy_info;
struct rtw89_debugfs_priv stations;
struct rtw89_debugfs_priv disable_dm;
+ struct rtw89_debugfs_priv mlo_mode;
};
struct rtw89_debugfs_iter_data {
@@ -4136,6 +4137,35 @@ static ssize_t rtw89_debug_priv_stations_get(struct rtw89_dev *rtwdev,
return p - buf;
}
+static void rtw89_debug_disable_dm_cfg_bmap(struct rtw89_dev *rtwdev, u32 new)
+{
+ struct rtw89_hal *hal = &rtwdev->hal;
+ u32 old = hal->disabled_dm_bitmap;
+
+ if (new == old)
+ return;
+
+ hal->disabled_dm_bitmap = new;
+
+ rtw89_debug(rtwdev, RTW89_DBG_STATE, "Disable DM: 0x%x -> 0x%x\n", old, new);
+}
+
+static void rtw89_debug_disable_dm_set_flag(struct rtw89_dev *rtwdev, u8 flag)
+{
+ struct rtw89_hal *hal = &rtwdev->hal;
+ u32 cur = hal->disabled_dm_bitmap;
+
+ rtw89_debug_disable_dm_cfg_bmap(rtwdev, cur | BIT(flag));
+}
+
+static void rtw89_debug_disable_dm_clr_flag(struct rtw89_dev *rtwdev, u8 flag)
+{
+ struct rtw89_hal *hal = &rtwdev->hal;
+ u32 cur = hal->disabled_dm_bitmap;
+
+ rtw89_debug_disable_dm_cfg_bmap(rtwdev, cur & ~BIT(flag));
+}
+
#define DM_INFO(type) {RTW89_DM_ ## type, #type}
static const struct rtw89_disabled_dm_info {
@@ -4145,6 +4175,7 @@ static const struct rtw89_disabled_dm_info {
DM_INFO(DYNAMIC_EDCCA),
DM_INFO(THERMAL_PROTECT),
DM_INFO(TAS),
+ DM_INFO(MLO),
};
static ssize_t
@@ -4178,7 +4209,6 @@ rtw89_debug_priv_disable_dm_set(struct rtw89_dev *rtwdev,
struct rtw89_debugfs_priv *debugfs_priv,
const char *buf, size_t count)
{
- struct rtw89_hal *hal = &rtwdev->hal;
u32 conf;
int ret;
@@ -4186,7 +4216,83 @@ rtw89_debug_priv_disable_dm_set(struct rtw89_dev *rtwdev,
if (ret)
return -EINVAL;
- hal->disabled_dm_bitmap = conf;
+ rtw89_debug_disable_dm_cfg_bmap(rtwdev, conf);
+
+ return count;
+}
+
+static void rtw89_debug_mlo_mode_set_mlsr(struct rtw89_dev *rtwdev,
+ unsigned int link_id)
+{
+ struct ieee80211_vif *vif;
+ struct rtw89_vif *rtwvif;
+
+ rtw89_for_each_rtwvif(rtwdev, rtwvif) {
+ vif = rtwvif_to_vif(rtwvif);
+ if (!ieee80211_vif_is_mld(vif))
+ continue;
+
+ rtw89_core_mlsr_switch(rtwdev, rtwvif, link_id);
+ }
+}
+
+static ssize_t
+rtw89_debug_priv_mlo_mode_get(struct rtw89_dev *rtwdev,
+ struct rtw89_debugfs_priv *debugfs_priv,
+ char *buf, size_t bufsz)
+{
+ bool mlo_dm_dis = rtwdev->hal.disabled_dm_bitmap & BIT(RTW89_DM_MLO);
+ char *p = buf, *end = buf + bufsz;
+ struct ieee80211_vif *vif;
+ struct rtw89_vif *rtwvif;
+ int count = 0;
+
+ p += scnprintf(p, end - p, "MLD(s) status: (MLO DM: %s)\n",
+ str_disable_enable(mlo_dm_dis));
+
+ rtw89_for_each_rtwvif(rtwdev, rtwvif) {
+ vif = rtwvif_to_vif(rtwvif);
+ if (!ieee80211_vif_is_mld(vif))
+ continue;
+
+ p += scnprintf(p, end - p,
+ "\t#%u: MLO mode %x, valid 0x%x, active 0x%x\n",
+ count++, rtwvif->mlo_mode, vif->valid_links,
+ vif->active_links);
+ }
+
+ if (count == 0)
+ p += scnprintf(p, end - p, "\t(None)\n");
+
+ return p - buf;
+}
+
+static ssize_t
+rtw89_debug_priv_mlo_mode_set(struct rtw89_dev *rtwdev,
+ struct rtw89_debugfs_priv *debugfs_priv,
+ const char *buf, size_t count)
+{
+ u8 num, mlo_mode;
+ u32 argv;
+
+ num = sscanf(buf, "%hhx %u", &mlo_mode, &argv);
+ if (num != 2)
+ return -EINVAL;
+
+ rtw89_debug_disable_dm_set_flag(rtwdev, RTW89_DM_MLO);
+
+ rtw89_debug(rtwdev, RTW89_DBG_STATE, "Set MLO mode to %x\n", mlo_mode);
+
+ switch (mlo_mode) {
+ case RTW89_MLO_MODE_MLSR:
+ rtw89_debug_mlo_mode_set_mlsr(rtwdev, argv);
+ break;
+ default:
+ rtw89_debug(rtwdev, RTW89_DBG_STATE, "Unsupported MLO mode\n");
+ rtw89_debug_disable_dm_clr_flag(rtwdev, RTW89_DM_MLO);
+
+ return -EOPNOTSUPP;
+ }
return count;
}
@@ -4247,7 +4353,8 @@ static const struct rtw89_debugfs rtw89_debugfs_templ = {
.fw_log_manual = rtw89_debug_priv_set(fw_log_manual, WLOCK),
.phy_info = rtw89_debug_priv_get(phy_info),
.stations = rtw89_debug_priv_get(stations, RLOCK),
- .disable_dm = rtw89_debug_priv_set_and_get(disable_dm),
+ .disable_dm = rtw89_debug_priv_set_and_get(disable_dm, RWLOCK),
+ .mlo_mode = rtw89_debug_priv_set_and_get(mlo_mode, RWLOCK),
};
#define rtw89_debugfs_add(name, mode, fopname, parent) \
@@ -4292,6 +4399,7 @@ void rtw89_debugfs_add_sec1(struct rtw89_dev *rtwdev, struct dentry *debugfs_top
rtw89_debugfs_add_r(phy_info);
rtw89_debugfs_add_r(stations);
rtw89_debugfs_add_rw(disable_dm);
+ rtw89_debugfs_add_rw(mlo_mode);
}
void rtw89_debugfs_init(struct rtw89_dev *rtwdev)
--
2.25.1
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH rtw-next 11/11] wifi: rtw89: declare MLO support if prerequisites are met
2025-05-05 7:24 [PATCH rtw-next 00/11] wifi: rtw89: support MLO feature Ping-Ke Shih
` (9 preceding siblings ...)
2025-05-05 7:24 ` [PATCH rtw-next 10/11] wifi: rtw89: debug: add mlo_mode dbgfs Ping-Ke Shih
@ 2025-05-05 7:24 ` Ping-Ke Shih
10 siblings, 0 replies; 13+ messages in thread
From: Ping-Ke Shih @ 2025-05-05 7:24 UTC (permalink / raw)
To: linux-wireless; +Cc: phhuang, kevin_yang
From: Zong-Zhe Yang <kevin_yang@realtek.com>
When the following prerequisites are met, driver will enable support_mlo.
It means that driver will declare WIPHY_FLAG_SUPPORTS_MLO, and then deal
with MLO related things.
The main prerequisites are as below.
1. all prerequisites for running with chanctx
2. FW feature NOTIFY_AP_INFO
Signed-off-by: Zong-Zhe Yang <kevin_yang@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
drivers/net/wireless/realtek/rtw89/core.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c
index 22a0c54de716..0b6fb30cbf52 100644
--- a/drivers/net/wireless/realtek/rtw89/core.c
+++ b/drivers/net/wireless/realtek/rtw89/core.c
@@ -5666,13 +5666,13 @@ struct rtw89_dev *rtw89_alloc_ieee80211_hw(struct device *device,
if (!hw)
goto err;
- /* TODO: When driver MLO arch. is done, determine whether to support MLO
- * according to the following conditions.
- * 1. run with chanctx_ops
- * 2. chip->support_link_num != 0
- * 3. FW feature supports AP_LINK_PS
+ /* Currently, our AP_LINK_PS handling only works for non-MLD softap
+ * or MLD-single-link softap. If RTW89_MLD_NON_STA_LINK_NUM enlarges,
+ * please tweak entire AP_LINKS_PS handling before supporting MLO.
*/
- support_mlo = false;
+ support_mlo = !no_chanctx && chip->support_link_num &&
+ RTW89_CHK_FW_FEATURE(NOTIFY_AP_INFO, &early_fw) &&
+ RTW89_MLD_NON_STA_LINK_NUM == 1;
hw->wiphy->iface_combinations = rtw89_iface_combs;
--
2.25.1
^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH rtw-next 01/11] wifi: rtw89: extract link part from core tx write function
2025-05-05 7:24 ` [PATCH rtw-next 01/11] wifi: rtw89: extract link part from core tx write function Ping-Ke Shih
@ 2025-05-10 1:06 ` Ping-Ke Shih
0 siblings, 0 replies; 13+ messages in thread
From: Ping-Ke Shih @ 2025-05-10 1:06 UTC (permalink / raw)
To: Ping-Ke Shih, linux-wireless; +Cc: phhuang, kevin_yang
Ping-Ke Shih <pkshih@realtek.com> wrote:
> From: Zong-Zhe Yang <kevin_yang@realtek.com>
>
> Extract core_tx_write_link from core_tx_write to accept given links as
> parameters. To make the follow-up changes of TX description more clear,
> tweak SW functions to split things ahead.
>
> (don't change logic at all)
>
> Signed-off-by: Zong-Zhe Yang <kevin_yang@realtek.com>
> Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
11 patch(es) applied to rtw-next branch of rtw.git, thanks.
0f34fbd274b8 wifi: rtw89: extract link part from core tx write function
829bd3599ae2 wifi: rtw89: allow driver to do specific band TX for MLO
a8ba4acab7db wifi: rtw89: send nullfunc based on the given link
5b6247de57d7 wifi: rtw89: chan: re-calculate MLO DBCC mode during setting channel
c3dba0653b1b wifi: rtw89: add handling of mlo_link_cfg H2C command and C2H event
e264a4d1c75f wifi: rtw89: add MLO track for MLSR switch decision
23a5c37ffb1a wifi: rtw89: debug: extend dbgfs for MLO
0c400c0a687d wifi: rtw89: debug: add MLD table dump
18dab90f5653 wifi: rtw89: debug: add FW log component for MLO
9dd85e739ce0 wifi: rtw89: debug: add mlo_mode dbgfs
52d2f6857c33 wifi: rtw89: declare MLO support if prerequisites are met
---
https://github.com/pkshih/rtw.git
^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2025-05-10 1:07 UTC | newest]
Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-05-05 7:24 [PATCH rtw-next 00/11] wifi: rtw89: support MLO feature Ping-Ke Shih
2025-05-05 7:24 ` [PATCH rtw-next 01/11] wifi: rtw89: extract link part from core tx write function Ping-Ke Shih
2025-05-10 1:06 ` Ping-Ke Shih
2025-05-05 7:24 ` [PATCH rtw-next 02/11] wifi: rtw89: allow driver to do specific band TX for MLO Ping-Ke Shih
2025-05-05 7:24 ` [PATCH rtw-next 03/11] wifi: rtw89: send nullfunc based on the given link Ping-Ke Shih
2025-05-05 7:24 ` [PATCH rtw-next 04/11] wifi: rtw89: chan: re-calculate MLO DBCC mode during setting channel Ping-Ke Shih
2025-05-05 7:24 ` [PATCH rtw-next 05/11] wifi: rtw89: add handling of mlo_link_cfg H2C command and C2H event Ping-Ke Shih
2025-05-05 7:24 ` [PATCH rtw-next 06/11] wifi: rtw89: add MLO track for MLSR switch decision Ping-Ke Shih
2025-05-05 7:24 ` [PATCH rtw-next 07/11] wifi: rtw89: debug: extend dbgfs for MLO Ping-Ke Shih
2025-05-05 7:24 ` [PATCH rtw-next 08/11] wifi: rtw89: debug: add MLD table dump Ping-Ke Shih
2025-05-05 7:24 ` [PATCH rtw-next 09/11] wifi: rtw89: debug: add FW log component for MLO Ping-Ke Shih
2025-05-05 7:24 ` [PATCH rtw-next 10/11] wifi: rtw89: debug: add mlo_mode dbgfs Ping-Ke Shih
2025-05-05 7:24 ` [PATCH rtw-next 11/11] wifi: rtw89: declare MLO support if prerequisites are met Ping-Ke Shih
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.