blob: f0528a981c0bf8a29b6ff1385273fc90bda20a10 [file] [log] [blame]
From fdf267776932e3bab7c0d87f2c9c8a96ac9a4e0f Mon Sep 17 00:00:00 2001
From: Allen Ye <allen.ye@mediatek.com>
Date: Tue, 28 May 2024 15:39:06 +0800
Subject: [PATCH 164/223] mtk: mt76: Add dynamic pp vendor and debug pp algo
cmd support
Add dynamic pp vendor and debug pp algo cmd support.
1. Add support channel switch with a punct bitmap.
2. Add pp event for fw mode and trigger a channel switch by hostapd.
3. Add pp algo dump cmd to get current fw punct bitmap and mode.
When extender sta have not connected to root ap and the chandef is null.
mt76 just ignore the event. Once the sta connect to ap, the sta part would
send a new fw cmd to update the pp bitmap.
Change-Id: I3574940a3f4165f136df8e07a819a32a5bc02b41
Change-Id: I1e9955ac0cecafa481fe851502880f6ea1a44469
Signed-off-by: Allen Ye <allen.ye@mediatek.com>
---
mt7996/mcu.c | 70 ++++++++++++++++++++++++++++-
mt7996/mcu.h | 38 ++++++++++++++++
mt7996/mt7996.h | 2 +
mt7996/mtk_debugfs.c | 14 ++++++
mt7996/vendor.c | 103 +++++++++++++++++++++++++++++++------------
mt7996/vendor.h | 8 +++-
6 files changed, 205 insertions(+), 30 deletions(-)
diff --git a/mt7996/mcu.c b/mt7996/mcu.c
index fce92046..77d3b2c8 100644
--- a/mt7996/mcu.c
+++ b/mt7996/mcu.c
@@ -1285,6 +1285,39 @@ mt7996_mcu_wed_rro_event(struct mt7996_dev *dev, struct sk_buff *skb)
}
}
+void
+mt7996_dump_pp_statistic_event(struct mt7996_dev *dev,
+ struct mt7996_mcu_pp_alg_ctrl_event *event)
+{
+ u32 unit_time = le32_to_cpu(event->pp_timer_intv);
+
+ dev_info(dev->mt76.dev, "band idx = %u\n", le32_to_cpu(event->band_idx));
+ dev_info(dev->mt76.dev, "x2 value = %u\n", le32_to_cpu(event->thr_x2_value));
+ dev_info(dev->mt76.dev, "x2 shift = %u\n", le32_to_cpu(event->thr_x2_shift));
+ dev_info(dev->mt76.dev, "x3 value = %u\n", le32_to_cpu(event->thr_x3_value));
+ dev_info(dev->mt76.dev, "x3 shift = %u\n", le32_to_cpu(event->thr_x3_shift));
+ dev_info(dev->mt76.dev, "x4 value = %u\n", le32_to_cpu(event->thr_x4_value));
+ dev_info(dev->mt76.dev, "x4 shift = %u\n", le32_to_cpu(event->thr_x4_shift));
+ dev_info(dev->mt76.dev, "x5 value = %u\n", le32_to_cpu(event->thr_x5_value));
+ dev_info(dev->mt76.dev, "x5 shift = %u\n", le32_to_cpu(event->thr_x5_shift));
+ dev_info(dev->mt76.dev, "x6 value = %u\n", le32_to_cpu(event->thr_x6_value));
+ dev_info(dev->mt76.dev, "x6 shift = %u\n", le32_to_cpu(event->thr_x6_shift));
+ dev_info(dev->mt76.dev, "x7 value = %u\n", le32_to_cpu(event->thr_x7_value));
+ dev_info(dev->mt76.dev, "x7 shift = %u\n", le32_to_cpu(event->thr_x7_shift));
+ dev_info(dev->mt76.dev, "x8 value = %u\n", le32_to_cpu(event->thr_x8_value));
+ dev_info(dev->mt76.dev, "x8 shift = %u\n", le32_to_cpu(event->thr_x8_shift));
+ dev_info(dev->mt76.dev, "sw_pp_time = %u (Unit: %u ms)\n",
+ le32_to_cpu(event->sw_pp_time), unit_time);
+ dev_info(dev->mt76.dev, "hw_pp_time = %u (Unit: %u ms)\n",
+ le32_to_cpu(event->hw_pp_time), unit_time);
+ dev_info(dev->mt76.dev, "no_pp_time = %u (Unit: %u ms)\n",
+ le32_to_cpu(event->no_pp_time), unit_time);
+ dev_info(dev->mt76.dev, "auto_bw_time = %u (Unit: %u ms)\n",
+ le32_to_cpu(event->auto_bw_time), unit_time);
+ dev_info(dev->mt76.dev, "punct_bitmap = 0x%04x\n",
+ le16_to_cpu(event->punct_bitmap));
+}
+
static void
mt7996_mcu_pp_event(struct mt7996_dev *dev, struct sk_buff *skb)
{
@@ -1311,9 +1344,13 @@ mt7996_mcu_pp_event(struct mt7996_dev *dev, struct sk_buff *skb)
if (phy->punct_bitmap == report_bitmap)
return;
- if (phy->pp_mode == PP_FW_MODE)
+ if (phy->pp_mode == PP_FW_MODE) {
phy->punct_bitmap = report_bitmap;
-
+ mt7996_vendor_pp_bitmap_update(phy, report_bitmap);
+ }
+ break;
+ case UNI_EVENT_PP_TAG_ALG_CTRL:
+ mt7996_dump_pp_statistic_event(dev, (struct mt7996_mcu_pp_alg_ctrl_event *)event);
break;
}
}
@@ -6415,6 +6452,35 @@ int mt7996_mcu_set_pp_sta_dscb(struct mt7996_phy *phy,
&req, sizeof(req), false);
}
+int mt7996_mcu_set_pp_alg_ctrl(struct mt7996_phy *phy, u8 action)
+{
+ struct mt7996_dev *dev = phy->dev;
+ struct {
+ u8 _rsv1[4];
+
+ __le16 tag;
+ __le16 len;
+
+ __le32 pp_timer_intv;
+ __le32 rsv2[14];
+ u8 band_idx;
+ u8 pp_action;
+ u8 reset;
+ u8 _rsv3;
+ } __packed req = {
+ .tag = cpu_to_le16(UNI_CMD_PP_ALG_CTRL),
+ .len = cpu_to_le16(sizeof(req) - 4),
+
+ .pp_timer_intv = action == PP_ALG_SET_TIMER ? 2000 : 0,
+ .band_idx = phy->mt76->band_idx,
+ .pp_action = action,
+ .reset = 0,
+ };
+
+ return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(PP),
+ &req, sizeof(req), false);
+}
+
int mt7996_mcu_set_tx_power_ctrl(struct mt7996_phy *phy, u8 power_ctrl_id, u8 data)
{
struct mt7996_dev *dev = phy->dev;
diff --git a/mt7996/mcu.h b/mt7996/mcu.h
index 011b6c7a..01eb0ea1 100644
--- a/mt7996/mcu.h
+++ b/mt7996/mcu.h
@@ -1162,6 +1162,7 @@ enum {
enum {
UNI_CMD_PP_EN_CTRL,
+ UNI_CMD_PP_ALG_CTRL,
UNI_CMD_PP_DSCB_CTRL,
};
@@ -1171,6 +1172,11 @@ enum pp_mode {
PP_USR_MODE,
};
+enum pp_alg_action {
+ PP_ALG_SET_TIMER,
+ PP_ALG_GET_STATISTICS = 2,
+};
+
enum {
UNI_EVENT_PP_TAG_ALG_CTRL = 1,
UNI_EVENT_STATIC_PP_TAG_DSCB_IE,
@@ -1204,6 +1210,38 @@ struct mt7996_mcu_pp_dscb_event {
u8 __rsv3[2];
} __packed;
+struct mt7996_mcu_pp_alg_ctrl_event {
+ struct mt7996_mcu_rxd rxd;
+
+ u8 __rsv1[4];
+
+ __le16 tag;
+ __le16 len;
+
+ __le32 pp_timer_intv;
+ __le32 thr_x2_value;
+ __le32 thr_x2_shift;
+ __le32 thr_x3_value;
+ __le32 thr_x3_shift;
+ __le32 thr_x4_value;
+ __le32 thr_x4_shift;
+ __le32 thr_x5_value;
+ __le32 thr_x5_shift;
+ __le32 thr_x6_value;
+ __le32 thr_x6_shift;
+ __le32 thr_x7_value;
+ __le32 thr_x7_shift;
+ __le32 thr_x8_value;
+ __le32 thr_x8_shift;
+ __le32 sw_pp_time;
+ __le32 hw_pp_time;
+ __le32 no_pp_time;
+ __le32 auto_bw_time;
+ u8 band_idx;
+ u8 __rsv2;
+ __le16 punct_bitmap;
+} __packed;
+
enum {
UNI_CMD_SCS_SEND_DATA,
UNI_CMD_SCS_SET_PD_THR_RANGE = 2,
diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
index 58151ed0..755b4cf0 100644
--- a/mt7996/mt7996.h
+++ b/mt7996/mt7996.h
@@ -1282,6 +1282,7 @@ int mt7996_mcu_cp_support(struct mt7996_dev *dev, u8 mode);
int mt7996_mcu_set_pp_en(struct mt7996_phy *phy, u8 mode, u16 bitmap);
int mt7996_mcu_set_pp_sta_dscb(struct mt7996_phy *phy, struct cfg80211_chan_def *chandef,
u8 omac_idx);
+int mt7996_mcu_set_pp_alg_ctrl(struct mt7996_phy *phy, u8 action);
int mt7996_mcu_set_eml_omn(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u8 link_id,
struct ieee80211_sta *sta, struct mt7996_eml_omn *eml_omn);
#ifdef CONFIG_MAC80211_DEBUGFS
@@ -1311,6 +1312,7 @@ int mt7996_mcu_set_muru_cfg(struct mt7996_dev *dev, void *data);
void mt7996_set_beacon_vif(void *data, u8 *mac, struct ieee80211_vif *vif);
int mt7996_mcu_set_csi(struct mt7996_phy *phy, u8 mode,
u8 cfg, u8 v1, u32 v2, u8 *mac_addr);
+int mt7996_vendor_pp_bitmap_update(struct mt7996_phy *phy, u16 bitmap);
#endif
int mt7996_mcu_edcca_enable(struct mt7996_phy *phy, bool enable);
diff --git a/mt7996/mtk_debugfs.c b/mt7996/mtk_debugfs.c
index 02a6ee81..2ded5f79 100644
--- a/mt7996/mtk_debugfs.c
+++ b/mt7996/mtk_debugfs.c
@@ -4367,6 +4367,18 @@ static const struct file_operations fops_muru_dbg_info = {
.llseek = default_llseek,
};
+static int mt7996_pp_alg_show(struct seq_file *s, void *data)
+{
+ struct mt7996_phy *phy = s->private;
+ struct mt7996_dev *dev = phy->dev;
+
+ dev_info(dev->mt76.dev, "pp_mode = %d\n", phy->pp_mode);
+ mt7996_mcu_set_pp_alg_ctrl(phy, PP_ALG_GET_STATISTICS);
+
+ return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(mt7996_pp_alg);
+
void mt7996_mtk_init_band_debugfs(struct mt7996_phy *phy, struct dentry *dir)
{
/* agg */
@@ -4389,6 +4401,8 @@ void mt7996_mtk_init_band_debugfs(struct mt7996_phy *phy, struct dentry *dir)
debugfs_create_file("thermal_enable", 0600, dir, phy, &fops_thermal_enable);
debugfs_create_file("scs_enable", 0200, dir, phy, &fops_scs_enable);
+
+ debugfs_create_file("pp_alg", 0200, dir, phy, &mt7996_pp_alg_fops);
}
void mt7996_mtk_init_dev_debugfs(struct mt7996_dev *dev, struct dentry *dir)
diff --git a/mt7996/vendor.c b/mt7996/vendor.c
index 33c682c0..d7973c5e 100644
--- a/mt7996/vendor.c
+++ b/mt7996/vendor.c
@@ -96,7 +96,9 @@ ibf_ctrl_policy[NUM_MTK_VENDOR_ATTRS_IBF_CTRL] = {
static struct nla_policy
pp_ctrl_policy[NUM_MTK_VENDOR_ATTRS_PP_CTRL] = {
[MTK_VENDOR_ATTR_PP_MODE] = { .type = NLA_U8 },
- [MTK_VENDOR_ATTR_PP_BAND_IDX] = { .type = NLA_U8 },
+ [MTK_VENDOR_ATTR_PP_LINK_ID] = { .type = NLA_U8 },
+ [MTK_VENDOR_ATTR_PP_BITMAP] = { .type = NLA_U16 },
+ [MTK_VENDOR_ATTR_PP_CURR_FREQ] = { .type = NLA_U32 },
};
static const struct nla_policy
@@ -805,31 +807,44 @@ static int mt7996_vendor_pp_ctrl(struct wiphy *wiphy, struct wireless_dev *wdev,
const void *data, int data_len)
{
struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
+ struct ieee80211_vif *vif = wdev_to_ieee80211_vif(wdev);
struct nlattr *tb[NUM_MTK_VENDOR_ATTRS_PP_CTRL];
struct mt7996_dev *dev = mt7996_hw_dev(hw);
struct mt7996_phy *phy;
- struct mt76_phy *mphy;
struct cfg80211_chan_def *chandef;
+ struct mt7996_bss_conf *mconf;
+ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
int err;
- u8 val8, band_idx = 0;
+ u8 mode = 0, link_id = 0;
+ u16 punct_bitmap = 0;
err = nla_parse(tb, MTK_VENDOR_ATTR_PP_CTRL_MAX, data, data_len,
pp_ctrl_policy, NULL);
- if (tb[MTK_VENDOR_ATTR_PP_BAND_IDX]) {
- band_idx = nla_get_u8(tb[MTK_VENDOR_ATTR_PP_BAND_IDX]);
- }
+ if (tb[MTK_VENDOR_ATTR_PP_MODE])
+ mode = nla_get_u8(tb[MTK_VENDOR_ATTR_PP_MODE]);
+ else
+ return -EINVAL;
- if (!mt7996_band_valid(dev, band_idx))
- goto error;
+ if (ieee80211_vif_is_mld(vif) && tb[MTK_VENDOR_ATTR_PP_LINK_ID]) {
+ link_id = nla_get_u8(tb[MTK_VENDOR_ATTR_PP_LINK_ID]);
+ if (link_id >= IEEE80211_LINK_UNSPECIFIED)
+ return -EINVAL;
+ }
- mphy = dev->mt76.phys[band_idx];
- if (!mphy)
+ rcu_read_lock();
+ mconf = rcu_dereference(mvif->link[link_id]);
+ if (!mconf) {
+ rcu_read_unlock();
goto error;
+ }
- phy = (struct mt7996_phy *)mphy->priv;
- if (!phy)
+ phy = mconf->phy;
+ if (!phy) {
+ rcu_read_unlock();
goto error;
+ }
+ rcu_read_unlock();
chandef = &phy->chanctx->chandef;
if (!chandef)
@@ -838,28 +853,53 @@ static int mt7996_vendor_pp_ctrl(struct wiphy *wiphy, struct wireless_dev *wdev,
if (chandef->chan->band == NL80211_BAND_2GHZ)
return 0;
- if (tb[MTK_VENDOR_ATTR_PP_MODE]) {
- val8 = nla_get_u8(tb[MTK_VENDOR_ATTR_PP_MODE]);
- switch (val8) {
- case PP_DISABLE:
- case PP_FW_MODE:
- err = mt7996_mcu_set_pp_en(phy, val8, 0);
- break;
- case PP_USR_MODE:
- /* handled by add_chanctx */
- err = 0;
- break;
- default:
- err = -EINVAL;
- }
+ switch (mode) {
+ case PP_USR_MODE:
+ if (tb[MTK_VENDOR_ATTR_PP_BITMAP])
+ punct_bitmap = nla_get_u16(tb[MTK_VENDOR_ATTR_PP_BITMAP]);
+ fallthrough;
+ case PP_FW_MODE:
+ case PP_DISABLE:
+ err = mt7996_mcu_set_pp_en(phy, mode, punct_bitmap);
+ break;
+ default:
+ return -EINVAL;
}
return err;
error:
- dev_err(dev->mt76.dev, "Invalid band idx: %d\n", band_idx);
+ dev_err(dev->mt76.dev, "Invalid link id: %d\n", link_id);
return -EINVAL;
}
+int mt7996_vendor_pp_bitmap_update(struct mt7996_phy *phy, u16 bitmap)
+{
+ struct sk_buff *skb;
+ struct mt76_phy *mphy = phy->mt76;
+ struct cfg80211_chan_def *chandef = &phy->chanctx->chandef;
+
+ if (!chandef)
+ return 0;
+
+ skb = cfg80211_vendor_event_alloc(mphy->hw->wiphy, NULL, 20,
+ MTK_NL80211_VENDOR_EVENT_PP_BMP_UPDATE,
+ GFP_ATOMIC);
+
+ if (!skb)
+ return -ENOMEM;
+
+ if (nla_put_u16(skb, MTK_VENDOR_ATTR_PP_BITMAP, bitmap) ||
+ nla_put_u32(skb, MTK_VENDOR_ATTR_PP_CURR_FREQ,
+ chandef->chan->center_freq)) {
+ dev_kfree_skb(skb);
+ return -ENOMEM;
+ }
+
+ cfg80211_vendor_event(skb, GFP_ATOMIC);
+
+ return 0;
+}
+
static int mt7996_vendor_rfeature_ctrl(struct wiphy *wiphy,
struct wireless_dev *wdev,
const void *data,
@@ -1490,10 +1530,19 @@ static const struct wiphy_vendor_command mt7996_vendor_commands[] = {
},
};
+static const struct nl80211_vendor_cmd_info mt7996_vendor_events[] = {
+ [MTK_NL80211_VENDOR_EVENT_PP_BMP_UPDATE] = {
+ .vendor_id = MTK_NL80211_VENDOR_ID,
+ .subcmd = MTK_NL80211_VENDOR_EVENT_PP_BMP_UPDATE,
+ },
+};
+
void mt7996_vendor_register(struct mt7996_phy *phy)
{
phy->mt76->hw->wiphy->vendor_commands = mt7996_vendor_commands;
phy->mt76->hw->wiphy->n_vendor_commands = ARRAY_SIZE(mt7996_vendor_commands);
+ phy->mt76->hw->wiphy->vendor_events = mt7996_vendor_events;
+ phy->mt76->hw->wiphy->n_vendor_events = ARRAY_SIZE(mt7996_vendor_events);
INIT_LIST_HEAD(&phy->csi.list);
spin_lock_init(&phy->csi.lock);
diff --git a/mt7996/vendor.h b/mt7996/vendor.h
index 714f0b3e..ca4f00ad 100644
--- a/mt7996/vendor.h
+++ b/mt7996/vendor.h
@@ -21,6 +21,10 @@ enum mtk_nl80211_vendor_subcmds {
MTK_NL80211_VENDOR_SUBCMD_EML_CTRL = 0xd3,
};
+enum mtk_nl80211_vendor_events {
+ MTK_NL80211_VENDOR_EVENT_PP_BMP_UPDATE = 0x5,
+};
+
enum mtk_vendor_attr_edcca_ctrl {
MTK_VENDOR_ATTR_EDCCA_THRESHOLD_INVALID = 0,
@@ -222,7 +226,9 @@ enum mtk_vendor_attr_pp_ctrl {
MTK_VENDOR_ATTR_PP_CTRL_UNSPEC,
MTK_VENDOR_ATTR_PP_MODE,
- MTK_VENDOR_ATTR_PP_BAND_IDX,
+ MTK_VENDOR_ATTR_PP_LINK_ID,
+ MTK_VENDOR_ATTR_PP_BITMAP,
+ MTK_VENDOR_ATTR_PP_CURR_FREQ,
/* keep last */
NUM_MTK_VENDOR_ATTRS_PP_CTRL,
--
2.45.2