18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2008 Felix Fietkau <nbd@openwrt.org> 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#ifndef __RC_MINSTREL_H 78c2ecf20Sopenharmony_ci#define __RC_MINSTREL_H 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#define EWMA_LEVEL 96 /* ewma weighting factor [/EWMA_DIV] */ 108c2ecf20Sopenharmony_ci#define EWMA_DIV 128 118c2ecf20Sopenharmony_ci#define SAMPLE_COLUMNS 10 /* number of columns in sample table */ 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci/* scaled fraction values */ 148c2ecf20Sopenharmony_ci#define MINSTREL_SCALE 12 158c2ecf20Sopenharmony_ci#define MINSTREL_FRAC(val, div) (((val) << MINSTREL_SCALE) / div) 168c2ecf20Sopenharmony_ci#define MINSTREL_TRUNC(val) ((val) >> MINSTREL_SCALE) 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci/* number of highest throughput rates to consider*/ 198c2ecf20Sopenharmony_ci#define MAX_THR_RATES 4 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci/* 228c2ecf20Sopenharmony_ci * Coefficients for moving average with noise filter (period=16), 238c2ecf20Sopenharmony_ci * scaled by 10 bits 248c2ecf20Sopenharmony_ci * 258c2ecf20Sopenharmony_ci * a1 = exp(-pi * sqrt(2) / period) 268c2ecf20Sopenharmony_ci * coeff2 = 2 * a1 * cos(sqrt(2) * 2 * pi / period) 278c2ecf20Sopenharmony_ci * coeff3 = -sqr(a1) 288c2ecf20Sopenharmony_ci * coeff1 = 1 - coeff2 - coeff3 298c2ecf20Sopenharmony_ci */ 308c2ecf20Sopenharmony_ci#define MINSTREL_AVG_COEFF1 (MINSTREL_FRAC(1, 1) - \ 318c2ecf20Sopenharmony_ci MINSTREL_AVG_COEFF2 - \ 328c2ecf20Sopenharmony_ci MINSTREL_AVG_COEFF3) 338c2ecf20Sopenharmony_ci#define MINSTREL_AVG_COEFF2 0x00001499 348c2ecf20Sopenharmony_ci#define MINSTREL_AVG_COEFF3 -0x0000092e 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci/* 378c2ecf20Sopenharmony_ci * Perform EWMA (Exponentially Weighted Moving Average) calculation 388c2ecf20Sopenharmony_ci */ 398c2ecf20Sopenharmony_cistatic inline int 408c2ecf20Sopenharmony_ciminstrel_ewma(int old, int new, int weight) 418c2ecf20Sopenharmony_ci{ 428c2ecf20Sopenharmony_ci int diff, incr; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci diff = new - old; 458c2ecf20Sopenharmony_ci incr = (EWMA_DIV - weight) * diff / EWMA_DIV; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci return old + incr; 488c2ecf20Sopenharmony_ci} 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistatic inline int minstrel_filter_avg_add(u16 *prev_1, u16 *prev_2, s32 in) 518c2ecf20Sopenharmony_ci{ 528c2ecf20Sopenharmony_ci s32 out_1 = *prev_1; 538c2ecf20Sopenharmony_ci s32 out_2 = *prev_2; 548c2ecf20Sopenharmony_ci s32 val; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci if (!in) 578c2ecf20Sopenharmony_ci in += 1; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci if (!out_1) { 608c2ecf20Sopenharmony_ci val = out_1 = in; 618c2ecf20Sopenharmony_ci goto out; 628c2ecf20Sopenharmony_ci } 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci val = MINSTREL_AVG_COEFF1 * in; 658c2ecf20Sopenharmony_ci val += MINSTREL_AVG_COEFF2 * out_1; 668c2ecf20Sopenharmony_ci val += MINSTREL_AVG_COEFF3 * out_2; 678c2ecf20Sopenharmony_ci val >>= MINSTREL_SCALE; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci if (val > 1 << MINSTREL_SCALE) 708c2ecf20Sopenharmony_ci val = 1 << MINSTREL_SCALE; 718c2ecf20Sopenharmony_ci if (val < 0) 728c2ecf20Sopenharmony_ci val = 1; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ciout: 758c2ecf20Sopenharmony_ci *prev_2 = out_1; 768c2ecf20Sopenharmony_ci *prev_1 = val; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci return val; 798c2ecf20Sopenharmony_ci} 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_cistruct minstrel_rate_stats { 828c2ecf20Sopenharmony_ci /* current / last sampling period attempts/success counters */ 838c2ecf20Sopenharmony_ci u16 attempts, last_attempts; 848c2ecf20Sopenharmony_ci u16 success, last_success; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci /* total attempts/success counters */ 878c2ecf20Sopenharmony_ci u32 att_hist, succ_hist; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci /* prob_avg - moving average of prob */ 908c2ecf20Sopenharmony_ci u16 prob_avg; 918c2ecf20Sopenharmony_ci u16 prob_avg_1; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci /* maximum retry counts */ 948c2ecf20Sopenharmony_ci u8 retry_count; 958c2ecf20Sopenharmony_ci u8 retry_count_rtscts; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci u8 sample_skipped; 988c2ecf20Sopenharmony_ci bool retry_updated; 998c2ecf20Sopenharmony_ci}; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_cistruct minstrel_rate { 1028c2ecf20Sopenharmony_ci int bitrate; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci s8 rix; 1058c2ecf20Sopenharmony_ci u8 retry_count_cts; 1068c2ecf20Sopenharmony_ci u8 adjusted_retry_count; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci unsigned int perfect_tx_time; 1098c2ecf20Sopenharmony_ci unsigned int ack_time; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci int sample_limit; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci struct minstrel_rate_stats stats; 1148c2ecf20Sopenharmony_ci}; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cistruct minstrel_sta_info { 1178c2ecf20Sopenharmony_ci struct ieee80211_sta *sta; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci unsigned long last_stats_update; 1208c2ecf20Sopenharmony_ci unsigned int sp_ack_dur; 1218c2ecf20Sopenharmony_ci unsigned int rate_avg; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci unsigned int lowest_rix; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci u8 max_tp_rate[MAX_THR_RATES]; 1268c2ecf20Sopenharmony_ci u8 max_prob_rate; 1278c2ecf20Sopenharmony_ci unsigned int total_packets; 1288c2ecf20Sopenharmony_ci unsigned int sample_packets; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci unsigned int sample_row; 1318c2ecf20Sopenharmony_ci unsigned int sample_column; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci int n_rates; 1348c2ecf20Sopenharmony_ci struct minstrel_rate *r; 1358c2ecf20Sopenharmony_ci bool prev_sample; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci /* sampling table */ 1388c2ecf20Sopenharmony_ci u8 *sample_table; 1398c2ecf20Sopenharmony_ci}; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_cistruct minstrel_priv { 1428c2ecf20Sopenharmony_ci struct ieee80211_hw *hw; 1438c2ecf20Sopenharmony_ci bool has_mrr; 1448c2ecf20Sopenharmony_ci bool new_avg; 1458c2ecf20Sopenharmony_ci u32 sample_switch; 1468c2ecf20Sopenharmony_ci unsigned int cw_min; 1478c2ecf20Sopenharmony_ci unsigned int cw_max; 1488c2ecf20Sopenharmony_ci unsigned int max_retry; 1498c2ecf20Sopenharmony_ci unsigned int segment_size; 1508c2ecf20Sopenharmony_ci unsigned int update_interval; 1518c2ecf20Sopenharmony_ci unsigned int lookaround_rate; 1528c2ecf20Sopenharmony_ci unsigned int lookaround_rate_mrr; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci u8 cck_rates[4]; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci#ifdef CONFIG_MAC80211_DEBUGFS 1578c2ecf20Sopenharmony_ci /* 1588c2ecf20Sopenharmony_ci * enable fixed rate processing per RC 1598c2ecf20Sopenharmony_ci * - write static index to debugfs:ieee80211/phyX/rc/fixed_rate_idx 1608c2ecf20Sopenharmony_ci * - write -1 to enable RC processing again 1618c2ecf20Sopenharmony_ci * - setting will be applied on next update 1628c2ecf20Sopenharmony_ci */ 1638c2ecf20Sopenharmony_ci u32 fixed_rate_idx; 1648c2ecf20Sopenharmony_ci#endif 1658c2ecf20Sopenharmony_ci}; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_cistruct minstrel_debugfs_info { 1688c2ecf20Sopenharmony_ci size_t len; 1698c2ecf20Sopenharmony_ci char buf[]; 1708c2ecf20Sopenharmony_ci}; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ciextern const struct rate_control_ops mac80211_minstrel; 1738c2ecf20Sopenharmony_civoid minstrel_add_sta_debugfs(void *priv, void *priv_sta, struct dentry *dir); 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci/* Recalculate success probabilities and counters for a given rate using EWMA */ 1768c2ecf20Sopenharmony_civoid minstrel_calc_rate_stats(struct minstrel_priv *mp, 1778c2ecf20Sopenharmony_ci struct minstrel_rate_stats *mrs); 1788c2ecf20Sopenharmony_ciint minstrel_get_tp_avg(struct minstrel_rate *mr, int prob_avg); 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci/* debugfs */ 1818c2ecf20Sopenharmony_ciint minstrel_stats_open(struct inode *inode, struct file *file); 1828c2ecf20Sopenharmony_ciint minstrel_stats_csv_open(struct inode *inode, struct file *file); 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci#endif 185