iwl-agn-rs.c 87.2 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
}

G
Guy Cohen 已提交
655
/* FIXME:RS: in 4965 we don't use greenfield at all */
G
Guy Cohen 已提交
656 657 658
/* FIXME:RS: don't use greenfield for now in TX */
#if 0
static inline u8 rs_use_green(struct iwl_priv *priv, struct ieee80211_conf *conf)
Z
Zhu Yi 已提交
659
{
660
	return (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) &&
661
		priv->current_ht_config.is_green_field &&
662
		!priv->current_ht_config.non_GF_STA_present;
G
Guy Cohen 已提交
663
}
664
#endif
G
Guy Cohen 已提交
665 666
static inline u8 rs_use_green(struct iwl_priv *priv, struct ieee80211_conf *conf)
{
667
	return 0;
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 2064
	tbl = &(lq_sta->lq_info[active_tbl]);
	is_green = lq_sta->is_green;
Z
Zhu Yi 已提交
2065

2066
	/* current tx rate */
2067
	index = lq_sta->last_txrate_idx;
Z
Zhu Yi 已提交
2068

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

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

2075
	IWL_DEBUG_RATE(priv, "mask 0x%04X \n", rate_mask);
Z
Zhu Yi 已提交
2076 2077 2078

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

	} else
		rate_scale_index_msk = rate_mask;

	if (!rate_scale_index_msk)
		rate_scale_index_msk = rate_mask;

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

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

2104 2105 2106 2107 2108 2109 2110 2111 2112
	/* 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 已提交
2113 2114
	window = &(tbl->win[index]);

2115 2116 2117 2118 2119 2120 2121
	/*
	 * 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 已提交
2122
	fail_count = window->counter - window->success_counter;
G
Guy Cohen 已提交
2123 2124
	if ((fail_count < IWL_RATE_MIN_FAILURE_TH) &&
			(window->success_counter < IWL_RATE_MIN_SUCCESS_TH)) {
2125
		IWL_DEBUG_RATE(priv, "LQ: still below TH. succ=%d total=%d "
Z
Zhu Yi 已提交
2126 2127
			       "for index %d\n",
			       window->success_counter, window->counter, index);
2128 2129

		/* Can't calculate this yet; not enough history */
Z
Zhu Yi 已提交
2130
		window->average_tpt = IWL_INVALID_VALUE;
2131 2132 2133

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

Z
Zhu Yi 已提交
2136
		goto out;
2137
	}
Z
Zhu Yi 已提交
2138

2139 2140
	/* Else we have enough samples; calculate estimate of
	 * actual average throughput */
2141 2142 2143

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

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

2148 2149 2150
		/* 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 已提交
2151 2152
		if (window->average_tpt > lq_sta->last_tpt) {

2153
			IWL_DEBUG_RATE(priv, "LQ: SWITCHING TO NEW TABLE "
G
Guy Cohen 已提交
2154 2155 2156 2157 2158 2159
					"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))
2160
				lq_sta->enable_counter = 1;
G
Guy Cohen 已提交
2161

2162
			/* Swap tables; "search" becomes "active" */
2163
			lq_sta->active_tbl = active_tbl;
Z
Zhu Yi 已提交
2164
			current_tpt = window->average_tpt;
2165 2166

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

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

2175
			/* Nullify "search" table */
Z
Zhu Yi 已提交
2176
			tbl->lq_type = LQ_NONE;
2177 2178

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

2182
			/* Revert to "active" rate and throughput info */
2183
			index = iwl_hwrate_to_plcp_idx(tbl->current_rate);
2184
			current_tpt = lq_sta->last_tpt;
Z
Zhu Yi 已提交
2185

2186
			/* Need to set up a new rate table in uCode */
Z
Zhu Yi 已提交
2187 2188
			update_lq = 1;
		}
2189 2190 2191

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

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

2204 2205 2206 2207 2208
	/* 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 已提交
2209 2210
	sr = window->success_ratio;

2211
	/* Collect measured throughputs for current and adjacent rates */
Z
Zhu Yi 已提交
2212 2213 2214 2215 2216 2217
	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 已提交
2218
	scale_action = 0;
Z
Zhu Yi 已提交
2219

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

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

		if (high != IWL_RATE_INVALID && sr >= IWL_RATE_INCREASE_TH)
			scale_action = 1;
		else if (low != IWL_RATE_INVALID)
2232
			scale_action = 0;
G
Guy Cohen 已提交
2233
	}
2234 2235 2236

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

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

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

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

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

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

		break;
	case 0:
2294
		/* No change */
Z
Zhu Yi 已提交
2295 2296 2297 2298
	default:
		break;
	}

2299
	IWL_DEBUG_RATE(priv, "choose rate scale index %d action %d low %d "
Z
Zhu Yi 已提交
2300 2301 2302
		    "high %d type %d\n",
		     index, scale_action, low, high, tbl->lq_type);

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

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

2314 2315 2316 2317 2318 2319
	/*
	 * 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
	 */
2320
	if (!update_lq && !done_search && !lq_sta->stay_in_tbl && window->counter) {
2321
		/* Save current throughput to compare with "search" throughput*/
2322
		lq_sta->last_tpt = current_tpt;
Z
Zhu Yi 已提交
2323

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

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

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

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

2353
	if (done_search && !lq_sta->stay_in_tbl) {
2354 2355 2356 2357 2358
		/* 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. */
2359
		tbl1 = &(lq_sta->lq_info[lq_sta->active_tbl]);
2360
		if (is_legacy(tbl1->lq_type) && !conf_is_ht(conf) &&
2361
		    lq_sta->action_counter > tbl1->max_search) {
2362
			IWL_DEBUG_RATE(priv, "LQ: STAY in legacy table\n");
2363
			rs_set_stay_in_table(priv, 1, lq_sta);
Z
Zhu Yi 已提交
2364 2365
		}

2366 2367 2368
		/* 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. */
2369
		if (lq_sta->enable_counter &&
2370
		    (lq_sta->action_counter >= tbl1->max_search)) {
2371 2372 2373
			if ((lq_sta->last_tpt > IWL_AGG_TPT_THREHOLD) &&
			    (lq_sta->tx_agg_tid_en & (1 << tid)) &&
			    (tid != MAX_TID_COUNT)) {
2374 2375 2376 2377 2378 2379 2380 2381 2382
				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 已提交
2383
			}
2384
			rs_set_stay_in_table(priv, 0, lq_sta);
Z
Zhu Yi 已提交
2385 2386 2387 2388
		}
	}

out:
T
Tomas Winkler 已提交
2389
	tbl->current_rate = rate_n_flags_from_tbl(priv, tbl, index, is_green);
Z
Zhu Yi 已提交
2390
	i = index;
2391
	lq_sta->last_txrate_idx = i;
Z
Zhu Yi 已提交
2392 2393 2394 2395 2396

	return;
}


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

2410
	if (!sta || !lq_sta)
Z
Zhu Yi 已提交
2411 2412
		goto out;

2413
	i = lq_sta->last_txrate_idx;
Z
Zhu Yi 已提交
2414

2415
	if ((lq_sta->lq.sta_id == 0xff) &&
2416
	    (priv->iw_mode == NL80211_IFTYPE_ADHOC))
Z
Zhu Yi 已提交
2417 2418
		goto out;

2419 2420
	valid_tx_ant = priv->hw_params.valid_tx_ant;

2421 2422
	if (!lq_sta->search_better_tbl)
		active_tbl = lq_sta->active_tbl;
Z
Zhu Yi 已提交
2423
	else
2424
		active_tbl = 1 - lq_sta->active_tbl;
Z
Zhu Yi 已提交
2425

2426
	tbl = &(lq_sta->lq_info[active_tbl]);
Z
Zhu Yi 已提交
2427 2428 2429 2430

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

2431
	rate = iwl_rates[i].plcp;
2432 2433
	tbl->ant_type = first_antenna(valid_tx_ant);
	rate |= tbl->ant_type << RATE_MCS_ANT_POS;
Z
Zhu Yi 已提交
2434 2435

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

G
Guy Cohen 已提交
2438
	rs_get_tbl_info_from_mcs(rate, priv->band, tbl, &rate_idx);
2439 2440
	if (!rs_is_valid_ant(valid_tx_ant, tbl->ant_type))
	    rs_toggle_antenna(valid_tx_ant, &rate, tbl);
Z
Zhu Yi 已提交
2441

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

2451 2452
static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta,
			struct ieee80211_tx_rate_control *txrc)
Z
Zhu Yi 已提交
2453 2454
{

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

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

2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477
	/* 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;
	}

2478 2479 2480
	if (sta)
		mask_bit = sta->supp_rates[sband->band];

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

2495
	rate_idx  = lq_sta->last_txrate_idx;
Z
Zhu Yi 已提交
2496

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

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

2517 2518 2519 2520
	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 已提交
2521

2522
	info->control.rates[0].idx = rate_idx;
Z
Zhu Yi 已提交
2523 2524
}

2525 2526
static void *rs_alloc_sta(void *priv_rate, struct ieee80211_sta *sta,
			  gfp_t gfp)
Z
Zhu Yi 已提交
2527
{
2528
	struct iwl_lq_sta *lq_sta;
2529
	struct iwl_priv *priv;
Z
Zhu Yi 已提交
2530 2531
	int i, j;

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

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

2537
	if (lq_sta == NULL)
Z
Zhu Yi 已提交
2538
		return NULL;
2539
	lq_sta->lq.sta_id = 0xff;
Z
Zhu Yi 已提交
2540

2541

Z
Zhu Yi 已提交
2542 2543
	for (j = 0; j < LQ_SIZE; j++)
		for (i = 0; i < IWL_RATE_COUNT; i++)
2544
			rs_rate_scale_clear_window(&lq_sta->lq_info[j].win[i]);
Z
Zhu Yi 已提交
2545

2546
	return lq_sta;
Z
Zhu Yi 已提交
2547 2548
}

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

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

2566
	IWL_DEBUG_RATE(priv, "LQ: *** rate scale station global init ***\n");
Z
Zhu Yi 已提交
2567 2568 2569 2570 2571
	/* 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.. */

2572
	lq_sta->ibss_sta_added = 0;
2573
	if (priv->iw_mode == NL80211_IFTYPE_AP) {
2574 2575
		u8 sta_id = priv->cfg->ops->smgmt->find_station(priv,
								sta->addr);
2576

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

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

2594
	lq_sta->is_dup = 0;
2595
	lq_sta->max_rate_idx = -1;
A
Abbas, Mohamed 已提交
2596
	lq_sta->missed_rate_counter = IWL_MISSED_RATE_MAX;
2597
	lq_sta->is_green = rs_use_green(priv, conf);
G
Guy Cohen 已提交
2598
	lq_sta->active_legacy_rate = priv->active_rate & ~(0x1000);
2599
	lq_sta->active_rate_basic = priv->active_rate_basic;
2600
	lq_sta->band = priv->band;
2601 2602 2603 2604
	/*
	 * 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 已提交
2605 2606
	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;
2607
	lq_sta->active_siso_rate &= ~((u16)0x2);
G
Guy Cohen 已提交
2608
	lq_sta->active_siso_rate <<= IWL_FIRST_OFDM_RATE;
Z
Zhu Yi 已提交
2609

2610
	/* Same here */
J
Johannes Berg 已提交
2611 2612
	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 已提交
2613 2614 2615
	lq_sta->active_mimo2_rate &= ~((u16)0x2);
	lq_sta->active_mimo2_rate <<= IWL_FIRST_OFDM_RATE;

J
Johannes Berg 已提交
2616 2617
	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 已提交
2618 2619 2620
	lq_sta->active_mimo3_rate &= ~((u16)0x2);
	lq_sta->active_mimo3_rate <<= IWL_FIRST_OFDM_RATE;

2621
	IWL_DEBUG_RATE(priv, "SISO-RATE=%X MIMO2-RATE=%X MIMO3-RATE=%X\n",
2622
		     lq_sta->active_siso_rate,
G
Guy Cohen 已提交
2623 2624 2625
		     lq_sta->active_mimo2_rate,
		     lq_sta->active_mimo3_rate);

T
Tomas Winkler 已提交
2626
	/* These values will be overridden later */
G
Guy Cohen 已提交
2627 2628 2629
	lq_sta->lq.general_params.single_stream_ant_msk = ANT_A;
	lq_sta->lq.general_params.dual_stream_ant_msk = ANT_AB;

2630 2631
	/* as default allow aggregation for all tids */
	lq_sta->tx_agg_tid_en = IWL_AGG_ALL_TID;
2632
	lq_sta->drv = priv;
Z
Zhu Yi 已提交
2633

M
Mohamed Abbas 已提交
2634
	/* Find highest tx rate supported by hardware and destination station */
A
Abbas, Mohamed 已提交
2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645
	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 已提交
2646 2647 2648
		if (mask_bit & BIT(i))
			lq_sta->last_txrate_idx = i;

2649
	rs_initialize_lq(priv, conf, sta, lq_sta);
Z
Zhu Yi 已提交
2650 2651
}

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

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

G
Guy Cohen 已提交
2667
	/* Interpret new_rate (rate_n_flags) */
2668
	memset(&tbl_type, 0, sizeof(tbl_type));
G
Guy Cohen 已提交
2669
	rs_get_tbl_info_from_mcs(new_rate, lq_sta->band,
Z
Zhu Yi 已提交
2670 2671
				  &tbl_type, &rate_idx);

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

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

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

G
Guy Cohen 已提交
2686 2687 2688 2689 2690 2691 2692
	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 已提交
2693 2694

	index++;
2695
	repeat_rate--;
Z
Zhu Yi 已提交
2696

2697 2698 2699
	if (priv)
		valid_tx_ant = priv->hw_params.valid_tx_ant;

2700
	/* Fill rest of rate table */
Z
Zhu Yi 已提交
2701
	while (index < LINK_QUAL_MAX_RETRY_NUM) {
2702 2703 2704
		/* 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. */
2705
		while (repeat_rate > 0 && (index < LINK_QUAL_MAX_RETRY_NUM)) {
Z
Zhu Yi 已提交
2706
			if (is_legacy(tbl_type.lq_type)) {
2707 2708 2709 2710 2711 2712 2713
				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;
}
2714

2715
			/* Override next rate if needed for debug purposes */
2716
			rs_dbgfs_set_mcs(lq_sta, &new_rate, index);
2717 2718

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

G
Guy Cohen 已提交
2725
		rs_get_tbl_info_from_mcs(new_rate, lq_sta->band, &tbl_type,
Z
Zhu Yi 已提交
2726 2727
						&rate_idx);

2728 2729 2730
		/* 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 已提交
2731 2732 2733
		if (is_mimo(tbl_type.lq_type))
			lq_cmd->general_params.mimo_delimiter = index;

2734
		/* Get next rate */
G
Guy Cohen 已提交
2735 2736
		new_rate = rs_get_lower_rate(lq_sta, &tbl_type, rate_idx,
					     use_ht_possible);
Z
Zhu Yi 已提交
2737

2738
		/* How many times should we repeat the next rate? */
Z
Zhu Yi 已提交
2739
		if (is_legacy(tbl_type.lq_type)) {
2740 2741 2742 2743 2744 2745 2746
			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;

2747
			repeat_rate = IWL_NUMBER_TRY;
2748
		} else {
2749
			repeat_rate = IWL_HT_NUMBER_TRY;
2750
		}
Z
Zhu Yi 已提交
2751

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

2756
		/* Override next rate if needed for debug purposes */
2757
		rs_dbgfs_set_mcs(lq_sta, &new_rate, index);
2758 2759

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

		index++;
2763
		repeat_rate--;
Z
Zhu Yi 已提交
2764 2765
	}

2766
	lq_cmd->agg_params.agg_frame_cnt_limit = 64;
Z
Zhu Yi 已提交
2767 2768 2769 2770
	lq_cmd->agg_params.agg_dis_start_th = 3;
	lq_cmd->agg_params.agg_time_limit = cpu_to_le16(4000);
}

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

2781 2782
static void rs_free_sta(void *priv_r, struct ieee80211_sta *sta,
			void *priv_sta)
Z
Zhu Yi 已提交
2783
{
2784
	struct iwl_lq_sta *lq_sta = priv_sta;
2785
	struct iwl_priv *priv __maybe_unused = priv_r;
Z
Zhu Yi 已提交
2786

2787
	IWL_DEBUG_RATE(priv, "enter\n");
2788
	kfree(lq_sta);
2789
	IWL_DEBUG_RATE(priv, "leave\n");
Z
Zhu Yi 已提交
2790 2791 2792
}


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

	priv = lq_sta->drv;
2807
	valid_tx_ant = priv->hw_params.valid_tx_ant;
G
Guy Cohen 已提交
2808
	if (lq_sta->dbg_fixed_rate) {
2809 2810 2811 2812
		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 已提交
2813
			*rate_n_flags = lq_sta->dbg_fixed_rate;
2814
			IWL_DEBUG_RATE(priv, "Fixed rate ON\n");
G
Guy Cohen 已提交
2815
		} else {
2816 2817 2818 2819 2820
			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 已提交
2821 2822
		}
	} else {
2823
		IWL_DEBUG_RATE(priv, "Fixed rate OFF\n");
2824 2825
	}
}
2826

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

2836
	priv = lq_sta->drv;
2837 2838 2839 2840 2841 2842
	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 已提交
2843
		lq_sta->dbg_fixed_rate = parsed_rate;
2844
	else
G
Guy Cohen 已提交
2845
		lq_sta->dbg_fixed_rate = 0;
2846

G
Guy Cohen 已提交
2847 2848 2849 2850
	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 */
2851

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

G
Guy Cohen 已提交
2855
	if (lq_sta->dbg_fixed_rate) {
G
Guy Cohen 已提交
2856
		rs_fill_link_cmd(NULL, lq_sta, lq_sta->dbg_fixed_rate);
2857
		iwl_send_lq_cmd(lq_sta->drv, &lq_sta->lq, CMD_ASYNC);
2858 2859 2860 2861
	}

	return count;
}
2862

2863 2864 2865
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 已提交
2866
	char *buff;
2867 2868
	int desc = 0;
	int i = 0;
2869
	int index = 0;
F
Frank Seidel 已提交
2870
	ssize_t ret;
2871

2872
	struct iwl_lq_sta *lq_sta = file->private_data;
2873
	struct iwl_priv *priv;
2874
	struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
2875

2876
	priv = lq_sta->drv;
F
Frank Seidel 已提交
2877 2878 2879 2880
	buff = kmalloc(1024, GFP_KERNEL);
	if (!buff)
		return -ENOMEM;

2881
	desc += sprintf(buff+desc, "sta_id %d\n", lq_sta->lq.sta_id);
2882
	desc += sprintf(buff+desc, "failed=%d success=%d rate=0%X\n",
2883
			lq_sta->total_failed, lq_sta->total_success,
G
Guy Cohen 已提交
2884
			lq_sta->active_legacy_rate);
2885
	desc += sprintf(buff+desc, "fixed rate 0x%X\n",
G
Guy Cohen 已提交
2886
			lq_sta->dbg_fixed_rate);
2887 2888 2889 2890
	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" : "");
2891 2892 2893 2894 2895 2896 2897 2898 2899 2900
	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");
		desc += sprintf(buff+desc, " %s\n", (tbl->is_SGI) ? "SGI" : "");
	}
2901 2902
	desc += sprintf(buff+desc, "last tx rate=0x%X\n",
		lq_sta->last_rate_n_flags);
2903 2904
	desc += sprintf(buff+desc, "general:"
		"flags=0x%X mimo-d=%d s-ant0x%x d-ant=0x%x\n",
2905 2906 2907 2908
		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);
2909 2910 2911

	desc += sprintf(buff+desc, "agg:"
			"time_limit=%d dist_start_th=%d frame_cnt_limit=%d\n",
2912 2913 2914
			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);
2915 2916 2917

	desc += sprintf(buff+desc,
			"Start idx [0]=0x%x [1]=0x%x [2]=0x%x [3]=0x%x\n",
2918 2919 2920 2921
			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]);
2922

2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935
	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);
		}
	}
2936

F
Frank Seidel 已提交
2937 2938 2939
	ret = simple_read_from_buffer(user_buf, count, ppos, buff, desc);
	kfree(buff);
	return ret;
2940 2941 2942
}

static const struct file_operations rs_sta_dbgfs_scale_table_ops = {
2943
	.write = rs_sta_dbgfs_scale_table_write,
2944 2945 2946
	.read = rs_sta_dbgfs_scale_table_read,
	.open = open_file_generic,
};
2947 2948 2949
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 已提交
2950
	char *buff;
2951 2952
	int desc = 0;
	int i, j;
F
Frank Seidel 已提交
2953
	ssize_t ret;
2954

2955
	struct iwl_lq_sta *lq_sta = file->private_data;
F
Frank Seidel 已提交
2956 2957 2958 2959 2960

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

2961 2962 2963
	for (i = 0; i < LQ_SIZE; i++) {
		desc += sprintf(buff+desc, "%s type=%d SGI=%d FAT=%d DUP=%d\n"
				"rate=0x%X\n",
2964
				lq_sta->active_tbl == i ? "*" : "x",
2965 2966 2967 2968
				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,
G
Guy Cohen 已提交
2969
				lq_sta->lq_info[i].current_rate);
2970 2971
		for (j = 0; j < IWL_RATE_COUNT; j++) {
			desc += sprintf(buff+desc,
2972 2973 2974 2975
				"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);
2976 2977
		}
	}
F
Frank Seidel 已提交
2978 2979 2980
	ret = simple_read_from_buffer(user_buf, count, ppos, buff, desc);
	kfree(buff);
	return ret;
2981 2982 2983 2984 2985 2986
}

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

2988 2989 2990 2991 2992 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
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,
};

3025 3026 3027
static void rs_add_debugfs(void *priv, void *priv_sta,
					struct dentry *dir)
{
3028
	struct iwl_lq_sta *lq_sta = priv_sta;
3029
	lq_sta->rs_sta_dbgfs_scale_table_file =
3030
		debugfs_create_file("rate_scale_table", 0600, dir,
3031 3032
				lq_sta, &rs_sta_dbgfs_scale_table_ops);
	lq_sta->rs_sta_dbgfs_stats_table_file =
3033
		debugfs_create_file("rate_stats_table", 0600, dir,
3034
			lq_sta, &rs_sta_dbgfs_stats_table_ops);
3035 3036 3037
	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);
3038 3039 3040 3041
	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);

3042 3043 3044 3045
}

static void rs_remove_debugfs(void *priv, void *priv_sta)
{
3046
	struct iwl_lq_sta *lq_sta = priv_sta;
3047 3048
	debugfs_remove(lq_sta->rs_sta_dbgfs_scale_table_file);
	debugfs_remove(lq_sta->rs_sta_dbgfs_stats_table_file);
3049
	debugfs_remove(lq_sta->rs_sta_dbgfs_rate_scale_data_file);
3050
	debugfs_remove(lq_sta->rs_sta_dbgfs_tx_agg_tid_en_file);
3051 3052 3053
}
#endif

Z
Zhu Yi 已提交
3054 3055 3056 3057 3058 3059 3060 3061 3062 3063
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,
3064 3065 3066 3067
#ifdef CONFIG_MAC80211_DEBUGFS
	.add_sta_debugfs = rs_add_debugfs,
	.remove_sta_debugfs = rs_remove_debugfs,
#endif
Z
Zhu Yi 已提交
3068 3069
};

3070
int iwlagn_rate_control_register(void)
Z
Zhu Yi 已提交
3071
{
3072
	return ieee80211_rate_control_register(&rs_ops);
Z
Zhu Yi 已提交
3073 3074
}

3075
void iwlagn_rate_control_unregister(void)
Z
Zhu Yi 已提交
3076 3077 3078 3079
{
	ieee80211_rate_control_unregister(&rs_ops);
}