| 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 |
| |