18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
28c2ecf20Sopenharmony_ci/* Copyright(c) 2018-2019  Realtek Corporation
38c2ecf20Sopenharmony_ci */
48c2ecf20Sopenharmony_ci
58c2ecf20Sopenharmony_ci#include "main.h"
68c2ecf20Sopenharmony_ci#include "rx.h"
78c2ecf20Sopenharmony_ci#include "ps.h"
88c2ecf20Sopenharmony_ci#include "debug.h"
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_civoid rtw_rx_stats(struct rtw_dev *rtwdev, struct ieee80211_vif *vif,
118c2ecf20Sopenharmony_ci		  struct sk_buff *skb)
128c2ecf20Sopenharmony_ci{
138c2ecf20Sopenharmony_ci	struct ieee80211_hdr *hdr;
148c2ecf20Sopenharmony_ci	struct rtw_vif *rtwvif;
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci	hdr = (struct ieee80211_hdr *)skb->data;
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci	if (!ieee80211_is_data(hdr->frame_control))
198c2ecf20Sopenharmony_ci		return;
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci	if (!is_broadcast_ether_addr(hdr->addr1) &&
228c2ecf20Sopenharmony_ci	    !is_multicast_ether_addr(hdr->addr1)) {
238c2ecf20Sopenharmony_ci		rtwdev->stats.rx_unicast += skb->len;
248c2ecf20Sopenharmony_ci		rtwdev->stats.rx_cnt++;
258c2ecf20Sopenharmony_ci		if (vif) {
268c2ecf20Sopenharmony_ci			rtwvif = (struct rtw_vif *)vif->drv_priv;
278c2ecf20Sopenharmony_ci			rtwvif->stats.rx_unicast += skb->len;
288c2ecf20Sopenharmony_ci			rtwvif->stats.rx_cnt++;
298c2ecf20Sopenharmony_ci		}
308c2ecf20Sopenharmony_ci	}
318c2ecf20Sopenharmony_ci}
328c2ecf20Sopenharmony_ciEXPORT_SYMBOL(rtw_rx_stats);
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_cistruct rtw_rx_addr_match_data {
358c2ecf20Sopenharmony_ci	struct rtw_dev *rtwdev;
368c2ecf20Sopenharmony_ci	struct ieee80211_hdr *hdr;
378c2ecf20Sopenharmony_ci	struct rtw_rx_pkt_stat *pkt_stat;
388c2ecf20Sopenharmony_ci	u8 *bssid;
398c2ecf20Sopenharmony_ci};
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_cistatic void rtw_rx_phy_stat(struct rtw_dev *rtwdev,
428c2ecf20Sopenharmony_ci			    struct rtw_rx_pkt_stat *pkt_stat,
438c2ecf20Sopenharmony_ci			    struct ieee80211_hdr *hdr)
448c2ecf20Sopenharmony_ci{
458c2ecf20Sopenharmony_ci	struct rtw_dm_info *dm_info = &rtwdev->dm_info;
468c2ecf20Sopenharmony_ci	struct rtw_pkt_count *cur_pkt_cnt = &dm_info->cur_pkt_count;
478c2ecf20Sopenharmony_ci	u8 rate_ss, rate_ss_evm, evm_id;
488c2ecf20Sopenharmony_ci	u8 i, idx;
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci	dm_info->curr_rx_rate = pkt_stat->rate;
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	if (ieee80211_is_beacon(hdr->frame_control))
538c2ecf20Sopenharmony_ci		cur_pkt_cnt->num_bcn_pkt++;
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	switch (pkt_stat->rate) {
568c2ecf20Sopenharmony_ci	case DESC_RATE1M...DESC_RATE11M:
578c2ecf20Sopenharmony_ci		goto pkt_num;
588c2ecf20Sopenharmony_ci	case DESC_RATE6M...DESC_RATE54M:
598c2ecf20Sopenharmony_ci		rate_ss = 0;
608c2ecf20Sopenharmony_ci		rate_ss_evm = 1;
618c2ecf20Sopenharmony_ci		evm_id = RTW_EVM_OFDM;
628c2ecf20Sopenharmony_ci		break;
638c2ecf20Sopenharmony_ci	case DESC_RATEMCS0...DESC_RATEMCS7:
648c2ecf20Sopenharmony_ci	case DESC_RATEVHT1SS_MCS0...DESC_RATEVHT1SS_MCS9:
658c2ecf20Sopenharmony_ci		rate_ss = 1;
668c2ecf20Sopenharmony_ci		rate_ss_evm = 1;
678c2ecf20Sopenharmony_ci		evm_id = RTW_EVM_1SS;
688c2ecf20Sopenharmony_ci		break;
698c2ecf20Sopenharmony_ci	case DESC_RATEMCS8...DESC_RATEMCS15:
708c2ecf20Sopenharmony_ci	case DESC_RATEVHT2SS_MCS0...DESC_RATEVHT2SS_MCS9:
718c2ecf20Sopenharmony_ci		rate_ss = 2;
728c2ecf20Sopenharmony_ci		rate_ss_evm = 2;
738c2ecf20Sopenharmony_ci		evm_id = RTW_EVM_2SS_A;
748c2ecf20Sopenharmony_ci		break;
758c2ecf20Sopenharmony_ci	default:
768c2ecf20Sopenharmony_ci		rtw_warn(rtwdev, "unknown pkt rate = %d\n", pkt_stat->rate);
778c2ecf20Sopenharmony_ci		return;
788c2ecf20Sopenharmony_ci	}
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci	for (i = 0; i < rate_ss_evm; i++) {
818c2ecf20Sopenharmony_ci		idx = evm_id + i;
828c2ecf20Sopenharmony_ci		ewma_evm_add(&dm_info->ewma_evm[idx],
838c2ecf20Sopenharmony_ci			     dm_info->rx_evm_dbm[i]);
848c2ecf20Sopenharmony_ci	}
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	for (i = 0; i < rtwdev->hal.rf_path_num; i++) {
878c2ecf20Sopenharmony_ci		idx = RTW_SNR_OFDM_A + 4 * rate_ss + i;
888c2ecf20Sopenharmony_ci		ewma_snr_add(&dm_info->ewma_snr[idx],
898c2ecf20Sopenharmony_ci			     dm_info->rx_snr[i]);
908c2ecf20Sopenharmony_ci	}
918c2ecf20Sopenharmony_cipkt_num:
928c2ecf20Sopenharmony_ci	cur_pkt_cnt->num_qry_pkt[pkt_stat->rate]++;
938c2ecf20Sopenharmony_ci}
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_cistatic void rtw_rx_addr_match_iter(void *data, u8 *mac,
968c2ecf20Sopenharmony_ci				   struct ieee80211_vif *vif)
978c2ecf20Sopenharmony_ci{
988c2ecf20Sopenharmony_ci	struct rtw_rx_addr_match_data *iter_data = data;
998c2ecf20Sopenharmony_ci	struct ieee80211_sta *sta;
1008c2ecf20Sopenharmony_ci	struct ieee80211_hdr *hdr = iter_data->hdr;
1018c2ecf20Sopenharmony_ci	struct rtw_dev *rtwdev = iter_data->rtwdev;
1028c2ecf20Sopenharmony_ci	struct rtw_sta_info *si;
1038c2ecf20Sopenharmony_ci	struct rtw_rx_pkt_stat *pkt_stat = iter_data->pkt_stat;
1048c2ecf20Sopenharmony_ci	u8 *bssid = iter_data->bssid;
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	if (!ether_addr_equal(vif->bss_conf.bssid, bssid))
1078c2ecf20Sopenharmony_ci		return;
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	if (!(ether_addr_equal(vif->addr, hdr->addr1) ||
1108c2ecf20Sopenharmony_ci	      ieee80211_is_beacon(hdr->frame_control)))
1118c2ecf20Sopenharmony_ci		return;
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	rtw_rx_phy_stat(rtwdev, pkt_stat, hdr);
1148c2ecf20Sopenharmony_ci	sta = ieee80211_find_sta_by_ifaddr(rtwdev->hw, hdr->addr2,
1158c2ecf20Sopenharmony_ci					   vif->addr);
1168c2ecf20Sopenharmony_ci	if (!sta)
1178c2ecf20Sopenharmony_ci		return;
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci	si = (struct rtw_sta_info *)sta->drv_priv;
1208c2ecf20Sopenharmony_ci	ewma_rssi_add(&si->avg_rssi, pkt_stat->rssi);
1218c2ecf20Sopenharmony_ci}
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_cistatic void rtw_rx_addr_match(struct rtw_dev *rtwdev,
1248c2ecf20Sopenharmony_ci			      struct rtw_rx_pkt_stat *pkt_stat,
1258c2ecf20Sopenharmony_ci			      struct ieee80211_hdr *hdr)
1268c2ecf20Sopenharmony_ci{
1278c2ecf20Sopenharmony_ci	struct rtw_rx_addr_match_data data = {};
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	if (pkt_stat->crc_err || pkt_stat->icv_err || !pkt_stat->phy_status ||
1308c2ecf20Sopenharmony_ci	    ieee80211_is_ctl(hdr->frame_control))
1318c2ecf20Sopenharmony_ci		return;
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	data.rtwdev = rtwdev;
1348c2ecf20Sopenharmony_ci	data.hdr = hdr;
1358c2ecf20Sopenharmony_ci	data.pkt_stat = pkt_stat;
1368c2ecf20Sopenharmony_ci	data.bssid = get_hdr_bssid(hdr);
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	rtw_iterate_vifs_atomic(rtwdev, rtw_rx_addr_match_iter, &data);
1398c2ecf20Sopenharmony_ci}
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_civoid rtw_rx_fill_rx_status(struct rtw_dev *rtwdev,
1428c2ecf20Sopenharmony_ci			   struct rtw_rx_pkt_stat *pkt_stat,
1438c2ecf20Sopenharmony_ci			   struct ieee80211_hdr *hdr,
1448c2ecf20Sopenharmony_ci			   struct ieee80211_rx_status *rx_status,
1458c2ecf20Sopenharmony_ci			   u8 *phy_status)
1468c2ecf20Sopenharmony_ci{
1478c2ecf20Sopenharmony_ci	struct ieee80211_hw *hw = rtwdev->hw;
1488c2ecf20Sopenharmony_ci	u8 path;
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	memset(rx_status, 0, sizeof(*rx_status));
1518c2ecf20Sopenharmony_ci	rx_status->freq = hw->conf.chandef.chan->center_freq;
1528c2ecf20Sopenharmony_ci	rx_status->band = hw->conf.chandef.chan->band;
1538c2ecf20Sopenharmony_ci	if (pkt_stat->crc_err)
1548c2ecf20Sopenharmony_ci		rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
1558c2ecf20Sopenharmony_ci	if (pkt_stat->decrypted)
1568c2ecf20Sopenharmony_ci		rx_status->flag |= RX_FLAG_DECRYPTED;
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	if (pkt_stat->rate >= DESC_RATEVHT1SS_MCS0)
1598c2ecf20Sopenharmony_ci		rx_status->encoding = RX_ENC_VHT;
1608c2ecf20Sopenharmony_ci	else if (pkt_stat->rate >= DESC_RATEMCS0)
1618c2ecf20Sopenharmony_ci		rx_status->encoding = RX_ENC_HT;
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	if (rx_status->band == NL80211_BAND_5GHZ &&
1648c2ecf20Sopenharmony_ci	    pkt_stat->rate >= DESC_RATE6M &&
1658c2ecf20Sopenharmony_ci	    pkt_stat->rate <= DESC_RATE54M) {
1668c2ecf20Sopenharmony_ci		rx_status->rate_idx = pkt_stat->rate - DESC_RATE6M;
1678c2ecf20Sopenharmony_ci	} else if (rx_status->band == NL80211_BAND_2GHZ &&
1688c2ecf20Sopenharmony_ci		   pkt_stat->rate >= DESC_RATE1M &&
1698c2ecf20Sopenharmony_ci		   pkt_stat->rate <= DESC_RATE54M) {
1708c2ecf20Sopenharmony_ci		rx_status->rate_idx = pkt_stat->rate - DESC_RATE1M;
1718c2ecf20Sopenharmony_ci	} else if (pkt_stat->rate >= DESC_RATEMCS0) {
1728c2ecf20Sopenharmony_ci		rtw_desc_to_mcsrate(pkt_stat->rate, &rx_status->rate_idx,
1738c2ecf20Sopenharmony_ci				    &rx_status->nss);
1748c2ecf20Sopenharmony_ci	}
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci	rx_status->flag |= RX_FLAG_MACTIME_START;
1778c2ecf20Sopenharmony_ci	rx_status->mactime = pkt_stat->tsf_low;
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	if (pkt_stat->bw == RTW_CHANNEL_WIDTH_80)
1808c2ecf20Sopenharmony_ci		rx_status->bw = RATE_INFO_BW_80;
1818c2ecf20Sopenharmony_ci	else if (pkt_stat->bw == RTW_CHANNEL_WIDTH_40)
1828c2ecf20Sopenharmony_ci		rx_status->bw = RATE_INFO_BW_40;
1838c2ecf20Sopenharmony_ci	else
1848c2ecf20Sopenharmony_ci		rx_status->bw = RATE_INFO_BW_20;
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	rx_status->signal = pkt_stat->signal_power;
1878c2ecf20Sopenharmony_ci	for (path = 0; path < rtwdev->hal.rf_path_num; path++) {
1888c2ecf20Sopenharmony_ci		rx_status->chains |= BIT(path);
1898c2ecf20Sopenharmony_ci		rx_status->chain_signal[path] = pkt_stat->rx_power[path];
1908c2ecf20Sopenharmony_ci	}
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	rtw_rx_addr_match(rtwdev, pkt_stat, hdr);
1938c2ecf20Sopenharmony_ci}
1948c2ecf20Sopenharmony_ciEXPORT_SYMBOL(rtw_rx_fill_rx_status);
195