Skip to content

Commit 79e7b04

Browse files
Lingbo Kongjeff-t-johnson
authored andcommitted
wifi: ath12k: report station mode signal strength
Currently, the signal strength of "iw dev xxx station dump" always show an invalid value. This is because signal strength is only set in ath12k_mgmt_rx_event() function, and not set for received data packet. So, change to get signal from firmware and report to mac80211. After that, "iw dev xxx station dump" show the correct signal strength. Such as: Station 00:03:7f:12:03:03 (on wlo1) inactive time: 36 ms rx bytes: 61571 rx packets: 336 tx bytes: 28204 tx packets: 205 tx retries: 49 tx failed: 0 beacon loss: 0 beacon rx: 83 rx drop misc: 66 signal: -24 dBm beacon signal avg: -22 dBm For WCN7850, the firmware supports db2dbm, so not need to add noise floor. For QCN9274, the firmware not support db2dbm, so need to add noise floor. This patch affects the station mode of WCN7850 and QCN9274. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.1.1-00214-QCAHKSWPL_SILICONZ-1 Signed-off-by: Lingbo Kong <quic_lingbok@quicinc.com> Link: https://patch.msgid.link/20250115063537.35797-4-quic_lingbok@quicinc.com Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
1 parent 5e73276 commit 79e7b04

File tree

4 files changed

+240
-2
lines changed

4 files changed

+240
-2
lines changed

drivers/net/wireless/ath/ath12k/core.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -503,6 +503,7 @@ struct ath12k_link_sta {
503503
struct ath12k_wbm_tx_stats *wbm_tx_stats;
504504
u32 bw_prev;
505505
u32 peer_nss;
506+
s8 rssi_beacon;
506507

507508
/* For now the assoc link will be considered primary */
508509
bool is_assoc_link;
@@ -722,6 +723,8 @@ struct ath12k {
722723

723724
bool nlo_enabled;
724725

726+
struct completion fw_stats_complete;
727+
725728
struct completion mlo_setup_done;
726729
u32 mlo_setup_status;
727730
u8 ftm_msgref;

drivers/net/wireless/ath/ath12k/mac.c

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10104,17 +10104,60 @@ static int ath12k_mac_op_get_survey(struct ieee80211_hw *hw, int idx,
1010410104
return 0;
1010510105
}
1010610106

10107+
static int ath12k_mac_get_fw_stats(struct ath12k *ar, u32 pdev_id,
10108+
u32 vdev_id, u32 stats_id)
10109+
{
10110+
struct ath12k_base *ab = ar->ab;
10111+
struct ath12k_hw *ah = ath12k_ar_to_ah(ar);
10112+
unsigned long time_left;
10113+
int ret;
10114+
10115+
guard(mutex)(&ah->hw_mutex);
10116+
10117+
if (ah->state != ATH12K_HW_STATE_ON)
10118+
return -ENETDOWN;
10119+
10120+
reinit_completion(&ar->fw_stats_complete);
10121+
10122+
ret = ath12k_wmi_send_stats_request_cmd(ar, stats_id, vdev_id, pdev_id);
10123+
10124+
if (ret) {
10125+
ath12k_warn(ab, "failed to request fw stats: %d\n", ret);
10126+
return ret;
10127+
}
10128+
10129+
ath12k_dbg(ab, ATH12K_DBG_WMI,
10130+
"get fw stat pdev id %d vdev id %d stats id 0x%x\n",
10131+
pdev_id, vdev_id, stats_id);
10132+
10133+
time_left = wait_for_completion_timeout(&ar->fw_stats_complete, 1 * HZ);
10134+
10135+
if (!time_left)
10136+
ath12k_warn(ab, "time out while waiting for get fw stats\n");
10137+
10138+
return ret;
10139+
}
10140+
1010710141
static void ath12k_mac_op_sta_statistics(struct ieee80211_hw *hw,
1010810142
struct ieee80211_vif *vif,
1010910143
struct ieee80211_sta *sta,
1011010144
struct station_info *sinfo)
1011110145
{
1011210146
struct ath12k_sta *ahsta = ath12k_sta_to_ahsta(sta);
1011310147
struct ath12k_link_sta *arsta;
10148+
struct ath12k *ar;
10149+
s8 signal;
10150+
bool db2dbm;
1011410151

1011510152
lockdep_assert_wiphy(hw->wiphy);
1011610153

1011710154
arsta = &ahsta->deflink;
10155+
ar = ath12k_get_ar_by_vif(hw, vif, arsta->link_id);
10156+
if (!ar)
10157+
return;
10158+
10159+
db2dbm = test_bit(WMI_TLV_SERVICE_HW_DB2DBM_CONVERSION_SUPPORT,
10160+
ar->ab->wmi_ab.svc_map);
1011810161

1011910162
sinfo->rx_duration = arsta->rx_duration;
1012010163
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_DURATION);
@@ -10141,8 +10184,18 @@ static void ath12k_mac_op_sta_statistics(struct ieee80211_hw *hw,
1014110184
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE);
1014210185

1014310186
/* TODO: Use real NF instead of default one. */
10144-
sinfo->signal = arsta->rssi_comb + ATH12K_DEFAULT_NOISE_FLOOR;
10145-
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL);
10187+
signal = arsta->rssi_comb;
10188+
10189+
if (!signal &&
10190+
ahsta->ahvif->vdev_type == WMI_VDEV_TYPE_STA &&
10191+
!(ath12k_mac_get_fw_stats(ar, ar->pdev->pdev_id, 0,
10192+
WMI_REQUEST_VDEV_STAT)))
10193+
signal = arsta->rssi_beacon;
10194+
10195+
if (signal) {
10196+
sinfo->signal = db2dbm ? signal : signal + ATH12K_DEFAULT_NOISE_FLOOR;
10197+
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL);
10198+
}
1014610199
}
1014710200

1014810201
static int ath12k_mac_op_cancel_remain_on_channel(struct ieee80211_hw *hw,
@@ -11123,6 +11176,8 @@ static int ath12k_mac_hw_register(struct ath12k_hw *ah)
1112311176
ath12k_debugfs_register(ar);
1112411177
}
1112511178

11179+
init_completion(&ar->fw_stats_complete);
11180+
1112611181
return 0;
1112711182

1112811183
err_unregister_hw:

drivers/net/wireless/ath/ath12k/wmi.c

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ struct ath12k_wmi_svc_ready_parse {
2626
bool wmi_svc_bitmap_done;
2727
};
2828

29+
struct wmi_tlv_fw_stats_parse {
30+
const struct wmi_stats_event *ev;
31+
};
32+
2933
struct ath12k_wmi_dma_ring_caps_parse {
3034
struct ath12k_wmi_dma_ring_caps_params *dma_ring_caps;
3135
u32 n_dma_ring_caps;
@@ -815,6 +819,39 @@ int ath12k_wmi_mgmt_send(struct ath12k *ar, u32 vdev_id, u32 buf_id,
815819
return ret;
816820
}
817821

822+
int ath12k_wmi_send_stats_request_cmd(struct ath12k *ar, u32 stats_id,
823+
u32 vdev_id, u32 pdev_id)
824+
{
825+
struct ath12k_wmi_pdev *wmi = ar->wmi;
826+
struct wmi_request_stats_cmd *cmd;
827+
struct sk_buff *skb;
828+
int ret;
829+
830+
skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd));
831+
if (!skb)
832+
return -ENOMEM;
833+
834+
cmd = (struct wmi_request_stats_cmd *)skb->data;
835+
cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_REQUEST_STATS_CMD,
836+
sizeof(*cmd));
837+
838+
cmd->stats_id = cpu_to_le32(stats_id);
839+
cmd->vdev_id = cpu_to_le32(vdev_id);
840+
cmd->pdev_id = cpu_to_le32(pdev_id);
841+
842+
ret = ath12k_wmi_cmd_send(wmi, skb, WMI_REQUEST_STATS_CMDID);
843+
if (ret) {
844+
ath12k_warn(ar->ab, "failed to send WMI_REQUEST_STATS cmd\n");
845+
dev_kfree_skb(skb);
846+
}
847+
848+
ath12k_dbg(ar->ab, ATH12K_DBG_WMI,
849+
"WMI request stats 0x%x vdev id %d pdev id %d\n",
850+
stats_id, vdev_id, pdev_id);
851+
852+
return ret;
853+
}
854+
818855
int ath12k_wmi_vdev_create(struct ath12k *ar, u8 *macaddr,
819856
struct ath12k_wmi_vdev_create_arg *args)
820857
{
@@ -6814,8 +6851,103 @@ static void ath12k_peer_assoc_conf_event(struct ath12k_base *ab, struct sk_buff
68146851
rcu_read_unlock();
68156852
}
68166853

6854+
static int ath12k_wmi_tlv_fw_stats_data_parse(struct ath12k_base *ab,
6855+
struct wmi_tlv_fw_stats_parse *parse,
6856+
const void *ptr,
6857+
u16 len)
6858+
{
6859+
const struct wmi_stats_event *ev = parse->ev;
6860+
struct ath12k *ar;
6861+
struct ath12k_link_vif *arvif;
6862+
struct ieee80211_sta *sta;
6863+
struct ath12k_sta *ahsta;
6864+
struct ath12k_link_sta *arsta;
6865+
int i, ret = 0;
6866+
const void *data = ptr;
6867+
6868+
if (!ev) {
6869+
ath12k_warn(ab, "failed to fetch update stats ev");
6870+
return -EPROTO;
6871+
}
6872+
6873+
rcu_read_lock();
6874+
6875+
ar = ath12k_mac_get_ar_by_pdev_id(ab, le32_to_cpu(ev->pdev_id));
6876+
if (!ar) {
6877+
ath12k_warn(ab, "invalid pdev id %d in update stats event\n",
6878+
le32_to_cpu(ev->pdev_id));
6879+
ret = -EPROTO;
6880+
goto exit;
6881+
}
6882+
6883+
for (i = 0; i < le32_to_cpu(ev->num_vdev_stats); i++) {
6884+
const struct wmi_vdev_stats_params *src;
6885+
6886+
src = data;
6887+
if (len < sizeof(*src)) {
6888+
ret = -EPROTO;
6889+
goto exit;
6890+
}
6891+
6892+
arvif = ath12k_mac_get_arvif(ar, le32_to_cpu(src->vdev_id));
6893+
if (arvif) {
6894+
sta = ieee80211_find_sta_by_ifaddr(ath12k_ar_to_hw(ar),
6895+
arvif->bssid,
6896+
NULL);
6897+
if (sta) {
6898+
ahsta = ath12k_sta_to_ahsta(sta);
6899+
arsta = &ahsta->deflink;
6900+
arsta->rssi_beacon = le32_to_cpu(src->beacon_snr);
6901+
ath12k_dbg(ab, ATH12K_DBG_WMI,
6902+
"wmi stats vdev id %d snr %d\n",
6903+
src->vdev_id, src->beacon_snr);
6904+
} else {
6905+
ath12k_dbg(ab, ATH12K_DBG_WMI,
6906+
"not found station bssid %pM for vdev stat\n",
6907+
arvif->bssid);
6908+
}
6909+
}
6910+
6911+
data += sizeof(*src);
6912+
len -= sizeof(*src);
6913+
}
6914+
6915+
complete(&ar->fw_stats_complete);
6916+
exit:
6917+
rcu_read_unlock();
6918+
return ret;
6919+
}
6920+
6921+
static int ath12k_wmi_tlv_fw_stats_parse(struct ath12k_base *ab,
6922+
u16 tag, u16 len,
6923+
const void *ptr, void *data)
6924+
{
6925+
struct wmi_tlv_fw_stats_parse *parse = data;
6926+
int ret = 0;
6927+
6928+
switch (tag) {
6929+
case WMI_TAG_STATS_EVENT:
6930+
parse->ev = ptr;
6931+
break;
6932+
case WMI_TAG_ARRAY_BYTE:
6933+
ret = ath12k_wmi_tlv_fw_stats_data_parse(ab, parse, ptr, len);
6934+
break;
6935+
default:
6936+
break;
6937+
}
6938+
return ret;
6939+
}
6940+
68176941
static void ath12k_update_stats_event(struct ath12k_base *ab, struct sk_buff *skb)
68186942
{
6943+
int ret;
6944+
struct wmi_tlv_fw_stats_parse parse = {};
6945+
6946+
ret = ath12k_wmi_tlv_iter(ab, skb->data, skb->len,
6947+
ath12k_wmi_tlv_fw_stats_parse,
6948+
&parse);
6949+
if (ret)
6950+
ath12k_warn(ab, "failed to parse fw stats %d\n", ret);
68196951
}
68206952

68216953
/* PDEV_CTL_FAILSAFE_CHECK_EVENT is received from FW when the frequency scanned

drivers/net/wireless/ath/ath12k/wmi.h

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5649,6 +5649,52 @@ enum wmi_sta_keepalive_method {
56495649
#define WMI_STA_KEEPALIVE_INTERVAL_DEFAULT 30
56505650
#define WMI_STA_KEEPALIVE_INTERVAL_DISABLE 0
56515651

5652+
struct wmi_stats_event {
5653+
__le32 stats_id;
5654+
__le32 num_pdev_stats;
5655+
__le32 num_vdev_stats;
5656+
__le32 num_peer_stats;
5657+
__le32 num_bcnflt_stats;
5658+
__le32 num_chan_stats;
5659+
__le32 num_mib_stats;
5660+
__le32 pdev_id;
5661+
__le32 num_bcn_stats;
5662+
__le32 num_peer_extd_stats;
5663+
__le32 num_peer_extd2_stats;
5664+
} __packed;
5665+
5666+
enum wmi_stats_id {
5667+
WMI_REQUEST_VDEV_STAT = BIT(3),
5668+
};
5669+
5670+
struct wmi_request_stats_cmd {
5671+
__le32 tlv_header;
5672+
__le32 stats_id;
5673+
__le32 vdev_id;
5674+
struct ath12k_wmi_mac_addr_params peer_macaddr;
5675+
__le32 pdev_id;
5676+
} __packed;
5677+
5678+
#define WLAN_MAX_AC 4
5679+
#define MAX_TX_RATE_VALUES 10
5680+
5681+
struct wmi_vdev_stats_params {
5682+
__le32 vdev_id;
5683+
__le32 beacon_snr;
5684+
__le32 data_snr;
5685+
__le32 num_tx_frames[WLAN_MAX_AC];
5686+
__le32 num_rx_frames;
5687+
__le32 num_tx_frames_retries[WLAN_MAX_AC];
5688+
__le32 num_tx_frames_failures[WLAN_MAX_AC];
5689+
__le32 num_rts_fail;
5690+
__le32 num_rts_success;
5691+
__le32 num_rx_err;
5692+
__le32 num_rx_discard;
5693+
__le32 num_tx_not_acked;
5694+
__le32 tx_rate_history[MAX_TX_RATE_VALUES];
5695+
__le32 beacon_rssi_history[MAX_TX_RATE_VALUES];
5696+
} __packed;
5697+
56525698
void ath12k_wmi_init_qcn9274(struct ath12k_base *ab,
56535699
struct ath12k_wmi_resource_config_arg *config);
56545700
void ath12k_wmi_init_wcn7850(struct ath12k_base *ab,
@@ -5774,6 +5820,8 @@ int ath12k_wmi_set_bios_cmd(struct ath12k_base *ab, u32 param_id,
57745820
const u8 *buf, size_t buf_len);
57755821
int ath12k_wmi_set_bios_sar_cmd(struct ath12k_base *ab, const u8 *psar_table);
57765822
int ath12k_wmi_set_bios_geo_cmd(struct ath12k_base *ab, const u8 *pgeo_table);
5823+
int ath12k_wmi_send_stats_request_cmd(struct ath12k *ar, u32 stats_id,
5824+
u32 vdev_id, u32 pdev_id);
57775825
__le32 ath12k_wmi_tlv_hdr(u32 cmd, u32 len);
57785826

57795827
static inline u32

0 commit comments

Comments
 (0)