/*
* 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 .
*/
#include
#include
#include "dev.h"
#include "ssv_ht_rc.h"
#include "ssv_rc.h"
#define SAMPLE_COUNT 4
#define HT_CW_MIN 15
#define HT_SEGMENT_SIZE 6000
#define AVG_PKT_SIZE 12000
#define SAMPLE_COLUMNS 10
#define EWMA_LEVEL 75
#define MCS_NBITS (AVG_PKT_SIZE << 3)
#define MCS_NSYMS(bps) ((MCS_NBITS + (bps) - 1) / (bps))
#define MCS_SYMBOL_TIME(sgi,syms) \
(sgi ? \
((syms) * 18 + 4) / 5 : \
(syms) << 2 \
)
#define MCS_DURATION(streams,sgi,bps) MCS_SYMBOL_TIME(sgi, MCS_NSYMS((streams) * (bps)))
#define MCS_GROUP(_streams,_sgi,_ht40) { \
.duration = { \
MCS_DURATION(_streams, _sgi, _ht40 ? 54 : 26), \
MCS_DURATION(_streams, _sgi, _ht40 ? 108 : 52), \
MCS_DURATION(_streams, _sgi, _ht40 ? 162 : 78), \
MCS_DURATION(_streams, _sgi, _ht40 ? 216 : 104), \
MCS_DURATION(_streams, _sgi, _ht40 ? 324 : 156), \
MCS_DURATION(_streams, _sgi, _ht40 ? 432 : 208), \
MCS_DURATION(_streams, _sgi, _ht40 ? 486 : 234), \
MCS_DURATION(_streams, _sgi, _ht40 ? 540 : 260) \
} \
}
const struct mcs_group minstrel_mcs_groups_ssv[] = {
MCS_GROUP(1, 0, 0),
MCS_GROUP(1, 1, 0),
};
const u16 ampdu_max_transmit_length[RATE_TABLE_SIZE] =
{
0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
4600, 9200, 13800, 18500, 27700, 37000, 41600, 46200,
5100, 10200, 15400, 20500, 30800, 41100, 46200, 51300,
4600, 9200, 13800, 18500, 27700, 37000, 41600, 46200
};
static u8 sample_table[SAMPLE_COLUMNS][MCS_GROUP_RATES];
static int minstrel_ewma(int old, int new, int weight)
{
return (new * (100 - weight) + old * weight) / 100;
}
static inline struct minstrel_rate_stats *minstrel_get_ratestats(struct ssv62xx_ht *mi, int index)
{
return &mi->groups.rates[index % MCS_GROUP_RATES];
}
static void minstrel_calc_rate_ewma(struct minstrel_rate_stats *mr)
{
if (unlikely(mr->attempts > 0)) {
mr->sample_skipped = 0;
mr->cur_prob = MINSTREL_FRAC(mr->success, mr->attempts);
if (!mr->att_hist)
mr->probability = mr->cur_prob;
else
mr->probability = minstrel_ewma(mr->probability,
mr->cur_prob, EWMA_LEVEL);
mr->att_hist += mr->attempts;
mr->succ_hist += mr->success;
} else {
mr->sample_skipped++;
}
mr->last_success = mr->success;
mr->last_attempts = mr->attempts;
mr->success = 0;
mr->attempts = 0;
}
static void minstrel_ht_calc_tp(struct ssv62xx_ht *mi, struct ssv_sta_rc_info *rc_sta, int rate)
{
struct minstrel_rate_stats *mr;
unsigned int usecs,group_id;
if(rc_sta->ht_rc_type == RC_TYPE_HT_LGI_20)
group_id = 0;
else
group_id = 1;
mr = &mi->groups.rates[rate];
if (mr->probability < MINSTREL_FRAC(1, 10)) {
mr->cur_tp = 0;
return;
}
usecs = mi->overhead / MINSTREL_TRUNC(mi->avg_ampdu_len);
usecs += minstrel_mcs_groups_ssv[group_id].duration[rate];
mr->cur_tp = MINSTREL_TRUNC((1000000 / usecs) * mr->probability);
}
static void rate_control_ht_sample(struct ssv62xx_ht *mi,struct ssv_sta_rc_info *rc_sta)
{
struct minstrel_mcs_group_data *mg;
struct minstrel_rate_stats *mr;
int cur_prob, cur_prob_tp, cur_tp, cur_tp2;
int i, index;
if (mi->ampdu_packets > 0) {
mi->avg_ampdu_len = minstrel_ewma(mi->avg_ampdu_len,
MINSTREL_FRAC(mi->ampdu_len, mi->ampdu_packets), EWMA_LEVEL);
mi->ampdu_len = 0;
mi->ampdu_packets = 0;
}
else
return;
mi->sample_slow = 0;
mi->sample_count = 0;
{
cur_prob = 0;
cur_prob_tp = 0;
cur_tp = 0;
cur_tp2 = 0;
mg = &mi->groups;
mg->max_tp_rate = 0;
mg->max_tp_rate2 = 0;
mg->max_prob_rate = 0;
for (i = 0; i < MCS_GROUP_RATES; i++) {
if (!(rc_sta->ht_supp_rates & BIT(i)))
continue;
mr = &mg->rates[i];
index = i;
minstrel_calc_rate_ewma(mr);
minstrel_ht_calc_tp(mi, rc_sta, i);
#ifdef RATE_CONTROL_HT_PARAMETER_DEBUG
if(mr->cur_prob)
printk("rate[%d]probability[%08d]cur_prob[%08d]TP[%04d]\n",i,mr->probability,mr->cur_prob,mr->cur_tp);
#endif
#ifdef RATE_CONTROL_HT_STUPID_DEBUG
printk("HT sample result max_tp_rate[%d]max_tp_rate2[%d]max_prob_rate[%d]\n",mg->max_tp_rate,mg->max_tp_rate2,mg->max_prob_rate);
printk("rate[%d]probability[%08d]TP[%d]\n",i,mr->probability,mr->cur_tp);
#endif
if (!mr->cur_tp)
continue;
#ifdef RATE_CONTROL_HT_STUPID_DEBUG
printk("HT--1 mr->cur_tp[%d]cur_prob_tp[%d]\n",mr->cur_tp,cur_prob_tp);
#endif
if ((mr->cur_tp > cur_prob_tp && mr->probability >
MINSTREL_FRAC(3, 4)) || mr->probability > cur_prob) {
mg->max_prob_rate = index;
cur_prob = mr->probability;
cur_prob_tp = mr->cur_tp;
}
#ifdef RATE_CONTROL_HT_STUPID_DEBUG
printk("HT--2 mr->cur_tp[%d]cur_tp[%d]\n",mr->cur_tp,cur_tp);
#endif
if (mr->cur_tp > cur_tp) {
swap(index, mg->max_tp_rate);
cur_tp = mr->cur_tp;
mr = minstrel_get_ratestats(mi, index);
}
#ifdef RATE_CONTROL_HT_STUPID_DEBUG
if(index != i)
printk("HT--3 index[%d]i[%d]mg->max_tp_rate[%d]\n",index,i,mg->max_tp_rate);
#endif
if (index >= mg->max_tp_rate)
continue;
#ifdef RATE_CONTROL_HT_STUPID_DEBUG
if(index != i)
printk("HT--4 mr->cur_tp[%d]cur_tp2[%d]\n",mr->cur_tp,cur_tp2);
#endif
if (mr->cur_tp > cur_tp2) {
mg->max_tp_rate2 = index;
cur_tp2 = mr->cur_tp;
}
}
}
mi->sample_count = SAMPLE_COUNT;
#if 0
cur_prob = 0;
cur_prob_tp = 0;
cur_tp = 0;
cur_tp2 = 0;
{
mg = &mi->groups;
mr = minstrel_get_ratestats(mi, mg->max_prob_rate);
if (cur_prob_tp < mr->cur_tp) {
mi->max_prob_rate = mg->max_prob_rate;
cur_prob = mr->cur_prob;
cur_prob_tp = mr->cur_tp;
}
mr = minstrel_get_ratestats(mi, mg->max_tp_rate);
if (cur_tp < mr->cur_tp) {
mi->max_tp_rate2 = mi->max_tp_rate;
cur_tp2 = cur_tp;
mi->max_tp_rate = mg->max_tp_rate;
cur_tp = mr->cur_tp;
}
mr = minstrel_get_ratestats(mi, mg->max_tp_rate2);
if (cur_tp2 < mr->cur_tp) {
mi->max_tp_rate2 = mg->max_tp_rate2;
cur_tp2 = mr->cur_tp;
}
}
#else
mi->max_tp_rate = mg->max_tp_rate;
mi->max_tp_rate2 = mg->max_tp_rate2;
mi->max_prob_rate = mg->max_prob_rate;
#endif
#ifdef RATE_CONTROL_HT_STUPID_DEBUG
printk("HT sample result max_tp_rate[%d]max_tp_rate2[%d]max_prob_rate[%d]\n",mi->max_tp_rate,mi->max_tp_rate2,mi->max_prob_rate);
#endif
mi->stats_update = jiffies;
}
#if 0
static void minstrel_calc_retransmit(struct ssv62xx_ht *mi,int index, struct ssv_sta_rc_info *rc_sta)
{
struct minstrel_rate_stats *mr;
const struct mcs_group *group;
unsigned int tx_time, tx_time_rtscts, tx_time_data;
unsigned int cw = HT_CW_MIN;
unsigned int cw_max = 1023;
unsigned int ctime = 0;
unsigned int t_slot = 9;
unsigned int ampdu_len = MINSTREL_TRUNC(mi->avg_ampdu_len);
unsigned int group_id;
if(rc_sta->ht_rc_type == RC_TYPE_HT_LGI_20)
group_id = 0;
else
group_id = 1;
mr = minstrel_get_ratestats(mi, index);
if (mr->probability < MINSTREL_FRAC(1, 10)) {
mr->retry_count = 1;
mr->retry_count_rtscts = 1;
return;
}
mr->retry_count = 2;
mr->retry_count_rtscts = 2;
mr->retry_updated = true;
group = &minstrel_mcs_groups_ssv[group_id];
tx_time_data = group->duration[index % MCS_GROUP_RATES] * ampdu_len;
ctime = (t_slot * cw) >> 1;
cw = min((cw << 1) | 1, cw_max);
ctime += (t_slot * cw) >> 1;
cw = min((cw << 1) | 1, cw_max);
tx_time = ctime + 2 * (mi->overhead + tx_time_data);
tx_time_rtscts = ctime + 2 * (mi->overhead_rtscts + tx_time_data);
do {
ctime = (t_slot * cw) >> 1;
cw = min((cw << 1) | 1, cw_max);
tx_time += ctime + mi->overhead + tx_time_data;
tx_time_rtscts += ctime + mi->overhead_rtscts + tx_time_data;
if (tx_time_rtscts < HT_SEGMENT_SIZE)
mr->retry_count_rtscts++;
} while ((tx_time < HT_SEGMENT_SIZE) &&
(++mr->retry_count < HW_MAX_RATE_TRIES));
}
#endif
static void minstrel_ht_set_rate(struct ssv62xx_ht *mi,
struct fw_rc_retry_params *rate, int index,
bool sample, bool rtscts, struct ssv_sta_rc_info *rc_sta,
struct ssv_rate_ctrl *ssv_rc)
{
struct minstrel_rate_stats *mr;
mr = minstrel_get_ratestats(mi, index);
#if 0
if (!mr->retry_updated)
minstrel_calc_retransmit(mi, index, rc_sta);
if (sample)
rate->count = 1;
else if (mr->probability < MINSTREL_FRAC(20, 100))
rate->count = 2;
else if (rtscts)
rate->count = mr->retry_count_rtscts;
else
rate->count = mr->retry_count;
#endif
rate->drate = ssv_rc->rc_table[mr->rc_index].hw_rate_idx;
rate->crate = ssv_rc->rc_table[mr->rc_index].ctrl_rate_idx;
}
static inline int minstrel_get_duration(int index, struct ssv_sta_rc_info *rc_sta)
{
unsigned int group_id;
const struct mcs_group *group;
if(rc_sta->ht_rc_type == RC_TYPE_HT_LGI_20)
group_id = 0;
else
group_id = 1;
group = &minstrel_mcs_groups_ssv[group_id];
return group->duration[index % MCS_GROUP_RATES];
}
static void minstrel_next_sample_idx(struct ssv62xx_ht *mi)
{
struct minstrel_mcs_group_data *mg;
for (;;) {
mg = &mi->groups;
if (++mg->index >= MCS_GROUP_RATES) {
mg->index = 0;
if (++mg->column >= ARRAY_SIZE(sample_table))
mg->column = 0;
}
break;
}
}
static int minstrel_get_sample_rate(struct ssv62xx_ht *mi, struct ssv_sta_rc_info *rc_sta)
{
struct minstrel_rate_stats *mr;
struct minstrel_mcs_group_data *mg;
int sample_idx = 0;
if (mi->sample_wait > 0) {
mi->sample_wait--;
return -1;
}
if (!mi->sample_tries)
return -1;
mi->sample_tries--;
mg = &mi->groups;
sample_idx = sample_table[mg->column][mg->index];
mr = &mg->rates[sample_idx];
minstrel_next_sample_idx(mi);
if (minstrel_get_duration(sample_idx, rc_sta) >
minstrel_get_duration(mi->max_tp_rate, rc_sta)) {
if (mr->sample_skipped < 20)
{
return -1;
}
if (mi->sample_slow++ > 2)
{
return -1;
}
}
return sample_idx;
}
static void _fill_txinfo_rates (struct ssv_rate_ctrl *ssv_rc, struct sk_buff *skb, struct fw_rc_retry_params *ar)
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
info->control.rates[0].idx = ssv_rc->rc_table[ar[0].drate].dot11_rate_idx;
info->control.rates[0].count = 1;
info->control.rates[SSV_DRATE_IDX].count = ar[0].drate;
info->control.rates[SSV_CRATE_IDX].count = ar[0].crate;
}
extern const u16 ssv6xxx_rc_rate_set[RC_TYPE_MAX][13];
s32 ssv62xx_ht_rate_update(struct sk_buff *skb, struct ssv_softc *sc, struct fw_rc_retry_params *ar)
{
struct ssv_rate_ctrl *ssv_rc = sc->rc;
struct SKB_info_st *skb_info = (struct SKB_info_st *)skb->head;
struct ieee80211_sta *sta = skb_info->sta;
struct ssv62xx_ht *mi = NULL;
int sample_idx;
bool sample = false;
struct ssv_sta_rc_info *rc_sta;
struct ssv_sta_priv_data *sta_priv;
struct rc_pid_sta_info *spinfo;
int ret = 0;
if (sc->sc_flags & SC_OP_FIXED_RATE)
{
ar[0].count = 3;
ar[0].drate = ssv_rc->rc_table[sc->max_rate_idx].hw_rate_idx;
ar[0].crate = ssv_rc->rc_table[sc->max_rate_idx].ctrl_rate_idx;
ar[1].count = 2;
ar[1].drate = ssv_rc->rc_table[sc->max_rate_idx].hw_rate_idx;
ar[1].crate = ssv_rc->rc_table[sc->max_rate_idx].ctrl_rate_idx;
ar[2].count = 2;
ar[2].drate = ssv_rc->rc_table[sc->max_rate_idx].hw_rate_idx;
ar[2].crate = ssv_rc->rc_table[sc->max_rate_idx].ctrl_rate_idx;
_fill_txinfo_rates(ssv_rc, skb, ar);
return ssv_rc->rc_table[sc->max_rate_idx].hw_rate_idx;
}
if(sta == NULL)
{
printk("@Q@...station NULL\n");
BUG_ON(1);
}
sta_priv = (struct ssv_sta_priv_data *)sta->drv_priv;
rc_sta = &ssv_rc->sta_rc_info[sta_priv->rc_idx];
spinfo= &rc_sta->spinfo;
if ((rc_sta->rc_wsid >= SSV_RC_MAX_HARDWARE_SUPPORT) || (rc_sta->rc_wsid < 0))
{
struct ssv_sta_priv_data *ssv_sta_priv;
int rateidx=99;
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))
{
if(ssv6xxx_rc_rate_set[rc_sta->ht_rc_type][0] == 12)
rateidx = (int)rc_sta->pinfo.rinfo[4].rc_index;
else
rateidx = (int)rc_sta->pinfo.rinfo[0].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 = (int)ssv_sta_priv->rx_data_rate;
rateidx -= SSV62XX_RATE_MCS_INDEX;
rateidx %= 8;
if(rc_sta->ht_rc_type == RC_TYPE_HT_SGI_20)
rateidx += SSV62XX_RATE_MCS_SGI_INDEX;
else if(rc_sta->ht_rc_type == RC_TYPE_HT_LGI_20)
rateidx += SSV62XX_RATE_MCS_LGI_INDEX;
else
rateidx += SSV62XX_RATE_MCS_GREENFIELD_INDEX;
}
}
ar[0].count = 3;
ar[2].drate = ar[1].drate = ar[0].drate = ssv_rc->rc_table[rateidx].hw_rate_idx;
ar[2].crate = ar[1].crate = ar[0].crate = ssv_rc->rc_table[rateidx].ctrl_rate_idx;
ar[1].count = 2;
ar[2].count = 2;
_fill_txinfo_rates(ssv_rc, skb, ar);
return rateidx;
}
mi = &rc_sta->ht;
sample_idx = minstrel_get_sample_rate(mi, rc_sta);
if (sample_idx >= 0) {
sample = true;
minstrel_ht_set_rate(mi, &ar[0], sample_idx,
true, false, rc_sta, ssv_rc);
} else {
minstrel_ht_set_rate(mi, &ar[0], mi->max_tp_rate,
false, false, rc_sta, ssv_rc);
}
ar[0].count = mi->first_try_count;
ret = ar[0].drate;
{
if (sample_idx >= 0)
minstrel_ht_set_rate(mi, &ar[1], mi->max_tp_rate,
false, false, rc_sta, ssv_rc);
else
minstrel_ht_set_rate(mi, &ar[1], mi->max_tp_rate2,
false, true, rc_sta, ssv_rc);
ar[1].count = mi->second_try_count;
if(ret > ar[1].drate)
ret = ar[1].drate;
minstrel_ht_set_rate(mi, &ar[2], mi->max_prob_rate,
false, !sample, rc_sta, ssv_rc);
ar[2].count = mi->other_try_count;
if(ret > ar[2].drate)
ret = ar[2].drate;
}
mi->total_packets++;
if (mi->total_packets == ~0) {
mi->total_packets = 0;
mi->sample_packets = 0;
}
if(spinfo->real_hw_index < SSV62XX_RATE_MCS_INDEX)
return spinfo->real_hw_index;
_fill_txinfo_rates(ssv_rc, skb, ar);
return ret;
}
static void init_sample_table(void)
{
int col, i, new_idx;
u8 rnd[MCS_GROUP_RATES];
memset(sample_table, 0xff, sizeof(sample_table));
for (col = 0; col < SAMPLE_COLUMNS; col++) {
for (i = 0; i < MCS_GROUP_RATES; i++) {
get_random_bytes(rnd, sizeof(rnd));
new_idx = (i + rnd[i]) % MCS_GROUP_RATES;
while (sample_table[col][new_idx] != 0xff)
new_idx = (new_idx + 1) % MCS_GROUP_RATES;
sample_table[col][new_idx] = i;
}
}
}
void ssv62xx_ht_rc_caps(const u16 ssv6xxx_rc_rate_set[RC_TYPE_MAX][13],struct ssv_sta_rc_info *rc_sta)
{
struct ssv62xx_ht *mi = &rc_sta->ht;
int ack_dur;
int i;
#if 1
unsigned int group_id;
if(rc_sta->ht_rc_type == RC_TYPE_HT_LGI_20)
group_id = 0;
else
group_id = 1;
for (i = 0; i < MCS_GROUP_RATES; i++) {
printk("[RC]HT duration[%d][%d]\n",i,minstrel_mcs_groups_ssv[group_id].duration[i]);
}
#endif
init_sample_table();
memset(mi, 0, sizeof(*mi));
mi->stats_update = jiffies;
ack_dur = pide_frame_duration( 10, 60, 0, 0);
mi->overhead = pide_frame_duration( 0, 60, 0, 0) + ack_dur;
mi->overhead_rtscts = mi->overhead + 2 * ack_dur;
mi->avg_ampdu_len = MINSTREL_FRAC(1, 1);
mi->sample_count = 16;
mi->sample_wait = 0;
mi->sample_tries = 4;
#ifdef DISABLE_RATE_CONTROL_SAMPLE
mi->max_tp_rate = MCS_GROUP_RATES - 1;
mi->max_tp_rate2 = MCS_GROUP_RATES - 1;
mi->max_prob_rate = MCS_GROUP_RATES - 1;
#endif
#if (HW_MAX_RATE_TRIES == 7)
{
mi->first_try_count = 3;
mi->second_try_count = 2;
mi->other_try_count = 2;
}
#else
{
mi->first_try_count = 2;
mi->second_try_count = 1;
mi->other_try_count = 1;
}
#endif
for (i = 0; i < MCS_GROUP_RATES; i++) {
mi->groups.rates[i].rc_index = ssv6xxx_rc_rate_set[rc_sta->ht_rc_type][i+1];
}
}
static bool minstrel_ht_txstat_valid(struct ssv62xx_tx_rate *rate)
{
if (!rate->count)
return false;
if (rate->data_rate < 0)
return false;
return true;
}
void ssv6xxx_ht_report_handler(struct ssv_softc *sc,struct sk_buff *skb,struct ssv_sta_rc_info *rc_sta)
{
struct cfg_host_event *host_event;
struct firmware_rate_control_report_data *report_data;
struct ssv62xx_ht *mi;
struct minstrel_rate_stats *rate;
bool last = false;
int i = 0;
u16 report_ampdu_packets = 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(host_event->h_event == SOC_EVT_RC_AMPDU_REPORT) {
#if 0
printk("SC HT AMPDU wsid[%d]ampdu_len[%d]ampdu_ack_len[%d]\n",report_data->wsid,report_data->ampdu_len,report_data->ampdu_ack_len);
for (i = 0; i < SSV62XX_TX_MAX_RATES ; i++) {
if(report_data->rates[i].data_rate == -1)
break;
if(report_data->rates[i].count == 0) {
printk("*********************************\n");
printk(" Illegal HT report \n");
printk("*********************************\n");
}
printk(" i=[%d] rate[%d] count[%d]\n",i,report_data->rates[i].data_rate,report_data->rates[i].count);
}
#endif
report_ampdu_packets = 1;
}
else if(host_event->h_event == SOC_EVT_RC_MPDU_REPORT) {
report_data->ampdu_len = 1;
report_ampdu_packets = report_data->ampdu_len;
#if 0
printk("SC MPDU wsid[%d]ampdu_len[%d]ampdu_ack_len[%d]\n",report_data->wsid,report_data->ampdu_len,report_data->ampdu_ack_len);
for (i = 0; i < SSV62XX_TX_MAX_RATES ; i++) {
if(report_data->rates[i].data_rate == -1)
break;
if(report_data->rates[i].count == 0) {
printk("*********************************\n");
printk(" Illegal MPDU report \n");
printk("*********************************\n");
}
printk(" i=[%d] rate[%d] count[%d]\n",i,report_data->rates[i].data_rate,report_data->rates[i].count);
}
#endif
}
else
{
printk("RC work get garbage!!\n");
return;
}
mi = &rc_sta->ht;
mi->ampdu_packets += report_ampdu_packets;
mi->ampdu_len += report_data->ampdu_len;
if (!mi->sample_wait && !mi->sample_tries && mi->sample_count > 0) {
mi->sample_wait = 16 + 2 * MINSTREL_TRUNC(mi->avg_ampdu_len);
mi->sample_tries = 2;
mi->sample_count--;
}
for (i = 0; !last; i++) {
last = (i == SSV62XX_TX_MAX_RATES - 1) ||
!minstrel_ht_txstat_valid(&report_data->rates[i+1]);
if (!minstrel_ht_txstat_valid(&report_data->rates[i]))
break;
#ifdef RATE_CONTROL_DEBUG
if((report_data->rates[i].data_rate < SSV62XX_RATE_MCS_INDEX) || (report_data->rates[i].data_rate >= SSV62XX_RATE_MCS_GREENFIELD_INDEX)) {
printk("[RC]ssv6xxx_ht_report_handler get error report rate[%d]\n",report_data->rates[i].data_rate);
break;
}
#endif
rate = &mi->groups.rates[(report_data->rates[i].data_rate - SSV62XX_RATE_MCS_INDEX) % MCS_GROUP_RATES];
if (last)
rate->success += report_data->ampdu_ack_len;
rate->attempts += report_data->rates[i].count * report_data->ampdu_len;
}
#if 0
rate = minstrel_get_ratestats(mi, mi->max_tp_rate);
if (rate->attempts > 30 &&
MINSTREL_FRAC(rate->success, rate->attempts) <
MINSTREL_FRAC(20, 100))
minstrel_downgrade_rate(mi, &mi->max_tp_rate, true);
rate2 = minstrel_get_ratestats(mi, mi->max_tp_rate2);
if (rate2->attempts > 30 &&
MINSTREL_FRAC(rate2->success, rate2->attempts) <
MINSTREL_FRAC(20, 100))
minstrel_downgrade_rate(mi, &mi->max_tp_rate2, false);
#endif
period = msecs_to_jiffies(SSV_RC_HT_INTERVAL/2);
if (time_after(jiffies, mi->stats_update + period)) {
rate_control_ht_sample(mi,rc_sta);
}
#if 0
period = msecs_to_jiffies(HT_RC_UPDATE_INTERVAL);
if (time_after(jiffies, mi->stats_update + period)) {
struct rc_pid_sta_info *spinfo;
spinfo = &rc_sta->spinfo;
#if 1
printk("AMPDU rate update time!!\n");
#endif
if(rc_sta->rc_num_rate == 12)
{
if(spinfo->txrate_idx >= 4)
rc_sta->ht.max_tp_rate = spinfo->txrate_idx - 4;
else
rc_sta->ht.max_tp_rate = 0;
}
else
rc_sta->ht.max_tp_rate = spinfo->txrate_idx;
mi->stats_update = jiffies;
}
#endif
}