iwl-4965-rs.c 73.6 KB
Newer Older
Z
Zhu Yi 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
/******************************************************************************
 *
 * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
 *
 * 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:
 * James P. Ketrenos <ipw2100-admin@linux.intel.com>
 * 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 <net/ieee80211.h>

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

#include <linux/workqueue.h>

#include "../net/mac80211/ieee80211_rate.h"

41
#include "iwl-4965.h"
Z
Zhu Yi 已提交
42 43 44 45 46 47 48 49
#include "iwl-helpers.h"

#define RS_NAME "iwl-4965-rs"

#define NUM_TRY_BEFORE_ANTENNA_TOGGLE 1
#define IWL_NUMBER_TRY      1
#define IWL_HT_NUMBER_TRY   3

50 51 52 53 54 55
#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 */

/* max time to accum history 2 seconds */
#define IWL_RATE_SCALE_FLUSH_INTVL   (2*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
};

C
Christoph Hellwig 已提交
67
struct iwl4965_rate {
Z
Zhu Yi 已提交
68 69 70
	u32 rate_n_flags;
} __attribute__ ((packed));

71 72 73
/**
 * struct iwl4965_rate_scale_data -- tx success history for one rate
 */
C
Christoph Hellwig 已提交
74
struct iwl4965_rate_scale_data {
75 76 77 78 79
	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 已提交
80 81 82
	unsigned long stamp;
};

83 84 85 86 87 88
/**
 * struct iwl4965_scale_tbl_info -- tx params and success history for all rates
 *
 * There are two of these in struct iwl_rate_scale_priv,
 * one for "active", and one for "search".
 */
C
Christoph Hellwig 已提交
89 90 91
struct iwl4965_scale_tbl_info {
	enum iwl4965_table_type lq_type;
	enum iwl4965_antenna_type antenna_type;
92 93 94 95 96 97 98
	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_* */
	s32 *expected_tpt;	/* throughput metrics; expected_tpt_G, etc. */
	struct iwl4965_rate current_rate;  /* rate_n_flags, uCode API format */
	struct iwl4965_rate_scale_data win[IWL_RATE_COUNT]; /* rate histories */
Z
Zhu Yi 已提交
99 100
};

101 102 103 104 105
/**
 * struct iwl_rate_scale_priv -- driver's rate scaling private structure
 *
 * Pointer to this gets passed back and forth between driver and mac80211.
 */
C
Christoph Hellwig 已提交
106
struct iwl4965_rate_scale_priv {
107 108 109 110
	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 已提交
111
	s32 last_tpt;
112 113

	/* The following determine when to search for a new mode */
Z
Zhu Yi 已提交
114
	u32 table_count_limit;
115 116
	u32 max_failure_limit;	/* # failed frames before new search */
	u32 max_success_limit;	/* # successful frames before new search */
Z
Zhu Yi 已提交
117
	u32 table_count;
118 119 120 121 122
	u32 total_failed;	/* total failed frames, any/all rates */
	u32 total_success;	/* total successful frames, any/all rates */
	u32 flush_timer;	/* time staying in mode before new search */

	u8 action_counter;	/* # mode-switch actions tried */
Z
Zhu Yi 已提交
123 124 125 126 127 128
	u8 antenna;
	u8 valid_antenna;
	u8 is_green;
	u8 is_dup;
	u8 phymode;
	u8 ibss_sta_added;
129 130

	/* The following are bitmaps of rates; IWL_RATE_6M_MASK, etc. */
131
	u32 supp_rates;
Z
Zhu Yi 已提交
132 133 134 135
	u16 active_rate;
	u16 active_siso_rate;
	u16 active_mimo_rate;
	u16 active_rate_basic;
136

C
Christoph Hellwig 已提交
137
	struct iwl4965_link_quality_cmd lq;
138
	struct iwl4965_scale_tbl_info lq_info[LQ_SIZE]; /* "active", "search" */
139
#ifdef CONFIG_MAC80211_DEBUGFS
140
	struct dentry *rs_sta_dbgfs_scale_table_file;
141
	struct dentry *rs_sta_dbgfs_stats_table_file;
C
Christoph Hellwig 已提交
142 143
	struct iwl4965_rate dbg_fixed;
	struct iwl4965_priv *drv;
144
#endif
Z
Zhu Yi 已提交
145 146
};

C
Christoph Hellwig 已提交
147
static void rs_rate_scale_perform(struct iwl4965_priv *priv,
Z
Zhu Yi 已提交
148 149 150
				   struct net_device *dev,
				   struct ieee80211_hdr *hdr,
				   struct sta_info *sta);
C
Christoph Hellwig 已提交
151 152 153
static void rs_fill_link_cmd(struct iwl4965_rate_scale_priv *lq_data,
			     struct iwl4965_rate *tx_mcs,
			     struct iwl4965_link_quality_cmd *tbl);
Z
Zhu Yi 已提交
154 155


156
#ifdef CONFIG_MAC80211_DEBUGFS
C
Christoph Hellwig 已提交
157 158
static void rs_dbgfs_set_mcs(struct iwl4965_rate_scale_priv *rs_priv,
				struct iwl4965_rate *mcs, int index);
159
#else
C
Christoph Hellwig 已提交
160 161
static void rs_dbgfs_set_mcs(struct iwl4965_rate_scale_priv *rs_priv,
				struct iwl4965_rate *mcs, int index)
162 163
{}
#endif
164 165 166 167 168 169

/*
 * 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).
 */
Z
Zhu Yi 已提交
170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
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
};

static s32 expected_tpt_mimo20MHz[IWL_RATE_COUNT] = {
	0, 0, 0, 0, 74, 74, 123, 155, 179, 214, 236, 244, 251
};

static s32 expected_tpt_mimo20MHzSGI[IWL_RATE_COUNT] = {
	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
};

static s32 expected_tpt_mimo40MHz[IWL_RATE_COUNT] = {
	0, 0, 0, 0, 123, 123, 182, 214, 235, 264, 279, 285, 289
};

static s32 expected_tpt_mimo40MHzSGI[IWL_RATE_COUNT] = {
	0, 0, 0, 0, 131, 131, 191, 222, 242, 270, 284, 289, 293
};

C
Christoph Hellwig 已提交
210 211
static int iwl4965_lq_sync_callback(struct iwl4965_priv *priv,
				struct iwl4965_cmd *cmd, struct sk_buff *skb)
Z
Zhu Yi 已提交
212 213 214 215 216
{
	/*We didn't cache the SKB; let the caller free it */
	return 1;
}

C
Christoph Hellwig 已提交
217
static inline u8 iwl4965_rate_get_rate(u32 rate_n_flags)
Z
Zhu Yi 已提交
218 219 220 221
{
	return (u8)(rate_n_flags & 0xFF);
}

C
Christoph Hellwig 已提交
222 223
static int rs_send_lq_cmd(struct iwl4965_priv *priv,
			  struct iwl4965_link_quality_cmd *lq, u8 flags)
Z
Zhu Yi 已提交
224
{
225
#ifdef CONFIG_IWL4965_DEBUG
Z
Zhu Yi 已提交
226 227
	int i;
#endif
C
Christoph Hellwig 已提交
228
	struct iwl4965_host_cmd cmd = {
Z
Zhu Yi 已提交
229
		.id = REPLY_TX_LINK_QUALITY_CMD,
C
Christoph Hellwig 已提交
230
		.len = sizeof(struct iwl4965_link_quality_cmd),
Z
Zhu Yi 已提交
231 232 233 234 235 236
		.meta.flags = flags,
		.data = lq,
	};

	if ((lq->sta_id == 0xFF) &&
	    (priv->iw_mode == IEEE80211_IF_TYPE_IBSS))
237
		return -EINVAL;
Z
Zhu Yi 已提交
238 239 240 241 242 243 244 245

	if (lq->sta_id == 0xFF)
		lq->sta_id = IWL_AP_ID;

	IWL_DEBUG_RATE("lq station id 0x%x\n", lq->sta_id);
	IWL_DEBUG_RATE("lq dta 0x%X 0x%X\n",
		       lq->general_params.single_stream_ant_msk,
		       lq->general_params.dual_stream_ant_msk);
246
#ifdef CONFIG_IWL4965_DEBUG
Z
Zhu Yi 已提交
247 248 249 250 251 252
	for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++)
		IWL_DEBUG_RATE("lq index %d 0x%X\n",
				i, lq->rs_table[i].rate_n_flags);
#endif

	if (flags & CMD_ASYNC)
C
Christoph Hellwig 已提交
253
		cmd.meta.u.callback = iwl4965_lq_sync_callback;
Z
Zhu Yi 已提交
254

C
Christoph Hellwig 已提交
255
	if (iwl4965_is_associated(priv) && priv->assoc_station_added &&
Z
Zhu Yi 已提交
256
	    priv->lq_mngr.lq_ready)
C
Christoph Hellwig 已提交
257
		return  iwl4965_send_cmd(priv, &cmd);
Z
Zhu Yi 已提交
258

259
	return 0;
Z
Zhu Yi 已提交
260 261
}

C
Christoph Hellwig 已提交
262
static void rs_rate_scale_clear_window(struct iwl4965_rate_scale_data *window)
Z
Zhu Yi 已提交
263 264 265 266 267 268 269 270 271
{
	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;
}

272 273 274 275 276 277 278
/**
 * 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.
 */
C
Christoph Hellwig 已提交
279
static int rs_collect_tx_data(struct iwl4965_rate_scale_data *windows,
Z
Zhu Yi 已提交
280 281
			      int scale_index, s32 tpt, u32 status)
{
C
Christoph Hellwig 已提交
282
	struct iwl4965_rate_scale_data *window = NULL;
Z
Zhu Yi 已提交
283 284 285 286
	u64 mask;
	u8 win_size = IWL_RATE_MAX_WINDOW;
	s32 fail_count;

287 288
	if (scale_index < 0 || scale_index >= IWL_RATE_COUNT)
		return -EINVAL;
Z
Zhu Yi 已提交
289

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

293 294 295 296 297 298 299 300
	/*
	 * 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!).
	 */
Z
Zhu Yi 已提交
301 302 303 304 305 306 307 308 309 310
	if (window->counter >= win_size) {
		window->counter = win_size - 1;
		mask = 1;
		mask = (mask << (win_size - 1));
		if ((window->data & mask)) {
			window->data &= ~mask;
			window->success_counter = window->success_counter - 1;
		}
	}

311
	/* Increment frames-attempted counter */
Z
Zhu Yi 已提交
312
	window->counter = window->counter + 1;
313 314 315

	/* Shift bitmap by one frame (throw away oldest history),
	 * OR in "1", and increment "success" if this frame was successful. */
Z
Zhu Yi 已提交
316 317 318 319 320 321 322
	mask = window->data;
	window->data = (mask << 1);
	if (status != 0) {
		window->success_counter = window->success_counter + 1;
		window->data |= 0x1;
	}

323
	/* Calculate current success ratio, avoid divide-by-0! */
Z
Zhu Yi 已提交
324 325 326 327 328 329 330 331
	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;

332
	/* Calculate average throughput, if we have enough history. */
Z
Zhu Yi 已提交
333 334 335 336 337 338
	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;

339
	/* Tag this window as having been updated */
Z
Zhu Yi 已提交
340 341
	window->stamp = jiffies;

342
	return 0;
Z
Zhu Yi 已提交
343 344
}

345 346 347
/*
 * Fill uCode API rate_n_flags field, based on "search" or "active" table.
 */
C
Christoph Hellwig 已提交
348 349
static void rs_mcs_from_tbl(struct iwl4965_rate *mcs_rate,
			   struct iwl4965_scale_tbl_info *tbl,
Z
Zhu Yi 已提交
350 351 352
			   int index, u8 use_green)
{
	if (is_legacy(tbl->lq_type)) {
C
Christoph Hellwig 已提交
353
		mcs_rate->rate_n_flags = iwl4965_rates[index].plcp;
Z
Zhu Yi 已提交
354 355 356 357 358 359
		if (index >= IWL_FIRST_CCK_RATE && index <= IWL_LAST_CCK_RATE)
			mcs_rate->rate_n_flags |= RATE_MCS_CCK_MSK;

	} else if (is_siso(tbl->lq_type)) {
		if (index > IWL_LAST_OFDM_RATE)
			index = IWL_LAST_OFDM_RATE;
C
Christoph Hellwig 已提交
360
		 mcs_rate->rate_n_flags = iwl4965_rates[index].plcp_siso |
Z
Zhu Yi 已提交
361 362 363 364
					  RATE_MCS_HT_MSK;
	} else {
		if (index > IWL_LAST_OFDM_RATE)
			index = IWL_LAST_OFDM_RATE;
C
Christoph Hellwig 已提交
365
		mcs_rate->rate_n_flags = iwl4965_rates[index].plcp_mimo |
Z
Zhu Yi 已提交
366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383
					 RATE_MCS_HT_MSK;
	}

	switch (tbl->antenna_type) {
	case ANT_BOTH:
		mcs_rate->rate_n_flags |= RATE_MCS_ANT_AB_MSK;
		break;
	case ANT_MAIN:
		mcs_rate->rate_n_flags |= RATE_MCS_ANT_A_MSK;
		break;
	case ANT_AUX:
		mcs_rate->rate_n_flags |= RATE_MCS_ANT_B_MSK;
		break;
	case ANT_NONE:
		break;
	}

	if (is_legacy(tbl->lq_type))
384
		return;
Z
Zhu Yi 已提交
385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401

	if (tbl->is_fat) {
		if (tbl->is_dup)
			mcs_rate->rate_n_flags |= RATE_MCS_DUP_MSK;
		else
			mcs_rate->rate_n_flags |= RATE_MCS_FAT_MSK;
	}
	if (tbl->is_SGI)
		mcs_rate->rate_n_flags |= RATE_MCS_SGI_MSK;

	if (use_green) {
		mcs_rate->rate_n_flags |= RATE_MCS_GF_MSK;
		if (is_siso(tbl->lq_type))
			mcs_rate->rate_n_flags &= ~RATE_MCS_SGI_MSK;
	}
}

402 403 404 405
/*
 * Interpret uCode API's rate_n_flags format,
 * fill "search" or "active" tx mode table.
 */
C
Christoph Hellwig 已提交
406 407
static int rs_get_tbl_info_from_mcs(const struct iwl4965_rate *mcs_rate,
				    int phymode, struct iwl4965_scale_tbl_info *tbl,
Z
Zhu Yi 已提交
408 409 410 411 412
				    int *rate_idx)
{
	int index;
	u32 ant_msk;

C
Christoph Hellwig 已提交
413
	index = iwl4965_rate_index_from_plcp(mcs_rate->rate_n_flags);
Z
Zhu Yi 已提交
414 415 416

	if (index  == IWL_RATE_INVALID) {
		*rate_idx = -1;
417
		return -EINVAL;
Z
Zhu Yi 已提交
418
	}
419
	tbl->is_SGI = 0;	/* default legacy setup */
Z
Zhu Yi 已提交
420 421
	tbl->is_fat = 0;
	tbl->is_dup = 0;
422
	tbl->antenna_type = ANT_BOTH;	/* default MIMO setup */
Z
Zhu Yi 已提交
423

424
	/* legacy rate format */
Z
Zhu Yi 已提交
425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443
	if (!(mcs_rate->rate_n_flags & RATE_MCS_HT_MSK)) {
		ant_msk = (mcs_rate->rate_n_flags & RATE_MCS_ANT_AB_MSK);

		if (ant_msk == RATE_MCS_ANT_AB_MSK)
			tbl->lq_type = LQ_NONE;
		else {

			if (phymode == MODE_IEEE80211A)
				tbl->lq_type = LQ_A;
			else
				tbl->lq_type = LQ_G;

			if (mcs_rate->rate_n_flags & RATE_MCS_ANT_A_MSK)
				tbl->antenna_type = ANT_MAIN;
			else
				tbl->antenna_type = ANT_AUX;
		}
		*rate_idx = index;

444
	/* HT rate format, SISO (might be 20 MHz legacy or 40 MHz fat width) */
C
Christoph Hellwig 已提交
445
	} else if (iwl4965_rate_get_rate(mcs_rate->rate_n_flags)
Z
Zhu Yi 已提交
446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468
					<= IWL_RATE_SISO_60M_PLCP) {
		tbl->lq_type = LQ_SISO;

		ant_msk = (mcs_rate->rate_n_flags & RATE_MCS_ANT_AB_MSK);
		if (ant_msk == RATE_MCS_ANT_AB_MSK)
			tbl->lq_type = LQ_NONE;
		else {
			if (mcs_rate->rate_n_flags & RATE_MCS_ANT_A_MSK)
				tbl->antenna_type = ANT_MAIN;
			else
				tbl->antenna_type = ANT_AUX;
		}
		if (mcs_rate->rate_n_flags & RATE_MCS_SGI_MSK)
			tbl->is_SGI = 1;

		if ((mcs_rate->rate_n_flags & RATE_MCS_FAT_MSK) ||
		    (mcs_rate->rate_n_flags & RATE_MCS_DUP_MSK))
			tbl->is_fat = 1;

		if (mcs_rate->rate_n_flags & RATE_MCS_DUP_MSK)
			tbl->is_dup = 1;

		*rate_idx = index;
469 470

	/* HT rate format, MIMO (might be 20 MHz legacy or 40 MHz fat width) */
Z
Zhu Yi 已提交
471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486
	} else {
		tbl->lq_type = LQ_MIMO;
		if (mcs_rate->rate_n_flags & RATE_MCS_SGI_MSK)
			tbl->is_SGI = 1;

		if ((mcs_rate->rate_n_flags & RATE_MCS_FAT_MSK) ||
		    (mcs_rate->rate_n_flags & RATE_MCS_DUP_MSK))
			tbl->is_fat = 1;

		if (mcs_rate->rate_n_flags & RATE_MCS_DUP_MSK)
			tbl->is_dup = 1;
		*rate_idx = index;
	}
	return 0;
}

C
Christoph Hellwig 已提交
487 488
static inline void rs_toggle_antenna(struct iwl4965_rate *new_rate,
				     struct iwl4965_scale_tbl_info *tbl)
Z
Zhu Yi 已提交
489 490 491 492 493 494 495 496 497 498 499 500
{
	if (tbl->antenna_type == ANT_AUX) {
		tbl->antenna_type = ANT_MAIN;
		new_rate->rate_n_flags &= ~RATE_MCS_ANT_B_MSK;
		new_rate->rate_n_flags |= RATE_MCS_ANT_A_MSK;
	} else {
		tbl->antenna_type = ANT_AUX;
		new_rate->rate_n_flags &= ~RATE_MCS_ANT_A_MSK;
		new_rate->rate_n_flags |= RATE_MCS_ANT_B_MSK;
	}
}

C
Christoph Hellwig 已提交
501
static inline u8 rs_use_green(struct iwl4965_priv *priv)
Z
Zhu Yi 已提交
502
{
503
#ifdef CONFIG_IWL4965_HT
Z
Zhu Yi 已提交
504 505 506
	if (!priv->is_ht_enabled || !priv->current_assoc_ht.is_ht)
		return 0;

507 508
	return ((priv->current_assoc_ht.is_green_field) &&
	    !(priv->current_assoc_ht.operating_mode & 0x4));
509
#endif	/*CONFIG_IWL4965_HT */
510
	return 0;
Z
Zhu Yi 已提交
511 512 513 514 515 516 517 518 519
}

/**
 * rs_get_supported_rates - get the available rates
 *
 * if management frame or broadcast frame only return
 * basic available rates.
 *
 */
C
Christoph Hellwig 已提交
520
static void rs_get_supported_rates(struct iwl4965_rate_scale_priv *lq_data,
Z
Zhu Yi 已提交
521
				   struct ieee80211_hdr *hdr,
C
Christoph Hellwig 已提交
522
				   enum iwl4965_table_type rate_type,
Z
Zhu Yi 已提交
523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543
				   u16 *data_rate)
{
	if (is_legacy(rate_type))
		*data_rate = lq_data->active_rate;
	else {
		if (is_siso(rate_type))
			*data_rate = lq_data->active_siso_rate;
		else
			*data_rate = lq_data->active_mimo_rate;
	}

	if (hdr && is_multicast_ether_addr(hdr->addr1) &&
	    lq_data->active_rate_basic)
		*data_rate = lq_data->active_rate_basic;
}

static u16 rs_get_adjacent_rate(u8 index, u16 rate_mask, int rate_type)
{
	u8 high = IWL_RATE_INVALID;
	u8 low = IWL_RATE_INVALID;

544
	/* 802.11A or ht walks to the next literal adjacent rate in
Z
Zhu Yi 已提交
545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572
	 * 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) {
C
Christoph Hellwig 已提交
573
		low = iwl4965_rates[low].prev_rs;
Z
Zhu Yi 已提交
574 575 576 577 578 579 580 581 582
		if (low == IWL_RATE_INVALID)
			break;
		if (rate_mask & (1 << low))
			break;
		IWL_DEBUG_RATE("Skipping masked lower rate: %d\n", low);
	}

	high = index;
	while (high != IWL_RATE_INVALID) {
C
Christoph Hellwig 已提交
583
		high = iwl4965_rates[high].next_rs;
Z
Zhu Yi 已提交
584 585 586 587 588 589 590 591 592 593
		if (high == IWL_RATE_INVALID)
			break;
		if (rate_mask & (1 << high))
			break;
		IWL_DEBUG_RATE("Skipping masked higher rate: %d\n", high);
	}

	return (high << 8) | low;
}

C
Christoph Hellwig 已提交
594 595 596
static void rs_get_lower_rate(struct iwl4965_rate_scale_priv *lq_data,
			     struct iwl4965_scale_tbl_info *tbl, u8 scale_index,
			     u8 ht_possible, struct iwl4965_rate *mcs_rate)
Z
Zhu Yi 已提交
597 598 599 600 601
{
	s32 low;
	u16 rate_mask;
	u16 high_low;
	u8 switch_to_legacy = 0;
602
	u8 is_green = lq_data->is_green;
Z
Zhu Yi 已提交
603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624

	/* 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];
		if (lq_data->phymode == MODE_IEEE80211A)
			tbl->lq_type = LQ_A;
		else
			tbl->lq_type = LQ_G;

		if ((tbl->antenna_type == ANT_BOTH) ||
		    (tbl->antenna_type == ANT_NONE))
			tbl->antenna_type = ANT_MAIN;

		tbl->is_fat = 0;
		tbl->is_SGI = 0;
	}

	rs_get_supported_rates(lq_data, NULL, tbl->lq_type, &rate_mask);

625
	/* Mask with station rate restriction */
Z
Zhu Yi 已提交
626
	if (is_legacy(tbl->lq_type)) {
627
		/* supp_rates has no CCK bits in A mode */
Z
Zhu Yi 已提交
628 629
		if (lq_data->phymode == (u8) MODE_IEEE80211A)
			rate_mask  = (u16)(rate_mask &
630
			   (lq_data->supp_rates << IWL_FIRST_OFDM_RATE));
Z
Zhu Yi 已提交
631
		else
632
			rate_mask = (u16)(rate_mask & lq_data->supp_rates);
Z
Zhu Yi 已提交
633 634
	}

635
	/* If we switched from HT to legacy, check current rate */
636
	if (switch_to_legacy && (rate_mask & (1 << scale_index))) {
Z
Zhu Yi 已提交
637
		rs_mcs_from_tbl(mcs_rate, tbl, scale_index, is_green);
638
		return;
Z
Zhu Yi 已提交
639 640 641 642 643 644 645 646 647 648 649
	}

	high_low = rs_get_adjacent_rate(scale_index, rate_mask, tbl->lq_type);
	low = high_low & 0xff;

	if (low != IWL_RATE_INVALID)
		rs_mcs_from_tbl(mcs_rate, tbl, low, is_green);
	else
		rs_mcs_from_tbl(mcs_rate, tbl, scale_index, is_green);
}

650 651 652
/*
 * mac80211 sends us Tx status
 */
Z
Zhu Yi 已提交
653 654 655 656 657 658 659 660
static void rs_tx_status(void *priv_rate,
			 struct net_device *dev,
			 struct sk_buff *skb,
			 struct ieee80211_tx_status *tx_resp)
{
	int status;
	u8 retries;
	int rs_index, index = 0;
C
Christoph Hellwig 已提交
661 662
	struct iwl4965_rate_scale_priv *lq;
	struct iwl4965_link_quality_cmd *table;
Z
Zhu Yi 已提交
663 664
	struct sta_info *sta;
	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
C
Christoph Hellwig 已提交
665
	struct iwl4965_priv *priv = (struct iwl4965_priv *)priv_rate;
Z
Zhu Yi 已提交
666
	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
C
Christoph Hellwig 已提交
667 668 669 670 671
	struct iwl4965_rate_scale_data *window = NULL;
	struct iwl4965_rate_scale_data *search_win = NULL;
	struct iwl4965_rate tx_mcs;
	struct iwl4965_scale_tbl_info tbl_type;
	struct iwl4965_scale_tbl_info *curr_tbl, *search_tbl;
Z
Zhu Yi 已提交
672 673 674 675
	u8 active_index = 0;
	u16 fc = le16_to_cpu(hdr->frame_control);
	s32 tpt = 0;

676
	IWL_DEBUG_RATE_LIMIT("get frame ack response, update rate scale window\n");
Z
Zhu Yi 已提交
677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694

	if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1))
		return;

	retries = tx_resp->retry_count;

	if (retries > 15)
		retries = 15;


	sta = sta_info_get(local, hdr->addr1);

	if (!sta || !sta->rate_ctrl_priv) {
		if (sta)
			sta_info_put(sta);
		return;
	}

C
Christoph Hellwig 已提交
695
	lq = (struct iwl4965_rate_scale_priv *)sta->rate_ctrl_priv;
Z
Zhu Yi 已提交
696 697 698 699 700 701 702 703 704 705

	if (!priv->lq_mngr.lq_ready)
		return;

	if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) && !lq->ibss_sta_added)
		return;

	table = &lq->lq;
	active_index = lq->active_tbl;

706
	/* Get mac80211 antenna info */
Z
Zhu Yi 已提交
707 708 709 710
	lq->antenna = (lq->valid_antenna & local->hw.conf.antenna_sel_tx);
	if (!lq->antenna)
		lq->antenna = lq->valid_antenna;

711
	/* Ignore mac80211 antenna info for now */
Z
Zhu Yi 已提交
712
	lq->antenna = lq->valid_antenna;
713

Z
Zhu Yi 已提交
714 715
	curr_tbl = &(lq->lq_info[active_index]);
	search_tbl = &(lq->lq_info[(1 - active_index)]);
C
Christoph Hellwig 已提交
716
	window = (struct iwl4965_rate_scale_data *)
Z
Zhu Yi 已提交
717
	    &(curr_tbl->win[0]);
C
Christoph Hellwig 已提交
718
	search_win = (struct iwl4965_rate_scale_data *)
Z
Zhu Yi 已提交
719 720 721 722 723 724 725 726 727 728 729 730 731
	    &(search_tbl->win[0]);

	tx_mcs.rate_n_flags = tx_resp->control.tx_rate;

	rs_get_tbl_info_from_mcs(&tx_mcs, priv->phymode,
				  &tbl_type, &rs_index);
	if ((rs_index < 0) || (rs_index >= IWL_RATE_COUNT)) {
		IWL_DEBUG_RATE("bad rate index at: %d rate 0x%X\n",
			     rs_index, tx_mcs.rate_n_flags);
		sta_info_put(sta);
		return;
	}

732 733 734 735 736 737 738 739
	/*
	 * 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).
	 */
Z
Zhu Yi 已提交
740 741 742 743 744 745 746 747 748 749
	if (retries &&
	    (tx_mcs.rate_n_flags !=
				le32_to_cpu(table->rs_table[0].rate_n_flags))) {
		IWL_DEBUG_RATE("initial rate does not match 0x%x 0x%x\n",
				tx_mcs.rate_n_flags,
				le32_to_cpu(table->rs_table[0].rate_n_flags));
		sta_info_put(sta);
		return;
	}

750
	/* Update frame history window with "failure" for each Tx retry. */
Z
Zhu Yi 已提交
751
	while (retries) {
752 753
		/* Look up the rate and other info used for each tx attempt.
		 * Each tx attempt steps one entry deeper in the rate table. */
Z
Zhu Yi 已提交
754 755 756 757 758
		tx_mcs.rate_n_flags =
		    le32_to_cpu(table->rs_table[index].rate_n_flags);
		rs_get_tbl_info_from_mcs(&tx_mcs, priv->phymode,
					  &tbl_type, &rs_index);

759 760
		/* If type matches "search" table,
		 * add failure to "search" history */
Z
Zhu Yi 已提交
761 762 763 764 765 766 767
		if ((tbl_type.lq_type == search_tbl->lq_type) &&
		    (tbl_type.antenna_type == search_tbl->antenna_type) &&
		    (tbl_type.is_SGI == search_tbl->is_SGI)) {
			if (search_tbl->expected_tpt)
				tpt = search_tbl->expected_tpt[rs_index];
			else
				tpt = 0;
768 769 770 771
			rs_collect_tx_data(search_win, rs_index, tpt, 0);

		/* Else if type matches "current/active" table,
		 * add failure to "current/active" history */
Z
Zhu Yi 已提交
772 773 774 775 776 777 778 779 780
		} else if ((tbl_type.lq_type == curr_tbl->lq_type) &&
			   (tbl_type.antenna_type == curr_tbl->antenna_type) &&
			   (tbl_type.is_SGI == curr_tbl->is_SGI)) {
			if (curr_tbl->expected_tpt)
				tpt = curr_tbl->expected_tpt[rs_index];
			else
				tpt = 0;
			rs_collect_tx_data(window, rs_index, tpt, 0);
		}
781 782 783

		/* If not searching for a new mode, increment failed counter
		 * ... this helps determine when to start searching again */
Z
Zhu Yi 已提交
784 785 786 787 788 789 790
		if (lq->stay_in_tbl)
			lq->total_failed++;
		--retries;
		index++;

	}

791 792 793 794 795
	/*
	 * 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.
	 */
Z
Zhu Yi 已提交
796 797 798 799 800 801 802 803 804
	if (!tx_resp->retry_count)
		tx_mcs.rate_n_flags = tx_resp->control.tx_rate;
	else
		tx_mcs.rate_n_flags =
			le32_to_cpu(table->rs_table[index].rate_n_flags);

	rs_get_tbl_info_from_mcs(&tx_mcs, priv->phymode,
				  &tbl_type, &rs_index);

805
	/* Update frame history window with "success" if Tx got ACKed ... */
Z
Zhu Yi 已提交
806 807 808 809 810
	if (tx_resp->flags & IEEE80211_TX_STATUS_ACK)
		status = 1;
	else
		status = 0;

811 812
	/* If type matches "search" table,
	 * add final tx status to "search" history */
Z
Zhu Yi 已提交
813 814 815 816 817 818 819 820 821
	if ((tbl_type.lq_type == search_tbl->lq_type) &&
	    (tbl_type.antenna_type == search_tbl->antenna_type) &&
	    (tbl_type.is_SGI == search_tbl->is_SGI)) {
		if (search_tbl->expected_tpt)
			tpt = search_tbl->expected_tpt[rs_index];
		else
			tpt = 0;
		rs_collect_tx_data(search_win,
				    rs_index, tpt, status);
822 823 824

	/* Else if type matches "current/active" table,
	 * add final tx status to "current/active" history */
Z
Zhu Yi 已提交
825 826 827 828 829 830 831 832 833 834
	} else if ((tbl_type.lq_type == curr_tbl->lq_type) &&
		   (tbl_type.antenna_type == curr_tbl->antenna_type) &&
		   (tbl_type.is_SGI == curr_tbl->is_SGI)) {
		if (curr_tbl->expected_tpt)
			tpt = curr_tbl->expected_tpt[rs_index];
		else
			tpt = 0;
		rs_collect_tx_data(window, rs_index, tpt, status);
	}

835 836
	/* If not searching for new mode, increment success/failed counter
	 * ... these help determine when to start searching again */
Z
Zhu Yi 已提交
837 838 839 840 841 842 843
	if (lq->stay_in_tbl) {
		if (status)
			lq->total_success++;
		else
			lq->total_failed++;
	}

844
	/* See if there's a better rate or modulation mode to try. */
Z
Zhu Yi 已提交
845 846 847 848 849 850
	rs_rate_scale_perform(priv, dev, hdr, sta);
	sta_info_put(sta);
	return;
}

static u8 rs_is_ant_connected(u8 valid_antenna,
C
Christoph Hellwig 已提交
851
			      enum iwl4965_antenna_type antenna_type)
Z
Zhu Yi 已提交
852 853 854 855 856
{
	if (antenna_type == ANT_AUX)
		return ((valid_antenna & 0x2) ? 1:0);
	else if (antenna_type == ANT_MAIN)
		return ((valid_antenna & 0x1) ? 1:0);
857 858
	else if (antenna_type == ANT_BOTH)
		return ((valid_antenna & 0x3) == 0x3);
Z
Zhu Yi 已提交
859 860 861 862 863

	return 1;
}

static u8 rs_is_other_ant_connected(u8 valid_antenna,
C
Christoph Hellwig 已提交
864
				    enum iwl4965_antenna_type antenna_type)
Z
Zhu Yi 已提交
865 866
{
	if (antenna_type == ANT_AUX)
867
		return rs_is_ant_connected(valid_antenna, ANT_MAIN);
Z
Zhu Yi 已提交
868
	else
869
		return rs_is_ant_connected(valid_antenna, ANT_AUX);
Z
Zhu Yi 已提交
870 871 872 873

	return 0;
}

874 875 876 877 878 879 880 881
/*
 * 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.
 */
Z
Zhu Yi 已提交
882
static void rs_set_stay_in_table(u8 is_legacy,
C
Christoph Hellwig 已提交
883
				 struct iwl4965_rate_scale_priv *lq_data)
Z
Zhu Yi 已提交
884 885
{
	IWL_DEBUG_HT("we are staying in the same table\n");
886
	lq_data->stay_in_tbl = 1;	/* only place this gets set */
Z
Zhu Yi 已提交
887 888 889
	if (is_legacy) {
		lq_data->table_count_limit = IWL_LEGACY_TABLE_COUNT;
		lq_data->max_failure_limit = IWL_LEGACY_FAILURE_LIMIT;
890
		lq_data->max_success_limit = IWL_LEGACY_SUCCESS_LIMIT;
Z
Zhu Yi 已提交
891 892 893 894 895 896 897 898 899 900
	} else {
		lq_data->table_count_limit = IWL_NONE_LEGACY_TABLE_COUNT;
		lq_data->max_failure_limit = IWL_NONE_LEGACY_FAILURE_LIMIT;
		lq_data->max_success_limit = IWL_NONE_LEGACY_SUCCESS_LIMIT;
	}
	lq_data->table_count = 0;
	lq_data->total_failed = 0;
	lq_data->total_success = 0;
}

901 902 903
/*
 * Find correct throughput table for given mode of modulation
 */
C
Christoph Hellwig 已提交
904 905
static void rs_get_expected_tpt_table(struct iwl4965_rate_scale_priv *lq_data,
				      struct iwl4965_scale_tbl_info *tbl)
Z
Zhu Yi 已提交
906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936
{
	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)) {
		if (tbl->is_fat && !lq_data->is_dup)
			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;

	} else if (is_mimo(tbl->lq_type)) {
		if (tbl->is_fat && !lq_data->is_dup)
			if (tbl->is_SGI)
				tbl->expected_tpt = expected_tpt_mimo40MHzSGI;
			else
				tbl->expected_tpt = expected_tpt_mimo40MHz;
		else if (tbl->is_SGI)
			tbl->expected_tpt = expected_tpt_mimo20MHzSGI;
		else
			tbl->expected_tpt = expected_tpt_mimo20MHz;
	} else
		tbl->expected_tpt = expected_tpt_G;
}

937
#ifdef CONFIG_IWL4965_HT
938 939 940 941 942 943 944 945 946 947 948 949
/*
 * 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.
 */
C
Christoph Hellwig 已提交
950 951
static s32 rs_get_best_rate(struct iwl4965_priv *priv,
			    struct iwl4965_rate_scale_priv *lq_data,
952
			    struct iwl4965_scale_tbl_info *tbl,	/* "search" */
Z
Zhu Yi 已提交
953 954
			    u16 rate_mask, s8 index, s8 rate)
{
955
	/* "active" values */
C
Christoph Hellwig 已提交
956
	struct iwl4965_scale_tbl_info *active_tbl =
Z
Zhu Yi 已提交
957 958 959
	    &(lq_data->lq_info[lq_data->active_tbl]);
	s32 active_sr = active_tbl->win[index].success_ratio;
	s32 active_tpt = active_tbl->expected_tpt[index];
960 961 962 963 964

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

	s32 new_rate, high, low, start_hi;
Z
Zhu Yi 已提交
965 966 967 968 969 970 971 972 973 974
	u16 high_low;

	new_rate = high = low = start_hi = IWL_RATE_INVALID;

	for (; ;) {
		high_low = rs_get_adjacent_rate(rate, rate_mask, tbl->lq_type);

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

975 976 977 978 979 980 981 982 983 984 985 986 987 988 989
		/*
		 * 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).
		 */
Z
Zhu Yi 已提交
990 991 992 993 994 995 996
		if ((((100 * tpt_tbl[rate]) > lq_data->last_tpt) &&
		     ((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))) {

997 998 999
			/* (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 已提交
1000 1001 1002 1003
			if (start_hi != IWL_RATE_INVALID) {
				new_rate = start_hi;
				break;
			}
1004

Z
Zhu Yi 已提交
1005
			new_rate = rate;
1006 1007

			/* Loop again with lower rate */
Z
Zhu Yi 已提交
1008 1009
			if (low != IWL_RATE_INVALID)
				rate = low;
1010 1011

			/* Lower rate not available, use the original */
Z
Zhu Yi 已提交
1012 1013
			else
				break;
1014 1015

		/* Else try to raise the "search" rate to match "active" */
Z
Zhu Yi 已提交
1016
		} else {
1017 1018 1019
			/* (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 已提交
1020 1021
			if (new_rate != IWL_RATE_INVALID)
				break;
1022 1023

			/* Loop again with higher rate */
Z
Zhu Yi 已提交
1024 1025 1026
			else if (high != IWL_RATE_INVALID) {
				start_hi = high;
				rate = high;
1027 1028

			/* Higher rate not available, use the original */
Z
Zhu Yi 已提交
1029 1030 1031 1032 1033 1034 1035 1036 1037
			} else {
				new_rate = rate;
				break;
			}
		}
	}

	return new_rate;
}
1038
#endif				/* CONFIG_IWL4965_HT */
Z
Zhu Yi 已提交
1039 1040 1041 1042 1043 1044

static inline u8 rs_is_both_ant_supp(u8 valid_antenna)
{
	return (rs_is_ant_connected(valid_antenna, ANT_BOTH));
}

1045 1046 1047
/*
 * Set up search table for MIMO
 */
C
Christoph Hellwig 已提交
1048 1049 1050
static int rs_switch_to_mimo(struct iwl4965_priv *priv,
			     struct iwl4965_rate_scale_priv *lq_data,
			     struct iwl4965_scale_tbl_info *tbl, int index)
Z
Zhu Yi 已提交
1051
{
1052
#ifdef CONFIG_IWL4965_HT
Z
Zhu Yi 已提交
1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067
	u16 rate_mask;
	s32 rate;
	s8 is_green = lq_data->is_green;

	if (!priv->is_ht_enabled || !priv->current_assoc_ht.is_ht)
		return -1;

	IWL_DEBUG_HT("LQ: try to switch to MIMO\n");
	tbl->lq_type = LQ_MIMO;
	rs_get_supported_rates(lq_data, NULL, tbl->lq_type,
				&rate_mask);

	if (priv->current_assoc_ht.tx_mimo_ps_mode == IWL_MIMO_PS_STATIC)
		return -1;

1068
	/* Need both Tx chains/antennas to support MIMO */
Z
Zhu Yi 已提交
1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099
	if (!rs_is_both_ant_supp(lq_data->antenna))
		return -1;

	tbl->is_dup = lq_data->is_dup;
	tbl->action = 0;
	if (priv->current_channel_width == IWL_CHANNEL_WIDTH_40MHZ)
		tbl->is_fat = 1;
	else
		tbl->is_fat = 0;

	if (tbl->is_fat) {
		if (priv->current_assoc_ht.sgf & HT_SHORT_GI_40MHZ_ONLY)
			tbl->is_SGI = 1;
		else
			tbl->is_SGI = 0;
	} else if (priv->current_assoc_ht.sgf & HT_SHORT_GI_20MHZ_ONLY)
		tbl->is_SGI = 1;
	else
		tbl->is_SGI = 0;

	rs_get_expected_tpt_table(lq_data, tbl);

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

	IWL_DEBUG_HT("LQ: MIMO best rate %d mask %X\n", rate, rate_mask);
	if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask))
		return -1;
	rs_mcs_from_tbl(&tbl->current_rate, tbl, rate, is_green);

	IWL_DEBUG_HT("LQ: Switch to new mcs %X index is green %X\n",
		     tbl->current_rate.rate_n_flags, is_green);
1100
	return 0;
1101 1102 1103
#else
	return -1;
#endif				/*CONFIG_IWL4965_HT */
Z
Zhu Yi 已提交
1104 1105
}

1106 1107 1108
/*
 * Set up search table for SISO
 */
C
Christoph Hellwig 已提交
1109 1110 1111
static int rs_switch_to_siso(struct iwl4965_priv *priv,
			     struct iwl4965_rate_scale_priv *lq_data,
			     struct iwl4965_scale_tbl_info *tbl, int index)
Z
Zhu Yi 已提交
1112
{
1113
#ifdef CONFIG_IWL4965_HT
Z
Zhu Yi 已提交
1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157
	u16 rate_mask;
	u8 is_green = lq_data->is_green;
	s32 rate;

	IWL_DEBUG_HT("LQ: try to switch to SISO\n");
	if (!priv->is_ht_enabled || !priv->current_assoc_ht.is_ht)
		return -1;

	tbl->is_dup = lq_data->is_dup;
	tbl->lq_type = LQ_SISO;
	tbl->action = 0;
	rs_get_supported_rates(lq_data, NULL, tbl->lq_type,
				&rate_mask);

	if (priv->current_channel_width == IWL_CHANNEL_WIDTH_40MHZ)
		tbl->is_fat = 1;
	else
		tbl->is_fat = 0;

	if (tbl->is_fat) {
		if (priv->current_assoc_ht.sgf & HT_SHORT_GI_40MHZ_ONLY)
			tbl->is_SGI = 1;
		else
			tbl->is_SGI = 0;
	} else if (priv->current_assoc_ht.sgf & HT_SHORT_GI_20MHZ_ONLY)
		tbl->is_SGI = 1;
	else
		tbl->is_SGI = 0;

	if (is_green)
		tbl->is_SGI = 0;

	rs_get_expected_tpt_table(lq_data, tbl);
	rate = rs_get_best_rate(priv, lq_data, tbl, rate_mask, index, index);

	IWL_DEBUG_HT("LQ: get best rate %d mask %X\n", rate, rate_mask);
	if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask)) {
		IWL_DEBUG_HT("can not switch with index %d rate mask %x\n",
			     rate, rate_mask);
		return -1;
	}
	rs_mcs_from_tbl(&tbl->current_rate, tbl, rate, is_green);
	IWL_DEBUG_HT("LQ: Switch to new mcs %X index is green %X\n",
		     tbl->current_rate.rate_n_flags, is_green);
1158 1159 1160
	return 0;
#else
	return -1;
Z
Zhu Yi 已提交
1161

1162
#endif				/*CONFIG_IWL4965_HT */
Z
Zhu Yi 已提交
1163 1164
}

1165 1166 1167
/*
 * Try to switch to new modulation mode from legacy
 */
C
Christoph Hellwig 已提交
1168 1169
static int rs_move_legacy_other(struct iwl4965_priv *priv,
				struct iwl4965_rate_scale_priv *lq_data,
Z
Zhu Yi 已提交
1170 1171
				int index)
{
1172
	int ret = 0;
C
Christoph Hellwig 已提交
1173
	struct iwl4965_scale_tbl_info *tbl =
Z
Zhu Yi 已提交
1174
	    &(lq_data->lq_info[lq_data->active_tbl]);
C
Christoph Hellwig 已提交
1175
	struct iwl4965_scale_tbl_info *search_tbl =
Z
Zhu Yi 已提交
1176
	    &(lq_data->lq_info[(1 - lq_data->active_tbl)]);
C
Christoph Hellwig 已提交
1177 1178 1179
	struct iwl4965_rate_scale_data *window = &(tbl->win[index]);
	u32 sz = (sizeof(struct iwl4965_scale_tbl_info) -
		  (sizeof(struct iwl4965_rate_scale_data) * IWL_RATE_COUNT));
Z
Zhu Yi 已提交
1180 1181 1182 1183 1184 1185 1186 1187 1188
	u8 start_action = tbl->action;

	for (; ;) {
		switch (tbl->action) {
		case IWL_LEGACY_SWITCH_ANTENNA:
			IWL_DEBUG_HT("LQ Legacy switch Antenna\n");

			search_tbl->lq_type = LQ_NONE;
			lq_data->action_counter++;
1189 1190

			/* Don't change antenna if success has been great */
Z
Zhu Yi 已提交
1191 1192
			if (window->success_ratio >= IWL_RS_GOOD_RATIO)
				break;
1193 1194

			/* Don't change antenna if other one is not connected */
Z
Zhu Yi 已提交
1195 1196 1197 1198
			if (!rs_is_other_ant_connected(lq_data->antenna,
							tbl->antenna_type))
				break;

1199
			/* Set up search table to try other antenna */
Z
Zhu Yi 已提交
1200 1201 1202 1203 1204 1205 1206 1207 1208 1209
			memcpy(search_tbl, tbl, sz);

			rs_toggle_antenna(&(search_tbl->current_rate),
					   search_tbl);
			rs_get_expected_tpt_table(lq_data, search_tbl);
			lq_data->search_better_tbl = 1;
			goto out;

		case IWL_LEGACY_SWITCH_SISO:
			IWL_DEBUG_HT("LQ: Legacy switch to SISO\n");
1210 1211

			/* Set up search table to try SISO */
Z
Zhu Yi 已提交
1212 1213 1214 1215
			memcpy(search_tbl, tbl, sz);
			search_tbl->lq_type = LQ_SISO;
			search_tbl->is_SGI = 0;
			search_tbl->is_fat = 0;
1216
			ret = rs_switch_to_siso(priv, lq_data, search_tbl,
Z
Zhu Yi 已提交
1217
					       index);
1218
			if (!ret) {
Z
Zhu Yi 已提交
1219 1220 1221
				lq_data->search_better_tbl = 1;
				lq_data->action_counter = 0;
				goto out;
1222
			}
Z
Zhu Yi 已提交
1223 1224 1225 1226

			break;
		case IWL_LEGACY_SWITCH_MIMO:
			IWL_DEBUG_HT("LQ: Legacy switch MIMO\n");
1227 1228

			/* Set up search table to try MIMO */
Z
Zhu Yi 已提交
1229 1230 1231 1232 1233
			memcpy(search_tbl, tbl, sz);
			search_tbl->lq_type = LQ_MIMO;
			search_tbl->is_SGI = 0;
			search_tbl->is_fat = 0;
			search_tbl->antenna_type = ANT_BOTH;
1234
			ret = rs_switch_to_mimo(priv, lq_data, search_tbl,
Z
Zhu Yi 已提交
1235
					       index);
1236
			if (!ret) {
Z
Zhu Yi 已提交
1237 1238 1239
				lq_data->search_better_tbl = 1;
				lq_data->action_counter = 0;
				goto out;
1240
			}
Z
Zhu Yi 已提交
1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260
			break;
		}
		tbl->action++;
		if (tbl->action > IWL_LEGACY_SWITCH_MIMO)
			tbl->action = IWL_LEGACY_SWITCH_ANTENNA;

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

	}
	return 0;

 out:
	tbl->action++;
	if (tbl->action > IWL_LEGACY_SWITCH_MIMO)
		tbl->action = IWL_LEGACY_SWITCH_ANTENNA;
	return 0;

}

1261 1262 1263
/*
 * Try to switch to new modulation mode from SISO
 */
C
Christoph Hellwig 已提交
1264 1265
static int rs_move_siso_to_other(struct iwl4965_priv *priv,
				 struct iwl4965_rate_scale_priv *lq_data,
Z
Zhu Yi 已提交
1266 1267
				 int index)
{
1268
	int ret;
Z
Zhu Yi 已提交
1269
	u8 is_green = lq_data->is_green;
C
Christoph Hellwig 已提交
1270
	struct iwl4965_scale_tbl_info *tbl =
Z
Zhu Yi 已提交
1271
	    &(lq_data->lq_info[lq_data->active_tbl]);
C
Christoph Hellwig 已提交
1272
	struct iwl4965_scale_tbl_info *search_tbl =
Z
Zhu Yi 已提交
1273
	    &(lq_data->lq_info[(1 - lq_data->active_tbl)]);
C
Christoph Hellwig 已提交
1274 1275 1276
	struct iwl4965_rate_scale_data *window = &(tbl->win[index]);
	u32 sz = (sizeof(struct iwl4965_scale_tbl_info) -
		  (sizeof(struct iwl4965_rate_scale_data) * IWL_RATE_COUNT));
Z
Zhu Yi 已提交
1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305
	u8 start_action = tbl->action;

	for (;;) {
		lq_data->action_counter++;
		switch (tbl->action) {
		case IWL_SISO_SWITCH_ANTENNA:
			IWL_DEBUG_HT("LQ: SISO SWITCH ANTENNA SISO\n");
			search_tbl->lq_type = LQ_NONE;
			if (window->success_ratio >= IWL_RS_GOOD_RATIO)
				break;
			if (!rs_is_other_ant_connected(lq_data->antenna,
						       tbl->antenna_type))
				break;

			memcpy(search_tbl, tbl, sz);
			search_tbl->action = IWL_SISO_SWITCH_MIMO;
			rs_toggle_antenna(&(search_tbl->current_rate),
					   search_tbl);
			lq_data->search_better_tbl = 1;

			goto out;

		case IWL_SISO_SWITCH_MIMO:
			IWL_DEBUG_HT("LQ: SISO SWITCH TO MIMO FROM SISO\n");
			memcpy(search_tbl, tbl, sz);
			search_tbl->lq_type = LQ_MIMO;
			search_tbl->is_SGI = 0;
			search_tbl->is_fat = 0;
			search_tbl->antenna_type = ANT_BOTH;
1306
			ret = rs_switch_to_mimo(priv, lq_data, search_tbl,
Z
Zhu Yi 已提交
1307
					       index);
1308
			if (!ret) {
Z
Zhu Yi 已提交
1309 1310
				lq_data->search_better_tbl = 1;
				goto out;
1311
			}
Z
Zhu Yi 已提交
1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353
			break;
		case IWL_SISO_SWITCH_GI:
			IWL_DEBUG_HT("LQ: SISO SWITCH TO GI\n");
			memcpy(search_tbl, tbl, sz);
			search_tbl->action = 0;
			if (search_tbl->is_SGI)
				search_tbl->is_SGI = 0;
			else if (!is_green)
				search_tbl->is_SGI = 1;
			else
				break;
			lq_data->search_better_tbl = 1;
			if ((tbl->lq_type == LQ_SISO) &&
			    (tbl->is_SGI)) {
				s32 tpt = lq_data->last_tpt / 100;
				if (((!tbl->is_fat) &&
				     (tpt >= expected_tpt_siso20MHz[index])) ||
				    ((tbl->is_fat) &&
				     (tpt >= expected_tpt_siso40MHz[index])))
					lq_data->search_better_tbl = 0;
			}
			rs_get_expected_tpt_table(lq_data, search_tbl);
			rs_mcs_from_tbl(&search_tbl->current_rate,
					     search_tbl, index, is_green);
			goto out;
		}
		tbl->action++;
		if (tbl->action > IWL_SISO_SWITCH_GI)
			tbl->action = IWL_SISO_SWITCH_ANTENNA;

		if (tbl->action == start_action)
			break;
	}
	return 0;

 out:
	tbl->action++;
	if (tbl->action > IWL_SISO_SWITCH_GI)
		tbl->action = IWL_SISO_SWITCH_ANTENNA;
	return 0;
}

1354 1355 1356
/*
 * Try to switch to new modulation mode from MIMO
 */
C
Christoph Hellwig 已提交
1357 1358
static int rs_move_mimo_to_other(struct iwl4965_priv *priv,
				 struct iwl4965_rate_scale_priv *lq_data,
Z
Zhu Yi 已提交
1359 1360
				 int index)
{
1361
	int ret;
Z
Zhu Yi 已提交
1362
	s8 is_green = lq_data->is_green;
C
Christoph Hellwig 已提交
1363
	struct iwl4965_scale_tbl_info *tbl =
Z
Zhu Yi 已提交
1364
	    &(lq_data->lq_info[lq_data->active_tbl]);
C
Christoph Hellwig 已提交
1365
	struct iwl4965_scale_tbl_info *search_tbl =
Z
Zhu Yi 已提交
1366
	    &(lq_data->lq_info[(1 - lq_data->active_tbl)]);
C
Christoph Hellwig 已提交
1367 1368
	u32 sz = (sizeof(struct iwl4965_scale_tbl_info) -
		  (sizeof(struct iwl4965_rate_scale_data) * IWL_RATE_COUNT));
Z
Zhu Yi 已提交
1369 1370 1371 1372 1373 1374 1375 1376
	u8 start_action = tbl->action;

	for (;;) {
		lq_data->action_counter++;
		switch (tbl->action) {
		case IWL_MIMO_SWITCH_ANTENNA_A:
		case IWL_MIMO_SWITCH_ANTENNA_B:
			IWL_DEBUG_HT("LQ: MIMO SWITCH TO SISO\n");
1377 1378

			/* Set up new search table for SISO */
Z
Zhu Yi 已提交
1379 1380 1381 1382 1383 1384 1385 1386 1387
			memcpy(search_tbl, tbl, sz);
			search_tbl->lq_type = LQ_SISO;
			search_tbl->is_SGI = 0;
			search_tbl->is_fat = 0;
			if (tbl->action == IWL_MIMO_SWITCH_ANTENNA_A)
				search_tbl->antenna_type = ANT_MAIN;
			else
				search_tbl->antenna_type = ANT_AUX;

1388
			ret = rs_switch_to_siso(priv, lq_data, search_tbl,
Z
Zhu Yi 已提交
1389
					       index);
1390
			if (!ret) {
Z
Zhu Yi 已提交
1391 1392 1393 1394 1395 1396 1397
				lq_data->search_better_tbl = 1;
				goto out;
			}
			break;

		case IWL_MIMO_SWITCH_GI:
			IWL_DEBUG_HT("LQ: MIMO SWITCH TO GI\n");
1398 1399

			/* Set up new search table for MIMO */
Z
Zhu Yi 已提交
1400 1401 1402 1403 1404 1405 1406 1407 1408
			memcpy(search_tbl, tbl, sz);
			search_tbl->lq_type = LQ_MIMO;
			search_tbl->antenna_type = ANT_BOTH;
			search_tbl->action = 0;
			if (search_tbl->is_SGI)
				search_tbl->is_SGI = 0;
			else
				search_tbl->is_SGI = 1;
			lq_data->search_better_tbl = 1;
1409 1410 1411 1412 1413 1414 1415

			/*
			 * 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!
			 */
Z
Zhu Yi 已提交
1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447
			if ((tbl->lq_type == LQ_MIMO) &&
			    (tbl->is_SGI)) {
				s32 tpt = lq_data->last_tpt / 100;
				if (((!tbl->is_fat) &&
				     (tpt >= expected_tpt_mimo20MHz[index])) ||
				    ((tbl->is_fat) &&
				     (tpt >= expected_tpt_mimo40MHz[index])))
					lq_data->search_better_tbl = 0;
			}
			rs_get_expected_tpt_table(lq_data, search_tbl);
			rs_mcs_from_tbl(&search_tbl->current_rate,
					     search_tbl, index, is_green);
			goto out;

		}
		tbl->action++;
		if (tbl->action > IWL_MIMO_SWITCH_GI)
			tbl->action = IWL_MIMO_SWITCH_ANTENNA_A;

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

	return 0;
 out:
	tbl->action++;
	if (tbl->action > IWL_MIMO_SWITCH_GI)
		tbl->action = IWL_MIMO_SWITCH_ANTENNA_A;
	return 0;

}

1448 1449 1450 1451 1452 1453 1454
/*
 * 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)
 */
C
Christoph Hellwig 已提交
1455
static void rs_stay_in_table(struct iwl4965_rate_scale_priv *lq_data)
Z
Zhu Yi 已提交
1456
{
C
Christoph Hellwig 已提交
1457
	struct iwl4965_scale_tbl_info *tbl;
Z
Zhu Yi 已提交
1458 1459 1460 1461 1462 1463 1464 1465
	int i;
	int active_tbl;
	int flush_interval_passed = 0;

	active_tbl = lq_data->active_tbl;

	tbl = &(lq_data->lq_info[active_tbl]);

1466
	/* If we've been disallowing search, see if we should now allow it */
Z
Zhu Yi 已提交
1467 1468
	if (lq_data->stay_in_tbl) {

1469
		/* Elapsed time using current modulation mode */
Z
Zhu Yi 已提交
1470 1471 1472 1473 1474 1475
		if (lq_data->flush_timer)
			flush_interval_passed =
			    time_after(jiffies,
				       (unsigned long)(lq_data->flush_timer +
					IWL_RATE_SCALE_FLUSH_INTVL));

1476
		/* For now, disable the elapsed time criterion */
Z
Zhu Yi 已提交
1477
		flush_interval_passed = 0;
1478 1479 1480 1481 1482 1483 1484 1485 1486

		/*
		 * 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.
		 */
Z
Zhu Yi 已提交
1487 1488 1489 1490 1491 1492 1493 1494
		if ((lq_data->total_failed > lq_data->max_failure_limit) ||
		    (lq_data->total_success > lq_data->max_success_limit) ||
		    ((!lq_data->search_better_tbl) && (lq_data->flush_timer)
		     && (flush_interval_passed))) {
			IWL_DEBUG_HT("LQ: stay is expired %d %d %d\n:",
				     lq_data->total_failed,
				     lq_data->total_success,
				     flush_interval_passed);
1495 1496 1497

			/* Allow search for new mode */
			lq_data->stay_in_tbl = 0;	/* only place reset */
Z
Zhu Yi 已提交
1498 1499 1500
			lq_data->total_failed = 0;
			lq_data->total_success = 0;
			lq_data->flush_timer = 0;
1501 1502 1503 1504 1505 1506 1507

		/*
		 * 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.
		 */
1508
		} else {
Z
Zhu Yi 已提交
1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520
			lq_data->table_count++;
			if (lq_data->table_count >=
			    lq_data->table_count_limit) {
				lq_data->table_count = 0;

				IWL_DEBUG_HT("LQ: stay in table clear win\n");
				for (i = 0; i < IWL_RATE_COUNT; i++)
					rs_rate_scale_clear_window(
						&(tbl->win[i]));
			}
		}

1521 1522 1523
		/* If transitioning to allow "search", reset all history
		 * bitmaps and stats in active table (this will become the new
		 * "search" table). */
Z
Zhu Yi 已提交
1524 1525 1526 1527 1528 1529 1530
		if (!lq_data->stay_in_tbl) {
			for (i = 0; i < IWL_RATE_COUNT; i++)
				rs_rate_scale_clear_window(&(tbl->win[i]));
		}
	}
}

1531 1532 1533
/*
 * Do rate scaling and search for new modulation mode.
 */
C
Christoph Hellwig 已提交
1534
static void rs_rate_scale_perform(struct iwl4965_priv *priv,
Z
Zhu Yi 已提交
1535 1536 1537 1538 1539 1540 1541 1542
				  struct net_device *dev,
				  struct ieee80211_hdr *hdr,
				  struct sta_info *sta)
{
	int low = IWL_RATE_INVALID;
	int high = IWL_RATE_INVALID;
	int index;
	int i;
C
Christoph Hellwig 已提交
1543
	struct iwl4965_rate_scale_data *window = NULL;
Z
Zhu Yi 已提交
1544 1545 1546 1547 1548 1549 1550
	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;
	u16 fc, rate_mask;
	u8 update_lq = 0;
C
Christoph Hellwig 已提交
1551 1552
	struct iwl4965_rate_scale_priv *lq_data;
	struct iwl4965_scale_tbl_info *tbl, *tbl1;
Z
Zhu Yi 已提交
1553
	u16 rate_scale_index_msk = 0;
C
Christoph Hellwig 已提交
1554
	struct iwl4965_rate mcs_rate;
Z
Zhu Yi 已提交
1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576
	u8 is_green = 0;
	u8 active_tbl = 0;
	u8 done_search = 0;
	u16 high_low;

	IWL_DEBUG_RATE("rate scale calculate new rate for skb\n");

	fc = le16_to_cpu(hdr->frame_control);
	if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1)) {
		/* Send management frames and broadcast/multicast data using
		 * lowest rate. */
		/* TODO: this could probably be improved.. */
		return;
	}

	if (!sta || !sta->rate_ctrl_priv)
		return;

	if (!priv->lq_mngr.lq_ready) {
		IWL_DEBUG_RATE("still rate scaling not ready\n");
		return;
	}
C
Christoph Hellwig 已提交
1577
	lq_data = (struct iwl4965_rate_scale_priv *)sta->rate_ctrl_priv;
Z
Zhu Yi 已提交
1578

1579 1580 1581 1582 1583
	/*
	 * 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.
	 */
Z
Zhu Yi 已提交
1584 1585 1586 1587 1588 1589 1590 1591
	if (!lq_data->search_better_tbl)
		active_tbl = lq_data->active_tbl;
	else
		active_tbl = 1 - lq_data->active_tbl;

	tbl = &(lq_data->lq_info[active_tbl]);
	is_green = lq_data->is_green;

1592
	/* current tx rate */
Z
Zhu Yi 已提交
1593 1594 1595 1596 1597
	index = sta->last_txrate;

	IWL_DEBUG_RATE("Rate scale index %d for type %d\n", index,
		       tbl->lq_type);

1598
	/* rates available for this association, and for modulation mode */
Z
Zhu Yi 已提交
1599 1600 1601 1602 1603 1604 1605 1606
	rs_get_supported_rates(lq_data, hdr, tbl->lq_type,
				&rate_mask);

	IWL_DEBUG_RATE("mask 0x%04X \n", rate_mask);

	/* mask with station rate restriction */
	if (is_legacy(tbl->lq_type)) {
		if (lq_data->phymode == (u8) MODE_IEEE80211A)
1607
			/* supp_rates has no CCK bits in A mode */
Z
Zhu Yi 已提交
1608
			rate_scale_index_msk = (u16) (rate_mask &
1609
				(lq_data->supp_rates << IWL_FIRST_OFDM_RATE));
Z
Zhu Yi 已提交
1610 1611
		else
			rate_scale_index_msk = (u16) (rate_mask &
1612
						      lq_data->supp_rates);
Z
Zhu Yi 已提交
1613 1614 1615 1616 1617 1618 1619

	} else
		rate_scale_index_msk = rate_mask;

	if (!rate_scale_index_msk)
		rate_scale_index_msk = rate_mask;

1620 1621
	/* If current rate is no longer supported on current association,
	 * or user changed preferences for rates, find a new supported rate. */
Z
Zhu Yi 已提交
1622 1623 1624 1625
	if (index < 0 || !((1 << index) & rate_scale_index_msk)) {
		index = IWL_INVALID_VALUE;
		update_lq = 1;

1626
		/* get the highest available rate */
Z
Zhu Yi 已提交
1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637
		for (i = 0; i <= IWL_RATE_COUNT; i++) {
			if ((1 << i) & rate_scale_index_msk)
				index = i;
		}

		if (index == IWL_INVALID_VALUE) {
			IWL_WARNING("Can not find a suitable rate\n");
			return;
		}
	}

1638
	/* Get expected throughput table and history window for current rate */
Z
Zhu Yi 已提交
1639 1640 1641 1642 1643
	if (!tbl->expected_tpt)
		rs_get_expected_tpt_table(lq_data, tbl);

	window = &(tbl->win[index]);

1644 1645 1646 1647 1648 1649 1650
	/*
	 * 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 已提交
1651 1652 1653 1654 1655 1656 1657
	fail_count = window->counter - window->success_counter;
	if (((fail_count < IWL_RATE_MIN_FAILURE_TH) &&
	     (window->success_counter < IWL_RATE_MIN_SUCCESS_TH))
	    || (tbl->expected_tpt == NULL)) {
		IWL_DEBUG_RATE("LQ: still below TH succ %d total %d "
			       "for index %d\n",
			       window->success_counter, window->counter, index);
1658 1659

		/* Can't calculate this yet; not enough history */
Z
Zhu Yi 已提交
1660
		window->average_tpt = IWL_INVALID_VALUE;
1661 1662 1663

		/* Should we stay with this modulation mode,
		 * or search for a new one? */
Z
Zhu Yi 已提交
1664
		rs_stay_in_table(lq_data);
1665 1666

		/* Set up new rate table in uCode, if needed */
Z
Zhu Yi 已提交
1667 1668
		if (update_lq) {
			rs_mcs_from_tbl(&mcs_rate, tbl, index, is_green);
1669
			rs_fill_link_cmd(lq_data, &mcs_rate, &lq_data->lq);
Z
Zhu Yi 已提交
1670 1671 1672 1673
			rs_send_lq_cmd(priv, &lq_data->lq, CMD_ASYNC);
		}
		goto out;

1674 1675
	/* Else we have enough samples; calculate estimate of
	 * actual average throughput */
Z
Zhu Yi 已提交
1676 1677 1678 1679
	} else
		window->average_tpt = ((window->success_ratio *
					tbl->expected_tpt[index] + 64) / 128);

1680
	/* If we are searching for better modulation mode, check success. */
Z
Zhu Yi 已提交
1681 1682 1683
	if (lq_data->search_better_tbl) {
		int success_limit = IWL_RATE_SCALE_SWITCH;

1684 1685 1686
		/* 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. */
Z
Zhu Yi 已提交
1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697
		if ((window->success_ratio > success_limit) ||
		    (window->average_tpt > lq_data->last_tpt)) {
			if (!is_legacy(tbl->lq_type)) {
				IWL_DEBUG_HT("LQ: we are switching to HT"
					     " rate suc %d current tpt %d"
					     " old tpt %d\n",
					     window->success_ratio,
					     window->average_tpt,
					     lq_data->last_tpt);
				lq_data->enable_counter = 1;
			}
1698
			/* Swap tables; "search" becomes "active" */
Z
Zhu Yi 已提交
1699 1700
			lq_data->active_tbl = active_tbl;
			current_tpt = window->average_tpt;
1701 1702

		/* Else poor success; go back to mode in "active" table */
Z
Zhu Yi 已提交
1703
		} else {
1704
			/* Nullify "search" table */
Z
Zhu Yi 已提交
1705
			tbl->lq_type = LQ_NONE;
1706 1707

			/* Revert to "active" table */
Z
Zhu Yi 已提交
1708 1709 1710
			active_tbl = lq_data->active_tbl;
			tbl = &(lq_data->lq_info[active_tbl]);

1711
			/* Revert to "active" rate and throughput info */
C
Christoph Hellwig 已提交
1712
			index = iwl4965_rate_index_from_plcp(
Z
Zhu Yi 已提交
1713
				tbl->current_rate.rate_n_flags);
1714
			current_tpt = lq_data->last_tpt;
Z
Zhu Yi 已提交
1715

1716
			/* Need to set up a new rate table in uCode */
Z
Zhu Yi 已提交
1717 1718 1719
			update_lq = 1;
			IWL_DEBUG_HT("XXY GO BACK TO OLD TABLE\n");
		}
1720 1721 1722

		/* Either way, we've made a decision; modulation mode
		 * search is done, allow rate adjustment next time. */
Z
Zhu Yi 已提交
1723
		lq_data->search_better_tbl = 0;
1724
		done_search = 1;	/* Don't switch modes below! */
Z
Zhu Yi 已提交
1725 1726 1727
		goto lq_update;
	}

1728 1729
	/* (Else) not in search of better modulation mode, try for better
	 * starting rate, while staying in this mode. */
Z
Zhu Yi 已提交
1730 1731 1732 1733 1734
	high_low = rs_get_adjacent_rate(index, rate_scale_index_msk,
					tbl->lq_type);
	low = high_low & 0xff;
	high = (high_low >> 8) & 0xff;

1735
	/* Collect measured throughputs for current and adjacent rates */
Z
Zhu Yi 已提交
1736 1737 1738 1739 1740 1741
	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;

1742
	/* Assume rate increase */
Z
Zhu Yi 已提交
1743 1744
	scale_action = 1;

1745
	/* Too many failures, decrease rate */
Z
Zhu Yi 已提交
1746 1747 1748 1749
	if ((window->success_ratio <= IWL_RATE_DECREASE_TH) ||
	    (current_tpt == 0)) {
		IWL_DEBUG_RATE("decrease rate because of low success_ratio\n");
		scale_action = -1;
1750 1751

	/* No throughput measured yet for adjacent rates; try increase. */
Z
Zhu Yi 已提交
1752 1753 1754
	} else if ((low_tpt == IWL_INVALID_VALUE) &&
		   (high_tpt == IWL_INVALID_VALUE))
		scale_action = 1;
1755 1756 1757

	/* Both adjacent throughputs are measured, but neither one has better
	 * throughput; we're using the best rate, don't change it! */
Z
Zhu Yi 已提交
1758 1759 1760 1761 1762
	else if ((low_tpt != IWL_INVALID_VALUE) &&
		 (high_tpt != IWL_INVALID_VALUE) &&
		 (low_tpt < current_tpt) &&
		 (high_tpt < current_tpt))
		scale_action = 0;
1763 1764 1765

	/* At least one adjacent rate's throughput is measured,
	 * and may have better performance. */
Z
Zhu Yi 已提交
1766
	else {
1767
		/* Higher adjacent rate's throughput is measured */
Z
Zhu Yi 已提交
1768
		if (high_tpt != IWL_INVALID_VALUE) {
1769
			/* Higher rate has better throughput */
Z
Zhu Yi 已提交
1770 1771 1772 1773 1774 1775 1776
			if (high_tpt > current_tpt)
				scale_action = 1;
			else {
				IWL_DEBUG_RATE
				    ("decrease rate because of high tpt\n");
				scale_action = -1;
			}
1777 1778

		/* Lower adjacent rate's throughput is measured */
Z
Zhu Yi 已提交
1779
		} else if (low_tpt != IWL_INVALID_VALUE) {
1780
			/* Lower rate has better throughput */
Z
Zhu Yi 已提交
1781 1782 1783 1784 1785 1786 1787 1788 1789
			if (low_tpt > current_tpt) {
				IWL_DEBUG_RATE
				    ("decrease rate because of low tpt\n");
				scale_action = -1;
			} else
				scale_action = 1;
		}
	}

1790 1791
	/* Sanity check; asked for decrease, but success rate or throughput
	 * has been good at old rate.  Don't change it. */
Z
Zhu Yi 已提交
1792 1793 1794 1795 1796
	if (scale_action == -1) {
		if ((low != IWL_RATE_INVALID) &&
		    ((window->success_ratio > IWL_RATE_HIGH_TH) ||
		     (current_tpt > (100 * tbl->expected_tpt[low]))))
			scale_action = 0;
1797 1798 1799

	/* Sanity check; asked for increase, but success rate has not been great
	 * even at old rate, higher rate will be worse.  Don't change it. */
Z
Zhu Yi 已提交
1800 1801 1802 1803 1804 1805
	} else if ((scale_action == 1) &&
		   (window->success_ratio < IWL_RATE_INCREASE_TH))
		scale_action = 0;

	switch (scale_action) {
	case -1:
1806
		/* Decrease starting rate, update uCode's rate table */
Z
Zhu Yi 已提交
1807 1808 1809 1810 1811 1812
		if (low != IWL_RATE_INVALID) {
			update_lq = 1;
			index = low;
		}
		break;
	case 1:
1813
		/* Increase starting rate, update uCode's rate table */
Z
Zhu Yi 已提交
1814 1815 1816 1817 1818 1819 1820
		if (high != IWL_RATE_INVALID) {
			update_lq = 1;
			index = high;
		}

		break;
	case 0:
1821
		/* No change */
Z
Zhu Yi 已提交
1822 1823 1824 1825 1826 1827 1828 1829 1830
	default:
		break;
	}

	IWL_DEBUG_HT("choose rate scale index %d action %d low %d "
		    "high %d type %d\n",
		     index, scale_action, low, high, tbl->lq_type);

 lq_update:
1831
	/* Replace uCode's rate table for the destination station. */
Z
Zhu Yi 已提交
1832 1833
	if (update_lq) {
		rs_mcs_from_tbl(&mcs_rate, tbl, index, is_green);
1834
		rs_fill_link_cmd(lq_data, &mcs_rate, &lq_data->lq);
Z
Zhu Yi 已提交
1835 1836
		rs_send_lq_cmd(priv, &lq_data->lq, CMD_ASYNC);
	}
1837 1838

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

1841 1842 1843 1844 1845 1846
	/*
	 * 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
	 */
Z
Zhu Yi 已提交
1847
	if (!update_lq && !done_search && !lq_data->stay_in_tbl) {
1848
		/* Save current throughput to compare with "search" throughput*/
Z
Zhu Yi 已提交
1849 1850
		lq_data->last_tpt = current_tpt;

1851 1852
		/* Select a new "search" modulation mode to try.
		 * If one is found, set up the new "search" table. */
Z
Zhu Yi 已提交
1853 1854 1855 1856 1857 1858 1859
		if (is_legacy(tbl->lq_type))
			rs_move_legacy_other(priv, lq_data, index);
		else if (is_siso(tbl->lq_type))
			rs_move_siso_to_other(priv, lq_data, index);
		else
			rs_move_mimo_to_other(priv, lq_data, index);

1860
		/* If new "search" mode was selected, set up in uCode table */
Z
Zhu Yi 已提交
1861
		if (lq_data->search_better_tbl) {
1862
			/* Access the "search" table, clear its history. */
Z
Zhu Yi 已提交
1863 1864 1865 1866
			tbl = &(lq_data->lq_info[(1 - lq_data->active_tbl)]);
			for (i = 0; i < IWL_RATE_COUNT; i++)
				rs_rate_scale_clear_window(&(tbl->win[i]));

1867
			/* Use new "search" start rate */
C
Christoph Hellwig 已提交
1868
			index = iwl4965_rate_index_from_plcp(
Z
Zhu Yi 已提交
1869 1870 1871 1872 1873
					tbl->current_rate.rate_n_flags);

			IWL_DEBUG_HT("Switch current  mcs: %X index: %d\n",
				     tbl->current_rate.rate_n_flags, index);
			rs_fill_link_cmd(lq_data, &tbl->current_rate,
1874
					 &lq_data->lq);
Z
Zhu Yi 已提交
1875 1876 1877
			rs_send_lq_cmd(priv, &lq_data->lq, CMD_ASYNC);
		}

1878 1879 1880 1881 1882 1883
		/* 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. */
		tbl1 = &(lq_data->lq_info[lq_data->active_tbl]);
Z
Zhu Yi 已提交
1884
		if (is_legacy(tbl1->lq_type) &&
1885
#ifdef CONFIG_IWL4965_HT
Z
Zhu Yi 已提交
1886 1887 1888 1889 1890 1891 1892 1893
		    !priv->current_assoc_ht.is_ht &&
#endif
		    (lq_data->action_counter >= 1)) {
			lq_data->action_counter = 0;
			IWL_DEBUG_HT("LQ: STAY in legacy table\n");
			rs_set_stay_in_table(1, lq_data);
		}

1894 1895 1896
		/* 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. */
Z
Zhu Yi 已提交
1897 1898
		if (lq_data->enable_counter &&
		    (lq_data->action_counter >= IWL_ACTION_LIMIT)) {
1899
#ifdef CONFIG_IWL4965_HT_AGG
1900
			/* If appropriate, set up aggregation! */
Z
Zhu Yi 已提交
1901 1902 1903 1904 1905 1906
			if ((lq_data->last_tpt > TID_AGG_TPT_THREHOLD) &&
			    (priv->lq_mngr.agg_ctrl.auto_agg)) {
				priv->lq_mngr.agg_ctrl.tid_retry =
				    TID_ALL_SPECIFIED;
				schedule_work(&priv->agg_work);
			}
1907
#endif /*CONFIG_IWL4965_HT_AGG */
Z
Zhu Yi 已提交
1908 1909 1910
			lq_data->action_counter = 0;
			rs_set_stay_in_table(0, lq_data);
		}
1911 1912 1913 1914 1915 1916 1917 1918

	/*
	 * Else, don't search for a new modulation mode.
	 * Put new timestamp in stay-in-modulation-mode flush timer if:
	 * 1)  Not changing rates right now
	 * 2)  Not just finishing up a search
	 * 3)  flush timer is empty
	 */
Z
Zhu Yi 已提交
1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940
	} else {
		if ((!update_lq) && (!done_search) && (!lq_data->flush_timer))
			lq_data->flush_timer = jiffies;
	}

out:
	rs_mcs_from_tbl(&tbl->current_rate, tbl, index, is_green);
	i = index;
	sta->last_txrate = i;

	/* sta->txrate is an index to A mode rates which start
	 * at IWL_FIRST_OFDM_RATE
	 */
	if (lq_data->phymode == (u8) MODE_IEEE80211A)
		sta->txrate = i - IWL_FIRST_OFDM_RATE;
	else
		sta->txrate = i;

	return;
}


C
Christoph Hellwig 已提交
1941
static void rs_initialize_lq(struct iwl4965_priv *priv,
Z
Zhu Yi 已提交
1942 1943 1944
			     struct sta_info *sta)
{
	int i;
C
Christoph Hellwig 已提交
1945 1946
	struct iwl4965_rate_scale_priv *lq;
	struct iwl4965_scale_tbl_info *tbl;
Z
Zhu Yi 已提交
1947 1948 1949
	u8 active_tbl = 0;
	int rate_idx;
	u8 use_green = rs_use_green(priv);
C
Christoph Hellwig 已提交
1950
	struct iwl4965_rate mcs_rate;
Z
Zhu Yi 已提交
1951 1952 1953 1954

	if (!sta || !sta->rate_ctrl_priv)
		goto out;

C
Christoph Hellwig 已提交
1955
	lq = (struct iwl4965_rate_scale_priv *)sta->rate_ctrl_priv;
Z
Zhu Yi 已提交
1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971
	i = sta->last_txrate;

	if ((lq->lq.sta_id == 0xff) &&
	    (priv->iw_mode == IEEE80211_IF_TYPE_IBSS))
		goto out;

	if (!lq->search_better_tbl)
		active_tbl = lq->active_tbl;
	else
		active_tbl = 1 - lq->active_tbl;

	tbl = &(lq->lq_info[active_tbl]);

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

C
Christoph Hellwig 已提交
1972
	mcs_rate.rate_n_flags = iwl4965_rates[i].plcp ;
Z
Zhu Yi 已提交
1973 1974 1975 1976 1977 1978 1979 1980 1981
	mcs_rate.rate_n_flags |= RATE_MCS_ANT_B_MSK;
	mcs_rate.rate_n_flags &= ~RATE_MCS_ANT_A_MSK;

	if (i >= IWL_FIRST_CCK_RATE && i <= IWL_LAST_CCK_RATE)
		mcs_rate.rate_n_flags |= RATE_MCS_CCK_MSK;

	tbl->antenna_type = ANT_AUX;
	rs_get_tbl_info_from_mcs(&mcs_rate, priv->phymode, tbl, &rate_idx);
	if (!rs_is_ant_connected(priv->valid_antenna, tbl->antenna_type))
1982
	    rs_toggle_antenna(&mcs_rate, tbl);
Z
Zhu Yi 已提交
1983 1984 1985 1986

	rs_mcs_from_tbl(&mcs_rate, tbl, rate_idx, use_green);
	tbl->current_rate.rate_n_flags = mcs_rate.rate_n_flags;
	rs_get_expected_tpt_table(lq, tbl);
1987
	rs_fill_link_cmd(lq, &mcs_rate, &lq->lq);
Z
Zhu Yi 已提交
1988 1989 1990 1991 1992
	rs_send_lq_cmd(priv, &lq->lq, CMD_ASYNC);
 out:
	return;
}

1993 1994 1995
static void rs_get_rate(void *priv_rate, struct net_device *dev,
			struct ieee80211_hw_mode *mode, struct sk_buff *skb,
			struct rate_selection *sel)
Z
Zhu Yi 已提交
1996 1997 1998 1999 2000 2001
{

	int i;
	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
	struct sta_info *sta;
C
Christoph Hellwig 已提交
2002 2003
	struct iwl4965_priv *priv = (struct iwl4965_priv *)priv_rate;
	struct iwl4965_rate_scale_priv *lq;
Z
Zhu Yi 已提交
2004

2005
	IWL_DEBUG_RATE_LIMIT("rate scale calculate new rate for skb\n");
Z
Zhu Yi 已提交
2006 2007 2008 2009

	sta = sta_info_get(local, hdr->addr1);

	if (!sta || !sta->rate_ctrl_priv) {
2010
		sel->rate = rate_lowest(local, local->oper_hw_mode, sta);
Z
Zhu Yi 已提交
2011 2012
		if (sta)
			sta_info_put(sta);
2013
		return;
Z
Zhu Yi 已提交
2014 2015
	}

C
Christoph Hellwig 已提交
2016
	lq = (struct iwl4965_rate_scale_priv *)sta->rate_ctrl_priv;
Z
Zhu Yi 已提交
2017 2018 2019
	i = sta->last_txrate;

	if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) && !lq->ibss_sta_added) {
C
Christoph Hellwig 已提交
2020
		u8 sta_id = iwl4965_hw_find_station(priv, hdr->addr1);
2021
		DECLARE_MAC_BUF(mac);
Z
Zhu Yi 已提交
2022 2023

		if (sta_id == IWL_INVALID_STATION) {
2024 2025
			IWL_DEBUG_RATE("LQ: ADD station %s\n",
				       print_mac(mac, hdr->addr1));
C
Christoph Hellwig 已提交
2026
			sta_id = iwl4965_add_station_flags(priv,
Z
Zhu Yi 已提交
2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039
						 hdr->addr1, 0, CMD_ASYNC);
		}
		if ((sta_id != IWL_INVALID_STATION)) {
			lq->lq.sta_id = sta_id;
			lq->lq.rs_table[0].rate_n_flags = 0;
			lq->ibss_sta_added = 1;
			rs_initialize_lq(priv, sta);
		}
		if (!lq->ibss_sta_added)
			goto done;
	}

 done:
2040 2041 2042 2043
	if ((i < 0) || (i > IWL_RATE_COUNT)) {
		sel->rate = rate_lowest(local, local->oper_hw_mode, sta);
		return;
	}
Z
Zhu Yi 已提交
2044 2045
	sta_info_put(sta);

2046
	sel->rate = &priv->ieee_rates[i];
Z
Zhu Yi 已提交
2047 2048 2049 2050
}

static void *rs_alloc_sta(void *priv, gfp_t gfp)
{
C
Christoph Hellwig 已提交
2051
	struct iwl4965_rate_scale_priv *crl;
Z
Zhu Yi 已提交
2052 2053 2054 2055
	int i, j;

	IWL_DEBUG_RATE("create station rate scale window\n");

C
Christoph Hellwig 已提交
2056
	crl = kzalloc(sizeof(struct iwl4965_rate_scale_priv), gfp);
Z
Zhu Yi 已提交
2057 2058 2059 2060 2061

	if (crl == NULL)
		return NULL;
	crl->lq.sta_id = 0xff;

2062

Z
Zhu Yi 已提交
2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075
	for (j = 0; j < LQ_SIZE; j++)
		for (i = 0; i < IWL_RATE_COUNT; i++)
			rs_rate_scale_clear_window(&(crl->lq_info[j].win[i]));

	return crl;
}

static void rs_rate_init(void *priv_rate, void *priv_sta,
			 struct ieee80211_local *local,
			 struct sta_info *sta)
{
	int i, j;
	struct ieee80211_hw_mode *mode = local->oper_hw_mode;
C
Christoph Hellwig 已提交
2076 2077
	struct iwl4965_priv *priv = (struct iwl4965_priv *)priv_rate;
	struct iwl4965_rate_scale_priv *crl = priv_sta;
Z
Zhu Yi 已提交
2078 2079

	crl->flush_timer = 0;
2080
	crl->supp_rates = sta->supp_rates;
Z
Zhu Yi 已提交
2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093
	sta->txrate = 3;
	for (j = 0; j < LQ_SIZE; j++)
		for (i = 0; i < IWL_RATE_COUNT; i++)
			rs_rate_scale_clear_window(&(crl->lq_info[j].win[i]));

	IWL_DEBUG_RATE("rate scale global init\n");
	/* 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.. */

	crl->ibss_sta_added = 0;
	if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {
C
Christoph Hellwig 已提交
2094
		u8 sta_id = iwl4965_hw_find_station(priv, sta->addr);
2095 2096
		DECLARE_MAC_BUF(mac);

Z
Zhu Yi 已提交
2097
		/* for IBSS the call are from tasklet */
2098 2099
		IWL_DEBUG_HT("LQ: ADD station %s\n",
			     print_mac(mac, sta->addr));
Z
Zhu Yi 已提交
2100 2101

		if (sta_id == IWL_INVALID_STATION) {
2102 2103
			IWL_DEBUG_RATE("LQ: ADD station %s\n",
				       print_mac(mac, sta->addr));
C
Christoph Hellwig 已提交
2104
			sta_id = iwl4965_add_station_flags(priv,
Z
Zhu Yi 已提交
2105 2106 2107 2108 2109 2110 2111 2112 2113 2114
						 sta->addr, 0, CMD_ASYNC);
		}
		if ((sta_id != IWL_INVALID_STATION)) {
			crl->lq.sta_id = sta_id;
			crl->lq.rs_table[0].rate_n_flags = 0;
		}
		/* FIXME: this is w/a remove it later */
		priv->assoc_station_added = 1;
	}

2115
	/* Find highest tx rate supported by hardware and destination station */
Z
Zhu Yi 已提交
2116 2117 2118 2119 2120 2121
	for (i = 0; i < mode->num_rates; i++) {
		if ((sta->supp_rates & BIT(i)) &&
		    (mode->rates[i].flags & IEEE80211_RATE_SUPPORTED))
			sta->txrate = i;
	}
	sta->last_txrate = sta->txrate;
2122
	/* For MODE_IEEE80211A, cck rates are at end of rate table */
Z
Zhu Yi 已提交
2123 2124 2125
	if (local->hw.conf.phymode == MODE_IEEE80211A)
		sta->last_txrate += IWL_FIRST_OFDM_RATE;

2126
	crl->is_dup = 0;
Z
Zhu Yi 已提交
2127 2128 2129 2130 2131 2132 2133
	crl->valid_antenna = priv->valid_antenna;
	crl->antenna = priv->antenna;
	crl->is_green = rs_use_green(priv);
	crl->active_rate = priv->active_rate;
	crl->active_rate &= ~(0x1000);
	crl->active_rate_basic = priv->active_rate_basic;
	crl->phymode = priv->phymode;
2134
#ifdef CONFIG_IWL4965_HT
2135 2136 2137 2138
	/*
	 * 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.
	 */
Z
Zhu Yi 已提交
2139 2140 2141 2142 2143
	crl->active_siso_rate = (priv->current_assoc_ht.supp_rates[0] << 1);
	crl->active_siso_rate |= (priv->current_assoc_ht.supp_rates[0] & 0x1);
	crl->active_siso_rate &= ~((u16)0x2);
	crl->active_siso_rate = crl->active_siso_rate << IWL_FIRST_OFDM_RATE;

2144
	/* Same here */
Z
Zhu Yi 已提交
2145 2146 2147 2148 2149 2150
	crl->active_mimo_rate = (priv->current_assoc_ht.supp_rates[1] << 1);
	crl->active_mimo_rate |= (priv->current_assoc_ht.supp_rates[1] & 0x1);
	crl->active_mimo_rate &= ~((u16)0x2);
	crl->active_mimo_rate = crl->active_mimo_rate << IWL_FIRST_OFDM_RATE;
	IWL_DEBUG_HT("MIMO RATE 0x%X SISO MASK 0x%X\n", crl->active_siso_rate,
		     crl->active_mimo_rate);
2151
#endif /*CONFIG_IWL4965_HT*/
2152 2153 2154
#ifdef CONFIG_MAC80211_DEBUGFS
	crl->drv = priv;
#endif
Z
Zhu Yi 已提交
2155 2156 2157 2158 2159 2160 2161

	if (priv->assoc_station_added)
		priv->lq_mngr.lq_ready = 1;

	rs_initialize_lq(priv, sta);
}

C
Christoph Hellwig 已提交
2162 2163 2164
static void rs_fill_link_cmd(struct iwl4965_rate_scale_priv *lq_data,
			    struct iwl4965_rate *tx_mcs,
			    struct iwl4965_link_quality_cmd *lq_cmd)
Z
Zhu Yi 已提交
2165 2166 2167
{
	int index = 0;
	int rate_idx;
2168
	int repeat_rate = 0;
Z
Zhu Yi 已提交
2169 2170
	u8 ant_toggle_count = 0;
	u8 use_ht_possible = 1;
C
Christoph Hellwig 已提交
2171 2172
	struct iwl4965_rate new_rate;
	struct iwl4965_scale_tbl_info tbl_type = { 0 };
Z
Zhu Yi 已提交
2173

2174
	/* Override starting rate (index 0) if needed for debug purposes */
2175 2176
	rs_dbgfs_set_mcs(lq_data, tx_mcs, index);

2177
	/* Interpret rate_n_flags */
Z
Zhu Yi 已提交
2178 2179 2180
	rs_get_tbl_info_from_mcs(tx_mcs, lq_data->phymode,
				  &tbl_type, &rate_idx);

2181
	/* How many times should we repeat the initial rate? */
Z
Zhu Yi 已提交
2182 2183
	if (is_legacy(tbl_type.lq_type)) {
		ant_toggle_count = 1;
2184
		repeat_rate = IWL_NUMBER_TRY;
Z
Zhu Yi 已提交
2185
	} else
2186
		repeat_rate = IWL_HT_NUMBER_TRY;
Z
Zhu Yi 已提交
2187 2188 2189

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

	/* Fill 1st table entry (index 0) */
Z
Zhu Yi 已提交
2192 2193 2194 2195 2196
	lq_cmd->rs_table[index].rate_n_flags =
			cpu_to_le32(tx_mcs->rate_n_flags);
	new_rate.rate_n_flags = tx_mcs->rate_n_flags;

	if (is_mimo(tbl_type.lq_type) || (tbl_type.antenna_type == ANT_MAIN))
2197 2198
		lq_cmd->general_params.single_stream_ant_msk
			= LINK_QUAL_ANT_A_MSK;
Z
Zhu Yi 已提交
2199
	else
2200 2201
		lq_cmd->general_params.single_stream_ant_msk
			= LINK_QUAL_ANT_B_MSK;
Z
Zhu Yi 已提交
2202 2203

	index++;
2204
	repeat_rate--;
Z
Zhu Yi 已提交
2205

2206
	/* Fill rest of rate table */
Z
Zhu Yi 已提交
2207
	while (index < LINK_QUAL_MAX_RETRY_NUM) {
2208 2209 2210
		/* 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. */
2211
		while (repeat_rate > 0 && (index < LINK_QUAL_MAX_RETRY_NUM)) {
Z
Zhu Yi 已提交
2212 2213 2214 2215 2216 2217 2218 2219 2220
			if (is_legacy(tbl_type.lq_type)) {
				if (ant_toggle_count <
				    NUM_TRY_BEFORE_ANTENNA_TOGGLE)
					ant_toggle_count++;
				else {
					rs_toggle_antenna(&new_rate, &tbl_type);
					ant_toggle_count = 1;
				}
			}
2221

2222
			/* Override next rate if needed for debug purposes */
2223
			rs_dbgfs_set_mcs(lq_data, &new_rate, index);
2224 2225

			/* Fill next table entry */
Z
Zhu Yi 已提交
2226 2227
			lq_cmd->rs_table[index].rate_n_flags =
					cpu_to_le32(new_rate.rate_n_flags);
2228
			repeat_rate--;
Z
Zhu Yi 已提交
2229 2230 2231 2232 2233 2234
			index++;
		}

		rs_get_tbl_info_from_mcs(&new_rate, lq_data->phymode, &tbl_type,
						&rate_idx);

2235 2236 2237
		/* 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 已提交
2238 2239 2240
		if (is_mimo(tbl_type.lq_type))
			lq_cmd->general_params.mimo_delimiter = index;

2241
		/* Get next rate */
Z
Zhu Yi 已提交
2242
		rs_get_lower_rate(lq_data, &tbl_type, rate_idx,
2243
				  use_ht_possible, &new_rate);
Z
Zhu Yi 已提交
2244

2245
		/* How many times should we repeat the next rate? */
Z
Zhu Yi 已提交
2246 2247 2248 2249 2250 2251 2252
		if (is_legacy(tbl_type.lq_type)) {
			if (ant_toggle_count < NUM_TRY_BEFORE_ANTENNA_TOGGLE)
				ant_toggle_count++;
			else {
				rs_toggle_antenna(&new_rate, &tbl_type);
				ant_toggle_count = 1;
			}
2253
			repeat_rate = IWL_NUMBER_TRY;
Z
Zhu Yi 已提交
2254
		} else
2255
			repeat_rate = IWL_HT_NUMBER_TRY;
Z
Zhu Yi 已提交
2256

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

2261
		/* Override next rate if needed for debug purposes */
2262
		rs_dbgfs_set_mcs(lq_data, &new_rate, index);
2263 2264

		/* Fill next table entry */
Z
Zhu Yi 已提交
2265 2266 2267 2268
		lq_cmd->rs_table[index].rate_n_flags =
				cpu_to_le32(new_rate.rate_n_flags);

		index++;
2269
		repeat_rate--;
Z
Zhu Yi 已提交
2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288
	}

	lq_cmd->general_params.dual_stream_ant_msk = 3;
	lq_cmd->agg_params.agg_dis_start_th = 3;
	lq_cmd->agg_params.agg_time_limit = cpu_to_le16(4000);
}

static void *rs_alloc(struct ieee80211_local *local)
{
	return local->hw.priv;
}
/* rate scale requires free function to be implemented */
static void rs_free(void *priv_rate)
{
	return;
}

static void rs_clear(void *priv_rate)
{
C
Christoph Hellwig 已提交
2289
	struct iwl4965_priv *priv = (struct iwl4965_priv *) priv_rate;
Z
Zhu Yi 已提交
2290 2291 2292 2293

	IWL_DEBUG_RATE("enter\n");

	priv->lq_mngr.lq_ready = 0;
2294 2295
#ifdef CONFIG_IWL4965_HT
#ifdef CONFIG_IWL4965_HT_AGG
Z
Zhu Yi 已提交
2296 2297
	if (priv->lq_mngr.agg_ctrl.granted_ba)
		iwl4965_turn_off_agg(priv, TID_ALL_SPECIFIED);
2298 2299
#endif /*CONFIG_IWL4965_HT_AGG */
#endif /* CONFIG_IWL4965_HT */
Z
Zhu Yi 已提交
2300 2301 2302 2303 2304 2305

	IWL_DEBUG_RATE("leave\n");
}

static void rs_free_sta(void *priv, void *priv_sta)
{
C
Christoph Hellwig 已提交
2306
	struct iwl4965_rate_scale_priv *rs_priv = priv_sta;
Z
Zhu Yi 已提交
2307 2308 2309 2310 2311 2312 2313

	IWL_DEBUG_RATE("enter\n");
	kfree(rs_priv);
	IWL_DEBUG_RATE("leave\n");
}


2314
#ifdef CONFIG_MAC80211_DEBUGFS
2315 2316 2317 2318 2319
static int open_file_generic(struct inode *inode, struct file *file)
{
	file->private_data = inode->i_private;
	return 0;
}
C
Christoph Hellwig 已提交
2320 2321
static void rs_dbgfs_set_mcs(struct iwl4965_rate_scale_priv *rs_priv,
				struct iwl4965_rate *mcs, int index)
2322
{
2323 2324 2325 2326 2327 2328 2329
	u32 base_rate;

	if (rs_priv->phymode == (u8) MODE_IEEE80211A)
		base_rate = 0x800D;
	else
		base_rate = 0x820A;

2330 2331 2332 2333
	if (rs_priv->dbg_fixed.rate_n_flags) {
		if (index < 12)
			mcs->rate_n_flags = rs_priv->dbg_fixed.rate_n_flags;
		else
2334
			mcs->rate_n_flags = base_rate;
2335 2336 2337 2338 2339 2340
		IWL_DEBUG_RATE("Fixed rate ON\n");
		return;
	}

	IWL_DEBUG_RATE("Fixed rate OFF\n");
}
2341

2342 2343 2344
static ssize_t rs_sta_dbgfs_scale_table_write(struct file *file,
			const char __user *user_buf, size_t count, loff_t *ppos)
{
C
Christoph Hellwig 已提交
2345
	struct iwl4965_rate_scale_priv *rs_priv = file->private_data;
2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359
	char buf[64];
	int buf_size;
	u32 parsed_rate;

	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)
		rs_priv->dbg_fixed.rate_n_flags = parsed_rate;
	else
		rs_priv->dbg_fixed.rate_n_flags = 0;

2360 2361 2362
	rs_priv->active_rate = 0x0FFF;		/* 1 - 54 MBits, includes CCK */
	rs_priv->active_siso_rate = 0x1FD0;	/* 6 - 60 MBits, no 9, no CCK */
	rs_priv->active_mimo_rate = 0x1FD0;	/* 6 - 60 MBits, no 9, no CCK */
2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373

	IWL_DEBUG_RATE("sta_id %d rate 0x%X\n",
		rs_priv->lq.sta_id, rs_priv->dbg_fixed.rate_n_flags);

	if (rs_priv->dbg_fixed.rate_n_flags) {
		rs_fill_link_cmd(rs_priv, &rs_priv->dbg_fixed, &rs_priv->lq);
		rs_send_lq_cmd(rs_priv->drv, &rs_priv->lq, CMD_ASYNC);
	}

	return count;
}
2374

2375 2376 2377 2378 2379 2380 2381
static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file,
			char __user *user_buf, size_t count, loff_t *ppos)
{
	char buff[1024];
	int desc = 0;
	int i = 0;

C
Christoph Hellwig 已提交
2382
	struct iwl4965_rate_scale_priv *rs_priv = file->private_data;
2383 2384

	desc += sprintf(buff+desc, "sta_id %d\n", rs_priv->lq.sta_id);
2385
	desc += sprintf(buff+desc, "failed=%d success=%d rate=0%X\n",
2386 2387
			rs_priv->total_failed, rs_priv->total_success,
			rs_priv->active_rate);
2388 2389
	desc += sprintf(buff+desc, "fixed rate 0x%X\n",
			rs_priv->dbg_fixed.rate_n_flags);
2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418
	desc += sprintf(buff+desc, "general:"
		"flags=0x%X mimo-d=%d s-ant0x%x d-ant=0x%x\n",
		rs_priv->lq.general_params.flags,
		rs_priv->lq.general_params.mimo_delimiter,
		rs_priv->lq.general_params.single_stream_ant_msk,
		rs_priv->lq.general_params.dual_stream_ant_msk);

	desc += sprintf(buff+desc, "agg:"
			"time_limit=%d dist_start_th=%d frame_cnt_limit=%d\n",
			le16_to_cpu(rs_priv->lq.agg_params.agg_time_limit),
			rs_priv->lq.agg_params.agg_dis_start_th,
			rs_priv->lq.agg_params.agg_frame_cnt_limit);

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


	for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++)
		desc += sprintf(buff+desc, " rate[%d] 0x%X\n",
			i, le32_to_cpu(rs_priv->lq.rs_table[i].rate_n_flags));

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

static const struct file_operations rs_sta_dbgfs_scale_table_ops = {
2419
	.write = rs_sta_dbgfs_scale_table_write,
2420 2421 2422
	.read = rs_sta_dbgfs_scale_table_read,
	.open = open_file_generic,
};
2423 2424 2425 2426 2427 2428 2429
static ssize_t rs_sta_dbgfs_stats_table_read(struct file *file,
			char __user *user_buf, size_t count, loff_t *ppos)
{
	char buff[1024];
	int desc = 0;
	int i, j;

C
Christoph Hellwig 已提交
2430
	struct iwl4965_rate_scale_priv *rs_priv = file->private_data;
2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454
	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",
				rs_priv->active_tbl == i?"*":"x",
				rs_priv->lq_info[i].lq_type,
				rs_priv->lq_info[i].is_SGI,
				rs_priv->lq_info[i].is_fat,
				rs_priv->lq_info[i].is_dup,
				rs_priv->lq_info[i].current_rate.rate_n_flags);
		for (j = 0; j < IWL_RATE_COUNT; j++) {
			desc += sprintf(buff+desc,
					"counter=%d success=%d %%=%d\n",
					rs_priv->lq_info[i].win[j].counter,
					rs_priv->lq_info[i].win[j].success_counter,
					rs_priv->lq_info[i].win[j].success_ratio);
		}
	}
	return simple_read_from_buffer(user_buf, count, ppos, buff, desc);
}

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

2456 2457 2458
static void rs_add_debugfs(void *priv, void *priv_sta,
					struct dentry *dir)
{
C
Christoph Hellwig 已提交
2459
	struct iwl4965_rate_scale_priv *rs_priv = priv_sta;
2460
	rs_priv->rs_sta_dbgfs_scale_table_file =
2461
		debugfs_create_file("rate_scale_table", 0600, dir,
2462
				rs_priv, &rs_sta_dbgfs_scale_table_ops);
2463 2464 2465
	rs_priv->rs_sta_dbgfs_stats_table_file =
		debugfs_create_file("rate_stats_table", 0600, dir,
			rs_priv, &rs_sta_dbgfs_stats_table_ops);
2466 2467 2468 2469
}

static void rs_remove_debugfs(void *priv, void *priv_sta)
{
C
Christoph Hellwig 已提交
2470
	struct iwl4965_rate_scale_priv *rs_priv = priv_sta;
2471
	debugfs_remove(rs_priv->rs_sta_dbgfs_scale_table_file);
2472
	debugfs_remove(rs_priv->rs_sta_dbgfs_stats_table_file);
2473 2474 2475
}
#endif

Z
Zhu Yi 已提交
2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486
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,
	.clear = rs_clear,
	.alloc = rs_alloc,
	.free = rs_free,
	.alloc_sta = rs_alloc_sta,
	.free_sta = rs_free_sta,
2487 2488 2489 2490
#ifdef CONFIG_MAC80211_DEBUGFS
	.add_sta_debugfs = rs_add_debugfs,
	.remove_sta_debugfs = rs_remove_debugfs,
#endif
Z
Zhu Yi 已提交
2491 2492
};

C
Christoph Hellwig 已提交
2493
int iwl4965_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id)
Z
Zhu Yi 已提交
2494 2495
{
	struct ieee80211_local *local = hw_to_local(hw);
C
Christoph Hellwig 已提交
2496 2497
	struct iwl4965_priv *priv = hw->priv;
	struct iwl4965_rate_scale_priv *rs_priv;
Z
Zhu Yi 已提交
2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529
	struct sta_info *sta;
	int count = 0, i;
	u32 samples = 0, success = 0, good = 0;
	unsigned long now = jiffies;
	u32 max_time = 0;
	u8 lq_type, antenna;

	sta = sta_info_get(local, priv->stations[sta_id].sta.sta.addr);
	if (!sta || !sta->rate_ctrl_priv) {
		if (sta) {
			sta_info_put(sta);
			IWL_DEBUG_RATE("leave - no private rate data!\n");
		} else
			IWL_DEBUG_RATE("leave - no station!\n");
		return sprintf(buf, "station %d not found\n", sta_id);
	}

	rs_priv = (void *)sta->rate_ctrl_priv;

	lq_type = rs_priv->lq_info[rs_priv->active_tbl].lq_type;
	antenna = rs_priv->lq_info[rs_priv->active_tbl].antenna_type;

	if (is_legacy(lq_type))
		i = IWL_RATE_54M_INDEX;
	else
		i = IWL_RATE_60M_INDEX;
	while (1) {
		u64 mask;
		int j;
		int active = rs_priv->active_tbl;

		count +=
C
Christoph Hellwig 已提交
2530
		    sprintf(&buf[count], " %2dMbs: ", iwl4965_rates[i].ieee / 2);
Z
Zhu Yi 已提交
2531 2532 2533 2534 2535 2536 2537 2538 2539 2540

		mask = (1ULL << (IWL_RATE_MAX_WINDOW - 1));
		for (j = 0; j < IWL_RATE_MAX_WINDOW; j++, mask >>= 1)
			buf[count++] =
				(rs_priv->lq_info[active].win[i].data & mask)
				? '1' : '0';

		samples += rs_priv->lq_info[active].win[i].counter;
		good += rs_priv->lq_info[active].win[i].success_counter;
		success += rs_priv->lq_info[active].win[i].success_counter *
C
Christoph Hellwig 已提交
2541
			   iwl4965_rates[i].ieee;
Z
Zhu Yi 已提交
2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554

		if (rs_priv->lq_info[active].win[i].stamp) {
			int delta =
				   jiffies_to_msecs(now -
				   rs_priv->lq_info[active].win[i].stamp);

			if (delta > max_time)
				max_time = delta;

			count += sprintf(&buf[count], "%5dms\n", delta);
		} else
			buf[count++] = '\n';

C
Christoph Hellwig 已提交
2555
		j = iwl4965_get_prev_ieee_rate(i);
Z
Zhu Yi 已提交
2556 2557 2558 2559 2560 2561 2562
		if (j == i)
			break;
		i = j;
	}

	/* Display the average rate of all samples taken.
	 *
2563
	 * NOTE:  We multiply # of samples by 2 since the IEEE measurement
C
Christoph Hellwig 已提交
2564
	 * added from iwl4965_rates is actually 2X the rate */
Z
Zhu Yi 已提交
2565 2566 2567 2568 2569 2570 2571 2572
	if (samples)
		count += sprintf(&buf[count],
			 "\nAverage rate is %3d.%02dMbs over last %4dms\n"
			 "%3d%% success (%d good packets over %d tries)\n",
			 success / (2 * samples), (success * 5 / samples) % 10,
			 max_time, good * 100 / samples, good, samples);
	else
		count += sprintf(&buf[count], "\nAverage rate: 0Mbs\n");
2573
	count += sprintf(&buf[count], "\nrate scale type %d antenna %d "
Z
Zhu Yi 已提交
2574 2575 2576 2577 2578 2579 2580
			 "active_search %d rate index %d\n", lq_type, antenna,
			 rs_priv->search_better_tbl, sta->last_txrate);

	sta_info_put(sta);
	return count;
}

C
Christoph Hellwig 已提交
2581
void iwl4965_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id)
Z
Zhu Yi 已提交
2582
{
C
Christoph Hellwig 已提交
2583
	struct iwl4965_priv *priv = hw->priv;
Z
Zhu Yi 已提交
2584 2585 2586 2587

	priv->lq_mngr.lq_ready = 1;
}

C
Christoph Hellwig 已提交
2588
void iwl4965_rate_control_register(struct ieee80211_hw *hw)
Z
Zhu Yi 已提交
2589 2590 2591 2592
{
	ieee80211_rate_control_register(&rs_ops);
}

C
Christoph Hellwig 已提交
2593
void iwl4965_rate_control_unregister(struct ieee80211_hw *hw)
Z
Zhu Yi 已提交
2594 2595 2596 2597
{
	ieee80211_rate_control_unregister(&rs_ops);
}