/*
|
* Copyright (c) 2015 South Silicon Valley Microelectronics Inc.
|
* Copyright (c) 2015 iComm Corporation
|
*
|
* This program is free software: you can redistribute it and/or modify
|
* it under the terms of the GNU General Public License as published by
|
* the Free Software Foundation, either version 3 of the License, or
|
* (at your option) any later version.
|
* 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, see <http://www.gnu.org/licenses/>.
|
*/
|
|
#include <linux/version.h>
|
#include <ssv6200.h>
|
#include "dev.h"
|
#include "ssv_ht_rc.h"
|
#include "ssv_rc.h"
|
#include "ssv_rc_common.h"
|
static struct ssv_rc_rate ssv_11bgn_rate_table[] =
|
{
|
[0] = { .rc_flags = RC_FLAG_LEGACY,
|
.phy_type = WLAN_RC_PHY_CCK,
|
.rate_kbps = 1000,
|
.dot11_rate_idx = 0,
|
.ctrl_rate_idx = 0,
|
.hw_rate_idx = 0,
|
.arith_shift = 8,
|
.target_pf = 26,
|
},
|
[1] = { .rc_flags = RC_FLAG_LEGACY,
|
.phy_type = WLAN_RC_PHY_CCK,
|
.rate_kbps = 2000,
|
.dot11_rate_idx = 1,
|
.ctrl_rate_idx = 1,
|
.hw_rate_idx = 1,
|
.arith_shift = 8,
|
.target_pf = 26,
|
},
|
[2] = { .rc_flags = RC_FLAG_LEGACY,
|
.phy_type = WLAN_RC_PHY_CCK,
|
.rate_kbps = 5500,
|
.dot11_rate_idx = 2,
|
.ctrl_rate_idx = 1,
|
.hw_rate_idx = 2,
|
.arith_shift = 8,
|
.target_pf = 26,
|
},
|
[3] = { .rc_flags = RC_FLAG_LEGACY,
|
.phy_type = WLAN_RC_PHY_CCK,
|
.rate_kbps = 11000,
|
.dot11_rate_idx = 3,
|
.ctrl_rate_idx = 1,
|
.hw_rate_idx = 3,
|
.arith_shift = 8,
|
.target_pf = 26,
|
},
|
[4] = { .rc_flags = RC_FLAG_LEGACY | RC_FLAG_SHORT_PREAMBLE,
|
.phy_type = WLAN_RC_PHY_CCK,
|
.rate_kbps = 2000,
|
.dot11_rate_idx = 1,
|
.ctrl_rate_idx = 4,
|
.hw_rate_idx = 4,
|
.arith_shift = 8,
|
.target_pf = 26,
|
},
|
[5] = { .rc_flags = RC_FLAG_LEGACY | RC_FLAG_SHORT_PREAMBLE,
|
.phy_type = WLAN_RC_PHY_CCK,
|
.rate_kbps = 5500,
|
.dot11_rate_idx = 2,
|
.ctrl_rate_idx = 4,
|
.hw_rate_idx = 5,
|
.arith_shift = 8,
|
.target_pf = 26,
|
},
|
[6] = { .rc_flags = RC_FLAG_LEGACY | RC_FLAG_SHORT_PREAMBLE,
|
.phy_type = WLAN_RC_PHY_CCK,
|
.rate_kbps = 11000,
|
.dot11_rate_idx = 3,
|
.ctrl_rate_idx = 4,
|
.hw_rate_idx = 6,
|
.arith_shift = 8,
|
.target_pf = 26,
|
},
|
[7] = { .rc_flags = RC_FLAG_LEGACY,
|
.phy_type = WLAN_RC_PHY_OFDM,
|
.rate_kbps = 6000,
|
.dot11_rate_idx = 4,
|
.ctrl_rate_idx = 7,
|
.hw_rate_idx = 7,
|
.arith_shift = 8,
|
.target_pf = 26,
|
},
|
[8] = { .rc_flags = RC_FLAG_LEGACY,
|
.phy_type = WLAN_RC_PHY_OFDM,
|
.rate_kbps = 9000,
|
.dot11_rate_idx = 5,
|
.ctrl_rate_idx = 7,
|
.hw_rate_idx = 8,
|
.arith_shift = 8,
|
.target_pf = 26,
|
},
|
[9] = { .rc_flags = RC_FLAG_LEGACY,
|
.phy_type = WLAN_RC_PHY_OFDM,
|
.rate_kbps = 12000,
|
.dot11_rate_idx = 6,
|
.ctrl_rate_idx = 9,
|
.hw_rate_idx = 9,
|
.arith_shift = 8,
|
.target_pf = 26,
|
},
|
[10] = { .rc_flags = RC_FLAG_LEGACY,
|
.phy_type = WLAN_RC_PHY_OFDM,
|
.rate_kbps = 18000,
|
.dot11_rate_idx = 7,
|
.ctrl_rate_idx = 9,
|
.hw_rate_idx = 10,
|
.arith_shift = 8,
|
.target_pf = 26,
|
},
|
[11] = { .rc_flags = RC_FLAG_LEGACY,
|
.phy_type = WLAN_RC_PHY_OFDM,
|
.rate_kbps = 24000,
|
.dot11_rate_idx = 8,
|
.ctrl_rate_idx = 11,
|
.hw_rate_idx = 11,
|
.arith_shift = 8,
|
.target_pf = 26,
|
},
|
[12] = { .rc_flags = RC_FLAG_LEGACY,
|
.phy_type = WLAN_RC_PHY_OFDM,
|
.rate_kbps = 36000,
|
.dot11_rate_idx = 9,
|
.ctrl_rate_idx = 11,
|
.hw_rate_idx = 12,
|
.arith_shift = 8,
|
.target_pf = 26,
|
},
|
[13] = { .rc_flags = RC_FLAG_LEGACY,
|
.phy_type = WLAN_RC_PHY_OFDM,
|
.rate_kbps = 48000,
|
.dot11_rate_idx = 10,
|
.ctrl_rate_idx = 11,
|
.hw_rate_idx = 13,
|
.arith_shift = 8,
|
.target_pf = 26,
|
},
|
[14] = { .rc_flags = RC_FLAG_LEGACY,
|
.phy_type = WLAN_RC_PHY_OFDM,
|
.rate_kbps = 54000,
|
.dot11_rate_idx = 11,
|
.ctrl_rate_idx = 11,
|
.hw_rate_idx = 14,
|
.arith_shift = 8,
|
.target_pf = 8
|
},
|
[15] = { .rc_flags = RC_FLAG_HT,
|
.phy_type = WLAN_RC_PHY_HT_20_SS_LGI,
|
.rate_kbps = 6500,
|
.dot11_rate_idx = 0,
|
.ctrl_rate_idx = 7,
|
.hw_rate_idx = 15,
|
.arith_shift = 8,
|
.target_pf = 26,
|
},
|
[16] = { .rc_flags = RC_FLAG_HT,
|
.phy_type = WLAN_RC_PHY_HT_20_SS_LGI,
|
.rate_kbps = 13000,
|
.dot11_rate_idx = 1,
|
.ctrl_rate_idx = 9,
|
.hw_rate_idx = 16,
|
.arith_shift = 8,
|
.target_pf = 26,
|
},
|
[17] = { .rc_flags = RC_FLAG_HT,
|
.phy_type = WLAN_RC_PHY_HT_20_SS_LGI,
|
.rate_kbps = 19500,
|
.dot11_rate_idx = 2,
|
.ctrl_rate_idx = 9,
|
.hw_rate_idx = 17,
|
.arith_shift = 8,
|
.target_pf = 26,
|
},
|
[18] = { .rc_flags = RC_FLAG_HT,
|
.phy_type = WLAN_RC_PHY_HT_20_SS_LGI,
|
.rate_kbps = 26000,
|
.dot11_rate_idx = 3,
|
.ctrl_rate_idx = 11,
|
.hw_rate_idx = 18,
|
.arith_shift = 8,
|
.target_pf = 26,
|
},
|
[19] = { .rc_flags = RC_FLAG_HT,
|
.phy_type = WLAN_RC_PHY_HT_20_SS_LGI,
|
.rate_kbps = 39000,
|
.dot11_rate_idx = 4,
|
.ctrl_rate_idx = 11,
|
.hw_rate_idx = 19,
|
.arith_shift = 8,
|
.target_pf = 26,
|
},
|
[20] = { .rc_flags = RC_FLAG_HT,
|
.phy_type = WLAN_RC_PHY_HT_20_SS_LGI,
|
.rate_kbps = 52000,
|
.dot11_rate_idx = 5,
|
.ctrl_rate_idx = 11,
|
.hw_rate_idx = 20,
|
.arith_shift = 8,
|
.target_pf = 26,
|
},
|
[21] = { .rc_flags = RC_FLAG_HT,
|
.phy_type = WLAN_RC_PHY_HT_20_SS_LGI,
|
.rate_kbps = 58500,
|
.dot11_rate_idx = 6,
|
.ctrl_rate_idx = 11,
|
.hw_rate_idx = 21,
|
.arith_shift = 8,
|
.target_pf = 26,
|
},
|
[22] = { .rc_flags = RC_FLAG_HT,
|
.phy_type = WLAN_RC_PHY_HT_20_SS_LGI,
|
.rate_kbps = 65000,
|
.dot11_rate_idx = 7,
|
.ctrl_rate_idx = 11,
|
.hw_rate_idx = 22,
|
.arith_shift = 8,
|
.target_pf = 8
|
},
|
[23] = { .rc_flags = RC_FLAG_HT | RC_FLAG_HT_SGI,
|
.phy_type = WLAN_RC_PHY_HT_20_SS_SGI,
|
.rate_kbps = 7200,
|
.dot11_rate_idx = 0,
|
.ctrl_rate_idx = 7,
|
.hw_rate_idx = 23,
|
.arith_shift = 8,
|
.target_pf = 26,
|
},
|
[24] = { .rc_flags = RC_FLAG_HT | RC_FLAG_HT_SGI,
|
.phy_type = WLAN_RC_PHY_HT_20_SS_SGI,
|
.rate_kbps = 14400,
|
.dot11_rate_idx = 1,
|
.ctrl_rate_idx = 9,
|
.hw_rate_idx = 24,
|
.arith_shift = 8,
|
.target_pf = 26,
|
},
|
[25] = { .rc_flags = RC_FLAG_HT | RC_FLAG_HT_SGI,
|
.phy_type = WLAN_RC_PHY_HT_20_SS_SGI,
|
.rate_kbps = 21700,
|
.dot11_rate_idx = 2,
|
.ctrl_rate_idx = 9,
|
.hw_rate_idx = 25,
|
.arith_shift = 8,
|
.target_pf = 26,
|
},
|
[26] = { .rc_flags = RC_FLAG_HT | RC_FLAG_HT_SGI,
|
.phy_type = WLAN_RC_PHY_HT_20_SS_SGI,
|
.rate_kbps = 28900,
|
.dot11_rate_idx = 3,
|
.ctrl_rate_idx = 11,
|
.hw_rate_idx = 26,
|
.arith_shift = 8,
|
.target_pf = 26,
|
},
|
[27] = { .rc_flags = RC_FLAG_HT | RC_FLAG_HT_SGI,
|
.phy_type = WLAN_RC_PHY_HT_20_SS_SGI,
|
.rate_kbps = 43300,
|
.dot11_rate_idx = 4,
|
.ctrl_rate_idx = 11,
|
.hw_rate_idx = 27,
|
.arith_shift = 8,
|
.target_pf = 26,
|
},
|
[28] = { .rc_flags = RC_FLAG_HT | RC_FLAG_HT_SGI,
|
.phy_type = WLAN_RC_PHY_HT_20_SS_SGI,
|
.rate_kbps = 57800,
|
.dot11_rate_idx = 5,
|
.ctrl_rate_idx = 11,
|
.hw_rate_idx = 28,
|
.arith_shift = 8,
|
.target_pf = 26,
|
},
|
[29] = { .rc_flags = RC_FLAG_HT | RC_FLAG_HT_SGI,
|
.phy_type = WLAN_RC_PHY_HT_20_SS_SGI,
|
.rate_kbps = 65000,
|
.dot11_rate_idx = 6,
|
.ctrl_rate_idx = 11,
|
.hw_rate_idx = 29,
|
.arith_shift = 8,
|
.target_pf = 26,
|
},
|
[30] = { .rc_flags = RC_FLAG_HT | RC_FLAG_HT_SGI,
|
.phy_type = WLAN_RC_PHY_HT_20_SS_SGI,
|
.rate_kbps = 72200,
|
.dot11_rate_idx = 7,
|
.ctrl_rate_idx = 11,
|
.hw_rate_idx = 30,
|
.arith_shift = 8,
|
.target_pf = 8
|
},
|
[31] = { .rc_flags = RC_FLAG_HT | RC_FLAG_HT_GF,
|
.phy_type = WLAN_RC_PHY_HT_20_SS_GF,
|
.rate_kbps = 6500,
|
.dot11_rate_idx = 0,
|
.ctrl_rate_idx = 7,
|
.hw_rate_idx = 31,
|
.arith_shift = 8,
|
.target_pf = 26,
|
},
|
[32] = { .rc_flags = RC_FLAG_HT | RC_FLAG_HT_GF,
|
.phy_type = WLAN_RC_PHY_HT_20_SS_GF,
|
.rate_kbps = 13000,
|
.dot11_rate_idx = 1,
|
.ctrl_rate_idx = 9,
|
.hw_rate_idx = 32,
|
.arith_shift = 8,
|
.target_pf = 26,
|
},
|
[33] = { .rc_flags = RC_FLAG_HT | RC_FLAG_HT_GF,
|
.phy_type = WLAN_RC_PHY_HT_20_SS_GF,
|
.rate_kbps = 19500,
|
.dot11_rate_idx = 2,
|
.ctrl_rate_idx = 9,
|
.hw_rate_idx = 33,
|
.arith_shift = 8,
|
.target_pf = 26,
|
},
|
[34] = { .rc_flags = RC_FLAG_HT | RC_FLAG_HT_GF,
|
.phy_type = WLAN_RC_PHY_HT_20_SS_GF,
|
.rate_kbps = 26000,
|
.dot11_rate_idx = 3,
|
.ctrl_rate_idx = 11,
|
.hw_rate_idx = 34,
|
.arith_shift = 8,
|
.target_pf = 26,
|
},
|
[35] = { .rc_flags = RC_FLAG_HT | RC_FLAG_HT_GF,
|
.phy_type = WLAN_RC_PHY_HT_20_SS_GF,
|
.rate_kbps = 39000,
|
.dot11_rate_idx = 4,
|
.ctrl_rate_idx = 11,
|
.hw_rate_idx = 35,
|
.arith_shift = 8,
|
.target_pf = 26,
|
},
|
[36] = { .rc_flags = RC_FLAG_HT | RC_FLAG_HT_GF,
|
.phy_type = WLAN_RC_PHY_HT_20_SS_GF,
|
.rate_kbps = 52000,
|
.dot11_rate_idx = 5,
|
.ctrl_rate_idx = 11,
|
.hw_rate_idx = 36,
|
.arith_shift = 8,
|
.target_pf = 26,
|
},
|
[37] = { .rc_flags = RC_FLAG_HT | RC_FLAG_HT_GF,
|
.phy_type = WLAN_RC_PHY_HT_20_SS_GF,
|
.rate_kbps = 58500,
|
.dot11_rate_idx = 6,
|
.ctrl_rate_idx = 11,
|
.hw_rate_idx = 37,
|
.arith_shift = 8,
|
.target_pf = 26,
|
},
|
[38] = { .rc_flags = RC_FLAG_HT | RC_FLAG_HT_GF,
|
.phy_type = WLAN_RC_PHY_HT_20_SS_GF,
|
.rate_kbps = 65000,
|
.dot11_rate_idx = 7,
|
.ctrl_rate_idx = 11,
|
.hw_rate_idx = 38,
|
.arith_shift = 8,
|
.target_pf = 8
|
},
|
};
|
const u16 ssv6xxx_rc_rate_set[RC_TYPE_MAX][13] =
|
{
|
[RC_TYPE_B_ONLY] = { 4, 0, 1, 2, 3},
|
[RC_TYPE_LEGACY_GB] = { 12, 0, 1, 2, 7, 8, 3, 9, 10, 11, 12, 13, 14 },
|
#if 0
|
[RC_TYPE_SGI_20] = { 12, 0, 1, 2, 3, 23, 24, 25, 26, 27, 28, 29, 30 },
|
[RC_TYPE_LGI_20] = { 12, 0, 1, 2, 3, 15, 16, 17, 18, 19, 20, 21, 22 },
|
#else
|
[RC_TYPE_SGI_20] = { 8, 23, 24, 25, 26, 27, 28, 29, 30 },
|
[RC_TYPE_LGI_20] = { 8, 15, 16, 17, 18, 19, 20, 21, 22 },
|
#endif
|
[RC_TYPE_HT_SGI_20] = { 8, 23, 24, 25, 26, 27, 28, 29, 30 },
|
[RC_TYPE_HT_LGI_20] = { 8, 15, 16, 17, 18, 19, 20, 21, 22 },
|
[RC_TYPE_HT_GF] = { 8, 31, 32, 33, 34, 35, 36, 37, 38 },
|
};
|
static u32 ssv6xxx_rate_supported(struct ssv_sta_rc_info *rc_sta, u32 index)
|
{
|
return (rc_sta->rc_supp_rates & BIT(index));
|
}
|
#if 1
|
static u8 ssv6xxx_rate_lowest_index(struct ssv_sta_rc_info *rc_sta)
|
{
|
int i;
|
for (i = 0; i < rc_sta->rc_num_rate; i++)
|
if (ssv6xxx_rate_supported(rc_sta, i))
|
return i;
|
return 0;
|
}
|
#endif
|
#ifdef DISABLE_RATE_CONTROL_SAMPLE
|
static u8 ssv6xxx_rate_highest_index(struct ssv_sta_rc_info *rc_sta)
|
{
|
int i;
|
for (i=rc_sta->rc_num_rate-1; i >= 0; i--)
|
if (ssv6xxx_rate_supported(rc_sta, i))
|
return i;
|
return 0;
|
}
|
#endif
|
static void rate_control_pid_adjust_rate(struct ssv_sta_rc_info *rc_sta,
|
struct rc_pid_sta_info *spinfo, int adj,struct rc_pid_rateinfo *rinfo)
|
{
|
int cur_sorted, new_sorted, probe, tmp, n_bitrates;
|
int cur = spinfo->txrate_idx;
|
n_bitrates = rc_sta->rc_num_rate;
|
cur_sorted = rinfo[cur].index;
|
new_sorted = cur_sorted + adj;
|
if (new_sorted < 0)
|
new_sorted = rinfo[0].index;
|
else if (new_sorted >= n_bitrates)
|
new_sorted = rinfo[n_bitrates - 1].index;
|
tmp = new_sorted;
|
if (adj < 0) {
|
for (probe = cur_sorted; probe >= new_sorted; probe--)
|
if (rinfo[probe].diff <= rinfo[cur_sorted].diff &&
|
ssv6xxx_rate_supported(rc_sta, rinfo[probe].index))
|
tmp = probe;
|
} else {
|
for (probe = new_sorted + 1; probe < n_bitrates; probe++)
|
if (rinfo[probe].diff <= rinfo[new_sorted].diff &&
|
ssv6xxx_rate_supported(rc_sta, rinfo[probe].index))
|
tmp = probe;
|
}
|
BUG_ON(tmp<0 || tmp>=n_bitrates);
|
do {
|
if (ssv6xxx_rate_supported(rc_sta, rinfo[tmp].index)) {
|
spinfo->tmp_rate_idx = rinfo[tmp].index;
|
break;
|
}
|
if (adj < 0)
|
tmp--;
|
else
|
tmp++;
|
} while (tmp < n_bitrates && tmp >= 0);
|
spinfo->oldrate = spinfo->txrate_idx;
|
if (spinfo->tmp_rate_idx != spinfo->txrate_idx) {
|
spinfo->monitoring = 1;
|
#ifdef RATE_CONTROL_PARAMETER_DEBUG
|
printk("Trigger monitor tmp_rate_idx=[%d]\n",spinfo->tmp_rate_idx);
|
#endif
|
spinfo->probe_cnt = MAXPROBES;
|
}
|
}
|
static void rate_control_pid_normalize(struct rc_pid_info *pinfo, int l)
|
{
|
int i, norm_offset = RC_PID_NORM_OFFSET;
|
struct rc_pid_rateinfo *r = pinfo->rinfo;
|
if (r[0].diff > norm_offset)
|
r[0].diff -= norm_offset;
|
else if (r[0].diff < -norm_offset)
|
r[0].diff += norm_offset;
|
for (i = 0; i < l - 1; i++)
|
if (r[i + 1].diff > r[i].diff + norm_offset)
|
r[i + 1].diff -= norm_offset;
|
else if (r[i + 1].diff <= r[i].diff)
|
r[i + 1].diff += norm_offset;
|
}
|
#ifdef RATE_CONTROL_DEBUG
|
unsigned int txrate_dlr=0;
|
#endif
|
static void rate_control_pid_sample(struct ssv_rate_ctrl* ssv_rc,struct rc_pid_info *pinfo,
|
struct ssv_sta_rc_info *rc_sta,
|
struct rc_pid_sta_info *spinfo)
|
{
|
struct rc_pid_rateinfo *rinfo = pinfo->rinfo;
|
u8 pf;
|
s32 err_avg;
|
s32 err_prop;
|
s32 err_int;
|
s32 err_der;
|
int adj, i, j, tmp;
|
struct ssv_rc_rate *rc_table;
|
unsigned int dlr;
|
unsigned int perfect_time = 0;
|
unsigned int this_thp, ewma_thp;
|
struct rc_pid_rateinfo *rate;
|
if (!spinfo->monitoring)
|
{
|
#if 0
|
period = msecs_to_jiffies(pinfo->sampling_period);
|
if (jiffies - spinfo->last_sample > 2 * period)
|
spinfo->sharp_cnt = RC_PID_SHARPENING_DURATION;
|
#endif
|
if (spinfo->tx_num_xmit == 0)
|
return;
|
spinfo->last_sample = jiffies;
|
pf = spinfo->tx_num_failed * 100 / spinfo->tx_num_xmit;
|
if (pinfo->rinfo[spinfo->txrate_idx].this_attempt > 0)
|
{
|
rate = &pinfo->rinfo[spinfo->txrate_idx];
|
rc_table = &ssv_rc->rc_table[spinfo->txrate_idx];
|
dlr = 100 - rate->this_fail * 100 / rate->this_attempt;
|
perfect_time = rate->perfect_tx_time;
|
if (!perfect_time)
|
perfect_time = 1000000;
|
this_thp = dlr * (1000000 / perfect_time);
|
ewma_thp = rate->throughput;
|
if (ewma_thp == 0)
|
rate->throughput = this_thp;
|
else
|
rate->throughput = (ewma_thp + this_thp) >> 1;
|
rate->attempt += rate->this_attempt;
|
rate->success += rate->this_success;
|
rate->fail += rate->this_fail;
|
spinfo->tx_num_xmit = 0;
|
spinfo->tx_num_failed = 0;
|
rate->this_fail = 0;
|
rate->this_success = 0;
|
rate->this_attempt = 0;
|
if (pinfo->oldrate<0 || pinfo->oldrate>=rc_sta->rc_num_rate)
|
{
|
WARN_ON(1);
|
}
|
if (spinfo->txrate_idx<0 || spinfo->txrate_idx>=rc_sta->rc_num_rate)
|
{
|
WARN_ON(1);
|
}
|
if (pinfo->oldrate != spinfo->txrate_idx) {
|
i = rinfo[pinfo->oldrate].index;
|
j = rinfo[spinfo->txrate_idx].index;
|
tmp = (pf - spinfo->last_pf);
|
tmp = RC_PID_DO_ARITH_RIGHT_SHIFT(tmp, rc_table->arith_shift);
|
rinfo[j].diff = rinfo[i].diff + tmp;
|
pinfo->oldrate = spinfo->txrate_idx;
|
}
|
rate_control_pid_normalize(pinfo, rc_sta->rc_num_rate);
|
err_prop = (rc_table->target_pf - pf) << rc_table->arith_shift;
|
err_avg = spinfo->err_avg_sc >> RC_PID_SMOOTHING_SHIFT;
|
spinfo->err_avg_sc = spinfo->err_avg_sc - err_avg + err_prop;
|
err_int = spinfo->err_avg_sc >> RC_PID_SMOOTHING_SHIFT;
|
err_der = pf - spinfo->last_pf;
|
spinfo->last_pf = pf;
|
spinfo->last_dlr = dlr;
|
spinfo->oldrate = spinfo->txrate_idx;
|
#if 0
|
if (spinfo->sharp_cnt)
|
spinfo->sharp_cnt--;
|
#endif
|
adj = (err_prop * RC_PID_COEFF_P + err_int * RC_PID_COEFF_I + err_der * RC_PID_COEFF_D);
|
adj = RC_PID_DO_ARITH_RIGHT_SHIFT(adj, rc_table->arith_shift<<1);
|
if (adj) {
|
#ifdef RATE_CONTROL_PARAMETER_DEBUG
|
if((spinfo->txrate_idx!=11) || ((spinfo->txrate_idx==11)&&(adj < 0)))
|
printk("[RC]Probe adjust[%d] dlr[%d%%] this_thp[%d] ewma_thp[%d] index[%d]\n",adj ,dlr,this_thp,ewma_thp,spinfo->txrate_idx);
|
#endif
|
rate_control_pid_adjust_rate(rc_sta, spinfo, adj, rinfo);
|
}
|
}
|
}
|
else
|
{
|
if((spinfo->feedback_probes >= MAXPROBES) || (spinfo->feedback_probes && spinfo->probe_cnt))
|
{
|
rate = &pinfo->rinfo[spinfo->txrate_idx];
|
#if 0
|
period = msecs_to_jiffies(pinfo->sampling_period);
|
if (jiffies - spinfo->last_sample > 2 * period)
|
spinfo->sharp_cnt = RC_PID_SHARPENING_DURATION;
|
#endif
|
spinfo->last_sample = jiffies;
|
if (rate->this_attempt > 0) {
|
dlr = 100 - rate->this_fail * 100 / rate->this_attempt;
|
#ifdef RATE_CONTROL_DEBUG
|
#ifdef PROBE
|
txrate_dlr=dlr;
|
#endif
|
#endif
|
spinfo->last_dlr = dlr;
|
perfect_time = rate->perfect_tx_time;
|
if (!perfect_time)
|
perfect_time = 1000000;
|
this_thp = dlr * (1000000 / perfect_time);
|
ewma_thp = rate->throughput;
|
if (ewma_thp == 0)
|
rate->throughput = this_thp;
|
else
|
rate->throughput = (ewma_thp + this_thp) >> 1;
|
rate->attempt += rate->this_attempt;
|
rate->success += rate->this_success;
|
rinfo[spinfo->txrate_idx].fail += rate->this_fail;
|
rate->this_fail = 0;
|
rate->this_success = 0;
|
rate->this_attempt = 0;
|
}
|
else
|
{
|
#ifdef RATE_CONTROL_DEBUG
|
#ifdef PROBE
|
txrate_dlr=0;
|
#endif
|
#endif
|
}
|
rate = &pinfo->rinfo[spinfo->tmp_rate_idx];
|
if (rate->this_attempt > 0) {
|
dlr = 100 - ((rate->this_fail * 100) / rate->this_attempt);
|
{
|
perfect_time = rate->perfect_tx_time;
|
if (!perfect_time)
|
perfect_time = 1000000;
|
if(dlr)
|
this_thp = dlr * (1000000 / perfect_time);
|
else
|
this_thp = 0;
|
ewma_thp = rate->throughput;
|
if (ewma_thp == 0)
|
rate->throughput = this_thp;
|
else
|
rate->throughput = (ewma_thp + this_thp) >> 1;
|
if (rate->throughput > pinfo->rinfo[spinfo->txrate_idx].throughput)
|
{
|
#ifdef RATE_CONTROL_PARAMETER_DEBUG
|
printk("[RC]UPDATE probe rate idx[%d] [%d][%d%%] Old idx[%d] [%d][%d%%] feedback[%d] \n",spinfo->tmp_rate_idx,rate->throughput,dlr,spinfo->txrate_idx,pinfo->rinfo[spinfo->txrate_idx].throughput,txrate_dlr,spinfo->feedback_probes);
|
#endif
|
spinfo->txrate_idx = spinfo->tmp_rate_idx;
|
}
|
else
|
{
|
#ifdef RATE_CONTROL_PARAMETER_DEBUG
|
printk("[RC]Fail probe rate idx[%d] [%d][%d%%] Old idx[%d] [%d][%d%%] feedback[%d] \n",spinfo->tmp_rate_idx,rate->throughput,dlr,spinfo->txrate_idx,pinfo->rinfo[spinfo->txrate_idx].throughput,txrate_dlr,spinfo->feedback_probes);
|
#endif
|
;
|
}
|
rate->attempt += rate->this_attempt;
|
rate->success += rate->this_success;
|
rate->fail += rate->this_fail;
|
rate->this_fail = 0;
|
rate->this_success = 0;
|
rate->this_attempt = 0;
|
spinfo->oldrate = spinfo->txrate_idx;
|
}
|
}
|
#ifdef RATE_CONTROL_DEBUG
|
else
|
printk("SHIT-2!!!!\n");
|
#endif
|
spinfo->feedback_probes = 0;
|
spinfo->tx_num_xmit = 0;
|
spinfo->tx_num_failed = 0;
|
spinfo->monitoring = 0;
|
#ifdef RATE_CONTROL_PARAMETER_DEBUG
|
printk("Disable monitor\n");
|
#endif
|
spinfo->probe_report_flag = 0;
|
spinfo->probe_wating_times = 0;
|
}
|
else
|
{
|
spinfo->probe_wating_times ++;
|
#ifdef RATE_CONTROL_DEBUG
|
if(spinfo->probe_wating_times > 3)
|
{
|
printk("[RC]@@@@@ PROBE LOSE @@@@@ feedback=[%d] need=[%d] probe_cnt=[%d] wating times[%d]\n",
|
spinfo->feedback_probes,MAXPROBES,spinfo->probe_cnt,spinfo->probe_wating_times);
|
spinfo->feedback_probes = 0;
|
spinfo->tx_num_xmit = 0;
|
spinfo->tx_num_failed = 0;
|
spinfo->monitoring = 0;
|
spinfo->probe_report_flag = 0;
|
spinfo->probe_wating_times = 0;
|
}
|
#else
|
if(spinfo->probe_wating_times > 3)
|
{
|
spinfo->feedback_probes = 0;
|
spinfo->tx_num_xmit = 0;
|
spinfo->tx_num_failed = 0;
|
spinfo->monitoring = 0;
|
spinfo->probe_report_flag = 0;
|
spinfo->probe_wating_times = 0;
|
}
|
#endif
|
}
|
}
|
}
|
#ifdef RATE_CONTROL_PERCENTAGE_TRACE
|
int percentage = 0;
|
int percentageCounter = 0;
|
#endif
|
void ssv6xxx_legacy_report_handler(struct ssv_softc *sc,struct sk_buff *skb,struct ssv_sta_rc_info *rc_sta)
|
{
|
struct ssv_rate_ctrl *ssv_rc=sc->rc;
|
struct cfg_host_event *host_event;
|
struct firmware_rate_control_report_data *report_data;
|
struct rc_pid_info *pinfo;
|
struct rc_pid_sta_info *spinfo;
|
struct rc_pid_rateinfo * pidrate;
|
struct rc_pid_rateinfo *rate;
|
s32 report_data_index = 0;
|
unsigned long period;
|
host_event = (struct cfg_host_event *)skb->data;
|
report_data = (struct firmware_rate_control_report_data *)&host_event->dat[0];
|
if ( (report_data->wsid != (-1))
|
&& sc->sta_info[report_data->wsid].sta == NULL)
|
{
|
dev_warn(sc->dev, "RC report has no valid STA.(%d)\n", report_data->wsid);
|
return;
|
}
|
pinfo = &rc_sta->pinfo;
|
spinfo = &rc_sta->spinfo;
|
pidrate = rc_sta->pinfo.rinfo;
|
if(host_event->h_event == SOC_EVT_RC_AMPDU_REPORT)
|
{
|
#if 1
|
period = msecs_to_jiffies(HT_RC_UPDATE_INTERVAL);
|
if (time_after(jiffies, spinfo->last_sample + period))
|
{
|
if(rc_sta->rc_num_rate == 12)
|
spinfo->txrate_idx = rc_sta->ht.max_tp_rate + 4;
|
else
|
spinfo->txrate_idx = rc_sta->ht.max_tp_rate;
|
#ifdef RATE_CONTROL_DEBUG
|
printk("MPDU rate update time txrate_idx[%d]!!\n",spinfo->txrate_idx);
|
#endif
|
spinfo->last_sample = jiffies;
|
}
|
#endif
|
return;
|
}
|
else if(host_event->h_event == SOC_EVT_RC_MPDU_REPORT)
|
{
|
#if 0
|
printk("SC report !MPDU! wsid[%d]rate[%d]M[%d]S[%d]R[%d]\n",report_data->wsid,report_data->rates[0].data_rate,
|
report_data->ampdu_len,report_data->ampdu_ack_len,report_data->rates[0].count);
|
#endif
|
;
|
}
|
else
|
{
|
printk("RC work get garbage!!\n");
|
return;
|
}
|
if(report_data->rates[0].data_rate < 7)
|
{
|
if(report_data->rates[0].data_rate>3)
|
{
|
report_data->rates[0].data_rate -= 3;
|
}
|
}
|
if(ssv_rc->rc_table[rc_sta->pinfo.rinfo[spinfo->txrate_idx].rc_index].hw_rate_idx == report_data->rates[0].data_rate)
|
{
|
report_data_index = rc_sta->pinfo.rinfo[spinfo->txrate_idx].index;
|
}
|
else if(ssv_rc->rc_table[rc_sta->pinfo.rinfo[spinfo->tmp_rate_idx].rc_index].hw_rate_idx == report_data->rates[0].data_rate)
|
{
|
report_data_index = rc_sta->pinfo.rinfo[spinfo->tmp_rate_idx].index;
|
}
|
if((report_data_index != spinfo->tmp_rate_idx) && (report_data_index != spinfo->txrate_idx))
|
{
|
#ifdef RATE_CONTROL_DEBUG
|
printk("Rate control report mismatch report_rate_idx[%d] tmp_rate_idx[%d]rate[%d] txrate_idx[%d]rate[%d]!!\n",
|
report_data->rates[0].data_rate,spinfo->tmp_rate_idx,
|
ssv_rc->rc_table[rc_sta->pinfo.rinfo[spinfo->tmp_rate_idx].rc_index].hw_rate_idx,
|
spinfo->txrate_idx,
|
ssv_rc->rc_table[rc_sta->pinfo.rinfo[spinfo->txrate_idx].rc_index].hw_rate_idx);
|
#endif
|
return;
|
}
|
if(report_data_index == spinfo->txrate_idx)
|
{
|
spinfo->tx_num_xmit += report_data->rates[0].count;
|
spinfo->tx_num_failed += (report_data->rates[0].count - report_data->ampdu_ack_len );
|
rate = &pidrate[spinfo->txrate_idx];
|
rate->this_fail += ( report_data->rates[0].count - report_data->ampdu_ack_len );
|
rate->this_attempt += report_data->rates[0].count;
|
rate->this_success += report_data->ampdu_ack_len;
|
}
|
if (report_data_index != spinfo->txrate_idx && report_data_index == spinfo->tmp_rate_idx)
|
{
|
spinfo->feedback_probes += report_data->ampdu_len;
|
rate = &pidrate[spinfo->tmp_rate_idx];
|
rate->this_fail += ( report_data->rates[0].count - report_data->ampdu_ack_len );
|
rate->this_attempt += report_data->rates[0].count;
|
rate->this_success += report_data->ampdu_ack_len;
|
}
|
period = msecs_to_jiffies(RC_PID_INTERVAL);
|
if (time_after(jiffies, spinfo->last_sample + period))
|
{
|
#ifdef RATE_CONTROL_PERCENTAGE_TRACE
|
rate = &pidrate[spinfo->txrate_idx];
|
if(rate->this_success > rate->this_attempt)
|
{
|
printk("#############################\n");
|
printk("this_success[%ld] this_attempt[%ld]\n",rate->this_success,rate->this_attempt);
|
printk("#############################\n");
|
}
|
else
|
{
|
if(percentage == 0)
|
percentage = (int)((rate->this_success*100)/rate->this_attempt);
|
else
|
percentage = (percentage + (int)((rate->this_success*100)/rate->this_attempt))/2;
|
printk("Percentage[%d]\n",percentage);
|
if((percentageCounter % 16)==1)
|
percentage = 0;
|
}
|
#endif
|
#ifdef RATE_CONTROL_STUPID_DEBUG
|
if (spinfo->txrate_idx != spinfo->tmp_rate_idx)
|
{
|
rate = &pidrate[spinfo->tmp_rate_idx];
|
if (spinfo->monitoring && ((rate->this_attempt == 0)||(rate->this_attempt!=MAXPROBES)))
|
{
|
printk("Probe result a[%ld]s[%ld]f[%ld]",rate->this_attempt,rate->this_success,rate->this_fail);
|
}
|
rate = &pidrate[spinfo->txrate_idx];
|
printk("New a[%ld]s[%ld]f[%ld] \n",rate->this_attempt,rate->this_success,rate->this_fail);
|
}
|
else
|
{
|
rate = &pidrate[spinfo->txrate_idx];
|
printk("New a[%ld]s[%ld]f[%ld] \n",rate->this_attempt,rate->this_success,rate->this_fail);
|
}
|
printk("w[%d]x%03d-f%03d\n",rc_sta->rc_wsid,spinfo->tx_num_xmit,spinfo->tx_num_failed);
|
#endif
|
rate_control_pid_sample(sc->rc, pinfo, rc_sta, spinfo);
|
}
|
}
|
void ssv6xxx_sample_work(struct work_struct *work)
|
{
|
struct ssv_softc *sc = container_of(work, struct ssv_softc, rc_sample_work);
|
struct ssv_rate_ctrl *ssv_rc=sc->rc;
|
struct sk_buff *skb;
|
struct cfg_host_event *host_event;
|
struct ssv_sta_rc_info *rc_sta=NULL;
|
struct firmware_rate_control_report_data *report_data;
|
struct ssv_sta_info *ssv_sta;
|
u8 hw_wsid = 0;
|
sc->rc_sample_sechedule = 1;
|
while(1)
|
{
|
skb = skb_dequeue(&sc->rc_report_queue);
|
if(skb == NULL)
|
break;
|
#ifdef DISABLE_RATE_CONTROL_SAMPLE
|
{
|
dev_kfree_skb_any(skb);
|
continue;
|
}
|
#endif
|
host_event = (struct cfg_host_event *)skb->data;
|
if((host_event->h_event == SOC_EVT_RC_AMPDU_REPORT) || (host_event->h_event == SOC_EVT_RC_MPDU_REPORT))
|
{
|
report_data = (struct firmware_rate_control_report_data *)&host_event->dat[0];
|
hw_wsid = report_data->wsid;
|
}
|
else
|
{
|
printk("RC work get garbage!!\n");
|
dev_kfree_skb_any(skb);
|
continue;
|
}
|
if(hw_wsid >= SSV_RC_MAX_HARDWARE_SUPPORT)
|
{
|
#ifdef RATE_CONTROL_DEBUG
|
printk("[RC]rc_sta is NULL pointer Check-0!!\n");
|
#endif
|
dev_kfree_skb_any(skb);
|
continue;
|
}
|
ssv_sta = &sc->sta_info[hw_wsid];
|
if (ssv_sta->sta == NULL)
|
{
|
dev_err(sc->dev, "Null STA %d for RC report.\n", hw_wsid);
|
rc_sta = NULL;
|
}
|
else
|
{
|
struct ssv_sta_priv_data *ssv_sta_priv = (struct ssv_sta_priv_data *)ssv_sta->sta->drv_priv;
|
rc_sta = &ssv_rc->sta_rc_info[ssv_sta_priv->rc_idx];
|
if (rc_sta->rc_wsid != hw_wsid)
|
{
|
rc_sta = NULL;
|
}
|
}
|
if(rc_sta == NULL)
|
{
|
dev_err(sc->dev, "[RC]rc_sta is NULL pointer Check-1!!\n");
|
dev_kfree_skb_any(skb);
|
continue;
|
}
|
#if 0
|
if(rc_sta->rc_wsid != hw_wsid)
|
{
|
printk("[RC] wsid mapping [ERROR] feedback wsid[%d] rc_wsid[%d]...><\n",hw_wsid,rc_sta->rc_wsid);
|
#if 1
|
for(i=0;i<SSV_RC_MAX_STA;i++)
|
{
|
rc_sta = &ssv_rc->sta_rc_info[i];
|
if(rc_sta == NULL)
|
break;
|
if(hw_wsid == rc_sta->rc_wsid)
|
{
|
printk("[RC] Get new mapping-%d-%d...@o@\n",hw_wsid, i);
|
break;
|
}
|
}
|
if(i == SSV_RC_MAX_STA)
|
#endif
|
rc_sta = NULL;
|
}
|
#endif
|
if(rc_sta == NULL)
|
{
|
#ifdef RATE_CONTROL_DEBUG
|
printk("[RC]rc_sta is NULL pointer Check-2!!\n");
|
#endif
|
dev_kfree_skb_any(skb);
|
continue;
|
}
|
if(rc_sta->is_ht)
|
{
|
ssv6xxx_legacy_report_handler(sc,skb,rc_sta);
|
ssv6xxx_ht_report_handler(sc,skb,rc_sta);
|
}
|
else
|
ssv6xxx_legacy_report_handler(sc,skb,rc_sta);
|
dev_kfree_skb_any(skb);
|
}
|
sc->rc_sample_sechedule = 0;
|
}
|
static void ssv6xxx_tx_status(void *priv, struct ieee80211_supported_band *sband,
|
struct ieee80211_sta *sta, void *priv_sta,
|
struct sk_buff *skb)
|
{
|
struct ssv_softc *sc;
|
struct ieee80211_hdr *hdr;
|
__le16 fc;
|
hdr = (struct ieee80211_hdr *)skb->data;
|
fc = hdr->frame_control;
|
if (!priv_sta || !ieee80211_is_data_qos(fc))
|
return;
|
sc = (struct ssv_softc *)priv;
|
if ( conf_is_ht(&sc->hw->conf)
|
&& (!(skb->protocol == cpu_to_be16(ETH_P_PAE))))
|
{
|
if (skb_get_queue_mapping(skb) != IEEE80211_AC_VO)
|
ssv6200_ampdu_tx_update_state(priv, sta, skb);
|
}
|
return;
|
}
|
#if 1
|
static void rateControlGetRate(u8 rateIndex, char * pointer)
|
{
|
switch(rateIndex)
|
{
|
case 0:
|
sprintf(pointer, "1Mbps");
|
return;
|
case 1:
|
case 4:
|
sprintf(pointer, "2Mbps");
|
return;
|
case 2:
|
case 5:
|
sprintf(pointer, "5.5Mbps");
|
return;
|
case 3:
|
case 6:
|
sprintf(pointer, "11Mbps");
|
return;
|
case 7:
|
sprintf(pointer, "6Mbps");
|
return;
|
case 8:
|
sprintf(pointer, "9Mbps");
|
return;
|
case 9:
|
sprintf(pointer, "12Mbps");
|
return;
|
case 10:
|
sprintf(pointer, "18Mbps");
|
return;
|
case 11:
|
sprintf(pointer, "24Mbps");
|
return;
|
case 12:
|
sprintf(pointer, "36Mbps");
|
return;
|
case 13:
|
sprintf(pointer, "48Mbps");
|
return;
|
case 14:
|
sprintf(pointer, "54Mbps");
|
return;
|
case 15:
|
case 31:
|
sprintf(pointer, "MCS0-l");
|
return;
|
case 16:
|
case 32:
|
sprintf(pointer, "MCS1-l");
|
return;
|
case 17:
|
case 33:
|
sprintf(pointer, "MCS2-l");
|
return;
|
case 18:
|
case 34:
|
sprintf(pointer, "MCS3-l");
|
return;
|
case 19:
|
case 35:
|
sprintf(pointer, "MCS4-l");
|
return;
|
case 20:
|
case 36:
|
sprintf(pointer, "MCS5-l");
|
return;
|
case 21:
|
case 37:
|
sprintf(pointer, "MCS6-l");
|
return;
|
case 22:
|
case 38:
|
sprintf(pointer, "MCS7-l");
|
return;
|
case 23:
|
sprintf(pointer, "MCS0-s");
|
return;
|
case 24:
|
sprintf(pointer, "MCS1-s");
|
return;
|
case 25:
|
sprintf(pointer, "MCS2-s");
|
return;
|
case 26:
|
sprintf(pointer, "MCS3-s");
|
return;
|
case 27:
|
sprintf(pointer, "MCS4-s");
|
return;
|
case 28:
|
sprintf(pointer, "MCS5-s");
|
return;
|
case 29:
|
sprintf(pointer, "MCS6-s");
|
return;
|
case 30:
|
sprintf(pointer, "MCS7-s");
|
return;
|
default:
|
sprintf(pointer, "Unknow");
|
return;
|
};
|
}
|
#endif
|
static void ssv6xxx_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
|
struct ieee80211_tx_rate_control *txrc)
|
{
|
struct ssv_softc *sc=priv;
|
struct ssv_rate_ctrl *ssv_rc=sc->rc;
|
struct ssv_sta_rc_info *rc_sta=priv_sta;
|
struct sk_buff *skb = txrc->skb;
|
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
|
struct ieee80211_tx_rate *rates = tx_info->control.rates;
|
struct rc_pid_sta_info *spinfo=&rc_sta->spinfo;
|
struct ssv_rc_rate *rc_rate = NULL;
|
struct ssv_sta_priv_data *ssv_sta_priv;
|
int rateidx = 99;
|
#if 0
|
if ( (tx_info->control.vif != NULL)
|
&& (tx_info->control.vif->p2p))
|
{
|
tx_info->flags |= IEEE80211_TX_CTL_NO_CCK_RATE;
|
}
|
#endif
|
if (rate_control_send_low(sta, priv_sta, txrc))
|
{
|
int i = 0;
|
int total_rates = (sizeof(ssv_11bgn_rate_table) / sizeof(ssv_11bgn_rate_table[0]));
|
#if 1
|
if ((txrc->rate_idx_mask & (1 << rates[0].idx)) == 0)
|
{
|
u32 rate_idx = rates[0].idx + 1;
|
u32 rate_idx_mask = txrc->rate_idx_mask >> rate_idx;
|
while (rate_idx_mask && (rate_idx_mask & 1) == 0)
|
{
|
rate_idx_mask >>= 1;
|
rate_idx++;
|
}
|
if (rate_idx_mask)
|
rates[0].idx = rate_idx;
|
else
|
{
|
WARN_ON(rate_idx_mask == 0);
|
}
|
}
|
#endif
|
for (i = 0; i < total_rates; i++)
|
{
|
if (rates[0].idx == ssv_11bgn_rate_table[i].dot11_rate_idx)
|
{
|
break;
|
}
|
}
|
if (i < total_rates)
|
rc_rate = &ssv_rc->rc_table[i];
|
else
|
{
|
WARN_ON("Failed to find matching low rate.");
|
}
|
}
|
if (rc_rate == NULL) {
|
if (conf_is_ht(&sc->hw->conf) &&
|
(sta->ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING))
|
tx_info->flags |= IEEE80211_TX_CTL_LDPC;
|
if (conf_is_ht(&sc->hw->conf) &&
|
(sta->ht_cap.cap & IEEE80211_HT_CAP_TX_STBC))
|
tx_info->flags |= (1 << IEEE80211_TX_CTL_STBC_SHIFT);
|
if (sc->sc_flags & SC_OP_FIXED_RATE) {
|
rateidx = sc->max_rate_idx;
|
}
|
else {
|
if (rc_sta->rc_valid == false) {
|
rateidx = 0;
|
}
|
else {
|
if ((rc_sta->rc_wsid >= SSV_RC_MAX_HARDWARE_SUPPORT) || (rc_sta->rc_wsid < 0))
|
{
|
ssv_sta_priv = (struct ssv_sta_priv_data *)sta->drv_priv;
|
{
|
if ((rc_sta->ht_rc_type >= RC_TYPE_HT_SGI_20) &&
|
(ssv_sta_priv->rx_data_rate < SSV62XX_RATE_MCS_INDEX))
|
{
|
rateidx = rc_sta->pinfo.rinfo[spinfo->txrate_idx].rc_index;
|
#if 0
|
printk("RC %d rx %d tx %d\n", ssv_sta_priv->sta_idx,
|
ssv_sta_priv->rx_data_rate, rateidx);
|
#endif
|
}
|
else
|
{
|
rateidx = ssv_sta_priv->rx_data_rate;
|
}
|
}
|
}
|
else
|
{
|
if (rc_sta->is_ht)
|
{
|
#ifdef DISABLE_RATE_CONTROL_SAMPLE
|
rateidx = rc_sta->ht.groups.rates[MCS_GROUP_RATES-1].rc_index;
|
#else
|
rateidx = rc_sta->pinfo.rinfo[spinfo->txrate_idx].rc_index;
|
#endif
|
}
|
else
|
{
|
#if 0
|
if (spinfo->monitoring && spinfo->probe_cnt > 0) {
|
rateidx = rc_sta->pinfo.rinfo[spinfo->tmp_rate_idx].rc_index;
|
spinfo->probe_cnt--;
|
}
|
else
|
#endif
|
{
|
BUG_ON(spinfo->txrate_idx >= rc_sta->rc_num_rate);
|
rateidx = rc_sta->pinfo.rinfo[spinfo->txrate_idx].rc_index;
|
}
|
if(rateidx<4)
|
{
|
if(rateidx)
|
{
|
if ((sc->sc_flags & SC_OP_SHORT_PREAMBLE)||(txrc->short_preamble))
|
{
|
rateidx += 3;
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
rc_rate = &ssv_rc->rc_table[rateidx];
|
#if 1
|
if (spinfo->real_hw_index != rc_rate->hw_rate_idx)
|
{
|
char string[24];
|
rateControlGetRate(rc_rate->hw_rate_idx,string);
|
}
|
#endif
|
spinfo->real_hw_index = rc_rate->hw_rate_idx;
|
rates[0].count = 4;
|
rates[0].idx = rc_rate->dot11_rate_idx;
|
tx_info->control.rts_cts_rate_idx =
|
ssv_rc->rc_table[rc_rate->ctrl_rate_idx].dot11_rate_idx;
|
if (rc_rate->rc_flags & RC_FLAG_SHORT_PREAMBLE)
|
rates[0].flags |= IEEE80211_TX_RC_USE_SHORT_PREAMBLE;
|
if (rc_rate->rc_flags & RC_FLAG_HT) {
|
rates[0].flags |= IEEE80211_TX_RC_MCS;
|
if (rc_rate->rc_flags & RC_FLAG_HT_SGI)
|
rates[0].flags |= IEEE80211_TX_RC_SHORT_GI;
|
if (rc_rate->rc_flags & RC_FLAG_HT_GF)
|
rates[0].flags |= IEEE80211_TX_RC_GREEN_FIELD;
|
}
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,5,0)
|
if (txrc->rts)
|
{
|
rates[0].flags |= IEEE80211_TX_RC_USE_RTS_CTS;
|
}
|
if ((tx_info->control.vif &&
|
tx_info->control.vif->bss_conf.use_cts_prot) &&
|
(rc_rate->phy_type==WLAN_RC_PHY_OFDM ||
|
rc_rate->phy_type>WLAN_RC_PHY_OFDM))
|
{
|
rates[0].flags |= IEEE80211_TX_RC_USE_CTS_PROTECT;
|
tx_info->control.rts_cts_rate_idx = 1;
|
}
|
#endif
|
}
|
rates[1].count = 0;
|
rates[1].idx = -1;
|
rates[SSV_DRATE_IDX].count = rc_rate->hw_rate_idx;
|
rc_rate = &ssv_rc->rc_table[rc_rate->ctrl_rate_idx];
|
rates[SSV_CRATE_IDX].count = rc_rate->hw_rate_idx;
|
}
|
int pide_frame_duration(size_t len,
|
int rate, int short_preamble, int flags)
|
{
|
int dur=0;
|
if (flags == WLAN_RC_PHY_CCK)
|
{
|
dur = 10;
|
dur += short_preamble ? (72 + 24) : (144 + 48);
|
dur += DIV_ROUND_UP(8 * (len + 4) * 10, rate);
|
}
|
else {
|
dur = 16;
|
dur += 16;
|
dur += 4;
|
dur += 4 * DIV_ROUND_UP((16 + 8 * (len + 4) + 6) * 10,
|
4 * rate);
|
}
|
return dur;
|
}
|
static void ssv62xx_rc_caps(struct ssv_sta_rc_info *rc_sta)
|
{
|
struct rc_pid_sta_info *spinfo;
|
struct rc_pid_info *pinfo;
|
struct rc_pid_rateinfo *rinfo;
|
int i;
|
spinfo = &rc_sta->spinfo;
|
pinfo = &rc_sta->pinfo;
|
memset(spinfo, 0, sizeof(struct rc_pid_sta_info));
|
memset(pinfo, 0, sizeof(struct rc_pid_info));
|
rinfo = rc_sta->pinfo.rinfo;
|
for(i=0; i<rc_sta->rc_num_rate; i++) {
|
rinfo[i].rc_index = ssv6xxx_rc_rate_set[rc_sta->rc_type][i+1];
|
rinfo[i].diff = i * RC_PID_NORM_OFFSET;
|
rinfo[i].index = (u16)i;
|
rinfo[i].perfect_tx_time = TDIFS + (TSLOT * 15 >> 1) + pide_frame_duration(1530,
|
ssv_11bgn_rate_table[rinfo[i].rc_index].rate_kbps/100, 1,ssv_11bgn_rate_table[rinfo[i].rc_index].phy_type) +
|
pide_frame_duration(10, ssv_11bgn_rate_table[rinfo[i].rc_index].rate_kbps/100, 1,ssv_11bgn_rate_table[rinfo[i].rc_index].phy_type);
|
#if 1
|
printk("[RC]Init perfect_tx_time[%d][%d]\n",i,rinfo[i].perfect_tx_time);
|
#endif
|
rinfo[i].throughput = 0;
|
}
|
if(rc_sta->is_ht)
|
{
|
if(ssv6xxx_rc_rate_set[rc_sta->ht_rc_type][0] == 12)
|
spinfo->txrate_idx = 4;
|
else
|
spinfo->txrate_idx = 0;
|
}
|
else
|
{
|
spinfo->txrate_idx = ssv6xxx_rate_lowest_index(rc_sta);
|
#ifdef DISABLE_RATE_CONTROL_SAMPLE
|
spinfo->txrate_idx = ssv6xxx_rate_highest_index(rc_sta);
|
#endif
|
}
|
spinfo->real_hw_index = 0;
|
spinfo->probe_cnt = MAXPROBES;
|
spinfo->tmp_rate_idx = spinfo->txrate_idx;
|
spinfo->oldrate = spinfo->txrate_idx;
|
spinfo->last_sample = jiffies;
|
spinfo->last_report = jiffies;
|
}
|
static void ssv6xxx_rate_update_rc_type(void *priv, struct ieee80211_supported_band *sband,
|
struct ieee80211_sta *sta, void *priv_sta)
|
{
|
struct ssv_softc *sc=priv;
|
struct ssv_hw *sh=sc->sh;
|
struct ssv_sta_rc_info *rc_sta=priv_sta;
|
int i;
|
u32 ht_supp_rates = 0;
|
BUG_ON(rc_sta->rc_valid == false);
|
printk("[I] %s(): \n", __FUNCTION__);
|
rc_sta->ht_supp_rates = 0;
|
rc_sta->rc_supp_rates = 0;
|
rc_sta->is_ht = 0;
|
#ifndef CONFIG_CH14_SUPPORT_GN_MODE
|
if(sc->cur_channel->hw_value == 14)
|
{
|
printk("[RC init ]Channel 14 support\n");
|
if((sta->supp_rates[sband->band] & (~0xfL)) == 0x0)
|
{
|
printk("[RC init ]B only mode\n");
|
rc_sta->rc_type = RC_TYPE_B_ONLY;
|
}
|
else
|
{
|
printk("[RC init ]GB mode\n");
|
rc_sta->rc_type = RC_TYPE_LEGACY_GB;
|
}
|
}
|
else
|
#endif
|
if (sta->ht_cap.ht_supported == true) {
|
printk("[RC init ]HT support wsid\n");
|
for (i = 0; i < SSV_HT_RATE_MAX; i++) {
|
if (sta->ht_cap.mcs.rx_mask[i/MCS_GROUP_RATES] & (1<<(i%MCS_GROUP_RATES)))
|
ht_supp_rates |= BIT(i);
|
}
|
rc_sta->ht_supp_rates = ht_supp_rates;
|
if (sta->ht_cap.cap & IEEE80211_HT_CAP_GRN_FLD)
|
{
|
rc_sta->rc_type = RC_TYPE_HT_GF;
|
rc_sta->ht_rc_type = RC_TYPE_HT_GF;
|
}
|
else if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20)
|
{
|
rc_sta->rc_type = RC_TYPE_SGI_20;
|
rc_sta->ht_rc_type = RC_TYPE_HT_SGI_20;
|
}
|
else
|
{
|
rc_sta->rc_type = RC_TYPE_LGI_20;
|
rc_sta->ht_rc_type = RC_TYPE_HT_LGI_20;
|
}
|
}
|
else
|
{
|
if((sta->supp_rates[sband->band] & (~0xfL)) == 0x0){
|
rc_sta->rc_type = RC_TYPE_B_ONLY;
|
printk("[RC init ]B only mode\n");
|
}
|
else{
|
rc_sta->rc_type = RC_TYPE_LEGACY_GB;
|
printk("[RC init ]legacy G mode\n");
|
}
|
}
|
#ifdef CONFIG_SSV_DPD
|
#ifdef CONFIG_SSV_CABRIO_E
|
if(rc_sta->rc_type == RC_TYPE_B_ONLY)
|
{
|
SMAC_REG_WRITE(sh, ADR_TX_FE_REGISTER, 0x3D3E84FE);
|
SMAC_REG_WRITE(sh, ADR_RX_FE_REGISTER_1, 0x1457D79);
|
SMAC_REG_WRITE(sh, ADR_DPD_CONTROL, 0x0);
|
}
|
else
|
{
|
SMAC_REG_WRITE(sh, ADR_TX_FE_REGISTER, 0x3CBE84FE);
|
SMAC_REG_WRITE(sh, ADR_RX_FE_REGISTER_1, 0x4507F9);
|
SMAC_REG_WRITE(sh, ADR_DPD_CONTROL, 0x3);
|
}
|
#endif
|
#endif
|
if((rc_sta->rc_type != RC_TYPE_B_ONLY) && (rc_sta->rc_type != RC_TYPE_LEGACY_GB))
|
{
|
if ((sta->ht_cap.ht_supported) && (sh->cfg.hw_caps & SSV6200_HW_CAP_AMPDU_TX))
|
{
|
rc_sta->is_ht = 1;
|
ssv62xx_ht_rc_caps(ssv6xxx_rc_rate_set, rc_sta);
|
}
|
}
|
{
|
rc_sta->rc_num_rate = (u8)ssv6xxx_rc_rate_set[rc_sta->rc_type][0];
|
if((rc_sta->rc_type == RC_TYPE_HT_GF) ||
|
(rc_sta->rc_type == RC_TYPE_LGI_20) || (rc_sta->rc_type == RC_TYPE_SGI_20))
|
{
|
if(rc_sta->rc_num_rate == 12)
|
{
|
rc_sta->rc_supp_rates = sta->supp_rates[sband->band] & 0xfL;
|
rc_sta->rc_supp_rates |= (ht_supp_rates << 4);
|
}
|
else
|
rc_sta->rc_supp_rates = ht_supp_rates;
|
}
|
else if(rc_sta->rc_type == RC_TYPE_LEGACY_GB)
|
rc_sta->rc_supp_rates = sta->supp_rates[sband->band];
|
else if(rc_sta->rc_type == RC_TYPE_B_ONLY)
|
rc_sta->rc_supp_rates = sta->supp_rates[sband->band] & 0xfL;
|
ssv62xx_rc_caps(rc_sta);
|
}
|
}
|
#if LINUX_VERSION_CODE > 0x030500
|
static void ssv6xxx_rate_update(void *priv, struct ieee80211_supported_band *sband,
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,13,0)
|
struct cfg80211_chan_def *chandef,
|
#endif
|
struct ieee80211_sta *sta, void *priv_sta,
|
u32 changed)
|
#else
|
static void ssv6xxx_rate_update(void *priv, struct ieee80211_supported_band *sband,
|
struct ieee80211_sta *sta, void *priv_sta,
|
u32 changed, enum nl80211_channel_type oper_chan_type)
|
#endif
|
{
|
printk("%s: changed=%d\n",__FUNCTION__,changed);
|
return;
|
}
|
static void ssv6xxx_rate_init(void *priv, struct ieee80211_supported_band *sband,
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,13,0)
|
struct cfg80211_chan_def *chandef,
|
#endif
|
struct ieee80211_sta *sta, void *priv_sta)
|
{
|
ssv6xxx_rate_update_rc_type(priv, sband, sta, priv_sta);
|
}
|
static void *ssv6xxx_rate_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp)
|
{
|
struct ssv_sta_priv_data *sta_priv = (struct ssv_sta_priv_data *)sta->drv_priv;
|
#ifndef RC_STA_DIRECT_MAP
|
struct ssv_softc *sc = priv;
|
struct ssv_rate_ctrl *ssv_rc = sc->rc;
|
int s;
|
sta_priv = (struct ssv_sta_priv_data *)sta->drv_priv;
|
for(s=0; s<SSV_RC_MAX_STA; s++) {
|
if (ssv_rc->sta_rc_info[s].rc_valid == false) {
|
printk("%s(): use index %d\n", __FUNCTION__, s);
|
memset(&ssv_rc->sta_rc_info[s], 0, sizeof(struct ssv_sta_rc_info));
|
ssv_rc->sta_rc_info[s].rc_valid = true;
|
ssv_rc->sta_rc_info[s].rc_wsid = -1;
|
sta_priv->rc_idx = s;
|
return &ssv_rc->sta_rc_info[s];
|
}
|
}
|
return NULL;
|
#else
|
sta_priv->rc_idx = (-1);
|
return sta_priv;
|
#endif
|
}
|
static void ssv6xxx_rate_free_sta(void *priv, struct ieee80211_sta *sta,
|
void *priv_sta)
|
{
|
struct ssv_sta_rc_info *rc_sta=priv_sta;
|
rc_sta->rc_valid = false;
|
}
|
static void *ssv6xxx_rate_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir)
|
{
|
struct ssv_softc *sc=hw->priv;
|
struct ssv_rate_ctrl *ssv_rc;
|
sc->rc = kzalloc(sizeof(struct ssv_rate_ctrl), GFP_KERNEL);
|
if (!sc->rc) {
|
printk("%s(): Unable to allocate RC structure !\n",
|
__FUNCTION__);
|
return NULL;
|
}
|
memset(sc->rc, 0, sizeof(struct ssv_rate_ctrl));
|
ssv_rc = (struct ssv_rate_ctrl *)sc->rc;
|
ssv_rc->rc_table = ssv_11bgn_rate_table;
|
skb_queue_head_init(&sc->rc_report_queue);
|
INIT_WORK(&sc->rc_sample_work,ssv6xxx_sample_work);
|
sc->rc_sample_workqueue = create_workqueue("ssv6xxx_rc_sample");
|
sc->rc_sample_sechedule = 0;
|
return hw->priv;
|
}
|
static void ssv6xxx_rate_free(void *priv)
|
{
|
struct ssv_softc *sc=priv;
|
if (sc->rc) {
|
kfree(sc->rc);
|
sc->rc = NULL;
|
}
|
sc->rc_sample_sechedule = 0;
|
cancel_work_sync(&sc->rc_sample_work);
|
flush_workqueue(sc->rc_sample_workqueue);
|
destroy_workqueue(sc->rc_sample_workqueue);
|
}
|
static struct rate_control_ops ssv_rate_ops =
|
{
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,15,0)
|
.module = NULL,
|
#endif
|
.name = "ssv6xxx_rate_control",
|
.tx_status = ssv6xxx_tx_status,
|
.get_rate = ssv6xxx_get_rate,
|
.rate_init = ssv6xxx_rate_init,
|
.rate_update = ssv6xxx_rate_update,
|
.alloc = ssv6xxx_rate_alloc,
|
.free = ssv6xxx_rate_free,
|
.alloc_sta = ssv6xxx_rate_alloc_sta,
|
.free_sta = ssv6xxx_rate_free_sta,
|
};
|
void ssv6xxx_rc_mac8011_rate_idx(struct ssv_softc *sc,
|
int hw_rate_idx, struct ieee80211_rx_status *rxs)
|
{
|
struct ssv_rate_ctrl *ssv_rc=sc->rc;
|
struct ssv_rc_rate *rc_rate;
|
BUG_ON(hw_rate_idx>=RATE_TABLE_SIZE &&
|
hw_rate_idx < 0);
|
rc_rate = &ssv_rc->rc_table[hw_rate_idx];
|
if (rc_rate->rc_flags & RC_FLAG_HT) {
|
rxs->flag |= RX_FLAG_HT;
|
if (rc_rate->rc_flags & RC_FLAG_HT_SGI)
|
rxs->flag |= RX_FLAG_SHORT_GI;
|
}
|
else {
|
if (rc_rate->rc_flags & RC_FLAG_SHORT_PREAMBLE)
|
rxs->flag |= RX_FLAG_SHORTPRE;
|
}
|
rxs->rate_idx = rc_rate->dot11_rate_idx;
|
}
|
void ssv6xxx_rc_hw_rate_idx(struct ssv_softc *sc,
|
struct ieee80211_tx_info *info, struct ssv_rate_info *sr)
|
{
|
struct ieee80211_tx_rate *tx_rate;
|
struct ssv_rate_ctrl *ssv_rc=sc->rc;
|
tx_rate = &info->control.rates[0];
|
sr->d_flags = (ssv_rc->rc_table[tx_rate[SSV_DRATE_IDX].count].phy_type == WLAN_RC_PHY_OFDM) ? IEEE80211_RATE_ERP_G:0;
|
sr->d_flags |= (ssv_rc->rc_table[tx_rate[SSV_DRATE_IDX].count].rc_flags & RC_FLAG_SHORT_PREAMBLE)? IEEE80211_RATE_SHORT_PREAMBLE:0;
|
sr->c_flags = (ssv_rc->rc_table[tx_rate[SSV_CRATE_IDX].count].phy_type == WLAN_RC_PHY_OFDM) ? IEEE80211_RATE_ERP_G:0;
|
sr->c_flags |= (ssv_rc->rc_table[tx_rate[SSV_CRATE_IDX].count].rc_flags & RC_FLAG_SHORT_PREAMBLE)? IEEE80211_RATE_SHORT_PREAMBLE:0;
|
sr->drate_kbps = ssv_rc->rc_table[tx_rate[SSV_DRATE_IDX].count].rate_kbps;
|
sr->drate_hw_idx = tx_rate[SSV_DRATE_IDX].count;
|
sr->crate_kbps = ssv_rc->rc_table[tx_rate[SSV_CRATE_IDX].count].rate_kbps;
|
sr->crate_hw_idx = tx_rate[SSV_CRATE_IDX].count;
|
}
|
#ifdef RATE_CONTROL_REALTIME_UPDATA
|
u8 ssv6xxx_rc_hw_rate_update_check(struct sk_buff *skb, struct ssv_softc *sc, u32 do_rts_cts)
|
{
|
int ret = 0;
|
struct ssv_rate_ctrl *ssv_rc = sc->rc;
|
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
|
struct SKB_info_st *skb_info = (struct SKB_info_st *)skb->head;
|
struct ieee80211_sta *sta = skb_info->sta;
|
struct ieee80211_tx_rate *rates = &tx_info->control.rates[0];
|
struct ssv_rc_rate *rc_rate = NULL;
|
u8 rateidx=0;
|
struct ssv_sta_rc_info *rc_sta = NULL;
|
struct rc_pid_sta_info *spinfo;
|
struct ssv_sta_priv_data *sta_priv = NULL;
|
unsigned long period=0;
|
if (sc->sc_flags & SC_OP_FIXED_RATE)
|
return ret;
|
if(sta == NULL)
|
return ret;
|
sta_priv = (struct ssv_sta_priv_data *)sta->drv_priv;
|
if(sta_priv == NULL)
|
{
|
#ifdef RATE_CONTROL_DEBUG
|
printk("%s sta_priv == NULL \n\r", __FUNCTION__);
|
#endif
|
return ret;
|
}
|
if((sta_priv->rc_idx < 0)||(sta_priv->rc_idx >= SSV_RC_MAX_STA))
|
{
|
#ifdef RATE_CONTROL_DEBUG
|
printk("%s rc_idx %x illegal \n\r", __FUNCTION__, sta_priv->rc_idx);
|
#endif
|
return ret;
|
}
|
rc_sta = &ssv_rc->sta_rc_info[sta_priv->rc_idx];
|
if(rc_sta->rc_valid == false)
|
{
|
#ifdef RATE_CONTROL_DEBUG
|
printk("%s rc_valid false \n\r", __FUNCTION__);
|
#endif
|
return ret;
|
}
|
spinfo= &rc_sta->spinfo;
|
period = msecs_to_jiffies(RC_PID_REPORT_INTERVAL);
|
if (time_after(jiffies, spinfo->last_report + period))
|
{
|
ret |= RC_FIRMWARE_REPORT_FLAG;
|
spinfo->last_report = jiffies;
|
}
|
{
|
if (spinfo->monitoring)
|
{
|
if(spinfo->probe_report_flag == 0)
|
{
|
ret |= RC_FIRMWARE_REPORT_FLAG;
|
spinfo->last_report = jiffies;
|
spinfo->probe_report_flag = 1;
|
rateidx = spinfo->real_hw_index;
|
}
|
else if (spinfo->probe_cnt > 0 && spinfo->probe_report_flag) {
|
rateidx = rc_sta->pinfo.rinfo[spinfo->tmp_rate_idx].rc_index;
|
spinfo->probe_cnt--;
|
if(spinfo->probe_cnt == 0)
|
{
|
ret |= RC_FIRMWARE_REPORT_FLAG;
|
spinfo->last_report = jiffies;
|
}
|
}
|
else
|
rateidx = spinfo->real_hw_index;
|
}
|
else
|
rateidx = spinfo->real_hw_index;
|
}
|
if(rateidx >= RATE_TABLE_SIZE)
|
{
|
printk("[ERROR]rateidx over range\n\r");
|
return 0;
|
}
|
rc_rate = &ssv_rc->rc_table[rateidx];
|
#ifdef RATE_CONTROL_STUPID_DEBUG
|
if (spinfo->monitoring && (spinfo->probe_cnt))
|
{
|
char string[24];
|
rateControlGetRate(rc_rate->hw_rate_idx,string);
|
printk("[RC]Probe rate[%s]\n",string);
|
}
|
#endif
|
if(rc_rate == NULL)
|
return ret;
|
if(rc_rate->hw_rate_idx != rates[SSV_DRATE_IDX].count)
|
{
|
rates[0].flags = 0;
|
if (rc_rate->rc_flags & RC_FLAG_SHORT_PREAMBLE)
|
rates[0].flags |= IEEE80211_TX_RC_USE_SHORT_PREAMBLE;
|
if (rc_rate->rc_flags & RC_FLAG_HT) {
|
rates[0].flags |= IEEE80211_TX_RC_MCS;
|
if (rc_rate->rc_flags & RC_FLAG_HT_SGI)
|
rates[0].flags |= IEEE80211_TX_RC_SHORT_GI;
|
if (rc_rate->rc_flags & RC_FLAG_HT_GF)
|
rates[0].flags |= IEEE80211_TX_RC_GREEN_FIELD;
|
}
|
rates[SSV_DRATE_IDX].count = rc_rate->hw_rate_idx;
|
if (do_rts_cts & IEEE80211_TX_RC_USE_CTS_PROTECT)
|
{
|
rates[SSV_CRATE_IDX].count = 0;
|
}
|
else
|
{
|
rc_rate = &ssv_rc->rc_table[rc_rate->ctrl_rate_idx];
|
rates[SSV_CRATE_IDX].count = rc_rate->hw_rate_idx;
|
}
|
ret |= 0x1;
|
}
|
return ret;
|
}
|
#endif
|
void ssv6xxx_rc_hw_reset(struct ssv_softc *sc, int rc_idx, int hwidx)
|
{
|
struct ssv_rate_ctrl *ssv_rc=sc->rc;
|
struct ssv_sta_rc_info *rc_sta;
|
u32 rc_hw_reg[] = { ADR_MTX_MIB_WSID0, ADR_MTX_MIB_WSID1 };
|
BUG_ON(rc_idx >= SSV_RC_MAX_STA);
|
rc_sta = &ssv_rc->sta_rc_info[rc_idx];
|
if (hwidx >=0 && hwidx<SSV_NUM_HW_STA) {
|
rc_sta->rc_wsid = hwidx;
|
printk("rc_wsid[%d] rc_idx[%d]\n",rc_sta[rc_idx].rc_wsid,rc_idx);
|
SMAC_REG_WRITE(sc->sh, rc_hw_reg[hwidx], 0x40000000);
|
}
|
else
|
{
|
rc_sta->rc_wsid = -1;
|
}
|
}
|
#define UPDATE_PHY_INFO_ACK_RATE(_phy_info,_ack_rate_idx) ( _phy_info = (_phy_info&0xfffffc0f)|(_ack_rate_idx<<4))
|
int ssv6xxx_rc_update_bmode_ctrl_rate(struct ssv_softc *sc, int rate_tbl_idx, int ctrl_rate_idx)
|
{
|
u32 temp32;
|
struct ssv_hw *sh = sc->sh;
|
u32 addr;
|
addr = sh->hw_pinfo+rate_tbl_idx*4;
|
ssv_11bgn_rate_table[rate_tbl_idx].ctrl_rate_idx = ctrl_rate_idx;
|
SMAC_REG_READ(sh, addr, &temp32);
|
UPDATE_PHY_INFO_ACK_RATE(temp32, ctrl_rate_idx);
|
SMAC_REG_WRITE(sh, addr, temp32);
|
SMAC_REG_CONFIRM(sh, addr, temp32);
|
return 0;
|
}
|
void ssv6xxx_rc_update_basic_rate(struct ssv_softc *sc, u32 basic_rates)
|
{
|
int i;
|
int rate_idx, pre_rate_idx = 0;
|
for(i=0;i<4;i++)
|
{
|
if(((basic_rates>>i)&0x01))
|
{
|
rate_idx = i;
|
pre_rate_idx = i;
|
}
|
else
|
rate_idx = pre_rate_idx;
|
ssv6xxx_rc_update_bmode_ctrl_rate(sc, i, rate_idx);
|
if(i)
|
ssv6xxx_rc_update_bmode_ctrl_rate(sc, i+3, rate_idx);
|
}
|
}
|
int ssv6xxx_rate_control_register(void)
|
{
|
return ieee80211_rate_control_register(&ssv_rate_ops);
|
}
|
void ssv6xxx_rate_control_unregister(void)
|
{
|
ieee80211_rate_control_unregister(&ssv_rate_ops);
|
}
|
void ssv6xxx_rc_rx_data_handler(struct ieee80211_hw *hw, struct sk_buff *skb, u32 rate_index)
|
{
|
struct ssv_softc *sc = hw->priv;
|
struct ieee80211_sta *sta;
|
struct ssv_sta_priv_data *ssv_sta_priv;
|
sta = ssv6xxx_find_sta_by_rx_skb(sc, skb);
|
if(sta == NULL)
|
{
|
return;
|
}
|
ssv_sta_priv = (struct ssv_sta_priv_data *)sta->drv_priv;
|
ssv_sta_priv->rx_data_rate = rate_index;
|
}
|