iwl-agn-rs.c 87.3 KB
Newer Older
Z
Zhu Yi 已提交
1 2
/******************************************************************************
 *
3
 * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved.
Z
Zhu Yi 已提交
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of version 2 of the GNU General Public License as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
 *
 * The full GNU General Public License is included in this distribution in the
 * file called LICENSE.
 *
 * Contact Information:
22
 *  Intel Linux Wireless <ilw@linux.intel.com>
Z
Zhu Yi 已提交
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 *
 *****************************************************************************/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/skbuff.h>
#include <linux/wireless.h>
#include <net/mac80211.h>

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

#include <linux/workqueue.h>

38
#include "iwl-dev.h"
39
#include "iwl-sta.h"
40
#include "iwl-core.h"
Z
Zhu Yi 已提交
41

42
#define RS_NAME "iwl-agn-rs"
Z
Zhu Yi 已提交
43

44
#define NUM_TRY_BEFORE_ANT_TOGGLE 1
Z
Zhu Yi 已提交
45 46 47
#define IWL_NUMBER_TRY      1
#define IWL_HT_NUMBER_TRY   3

48 49 50 51
#define IWL_RATE_MAX_WINDOW		62	/* # tx in history window */
#define IWL_RATE_MIN_FAILURE_TH		6	/* min failures to calc tpt */
#define IWL_RATE_MIN_SUCCESS_TH		8	/* min successes to calc tpt */

A
Abbas, Mohamed 已提交
52 53
/* max allowed rate miss before sync LQ cmd */
#define IWL_MISSED_RATE_MAX		15
54
/* max time to accum history 2 seconds */
55
#define IWL_RATE_SCALE_FLUSH_INTVL   (3*HZ)
Z
Zhu Yi 已提交
56 57 58 59 60 61 62 63 64 65 66

static u8 rs_ht_to_legacy[] = {
	IWL_RATE_6M_INDEX, IWL_RATE_6M_INDEX,
	IWL_RATE_6M_INDEX, IWL_RATE_6M_INDEX,
	IWL_RATE_6M_INDEX,
	IWL_RATE_6M_INDEX, IWL_RATE_9M_INDEX,
	IWL_RATE_12M_INDEX, IWL_RATE_18M_INDEX,
	IWL_RATE_24M_INDEX, IWL_RATE_36M_INDEX,
	IWL_RATE_48M_INDEX, IWL_RATE_54M_INDEX
};

67 68 69 70 71 72 73 74 75 76 77
static const u8 ant_toggle_lookup[] = {
	/*ANT_NONE -> */ ANT_NONE,
	/*ANT_A    -> */ ANT_B,
	/*ANT_B    -> */ ANT_C,
	/*ANT_AB   -> */ ANT_BC,
	/*ANT_C    -> */ ANT_A,
	/*ANT_AC   -> */ ANT_AB,
	/*ANT_BC   -> */ ANT_AC,
	/*ANT_ABC  -> */ ANT_ABC,
};

78
/**
79
 * struct iwl_rate_scale_data -- tx success history for one rate
80
 */
81
struct iwl_rate_scale_data {
82 83 84 85 86
	u64 data;		/* bitmap of successful frames */
	s32 success_counter;	/* number of frames successful */
	s32 success_ratio;	/* per-cent * 128  */
	s32 counter;		/* number of frames attempted */
	s32 average_tpt;	/* success ratio * expected throughput */
Z
Zhu Yi 已提交
87 88 89
	unsigned long stamp;
};

90
/**
91
 * struct iwl_scale_tbl_info -- tx params and success history for all rates
92
 *
93
 * There are two of these in struct iwl_lq_sta,
94 95
 * one for "active", and one for "search".
 */
96
struct iwl_scale_tbl_info {
G
Guy Cohen 已提交
97 98
	enum iwl_table_type lq_type;
	u8 ant_type;
99 100 101 102
	u8 is_SGI;	/* 1 = short guard interval */
	u8 is_fat;	/* 1 = 40 MHz channel width */
	u8 is_dup;	/* 1 = duplicated data streams */
	u8 action;	/* change modulation; IWL_[LEGACY/SISO/MIMO]_SWITCH_* */
103
	u8 max_search;	/* maximun number of tables we can search */
104
	s32 *expected_tpt;	/* throughput metrics; expected_tpt_G, etc. */
G
Guy Cohen 已提交
105
	u32 current_rate;  /* rate_n_flags, uCode API format */
106
	struct iwl_rate_scale_data win[IWL_RATE_COUNT]; /* rate histories */
Z
Zhu Yi 已提交
107 108
};

109
struct iwl_traffic_load {
110 111 112 113 114 115 116 117 118 119
	unsigned long time_stamp;	/* age of the oldest statistics */
	u32 packet_count[TID_QUEUE_MAX_SIZE];   /* packet count in this time
						 * slice */
	u32 total;			/* total num of packets during the
					 * last TID_MAX_TIME_DIFF */
	u8 queue_count;			/* number of queues that has
					 * been used since the last cleanup */
	u8 head;			/* start of the circular buffer */
};

120
/**
121
 * struct iwl_lq_sta -- driver's rate scaling private structure
122 123 124
 *
 * Pointer to this gets passed back and forth between driver and mac80211.
 */
125
struct iwl_lq_sta {
126 127 128 129
	u8 active_tbl;		/* index of active table, range 0-1 */
	u8 enable_counter;	/* indicates HT mode */
	u8 stay_in_tbl;		/* 1: disallow, 0: allow search for new mode */
	u8 search_better_tbl;	/* 1: currently trying alternate mode */
Z
Zhu Yi 已提交
130
	s32 last_tpt;
131 132

	/* The following determine when to search for a new mode */
Z
Zhu Yi 已提交
133
	u32 table_count_limit;
134 135
	u32 max_failure_limit;	/* # failed frames before new search */
	u32 max_success_limit;	/* # successful frames before new search */
Z
Zhu Yi 已提交
136
	u32 table_count;
137 138
	u32 total_failed;	/* total failed frames, any/all rates */
	u32 total_success;	/* total successful frames, any/all rates */
139
	u64 flush_timer;	/* time staying in mode before new search */
140 141

	u8 action_counter;	/* # mode-switch actions tried */
Z
Zhu Yi 已提交
142 143
	u8 is_green;
	u8 is_dup;
144
	enum ieee80211_band band;
Z
Zhu Yi 已提交
145
	u8 ibss_sta_added;
146 147

	/* The following are bitmaps of rates; IWL_RATE_6M_MASK, etc. */
148
	u32 supp_rates;
G
Guy Cohen 已提交
149
	u16 active_legacy_rate;
Z
Zhu Yi 已提交
150
	u16 active_siso_rate;
G
Guy Cohen 已提交
151 152
	u16 active_mimo2_rate;
	u16 active_mimo3_rate;
Z
Zhu Yi 已提交
153
	u16 active_rate_basic;
154
	s8 max_rate_idx;     /* Max rate set by user */
A
Abbas, Mohamed 已提交
155
	u8 missed_rate_counter;
156

157
	struct iwl_link_quality_cmd lq;
158 159
	struct iwl_scale_tbl_info lq_info[LQ_SIZE]; /* "active", "search" */
	struct iwl_traffic_load load[TID_MAX_LOAD_COUNT];
160
	u8 tx_agg_tid_en;
161
#ifdef CONFIG_MAC80211_DEBUGFS
162
	struct dentry *rs_sta_dbgfs_scale_table_file;
163
	struct dentry *rs_sta_dbgfs_stats_table_file;
164
	struct dentry *rs_sta_dbgfs_rate_scale_data_file;
165
	struct dentry *rs_sta_dbgfs_tx_agg_tid_en_file;
G
Guy Cohen 已提交
166
	u32 dbg_fixed_rate;
167
#endif
168
	struct iwl_priv *drv;
169 170 171

	/* used to be in sta_info */
	int last_txrate_idx;
172 173
	/* last tx rate_n_flags */
	u32 last_rate_n_flags;
Z
Zhu Yi 已提交
174 175
};

176
static void rs_rate_scale_perform(struct iwl_priv *priv,
177
				   struct sk_buff *skb,
178 179
				   struct ieee80211_sta *sta,
				   struct iwl_lq_sta *lq_sta);
G
Guy Cohen 已提交
180
static void rs_fill_link_cmd(const struct iwl_priv *priv,
181
			     struct iwl_lq_sta *lq_sta, u32 rate_n_flags);
Z
Zhu Yi 已提交
182 183


184
#ifdef CONFIG_MAC80211_DEBUGFS
185 186
static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta,
			     u32 *rate_n_flags, int index);
187
#else
188 189
static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta,
			     u32 *rate_n_flags, int index)
190 191
{}
#endif
192 193 194 195 196 197

/*
 * Expected throughput metrics for following rates:
 * 1, 2, 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54, 60 MBits
 * "G" is the only table that supports CCK (the first 4 rates).
 */
198

Z
Zhu Yi 已提交
199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214
static s32 expected_tpt_A[IWL_RATE_COUNT] = {
	0, 0, 0, 0, 40, 57, 72, 98, 121, 154, 177, 186, 186
};

static s32 expected_tpt_G[IWL_RATE_COUNT] = {
	7, 13, 35, 58, 40, 57, 72, 98, 121, 154, 177, 186, 186
};

static s32 expected_tpt_siso20MHz[IWL_RATE_COUNT] = {
	0, 0, 0, 0, 42, 42, 76, 102, 124, 159, 183, 193, 202
};

static s32 expected_tpt_siso20MHzSGI[IWL_RATE_COUNT] = {
	0, 0, 0, 0, 46, 46, 82, 110, 132, 168, 192, 202, 211
};

215
static s32 expected_tpt_mimo2_20MHz[IWL_RATE_COUNT] = {
Z
Zhu Yi 已提交
216 217 218
	0, 0, 0, 0, 74, 74, 123, 155, 179, 214, 236, 244, 251
};

219
static s32 expected_tpt_mimo2_20MHzSGI[IWL_RATE_COUNT] = {
Z
Zhu Yi 已提交
220 221 222 223 224 225 226 227 228 229 230
	0, 0, 0, 0, 81, 81, 131, 164, 188, 222, 243, 251, 257
};

static s32 expected_tpt_siso40MHz[IWL_RATE_COUNT] = {
	0, 0, 0, 0, 77, 77, 127, 160, 184, 220, 242, 250, 257
};

static s32 expected_tpt_siso40MHzSGI[IWL_RATE_COUNT] = {
	0, 0, 0, 0, 83, 83, 135, 169, 193, 229, 250, 257, 264
};

231
static s32 expected_tpt_mimo2_40MHz[IWL_RATE_COUNT] = {
Z
Zhu Yi 已提交
232 233 234
	0, 0, 0, 0, 123, 123, 182, 214, 235, 264, 279, 285, 289
};

235
static s32 expected_tpt_mimo2_40MHzSGI[IWL_RATE_COUNT] = {
Z
Zhu Yi 已提交
236 237 238
	0, 0, 0, 0, 131, 131, 191, 222, 242, 270, 284, 289, 293
};

239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255
/* Expected throughput metric MIMO3 */
static s32 expected_tpt_mimo3_20MHz[IWL_RATE_COUNT] = {
	0, 0, 0, 0, 99, 99, 153, 186, 208, 239, 256, 263, 268
};

static s32 expected_tpt_mimo3_20MHzSGI[IWL_RATE_COUNT] = {
	0, 0, 0, 0, 106, 106, 162, 194, 215, 246, 262, 268, 273
};

static s32 expected_tpt_mimo3_40MHz[IWL_RATE_COUNT] = {
	0, 0, 0, 0, 152, 152, 211, 239, 255, 279, 290, 294, 297
};

static s32 expected_tpt_mimo3_40MHzSGI[IWL_RATE_COUNT] = {
	0, 0, 0, 0, 160, 160, 219, 245, 261, 284, 294, 297, 300
};

256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272
/* mbps, mcs */
const static struct iwl_rate_mcs_info iwl_rate_mcs[IWL_RATE_COUNT] = {
  {"1", ""},
  {"2", ""},
  {"5.5", ""},
  {"11", ""},
  {"6", "BPSK 1/2"},
  {"9", "BPSK 1/2"},
  {"12", "QPSK 1/2"},
  {"18", "QPSK 3/4"},
  {"24", "16QAM 1/2"},
  {"36", "16QAM 3/4"},
  {"48", "64QAM 2/3"},
  {"54", "64QAM 3/4"},
  {"60", "64QAM 5/6"}
};

G
Guy Cohen 已提交
273
static inline u8 rs_extract_rate(u32 rate_n_flags)
Z
Zhu Yi 已提交
274 275 276 277
{
	return (u8)(rate_n_flags & 0xFF);
}

278
static void rs_rate_scale_clear_window(struct iwl_rate_scale_data *window)
Z
Zhu Yi 已提交
279 280 281 282 283 284 285 286 287
{
	window->data = 0;
	window->success_counter = 0;
	window->success_ratio = IWL_INVALID_VALUE;
	window->counter = 0;
	window->average_tpt = IWL_INVALID_VALUE;
	window->stamp = 0;
}

288 289
static inline u8 rs_is_valid_ant(u8 valid_antenna, u8 ant_type)
{
290
	return (ant_type & valid_antenna) == ant_type;
291 292
}

293 294 295 296
/*
 *	removes the old data from the statistics. All data that is older than
 *	TID_MAX_TIME_DIFF, will be deleted.
 */
297
static void rs_tl_rm_old_stats(struct iwl_traffic_load *tl, u32 curr_time)
298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317
{
	/* The oldest age we want to keep */
	u32 oldest_time = curr_time - TID_MAX_TIME_DIFF;

	while (tl->queue_count &&
	       (tl->time_stamp < oldest_time)) {
		tl->total -= tl->packet_count[tl->head];
		tl->packet_count[tl->head] = 0;
		tl->time_stamp += TID_QUEUE_CELL_SPACING;
		tl->queue_count--;
		tl->head++;
		if (tl->head >= TID_QUEUE_MAX_SIZE)
			tl->head = 0;
	}
}

/*
 *	increment traffic load value for tid and also remove
 *	any old values if passed the certain time period
 */
318
static u8 rs_tl_add_packet(struct iwl_lq_sta *lq_data,
319
			   struct ieee80211_hdr *hdr)
320 321 322 323
{
	u32 curr_time = jiffies_to_msecs(jiffies);
	u32 time_diff;
	s32 index;
324
	struct iwl_traffic_load *tl = NULL;
325
	u8 tid;
326

327
	if (ieee80211_is_data_qos(hdr->frame_control)) {
328
		u8 *qc = ieee80211_get_qos_ctl(hdr);
329 330
		tid = qc[0] & 0xf;
	} else
331
		return MAX_TID_COUNT;
332 333 334 335 336 337 338 339 340 341 342 343

	tl = &lq_data->load[tid];

	curr_time -= curr_time % TID_ROUND_VALUE;

	/* Happens only for the first packet. Initialize the data */
	if (!(tl->queue_count)) {
		tl->total = 1;
		tl->time_stamp = curr_time;
		tl->queue_count = 1;
		tl->head = 0;
		tl->packet_count[0] = 1;
344
		return MAX_TID_COUNT;
345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360
	}

	time_diff = TIME_WRAP_AROUND(tl->time_stamp, curr_time);
	index = time_diff / TID_QUEUE_CELL_SPACING;

	/* The history is too long: remove data that is older than */
	/* TID_MAX_TIME_DIFF */
	if (index >= TID_QUEUE_MAX_SIZE)
		rs_tl_rm_old_stats(tl, curr_time);

	index = (tl->head + index) % TID_QUEUE_MAX_SIZE;
	tl->packet_count[index] = tl->packet_count[index] + 1;
	tl->total = tl->total + 1;

	if ((index + 1) > tl->queue_count)
		tl->queue_count = index + 1;
361 362

	return tid;
363 364 365 366 367
}

/*
	get the traffic load value for tid
*/
368
static u32 rs_tl_get_load(struct iwl_lq_sta *lq_data, u8 tid)
369 370 371 372
{
	u32 curr_time = jiffies_to_msecs(jiffies);
	u32 time_diff;
	s32 index;
373
	struct iwl_traffic_load *tl = NULL;
374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395

	if (tid >= TID_MAX_LOAD_COUNT)
		return 0;

	tl = &(lq_data->load[tid]);

	curr_time -= curr_time % TID_ROUND_VALUE;

	if (!(tl->queue_count))
		return 0;

	time_diff = TIME_WRAP_AROUND(tl->time_stamp, curr_time);
	index = time_diff / TID_QUEUE_CELL_SPACING;

	/* The history is too long: remove data that is older than */
	/* TID_MAX_TIME_DIFF */
	if (index >= TID_QUEUE_MAX_SIZE)
		rs_tl_rm_old_stats(tl, curr_time);

	return tl->total;
}

396
static void rs_tl_turn_on_agg_for_tid(struct iwl_priv *priv,
397
				      struct iwl_lq_sta *lq_data, u8 tid,
398
				      struct ieee80211_sta *sta)
399
{
400
	if (rs_tl_get_load(lq_data, tid) > IWL_AGG_LOAD_THRESHOLD) {
401
		IWL_DEBUG_HT(priv, "Starting Tx agg: STA: %pM tid: %d\n",
J
Johannes Berg 已提交
402
				sta->addr, tid);
403
		ieee80211_start_tx_ba_session(priv->hw, sta->addr, tid);
404 405 406
	}
}

407
static void rs_tl_turn_on_agg(struct iwl_priv *priv, u8 tid,
408
			      struct iwl_lq_sta *lq_data,
409
			      struct ieee80211_sta *sta)
410 411 412 413 414 415 416 417
{
	if ((tid < TID_MAX_LOAD_COUNT))
		rs_tl_turn_on_agg_for_tid(priv, lq_data, tid, sta);
	else if (tid == IWL_AGG_ALL_TID)
		for (tid = 0; tid < TID_MAX_LOAD_COUNT; tid++)
			rs_tl_turn_on_agg_for_tid(priv, lq_data, tid, sta);
}

G
Guy Cohen 已提交
418
static inline int get_num_of_ant_from_rate(u32 rate_n_flags)
G
Guy Cohen 已提交
419
{
420 421 422
	return !!(rate_n_flags & RATE_MCS_ANT_A_MSK) +
	       !!(rate_n_flags & RATE_MCS_ANT_B_MSK) +
	       !!(rate_n_flags & RATE_MCS_ANT_C_MSK);
G
Guy Cohen 已提交
423 424
}

425 426 427 428 429 430 431
/**
 * 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.
 */
432
static int rs_collect_tx_data(struct iwl_rate_scale_data *windows,
433 434
			      int scale_index, s32 tpt, int retries,
			      int successes)
Z
Zhu Yi 已提交
435
{
436
	struct iwl_rate_scale_data *window = NULL;
G
Guy Cohen 已提交
437
	static const u64 mask = (((u64)1) << (IWL_RATE_MAX_WINDOW - 1));
Z
Zhu Yi 已提交
438 439
	s32 fail_count;

440 441
	if (scale_index < 0 || scale_index >= IWL_RATE_COUNT)
		return -EINVAL;
Z
Zhu Yi 已提交
442

443
	/* Select data for current tx bit rate */
Z
Zhu Yi 已提交
444 445
	window = &(windows[scale_index]);

446 447 448 449 450 451 452 453
	/*
	 * Keep track of only the latest 62 tx frame attempts in this rate's
	 * history window; anything older isn't really relevant any more.
	 * If we have filled up the sliding window, drop the oldest attempt;
	 * if the oldest attempt (highest bit in bitmap) shows "success",
	 * subtract "1" from the success counter (this is the main reason
	 * we keep these bitmaps!).
	 */
454
	while (retries > 0) {
G
Guy Cohen 已提交
455 456 457 458 459
		if (window->counter >= IWL_RATE_MAX_WINDOW) {

			/* remove earliest */
			window->counter = IWL_RATE_MAX_WINDOW - 1;

460 461
			if (window->data & mask) {
				window->data &= ~mask;
G
Guy Cohen 已提交
462
				window->success_counter--;
463
			}
Z
Zhu Yi 已提交
464 465
		}

466 467 468 469 470 471
		/* Increment frames-attempted counter */
		window->counter++;

		/* Shift bitmap by one frame (throw away oldest history),
		 * OR in "1", and increment "success" if this
		 * frame was successful. */
472
		window->data <<= 1;
473
		if (successes > 0) {
G
Guy Cohen 已提交
474
			window->success_counter++;
475 476 477
			window->data |= 0x1;
			successes--;
		}
478

479
		retries--;
Z
Zhu Yi 已提交
480 481
	}

482
	/* Calculate current success ratio, avoid divide-by-0! */
Z
Zhu Yi 已提交
483 484 485 486 487 488 489 490
	if (window->counter > 0)
		window->success_ratio = 128 * (100 * window->success_counter)
					/ window->counter;
	else
		window->success_ratio = IWL_INVALID_VALUE;

	fail_count = window->counter - window->success_counter;

491
	/* Calculate average throughput, if we have enough history. */
Z
Zhu Yi 已提交
492 493 494 495 496 497
	if ((fail_count >= IWL_RATE_MIN_FAILURE_TH) ||
	    (window->success_counter >= IWL_RATE_MIN_SUCCESS_TH))
		window->average_tpt = (window->success_ratio * tpt + 64) / 128;
	else
		window->average_tpt = IWL_INVALID_VALUE;

498
	/* Tag this window as having been updated */
Z
Zhu Yi 已提交
499 500
	window->stamp = jiffies;

501
	return 0;
Z
Zhu Yi 已提交
502 503
}

504 505 506
/*
 * Fill uCode API rate_n_flags field, based on "search" or "active" table.
 */
G
Guy Cohen 已提交
507
/* FIXME:RS:remove this function and put the flags statically in the table */
T
Tomas Winkler 已提交
508 509 510
static u32 rate_n_flags_from_tbl(struct iwl_priv *priv,
				 struct iwl_scale_tbl_info *tbl,
				 int index, u8 use_green)
Z
Zhu Yi 已提交
511
{
G
Guy Cohen 已提交
512 513
	u32 rate_n_flags = 0;

Z
Zhu Yi 已提交
514
	if (is_legacy(tbl->lq_type)) {
515
		rate_n_flags = iwl_rates[index].plcp;
Z
Zhu Yi 已提交
516
		if (index >= IWL_FIRST_CCK_RATE && index <= IWL_LAST_CCK_RATE)
G
Guy Cohen 已提交
517
			rate_n_flags |= RATE_MCS_CCK_MSK;
Z
Zhu Yi 已提交
518

G
Guy Cohen 已提交
519 520
	} else if (is_Ht(tbl->lq_type)) {
		if (index > IWL_LAST_OFDM_RATE) {
T
Tomas Winkler 已提交
521
			IWL_ERR(priv, "Invalid HT rate index %d\n", index);
Z
Zhu Yi 已提交
522
			index = IWL_LAST_OFDM_RATE;
G
Guy Cohen 已提交
523
		}
G
Guy Cohen 已提交
524
		rate_n_flags = RATE_MCS_HT_MSK;
G
Guy Cohen 已提交
525 526

		if (is_siso(tbl->lq_type))
527
			rate_n_flags |=	iwl_rates[index].plcp_siso;
G
Guy Cohen 已提交
528
		else if (is_mimo2(tbl->lq_type))
529
			rate_n_flags |=	iwl_rates[index].plcp_mimo2;
G
Guy Cohen 已提交
530
		else
531
			rate_n_flags |=	iwl_rates[index].plcp_mimo3;
Z
Zhu Yi 已提交
532
	} else {
T
Tomas Winkler 已提交
533
		IWL_ERR(priv, "Invalid tbl->lq_type %d\n", tbl->lq_type);
Z
Zhu Yi 已提交
534 535
	}

G
Guy Cohen 已提交
536
	rate_n_flags |= ((tbl->ant_type << RATE_MCS_ANT_POS) &
G
Guy Cohen 已提交
537
						     RATE_MCS_ANT_ABC_MSK);
Z
Zhu Yi 已提交
538

G
Guy Cohen 已提交
539 540 541 542 543 544 545 546 547 548 549 550 551 552
	if (is_Ht(tbl->lq_type)) {
		if (tbl->is_fat) {
			if (tbl->is_dup)
				rate_n_flags |= RATE_MCS_DUP_MSK;
			else
				rate_n_flags |= RATE_MCS_FAT_MSK;
		}
		if (tbl->is_SGI)
			rate_n_flags |= RATE_MCS_SGI_MSK;

		if (use_green) {
			rate_n_flags |= RATE_MCS_GF_MSK;
			if (is_siso(tbl->lq_type) && tbl->is_SGI) {
				rate_n_flags &= ~RATE_MCS_SGI_MSK;
T
Tomas Winkler 已提交
553
				IWL_ERR(priv, "GF was set with SGI:SISO\n");
G
Guy Cohen 已提交
554 555
			}
		}
Z
Zhu Yi 已提交
556
	}
G
Guy Cohen 已提交
557
	return rate_n_flags;
Z
Zhu Yi 已提交
558 559
}

560 561 562 563
/*
 * Interpret uCode API's rate_n_flags format,
 * fill "search" or "active" tx mode table.
 */
G
Guy Cohen 已提交
564
static int rs_get_tbl_info_from_mcs(const u32 rate_n_flags,
565
				    enum ieee80211_band band,
566
				    struct iwl_scale_tbl_info *tbl,
Z
Zhu Yi 已提交
567 568
				    int *rate_idx)
{
G
Guy Cohen 已提交
569 570 571
	u32 ant_msk = (rate_n_flags & RATE_MCS_ANT_ABC_MSK);
	u8 num_of_ant = get_num_of_ant_from_rate(rate_n_flags);
	u8 mcs;
Z
Zhu Yi 已提交
572

573
	*rate_idx = iwl_hwrate_to_plcp_idx(rate_n_flags);
Z
Zhu Yi 已提交
574

G
Guy Cohen 已提交
575
	if (*rate_idx  == IWL_RATE_INVALID) {
Z
Zhu Yi 已提交
576
		*rate_idx = -1;
577
		return -EINVAL;
Z
Zhu Yi 已提交
578
	}
579
	tbl->is_SGI = 0;	/* default legacy setup */
Z
Zhu Yi 已提交
580 581
	tbl->is_fat = 0;
	tbl->is_dup = 0;
G
Guy Cohen 已提交
582 583
	tbl->ant_type = (ant_msk >> RATE_MCS_ANT_POS);
	tbl->lq_type = LQ_NONE;
584
	tbl->max_search = IWL_MAX_SEARCH;
Z
Zhu Yi 已提交
585

586
	/* legacy rate format */
G
Guy Cohen 已提交
587
	if (!(rate_n_flags & RATE_MCS_HT_MSK)) {
G
Guy Cohen 已提交
588
		if (num_of_ant == 1) {
589
			if (band == IEEE80211_BAND_5GHZ)
Z
Zhu Yi 已提交
590 591 592 593
				tbl->lq_type = LQ_A;
			else
				tbl->lq_type = LQ_G;
		}
G
Guy Cohen 已提交
594
	/* HT rate format */
Z
Zhu Yi 已提交
595
	} else {
G
Guy Cohen 已提交
596
		if (rate_n_flags & RATE_MCS_SGI_MSK)
Z
Zhu Yi 已提交
597 598
			tbl->is_SGI = 1;

G
Guy Cohen 已提交
599 600
		if ((rate_n_flags & RATE_MCS_FAT_MSK) ||
		    (rate_n_flags & RATE_MCS_DUP_MSK))
Z
Zhu Yi 已提交
601 602
			tbl->is_fat = 1;

G
Guy Cohen 已提交
603
		if (rate_n_flags & RATE_MCS_DUP_MSK)
Z
Zhu Yi 已提交
604
			tbl->is_dup = 1;
G
Guy Cohen 已提交
605

G
Guy Cohen 已提交
606
		mcs = rs_extract_rate(rate_n_flags);
G
Guy Cohen 已提交
607

G
Guy Cohen 已提交
608 609
		/* SISO */
		if (mcs <= IWL_RATE_SISO_60M_PLCP) {
G
Guy Cohen 已提交
610 611 612
			if (num_of_ant == 1)
				tbl->lq_type = LQ_SISO; /*else NONE*/
		/* MIMO2 */
G
Guy Cohen 已提交
613
		} else if (mcs <= IWL_RATE_MIMO2_60M_PLCP) {
G
Guy Cohen 已提交
614 615 616 617
			if (num_of_ant == 2)
				tbl->lq_type = LQ_MIMO2;
		/* MIMO3 */
		} else {
618 619
			if (num_of_ant == 3) {
				tbl->max_search = IWL_MAX_11N_MIMO3_SEARCH;
G
Guy Cohen 已提交
620
				tbl->lq_type = LQ_MIMO3;
621
			}
G
Guy Cohen 已提交
622
		}
Z
Zhu Yi 已提交
623 624 625
	}
	return 0;
}
626 627 628 629

/* 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,
630
			     struct iwl_scale_tbl_info *tbl)
Z
Zhu Yi 已提交
631
{
632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652
	u8 new_ant_type;

	if (!tbl->ant_type || tbl->ant_type > ANT_ABC)
		return 0;

	if (!rs_is_valid_ant(valid_ant, tbl->ant_type))
		return 0;

	new_ant_type = ant_toggle_lookup[tbl->ant_type];

	while ((new_ant_type != tbl->ant_type) &&
	       !rs_is_valid_ant(valid_ant, new_ant_type))
		new_ant_type = ant_toggle_lookup[new_ant_type];

	if (new_ant_type == tbl->ant_type)
		return 0;

	tbl->ant_type = new_ant_type;
	*rate_n_flags &= ~RATE_MCS_ANT_ABC_MSK;
	*rate_n_flags |= new_ant_type << RATE_MCS_ANT_POS;
	return 1;
Z
Zhu Yi 已提交
653 654
}

655 656 657
/* in 4965 we don't use greenfield at all */
static inline u8 rs_use_green(struct iwl_priv *priv,
			      struct ieee80211_conf *conf)
Z
Zhu Yi 已提交
658
{
659 660 661 662 663 664 665 666 667
	u8 is_green;

	if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965)
		is_green = 0;
	else
		is_green = (conf_is_ht(conf) &&
			   priv->current_ht_config.is_green_field &&
			   !priv->current_ht_config.non_GF_STA_present);
	return is_green;
Z
Zhu Yi 已提交
668 669 670 671 672 673 674 675 676
}

/**
 * rs_get_supported_rates - get the available rates
 *
 * if management frame or broadcast frame only return
 * basic available rates.
 *
 */
677 678 679
static u16 rs_get_supported_rates(struct iwl_lq_sta *lq_sta,
				  struct ieee80211_hdr *hdr,
				  enum iwl_table_type rate_type)
Z
Zhu Yi 已提交
680
{
G
Guy Cohen 已提交
681 682 683 684 685 686 687
	if (hdr && is_multicast_ether_addr(hdr->addr1) &&
	    lq_sta->active_rate_basic)
		return lq_sta->active_rate_basic;

	if (is_legacy(rate_type)) {
		return lq_sta->active_legacy_rate;
	} else {
Z
Zhu Yi 已提交
688
		if (is_siso(rate_type))
G
Guy Cohen 已提交
689
			return lq_sta->active_siso_rate;
G
Guy Cohen 已提交
690
		else if (is_mimo2(rate_type))
G
Guy Cohen 已提交
691
			return lq_sta->active_mimo2_rate;
Z
Zhu Yi 已提交
692
		else
G
Guy Cohen 已提交
693
			return lq_sta->active_mimo3_rate;
694
	}
Z
Zhu Yi 已提交
695 696
}

697 698
static u16 rs_get_adjacent_rate(struct iwl_priv *priv, u8 index, u16 rate_mask,
				int rate_type)
Z
Zhu Yi 已提交
699 700 701 702
{
	u8 high = IWL_RATE_INVALID;
	u8 low = IWL_RATE_INVALID;

703
	/* 802.11A or ht walks to the next literal adjacent rate in
Z
Zhu Yi 已提交
704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731
	 * the rate table */
	if (is_a_band(rate_type) || !is_legacy(rate_type)) {
		int i;
		u32 mask;

		/* Find the previous rate that is in the rate mask */
		i = index - 1;
		for (mask = (1 << i); i >= 0; i--, mask >>= 1) {
			if (rate_mask & mask) {
				low = i;
				break;
			}
		}

		/* Find the next rate that is in the rate mask */
		i = index + 1;
		for (mask = (1 << i); i < IWL_RATE_COUNT; i++, mask <<= 1) {
			if (rate_mask & mask) {
				high = i;
				break;
			}
		}

		return (high << 8) | low;
	}

	low = index;
	while (low != IWL_RATE_INVALID) {
732
		low = iwl_rates[low].prev_rs;
Z
Zhu Yi 已提交
733 734 735 736
		if (low == IWL_RATE_INVALID)
			break;
		if (rate_mask & (1 << low))
			break;
737
		IWL_DEBUG_RATE(priv, "Skipping masked lower rate: %d\n", low);
Z
Zhu Yi 已提交
738 739 740 741
	}

	high = index;
	while (high != IWL_RATE_INVALID) {
742
		high = iwl_rates[high].next_rs;
Z
Zhu Yi 已提交
743 744 745 746
		if (high == IWL_RATE_INVALID)
			break;
		if (rate_mask & (1 << high))
			break;
747
		IWL_DEBUG_RATE(priv, "Skipping masked higher rate: %d\n", high);
Z
Zhu Yi 已提交
748 749 750 751 752
	}

	return (high << 8) | low;
}

753 754 755
static u32 rs_get_lower_rate(struct iwl_lq_sta *lq_sta,
			     struct iwl_scale_tbl_info *tbl,
			     u8 scale_index, u8 ht_possible)
Z
Zhu Yi 已提交
756 757 758 759 760
{
	s32 low;
	u16 rate_mask;
	u16 high_low;
	u8 switch_to_legacy = 0;
761
	u8 is_green = lq_sta->is_green;
Z
Zhu Yi 已提交
762 763 764 765 766 767 768

	/* check if we need to switch from HT to legacy rates.
	 * assumption is that mandatory rates (1Mbps or 6Mbps)
	 * are always supported (spec demand) */
	if (!is_legacy(tbl->lq_type) && (!ht_possible || !scale_index)) {
		switch_to_legacy = 1;
		scale_index = rs_ht_to_legacy[scale_index];
769
		if (lq_sta->band == IEEE80211_BAND_5GHZ)
Z
Zhu Yi 已提交
770 771 772 773
			tbl->lq_type = LQ_A;
		else
			tbl->lq_type = LQ_G;

774
		if (num_of_ant(tbl->ant_type) > 1)
G
Guy Cohen 已提交
775
			tbl->ant_type = ANT_A;/*FIXME:RS*/
Z
Zhu Yi 已提交
776 777 778

		tbl->is_fat = 0;
		tbl->is_SGI = 0;
779
		tbl->max_search = IWL_MAX_SEARCH;
Z
Zhu Yi 已提交
780 781
	}

G
Guy Cohen 已提交
782
	rate_mask = rs_get_supported_rates(lq_sta, NULL, tbl->lq_type);
Z
Zhu Yi 已提交
783

784
	/* Mask with station rate restriction */
Z
Zhu Yi 已提交
785
	if (is_legacy(tbl->lq_type)) {
786
		/* supp_rates has no CCK bits in A mode */
787
		if (lq_sta->band == IEEE80211_BAND_5GHZ)
Z
Zhu Yi 已提交
788
			rate_mask  = (u16)(rate_mask &
789
			   (lq_sta->supp_rates << IWL_FIRST_OFDM_RATE));
Z
Zhu Yi 已提交
790
		else
791
			rate_mask = (u16)(rate_mask & lq_sta->supp_rates);
Z
Zhu Yi 已提交
792 793
	}

794
	/* If we switched from HT to legacy, check current rate */
795
	if (switch_to_legacy && (rate_mask & (1 << scale_index))) {
G
Guy Cohen 已提交
796 797
		low = scale_index;
		goto out;
Z
Zhu Yi 已提交
798 799
	}

800 801
	high_low = rs_get_adjacent_rate(lq_sta->drv, scale_index, rate_mask,
					tbl->lq_type);
Z
Zhu Yi 已提交
802 803
	low = high_low & 0xff;

G
Guy Cohen 已提交
804 805 806 807
	if (low == IWL_RATE_INVALID)
		low = scale_index;

out:
T
Tomas Winkler 已提交
808
	return rate_n_flags_from_tbl(lq_sta->drv, tbl, low, is_green);
Z
Zhu Yi 已提交
809 810
}

811 812 813
/*
 * mac80211 sends us Tx status
 */
814 815
static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband,
			 struct ieee80211_sta *sta, void *priv_sta,
816
			 struct sk_buff *skb)
Z
Zhu Yi 已提交
817 818 819 820
{
	int status;
	u8 retries;
	int rs_index, index = 0;
821
	struct iwl_lq_sta *lq_sta = priv_sta;
822
	struct iwl_link_quality_cmd *table;
Z
Zhu Yi 已提交
823
	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
824 825
	struct iwl_priv *priv = (struct iwl_priv *)priv_r;
	struct ieee80211_hw *hw = priv->hw;
826
	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
827 828
	struct iwl_rate_scale_data *window = NULL;
	struct iwl_rate_scale_data *search_win = NULL;
G
Guy Cohen 已提交
829
	u32 tx_rate;
830 831
	struct iwl_scale_tbl_info tbl_type;
	struct iwl_scale_tbl_info *curr_tbl, *search_tbl;
Z
Zhu Yi 已提交
832 833 834
	u8 active_index = 0;
	s32 tpt = 0;

835
	IWL_DEBUG_RATE_LIMIT(priv, "get frame ack response, update rate scale window\n");
Z
Zhu Yi 已提交
836

837
	if (!ieee80211_is_data(hdr->frame_control) ||
838
	    info->flags & IEEE80211_TX_CTL_NO_ACK)
Z
Zhu Yi 已提交
839 840
		return;

841
	/* This packet was aggregated but doesn't carry rate scale info */
842 843
	if ((info->flags & IEEE80211_TX_CTL_AMPDU) &&
	    !(info->flags & IEEE80211_TX_STAT_AMPDU))
844 845
		return;

846 847 848 849
	if (info->flags & IEEE80211_TX_STAT_AMPDU)
		retries = 0;
	else
		retries = info->status.rates[0].count - 1;
Z
Zhu Yi 已提交
850 851 852 853

	if (retries > 15)
		retries = 15;

854
	if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) &&
855
	    !lq_sta->ibss_sta_added)
856
		goto out;
Z
Zhu Yi 已提交
857

858 859
	table = &lq_sta->lq;
	active_index = lq_sta->active_tbl;
Z
Zhu Yi 已提交
860

861 862
	curr_tbl = &(lq_sta->lq_info[active_index]);
	search_tbl = &(lq_sta->lq_info[(1 - active_index)]);
863 864
	window = (struct iwl_rate_scale_data *)&(curr_tbl->win[0]);
	search_win = (struct iwl_rate_scale_data *)&(search_tbl->win[0]);
Z
Zhu Yi 已提交
865

866 867 868 869 870 871 872 873
	/*
	 * Ignore this Tx frame response if its initial rate doesn't match
	 * that of latest Link Quality command.  There may be stragglers
	 * from a previous Link Quality command, but we're no longer interested
	 * in those; they're either from the "active" mode while we're trying
	 * to check "search" mode, or a prior "search" mode after we've moved
	 * to a new "search" mode (which might become the new "active" mode).
	 */
G
Guy Cohen 已提交
874 875
	tx_rate = le32_to_cpu(table->rs_table[0].rate_n_flags);
	rs_get_tbl_info_from_mcs(tx_rate, priv->band, &tbl_type, &rs_index);
876 877 878
	if (priv->band == IEEE80211_BAND_5GHZ)
		rs_index -= IWL_FIRST_OFDM_RATE;

879 880 881 882 883 884 885
	if ((info->status.rates[0].idx < 0) ||
	    (tbl_type.is_SGI != !!(info->status.rates[0].flags & IEEE80211_TX_RC_SHORT_GI)) ||
	    (tbl_type.is_fat != !!(info->status.rates[0].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)) ||
	    (tbl_type.is_dup != !!(info->status.rates[0].flags & IEEE80211_TX_RC_DUP_DATA)) ||
	    (tbl_type.ant_type != info->antenna_sel_tx) ||
	    (!!(tx_rate & RATE_MCS_HT_MSK) != !!(info->status.rates[0].flags & IEEE80211_TX_RC_MCS)) ||
	    (!!(tx_rate & RATE_MCS_GF_MSK) != !!(info->status.rates[0].flags & IEEE80211_TX_RC_GREEN_FIELD)) ||
886
	    (hw->wiphy->bands[priv->band]->bitrates[rs_index].bitrate !=
887
	     hw->wiphy->bands[info->band]->bitrates[info->status.rates[0].idx].bitrate)) {
888
		IWL_DEBUG_RATE(priv, "initial rate does not match 0x%x\n", tx_rate);
M
Mohamed Abbas 已提交
889 890 891
		/* the last LQ command could failed so the LQ in ucode not
		 * the same in driver sync up
		 */
A
Abbas, Mohamed 已提交
892 893 894 895 896
		lq_sta->missed_rate_counter++;
		if (lq_sta->missed_rate_counter > IWL_MISSED_RATE_MAX) {
			lq_sta->missed_rate_counter = 0;
			iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC);
		}
897
		goto out;
Z
Zhu Yi 已提交
898 899
	}

A
Abbas, Mohamed 已提交
900
	lq_sta->missed_rate_counter = 0;
901
	/* Update frame history window with "failure" for each Tx retry. */
Z
Zhu Yi 已提交
902
	while (retries) {
903 904
		/* Look up the rate and other info used for each tx attempt.
		 * Each tx attempt steps one entry deeper in the rate table. */
G
Guy Cohen 已提交
905 906
		tx_rate = le32_to_cpu(table->rs_table[index].rate_n_flags);
		rs_get_tbl_info_from_mcs(tx_rate, priv->band,
Z
Zhu Yi 已提交
907 908
					  &tbl_type, &rs_index);

909 910
		/* If type matches "search" table,
		 * add failure to "search" history */
Z
Zhu Yi 已提交
911
		if ((tbl_type.lq_type == search_tbl->lq_type) &&
G
Guy Cohen 已提交
912
		    (tbl_type.ant_type == search_tbl->ant_type) &&
Z
Zhu Yi 已提交
913 914 915 916 917
		    (tbl_type.is_SGI == search_tbl->is_SGI)) {
			if (search_tbl->expected_tpt)
				tpt = search_tbl->expected_tpt[rs_index];
			else
				tpt = 0;
918
			rs_collect_tx_data(search_win, rs_index, tpt, 1, 0);
919 920 921

		/* Else if type matches "current/active" table,
		 * add failure to "current/active" history */
Z
Zhu Yi 已提交
922
		} else if ((tbl_type.lq_type == curr_tbl->lq_type) &&
G
Guy Cohen 已提交
923
			   (tbl_type.ant_type == curr_tbl->ant_type) &&
Z
Zhu Yi 已提交
924 925 926 927 928
			   (tbl_type.is_SGI == curr_tbl->is_SGI)) {
			if (curr_tbl->expected_tpt)
				tpt = curr_tbl->expected_tpt[rs_index];
			else
				tpt = 0;
929
			rs_collect_tx_data(window, rs_index, tpt, 1, 0);
Z
Zhu Yi 已提交
930
		}
931 932 933

		/* If not searching for a new mode, increment failed counter
		 * ... this helps determine when to start searching again */
934 935
		if (lq_sta->stay_in_tbl)
			lq_sta->total_failed++;
Z
Zhu Yi 已提交
936 937 938 939 940
		--retries;
		index++;

	}

941 942 943 944 945
	/*
	 * Find (by rate) the history window to update with final Tx attempt;
	 * if Tx was successful first try, use original rate,
	 * else look up the rate that was, finally, successful.
	 */
G
Guy Cohen 已提交
946
	tx_rate = le32_to_cpu(table->rs_table[index].rate_n_flags);
947
	lq_sta->last_rate_n_flags = tx_rate;
G
Guy Cohen 已提交
948
	rs_get_tbl_info_from_mcs(tx_rate, priv->band, &tbl_type, &rs_index);
Z
Zhu Yi 已提交
949

950
	/* Update frame history window with "success" if Tx got ACKed ... */
951
	status = !!(info->flags & IEEE80211_TX_STAT_ACK);
Z
Zhu Yi 已提交
952

953 954
	/* If type matches "search" table,
	 * add final tx status to "search" history */
Z
Zhu Yi 已提交
955
	if ((tbl_type.lq_type == search_tbl->lq_type) &&
G
Guy Cohen 已提交
956
	    (tbl_type.ant_type == search_tbl->ant_type) &&
Z
Zhu Yi 已提交
957 958 959 960 961
	    (tbl_type.is_SGI == search_tbl->is_SGI)) {
		if (search_tbl->expected_tpt)
			tpt = search_tbl->expected_tpt[rs_index];
		else
			tpt = 0;
962
		if (info->flags & IEEE80211_TX_STAT_AMPDU)
963
			rs_collect_tx_data(search_win, rs_index, tpt,
964 965
					   info->status.ampdu_ack_len,
					   info->status.ampdu_ack_map);
966 967 968
		else
			rs_collect_tx_data(search_win, rs_index, tpt,
					   1, status);
969 970
	/* Else if type matches "current/active" table,
	 * add final tx status to "current/active" history */
Z
Zhu Yi 已提交
971
	} else if ((tbl_type.lq_type == curr_tbl->lq_type) &&
G
Guy Cohen 已提交
972
		   (tbl_type.ant_type == curr_tbl->ant_type) &&
Z
Zhu Yi 已提交
973 974 975 976 977
		   (tbl_type.is_SGI == curr_tbl->is_SGI)) {
		if (curr_tbl->expected_tpt)
			tpt = curr_tbl->expected_tpt[rs_index];
		else
			tpt = 0;
978
		if (info->flags & IEEE80211_TX_STAT_AMPDU)
979
			rs_collect_tx_data(window, rs_index, tpt,
980 981
					   info->status.ampdu_ack_len,
					   info->status.ampdu_ack_map);
982 983 984
		else
			rs_collect_tx_data(window, rs_index, tpt,
					   1, status);
Z
Zhu Yi 已提交
985 986
	}

987 988
	/* If not searching for new mode, increment success/failed counter
	 * ... these help determine when to start searching again */
989
	if (lq_sta->stay_in_tbl) {
990
		if (info->flags & IEEE80211_TX_STAT_AMPDU) {
991
			lq_sta->total_success += info->status.ampdu_ack_map;
992
			lq_sta->total_failed +=
993
			     (info->status.ampdu_ack_len - info->status.ampdu_ack_map);
994 995 996 997 998 999
		} else {
			if (status)
				lq_sta->total_success++;
			else
				lq_sta->total_failed++;
		}
Z
Zhu Yi 已提交
1000 1001
	}

1002
	/* See if there's a better rate or modulation mode to try. */
1003
	if (sta && sta->supp_rates[sband->band])
1004
		rs_rate_scale_perform(priv, skb, sta, lq_sta);
1005
out:
Z
Zhu Yi 已提交
1006 1007 1008
	return;
}

1009 1010 1011 1012 1013 1014 1015 1016
/*
 * 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.
 */
1017
static void rs_set_stay_in_table(struct iwl_priv *priv, u8 is_legacy,
1018
				 struct iwl_lq_sta *lq_sta)
Z
Zhu Yi 已提交
1019
{
1020
	IWL_DEBUG_RATE(priv, "we are staying in the same table\n");
1021
	lq_sta->stay_in_tbl = 1;	/* only place this gets set */
Z
Zhu Yi 已提交
1022
	if (is_legacy) {
1023 1024 1025
		lq_sta->table_count_limit = IWL_LEGACY_TABLE_COUNT;
		lq_sta->max_failure_limit = IWL_LEGACY_FAILURE_LIMIT;
		lq_sta->max_success_limit = IWL_LEGACY_SUCCESS_LIMIT;
Z
Zhu Yi 已提交
1026
	} else {
1027 1028 1029
		lq_sta->table_count_limit = IWL_NONE_LEGACY_TABLE_COUNT;
		lq_sta->max_failure_limit = IWL_NONE_LEGACY_FAILURE_LIMIT;
		lq_sta->max_success_limit = IWL_NONE_LEGACY_SUCCESS_LIMIT;
Z
Zhu Yi 已提交
1030
	}
1031 1032 1033
	lq_sta->table_count = 0;
	lq_sta->total_failed = 0;
	lq_sta->total_success = 0;
1034
	lq_sta->flush_timer = jiffies;
1035
	lq_sta->action_counter = 0;
Z
Zhu Yi 已提交
1036 1037
}

1038 1039 1040
/*
 * Find correct throughput table for given mode of modulation
 */
1041 1042
static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta,
				      struct iwl_scale_tbl_info *tbl)
Z
Zhu Yi 已提交
1043 1044 1045 1046 1047 1048 1049
{
	if (is_legacy(tbl->lq_type)) {
		if (!is_a_band(tbl->lq_type))
			tbl->expected_tpt = expected_tpt_G;
		else
			tbl->expected_tpt = expected_tpt_A;
	} else if (is_siso(tbl->lq_type)) {
1050
		if (tbl->is_fat && !lq_sta->is_dup)
Z
Zhu Yi 已提交
1051 1052 1053 1054 1055 1056 1057 1058
			if (tbl->is_SGI)
				tbl->expected_tpt = expected_tpt_siso40MHzSGI;
			else
				tbl->expected_tpt = expected_tpt_siso40MHz;
		else if (tbl->is_SGI)
			tbl->expected_tpt = expected_tpt_siso20MHzSGI;
		else
			tbl->expected_tpt = expected_tpt_siso20MHz;
1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069
	} else if (is_mimo2(tbl->lq_type)) {
		if (tbl->is_fat && !lq_sta->is_dup)
			if (tbl->is_SGI)
				tbl->expected_tpt = expected_tpt_mimo2_40MHzSGI;
			else
				tbl->expected_tpt = expected_tpt_mimo2_40MHz;
		else if (tbl->is_SGI)
			tbl->expected_tpt = expected_tpt_mimo2_20MHzSGI;
		else
			tbl->expected_tpt = expected_tpt_mimo2_20MHz;
	} else if (is_mimo3(tbl->lq_type)) {
1070
		if (tbl->is_fat && !lq_sta->is_dup)
Z
Zhu Yi 已提交
1071
			if (tbl->is_SGI)
1072
				tbl->expected_tpt = expected_tpt_mimo3_40MHzSGI;
Z
Zhu Yi 已提交
1073
			else
1074
				tbl->expected_tpt = expected_tpt_mimo3_40MHz;
Z
Zhu Yi 已提交
1075
		else if (tbl->is_SGI)
1076
			tbl->expected_tpt = expected_tpt_mimo3_20MHzSGI;
Z
Zhu Yi 已提交
1077
		else
1078
			tbl->expected_tpt = expected_tpt_mimo3_20MHz;
Z
Zhu Yi 已提交
1079 1080 1081 1082
	} else
		tbl->expected_tpt = expected_tpt_G;
}

1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094
/*
 * 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.
 */
1095
static s32 rs_get_best_rate(struct iwl_priv *priv,
1096 1097
			    struct iwl_lq_sta *lq_sta,
			    struct iwl_scale_tbl_info *tbl,	/* "search" */
G
Guy Cohen 已提交
1098
			    u16 rate_mask, s8 index)
Z
Zhu Yi 已提交
1099
{
1100
	/* "active" values */
1101
	struct iwl_scale_tbl_info *active_tbl =
1102
	    &(lq_sta->lq_info[lq_sta->active_tbl]);
Z
Zhu Yi 已提交
1103 1104
	s32 active_sr = active_tbl->win[index].success_ratio;
	s32 active_tpt = active_tbl->expected_tpt[index];
1105 1106 1107 1108 1109

	/* expected "search" throughput */
	s32 *tpt_tbl = tbl->expected_tpt;

	s32 new_rate, high, low, start_hi;
Z
Zhu Yi 已提交
1110
	u16 high_low;
G
Guy Cohen 已提交
1111
	s8 rate = index;
Z
Zhu Yi 已提交
1112 1113 1114 1115

	new_rate = high = low = start_hi = IWL_RATE_INVALID;

	for (; ;) {
1116 1117
		high_low = rs_get_adjacent_rate(priv, rate, rate_mask,
						tbl->lq_type);
Z
Zhu Yi 已提交
1118 1119 1120 1121

		low = high_low & 0xff;
		high = (high_low >> 8) & 0xff;

1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136
		/*
		 * Lower the "search" bit rate, to give new "search" mode
		 * approximately the same throughput as "active" if:
		 *
		 * 1) "Active" mode has been working modestly well (but not
		 *    great), and expected "search" throughput (under perfect
		 *    conditions) at candidate rate is above the actual
		 *    measured "active" throughput (but less than expected
		 *    "active" throughput under perfect conditions).
		 * OR
		 * 2) "Active" mode has been working perfectly or very well
		 *    and expected "search" throughput (under perfect
		 *    conditions) at candidate rate is above expected
		 *    "active" throughput (under perfect conditions).
		 */
1137
		if ((((100 * tpt_tbl[rate]) > lq_sta->last_tpt) &&
Z
Zhu Yi 已提交
1138 1139 1140 1141 1142 1143
		     ((active_sr > IWL_RATE_DECREASE_TH) &&
		      (active_sr <= IWL_RATE_HIGH_TH) &&
		      (tpt_tbl[rate] <= active_tpt))) ||
		    ((active_sr >= IWL_RATE_SCALE_SWITCH) &&
		     (tpt_tbl[rate] > active_tpt))) {

1144 1145 1146
			/* (2nd or later pass)
			 * If we've already tried to raise the rate, and are
			 * now trying to lower it, use the higher rate. */
Z
Zhu Yi 已提交
1147 1148 1149 1150
			if (start_hi != IWL_RATE_INVALID) {
				new_rate = start_hi;
				break;
			}
1151

Z
Zhu Yi 已提交
1152
			new_rate = rate;
1153 1154

			/* Loop again with lower rate */
Z
Zhu Yi 已提交
1155 1156
			if (low != IWL_RATE_INVALID)
				rate = low;
1157 1158

			/* Lower rate not available, use the original */
Z
Zhu Yi 已提交
1159 1160
			else
				break;
1161 1162

		/* Else try to raise the "search" rate to match "active" */
Z
Zhu Yi 已提交
1163
		} else {
1164 1165 1166
			/* (2nd or later pass)
			 * If we've already tried to lower the rate, and are
			 * now trying to raise it, use the lower rate. */
Z
Zhu Yi 已提交
1167 1168
			if (new_rate != IWL_RATE_INVALID)
				break;
1169 1170

			/* Loop again with higher rate */
Z
Zhu Yi 已提交
1171 1172 1173
			else if (high != IWL_RATE_INVALID) {
				start_hi = high;
				rate = high;
1174 1175

			/* Higher rate not available, use the original */
Z
Zhu Yi 已提交
1176
			} else {
1177
				new_rate = rate;
Z
Zhu Yi 已提交
1178 1179 1180 1181 1182 1183 1184 1185
				break;
			}
		}
	}

	return new_rate;
}

1186
/*
1187
 * Set up search table for MIMO2
1188
 */
G
Guy Cohen 已提交
1189
static int rs_switch_to_mimo2(struct iwl_priv *priv,
1190
			     struct iwl_lq_sta *lq_sta,
1191
			     struct ieee80211_conf *conf,
1192
			     struct ieee80211_sta *sta,
1193
			     struct iwl_scale_tbl_info *tbl, int index)
Z
Zhu Yi 已提交
1194 1195 1196
{
	u16 rate_mask;
	s32 rate;
1197
	s8 is_green = lq_sta->is_green;
Z
Zhu Yi 已提交
1198

1199
	if (!conf_is_ht(conf) || !sta->ht_cap.ht_supported)
Z
Zhu Yi 已提交
1200 1201
		return -1;

J
Johannes Berg 已提交
1202
	if (((sta->ht_cap.cap & IEEE80211_HT_CAP_SM_PS) >> 2)
1203
						== WLAN_HT_CAP_SM_PS_STATIC)
Z
Zhu Yi 已提交
1204 1205
		return -1;

1206
	/* Need both Tx chains/antennas to support MIMO */
1207
	if (priv->hw_params.tx_chains_num < 2)
Z
Zhu Yi 已提交
1208 1209
		return -1;

1210
	IWL_DEBUG_RATE(priv, "LQ: try to switch to MIMO2\n");
G
Guy Cohen 已提交
1211 1212

	tbl->lq_type = LQ_MIMO2;
1213
	tbl->is_dup = lq_sta->is_dup;
Z
Zhu Yi 已提交
1214
	tbl->action = 0;
1215
	tbl->max_search = IWL_MAX_SEARCH;
G
Guy Cohen 已提交
1216 1217
	rate_mask = lq_sta->active_mimo2_rate;

1218
	if (iwl_is_fat_tx_allowed(priv, &sta->ht_cap))
Z
Zhu Yi 已提交
1219 1220 1221 1222
		tbl->is_fat = 1;
	else
		tbl->is_fat = 0;

G
Guy Cohen 已提交
1223
	/* FIXME: - don't toggle SGI here
Z
Zhu Yi 已提交
1224
	if (tbl->is_fat) {
1225
		if (priv->current_ht_config.sgf & HT_SHORT_GI_40MHZ_ONLY)
Z
Zhu Yi 已提交
1226 1227 1228
			tbl->is_SGI = 1;
		else
			tbl->is_SGI = 0;
1229
	} else if (priv->current_ht_config.sgf & HT_SHORT_GI_20MHZ_ONLY)
Z
Zhu Yi 已提交
1230 1231 1232
		tbl->is_SGI = 1;
	else
		tbl->is_SGI = 0;
G
Guy Cohen 已提交
1233
	*/
Z
Zhu Yi 已提交
1234

G
Guy Cohen 已提交
1235
	rs_set_expected_tpt_table(lq_sta, tbl);
Z
Zhu Yi 已提交
1236

G
Guy Cohen 已提交
1237
	rate = rs_get_best_rate(priv, lq_sta, tbl, rate_mask, index);
Z
Zhu Yi 已提交
1238

1239
	IWL_DEBUG_RATE(priv, "LQ: MIMO2 best rate %d mask %X\n", rate, rate_mask);
1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280
	if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask)) {
		IWL_DEBUG_RATE(priv, "Can't switch with index %d rate mask %x\n",
						rate, rate_mask);
		return -1;
	}
	tbl->current_rate = rate_n_flags_from_tbl(priv, tbl, rate, is_green);

	IWL_DEBUG_RATE(priv, "LQ: Switch to new mcs %X index is green %X\n",
		     tbl->current_rate, is_green);
	return 0;
}

/*
 * 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)
{
	u16 rate_mask;
	s32 rate;
	s8 is_green = lq_sta->is_green;

	if (!conf_is_ht(conf) || !sta->ht_cap.ht_supported)
		return -1;

	if (((sta->ht_cap.cap & IEEE80211_HT_CAP_SM_PS) >> 2)
						== WLAN_HT_CAP_SM_PS_STATIC)
		return -1;

	/* Need both Tx chains/antennas to support MIMO */
	if (priv->hw_params.tx_chains_num < 3)
		return -1;

	IWL_DEBUG_RATE(priv, "LQ: try to switch to MIMO3\n");

	tbl->lq_type = LQ_MIMO3;
	tbl->is_dup = lq_sta->is_dup;
	tbl->action = 0;
1281
	tbl->max_search = IWL_MAX_11N_MIMO3_SEARCH;
1282 1283
	rate_mask = lq_sta->active_mimo3_rate;

1284
	if (iwl_is_fat_tx_allowed(priv, &sta->ht_cap))
1285 1286 1287
		tbl->is_fat = 1;
	else
		tbl->is_fat = 0;
G
Guy Cohen 已提交
1288

1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306
	/* FIXME: - don't toggle SGI here
	if (tbl->is_fat) {
		if (priv->current_ht_config.sgf & HT_SHORT_GI_40MHZ_ONLY)
			tbl->is_SGI = 1;
		else
			tbl->is_SGI = 0;
	} else if (priv->current_ht_config.sgf & HT_SHORT_GI_20MHZ_ONLY)
		tbl->is_SGI = 1;
	else
		tbl->is_SGI = 0;
	*/

	rs_set_expected_tpt_table(lq_sta, tbl);

	rate = rs_get_best_rate(priv, lq_sta, tbl, rate_mask, index);

	IWL_DEBUG_RATE(priv, "LQ: MIMO3 best rate %d mask %X\n",
		rate, rate_mask);
G
Guy Cohen 已提交
1307
	if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask)) {
1308
		IWL_DEBUG_RATE(priv, "Can't switch with index %d rate mask %x\n",
G
Guy Cohen 已提交
1309
						rate, rate_mask);
Z
Zhu Yi 已提交
1310
		return -1;
G
Guy Cohen 已提交
1311
	}
T
Tomas Winkler 已提交
1312
	tbl->current_rate = rate_n_flags_from_tbl(priv, tbl, rate, is_green);
Z
Zhu Yi 已提交
1313

1314
	IWL_DEBUG_RATE(priv, "LQ: Switch to new mcs %X index is green %X\n",
G
Guy Cohen 已提交
1315
		     tbl->current_rate, is_green);
1316
	return 0;
G
Guy Cohen 已提交
1317
}
Z
Zhu Yi 已提交
1318

1319 1320 1321
/*
 * Set up search table for SISO
 */
1322
static int rs_switch_to_siso(struct iwl_priv *priv,
1323
			     struct iwl_lq_sta *lq_sta,
1324
			     struct ieee80211_conf *conf,
1325
			     struct ieee80211_sta *sta,
1326
			     struct iwl_scale_tbl_info *tbl, int index)
Z
Zhu Yi 已提交
1327 1328
{
	u16 rate_mask;
1329
	u8 is_green = lq_sta->is_green;
Z
Zhu Yi 已提交
1330 1331
	s32 rate;

1332
	if (!conf_is_ht(conf) || !sta->ht_cap.ht_supported)
Z
Zhu Yi 已提交
1333 1334
		return -1;

1335
	IWL_DEBUG_RATE(priv, "LQ: try to switch to SISO\n");
G
Guy Cohen 已提交
1336

1337
	tbl->is_dup = lq_sta->is_dup;
Z
Zhu Yi 已提交
1338 1339
	tbl->lq_type = LQ_SISO;
	tbl->action = 0;
1340
	tbl->max_search = IWL_MAX_SEARCH;
G
Guy Cohen 已提交
1341
	rate_mask = lq_sta->active_siso_rate;
Z
Zhu Yi 已提交
1342

1343
	if (iwl_is_fat_tx_allowed(priv, &sta->ht_cap))
Z
Zhu Yi 已提交
1344 1345 1346 1347
		tbl->is_fat = 1;
	else
		tbl->is_fat = 0;

G
Guy Cohen 已提交
1348
	/* FIXME: - don't toggle SGI here
Z
Zhu Yi 已提交
1349
	if (tbl->is_fat) {
1350
		if (priv->current_ht_config.sgf & HT_SHORT_GI_40MHZ_ONLY)
Z
Zhu Yi 已提交
1351 1352 1353
			tbl->is_SGI = 1;
		else
			tbl->is_SGI = 0;
1354
	} else if (priv->current_ht_config.sgf & HT_SHORT_GI_20MHZ_ONLY)
Z
Zhu Yi 已提交
1355 1356 1357
		tbl->is_SGI = 1;
	else
		tbl->is_SGI = 0;
G
Guy Cohen 已提交
1358
	*/
Z
Zhu Yi 已提交
1359 1360

	if (is_green)
G
Guy Cohen 已提交
1361
		tbl->is_SGI = 0; /*11n spec: no SGI in SISO+Greenfield*/
Z
Zhu Yi 已提交
1362

G
Guy Cohen 已提交
1363
	rs_set_expected_tpt_table(lq_sta, tbl);
G
Guy Cohen 已提交
1364
	rate = rs_get_best_rate(priv, lq_sta, tbl, rate_mask, index);
Z
Zhu Yi 已提交
1365

1366
	IWL_DEBUG_RATE(priv, "LQ: get best rate %d mask %X\n", rate, rate_mask);
Z
Zhu Yi 已提交
1367
	if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask)) {
1368
		IWL_DEBUG_RATE(priv, "can not switch with index %d rate mask %x\n",
Z
Zhu Yi 已提交
1369 1370 1371
			     rate, rate_mask);
		return -1;
	}
T
Tomas Winkler 已提交
1372
	tbl->current_rate = rate_n_flags_from_tbl(priv, tbl, rate, is_green);
1373
	IWL_DEBUG_RATE(priv, "LQ: Switch to new mcs %X index is green %X\n",
G
Guy Cohen 已提交
1374
		     tbl->current_rate, is_green);
1375
	return 0;
Z
Zhu Yi 已提交
1376 1377
}

1378 1379 1380
/*
 * Try to switch to new modulation mode from legacy
 */
1381
static int rs_move_legacy_other(struct iwl_priv *priv,
1382
				struct iwl_lq_sta *lq_sta,
1383
				struct ieee80211_conf *conf,
1384
				struct ieee80211_sta *sta,
Z
Zhu Yi 已提交
1385 1386
				int index)
{
1387 1388 1389 1390 1391 1392
	struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
	struct iwl_scale_tbl_info *search_tbl =
				&(lq_sta->lq_info[(1 - lq_sta->active_tbl)]);
	struct iwl_rate_scale_data *window = &(tbl->win[index]);
	u32 sz = (sizeof(struct iwl_scale_tbl_info) -
		  (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
Z
Zhu Yi 已提交
1393
	u8 start_action = tbl->action;
G
Guy Cohen 已提交
1394
	u8 valid_tx_ant = priv->hw_params.valid_tx_ant;
1395
	u8 tx_chains_num = priv->hw_params.tx_chains_num;
G
Guy Cohen 已提交
1396
	int ret = 0;
1397
	u8 update_search_tbl_counter = 0;
Z
Zhu Yi 已提交
1398 1399

	for (; ;) {
1400
		lq_sta->action_counter++;
Z
Zhu Yi 已提交
1401
		switch (tbl->action) {
1402 1403
		case IWL_LEGACY_SWITCH_ANTENNA1:
		case IWL_LEGACY_SWITCH_ANTENNA2:
1404
			IWL_DEBUG_RATE(priv, "LQ: Legacy toggle Antenna\n");
Z
Zhu Yi 已提交
1405

1406 1407 1408 1409 1410 1411
			if ((tbl->action == IWL_LEGACY_SWITCH_ANTENNA1 &&
							tx_chains_num <= 1) ||
			    (tbl->action == IWL_LEGACY_SWITCH_ANTENNA2 &&
							tx_chains_num <= 2))
				break;

1412
			/* Don't change antenna if success has been great */
Z
Zhu Yi 已提交
1413 1414
			if (window->success_ratio >= IWL_RS_GOOD_RATIO)
				break;
1415 1416

			/* Set up search table to try other antenna */
Z
Zhu Yi 已提交
1417 1418
			memcpy(search_tbl, tbl, sz);

1419 1420
			if (rs_toggle_antenna(valid_tx_ant,
				&search_tbl->current_rate, search_tbl)) {
1421
				update_search_tbl_counter = 1;
1422
				rs_set_expected_tpt_table(lq_sta, search_tbl);
1423 1424
				goto out;
			}
G
Guy Cohen 已提交
1425
			break;
Z
Zhu Yi 已提交
1426
		case IWL_LEGACY_SWITCH_SISO:
1427
			IWL_DEBUG_RATE(priv, "LQ: Legacy switch to SISO\n");
1428 1429

			/* Set up search table to try SISO */
Z
Zhu Yi 已提交
1430 1431
			memcpy(search_tbl, tbl, sz);
			search_tbl->is_SGI = 0;
1432
			ret = rs_switch_to_siso(priv, lq_sta, conf, sta,
1433
						 search_tbl, index);
1434
			if (!ret) {
1435
				lq_sta->action_counter = 0;
Z
Zhu Yi 已提交
1436
				goto out;
1437
			}
Z
Zhu Yi 已提交
1438 1439

			break;
1440 1441 1442
		case IWL_LEGACY_SWITCH_MIMO2_AB:
		case IWL_LEGACY_SWITCH_MIMO2_AC:
		case IWL_LEGACY_SWITCH_MIMO2_BC:
1443
			IWL_DEBUG_RATE(priv, "LQ: Legacy switch to MIMO2\n");
1444 1445

			/* Set up search table to try MIMO */
Z
Zhu Yi 已提交
1446 1447
			memcpy(search_tbl, tbl, sz);
			search_tbl->is_SGI = 0;
1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458

			if (tbl->action == IWL_LEGACY_SWITCH_MIMO2_AB)
				search_tbl->ant_type = ANT_AB;
			else if (tbl->action == IWL_LEGACY_SWITCH_MIMO2_AC)
				search_tbl->ant_type = ANT_AC;
			else
				search_tbl->ant_type = ANT_BC;

			if (!rs_is_valid_ant(valid_tx_ant, search_tbl->ant_type))
				break;

G
Guy Cohen 已提交
1459
			ret = rs_switch_to_mimo2(priv, lq_sta, conf, sta,
1460
						 search_tbl, index);
1461
			if (!ret) {
1462
				lq_sta->action_counter = 0;
Z
Zhu Yi 已提交
1463
				goto out;
1464
			}
Z
Zhu Yi 已提交
1465
			break;
1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485

		case IWL_LEGACY_SWITCH_MIMO3_ABC:
			IWL_DEBUG_RATE(priv, "LQ: Legacy switch to MIMO3\n");

			/* Set up search table to try MIMO3 */
			memcpy(search_tbl, tbl, sz);
			search_tbl->is_SGI = 0;

			search_tbl->ant_type = ANT_ABC;

			if (!rs_is_valid_ant(valid_tx_ant, search_tbl->ant_type))
				break;

			ret = rs_switch_to_mimo3(priv, lq_sta, conf, sta,
						 search_tbl, index);
			if (!ret) {
				lq_sta->action_counter = 0;
				goto out;
			}
			break;
Z
Zhu Yi 已提交
1486 1487
		}
		tbl->action++;
1488
		if (tbl->action > IWL_LEGACY_SWITCH_MIMO3_ABC)
1489
			tbl->action = IWL_LEGACY_SWITCH_ANTENNA1;
Z
Zhu Yi 已提交
1490 1491 1492 1493 1494

		if (tbl->action == start_action)
			break;

	}
1495
	search_tbl->lq_type = LQ_NONE;
Z
Zhu Yi 已提交
1496 1497
	return 0;

1498 1499
out:
	lq_sta->search_better_tbl = 1;
Z
Zhu Yi 已提交
1500
	tbl->action++;
1501
	if (tbl->action > IWL_LEGACY_SWITCH_MIMO3_ABC)
1502
		tbl->action = IWL_LEGACY_SWITCH_ANTENNA1;
1503 1504
	if (update_search_tbl_counter)
		search_tbl->action = tbl->action;
Z
Zhu Yi 已提交
1505 1506 1507 1508
	return 0;

}

1509 1510 1511
/*
 * Try to switch to new modulation mode from SISO
 */
1512
static int rs_move_siso_to_other(struct iwl_priv *priv,
1513
				 struct iwl_lq_sta *lq_sta,
1514
				 struct ieee80211_conf *conf,
1515
				 struct ieee80211_sta *sta, int index)
Z
Zhu Yi 已提交
1516
{
1517
	u8 is_green = lq_sta->is_green;
1518 1519 1520 1521 1522 1523
	struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
	struct iwl_scale_tbl_info *search_tbl =
				&(lq_sta->lq_info[(1 - lq_sta->active_tbl)]);
	struct iwl_rate_scale_data *window = &(tbl->win[index]);
	u32 sz = (sizeof(struct iwl_scale_tbl_info) -
		  (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
Z
Zhu Yi 已提交
1524
	u8 start_action = tbl->action;
G
Guy Cohen 已提交
1525
	u8 valid_tx_ant = priv->hw_params.valid_tx_ant;
1526
	u8 tx_chains_num = priv->hw_params.tx_chains_num;
1527
	u8 update_search_tbl_counter = 0;
G
Guy Cohen 已提交
1528
	int ret;
Z
Zhu Yi 已提交
1529 1530

	for (;;) {
1531
		lq_sta->action_counter++;
Z
Zhu Yi 已提交
1532
		switch (tbl->action) {
1533 1534
		case IWL_SISO_SWITCH_ANTENNA1:
		case IWL_SISO_SWITCH_ANTENNA2:
1535
			IWL_DEBUG_RATE(priv, "LQ: SISO toggle Antenna\n");
1536 1537 1538 1539 1540 1541 1542

			if ((tbl->action == IWL_SISO_SWITCH_ANTENNA1 &&
							tx_chains_num <= 1) ||
			    (tbl->action == IWL_SISO_SWITCH_ANTENNA2 &&
							tx_chains_num <= 2))
				break;

Z
Zhu Yi 已提交
1543 1544 1545 1546
			if (window->success_ratio >= IWL_RS_GOOD_RATIO)
				break;

			memcpy(search_tbl, tbl, sz);
1547
			if (rs_toggle_antenna(valid_tx_ant,
1548 1549
				       &search_tbl->current_rate, search_tbl)) {
				update_search_tbl_counter = 1;
1550
				goto out;
1551
			}
G
Guy Cohen 已提交
1552
			break;
1553 1554 1555
		case IWL_SISO_SWITCH_MIMO2_AB:
		case IWL_SISO_SWITCH_MIMO2_AC:
		case IWL_SISO_SWITCH_MIMO2_BC:
1556
			IWL_DEBUG_RATE(priv, "LQ: SISO switch to MIMO2\n");
Z
Zhu Yi 已提交
1557 1558
			memcpy(search_tbl, tbl, sz);
			search_tbl->is_SGI = 0;
1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569

			if (tbl->action == IWL_SISO_SWITCH_MIMO2_AB)
				search_tbl->ant_type = ANT_AB;
			else if (tbl->action == IWL_SISO_SWITCH_MIMO2_AC)
				search_tbl->ant_type = ANT_AC;
			else
				search_tbl->ant_type = ANT_BC;

			if (!rs_is_valid_ant(valid_tx_ant, search_tbl->ant_type))
				break;

G
Guy Cohen 已提交
1570
			ret = rs_switch_to_mimo2(priv, lq_sta, conf, sta,
1571
						 search_tbl, index);
1572
			if (!ret)
Z
Zhu Yi 已提交
1573 1574 1575
				goto out;
			break;
		case IWL_SISO_SWITCH_GI:
1576 1577 1578 1579 1580 1581 1582 1583 1584
			if (!tbl->is_fat &&
				!(priv->current_ht_config.sgf &
						HT_SHORT_GI_20MHZ))
				break;
			if (tbl->is_fat &&
				!(priv->current_ht_config.sgf &
						HT_SHORT_GI_40MHZ))
				break;

1585
			IWL_DEBUG_RATE(priv, "LQ: SISO toggle SGI/NGI\n");
1586

Z
Zhu Yi 已提交
1587
			memcpy(search_tbl, tbl, sz);
G
Guy Cohen 已提交
1588 1589 1590 1591
			if (is_green) {
				if (!tbl->is_SGI)
					break;
				else
1592 1593
					IWL_ERR(priv,
						"SGI was set in GF+SISO\n");
Z
Zhu Yi 已提交
1594
			}
G
Guy Cohen 已提交
1595
			search_tbl->is_SGI = !tbl->is_SGI;
G
Guy Cohen 已提交
1596
			rs_set_expected_tpt_table(lq_sta, search_tbl);
G
Guy Cohen 已提交
1597 1598 1599 1600 1601
			if (tbl->is_SGI) {
				s32 tpt = lq_sta->last_tpt / 100;
				if (tpt >= search_tbl->expected_tpt[index])
					break;
			}
T
Tomas Winkler 已提交
1602 1603 1604
			search_tbl->current_rate =
				rate_n_flags_from_tbl(priv, search_tbl,
						      index, is_green);
1605
			update_search_tbl_counter = 1;
Z
Zhu Yi 已提交
1606
			goto out;
1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620
		case IWL_SISO_SWITCH_MIMO3_ABC:
			IWL_DEBUG_RATE(priv, "LQ: SISO switch to MIMO3\n");
			memcpy(search_tbl, tbl, sz);
			search_tbl->is_SGI = 0;
			search_tbl->ant_type = ANT_ABC;

			if (!rs_is_valid_ant(valid_tx_ant, search_tbl->ant_type))
				break;

			ret = rs_switch_to_mimo3(priv, lq_sta, conf, sta,
						 search_tbl, index);
			if (!ret)
				goto out;
			break;
Z
Zhu Yi 已提交
1621 1622
		}
		tbl->action++;
1623
		if (tbl->action > IWL_LEGACY_SWITCH_MIMO3_ABC)
1624
			tbl->action = IWL_SISO_SWITCH_ANTENNA1;
Z
Zhu Yi 已提交
1625 1626 1627 1628

		if (tbl->action == start_action)
			break;
	}
1629
	search_tbl->lq_type = LQ_NONE;
Z
Zhu Yi 已提交
1630 1631 1632
	return 0;

 out:
1633
	lq_sta->search_better_tbl = 1;
Z
Zhu Yi 已提交
1634
	tbl->action++;
1635
	if (tbl->action > IWL_SISO_SWITCH_MIMO3_ABC)
1636
		tbl->action = IWL_SISO_SWITCH_ANTENNA1;
1637 1638 1639
	if (update_search_tbl_counter)
		search_tbl->action = tbl->action;

Z
Zhu Yi 已提交
1640 1641 1642
	return 0;
}

1643
/*
1644
 * Try to switch to new modulation mode from MIMO2
1645
 */
1646
static int rs_move_mimo2_to_other(struct iwl_priv *priv,
1647
				 struct iwl_lq_sta *lq_sta,
1648
				 struct ieee80211_conf *conf,
1649
				 struct ieee80211_sta *sta, int index)
Z
Zhu Yi 已提交
1650
{
1651
	s8 is_green = lq_sta->is_green;
1652 1653 1654
	struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
	struct iwl_scale_tbl_info *search_tbl =
				&(lq_sta->lq_info[(1 - lq_sta->active_tbl)]);
1655
	struct iwl_rate_scale_data *window = &(tbl->win[index]);
1656 1657
	u32 sz = (sizeof(struct iwl_scale_tbl_info) -
		  (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
Z
Zhu Yi 已提交
1658
	u8 start_action = tbl->action;
1659 1660
	u8 valid_tx_ant = priv->hw_params.valid_tx_ant;
	u8 tx_chains_num = priv->hw_params.tx_chains_num;
1661
	u8 update_search_tbl_counter = 0;
1662
	int ret;
Z
Zhu Yi 已提交
1663 1664

	for (;;) {
1665
		lq_sta->action_counter++;
Z
Zhu Yi 已提交
1666
		switch (tbl->action) {
1667 1668
		case IWL_MIMO2_SWITCH_ANTENNA1:
		case IWL_MIMO2_SWITCH_ANTENNA2:
1669
			IWL_DEBUG_RATE(priv, "LQ: MIMO2 toggle Antennas\n");
1670 1671 1672 1673 1674 1675 1676 1677 1678

			if (tx_chains_num <= 2)
				break;

			if (window->success_ratio >= IWL_RS_GOOD_RATIO)
				break;

			memcpy(search_tbl, tbl, sz);
			if (rs_toggle_antenna(valid_tx_ant,
1679 1680
				       &search_tbl->current_rate, search_tbl)) {
				update_search_tbl_counter = 1;
1681
				goto out;
1682
			}
1683 1684 1685 1686
			break;
		case IWL_MIMO2_SWITCH_SISO_A:
		case IWL_MIMO2_SWITCH_SISO_B:
		case IWL_MIMO2_SWITCH_SISO_C:
1687
			IWL_DEBUG_RATE(priv, "LQ: MIMO2 switch to SISO\n");
1688

1689
			/* Set up new search table for SISO */
Z
Zhu Yi 已提交
1690
			memcpy(search_tbl, tbl, sz);
G
Guy Cohen 已提交
1691

1692
			if (tbl->action == IWL_MIMO2_SWITCH_SISO_A)
G
Guy Cohen 已提交
1693
				search_tbl->ant_type = ANT_A;
1694
			else if (tbl->action == IWL_MIMO2_SWITCH_SISO_B)
G
Guy Cohen 已提交
1695
				search_tbl->ant_type = ANT_B;
1696 1697 1698 1699 1700
			else
				search_tbl->ant_type = ANT_C;

			if (!rs_is_valid_ant(valid_tx_ant, search_tbl->ant_type))
				break;
Z
Zhu Yi 已提交
1701

1702
			ret = rs_switch_to_siso(priv, lq_sta, conf, sta,
1703
						 search_tbl, index);
1704
			if (!ret)
Z
Zhu Yi 已提交
1705
				goto out;
1706

Z
Zhu Yi 已提交
1707 1708
			break;

1709
		case IWL_MIMO2_SWITCH_GI:
1710 1711 1712 1713 1714 1715 1716 1717 1718
			if (!tbl->is_fat &&
				!(priv->current_ht_config.sgf &
						HT_SHORT_GI_20MHZ))
				break;
			if (tbl->is_fat &&
				!(priv->current_ht_config.sgf &
						HT_SHORT_GI_40MHZ))
				break;

1719
			IWL_DEBUG_RATE(priv, "LQ: MIMO2 toggle SGI/NGI\n");
1720

1721
			/* Set up new search table for MIMO2 */
Z
Zhu Yi 已提交
1722
			memcpy(search_tbl, tbl, sz);
G
Guy Cohen 已提交
1723
			search_tbl->is_SGI = !tbl->is_SGI;
G
Guy Cohen 已提交
1724
			rs_set_expected_tpt_table(lq_sta, search_tbl);
1725 1726 1727 1728 1729 1730
			/*
			 * If active table already uses the fastest possible
			 * modulation (dual stream with short guard interval),
			 * and it's working well, there's no need to look
			 * for a better type of modulation!
			 */
G
Guy Cohen 已提交
1731
			if (tbl->is_SGI) {
1732
				s32 tpt = lq_sta->last_tpt / 100;
G
Guy Cohen 已提交
1733 1734
				if (tpt >= search_tbl->expected_tpt[index])
					break;
Z
Zhu Yi 已提交
1735
			}
T
Tomas Winkler 已提交
1736 1737 1738
			search_tbl->current_rate =
				rate_n_flags_from_tbl(priv, search_tbl,
						      index, is_green);
1739
			update_search_tbl_counter = 1;
Z
Zhu Yi 已提交
1740 1741
			goto out;

1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756
		case IWL_MIMO2_SWITCH_MIMO3_ABC:
			IWL_DEBUG_RATE(priv, "LQ: MIMO2 switch to MIMO3\n");
			memcpy(search_tbl, tbl, sz);
			search_tbl->is_SGI = 0;
			search_tbl->ant_type = ANT_ABC;

			if (!rs_is_valid_ant(valid_tx_ant, search_tbl->ant_type))
				break;

			ret = rs_switch_to_mimo3(priv, lq_sta, conf, sta,
						 search_tbl, index);
			if (!ret)
				goto out;

			break;
Z
Zhu Yi 已提交
1757 1758
		}
		tbl->action++;
1759
		if (tbl->action > IWL_MIMO2_SWITCH_MIMO3_ABC)
1760
			tbl->action = IWL_MIMO2_SWITCH_ANTENNA1;
Z
Zhu Yi 已提交
1761 1762 1763 1764

		if (tbl->action == start_action)
			break;
	}
1765
	search_tbl->lq_type = LQ_NONE;
Z
Zhu Yi 已提交
1766 1767
	return 0;
 out:
1768
	lq_sta->search_better_tbl = 1;
Z
Zhu Yi 已提交
1769
	tbl->action++;
1770
	if (tbl->action > IWL_MIMO2_SWITCH_MIMO3_ABC)
1771
		tbl->action = IWL_MIMO2_SWITCH_ANTENNA1;
1772 1773 1774
	if (update_search_tbl_counter)
		search_tbl->action = tbl->action;

Z
Zhu Yi 已提交
1775 1776 1777 1778
	return 0;

}

1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797
/*
 * Try to switch to new modulation mode from MIMO3
 */
static int 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)
{
	s8 is_green = lq_sta->is_green;
	struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
	struct iwl_scale_tbl_info *search_tbl =
				&(lq_sta->lq_info[(1 - lq_sta->active_tbl)]);
	struct iwl_rate_scale_data *window = &(tbl->win[index]);
	u32 sz = (sizeof(struct iwl_scale_tbl_info) -
		  (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
	u8 start_action = tbl->action;
	u8 valid_tx_ant = priv->hw_params.valid_tx_ant;
	u8 tx_chains_num = priv->hw_params.tx_chains_num;
	int ret;
1798
	u8 update_search_tbl_counter = 0;
1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896

	for (;;) {
		lq_sta->action_counter++;
		switch (tbl->action) {
		case IWL_MIMO3_SWITCH_ANTENNA1:
		case IWL_MIMO3_SWITCH_ANTENNA2:
			IWL_DEBUG_RATE(priv, "LQ: MIMO3 toggle Antennas\n");

			if (tx_chains_num <= 3)
				break;

			if (window->success_ratio >= IWL_RS_GOOD_RATIO)
				break;

			memcpy(search_tbl, tbl, sz);
			if (rs_toggle_antenna(valid_tx_ant,
				       &search_tbl->current_rate, search_tbl))
				goto out;
			break;
		case IWL_MIMO3_SWITCH_SISO_A:
		case IWL_MIMO3_SWITCH_SISO_B:
		case IWL_MIMO3_SWITCH_SISO_C:
			IWL_DEBUG_RATE(priv, "LQ: MIMO3 switch to SISO\n");

			/* Set up new search table for SISO */
			memcpy(search_tbl, tbl, sz);

			if (tbl->action == IWL_MIMO3_SWITCH_SISO_A)
				search_tbl->ant_type = ANT_A;
			else if (tbl->action == IWL_MIMO3_SWITCH_SISO_B)
				search_tbl->ant_type = ANT_B;
			else
				search_tbl->ant_type = ANT_C;

			if (!rs_is_valid_ant(valid_tx_ant, search_tbl->ant_type))
				break;

			ret = rs_switch_to_siso(priv, lq_sta, conf, sta,
						 search_tbl, index);
			if (!ret)
				goto out;

			break;

		case IWL_MIMO3_SWITCH_MIMO2_AB:
		case IWL_MIMO3_SWITCH_MIMO2_AC:
		case IWL_MIMO3_SWITCH_MIMO2_BC:
			IWL_DEBUG_RATE(priv, "LQ: MIMO3 switch to MIMO2\n");

			memcpy(search_tbl, tbl, sz);
			search_tbl->is_SGI = 0;
			if (tbl->action == IWL_MIMO3_SWITCH_MIMO2_AB)
				search_tbl->ant_type = ANT_AB;
			else if (tbl->action == IWL_MIMO3_SWITCH_MIMO2_AC)
				search_tbl->ant_type = ANT_AC;
			else
				search_tbl->ant_type = ANT_BC;

			if (!rs_is_valid_ant(valid_tx_ant, search_tbl->ant_type))
				break;

			ret = rs_switch_to_mimo2(priv, lq_sta, conf, sta,
						 search_tbl, index);
			if (!ret)
				goto out;

			break;

		case IWL_MIMO3_SWITCH_GI:
			if (!tbl->is_fat &&
				!(priv->current_ht_config.sgf &
						HT_SHORT_GI_20MHZ))
				break;
			if (tbl->is_fat &&
				!(priv->current_ht_config.sgf &
						HT_SHORT_GI_40MHZ))
				break;

			IWL_DEBUG_RATE(priv, "LQ: MIMO3 toggle SGI/NGI\n");

			/* Set up new search table for MIMO */
			memcpy(search_tbl, tbl, sz);
			search_tbl->is_SGI = !tbl->is_SGI;
			rs_set_expected_tpt_table(lq_sta, search_tbl);
			/*
			 * If active table already uses the fastest possible
			 * modulation (dual stream with short guard interval),
			 * and it's working well, there's no need to look
			 * for a better type of modulation!
			 */
			if (tbl->is_SGI) {
				s32 tpt = lq_sta->last_tpt / 100;
				if (tpt >= search_tbl->expected_tpt[index])
					break;
			}
			search_tbl->current_rate =
				rate_n_flags_from_tbl(priv, search_tbl,
						      index, is_green);
1897
			update_search_tbl_counter = 1;
1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913
			goto out;
		}
		tbl->action++;
		if (tbl->action > IWL_MIMO3_SWITCH_GI)
			tbl->action = IWL_MIMO3_SWITCH_ANTENNA1;

		if (tbl->action == start_action)
			break;
	}
	search_tbl->lq_type = LQ_NONE;
	return 0;
 out:
	lq_sta->search_better_tbl = 1;
	tbl->action++;
	if (tbl->action > IWL_MIMO3_SWITCH_GI)
		tbl->action = IWL_MIMO3_SWITCH_ANTENNA1;
1914 1915 1916
	if (update_search_tbl_counter)
		search_tbl->action = tbl->action;

1917 1918 1919 1920
	return 0;

}

1921 1922 1923 1924 1925 1926 1927
/*
 * 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)
 */
1928
static void rs_stay_in_table(struct iwl_lq_sta *lq_sta)
Z
Zhu Yi 已提交
1929
{
1930
	struct iwl_scale_tbl_info *tbl;
Z
Zhu Yi 已提交
1931 1932 1933
	int i;
	int active_tbl;
	int flush_interval_passed = 0;
1934
	struct iwl_priv *priv;
Z
Zhu Yi 已提交
1935

1936
	priv = lq_sta->drv;
1937
	active_tbl = lq_sta->active_tbl;
Z
Zhu Yi 已提交
1938

1939
	tbl = &(lq_sta->lq_info[active_tbl]);
Z
Zhu Yi 已提交
1940

1941
	/* If we've been disallowing search, see if we should now allow it */
1942
	if (lq_sta->stay_in_tbl) {
Z
Zhu Yi 已提交
1943

1944
		/* Elapsed time using current modulation mode */
1945
		if (lq_sta->flush_timer)
Z
Zhu Yi 已提交
1946
			flush_interval_passed =
1947 1948
			time_after(jiffies,
					(unsigned long)(lq_sta->flush_timer +
Z
Zhu Yi 已提交
1949 1950
					IWL_RATE_SCALE_FLUSH_INTVL));

1951 1952 1953 1954 1955 1956 1957 1958
		/*
		 * Check if we should allow search for new modulation mode.
		 * If many frames have failed or succeeded, or we've used
		 * this same modulation for a long time, allow search, and
		 * reset history stats that keep track of whether we should
		 * allow a new search.  Also (below) reset all bitmaps and
		 * stats in active history.
		 */
1959 1960 1961
		if ((lq_sta->total_failed > lq_sta->max_failure_limit) ||
		    (lq_sta->total_success > lq_sta->max_success_limit) ||
		    ((!lq_sta->search_better_tbl) && (lq_sta->flush_timer)
Z
Zhu Yi 已提交
1962
		     && (flush_interval_passed))) {
1963
			IWL_DEBUG_RATE(priv, "LQ: stay is expired %d %d %d\n:",
1964 1965
				     lq_sta->total_failed,
				     lq_sta->total_success,
Z
Zhu Yi 已提交
1966
				     flush_interval_passed);
1967 1968

			/* Allow search for new mode */
1969 1970 1971 1972
			lq_sta->stay_in_tbl = 0;	/* only place reset */
			lq_sta->total_failed = 0;
			lq_sta->total_success = 0;
			lq_sta->flush_timer = 0;
1973 1974 1975 1976 1977 1978 1979

		/*
		 * Else if we've used this modulation mode enough repetitions
		 * (regardless of elapsed time or success/failure), reset
		 * history bitmaps and rate-specific stats for all rates in
		 * active table.
		 */
1980
		} else {
1981 1982 1983 1984
			lq_sta->table_count++;
			if (lq_sta->table_count >=
			    lq_sta->table_count_limit) {
				lq_sta->table_count = 0;
Z
Zhu Yi 已提交
1985

1986
				IWL_DEBUG_RATE(priv, "LQ: stay in table clear win\n");
Z
Zhu Yi 已提交
1987 1988 1989 1990 1991 1992
				for (i = 0; i < IWL_RATE_COUNT; i++)
					rs_rate_scale_clear_window(
						&(tbl->win[i]));
			}
		}

1993 1994 1995
		/* If transitioning to allow "search", reset all history
		 * bitmaps and stats in active table (this will become the new
		 * "search" table). */
1996
		if (!lq_sta->stay_in_tbl) {
Z
Zhu Yi 已提交
1997 1998 1999 2000 2001 2002
			for (i = 0; i < IWL_RATE_COUNT; i++)
				rs_rate_scale_clear_window(&(tbl->win[i]));
		}
	}
}

2003 2004 2005
/*
 * Do rate scaling and search for new modulation mode.
 */
2006
static void rs_rate_scale_perform(struct iwl_priv *priv,
2007
				  struct sk_buff *skb,
2008 2009
				  struct ieee80211_sta *sta,
				  struct iwl_lq_sta *lq_sta)
Z
Zhu Yi 已提交
2010
{
2011
	struct ieee80211_hw *hw = priv->hw;
2012
	struct ieee80211_conf *conf = &hw->conf;
2013 2014
	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
Z
Zhu Yi 已提交
2015 2016 2017 2018
	int low = IWL_RATE_INVALID;
	int high = IWL_RATE_INVALID;
	int index;
	int i;
2019
	struct iwl_rate_scale_data *window = NULL;
Z
Zhu Yi 已提交
2020 2021 2022 2023 2024
	int current_tpt = IWL_INVALID_VALUE;
	int low_tpt = IWL_INVALID_VALUE;
	int high_tpt = IWL_INVALID_VALUE;
	u32 fail_count;
	s8 scale_action = 0;
2025
	u16 rate_mask;
Z
Zhu Yi 已提交
2026
	u8 update_lq = 0;
2027
	struct iwl_scale_tbl_info *tbl, *tbl1;
Z
Zhu Yi 已提交
2028
	u16 rate_scale_index_msk = 0;
G
Guy Cohen 已提交
2029
	u32 rate;
Z
Zhu Yi 已提交
2030 2031 2032 2033
	u8 is_green = 0;
	u8 active_tbl = 0;
	u8 done_search = 0;
	u16 high_low;
G
Guy Cohen 已提交
2034
	s32 sr;
2035
	u8 tid = MAX_TID_COUNT;
2036
	struct iwl_tid_data *tid_data;
Z
Zhu Yi 已提交
2037

2038
	IWL_DEBUG_RATE(priv, "rate scale calculate new rate for skb\n");
Z
Zhu Yi 已提交
2039

2040
	/* Send management frames and NO_ACK data using lowest rate. */
2041 2042
	/* TODO: this could probably be improved.. */
	if (!ieee80211_is_data(hdr->frame_control) ||
2043
	    info->flags & IEEE80211_TX_CTL_NO_ACK)
Z
Zhu Yi 已提交
2044 2045
		return;

2046
	if (!sta || !lq_sta)
Z
Zhu Yi 已提交
2047 2048
		return;

2049
	lq_sta->supp_rates = sta->supp_rates[lq_sta->band];
Z
Zhu Yi 已提交
2050

2051 2052
	tid = rs_tl_add_packet(lq_sta, hdr);

2053 2054 2055 2056 2057
	/*
	 * Select rate-scale / modulation-mode table to work with in
	 * the rest of this function:  "search" if searching for better
	 * modulation mode, or "active" if doing rate scaling within a mode.
	 */
2058 2059
	if (!lq_sta->search_better_tbl)
		active_tbl = lq_sta->active_tbl;
Z
Zhu Yi 已提交
2060
	else
2061
		active_tbl = 1 - lq_sta->active_tbl;
Z
Zhu Yi 已提交
2062

2063
	tbl = &(lq_sta->lq_info[active_tbl]);
2064 2065 2066 2067
	if (is_legacy(tbl->lq_type))
		lq_sta->is_green = 0;
	else
		lq_sta->is_green = rs_use_green(priv, conf);
2068
	is_green = lq_sta->is_green;
Z
Zhu Yi 已提交
2069

2070
	/* current tx rate */
2071
	index = lq_sta->last_txrate_idx;
Z
Zhu Yi 已提交
2072

2073
	IWL_DEBUG_RATE(priv, "Rate scale index %d for type %d\n", index,
Z
Zhu Yi 已提交
2074 2075
		       tbl->lq_type);

2076
	/* rates available for this association, and for modulation mode */
G
Guy Cohen 已提交
2077
	rate_mask = rs_get_supported_rates(lq_sta, hdr, tbl->lq_type);
Z
Zhu Yi 已提交
2078

2079
	IWL_DEBUG_RATE(priv, "mask 0x%04X \n", rate_mask);
Z
Zhu Yi 已提交
2080 2081 2082

	/* mask with station rate restriction */
	if (is_legacy(tbl->lq_type)) {
2083
		if (lq_sta->band == IEEE80211_BAND_5GHZ)
2084
			/* supp_rates has no CCK bits in A mode */
Z
Zhu Yi 已提交
2085
			rate_scale_index_msk = (u16) (rate_mask &
2086
				(lq_sta->supp_rates << IWL_FIRST_OFDM_RATE));
Z
Zhu Yi 已提交
2087 2088
		else
			rate_scale_index_msk = (u16) (rate_mask &
2089
						      lq_sta->supp_rates);
Z
Zhu Yi 已提交
2090 2091 2092 2093 2094 2095 2096

	} else
		rate_scale_index_msk = rate_mask;

	if (!rate_scale_index_msk)
		rate_scale_index_msk = rate_mask;

G
Guy Cohen 已提交
2097
	if (!((1 << index) & rate_scale_index_msk)) {
2098
		IWL_ERR(priv, "Current Rate is not valid\n");
G
Guy Cohen 已提交
2099
		return;
Z
Zhu Yi 已提交
2100 2101
	}

2102
	/* Get expected throughput table and history window for current rate */
G
Guy Cohen 已提交
2103
	if (!tbl->expected_tpt) {
2104
		IWL_ERR(priv, "tbl->expected_tpt is NULL\n");
G
Guy Cohen 已提交
2105 2106
		return;
	}
Z
Zhu Yi 已提交
2107

2108 2109 2110 2111 2112 2113 2114 2115 2116
	/* force user max rate if set by user */
	if ((lq_sta->max_rate_idx != -1) &&
	    (lq_sta->max_rate_idx < index)) {
		index = lq_sta->max_rate_idx;
		update_lq = 1;
		window = &(tbl->win[index]);
		goto lq_update;
	}

Z
Zhu Yi 已提交
2117 2118
	window = &(tbl->win[index]);

2119 2120 2121 2122 2123 2124 2125
	/*
	 * If there is not enough history to calculate actual average
	 * throughput, keep analyzing results of more tx frames, without
	 * changing rate or mode (bypass most of the rest of this function).
	 * Set up new rate table in uCode only if old rate is not supported
	 * in current association (use new rate found above).
	 */
Z
Zhu Yi 已提交
2126
	fail_count = window->counter - window->success_counter;
G
Guy Cohen 已提交
2127 2128
	if ((fail_count < IWL_RATE_MIN_FAILURE_TH) &&
			(window->success_counter < IWL_RATE_MIN_SUCCESS_TH)) {
2129
		IWL_DEBUG_RATE(priv, "LQ: still below TH. succ=%d total=%d "
Z
Zhu Yi 已提交
2130 2131
			       "for index %d\n",
			       window->success_counter, window->counter, index);
2132 2133

		/* Can't calculate this yet; not enough history */
Z
Zhu Yi 已提交
2134
		window->average_tpt = IWL_INVALID_VALUE;
2135 2136 2137

		/* Should we stay with this modulation mode,
		 * or search for a new one? */
2138
		rs_stay_in_table(lq_sta);
2139

Z
Zhu Yi 已提交
2140
		goto out;
2141
	}
Z
Zhu Yi 已提交
2142

2143 2144
	/* Else we have enough samples; calculate estimate of
	 * actual average throughput */
2145 2146 2147

	BUG_ON(window->average_tpt != ((window->success_ratio *
			tbl->expected_tpt[index] + 64) / 128));
Z
Zhu Yi 已提交
2148

2149
	/* If we are searching for better modulation mode, check success. */
2150
	if (lq_sta->search_better_tbl) {
Z
Zhu Yi 已提交
2151

2152 2153 2154
		/* If good success, continue using the "search" mode;
		 * no need to send new link quality command, since we're
		 * continuing to use the setup that we've been trying. */
G
Guy Cohen 已提交
2155 2156
		if (window->average_tpt > lq_sta->last_tpt) {

2157
			IWL_DEBUG_RATE(priv, "LQ: SWITCHING TO NEW TABLE "
G
Guy Cohen 已提交
2158 2159 2160 2161 2162 2163
					"suc=%d cur-tpt=%d old-tpt=%d\n",
					window->success_ratio,
					window->average_tpt,
					lq_sta->last_tpt);

			if (!is_legacy(tbl->lq_type))
2164
				lq_sta->enable_counter = 1;
G
Guy Cohen 已提交
2165

2166
			/* Swap tables; "search" becomes "active" */
2167
			lq_sta->active_tbl = active_tbl;
Z
Zhu Yi 已提交
2168
			current_tpt = window->average_tpt;
2169 2170

		/* Else poor success; go back to mode in "active" table */
Z
Zhu Yi 已提交
2171
		} else {
G
Guy Cohen 已提交
2172

2173
			IWL_DEBUG_RATE(priv, "LQ: GOING BACK TO THE OLD TABLE "
G
Guy Cohen 已提交
2174 2175 2176 2177 2178
					"suc=%d cur-tpt=%d old-tpt=%d\n",
					window->success_ratio,
					window->average_tpt,
					lq_sta->last_tpt);

2179
			/* Nullify "search" table */
Z
Zhu Yi 已提交
2180
			tbl->lq_type = LQ_NONE;
2181 2182

			/* Revert to "active" table */
2183 2184
			active_tbl = lq_sta->active_tbl;
			tbl = &(lq_sta->lq_info[active_tbl]);
Z
Zhu Yi 已提交
2185

2186
			/* Revert to "active" rate and throughput info */
2187
			index = iwl_hwrate_to_plcp_idx(tbl->current_rate);
2188
			current_tpt = lq_sta->last_tpt;
Z
Zhu Yi 已提交
2189

2190
			/* Need to set up a new rate table in uCode */
Z
Zhu Yi 已提交
2191 2192
			update_lq = 1;
		}
2193 2194 2195

		/* Either way, we've made a decision; modulation mode
		 * search is done, allow rate adjustment next time. */
2196
		lq_sta->search_better_tbl = 0;
2197
		done_search = 1;	/* Don't switch modes below! */
Z
Zhu Yi 已提交
2198 2199 2200
		goto lq_update;
	}

2201 2202
	/* (Else) not in search of better modulation mode, try for better
	 * starting rate, while staying in this mode. */
2203
	high_low = rs_get_adjacent_rate(priv, index, rate_scale_index_msk,
Z
Zhu Yi 已提交
2204 2205 2206 2207
					tbl->lq_type);
	low = high_low & 0xff;
	high = (high_low >> 8) & 0xff;

2208 2209 2210 2211 2212
	/* If user set max rate, dont allow higher than user constrain */
	if ((lq_sta->max_rate_idx != -1) &&
	    (lq_sta->max_rate_idx < high))
		high = IWL_RATE_INVALID;

G
Guy Cohen 已提交
2213 2214
	sr = window->success_ratio;

2215
	/* Collect measured throughputs for current and adjacent rates */
Z
Zhu Yi 已提交
2216 2217 2218 2219 2220 2221
	current_tpt = window->average_tpt;
	if (low != IWL_RATE_INVALID)
		low_tpt = tbl->win[low].average_tpt;
	if (high != IWL_RATE_INVALID)
		high_tpt = tbl->win[high].average_tpt;

G
Guy Cohen 已提交
2222
	scale_action = 0;
Z
Zhu Yi 已提交
2223

2224
	/* Too many failures, decrease rate */
G
Guy Cohen 已提交
2225
	if ((sr <= IWL_RATE_DECREASE_TH) || (current_tpt == 0)) {
2226
		IWL_DEBUG_RATE(priv, "decrease rate because of low success_ratio\n");
Z
Zhu Yi 已提交
2227
		scale_action = -1;
2228 2229

	/* No throughput measured yet for adjacent rates; try increase. */
Z
Zhu Yi 已提交
2230
	} else if ((low_tpt == IWL_INVALID_VALUE) &&
G
Guy Cohen 已提交
2231 2232 2233 2234 2235
		   (high_tpt == IWL_INVALID_VALUE)) {

		if (high != IWL_RATE_INVALID && sr >= IWL_RATE_INCREASE_TH)
			scale_action = 1;
		else if (low != IWL_RATE_INVALID)
2236
			scale_action = 0;
G
Guy Cohen 已提交
2237
	}
2238 2239 2240

	/* Both adjacent throughputs are measured, but neither one has better
	 * throughput; we're using the best rate, don't change it! */
Z
Zhu Yi 已提交
2241 2242 2243 2244 2245
	else if ((low_tpt != IWL_INVALID_VALUE) &&
		 (high_tpt != IWL_INVALID_VALUE) &&
		 (low_tpt < current_tpt) &&
		 (high_tpt < current_tpt))
		scale_action = 0;
2246 2247 2248

	/* At least one adjacent rate's throughput is measured,
	 * and may have better performance. */
Z
Zhu Yi 已提交
2249
	else {
2250
		/* Higher adjacent rate's throughput is measured */
Z
Zhu Yi 已提交
2251
		if (high_tpt != IWL_INVALID_VALUE) {
2252
			/* Higher rate has better throughput */
G
Guy Cohen 已提交
2253 2254
			if (high_tpt > current_tpt &&
					sr >= IWL_RATE_INCREASE_TH) {
Z
Zhu Yi 已提交
2255
				scale_action = 1;
G
Guy Cohen 已提交
2256
			} else {
2257
				scale_action = 0;
Z
Zhu Yi 已提交
2258
			}
2259 2260

		/* Lower adjacent rate's throughput is measured */
Z
Zhu Yi 已提交
2261
		} else if (low_tpt != IWL_INVALID_VALUE) {
2262
			/* Lower rate has better throughput */
Z
Zhu Yi 已提交
2263
			if (low_tpt > current_tpt) {
2264 2265
				IWL_DEBUG_RATE(priv,
				    "decrease rate because of low tpt\n");
Z
Zhu Yi 已提交
2266
				scale_action = -1;
G
Guy Cohen 已提交
2267
			} else if (sr >= IWL_RATE_INCREASE_TH) {
Z
Zhu Yi 已提交
2268
				scale_action = 1;
G
Guy Cohen 已提交
2269
			}
Z
Zhu Yi 已提交
2270 2271 2272
		}
	}

2273 2274
	/* Sanity check; asked for decrease, but success rate or throughput
	 * has been good at old rate.  Don't change it. */
G
Guy Cohen 已提交
2275 2276
	if ((scale_action == -1) && (low != IWL_RATE_INVALID) &&
		    ((sr > IWL_RATE_HIGH_TH) ||
Z
Zhu Yi 已提交
2277 2278 2279 2280 2281
		     (current_tpt > (100 * tbl->expected_tpt[low]))))
		scale_action = 0;

	switch (scale_action) {
	case -1:
2282
		/* Decrease starting rate, update uCode's rate table */
Z
Zhu Yi 已提交
2283 2284 2285 2286
		if (low != IWL_RATE_INVALID) {
			update_lq = 1;
			index = low;
		}
2287

Z
Zhu Yi 已提交
2288 2289
		break;
	case 1:
2290
		/* Increase starting rate, update uCode's rate table */
Z
Zhu Yi 已提交
2291 2292 2293 2294 2295 2296 2297
		if (high != IWL_RATE_INVALID) {
			update_lq = 1;
			index = high;
		}

		break;
	case 0:
2298
		/* No change */
Z
Zhu Yi 已提交
2299 2300 2301 2302
	default:
		break;
	}

2303
	IWL_DEBUG_RATE(priv, "choose rate scale index %d action %d low %d "
Z
Zhu Yi 已提交
2304 2305 2306
		    "high %d type %d\n",
		     index, scale_action, low, high, tbl->lq_type);

G
Guy Cohen 已提交
2307
lq_update:
2308
	/* Replace uCode's rate table for the destination station. */
Z
Zhu Yi 已提交
2309
	if (update_lq) {
T
Tomas Winkler 已提交
2310
		rate = rate_n_flags_from_tbl(priv, tbl, index, is_green);
G
Guy Cohen 已提交
2311
		rs_fill_link_cmd(priv, lq_sta, rate);
2312
		iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC);
Z
Zhu Yi 已提交
2313
	}
2314 2315

	/* Should we stay with this modulation mode, or search for a new one? */
2316
	rs_stay_in_table(lq_sta);
Z
Zhu Yi 已提交
2317

2318 2319 2320 2321 2322 2323
	/*
	 * Search for new modulation mode if we're:
	 * 1)  Not changing rates right now
	 * 2)  Not just finishing up a search
	 * 3)  Allowing a new search
	 */
2324
	if (!update_lq && !done_search && !lq_sta->stay_in_tbl && window->counter) {
2325
		/* Save current throughput to compare with "search" throughput*/
2326
		lq_sta->last_tpt = current_tpt;
Z
Zhu Yi 已提交
2327

2328 2329
		/* Select a new "search" modulation mode to try.
		 * If one is found, set up the new "search" table. */
Z
Zhu Yi 已提交
2330
		if (is_legacy(tbl->lq_type))
2331
			rs_move_legacy_other(priv, lq_sta, conf, sta, index);
Z
Zhu Yi 已提交
2332
		else if (is_siso(tbl->lq_type))
2333
			rs_move_siso_to_other(priv, lq_sta, conf, sta, index);
2334 2335
		else if (is_mimo2(tbl->lq_type))
			rs_move_mimo2_to_other(priv, lq_sta, conf, sta, index);
Z
Zhu Yi 已提交
2336
		else
2337
			rs_move_mimo3_to_other(priv, lq_sta, conf, sta, index);
Z
Zhu Yi 已提交
2338

2339
		/* If new "search" mode was selected, set up in uCode table */
2340
		if (lq_sta->search_better_tbl) {
2341
			/* Access the "search" table, clear its history. */
2342
			tbl = &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]);
Z
Zhu Yi 已提交
2343 2344 2345
			for (i = 0; i < IWL_RATE_COUNT; i++)
				rs_rate_scale_clear_window(&(tbl->win[i]));

2346
			/* Use new "search" start rate */
2347
			index = iwl_hwrate_to_plcp_idx(tbl->current_rate);
Z
Zhu Yi 已提交
2348

2349
			IWL_DEBUG_RATE(priv, "Switch current  mcs: %X index: %d\n",
G
Guy Cohen 已提交
2350
				     tbl->current_rate, index);
G
Guy Cohen 已提交
2351
			rs_fill_link_cmd(priv, lq_sta, tbl->current_rate);
2352
			iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC);
2353 2354 2355
		} else
			done_search = 1;
	}
Z
Zhu Yi 已提交
2356

2357
	if (done_search && !lq_sta->stay_in_tbl) {
2358 2359 2360 2361 2362
		/* If the "active" (non-search) mode was legacy,
		 * and we've tried switching antennas,
		 * but we haven't been able to try HT modes (not available),
		 * stay with best antenna legacy modulation for a while
		 * before next round of mode comparisons. */
2363
		tbl1 = &(lq_sta->lq_info[lq_sta->active_tbl]);
2364
		if (is_legacy(tbl1->lq_type) && !conf_is_ht(conf) &&
2365
		    lq_sta->action_counter > tbl1->max_search) {
2366
			IWL_DEBUG_RATE(priv, "LQ: STAY in legacy table\n");
2367
			rs_set_stay_in_table(priv, 1, lq_sta);
Z
Zhu Yi 已提交
2368 2369
		}

2370 2371 2372
		/* If we're in an HT mode, and all 3 mode switch actions
		 * have been tried and compared, stay in this best modulation
		 * mode for a while before next round of mode comparisons. */
2373
		if (lq_sta->enable_counter &&
2374
		    (lq_sta->action_counter >= tbl1->max_search)) {
2375 2376 2377
			if ((lq_sta->last_tpt > IWL_AGG_TPT_THREHOLD) &&
			    (lq_sta->tx_agg_tid_en & (1 << tid)) &&
			    (tid != MAX_TID_COUNT)) {
2378 2379 2380 2381 2382 2383 2384 2385 2386
				tid_data =
				   &priv->stations[lq_sta->lq.sta_id].tid[tid];
				if (tid_data->agg.state == IWL_AGG_OFF) {
					IWL_DEBUG_RATE(priv,
						       "try to aggregate tid %d\n",
						       tid);
					rs_tl_turn_on_agg(priv, tid,
							  lq_sta, sta);
				}
Z
Zhu Yi 已提交
2387
			}
2388
			rs_set_stay_in_table(priv, 0, lq_sta);
Z
Zhu Yi 已提交
2389 2390 2391 2392
		}
	}

out:
T
Tomas Winkler 已提交
2393
	tbl->current_rate = rate_n_flags_from_tbl(priv, tbl, index, is_green);
Z
Zhu Yi 已提交
2394
	i = index;
2395
	lq_sta->last_txrate_idx = i;
Z
Zhu Yi 已提交
2396 2397 2398 2399 2400

	return;
}


2401
static void rs_initialize_lq(struct iwl_priv *priv,
2402
			     struct ieee80211_conf *conf,
2403 2404
			     struct ieee80211_sta *sta,
			     struct iwl_lq_sta *lq_sta)
Z
Zhu Yi 已提交
2405
{
2406
	struct iwl_scale_tbl_info *tbl;
Z
Zhu Yi 已提交
2407
	int rate_idx;
2408
	int i;
G
Guy Cohen 已提交
2409
	u32 rate;
2410 2411 2412
	u8 use_green = rs_use_green(priv, conf);
	u8 active_tbl = 0;
	u8 valid_tx_ant;
Z
Zhu Yi 已提交
2413

2414
	if (!sta || !lq_sta)
Z
Zhu Yi 已提交
2415 2416
		goto out;

2417
	i = lq_sta->last_txrate_idx;
Z
Zhu Yi 已提交
2418

2419
	if ((lq_sta->lq.sta_id == 0xff) &&
2420
	    (priv->iw_mode == NL80211_IFTYPE_ADHOC))
Z
Zhu Yi 已提交
2421 2422
		goto out;

2423 2424
	valid_tx_ant = priv->hw_params.valid_tx_ant;

2425 2426
	if (!lq_sta->search_better_tbl)
		active_tbl = lq_sta->active_tbl;
Z
Zhu Yi 已提交
2427
	else
2428
		active_tbl = 1 - lq_sta->active_tbl;
Z
Zhu Yi 已提交
2429

2430
	tbl = &(lq_sta->lq_info[active_tbl]);
Z
Zhu Yi 已提交
2431 2432 2433 2434

	if ((i < 0) || (i >= IWL_RATE_COUNT))
		i = 0;

2435
	rate = iwl_rates[i].plcp;
2436 2437
	tbl->ant_type = first_antenna(valid_tx_ant);
	rate |= tbl->ant_type << RATE_MCS_ANT_POS;
Z
Zhu Yi 已提交
2438 2439

	if (i >= IWL_FIRST_CCK_RATE && i <= IWL_LAST_CCK_RATE)
G
Guy Cohen 已提交
2440
		rate |= RATE_MCS_CCK_MSK;
Z
Zhu Yi 已提交
2441

G
Guy Cohen 已提交
2442
	rs_get_tbl_info_from_mcs(rate, priv->band, tbl, &rate_idx);
2443 2444
	if (!rs_is_valid_ant(valid_tx_ant, tbl->ant_type))
	    rs_toggle_antenna(valid_tx_ant, &rate, tbl);
Z
Zhu Yi 已提交
2445

T
Tomas Winkler 已提交
2446
	rate = rate_n_flags_from_tbl(priv, tbl, rate_idx, use_green);
G
Guy Cohen 已提交
2447
	tbl->current_rate = rate;
G
Guy Cohen 已提交
2448
	rs_set_expected_tpt_table(lq_sta, tbl);
G
Guy Cohen 已提交
2449
	rs_fill_link_cmd(NULL, lq_sta, rate);
2450
	iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC);
Z
Zhu Yi 已提交
2451 2452 2453 2454
 out:
	return;
}

2455 2456
static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta,
			struct ieee80211_tx_rate_control *txrc)
Z
Zhu Yi 已提交
2457 2458
{

2459 2460
	struct sk_buff *skb = txrc->skb;
	struct ieee80211_supported_band *sband = txrc->sband;
2461 2462
	struct iwl_priv *priv = (struct iwl_priv *)priv_r;
	struct ieee80211_conf *conf = &priv->hw->conf;
Z
Zhu Yi 已提交
2463
	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
2464
	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
2465 2466
	struct iwl_lq_sta *lq_sta = priv_sta;
	int rate_idx;
2467
	u64 mask_bit = 0;
Z
Zhu Yi 已提交
2468

2469
	IWL_DEBUG_RATE_LIMIT(priv, "rate scale calculate new rate for skb\n");
Z
Zhu Yi 已提交
2470

2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481
	/* Get max rate if user set max rate */
	if (lq_sta) {
		lq_sta->max_rate_idx = txrc->max_rate_idx;
		if ((sband->band == IEEE80211_BAND_5GHZ) &&
		    (lq_sta->max_rate_idx != -1))
			lq_sta->max_rate_idx += IWL_FIRST_OFDM_RATE;
		if ((lq_sta->max_rate_idx < 0) ||
		    (lq_sta->max_rate_idx >= IWL_RATE_COUNT))
			lq_sta->max_rate_idx = -1;
	}

2482 2483 2484
	if (sta)
		mask_bit = sta->supp_rates[sband->band];

2485
	/* Send management frames and NO_ACK data using lowest rate. */
2486
	if (!ieee80211_is_data(hdr->frame_control) ||
2487
	    info->flags & IEEE80211_TX_CTL_NO_ACK || !sta || !lq_sta) {
2488 2489 2490 2491 2492 2493
		if (!mask_bit)
			info->control.rates[0].idx =
					rate_lowest_index(sband, NULL);
		else
			info->control.rates[0].idx =
					rate_lowest_index(sband, sta);
2494 2495
		if (info->flags & IEEE80211_TX_CTL_NO_ACK)
			info->control.rates[0].count = 1;
2496
		return;
Z
Zhu Yi 已提交
2497 2498
	}

2499
	rate_idx  = lq_sta->last_txrate_idx;
Z
Zhu Yi 已提交
2500

2501
	if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) &&
2502
	    !lq_sta->ibss_sta_added) {
2503 2504
		u8 sta_id = priv->cfg->ops->smgmt->find_station(priv,
						   hdr->addr1);
Z
Zhu Yi 已提交
2505 2506

		if (sta_id == IWL_INVALID_STATION) {
2507
			IWL_DEBUG_RATE(priv, "LQ: ADD station %pM\n",
J
Johannes Berg 已提交
2508
				       hdr->addr1);
2509
			sta_id = priv->cfg->ops->smgmt->add_station(priv,
2510 2511
						hdr->addr1, 0,
						CMD_ASYNC, NULL);
Z
Zhu Yi 已提交
2512 2513
		}
		if ((sta_id != IWL_INVALID_STATION)) {
2514 2515 2516
			lq_sta->lq.sta_id = sta_id;
			lq_sta->lq.rs_table[0].rate_n_flags = 0;
			lq_sta->ibss_sta_added = 1;
2517
			rs_initialize_lq(priv, conf, sta, lq_sta);
Z
Zhu Yi 已提交
2518 2519 2520
		}
	}

2521 2522 2523 2524
	if (rate_idx < 0 || rate_idx > IWL_RATE_COUNT)
		rate_idx = rate_lowest_index(sband, sta);
	else if (sband->band == IEEE80211_BAND_5GHZ)
		rate_idx -= IWL_FIRST_OFDM_RATE;
Z
Zhu Yi 已提交
2525

2526
	info->control.rates[0].idx = rate_idx;
Z
Zhu Yi 已提交
2527 2528
}

2529 2530
static void *rs_alloc_sta(void *priv_rate, struct ieee80211_sta *sta,
			  gfp_t gfp)
Z
Zhu Yi 已提交
2531
{
2532
	struct iwl_lq_sta *lq_sta;
2533
	struct iwl_priv *priv;
Z
Zhu Yi 已提交
2534 2535
	int i, j;

2536
	priv = (struct iwl_priv *)priv_rate;
2537
	IWL_DEBUG_RATE(priv, "create station rate scale window\n");
Z
Zhu Yi 已提交
2538

2539
	lq_sta = kzalloc(sizeof(struct iwl_lq_sta), gfp);
Z
Zhu Yi 已提交
2540

2541
	if (lq_sta == NULL)
Z
Zhu Yi 已提交
2542
		return NULL;
2543
	lq_sta->lq.sta_id = 0xff;
Z
Zhu Yi 已提交
2544

2545

Z
Zhu Yi 已提交
2546 2547
	for (j = 0; j < LQ_SIZE; j++)
		for (i = 0; i < IWL_RATE_COUNT; i++)
2548
			rs_rate_scale_clear_window(&lq_sta->lq_info[j].win[i]);
Z
Zhu Yi 已提交
2549

2550
	return lq_sta;
Z
Zhu Yi 已提交
2551 2552
}

2553 2554
static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband,
			 struct ieee80211_sta *sta, void *priv_sta)
Z
Zhu Yi 已提交
2555 2556
{
	int i, j;
2557 2558
	struct iwl_priv *priv = (struct iwl_priv *)priv_r;
	struct ieee80211_conf *conf = &priv->hw->conf;
2559
	struct iwl_lq_sta *lq_sta = priv_sta;
M
Mohamed Abbas 已提交
2560
	u16 mask_bit = 0;
A
Abbas, Mohamed 已提交
2561 2562
	int count;
	int start_rate = 0;
Z
Zhu Yi 已提交
2563

2564
	lq_sta->flush_timer = 0;
2565
	lq_sta->supp_rates = sta->supp_rates[sband->band];
Z
Zhu Yi 已提交
2566 2567
	for (j = 0; j < LQ_SIZE; j++)
		for (i = 0; i < IWL_RATE_COUNT; i++)
2568
			rs_rate_scale_clear_window(&lq_sta->lq_info[j].win[i]);
Z
Zhu Yi 已提交
2569

2570
	IWL_DEBUG_RATE(priv, "LQ: *** rate scale station global init ***\n");
Z
Zhu Yi 已提交
2571 2572 2573 2574 2575
	/* TODO: what is a good starting rate for STA? About middle? Maybe not
	 * the lowest or the highest rate.. Could consider using RSSI from
	 * previous packets? Need to have IEEE 802.1X auth succeed immediately
	 * after assoc.. */

2576
	lq_sta->ibss_sta_added = 0;
2577
	if (priv->iw_mode == NL80211_IFTYPE_AP) {
2578 2579
		u8 sta_id = priv->cfg->ops->smgmt->find_station(priv,
								sta->addr);
2580

Z
Zhu Yi 已提交
2581
		/* for IBSS the call are from tasklet */
2582
		IWL_DEBUG_RATE(priv, "LQ: ADD station %pM\n", sta->addr);
Z
Zhu Yi 已提交
2583 2584

		if (sta_id == IWL_INVALID_STATION) {
2585
			IWL_DEBUG_RATE(priv, "LQ: ADD station %pM\n", sta->addr);
2586
			sta_id = priv->cfg->ops->smgmt->add_station(priv,
2587 2588
							sta->addr, 0,
							CMD_ASYNC, NULL);
Z
Zhu Yi 已提交
2589 2590
		}
		if ((sta_id != IWL_INVALID_STATION)) {
2591 2592
			lq_sta->lq.sta_id = sta_id;
			lq_sta->lq.rs_table[0].rate_n_flags = 0;
Z
Zhu Yi 已提交
2593 2594 2595 2596 2597
		}
		/* FIXME: this is w/a remove it later */
		priv->assoc_station_added = 1;
	}

2598
	lq_sta->is_dup = 0;
2599
	lq_sta->max_rate_idx = -1;
A
Abbas, Mohamed 已提交
2600
	lq_sta->missed_rate_counter = IWL_MISSED_RATE_MAX;
2601
	lq_sta->is_green = rs_use_green(priv, conf);
G
Guy Cohen 已提交
2602
	lq_sta->active_legacy_rate = priv->active_rate & ~(0x1000);
2603
	lq_sta->active_rate_basic = priv->active_rate_basic;
2604
	lq_sta->band = priv->band;
2605 2606 2607 2608
	/*
	 * active_siso_rate mask includes 9 MBits (bit 5), and CCK (bits 0-3),
	 * supp_rates[] does not; shift to convert format, force 9 MBits off.
	 */
J
Johannes Berg 已提交
2609 2610
	lq_sta->active_siso_rate = sta->ht_cap.mcs.rx_mask[0] << 1;
	lq_sta->active_siso_rate |= sta->ht_cap.mcs.rx_mask[0] & 0x1;
2611
	lq_sta->active_siso_rate &= ~((u16)0x2);
G
Guy Cohen 已提交
2612
	lq_sta->active_siso_rate <<= IWL_FIRST_OFDM_RATE;
Z
Zhu Yi 已提交
2613

2614
	/* Same here */
J
Johannes Berg 已提交
2615 2616
	lq_sta->active_mimo2_rate = sta->ht_cap.mcs.rx_mask[1] << 1;
	lq_sta->active_mimo2_rate |= sta->ht_cap.mcs.rx_mask[1] & 0x1;
G
Guy Cohen 已提交
2617 2618 2619
	lq_sta->active_mimo2_rate &= ~((u16)0x2);
	lq_sta->active_mimo2_rate <<= IWL_FIRST_OFDM_RATE;

J
Johannes Berg 已提交
2620 2621
	lq_sta->active_mimo3_rate = sta->ht_cap.mcs.rx_mask[2] << 1;
	lq_sta->active_mimo3_rate |= sta->ht_cap.mcs.rx_mask[2] & 0x1;
G
Guy Cohen 已提交
2622 2623 2624
	lq_sta->active_mimo3_rate &= ~((u16)0x2);
	lq_sta->active_mimo3_rate <<= IWL_FIRST_OFDM_RATE;

2625
	IWL_DEBUG_RATE(priv, "SISO-RATE=%X MIMO2-RATE=%X MIMO3-RATE=%X\n",
2626
		     lq_sta->active_siso_rate,
G
Guy Cohen 已提交
2627 2628 2629
		     lq_sta->active_mimo2_rate,
		     lq_sta->active_mimo3_rate);

T
Tomas Winkler 已提交
2630
	/* These values will be overridden later */
G
Guy Cohen 已提交
2631 2632 2633
	lq_sta->lq.general_params.single_stream_ant_msk = ANT_A;
	lq_sta->lq.general_params.dual_stream_ant_msk = ANT_AB;

2634 2635
	/* as default allow aggregation for all tids */
	lq_sta->tx_agg_tid_en = IWL_AGG_ALL_TID;
2636
	lq_sta->drv = priv;
Z
Zhu Yi 已提交
2637

M
Mohamed Abbas 已提交
2638
	/* Find highest tx rate supported by hardware and destination station */
A
Abbas, Mohamed 已提交
2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649
	mask_bit = sta->supp_rates[sband->band];
	count = sband->n_bitrates;
	if (sband->band == IEEE80211_BAND_5GHZ) {
		count += IWL_FIRST_OFDM_RATE;
		start_rate = IWL_FIRST_OFDM_RATE;
		mask_bit <<= IWL_FIRST_OFDM_RATE;
	}

	mask_bit = mask_bit & lq_sta->active_legacy_rate;
	lq_sta->last_txrate_idx = 4;
	for (i = start_rate; i < count; i++)
M
Mohamed Abbas 已提交
2650 2651 2652
		if (mask_bit & BIT(i))
			lq_sta->last_txrate_idx = i;

2653
	rs_initialize_lq(priv, conf, sta, lq_sta);
Z
Zhu Yi 已提交
2654 2655
}

G
Guy Cohen 已提交
2656
static void rs_fill_link_cmd(const struct iwl_priv *priv,
2657
			     struct iwl_lq_sta *lq_sta, u32 new_rate)
Z
Zhu Yi 已提交
2658
{
2659
	struct iwl_scale_tbl_info tbl_type;
Z
Zhu Yi 已提交
2660 2661
	int index = 0;
	int rate_idx;
2662
	int repeat_rate = 0;
2663
	u8 ant_toggle_cnt = 0;
Z
Zhu Yi 已提交
2664
	u8 use_ht_possible = 1;
2665
	u8 valid_tx_ant = 0;
G
Guy Cohen 已提交
2666
	struct iwl_link_quality_cmd *lq_cmd = &lq_sta->lq;
Z
Zhu Yi 已提交
2667

2668
	/* Override starting rate (index 0) if needed for debug purposes */
G
Guy Cohen 已提交
2669
	rs_dbgfs_set_mcs(lq_sta, &new_rate, index);
2670

G
Guy Cohen 已提交
2671
	/* Interpret new_rate (rate_n_flags) */
2672
	memset(&tbl_type, 0, sizeof(tbl_type));
G
Guy Cohen 已提交
2673
	rs_get_tbl_info_from_mcs(new_rate, lq_sta->band,
Z
Zhu Yi 已提交
2674 2675
				  &tbl_type, &rate_idx);

2676
	/* How many times should we repeat the initial rate? */
Z
Zhu Yi 已提交
2677
	if (is_legacy(tbl_type.lq_type)) {
2678
		ant_toggle_cnt = 1;
2679
		repeat_rate = IWL_NUMBER_TRY;
2680
	} else {
2681
		repeat_rate = IWL_HT_NUMBER_TRY;
2682
	}
Z
Zhu Yi 已提交
2683 2684 2685

	lq_cmd->general_params.mimo_delimiter =
			is_mimo(tbl_type.lq_type) ? 1 : 0;
2686 2687

	/* Fill 1st table entry (index 0) */
G
Guy Cohen 已提交
2688
	lq_cmd->rs_table[index].rate_n_flags = cpu_to_le32(new_rate);
Z
Zhu Yi 已提交
2689

G
Guy Cohen 已提交
2690 2691 2692 2693 2694 2695 2696
	if (num_of_ant(tbl_type.ant_type) == 1) {
		lq_cmd->general_params.single_stream_ant_msk =
						tbl_type.ant_type;
	} else if (num_of_ant(tbl_type.ant_type) == 2) {
		lq_cmd->general_params.dual_stream_ant_msk =
						tbl_type.ant_type;
	} /* otherwise we don't modify the existing value */
Z
Zhu Yi 已提交
2697 2698

	index++;
2699
	repeat_rate--;
Z
Zhu Yi 已提交
2700

2701 2702 2703
	if (priv)
		valid_tx_ant = priv->hw_params.valid_tx_ant;

2704
	/* Fill rest of rate table */
Z
Zhu Yi 已提交
2705
	while (index < LINK_QUAL_MAX_RETRY_NUM) {
2706 2707 2708
		/* Repeat initial/next rate.
		 * For legacy IWL_NUMBER_TRY == 1, this loop will not execute.
		 * For HT IWL_HT_NUMBER_TRY == 3, this executes twice. */
2709
		while (repeat_rate > 0 && (index < LINK_QUAL_MAX_RETRY_NUM)) {
Z
Zhu Yi 已提交
2710
			if (is_legacy(tbl_type.lq_type)) {
2711 2712 2713 2714 2715 2716 2717
				if (ant_toggle_cnt < NUM_TRY_BEFORE_ANT_TOGGLE)
					ant_toggle_cnt++;
				else if (priv &&
					 rs_toggle_antenna(valid_tx_ant,
							&new_rate, &tbl_type))
					ant_toggle_cnt = 1;
}
2718

2719
			/* Override next rate if needed for debug purposes */
2720
			rs_dbgfs_set_mcs(lq_sta, &new_rate, index);
2721 2722

			/* Fill next table entry */
Z
Zhu Yi 已提交
2723
			lq_cmd->rs_table[index].rate_n_flags =
G
Guy Cohen 已提交
2724
					cpu_to_le32(new_rate);
2725
			repeat_rate--;
Z
Zhu Yi 已提交
2726 2727 2728
			index++;
		}

G
Guy Cohen 已提交
2729
		rs_get_tbl_info_from_mcs(new_rate, lq_sta->band, &tbl_type,
Z
Zhu Yi 已提交
2730 2731
						&rate_idx);

2732 2733 2734
		/* Indicate to uCode which entries might be MIMO.
		 * If initial rate was MIMO, this will finally end up
		 * as (IWL_HT_NUMBER_TRY * 2), after 2nd pass, otherwise 0. */
Z
Zhu Yi 已提交
2735 2736 2737
		if (is_mimo(tbl_type.lq_type))
			lq_cmd->general_params.mimo_delimiter = index;

2738
		/* Get next rate */
G
Guy Cohen 已提交
2739 2740
		new_rate = rs_get_lower_rate(lq_sta, &tbl_type, rate_idx,
					     use_ht_possible);
Z
Zhu Yi 已提交
2741

2742
		/* How many times should we repeat the next rate? */
Z
Zhu Yi 已提交
2743
		if (is_legacy(tbl_type.lq_type)) {
2744 2745 2746 2747 2748 2749 2750
			if (ant_toggle_cnt < NUM_TRY_BEFORE_ANT_TOGGLE)
				ant_toggle_cnt++;
			else if (priv &&
				 rs_toggle_antenna(valid_tx_ant,
						   &new_rate, &tbl_type))
				ant_toggle_cnt = 1;

2751
			repeat_rate = IWL_NUMBER_TRY;
2752
		} else {
2753
			repeat_rate = IWL_HT_NUMBER_TRY;
2754
		}
Z
Zhu Yi 已提交
2755

2756 2757
		/* Don't allow HT rates after next pass.
		 * rs_get_lower_rate() will change type to LQ_A or LQ_G. */
Z
Zhu Yi 已提交
2758 2759
		use_ht_possible = 0;

2760
		/* Override next rate if needed for debug purposes */
2761
		rs_dbgfs_set_mcs(lq_sta, &new_rate, index);
2762 2763

		/* Fill next table entry */
G
Guy Cohen 已提交
2764
		lq_cmd->rs_table[index].rate_n_flags = cpu_to_le32(new_rate);
Z
Zhu Yi 已提交
2765 2766

		index++;
2767
		repeat_rate--;
Z
Zhu Yi 已提交
2768 2769
	}

2770
	lq_cmd->agg_params.agg_frame_cnt_limit = 64;
Z
Zhu Yi 已提交
2771 2772 2773 2774
	lq_cmd->agg_params.agg_dis_start_th = 3;
	lq_cmd->agg_params.agg_time_limit = cpu_to_le16(4000);
}

2775
static void *rs_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir)
Z
Zhu Yi 已提交
2776
{
2777
	return hw->priv;
Z
Zhu Yi 已提交
2778 2779 2780 2781 2782 2783 2784
}
/* rate scale requires free function to be implemented */
static void rs_free(void *priv_rate)
{
	return;
}

2785 2786
static void rs_free_sta(void *priv_r, struct ieee80211_sta *sta,
			void *priv_sta)
Z
Zhu Yi 已提交
2787
{
2788
	struct iwl_lq_sta *lq_sta = priv_sta;
2789
	struct iwl_priv *priv __maybe_unused = priv_r;
Z
Zhu Yi 已提交
2790

2791
	IWL_DEBUG_RATE(priv, "enter\n");
2792
	kfree(lq_sta);
2793
	IWL_DEBUG_RATE(priv, "leave\n");
Z
Zhu Yi 已提交
2794 2795 2796
}


2797
#ifdef CONFIG_MAC80211_DEBUGFS
2798 2799 2800 2801 2802
static int open_file_generic(struct inode *inode, struct file *file)
{
	file->private_data = inode->i_private;
	return 0;
}
2803 2804
static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta,
			     u32 *rate_n_flags, int index)
2805
{
2806
	struct iwl_priv *priv;
2807 2808
	u8 valid_tx_ant;
	u8 ant_sel_tx;
2809 2810

	priv = lq_sta->drv;
2811
	valid_tx_ant = priv->hw_params.valid_tx_ant;
G
Guy Cohen 已提交
2812
	if (lq_sta->dbg_fixed_rate) {
2813 2814 2815 2816
		ant_sel_tx =
		  ((lq_sta->dbg_fixed_rate & RATE_MCS_ANT_ABC_MSK)
		  >> RATE_MCS_ANT_POS);
		if ((valid_tx_ant & ant_sel_tx) == ant_sel_tx) {
G
Guy Cohen 已提交
2817
			*rate_n_flags = lq_sta->dbg_fixed_rate;
2818
			IWL_DEBUG_RATE(priv, "Fixed rate ON\n");
G
Guy Cohen 已提交
2819
		} else {
2820 2821 2822 2823 2824
			lq_sta->dbg_fixed_rate = 0;
			IWL_ERR(priv,
			    "Invalid antenna selection 0x%X, Valid is 0x%X\n",
			    ant_sel_tx, valid_tx_ant);
			IWL_DEBUG_RATE(priv, "Fixed rate OFF\n");
G
Guy Cohen 已提交
2825 2826
		}
	} else {
2827
		IWL_DEBUG_RATE(priv, "Fixed rate OFF\n");
2828 2829
	}
}
2830

2831 2832 2833
static ssize_t rs_sta_dbgfs_scale_table_write(struct file *file,
			const char __user *user_buf, size_t count, loff_t *ppos)
{
2834
	struct iwl_lq_sta *lq_sta = file->private_data;
2835
	struct iwl_priv *priv;
2836 2837 2838 2839
	char buf[64];
	int buf_size;
	u32 parsed_rate;

2840
	priv = lq_sta->drv;
2841 2842 2843 2844 2845 2846
	memset(buf, 0, sizeof(buf));
	buf_size = min(count, sizeof(buf) -  1);
	if (copy_from_user(buf, user_buf, buf_size))
		return -EFAULT;

	if (sscanf(buf, "%x", &parsed_rate) == 1)
G
Guy Cohen 已提交
2847
		lq_sta->dbg_fixed_rate = parsed_rate;
2848
	else
G
Guy Cohen 已提交
2849
		lq_sta->dbg_fixed_rate = 0;
2850

G
Guy Cohen 已提交
2851 2852 2853 2854
	lq_sta->active_legacy_rate = 0x0FFF;	/* 1 - 54 MBits, includes CCK */
	lq_sta->active_siso_rate   = 0x1FD0;	/* 6 - 60 MBits, no 9, no CCK */
	lq_sta->active_mimo2_rate  = 0x1FD0;	/* 6 - 60 MBits, no 9, no CCK */
	lq_sta->active_mimo3_rate  = 0x1FD0;	/* 6 - 60 MBits, no 9, no CCK */
2855

2856
	IWL_DEBUG_RATE(priv, "sta_id %d rate 0x%X\n",
G
Guy Cohen 已提交
2857
		lq_sta->lq.sta_id, lq_sta->dbg_fixed_rate);
2858

G
Guy Cohen 已提交
2859
	if (lq_sta->dbg_fixed_rate) {
G
Guy Cohen 已提交
2860
		rs_fill_link_cmd(NULL, lq_sta, lq_sta->dbg_fixed_rate);
2861
		iwl_send_lq_cmd(lq_sta->drv, &lq_sta->lq, CMD_ASYNC);
2862 2863 2864 2865
	}

	return count;
}
2866

2867 2868 2869
static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file,
			char __user *user_buf, size_t count, loff_t *ppos)
{
F
Frank Seidel 已提交
2870
	char *buff;
2871 2872
	int desc = 0;
	int i = 0;
2873
	int index = 0;
F
Frank Seidel 已提交
2874
	ssize_t ret;
2875

2876
	struct iwl_lq_sta *lq_sta = file->private_data;
2877
	struct iwl_priv *priv;
2878
	struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
2879

2880
	priv = lq_sta->drv;
F
Frank Seidel 已提交
2881 2882 2883 2884
	buff = kmalloc(1024, GFP_KERNEL);
	if (!buff)
		return -ENOMEM;

2885
	desc += sprintf(buff+desc, "sta_id %d\n", lq_sta->lq.sta_id);
2886
	desc += sprintf(buff+desc, "failed=%d success=%d rate=0%X\n",
2887
			lq_sta->total_failed, lq_sta->total_success,
G
Guy Cohen 已提交
2888
			lq_sta->active_legacy_rate);
2889
	desc += sprintf(buff+desc, "fixed rate 0x%X\n",
G
Guy Cohen 已提交
2890
			lq_sta->dbg_fixed_rate);
2891 2892 2893 2894
	desc += sprintf(buff+desc, "valid_tx_ant %s%s%s\n",
	    (priv->hw_params.valid_tx_ant & ANT_A) ? "ANT_A," : "",
	    (priv->hw_params.valid_tx_ant & ANT_B) ? "ANT_B," : "",
	    (priv->hw_params.valid_tx_ant & ANT_C) ? "ANT_C" : "");
2895 2896 2897 2898 2899 2900 2901 2902
	desc += sprintf(buff+desc, "lq type %s\n",
	   (is_legacy(tbl->lq_type)) ? "legacy" : "HT");
	if (is_Ht(tbl->lq_type)) {
		desc += sprintf(buff+desc, " %s",
		   (is_siso(tbl->lq_type)) ? "SISO" :
		   ((is_mimo2(tbl->lq_type)) ? "MIMO2" : "MIMO3"));
		   desc += sprintf(buff+desc, " %s",
		   (tbl->is_fat) ? "40MHz" : "20MHz");
2903 2904
		   desc += sprintf(buff+desc, " %s %s\n", (tbl->is_SGI) ? "SGI" : "",
		   (lq_sta->is_green) ? "GF enabled" : "");
2905
	}
2906 2907
	desc += sprintf(buff+desc, "last tx rate=0x%X\n",
		lq_sta->last_rate_n_flags);
2908 2909
	desc += sprintf(buff+desc, "general:"
		"flags=0x%X mimo-d=%d s-ant0x%x d-ant=0x%x\n",
2910 2911 2912 2913
		lq_sta->lq.general_params.flags,
		lq_sta->lq.general_params.mimo_delimiter,
		lq_sta->lq.general_params.single_stream_ant_msk,
		lq_sta->lq.general_params.dual_stream_ant_msk);
2914 2915 2916

	desc += sprintf(buff+desc, "agg:"
			"time_limit=%d dist_start_th=%d frame_cnt_limit=%d\n",
2917 2918 2919
			le16_to_cpu(lq_sta->lq.agg_params.agg_time_limit),
			lq_sta->lq.agg_params.agg_dis_start_th,
			lq_sta->lq.agg_params.agg_frame_cnt_limit);
2920 2921 2922

	desc += sprintf(buff+desc,
			"Start idx [0]=0x%x [1]=0x%x [2]=0x%x [3]=0x%x\n",
2923 2924 2925 2926
			lq_sta->lq.general_params.start_rate_index[0],
			lq_sta->lq.general_params.start_rate_index[1],
			lq_sta->lq.general_params.start_rate_index[2],
			lq_sta->lq.general_params.start_rate_index[3]);
2927

2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940
	for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) {
		index = iwl_hwrate_to_plcp_idx(
			le32_to_cpu(lq_sta->lq.rs_table[i].rate_n_flags));
		if (is_legacy(tbl->lq_type)) {
			desc += sprintf(buff+desc, " rate[%d] 0x%X %smbps\n",
				i, le32_to_cpu(lq_sta->lq.rs_table[i].rate_n_flags),
				iwl_rate_mcs[index].mbps);
		} else {
			desc += sprintf(buff+desc, " rate[%d] 0x%X %smbps (%s)\n",
				i, le32_to_cpu(lq_sta->lq.rs_table[i].rate_n_flags),
				iwl_rate_mcs[index].mbps, iwl_rate_mcs[index].mcs);
		}
	}
2941

F
Frank Seidel 已提交
2942 2943 2944
	ret = simple_read_from_buffer(user_buf, count, ppos, buff, desc);
	kfree(buff);
	return ret;
2945 2946 2947
}

static const struct file_operations rs_sta_dbgfs_scale_table_ops = {
2948
	.write = rs_sta_dbgfs_scale_table_write,
2949 2950 2951
	.read = rs_sta_dbgfs_scale_table_read,
	.open = open_file_generic,
};
2952 2953 2954
static ssize_t rs_sta_dbgfs_stats_table_read(struct file *file,
			char __user *user_buf, size_t count, loff_t *ppos)
{
F
Frank Seidel 已提交
2955
	char *buff;
2956 2957
	int desc = 0;
	int i, j;
F
Frank Seidel 已提交
2958
	ssize_t ret;
2959

2960
	struct iwl_lq_sta *lq_sta = file->private_data;
F
Frank Seidel 已提交
2961 2962 2963 2964 2965

	buff = kmalloc(1024, GFP_KERNEL);
	if (!buff)
		return -ENOMEM;

2966
	for (i = 0; i < LQ_SIZE; i++) {
2967
		desc += sprintf(buff+desc, "%s type=%d SGI=%d FAT=%d DUP=%d GF=%d\n"
2968
				"rate=0x%X\n",
2969
				lq_sta->active_tbl == i ? "*" : "x",
2970 2971 2972 2973
				lq_sta->lq_info[i].lq_type,
				lq_sta->lq_info[i].is_SGI,
				lq_sta->lq_info[i].is_fat,
				lq_sta->lq_info[i].is_dup,
2974
				lq_sta->is_green,
G
Guy Cohen 已提交
2975
				lq_sta->lq_info[i].current_rate);
2976 2977
		for (j = 0; j < IWL_RATE_COUNT; j++) {
			desc += sprintf(buff+desc,
2978 2979 2980 2981
				"counter=%d success=%d %%=%d\n",
				lq_sta->lq_info[i].win[j].counter,
				lq_sta->lq_info[i].win[j].success_counter,
				lq_sta->lq_info[i].win[j].success_ratio);
2982 2983
		}
	}
F
Frank Seidel 已提交
2984 2985 2986
	ret = simple_read_from_buffer(user_buf, count, ppos, buff, desc);
	kfree(buff);
	return ret;
2987 2988 2989 2990 2991 2992
}

static const struct file_operations rs_sta_dbgfs_stats_table_ops = {
	.read = rs_sta_dbgfs_stats_table_read,
	.open = open_file_generic,
};
2993

2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030
static ssize_t rs_sta_dbgfs_rate_scale_data_read(struct file *file,
			char __user *user_buf, size_t count, loff_t *ppos)
{
	char buff[120];
	int desc = 0;
	ssize_t ret;

	struct iwl_lq_sta *lq_sta = file->private_data;
	struct iwl_priv *priv;
	struct iwl_scale_tbl_info *tbl = &lq_sta->lq_info[lq_sta->active_tbl];

	priv = lq_sta->drv;

	if (is_Ht(tbl->lq_type))
		desc += sprintf(buff+desc,
				"Bit Rate= %d Mb/s\n",
				tbl->expected_tpt[lq_sta->last_txrate_idx]);
	else
		desc += sprintf(buff+desc,
				"Bit Rate= %d Mb/s\n",
				iwl_rates[lq_sta->last_txrate_idx].ieee >> 1);
	desc += sprintf(buff+desc,
			"Signal Level= %d dBm\tNoise Level= %d dBm\n",
			priv->last_rx_rssi, priv->last_rx_noise);
	desc += sprintf(buff+desc,
			"Tsf= 0x%llx\tBeacon time= 0x%08X\n",
			priv->last_tsf, priv->last_beacon_time);

	ret = simple_read_from_buffer(user_buf, count, ppos, buff, desc);
	return ret;
}

static const struct file_operations rs_sta_dbgfs_rate_scale_data_ops = {
	.read = rs_sta_dbgfs_rate_scale_data_read,
	.open = open_file_generic,
};

3031 3032 3033
static void rs_add_debugfs(void *priv, void *priv_sta,
					struct dentry *dir)
{
3034
	struct iwl_lq_sta *lq_sta = priv_sta;
3035
	lq_sta->rs_sta_dbgfs_scale_table_file =
3036
		debugfs_create_file("rate_scale_table", 0600, dir,
3037 3038
				lq_sta, &rs_sta_dbgfs_scale_table_ops);
	lq_sta->rs_sta_dbgfs_stats_table_file =
3039
		debugfs_create_file("rate_stats_table", 0600, dir,
3040
			lq_sta, &rs_sta_dbgfs_stats_table_ops);
3041 3042 3043
	lq_sta->rs_sta_dbgfs_rate_scale_data_file =
		debugfs_create_file("rate_scale_data", 0600, dir,
			lq_sta, &rs_sta_dbgfs_rate_scale_data_ops);
3044 3045 3046 3047
	lq_sta->rs_sta_dbgfs_tx_agg_tid_en_file =
		debugfs_create_u8("tx_agg_tid_enable", 0600, dir,
		&lq_sta->tx_agg_tid_en);

3048 3049 3050 3051
}

static void rs_remove_debugfs(void *priv, void *priv_sta)
{
3052
	struct iwl_lq_sta *lq_sta = priv_sta;
3053 3054
	debugfs_remove(lq_sta->rs_sta_dbgfs_scale_table_file);
	debugfs_remove(lq_sta->rs_sta_dbgfs_stats_table_file);
3055
	debugfs_remove(lq_sta->rs_sta_dbgfs_rate_scale_data_file);
3056
	debugfs_remove(lq_sta->rs_sta_dbgfs_tx_agg_tid_en_file);
3057 3058 3059
}
#endif

Z
Zhu Yi 已提交
3060 3061 3062 3063 3064 3065 3066 3067 3068 3069
static struct rate_control_ops rs_ops = {
	.module = NULL,
	.name = RS_NAME,
	.tx_status = rs_tx_status,
	.get_rate = rs_get_rate,
	.rate_init = rs_rate_init,
	.alloc = rs_alloc,
	.free = rs_free,
	.alloc_sta = rs_alloc_sta,
	.free_sta = rs_free_sta,
3070 3071 3072 3073
#ifdef CONFIG_MAC80211_DEBUGFS
	.add_sta_debugfs = rs_add_debugfs,
	.remove_sta_debugfs = rs_remove_debugfs,
#endif
Z
Zhu Yi 已提交
3074 3075
};

3076
int iwlagn_rate_control_register(void)
Z
Zhu Yi 已提交
3077
{
3078
	return ieee80211_rate_control_register(&rs_ops);
Z
Zhu Yi 已提交
3079 3080
}

3081
void iwlagn_rate_control_unregister(void)
Z
Zhu Yi 已提交
3082 3083 3084 3085
{
	ieee80211_rate_control_unregister(&rs_ops);
}