xref: /freebsd/sys/contrib/dev/iwlwifi/mvm/rs.c (revision 3f8cfb8a3a3b9fbe6d4aebde81aee80f8e89e2ea)
1bfcc09ddSBjoern A. Zeeb /*-
2*3f8cfb8aSBjoern A. Zeeb  * Copyright (c) 2020-2025 The FreeBSD Foundation
3bfcc09ddSBjoern A. Zeeb  *
4bfcc09ddSBjoern A. Zeeb  * This software was developed by Björn Zeeb under sponsorship from
5bfcc09ddSBjoern A. Zeeb  * the FreeBSD Foundation.
6bfcc09ddSBjoern A. Zeeb  *
7bfcc09ddSBjoern A. Zeeb  * Redistribution and use in source and binary forms, with or without
8bfcc09ddSBjoern A. Zeeb  * modification, are permitted provided that the following conditions
9bfcc09ddSBjoern A. Zeeb  * are met:
10bfcc09ddSBjoern A. Zeeb  * 1. Redistributions of source code must retain the above copyright
11bfcc09ddSBjoern A. Zeeb  *    notice, this list of conditions and the following disclaimer.
12bfcc09ddSBjoern A. Zeeb  * 2. Redistributions in binary form must reproduce the above copyright
13bfcc09ddSBjoern A. Zeeb  *    notice, this list of conditions and the following disclaimer in the
14bfcc09ddSBjoern A. Zeeb  *    documentation and/or other materials provided with the distribution.
15bfcc09ddSBjoern A. Zeeb  *
16bfcc09ddSBjoern A. Zeeb  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17bfcc09ddSBjoern A. Zeeb  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18bfcc09ddSBjoern A. Zeeb  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19bfcc09ddSBjoern A. Zeeb  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20bfcc09ddSBjoern A. Zeeb  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21bfcc09ddSBjoern A. Zeeb  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22bfcc09ddSBjoern A. Zeeb  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23bfcc09ddSBjoern A. Zeeb  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24bfcc09ddSBjoern A. Zeeb  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25bfcc09ddSBjoern A. Zeeb  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26bfcc09ddSBjoern A. Zeeb  * SUCH DAMAGE.
27bfcc09ddSBjoern A. Zeeb  *
28bfcc09ddSBjoern A. Zeeb  * $FreeBSD$
29bfcc09ddSBjoern A. Zeeb  */
30bfcc09ddSBjoern A. Zeeb 
31bfcc09ddSBjoern A. Zeeb /*
32bfcc09ddSBjoern A. Zeeb  * XXX-BZ:
33bfcc09ddSBjoern A. Zeeb  * This file is left as a wrapper to make mvm compile and we will only
34bfcc09ddSBjoern A. Zeeb  * deal with it on a need basis.  Most newer chipsets do this in firmware.
35bfcc09ddSBjoern A. Zeeb  */
36*3f8cfb8aSBjoern A. Zeeb #include <sys/param.h>
37*3f8cfb8aSBjoern A. Zeeb #include <net/cfg80211.h>		/* LinuxKPI 802.11 TODO() calls. */
38bfcc09ddSBjoern A. Zeeb 
39*3f8cfb8aSBjoern A. Zeeb #include "rs.h"
40bfcc09ddSBjoern A. Zeeb #include "mvm.h"
41bfcc09ddSBjoern A. Zeeb 
4292daf3a6SBjoern A. Zeeb #ifdef CONFIG_IWLWIFI_DEBUGFS
43*3f8cfb8aSBjoern A. Zeeb /*
44*3f8cfb8aSBjoern A. Zeeb  * Fill struct iwl_mvm_frame_stats.
45*3f8cfb8aSBjoern A. Zeeb  * Deal with various RATE_MCS_*_MSK. See rx.c, fw/api/rs.h, et al.
46*3f8cfb8aSBjoern A. Zeeb  * XXX-BZ consider calling iwl_new_rate_from_v1() in rx.c so we can also
47*3f8cfb8aSBjoern A. Zeeb  * use this in rxmq.c.
48*3f8cfb8aSBjoern A. Zeeb  */
4992daf3a6SBjoern A. Zeeb void
iwl_mvm_update_frame_stats(struct iwl_mvm * mvm,u32 rate,bool agg)5092daf3a6SBjoern A. Zeeb iwl_mvm_update_frame_stats(struct iwl_mvm *mvm, u32 rate, bool agg)
5192daf3a6SBjoern A. Zeeb {
52*3f8cfb8aSBjoern A. Zeeb 	uint8_t nss;
5392daf3a6SBjoern A. Zeeb 
54*3f8cfb8aSBjoern A. Zeeb 	spin_lock_bh(&mvm->drv_stats_lock);
55*3f8cfb8aSBjoern A. Zeeb 	mvm->drv_rx_stats.success_frames++;
56*3f8cfb8aSBjoern A. Zeeb 
57*3f8cfb8aSBjoern A. Zeeb 	if (rate & RATE_MCS_HT_MSK_V1) {
58*3f8cfb8aSBjoern A. Zeeb 		mvm->drv_rx_stats.ht_frames++;
59*3f8cfb8aSBjoern A. Zeeb 		nss = 1 + ((rate & RATE_HT_MCS_NSS_MSK_V1) >> RATE_HT_MCS_NSS_POS_V1);
60*3f8cfb8aSBjoern A. Zeeb 	} else if (rate & RATE_MCS_VHT_MSK_V1) {
61*3f8cfb8aSBjoern A. Zeeb 		mvm->drv_rx_stats.vht_frames++;
62*3f8cfb8aSBjoern A. Zeeb 		nss = 1 + FIELD_GET(RATE_MCS_NSS_MSK, rate);
63*3f8cfb8aSBjoern A. Zeeb 	} else {
64*3f8cfb8aSBjoern A. Zeeb 		mvm->drv_rx_stats.legacy_frames++;
65*3f8cfb8aSBjoern A. Zeeb 		nss = 0;
66*3f8cfb8aSBjoern A. Zeeb 	}
67*3f8cfb8aSBjoern A. Zeeb 
68*3f8cfb8aSBjoern A. Zeeb 	switch (rate & RATE_MCS_CHAN_WIDTH_MSK_V1) {
69*3f8cfb8aSBjoern A. Zeeb 	case RATE_MCS_CHAN_WIDTH_20:
70*3f8cfb8aSBjoern A. Zeeb 		mvm->drv_rx_stats.bw_20_frames++;
71*3f8cfb8aSBjoern A. Zeeb 		break;
72*3f8cfb8aSBjoern A. Zeeb 	case RATE_MCS_CHAN_WIDTH_40:
73*3f8cfb8aSBjoern A. Zeeb 		mvm->drv_rx_stats.bw_40_frames++;
74*3f8cfb8aSBjoern A. Zeeb 		break;
75*3f8cfb8aSBjoern A. Zeeb 	case RATE_MCS_CHAN_WIDTH_80:
76*3f8cfb8aSBjoern A. Zeeb 		mvm->drv_rx_stats.bw_80_frames++;
77*3f8cfb8aSBjoern A. Zeeb 		break;
78*3f8cfb8aSBjoern A. Zeeb 	case RATE_MCS_CHAN_WIDTH_160:
79*3f8cfb8aSBjoern A. Zeeb 		mvm->drv_rx_stats.bw_160_frames++;
80*3f8cfb8aSBjoern A. Zeeb 		break;
81*3f8cfb8aSBjoern A. Zeeb 	}
82*3f8cfb8aSBjoern A. Zeeb 
83*3f8cfb8aSBjoern A. Zeeb 	if ((rate & RATE_MCS_CCK_MSK_V1) == 0 &&
84*3f8cfb8aSBjoern A. Zeeb 	    (rate & RATE_MCS_SGI_MSK_V1) != 0)
85*3f8cfb8aSBjoern A. Zeeb 		mvm->drv_rx_stats.sgi_frames++;
86*3f8cfb8aSBjoern A. Zeeb 	else
87*3f8cfb8aSBjoern A. Zeeb 		mvm->drv_rx_stats.ngi_frames++;
88*3f8cfb8aSBjoern A. Zeeb 
89*3f8cfb8aSBjoern A. Zeeb 	switch (nss) {
90*3f8cfb8aSBjoern A. Zeeb 	case 1:
91*3f8cfb8aSBjoern A. Zeeb 		mvm->drv_rx_stats.siso_frames++;
92*3f8cfb8aSBjoern A. Zeeb 		break;
93*3f8cfb8aSBjoern A. Zeeb 	case 2:
94*3f8cfb8aSBjoern A. Zeeb 		mvm->drv_rx_stats.mimo2_frames++;
95*3f8cfb8aSBjoern A. Zeeb 		break;
96*3f8cfb8aSBjoern A. Zeeb 	}
97*3f8cfb8aSBjoern A. Zeeb 
98*3f8cfb8aSBjoern A. Zeeb 	if (agg)
99*3f8cfb8aSBjoern A. Zeeb 		mvm->drv_rx_stats.agg_frames++;
100*3f8cfb8aSBjoern A. Zeeb 
101*3f8cfb8aSBjoern A. Zeeb 	/* ampdu_count? */
102*3f8cfb8aSBjoern A. Zeeb 	/* fail_frames? */
103*3f8cfb8aSBjoern A. Zeeb 
104*3f8cfb8aSBjoern A. Zeeb 	mvm->drv_rx_stats.last_rates[mvm->drv_rx_stats.last_frame_idx] = rate;
105*3f8cfb8aSBjoern A. Zeeb 	mvm->drv_rx_stats.last_frame_idx++;
106*3f8cfb8aSBjoern A. Zeeb 	mvm->drv_rx_stats.last_frame_idx %=
107*3f8cfb8aSBjoern A. Zeeb 	    ARRAY_SIZE(mvm->drv_rx_stats.last_rates);
108*3f8cfb8aSBjoern A. Zeeb 
109*3f8cfb8aSBjoern A. Zeeb 	spin_unlock_bh(&mvm->drv_stats_lock);
11092daf3a6SBjoern A. Zeeb }
11192daf3a6SBjoern A. Zeeb 
11292daf3a6SBjoern A. Zeeb void
iwl_mvm_reset_frame_stats(struct iwl_mvm * mvm)11392daf3a6SBjoern A. Zeeb iwl_mvm_reset_frame_stats(struct iwl_mvm *mvm)
11492daf3a6SBjoern A. Zeeb {
115*3f8cfb8aSBjoern A. Zeeb 	/* Apply same locking rx.c does; debugfs seems to read unloked? */
116*3f8cfb8aSBjoern A. Zeeb 	spin_lock_bh(&mvm->drv_stats_lock);
117*3f8cfb8aSBjoern A. Zeeb 	memset(&mvm->drv_rx_stats, 0, sizeof(mvm->drv_rx_stats));
118*3f8cfb8aSBjoern A. Zeeb 	spin_unlock_bh(&mvm->drv_stats_lock);
11992daf3a6SBjoern A. Zeeb }
12092daf3a6SBjoern A. Zeeb #endif
121bfcc09ddSBjoern A. Zeeb 
122bfcc09ddSBjoern A. Zeeb int
iwl_mvm_rate_control_register(void)123bfcc09ddSBjoern A. Zeeb iwl_mvm_rate_control_register(void)
124bfcc09ddSBjoern A. Zeeb {
125*3f8cfb8aSBjoern A. Zeeb 	TODO("This likely has to call into net80211 unless we gain compat code in LinuxKPI");
126bfcc09ddSBjoern A. Zeeb 	return (0);
127bfcc09ddSBjoern A. Zeeb }
128bfcc09ddSBjoern A. Zeeb 
129bfcc09ddSBjoern A. Zeeb void
iwl_mvm_rate_control_unregister(void)130bfcc09ddSBjoern A. Zeeb iwl_mvm_rate_control_unregister(void)
131bfcc09ddSBjoern A. Zeeb {
132*3f8cfb8aSBjoern A. Zeeb 	TODO("This likely has to call into net80211 unless we gain compat code in LinuxKPI");
133*3f8cfb8aSBjoern A. Zeeb }
134*3f8cfb8aSBjoern A. Zeeb 
135*3f8cfb8aSBjoern A. Zeeb int
iwl_mvm_tx_protection(struct iwl_mvm * mvm,struct iwl_mvm_sta * mvmsta,bool enable)136*3f8cfb8aSBjoern A. Zeeb iwl_mvm_tx_protection(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta, bool enable)
137*3f8cfb8aSBjoern A. Zeeb {
138*3f8cfb8aSBjoern A. Zeeb 	if (iwl_mvm_has_tlc_offload(mvm))
139*3f8cfb8aSBjoern A. Zeeb 		return (rs_fw_tx_protection(mvm, mvmsta, enable));
140*3f8cfb8aSBjoern A. Zeeb         else {
141*3f8cfb8aSBjoern A. Zeeb 		TODO();
142*3f8cfb8aSBjoern A. Zeeb 		return (0);
143*3f8cfb8aSBjoern A. Zeeb 	}
144*3f8cfb8aSBjoern A. Zeeb }
145*3f8cfb8aSBjoern A. Zeeb 
146*3f8cfb8aSBjoern A. Zeeb static void
iwl_mvm_rs_sw_rate_init(struct iwl_mvm * mvm,struct ieee80211_vif * vif,struct ieee80211_sta * sta,struct ieee80211_bss_conf * link_conf,struct ieee80211_link_sta * link_sta,enum nl80211_band band)147*3f8cfb8aSBjoern A. Zeeb iwl_mvm_rs_sw_rate_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
148*3f8cfb8aSBjoern A. Zeeb     struct ieee80211_sta *sta,
149*3f8cfb8aSBjoern A. Zeeb     struct ieee80211_bss_conf *link_conf, struct ieee80211_link_sta *link_sta,
150*3f8cfb8aSBjoern A. Zeeb     enum nl80211_band band)
151*3f8cfb8aSBjoern A. Zeeb {
152*3f8cfb8aSBjoern A. Zeeb 	TODO();
153bfcc09ddSBjoern A. Zeeb }
154bfcc09ddSBjoern A. Zeeb 
155bfcc09ddSBjoern A. Zeeb void
iwl_mvm_rs_rate_init(struct iwl_mvm * mvm,struct ieee80211_vif * vif,struct ieee80211_sta * sta,struct ieee80211_bss_conf * link_conf,struct ieee80211_link_sta * link_sta,enum nl80211_band band)1569af1bba4SBjoern A. Zeeb iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
1579af1bba4SBjoern A. Zeeb     struct ieee80211_sta *sta,
1589af1bba4SBjoern A. Zeeb     struct ieee80211_bss_conf *link_conf, struct ieee80211_link_sta *link_sta,
1599af1bba4SBjoern A. Zeeb     enum nl80211_band band)
160bfcc09ddSBjoern A. Zeeb {
161*3f8cfb8aSBjoern A. Zeeb 	if (iwl_mvm_has_tlc_offload(mvm))
162*3f8cfb8aSBjoern A. Zeeb 		iwl_mvm_rs_fw_rate_init(mvm, vif, sta, link_conf, link_sta, band);
163*3f8cfb8aSBjoern A. Zeeb 	else
164*3f8cfb8aSBjoern A. Zeeb 		iwl_mvm_rs_sw_rate_init(mvm, vif, sta, link_conf, link_sta, band);
165bfcc09ddSBjoern A. Zeeb }
166bfcc09ddSBjoern A. Zeeb 
167bfcc09ddSBjoern A. Zeeb void
iwl_mvm_rs_tx_status(struct iwl_mvm * mvm,struct ieee80211_sta * sta,int tid,struct ieee80211_tx_info * ba_info,bool t)168bfcc09ddSBjoern A. Zeeb iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta, int tid,
169bfcc09ddSBjoern A. Zeeb     struct ieee80211_tx_info *ba_info, bool t)
170bfcc09ddSBjoern A. Zeeb {
171*3f8cfb8aSBjoern A. Zeeb 	TODO();
172bfcc09ddSBjoern A. Zeeb }
173bfcc09ddSBjoern A. Zeeb 
174bfcc09ddSBjoern A. Zeeb void
rs_update_last_rssi(struct iwl_mvm * mvm __unused,struct iwl_mvm_sta * mvmsta,struct ieee80211_rx_status * rx_status)175*3f8cfb8aSBjoern A. Zeeb rs_update_last_rssi(struct iwl_mvm *mvm __unused, struct iwl_mvm_sta *mvmsta,
176bfcc09ddSBjoern A. Zeeb     struct ieee80211_rx_status *rx_status)
177bfcc09ddSBjoern A. Zeeb {
178*3f8cfb8aSBjoern A. Zeeb 	struct iwl_lq_sta *lq_sta;
179*3f8cfb8aSBjoern A. Zeeb 	int i;
180*3f8cfb8aSBjoern A. Zeeb 
181*3f8cfb8aSBjoern A. Zeeb 	if (mvmsta == NULL || rx_status == NULL)
182*3f8cfb8aSBjoern A. Zeeb 		return;
183bfcc09ddSBjoern A. Zeeb 
184bfcc09ddSBjoern A. Zeeb 	/*
185bfcc09ddSBjoern A. Zeeb 	 * Assumption based on mvm/sta.h is that this should update
186bfcc09ddSBjoern A. Zeeb 	 * mvmsta->lq_sta.rs_drv but so far we only saw a iwl_lq_cmd (lq)
187bfcc09ddSBjoern A. Zeeb 	 * access in that struct so nowhere to put rssi information.
188bfcc09ddSBjoern A. Zeeb 	 * So the only thing would be if this is required internally
189bfcc09ddSBjoern A. Zeeb 	 * to functions in this file.
190*3f8cfb8aSBjoern A. Zeeb 	 * The "FW" version accesses more fields.  We assume they
191*3f8cfb8aSBjoern A. Zeeb 	 * are the same for now.
192bfcc09ddSBjoern A. Zeeb 	 */
193*3f8cfb8aSBjoern A. Zeeb 
194*3f8cfb8aSBjoern A. Zeeb 	lq_sta = &mvmsta->deflink.lq_sta.rs_drv;
195*3f8cfb8aSBjoern A. Zeeb 
196*3f8cfb8aSBjoern A. Zeeb 	lq_sta->pers.last_rssi = S8_MIN;
197*3f8cfb8aSBjoern A. Zeeb 	lq_sta->pers.chains = rx_status->chains;
198*3f8cfb8aSBjoern A. Zeeb 
199*3f8cfb8aSBjoern A. Zeeb 	for (i = 0; i < nitems(lq_sta->pers.chain_signal); i++) {
200*3f8cfb8aSBjoern A. Zeeb 		if ((rx_status->chains & BIT(i)) == 0)
201*3f8cfb8aSBjoern A. Zeeb 			continue;
202*3f8cfb8aSBjoern A. Zeeb 
203*3f8cfb8aSBjoern A. Zeeb 		lq_sta->pers.chain_signal[i] = rx_status->chain_signal[i];
204*3f8cfb8aSBjoern A. Zeeb 		if (rx_status->chain_signal[i] > lq_sta->pers.last_rssi)
205*3f8cfb8aSBjoern A. Zeeb 			lq_sta->pers.last_rssi = rx_status->chain_signal[i];
206*3f8cfb8aSBjoern A. Zeeb 	}
207bfcc09ddSBjoern A. Zeeb }
208bfcc09ddSBjoern A. Zeeb 
209bfcc09ddSBjoern A. Zeeb int
rs_pretty_print_rate_v1(char * buf,int bufsz,const u32 rate)210bfcc09ddSBjoern A. Zeeb rs_pretty_print_rate_v1(char *buf, int bufsz, const u32 rate)
211bfcc09ddSBjoern A. Zeeb {
212*3f8cfb8aSBjoern A. Zeeb 	TODO();
213bfcc09ddSBjoern A. Zeeb 	return (0);
214bfcc09ddSBjoern A. Zeeb }
215