/******************************************************************************
*
* Copyright(c) 2005 - 2011 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:
* Intel Linux Wireless <ilw@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/slab.h>
#include <net/mac80211.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/delay.h>
#include <linux/workqueue.h>
#include "commands.h"
#include "3945.h"
#define RS_NAME "iwl-3945-rs"
static s32 il3945_expected_tpt_g[RATE_COUNT_3945] = {
7, 13, 35, 58, 0, 0, 76, 104, 130, 168, 191, 202
};
static s32 il3945_expected_tpt_g_prot[RATE_COUNT_3945] = {
7, 13, 35, 58, 0, 0, 0, 80, 93, 113, 123, 125
};
static s32 il3945_expected_tpt_a[RATE_COUNT_3945] = {
0, 0, 0, 0, 40, 57, 72, 98, 121, 154, 177, 186
};
static s32 il3945_expected_tpt_b[RATE_COUNT_3945] = {
7, 13, 35, 58, 0, 0, 0, 0, 0, 0, 0, 0
};
struct il3945_tpt_entry {
s8 min_rssi;
u8 idx;
};
static struct il3945_tpt_entry il3945_tpt_table_a[] = {
{-60, RATE_54M_IDX},
{-64, RATE_48M_IDX},
{-72, RATE_36M_IDX},
{-80, RATE_24M_IDX},
{-84, RATE_18M_IDX},
{-85, RATE_12M_IDX},
{-87, RATE_9M_IDX},
{-89, RATE_6M_IDX}
};
static struct il3945_tpt_entry il3945_tpt_table_g[] = {
{-60, RATE_54M_IDX},
{-64, RATE_48M_IDX},
{-68, RATE_36M_IDX},
{-80, RATE_24M_IDX},
{-84, RATE_18M_IDX},
{-85, RATE_12M_IDX},
{-86, RATE_11M_IDX},
{-88, RATE_5M_IDX},
{-90, RATE_2M_IDX},
{-92, RATE_1M_IDX}
};
#define RATE_MAX_WINDOW 62
#define RATE_FLUSH (3*HZ)
#define RATE_WIN_FLUSH (HZ/2)
#define IL39_RATE_HIGH_TH 11520
#define IL_SUCCESS_UP_TH 8960
#define IL_SUCCESS_DOWN_TH 10880
#define RATE_MIN_FAILURE_TH 6
#define RATE_MIN_SUCCESS_TH 8
#define RATE_DECREASE_TH 1920
#define RATE_RETRY_TH 15
static u8
il3945_get_rate_idx_by_rssi(s32 rssi, enum ieee80211_band band)
{
u32 idx = 0;
u32 table_size = 0;
struct il3945_tpt_entry *tpt_table = NULL;
if (rssi < IL_MIN_RSSI_VAL || rssi > IL_MAX_RSSI_VAL)
rssi = IL_MIN_RSSI_VAL;
switch (band) {
case IEEE80211_BAND_2GHZ:
tpt_table = il3945_tpt_table_g;
table_size = ARRAY_SIZE(il3945_tpt_table_g);
break;
case IEEE80211_BAND_5GHZ:
tpt_table = il3945_tpt_table_a;
table_size = ARRAY_SIZE(il3945_tpt_table_a);
break;
default:
BUG();
break;
}
while (idx < table_size && rssi < tpt_table[idx].min_rssi)
idx++;
idx = min(idx, table_size - 1);
return tpt_table[idx].idx;
}
static void
il3945_clear_win(struct il3945_rate_scale_data *win)
{
win->data = 0;
win->success_counter = 0;
win->success_ratio = -1;
win->counter = 0;
win->average_tpt = IL_INVALID_VALUE;
win->stamp = 0;
}
/**
* il3945_rate_scale_flush_wins - flush out the rate scale wins
*
* Returns the number of wins that have gathered data but were
* not flushed. If there were any that were not flushed, then
* reschedule the rate flushing routine.
*/
static int
il3945_rate_scale_flush_wins(struct il3945_rs_sta *rs_sta)
{
int unflushed = 0;
int i;
unsigned long flags;
struct il_priv *il __maybe_unused = rs_sta->il;
/*
* For each rate, if we have collected data on that rate
* and it has been more than RATE_WIN_FLUSH
* since we flushed, clear out the gathered stats
*/
for (i = 0; i < RATE_COUNT_3945; i++) {
if (!rs_sta->win[i].counter)
continue;
spin_lock_irqsave(&rs_sta->lock, flags);
if (time_after(jiffies, rs_sta->win[i].stamp + RATE_WIN_FLUSH)) {
D_RATE("flushing %d samples of rate " "idx %d\n",
rs_sta->win[i].counter, i);