linux/drivers/net/wireless/intel/iwlwifi/dvm/rs.c

// SPDX-License-Identifier: GPL-2.0-only
/******************************************************************************
 *
 * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
 * Copyright (C) 2019 - 2020, 2022 - 2023 Intel Corporation
 *****************************************************************************/
#include <linux/kernel.h>
#include <linux/skbuff.h>
#include <linux/slab.h>
#include <net/mac80211.h>

#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/delay.h>

#include <linux/workqueue.h>

#include "dev.h"
#include "agn.h"

#define RS_NAME

#define NUM_TRY_BEFORE_ANT_TOGGLE
#define IWL_NUMBER_TRY
#define IWL_HT_NUMBER_TRY

#define IWL_RATE_MAX_WINDOW
#define IWL_RATE_MIN_FAILURE_TH
#define IWL_RATE_MIN_SUCCESS_TH

/* max allowed rate miss before sync LQ cmd */
#define IWL_MISSED_RATE_MAX
/* max time to accum history 2 seconds */
#define IWL_RATE_SCALE_FLUSH_INTVL

static u8 rs_ht_to_legacy[] =;

static const u8 ant_toggle_lookup[] =;

#define IWL_DECLARE_RATE_INFO(r, s, ip, in, rp, rn, pp, np)

/*
 * Parameter order:
 *   rate, ht rate, prev rate, next rate, prev tgg rate, next tgg rate
 *
 * If there isn't a valid next or previous rate then INV is used which
 * maps to IWL_RATE_INVALID
 *
 */
const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT] =;

static inline u8 rs_extract_rate(u32 rate_n_flags)
{}

static int iwl_hwrate_to_plcp_idx(u32 rate_n_flags)
{}

static void rs_rate_scale_perform(struct iwl_priv *priv,
				   struct sk_buff *skb,
				   struct ieee80211_sta *sta,
				   struct iwl_lq_sta *lq_sta);
static void rs_fill_link_cmd(struct iwl_priv *priv,
			     struct iwl_lq_sta *lq_sta, u32 rate_n_flags);
static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search);


#ifdef CONFIG_MAC80211_DEBUGFS
static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta,
			     u32 *rate_n_flags, int index);
#else
static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta,
			     u32 *rate_n_flags, int index)
{}
#endif

/*
 * The following tables contain the expected throughput metrics for all rates
 *
 *	1, 2, 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54, 60 MBits
 *
 * where invalid entries are zeros.
 *
 * CCK rates are only valid in legacy table and will only be used in G
 * (2.4 GHz) band.
 */

static const u16 expected_tpt_legacy[IWL_RATE_COUNT] =;

static const u16 expected_tpt_siso20MHz[4][IWL_RATE_COUNT] =;

static const u16 expected_tpt_siso40MHz[4][IWL_RATE_COUNT] =;

static const u16 expected_tpt_mimo2_20MHz[4][IWL_RATE_COUNT] =;

static const u16 expected_tpt_mimo2_40MHz[4][IWL_RATE_COUNT] =;

static const u16 expected_tpt_mimo3_20MHz[4][IWL_RATE_COUNT] =;

static const u16 expected_tpt_mimo3_40MHz[4][IWL_RATE_COUNT] =;

#define MCS_INDEX_PER_STREAM

static void rs_rate_scale_clear_window(struct iwl_rate_scale_data *window)
{}

static inline u8 rs_is_valid_ant(u8 valid_antenna, u8 ant_type)
{}

/*
 *	removes the old data from the statistics. All data that is older than
 *	TID_MAX_TIME_DIFF, will be deleted.
 */
static void rs_tl_rm_old_stats(struct iwl_traffic_load *tl, u32 curr_time)
{}

/*
 *	increment traffic load value for tid and also remove
 *	any old values if passed the certain time period
 */
static u8 rs_tl_add_packet(struct iwl_lq_sta *lq_data,
			   struct ieee80211_hdr *hdr)
{}

#ifdef CONFIG_MAC80211_DEBUGFS
/*
 * Program the device to use fixed rate for frame transmit
 * This is for debugging/testing only
 * once the device start use fixed rate, we need to reload the module
 * to being back the normal operation.
 */
static void rs_program_fix_rate(struct iwl_priv *priv,
				struct iwl_lq_sta *lq_sta)
{}
#endif

/*
	get the traffic load value for tid
*/
static void rs_tl_get_load(struct iwl_lq_sta *lq_data, u8 tid)
{}

static int rs_tl_turn_on_agg_for_tid(struct iwl_priv *priv,
				      struct iwl_lq_sta *lq_data, u8 tid,
				      struct ieee80211_sta *sta)
{}

static void rs_tl_turn_on_agg(struct iwl_priv *priv, u8 tid,
			      struct iwl_lq_sta *lq_data,
			      struct ieee80211_sta *sta)
{}

static inline int get_num_of_ant_from_rate(u32 rate_n_flags)
{}

/*
 * Static function to get the expected throughput from an iwl_scale_tbl_info
 * that wraps a NULL pointer check
 */
static s32 get_expected_tpt(struct iwl_scale_tbl_info *tbl, int rs_index)
{}

/*
 * rs_collect_tx_data - Update the success/failure sliding window
 *
 * We keep a sliding window of the last 62 packets transmitted
 * at this rate.  window->data contains the bitmask of successful
 * packets.
 */
static int rs_collect_tx_data(struct iwl_scale_tbl_info *tbl,
			      int scale_index, int attempts, int successes)
{}

/*
 * Fill uCode API rate_n_flags field, based on "search" or "active" table.
 */
/* FIXME:RS:remove this function and put the flags statically in the table */
static u32 rate_n_flags_from_tbl(struct iwl_priv *priv,
				 struct iwl_scale_tbl_info *tbl,
				 int index, u8 use_green)
{}

/*
 * Interpret uCode API's rate_n_flags format,
 * fill "search" or "active" tx mode table.
 */
static int rs_get_tbl_info_from_mcs(const u32 rate_n_flags,
				    enum nl80211_band band,
				    struct iwl_scale_tbl_info *tbl,
				    int *rate_idx)
{}

/* switch to another antenna/antennas and return 1 */
/* if no other valid antenna found, return 0 */
static int rs_toggle_antenna(u32 valid_ant, u32 *rate_n_flags,
			     struct iwl_scale_tbl_info *tbl)
{}

/*
 * Green-field mode is valid if the station supports it and
 * there are no non-GF stations present in the BSS.
 */
static bool rs_use_green(struct ieee80211_sta *sta)
{}

/*
 * rs_get_supported_rates - get the available rates
 *
 * if management frame or broadcast frame only return
 * basic available rates.
 *
 */
static u16 rs_get_supported_rates(struct iwl_lq_sta *lq_sta,
				  struct ieee80211_hdr *hdr,
				  enum iwl_table_type rate_type)
{}

static u16 rs_get_adjacent_rate(struct iwl_priv *priv, u8 index, u16 rate_mask,
				int rate_type)
{}

static u32 rs_get_lower_rate(struct iwl_lq_sta *lq_sta,
			     struct iwl_scale_tbl_info *tbl,
			     u8 scale_index, u8 ht_possible)
{}

/*
 * Simple function to compare two rate scale table types
 */
static bool table_type_matches(struct iwl_scale_tbl_info *a,
			       struct iwl_scale_tbl_info *b)
{}

static void rs_bt_update_lq(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
			    struct iwl_lq_sta *lq_sta)
{}

/*
 * mac80211 sends us Tx status
 */
static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband,
			 struct ieee80211_sta *sta, void *priv_sta,
			 struct sk_buff *skb)
{}

/*
 * Begin a period of staying with a selected modulation mode.
 * Set "stay_in_tbl" flag to prevent any mode switches.
 * Set frame tx success limits according to legacy vs. high-throughput,
 * and reset overall (spanning all rates) tx success history statistics.
 * These control how long we stay using same modulation mode before
 * searching for a new mode.
 */
static void rs_set_stay_in_table(struct iwl_priv *priv, u8 is_legacy,
				 struct iwl_lq_sta *lq_sta)
{}

/*
 * Find correct throughput table for given mode of modulation
 */
static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta,
				      struct iwl_scale_tbl_info *tbl)
{}

/*
 * Find starting rate for new "search" high-throughput mode of modulation.
 * Goal is to find lowest expected rate (under perfect conditions) that is
 * above the current measured throughput of "active" mode, to give new mode
 * a fair chance to prove itself without too many challenges.
 *
 * This gets called when transitioning to more aggressive modulation
 * (i.e. legacy to SISO or MIMO, or SISO to MIMO), as well as less aggressive
 * (i.e. MIMO to SISO).  When moving to MIMO, bit rate will typically need
 * to decrease to match "active" throughput.  When moving from MIMO to SISO,
 * bit rate will typically need to increase, but not if performance was bad.
 */
static s32 rs_get_best_rate(struct iwl_priv *priv,
			    struct iwl_lq_sta *lq_sta,
			    struct iwl_scale_tbl_info *tbl,	/* "search" */
			    u16 rate_mask, s8 index)
{}

/*
 * Set up search table for MIMO2
 */
static int rs_switch_to_mimo2(struct iwl_priv *priv,
			     struct iwl_lq_sta *lq_sta,
			     struct ieee80211_conf *conf,
			     struct ieee80211_sta *sta,
			     struct iwl_scale_tbl_info *tbl, int index)
{}

/*
 * Set up search table for MIMO3
 */
static int rs_switch_to_mimo3(struct iwl_priv *priv,
			     struct iwl_lq_sta *lq_sta,
			     struct ieee80211_conf *conf,
			     struct ieee80211_sta *sta,
			     struct iwl_scale_tbl_info *tbl, int index)
{}

/*
 * Set up search table for SISO
 */
static int rs_switch_to_siso(struct iwl_priv *priv,
			     struct iwl_lq_sta *lq_sta,
			     struct ieee80211_conf *conf,
			     struct ieee80211_sta *sta,
			     struct iwl_scale_tbl_info *tbl, int index)
{}

/*
 * Try to switch to new modulation mode from legacy
 */
static void rs_move_legacy_other(struct iwl_priv *priv,
				 struct iwl_lq_sta *lq_sta,
				 struct ieee80211_conf *conf,
				 struct ieee80211_sta *sta,
				 int index)
{}

/*
 * Try to switch to new modulation mode from SISO
 */
static void rs_move_siso_to_other(struct iwl_priv *priv,
				  struct iwl_lq_sta *lq_sta,
				  struct ieee80211_conf *conf,
				  struct ieee80211_sta *sta, int index)
{}

/*
 * Try to switch to new modulation mode from MIMO2
 */
static void rs_move_mimo2_to_other(struct iwl_priv *priv,
				   struct iwl_lq_sta *lq_sta,
				   struct ieee80211_conf *conf,
				   struct ieee80211_sta *sta, int index)
{}

/*
 * Try to switch to new modulation mode from MIMO3
 */
static void rs_move_mimo3_to_other(struct iwl_priv *priv,
				   struct iwl_lq_sta *lq_sta,
				   struct ieee80211_conf *conf,
				   struct ieee80211_sta *sta, int index)
{}

/*
 * Check whether we should continue using same modulation mode, or
 * begin search for a new mode, based on:
 * 1) # tx successes or failures while using this mode
 * 2) # times calling this function
 * 3) elapsed time in this mode (not used, for now)
 */
static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search)
{}

/*
 * setup rate table in uCode
 */
static void rs_update_rate_tbl(struct iwl_priv *priv,
			       struct iwl_rxon_context *ctx,
			       struct iwl_lq_sta *lq_sta,
			       struct iwl_scale_tbl_info *tbl,
			       int index, u8 is_green)
{}

/*
 * Do rate scaling and search for new modulation mode.
 */
static void rs_rate_scale_perform(struct iwl_priv *priv,
				  struct sk_buff *skb,
				  struct ieee80211_sta *sta,
				  struct iwl_lq_sta *lq_sta)
{}

/*
 * rs_initialize_lq - Initialize a station's hardware rate table
 *
 * The uCode's station table contains a table of fallback rates
 * for automatic fallback during transmission.
 *
 * NOTE: This sets up a default set of values.  These will be replaced later
 *       if the driver's iwl-agn-rs rate scaling algorithm is used, instead of
 *       rc80211_simple.
 *
 * NOTE: Run REPLY_ADD_STA command to set up station table entry, before
 *       calling this function (which runs REPLY_TX_LINK_QUALITY_CMD,
 *       which requires station table entry to exist).
 */
static void rs_initialize_lq(struct iwl_priv *priv,
			     struct ieee80211_sta *sta,
			     struct iwl_lq_sta *lq_sta)
{}

static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta,
			struct ieee80211_tx_rate_control *txrc)
{}

static void *rs_alloc_sta(void *priv_rate, struct ieee80211_sta *sta,
			  gfp_t gfp)
{}

/*
 * Called after adding a new station to initialize rate scaling
 */
void iwl_rs_rate_init(struct iwl_priv *priv, struct ieee80211_sta *sta, u8 sta_id)
{}

static void rs_fill_link_cmd(struct iwl_priv *priv,
			     struct iwl_lq_sta *lq_sta, u32 new_rate)
{}

static void *rs_alloc(struct ieee80211_hw *hw)
{}
/* rate scale requires free function to be implemented */
static void rs_free(void *priv_rate)
{}

static void rs_free_sta(void *priv_r, struct ieee80211_sta *sta,
			void *priv_sta)
{}

#ifdef CONFIG_MAC80211_DEBUGFS
static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta,
			     u32 *rate_n_flags, int index)
{}

static ssize_t rs_sta_dbgfs_scale_table_write(struct file *file,
			const char __user *user_buf, size_t count, loff_t *ppos)
{}

static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file,
			char __user *user_buf, size_t count, loff_t *ppos)
{}

static const struct file_operations rs_sta_dbgfs_scale_table_ops =;
static ssize_t rs_sta_dbgfs_stats_table_read(struct file *file,
			char __user *user_buf, size_t count, loff_t *ppos)
{}

static const struct file_operations rs_sta_dbgfs_stats_table_ops =;

static ssize_t rs_sta_dbgfs_rate_scale_data_read(struct file *file,
			char __user *user_buf, size_t count, loff_t *ppos)
{}

static const struct file_operations rs_sta_dbgfs_rate_scale_data_ops =;

static void rs_add_debugfs(void *priv, void *priv_sta,
					struct dentry *dir)
{}
#endif

/*
 * Initialization of rate scaling information is done by driver after
 * the station is added. Since mac80211 calls this function before a
 * station is added we ignore it.
 */
static void rs_rate_init_stub(void *priv_r, struct ieee80211_supported_band *sband,
			      struct cfg80211_chan_def *chandef,
			      struct ieee80211_sta *sta, void *priv_sta)
{}

static const struct rate_control_ops rs_ops =;

int iwlagn_rate_control_register(void)
{}

void iwlagn_rate_control_unregister(void)
{}