| From da85f2d8c8f3147aab467ba9d65c6457cba0ad1e Mon Sep 17 00:00:00 2001 |
| From: Benjamin Lin <benjamin-jw.lin@mediatek.com> |
| Date: Fri, 17 Nov 2023 18:08:06 +0800 |
| Subject: [PATCH 2020/2032] mtk: wifi: mt76: mt7996: get airtime and RSSI via |
| MCU commands |
| |
| Direct access to WTBL for airtime and RSSI may cause synchronization issue with FW. |
| Moreover, frequent access to WTBL, whenever TX-Free-Done event is received, leads to heavy CPU overheads. |
| Therefore, indirect access to WTBL, through FW, with lower frequence is performed. |
| |
| Signed-off-by: Yi-Chia Hsieh <yi-chia.hsieh@mediatek.com> |
| Signed-off-by: Benjamin Lin <benjamin-jw.lin@mediatek.com> |
| --- |
| mt76.h | 20 +++++ |
| mt76_connac_mcu.h | 14 +++- |
| mt7996/debugfs.c | 17 ++--- |
| mt7996/mac.c | 145 ++++++----------------------------- |
| mt7996/mcu.c | 177 +++++++++++++++++++++++++++++++++++++++++-- |
| mt7996/mcu.h | 32 +++++++- |
| mt7996/mt7996.h | 26 ++++++- |
| mt7996/mtk_debugfs.c | 71 +++++++++++++++++ |
| mt7996/regs.h | 2 + |
| 9 files changed, 361 insertions(+), 143 deletions(-) |
| |
| diff --git a/mt76.h b/mt76.h |
| index 49b66ff2..c7816721 100644 |
| --- a/mt76.h |
| +++ b/mt76.h |
| @@ -327,11 +327,15 @@ struct mt76_sta_stats { |
| u32 tx_packets; /* unit: MSDU */ |
| u32 tx_retries; |
| u32 tx_failed; |
| + u32 tx_total_mpdu_cnt; |
| + u32 tx_failed_mpdu_cnt; |
| + u64 tx_airtime; |
| /* WED RX */ |
| u64 rx_bytes; |
| u32 rx_packets; |
| u32 rx_errors; |
| u32 rx_drops; |
| + u64 rx_airtime; |
| }; |
| |
| enum mt76_wcid_flags { |
| @@ -1330,6 +1334,22 @@ static inline int mt76_decr(int val, int size) |
| |
| u8 mt76_ac_to_hwq(u8 ac); |
| |
| +static inline u8 |
| +mt76_ac_to_tid(u8 ac) |
| +{ |
| + static const u8 ac_to_tid[] = { |
| + [IEEE80211_AC_BE] = 0, |
| + [IEEE80211_AC_BK] = 1, |
| + [IEEE80211_AC_VI] = 4, |
| + [IEEE80211_AC_VO] = 6 |
| + }; |
| + |
| + if (WARN_ON(ac >= IEEE80211_NUM_ACS)) |
| + return 0; |
| + |
| + return ac_to_tid[ac]; |
| +} |
| + |
| static inline struct ieee80211_txq * |
| mtxq_to_txq(struct mt76_txq *mtxq) |
| { |
| diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h |
| index 266ee711..4f4b7b4f 100644 |
| --- a/mt76_connac_mcu.h |
| +++ b/mt76_connac_mcu.h |
| @@ -1368,11 +1368,23 @@ enum { |
| UNI_OFFLOAD_OFFLOAD_BMC_RPY_DETECT, |
| }; |
| |
| +enum UNI_PER_STA_INFO_TAG { |
| + UNI_PER_STA_RSSI, |
| + UNI_PER_STA_CONTENTION_RX_RATE, |
| + UNI_PER_STA_PER, |
| + UNI_PER_STA_SNR, |
| + UNI_PER_STA_TX_RATE, |
| + UNI_PER_STA_TX_CNT, |
| + UNI_PER_STA_TID_SN_GET, |
| + UNI_PER_STA_TID_SN_SET, |
| + UNI_PER_STA_MAX_NUM |
| +}; |
| + |
| enum UNI_ALL_STA_INFO_TAG { |
| UNI_ALL_STA_TXRX_RATE, |
| UNI_ALL_STA_TX_STAT, |
| UNI_ALL_STA_TXRX_ADM_STAT, |
| - UNI_ALL_STA_TXRX_AIR_TIME, |
| + UNI_ALL_STA_TXRX_AIRTIME, |
| UNI_ALL_STA_DATA_TX_RETRY_COUNT, |
| UNI_ALL_STA_GI_MODE, |
| UNI_ALL_STA_TXRX_MSDU_COUNT, |
| diff --git a/mt7996/debugfs.c b/mt7996/debugfs.c |
| index 8e4ceeeb..6ccf0827 100644 |
| --- a/mt7996/debugfs.c |
| +++ b/mt7996/debugfs.c |
| @@ -987,12 +987,11 @@ mt7996_airtime_read(struct seq_file *s, void *data) |
| { |
| struct mt7996_dev *dev = dev_get_drvdata(s->private); |
| struct mt76_dev *mdev = &dev->mt76; |
| - struct mt7996_vow_sta_ctrl *vow; |
| + struct mt76_sta_stats *stats; |
| struct ieee80211_sta *sta; |
| struct mt7996_sta *msta; |
| struct mt76_wcid *wcid; |
| struct mt76_vif *vif; |
| - u64 airtime; |
| u16 i; |
| |
| seq_printf(s, "VoW Airtime Information:\n"); |
| @@ -1004,16 +1003,16 @@ mt7996_airtime_read(struct seq_file *s, void *data) |
| |
| msta = container_of(wcid, struct mt7996_sta, wcid); |
| sta = container_of((void *)msta, struct ieee80211_sta, drv_priv); |
| - vow = &msta->vow; |
| vif = &msta->vif->mt76; |
| + stats = &wcid->stats; |
| |
| - spin_lock_bh(&vow->lock); |
| - airtime = vow->tx_airtime; |
| - vow->tx_airtime = 0; |
| - spin_unlock_bh(&vow->lock); |
| + seq_printf(s, "%pM WCID: %hu BandIdx: %hhu OmacIdx: 0x%hhx\t" |
| + "TxAirtime: %llu\tRxAirtime: %llu\n", |
| + sta->addr, i, vif->band_idx, vif->omac_idx, |
| + stats->tx_airtime, stats->rx_airtime); |
| |
| - seq_printf(s, "%pM WCID: %hu BandIdx: %hhu OmacIdx: 0x%hhx\tTxAirtime: %llu\n", |
| - sta->addr, i, vif->band_idx, vif->omac_idx, airtime); |
| + stats->tx_airtime = 0; |
| + stats->rx_airtime = 0; |
| } |
| rcu_read_unlock(); |
| |
| diff --git a/mt7996/mac.c b/mt7996/mac.c |
| index 142e9372..901c2036 100644 |
| --- a/mt7996/mac.c |
| +++ b/mt7996/mac.c |
| @@ -12,8 +12,6 @@ |
| #include "mcu.h" |
| #include "vendor.h" |
| |
| -#define to_rssi(field, rcpi) ((FIELD_GET(field, rcpi) - 220) / 2) |
| - |
| static const struct mt7996_dfs_radar_spec etsi_radar_specs = { |
| .pulse_th = { 110, -10, -80, 40, 5200, 128, 5200 }, |
| .radar_pattern = { |
| @@ -93,110 +91,6 @@ u32 mt7996_mac_wtbl_lmac_addr(struct mt7996_dev *dev, u16 wcid, u8 dw) |
| return MT_WTBL_LMAC_OFFS(wcid, dw); |
| } |
| |
| -static void mt7996_mac_sta_poll(struct mt7996_dev *dev) |
| -{ |
| - static const u8 ac_to_tid[] = { |
| - [IEEE80211_AC_BE] = 0, |
| - [IEEE80211_AC_BK] = 1, |
| - [IEEE80211_AC_VI] = 4, |
| - [IEEE80211_AC_VO] = 6 |
| - }; |
| - struct ieee80211_sta *sta; |
| - struct mt7996_sta *msta; |
| - struct mt7996_vow_sta_ctrl *vow; |
| - u32 tx_time[IEEE80211_NUM_ACS], rx_time[IEEE80211_NUM_ACS]; |
| - LIST_HEAD(sta_poll_list); |
| - int i; |
| - |
| - spin_lock_bh(&dev->mt76.sta_poll_lock); |
| - list_splice_init(&dev->mt76.sta_poll_list, &sta_poll_list); |
| - spin_unlock_bh(&dev->mt76.sta_poll_lock); |
| - |
| - rcu_read_lock(); |
| - |
| - while (true) { |
| - bool clear = false; |
| - u32 addr, val; |
| - u16 idx; |
| - s8 rssi[4]; |
| - |
| - spin_lock_bh(&dev->mt76.sta_poll_lock); |
| - if (list_empty(&sta_poll_list)) { |
| - spin_unlock_bh(&dev->mt76.sta_poll_lock); |
| - break; |
| - } |
| - msta = list_first_entry(&sta_poll_list, |
| - struct mt7996_sta, wcid.poll_list); |
| - list_del_init(&msta->wcid.poll_list); |
| - spin_unlock_bh(&dev->mt76.sta_poll_lock); |
| - |
| - idx = msta->wcid.idx; |
| - |
| - /* refresh peer's airtime reporting */ |
| - addr = mt7996_mac_wtbl_lmac_addr(dev, idx, 20); |
| - |
| - for (i = 0; i < IEEE80211_NUM_ACS; i++) { |
| - u32 tx_last = msta->airtime_ac[i]; |
| - u32 rx_last = msta->airtime_ac[i + 4]; |
| - |
| - msta->airtime_ac[i] = mt76_rr(dev, addr); |
| - msta->airtime_ac[i + 4] = mt76_rr(dev, addr + 4); |
| - |
| - tx_time[i] = msta->airtime_ac[i] - tx_last; |
| - rx_time[i] = msta->airtime_ac[i + 4] - rx_last; |
| - |
| - if ((tx_last | rx_last) & BIT(30)) |
| - clear = true; |
| - |
| - addr += 8; |
| - } |
| - |
| - if (clear) { |
| - mt7996_mac_wtbl_update(dev, idx, |
| - MT_WTBL_UPDATE_ADM_COUNT_CLEAR); |
| - memset(msta->airtime_ac, 0, sizeof(msta->airtime_ac)); |
| - } |
| - |
| - if (!msta->wcid.sta) |
| - continue; |
| - |
| - sta = container_of((void *)msta, struct ieee80211_sta, |
| - drv_priv); |
| - vow = &msta->vow; |
| - for (i = 0; i < IEEE80211_NUM_ACS; i++) { |
| - u8 q = mt76_connac_lmac_mapping(i); |
| - u32 tx_cur = tx_time[q]; |
| - u32 rx_cur = rx_time[q]; |
| - u8 tid = ac_to_tid[i]; |
| - |
| - if (!tx_cur && !rx_cur) |
| - continue; |
| - |
| - ieee80211_sta_register_airtime(sta, tid, tx_cur, rx_cur); |
| - |
| - spin_lock_bh(&vow->lock); |
| - vow->tx_airtime += tx_cur; |
| - spin_unlock_bh(&vow->lock); |
| - } |
| - |
| - /* get signal strength of resp frames (CTS/BA/ACK) */ |
| - addr = mt7996_mac_wtbl_lmac_addr(dev, idx, 34); |
| - val = mt76_rr(dev, addr); |
| - |
| - rssi[0] = to_rssi(GENMASK(7, 0), val); |
| - rssi[1] = to_rssi(GENMASK(15, 8), val); |
| - rssi[2] = to_rssi(GENMASK(23, 16), val); |
| - rssi[3] = to_rssi(GENMASK(31, 14), val); |
| - |
| - msta->ack_signal = |
| - mt76_rx_signal(msta->vif->phy->mt76->antenna_mask, rssi); |
| - |
| - ewma_avg_signal_add(&msta->avg_ack_signal, -msta->ack_signal); |
| - } |
| - |
| - rcu_read_unlock(); |
| -} |
| - |
| void mt7996_mac_enable_rtscts(struct mt7996_dev *dev, |
| struct ieee80211_vif *vif, bool enable) |
| { |
| @@ -1206,8 +1100,6 @@ mt7996_mac_tx_free(struct mt7996_dev *dev, void *data, int len) |
| } |
| } |
| |
| - mt7996_mac_sta_poll(dev); |
| - |
| if (wake) |
| mt76_set_tx_blocked(&dev->mt76, false); |
| |
| @@ -2383,31 +2275,42 @@ void mt7996_mac_sta_rc_work(struct work_struct *work) |
| |
| void mt7996_mac_work(struct work_struct *work) |
| { |
| - struct mt7996_phy *phy; |
| - struct mt76_phy *mphy; |
| - |
| - mphy = (struct mt76_phy *)container_of(work, struct mt76_phy, |
| - mac_work.work); |
| - phy = mphy->priv; |
| + struct mt76_phy *mphy = (struct mt76_phy *)container_of(work, struct mt76_phy, |
| + mac_work.work); |
| + struct mt7996_phy *phy = mphy->priv; |
| + struct mt76_dev *mdev = mphy->dev; |
| |
| - mutex_lock(&mphy->dev->mutex); |
| + mutex_lock(&mdev->mutex); |
| |
| mt76_update_survey(mphy); |
| if (++mphy->mac_work_count == 5) { |
| + int i; |
| + |
| mphy->mac_work_count = 0; |
| |
| mt7996_mac_update_stats(phy); |
| |
| - mt7996_mcu_get_all_sta_info(phy, UNI_ALL_STA_TXRX_RATE); |
| - if (mtk_wed_device_active(&phy->dev->mt76.mmio.wed)) { |
| - mt7996_mcu_get_all_sta_info(phy, UNI_ALL_STA_TXRX_ADM_STAT); |
| - mt7996_mcu_get_all_sta_info(phy, UNI_ALL_STA_TXRX_MSDU_COUNT); |
| + /* Update DEV-wise information only in |
| + * the MAC work of the first band running. |
| + */ |
| + for (i = MT_BAND0; i <= mphy->band_idx; ++i) { |
| + if (i == mphy->band_idx) { |
| + mt7996_mcu_get_all_sta_info(mdev, UNI_ALL_STA_TXRX_RATE); |
| + mt7996_mcu_get_all_sta_info(mdev, UNI_ALL_STA_TXRX_AIRTIME); |
| + mt7996_mcu_get_rssi(mdev); |
| + if (mtk_wed_device_active(&mdev->mmio.wed)) { |
| + mt7996_mcu_get_all_sta_info(mdev, UNI_ALL_STA_TXRX_ADM_STAT); |
| + mt7996_mcu_get_all_sta_info(mdev, UNI_ALL_STA_TXRX_MSDU_COUNT); |
| + } |
| + } else if (mt7996_band_valid(phy->dev, i) && |
| + test_bit(MT76_STATE_RUNNING, &mdev->phys[i]->state)) |
| + break; |
| } |
| } |
| |
| - mutex_unlock(&mphy->dev->mutex); |
| + mutex_unlock(&mdev->mutex); |
| |
| - mt76_tx_status_check(mphy->dev, false); |
| + mt76_tx_status_check(mdev, false); |
| |
| ieee80211_queue_delayed_work(mphy->hw, &mphy->mac_work, |
| MT7996_WATCHDOG_TIME); |
| diff --git a/mt7996/mcu.c b/mt7996/mcu.c |
| index 08979465..4907f729 100644 |
| --- a/mt7996/mcu.c |
| +++ b/mt7996/mcu.c |
| @@ -560,7 +560,8 @@ mt7996_mcu_rx_all_sta_info_event(struct mt7996_dev *dev, struct sk_buff *skb) |
| u16 wlan_idx; |
| struct mt76_wcid *wcid; |
| struct mt76_phy *mphy; |
| - u32 tx_bytes, rx_bytes, tx_packets, rx_packets; |
| + struct ieee80211_sta *sta; |
| + u32 tx_bytes, rx_bytes, tx_airtime, rx_airtime, tx_packets, rx_packets; |
| |
| switch (le16_to_cpu(res->tag)) { |
| case UNI_ALL_STA_TXRX_RATE: |
| @@ -581,7 +582,7 @@ mt7996_mcu_rx_all_sta_info_event(struct mt7996_dev *dev, struct sk_buff *skb) |
| break; |
| |
| mphy = mt76_dev_phy(&dev->mt76, wcid->phy_idx); |
| - for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { |
| + for (ac = IEEE80211_AC_VO; ac < IEEE80211_NUM_ACS; ac++) { |
| tx_bytes = le32_to_cpu(res->adm_stat[i].tx_bytes[ac]); |
| rx_bytes = le32_to_cpu(res->adm_stat[i].rx_bytes[ac]); |
| |
| @@ -613,6 +614,24 @@ mt7996_mcu_rx_all_sta_info_event(struct mt7996_dev *dev, struct sk_buff *skb) |
| __mt7996_stat_to_netdev(mphy, wcid, 0, 0, |
| tx_packets, rx_packets); |
| break; |
| + case UNI_ALL_STA_TXRX_AIRTIME: |
| + wlan_idx = le16_to_cpu(res->airtime[i].wlan_idx); |
| + wcid = rcu_dereference(dev->mt76.wcid[wlan_idx]); |
| + sta = wcid_to_sta(wcid); |
| + if (!sta) |
| + continue; |
| + |
| + for (ac = IEEE80211_AC_VO; ac < IEEE80211_NUM_ACS; ++ac) { |
| + u8 lmac_ac = mt76_connac_lmac_mapping(ac); |
| + tx_airtime = le32_to_cpu(res->airtime[i].tx[lmac_ac]); |
| + rx_airtime = le32_to_cpu(res->airtime[i].rx[lmac_ac]); |
| + |
| + wcid->stats.tx_airtime += tx_airtime; |
| + wcid->stats.rx_airtime += rx_airtime; |
| + ieee80211_sta_register_airtime(sta, mt76_ac_to_tid(ac), |
| + tx_airtime, rx_airtime); |
| + } |
| + break; |
| default: |
| break; |
| } |
| @@ -2242,8 +2261,6 @@ mt7996_mcu_sta_init_vow(struct mt7996_phy *phy, struct mt7996_sta *msta) |
| vow->drr_quantum[IEEE80211_AC_VI] = VOW_DRR_QUANTUM_IDX1; |
| vow->drr_quantum[IEEE80211_AC_BE] = VOW_DRR_QUANTUM_IDX2; |
| vow->drr_quantum[IEEE80211_AC_BK] = VOW_DRR_QUANTUM_IDX2; |
| - vow->tx_airtime = 0; |
| - spin_lock_init(&vow->lock); |
| |
| ret = mt7996_mcu_set_vow_drr_ctrl(phy, msta, VOW_DRR_CTRL_STA_BSS_GROUP); |
| if (ret) |
| @@ -4849,9 +4866,155 @@ int mt7996_mcu_set_rro(struct mt7996_dev *dev, u16 tag, u16 val) |
| sizeof(req), true); |
| } |
| |
| -int mt7996_mcu_get_all_sta_info(struct mt7996_phy *phy, u16 tag) |
| +int mt7996_mcu_get_per_sta_info(struct mt76_dev *dev, u16 tag, |
| + u16 sta_num, u16 *sta_list) |
| +{ |
| +#define PER_STA_INFO_MAX_NUM 90 |
| + struct mt7996_mcu_per_sta_info_event *res; |
| + struct mt76_wcid *wcid; |
| + struct sk_buff *skb; |
| + u16 wlan_idx; |
| + int i, ret; |
| + struct { |
| + u8 __rsv1; |
| + u8 unsolicit; |
| + u8 __rsv2[2]; |
| + |
| + __le16 tag; |
| + __le16 len; |
| + __le16 sta_num; |
| + u8 __rsv3[2]; |
| + __le16 sta_list[PER_STA_INFO_MAX_NUM]; |
| + } __packed req = { |
| + .unsolicit = 0, |
| + .tag = cpu_to_le16(tag), |
| + .len = cpu_to_le16(sizeof(req) - 4), |
| + .sta_num = cpu_to_le16(sta_num) |
| + }; |
| + |
| + if (sta_num > PER_STA_INFO_MAX_NUM) |
| + return -EINVAL; |
| + |
| + for (i = 0; i < sta_num; ++i) |
| + req.sta_list[i] = cpu_to_le16(sta_list[i]); |
| + |
| + ret = mt76_mcu_send_and_get_msg(dev, MCU_WM_UNI_CMD(PER_STA_INFO), |
| + &req, sizeof(req), true, &skb); |
| + if (ret) |
| + return ret; |
| + |
| + res = (struct mt7996_mcu_per_sta_info_event *)skb->data; |
| + if (le16_to_cpu(res->tag) != tag) { |
| + ret = -EINVAL; |
| + goto out; |
| + } |
| + |
| + rcu_read_lock(); |
| + switch (tag) { |
| + case UNI_PER_STA_RSSI: |
| + for (i = 0; i < sta_num; ++i) { |
| + struct mt7996_sta *msta; |
| + struct mt76_phy *phy; |
| + s8 rssi[4]; |
| + u8 *rcpi; |
| + |
| + wlan_idx = le16_to_cpu(res->rssi[i].wlan_idx); |
| + wcid = rcu_dereference(dev->wcid[wlan_idx]); |
| + if (wcid) { |
| + rcpi = res->rssi[i].rcpi; |
| + rssi[0] = to_rssi(MT_PRXV_RCPI0, rcpi[0]); |
| + rssi[1] = to_rssi(MT_PRXV_RCPI0, rcpi[1]); |
| + rssi[2] = to_rssi(MT_PRXV_RCPI0, rcpi[2]); |
| + rssi[3] = to_rssi(MT_PRXV_RCPI0, rcpi[3]); |
| + |
| + msta = container_of(wcid, struct mt7996_sta, wcid); |
| + phy = msta->vif->phy->mt76; |
| + msta->ack_signal = mt76_rx_signal(phy->antenna_mask, rssi); |
| + ewma_avg_signal_add(&msta->avg_ack_signal, -msta->ack_signal); |
| + } else { |
| + ret = -EINVAL; |
| + dev_err(dev->dev, "Failed to update RSSI for " |
| + "invalid WCID: %hu\n", wlan_idx); |
| + } |
| + } |
| + break; |
| + case UNI_PER_STA_TX_CNT: |
| + for (i = 0; i < sta_num; ++i) { |
| + wlan_idx = le16_to_cpu(res->tx_cnt[i].wlan_idx); |
| + wcid = rcu_dereference(dev->wcid[wlan_idx]); |
| + if (wcid) { |
| + wcid->stats.tx_total_mpdu_cnt += |
| + le32_to_cpu(res->tx_cnt[i].total); |
| + wcid->stats.tx_failed_mpdu_cnt += |
| + le32_to_cpu(res->tx_cnt[i].failed); |
| + } else { |
| + ret = -EINVAL; |
| + dev_err(dev->dev, "Failed to update TX MPDU counts " |
| + "for invalid WCID: %hu\n", wlan_idx); |
| + } |
| + } |
| + break; |
| + default: |
| + ret = -EINVAL; |
| + dev_err(dev->dev, "Unknown UNI_PER_STA_INFO_TAG: %d\n", tag); |
| + } |
| + rcu_read_unlock(); |
| +out: |
| + dev_kfree_skb(skb); |
| + return ret; |
| +} |
| + |
| +int mt7996_mcu_get_rssi(struct mt76_dev *dev) |
| +{ |
| + u16 sta_list[PER_STA_INFO_MAX_NUM]; |
| + LIST_HEAD(sta_poll_list); |
| + struct mt7996_sta *msta; |
| + int i, ret; |
| + bool empty = false; |
| + |
| + spin_lock_bh(&dev->sta_poll_lock); |
| + list_splice_init(&dev->sta_poll_list, &sta_poll_list); |
| + spin_unlock_bh(&dev->sta_poll_lock); |
| + |
| + while (!empty) { |
| + for (i = 0; i < PER_STA_INFO_MAX_NUM; ++i) { |
| + spin_lock_bh(&dev->sta_poll_lock); |
| + if (list_empty(&sta_poll_list)) { |
| + spin_unlock_bh(&dev->sta_poll_lock); |
| + |
| + if (i == 0) |
| + return 0; |
| + |
| + empty = true; |
| + break; |
| + } |
| + msta = list_first_entry(&sta_poll_list, |
| + struct mt7996_sta, |
| + wcid.poll_list); |
| + list_del_init(&msta->wcid.poll_list); |
| + spin_unlock_bh(&dev->sta_poll_lock); |
| + |
| + sta_list[i] = msta->wcid.idx; |
| + } |
| + |
| + ret = mt7996_mcu_get_per_sta_info(dev, UNI_PER_STA_RSSI, |
| + i, sta_list); |
| + if (ret) { |
| + /* Add STAs, whose RSSI has not been updated, |
| + * back to polling list. |
| + */ |
| + spin_lock_bh(&dev->sta_poll_lock); |
| + list_splice(&sta_poll_list, &dev->sta_poll_list); |
| + spin_unlock_bh(&dev->sta_poll_lock); |
| + break; |
| + } |
| + } |
| + |
| + return ret; |
| +} |
| + |
| +int mt7996_mcu_get_all_sta_info(struct mt76_dev *dev, u16 tag) |
| { |
| - struct mt7996_dev *dev = phy->dev; |
| struct { |
| u8 _rsv[4]; |
| |
| @@ -4862,7 +5025,7 @@ int mt7996_mcu_get_all_sta_info(struct mt7996_phy *phy, u16 tag) |
| .len = cpu_to_le16(sizeof(req) - 4), |
| }; |
| |
| - return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(ALL_STA_INFO), |
| + return mt76_mcu_send_msg(dev, MCU_WM_UNI_CMD(ALL_STA_INFO), |
| &req, sizeof(req), false); |
| } |
| |
| diff --git a/mt7996/mcu.h b/mt7996/mcu.h |
| index a05dd6a5..cd327451 100644 |
| --- a/mt7996/mcu.h |
| +++ b/mt7996/mcu.h |
| @@ -199,6 +199,31 @@ struct mt7996_mcu_mib { |
| __le64 data; |
| } __packed; |
| |
| +struct per_sta_rssi { |
| + __le16 wlan_idx; |
| + u8 __rsv[2]; |
| + u8 rcpi[4]; |
| +} __packed; |
| + |
| +struct per_sta_tx_cnt { |
| + __le16 wlan_idx; |
| + u8 __rsv[2]; |
| + __le32 total; |
| + __le32 failed; |
| +} __packed; |
| + |
| +struct mt7996_mcu_per_sta_info_event { |
| + u8 __rsv[4]; |
| + |
| + __le16 tag; |
| + __le16 len; |
| + |
| + union { |
| + struct per_sta_rssi rssi[0]; |
| + struct per_sta_tx_cnt tx_cnt[0]; |
| + }; |
| +} __packed; |
| + |
| struct all_sta_trx_rate { |
| __le16 wlan_idx; |
| u8 __rsv1[2]; |
| @@ -237,13 +262,18 @@ struct mt7996_mcu_all_sta_info_event { |
| __le32 tx_bytes[IEEE80211_NUM_ACS]; |
| __le32 rx_bytes[IEEE80211_NUM_ACS]; |
| } adm_stat[0] __packed; |
| - |
| struct { |
| __le16 wlan_idx; |
| u8 rsv[2]; |
| __le32 tx_msdu_cnt; |
| __le32 rx_msdu_cnt; |
| } msdu_cnt[0] __packed; |
| + struct { |
| + __le16 wlan_idx; |
| + u8 __rsv[2]; |
| + __le32 tx[IEEE80211_NUM_ACS]; |
| + __le32 rx[IEEE80211_NUM_ACS]; |
| + } airtime[0] __packed; |
| } __packed; |
| } __packed; |
| |
| diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h |
| index d1d35e56..c5b83648 100644 |
| --- a/mt7996/mt7996.h |
| +++ b/mt7996/mt7996.h |
| @@ -126,6 +126,8 @@ |
| #define MT7996_RRO_MSDU_PG_CR_CNT 8 |
| #define MT7996_RRO_MSDU_PG_SIZE_PER_CR 0x10000 |
| |
| +#define to_rssi(field, rcpi) ((FIELD_GET(field, rcpi) - 220) / 2) |
| + |
| struct mt7996_vif; |
| struct mt7996_sta; |
| struct mt7996_dfs_pulse; |
| @@ -298,8 +300,6 @@ struct mt7996_vow_sta_ctrl { |
| bool paused; |
| u8 bss_grp_idx; |
| u8 drr_quantum[IEEE80211_NUM_ACS]; |
| - u64 tx_airtime; |
| - spinlock_t lock; |
| }; |
| |
| struct mt7996_sta { |
| @@ -308,7 +308,6 @@ struct mt7996_sta { |
| struct mt7996_vif *vif; |
| |
| struct list_head rc_list; |
| - u32 airtime_ac[8]; |
| |
| int ack_signal; |
| struct ewma_avg_signal avg_ack_signal; |
| @@ -405,6 +404,21 @@ struct mt7996_air_monitor_ctrl { |
| }; |
| #endif |
| |
| +struct mt7996_rro_ba_session { |
| + u32 ack_sn :12; |
| + u32 win_sz :3; |
| + u32 bn :1; |
| + u32 last_in_sn :12; |
| + u32 bc :1; |
| + u32 bd :1; |
| + u32 sat :1; |
| + u32 cn :1; |
| + u32 within_cnt :12; |
| + u32 to_sel :3; |
| + u32 rsv :1; |
| + u32 last_in_rxtime :12; |
| +}; |
| + |
| struct mt7996_phy { |
| struct mt76_phy *mt76; |
| struct mt7996_dev *dev; |
| @@ -594,6 +608,7 @@ struct mt7996_dev { |
| u32 fw_dbg_module; |
| u8 fw_dbg_lv; |
| u32 bcn_total_cnt[__MT_MAX_BAND]; |
| + u32 sid; |
| } dbg; |
| const struct mt7996_dbg_reg_desc *dbg_reg; |
| #endif |
| @@ -819,7 +834,10 @@ int mt7996_mcu_fw_dbg_ctrl(struct mt7996_dev *dev, u32 module, u8 level); |
| int mt7996_mcu_trigger_assert(struct mt7996_dev *dev); |
| void mt7996_mcu_rx_event(struct mt7996_dev *dev, struct sk_buff *skb); |
| void mt7996_mcu_exit(struct mt7996_dev *dev); |
| -int mt7996_mcu_get_all_sta_info(struct mt7996_phy *phy, u16 tag); |
| +int mt7996_mcu_get_per_sta_info(struct mt76_dev *dev, u16 tag, |
| + u16 sta_num, u16 *sta_list); |
| +int mt7996_mcu_get_rssi(struct mt76_dev *dev); |
| +int mt7996_mcu_get_all_sta_info(struct mt76_dev *dev, u16 tag); |
| int mt7996_mcu_wed_rro_reset_sessions(struct mt7996_dev *dev, u16 id); |
| int mt7996_mcu_set_tx_power_ctrl(struct mt7996_phy *phy, u8 power_ctrl_id, u8 data); |
| int mt7996_mcu_get_tx_power_info(struct mt7996_phy *phy, u8 category, void *event); |
| diff --git a/mt7996/mtk_debugfs.c b/mt7996/mtk_debugfs.c |
| index 6eea2c3c..916c7c06 100644 |
| --- a/mt7996/mtk_debugfs.c |
| +++ b/mt7996/mtk_debugfs.c |
| @@ -3047,6 +3047,69 @@ mt7996_vow_drr_dbg(void *data, u64 val) |
| DEFINE_DEBUGFS_ATTRIBUTE(fops_vow_drr_dbg, NULL, |
| mt7996_vow_drr_dbg, "%lld\n"); |
| |
| +static int |
| +mt7996_rro_session_read(struct seq_file *s, void *data) |
| +{ |
| + struct mt7996_dev *dev = dev_get_drvdata(s->private); |
| + struct mt7996_rro_ba_session *tbl; |
| + u32 value[2]; |
| + |
| + mt76_wr(dev, MT_RRO_DBG_RD_CTRL, MT_RRO_DBG_RD_EXEC + |
| + (dev->dbg.sid >> 1) + 0x200); |
| + |
| + if (dev->dbg.sid & 0x1) { |
| + value[0] = mt76_rr(dev, MT_RRO_DBG_RDAT_DW(2)); |
| + value[1] = mt76_rr(dev, MT_RRO_DBG_RDAT_DW(3)); |
| + } else { |
| + value[0] = mt76_rr(dev, MT_RRO_DBG_RDAT_DW(0)); |
| + value[1] = mt76_rr(dev, MT_RRO_DBG_RDAT_DW(1)); |
| + } |
| + |
| + tbl = (struct mt7996_rro_ba_session *)&value[0]; |
| + |
| + seq_printf(s, " seid %d:\nba session table DW0:%08x DW2:%08x\n", |
| + dev->dbg.sid, value[0], value[1]); |
| + |
| + seq_printf(s, "ack_sn = 0x%x, last_in_sn = 0x%x, sat/bn/bc/bd/cn = %d/%d/%d/%d/%d\n", |
| + tbl->ack_sn, tbl->last_in_sn, tbl->sat, tbl->bn, tbl->bc, tbl->bd, tbl->cn); |
| + |
| + seq_printf(s, "within_cnt = %d, to_sel = %d, last_in_rxtime = %d\n", |
| + tbl->within_cnt, tbl->to_sel, tbl->last_in_rxtime); |
| + |
| + return 0; |
| +} |
| + |
| +static int |
| +mt7996_show_rro_mib(struct seq_file *s, void *data) |
| +{ |
| + struct mt7996_dev *dev = dev_get_drvdata(s->private); |
| + u32 reg[12]; |
| + |
| + seq_printf(s, "RRO mib Info:\n"); |
| + |
| + reg[0] = mt76_rr(dev, WF_RRO_TOP_STATISTIC(0)); |
| + reg[1] = mt76_rr(dev, WF_RRO_TOP_STATISTIC(1)); |
| + reg[2] = mt76_rr(dev, WF_RRO_TOP_STATISTIC(2)); |
| + reg[3] = mt76_rr(dev, WF_RRO_TOP_STATISTIC(3)); |
| + reg[4] = mt76_rr(dev, WF_RRO_TOP_STATISTIC(4)); |
| + reg[5] = mt76_rr(dev, WF_RRO_TOP_STATISTIC(5)); |
| + reg[6] = mt76_rr(dev, WF_RRO_TOP_STATISTIC(6)); |
| + reg[7] = mt76_rr(dev, WF_RRO_TOP_STATISTIC(7)); |
| + reg[8] = mt76_rr(dev, WF_RRO_TOP_STATISTIC(8)); |
| + reg[9] = mt76_rr(dev, WF_RRO_TOP_STATISTIC(9)); |
| + reg[10] = mt76_rr(dev, WF_RRO_TOP_STATISTIC(10)); |
| + reg[11] = mt76_rr(dev, WF_RRO_TOP_STATISTIC(11)); |
| + |
| + seq_printf(s, "STEP_ONE/WITHIN/SURPASS = %x/%x/%x\n", reg[0], reg[3], reg[4]); |
| + seq_printf(s, "REPEAT/OLDPKT/BAR = %x/%x/%x\n", reg[1], reg[2], reg[5]); |
| + seq_printf(s, "SURPASS with big gap = %x\n", reg[6]); |
| + seq_printf(s, "DISCONNECT/INVALID = %x/%x\n", reg[7], reg[8]); |
| + seq_printf(s, "TO(Step one)/TO(flush all) = %x/%x\n", reg[9], reg[10]); |
| + seq_printf(s, "buf ran out = %x\n", reg[11]); |
| + |
| + return 0; |
| +} |
| + |
| int mt7996_mtk_init_debugfs(struct mt7996_phy *phy, struct dentry *dir) |
| { |
| struct mt7996_dev *dev = phy->dev; |
| @@ -3146,6 +3209,14 @@ int mt7996_mtk_init_debugfs(struct mt7996_phy *phy, struct dentry *dir) |
| |
| debugfs_create_file("muru_prot_thr", 0200, dir, phy, &fops_muru_prot_thr); |
| |
| + if (dev->has_rro) { |
| + debugfs_create_u32("rro_sid", 0600, dir, &dev->dbg.sid); |
| + debugfs_create_devm_seqfile(dev->mt76.dev, "rro_sid_info", dir, |
| + mt7996_rro_session_read); |
| + debugfs_create_devm_seqfile(dev->mt76.dev, "rro_mib", dir, |
| + mt7996_show_rro_mib); |
| + } |
| + |
| return 0; |
| } |
| |
| diff --git a/mt7996/regs.h b/mt7996/regs.h |
| index a3b62339..476b23c3 100644 |
| --- a/mt7996/regs.h |
| +++ b/mt7996/regs.h |
| @@ -122,6 +122,8 @@ enum offs_rev { |
| #define MT_MCU_INT_EVENT_DMA_INIT BIT(1) |
| #define MT_MCU_INT_EVENT_RESET_DONE BIT(3) |
| |
| +#define WF_RRO_TOP_STATISTIC(_n) MT_RRO_TOP(0x180 + _n * 0x4) |
| + |
| /* PLE */ |
| #define MT_PLE_BASE 0x820c0000 |
| #define MT_PLE(ofs) (MT_PLE_BASE + (ofs)) |
| -- |
| 2.18.0 |
| |