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