Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
/*
 * 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;
}