162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
262306a36Sopenharmony_ci/* Copyright(c) 2018-2019  Realtek Corporation
362306a36Sopenharmony_ci */
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci#include "main.h"
662306a36Sopenharmony_ci#include "rx.h"
762306a36Sopenharmony_ci#include "ps.h"
862306a36Sopenharmony_ci#include "debug.h"
962306a36Sopenharmony_ci#include "fw.h"
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_civoid rtw_rx_stats(struct rtw_dev *rtwdev, struct ieee80211_vif *vif,
1262306a36Sopenharmony_ci		  struct sk_buff *skb)
1362306a36Sopenharmony_ci{
1462306a36Sopenharmony_ci	struct ieee80211_hdr *hdr;
1562306a36Sopenharmony_ci	struct rtw_vif *rtwvif;
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci	hdr = (struct ieee80211_hdr *)skb->data;
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci	if (!ieee80211_is_data(hdr->frame_control))
2062306a36Sopenharmony_ci		return;
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci	if (!is_broadcast_ether_addr(hdr->addr1) &&
2362306a36Sopenharmony_ci	    !is_multicast_ether_addr(hdr->addr1)) {
2462306a36Sopenharmony_ci		rtwdev->stats.rx_unicast += skb->len;
2562306a36Sopenharmony_ci		rtwdev->stats.rx_cnt++;
2662306a36Sopenharmony_ci		if (vif) {
2762306a36Sopenharmony_ci			rtwvif = (struct rtw_vif *)vif->drv_priv;
2862306a36Sopenharmony_ci			rtwvif->stats.rx_unicast += skb->len;
2962306a36Sopenharmony_ci			rtwvif->stats.rx_cnt++;
3062306a36Sopenharmony_ci		}
3162306a36Sopenharmony_ci	}
3262306a36Sopenharmony_ci}
3362306a36Sopenharmony_ciEXPORT_SYMBOL(rtw_rx_stats);
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_cistruct rtw_rx_addr_match_data {
3662306a36Sopenharmony_ci	struct rtw_dev *rtwdev;
3762306a36Sopenharmony_ci	struct ieee80211_hdr *hdr;
3862306a36Sopenharmony_ci	struct rtw_rx_pkt_stat *pkt_stat;
3962306a36Sopenharmony_ci	u8 *bssid;
4062306a36Sopenharmony_ci};
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_cistatic void rtw_rx_phy_stat(struct rtw_dev *rtwdev,
4362306a36Sopenharmony_ci			    struct rtw_rx_pkt_stat *pkt_stat,
4462306a36Sopenharmony_ci			    struct ieee80211_hdr *hdr)
4562306a36Sopenharmony_ci{
4662306a36Sopenharmony_ci	struct rtw_dm_info *dm_info = &rtwdev->dm_info;
4762306a36Sopenharmony_ci	struct rtw_pkt_count *cur_pkt_cnt = &dm_info->cur_pkt_count;
4862306a36Sopenharmony_ci	u8 rate_ss, rate_ss_evm, evm_id;
4962306a36Sopenharmony_ci	u8 i, idx;
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	dm_info->curr_rx_rate = pkt_stat->rate;
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	if (ieee80211_is_beacon(hdr->frame_control))
5462306a36Sopenharmony_ci		cur_pkt_cnt->num_bcn_pkt++;
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	switch (pkt_stat->rate) {
5762306a36Sopenharmony_ci	case DESC_RATE1M...DESC_RATE11M:
5862306a36Sopenharmony_ci		goto pkt_num;
5962306a36Sopenharmony_ci	case DESC_RATE6M...DESC_RATE54M:
6062306a36Sopenharmony_ci		rate_ss = 0;
6162306a36Sopenharmony_ci		rate_ss_evm = 1;
6262306a36Sopenharmony_ci		evm_id = RTW_EVM_OFDM;
6362306a36Sopenharmony_ci		break;
6462306a36Sopenharmony_ci	case DESC_RATEMCS0...DESC_RATEMCS7:
6562306a36Sopenharmony_ci	case DESC_RATEVHT1SS_MCS0...DESC_RATEVHT1SS_MCS9:
6662306a36Sopenharmony_ci		rate_ss = 1;
6762306a36Sopenharmony_ci		rate_ss_evm = 1;
6862306a36Sopenharmony_ci		evm_id = RTW_EVM_1SS;
6962306a36Sopenharmony_ci		break;
7062306a36Sopenharmony_ci	case DESC_RATEMCS8...DESC_RATEMCS15:
7162306a36Sopenharmony_ci	case DESC_RATEVHT2SS_MCS0...DESC_RATEVHT2SS_MCS9:
7262306a36Sopenharmony_ci		rate_ss = 2;
7362306a36Sopenharmony_ci		rate_ss_evm = 2;
7462306a36Sopenharmony_ci		evm_id = RTW_EVM_2SS_A;
7562306a36Sopenharmony_ci		break;
7662306a36Sopenharmony_ci	default:
7762306a36Sopenharmony_ci		rtw_warn(rtwdev, "unknown pkt rate = %d\n", pkt_stat->rate);
7862306a36Sopenharmony_ci		return;
7962306a36Sopenharmony_ci	}
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	for (i = 0; i < rate_ss_evm; i++) {
8262306a36Sopenharmony_ci		idx = evm_id + i;
8362306a36Sopenharmony_ci		ewma_evm_add(&dm_info->ewma_evm[idx],
8462306a36Sopenharmony_ci			     dm_info->rx_evm_dbm[i]);
8562306a36Sopenharmony_ci	}
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	for (i = 0; i < rtwdev->hal.rf_path_num; i++) {
8862306a36Sopenharmony_ci		idx = RTW_SNR_OFDM_A + 4 * rate_ss + i;
8962306a36Sopenharmony_ci		ewma_snr_add(&dm_info->ewma_snr[idx],
9062306a36Sopenharmony_ci			     dm_info->rx_snr[i]);
9162306a36Sopenharmony_ci	}
9262306a36Sopenharmony_cipkt_num:
9362306a36Sopenharmony_ci	cur_pkt_cnt->num_qry_pkt[pkt_stat->rate]++;
9462306a36Sopenharmony_ci}
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_cistatic void rtw_rx_addr_match_iter(void *data, u8 *mac,
9762306a36Sopenharmony_ci				   struct ieee80211_vif *vif)
9862306a36Sopenharmony_ci{
9962306a36Sopenharmony_ci	struct rtw_rx_addr_match_data *iter_data = data;
10062306a36Sopenharmony_ci	struct ieee80211_sta *sta;
10162306a36Sopenharmony_ci	struct ieee80211_hdr *hdr = iter_data->hdr;
10262306a36Sopenharmony_ci	struct rtw_dev *rtwdev = iter_data->rtwdev;
10362306a36Sopenharmony_ci	struct rtw_sta_info *si;
10462306a36Sopenharmony_ci	struct rtw_rx_pkt_stat *pkt_stat = iter_data->pkt_stat;
10562306a36Sopenharmony_ci	u8 *bssid = iter_data->bssid;
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	if (!ether_addr_equal(vif->bss_conf.bssid, bssid))
10862306a36Sopenharmony_ci		return;
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	if (!(ether_addr_equal(vif->addr, hdr->addr1) ||
11162306a36Sopenharmony_ci	      ieee80211_is_beacon(hdr->frame_control)))
11262306a36Sopenharmony_ci		return;
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	rtw_rx_phy_stat(rtwdev, pkt_stat, hdr);
11562306a36Sopenharmony_ci	sta = ieee80211_find_sta_by_ifaddr(rtwdev->hw, hdr->addr2,
11662306a36Sopenharmony_ci					   vif->addr);
11762306a36Sopenharmony_ci	if (!sta)
11862306a36Sopenharmony_ci		return;
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	si = (struct rtw_sta_info *)sta->drv_priv;
12162306a36Sopenharmony_ci	ewma_rssi_add(&si->avg_rssi, pkt_stat->rssi);
12262306a36Sopenharmony_ci}
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_cistatic void rtw_rx_addr_match(struct rtw_dev *rtwdev,
12562306a36Sopenharmony_ci			      struct rtw_rx_pkt_stat *pkt_stat,
12662306a36Sopenharmony_ci			      struct ieee80211_hdr *hdr)
12762306a36Sopenharmony_ci{
12862306a36Sopenharmony_ci	struct rtw_rx_addr_match_data data = {};
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	if (pkt_stat->crc_err || pkt_stat->icv_err || !pkt_stat->phy_status ||
13162306a36Sopenharmony_ci	    ieee80211_is_ctl(hdr->frame_control))
13262306a36Sopenharmony_ci		return;
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	data.rtwdev = rtwdev;
13562306a36Sopenharmony_ci	data.hdr = hdr;
13662306a36Sopenharmony_ci	data.pkt_stat = pkt_stat;
13762306a36Sopenharmony_ci	data.bssid = get_hdr_bssid(hdr);
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	rtw_iterate_vifs_atomic(rtwdev, rtw_rx_addr_match_iter, &data);
14062306a36Sopenharmony_ci}
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_cistatic void rtw_set_rx_freq_by_pktstat(struct rtw_rx_pkt_stat *pkt_stat,
14362306a36Sopenharmony_ci				       struct ieee80211_rx_status *rx_status)
14462306a36Sopenharmony_ci{
14562306a36Sopenharmony_ci	rx_status->freq = pkt_stat->freq;
14662306a36Sopenharmony_ci	rx_status->band = pkt_stat->band;
14762306a36Sopenharmony_ci}
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_civoid rtw_rx_fill_rx_status(struct rtw_dev *rtwdev,
15062306a36Sopenharmony_ci			   struct rtw_rx_pkt_stat *pkt_stat,
15162306a36Sopenharmony_ci			   struct ieee80211_hdr *hdr,
15262306a36Sopenharmony_ci			   struct ieee80211_rx_status *rx_status,
15362306a36Sopenharmony_ci			   u8 *phy_status)
15462306a36Sopenharmony_ci{
15562306a36Sopenharmony_ci	struct ieee80211_hw *hw = rtwdev->hw;
15662306a36Sopenharmony_ci	u8 path;
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	memset(rx_status, 0, sizeof(*rx_status));
15962306a36Sopenharmony_ci	rx_status->freq = hw->conf.chandef.chan->center_freq;
16062306a36Sopenharmony_ci	rx_status->band = hw->conf.chandef.chan->band;
16162306a36Sopenharmony_ci	if (rtw_fw_feature_check(&rtwdev->fw, FW_FEATURE_SCAN_OFFLOAD) &&
16262306a36Sopenharmony_ci	    test_bit(RTW_FLAG_SCANNING, rtwdev->flags))
16362306a36Sopenharmony_ci		rtw_set_rx_freq_by_pktstat(pkt_stat, rx_status);
16462306a36Sopenharmony_ci	if (pkt_stat->crc_err)
16562306a36Sopenharmony_ci		rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
16662306a36Sopenharmony_ci	if (pkt_stat->decrypted)
16762306a36Sopenharmony_ci		rx_status->flag |= RX_FLAG_DECRYPTED;
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	if (pkt_stat->rate >= DESC_RATEVHT1SS_MCS0)
17062306a36Sopenharmony_ci		rx_status->encoding = RX_ENC_VHT;
17162306a36Sopenharmony_ci	else if (pkt_stat->rate >= DESC_RATEMCS0)
17262306a36Sopenharmony_ci		rx_status->encoding = RX_ENC_HT;
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	if (rx_status->band == NL80211_BAND_5GHZ &&
17562306a36Sopenharmony_ci	    pkt_stat->rate >= DESC_RATE6M &&
17662306a36Sopenharmony_ci	    pkt_stat->rate <= DESC_RATE54M) {
17762306a36Sopenharmony_ci		rx_status->rate_idx = pkt_stat->rate - DESC_RATE6M;
17862306a36Sopenharmony_ci	} else if (rx_status->band == NL80211_BAND_2GHZ &&
17962306a36Sopenharmony_ci		   pkt_stat->rate >= DESC_RATE1M &&
18062306a36Sopenharmony_ci		   pkt_stat->rate <= DESC_RATE54M) {
18162306a36Sopenharmony_ci		rx_status->rate_idx = pkt_stat->rate - DESC_RATE1M;
18262306a36Sopenharmony_ci	} else if (pkt_stat->rate >= DESC_RATEMCS0) {
18362306a36Sopenharmony_ci		rtw_desc_to_mcsrate(pkt_stat->rate, &rx_status->rate_idx,
18462306a36Sopenharmony_ci				    &rx_status->nss);
18562306a36Sopenharmony_ci	}
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	rx_status->flag |= RX_FLAG_MACTIME_START;
18862306a36Sopenharmony_ci	rx_status->mactime = pkt_stat->tsf_low;
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	if (pkt_stat->bw == RTW_CHANNEL_WIDTH_80)
19162306a36Sopenharmony_ci		rx_status->bw = RATE_INFO_BW_80;
19262306a36Sopenharmony_ci	else if (pkt_stat->bw == RTW_CHANNEL_WIDTH_40)
19362306a36Sopenharmony_ci		rx_status->bw = RATE_INFO_BW_40;
19462306a36Sopenharmony_ci	else
19562306a36Sopenharmony_ci		rx_status->bw = RATE_INFO_BW_20;
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	rx_status->signal = pkt_stat->signal_power;
19862306a36Sopenharmony_ci	for (path = 0; path < rtwdev->hal.rf_path_num; path++) {
19962306a36Sopenharmony_ci		rx_status->chains |= BIT(path);
20062306a36Sopenharmony_ci		rx_status->chain_signal[path] = pkt_stat->rx_power[path];
20162306a36Sopenharmony_ci	}
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	rtw_rx_addr_match(rtwdev, pkt_stat, hdr);
20462306a36Sopenharmony_ci}
20562306a36Sopenharmony_ciEXPORT_SYMBOL(rtw_rx_fill_rx_status);
206