mirror of
https://github.com/RinCat/RTL88x2BU-Linux-Driver.git
synced 2024-12-26 10:01:33 +00:00
1153 lines
36 KiB
C
1153 lines
36 KiB
C
/******************************************************************************
|
|
*
|
|
* Copyright(c) 2007 - 2017 Realtek Corporation.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms of version 2 of the GNU General Public License as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
* more details.
|
|
*
|
|
* The full GNU General Public License is included in this distribution in the
|
|
* file called LICENSE.
|
|
*
|
|
* Contact Information:
|
|
* wlanfae <wlanfae@realtek.com>
|
|
* Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
|
|
* Hsinchu 300, Taiwan.
|
|
*
|
|
* Larry Finger <Larry.Finger@lwfinger.net>
|
|
*
|
|
*****************************************************************************/
|
|
|
|
/* ************************************************************
|
|
* include files
|
|
* ************************************************************ */
|
|
#include "mp_precomp.h"
|
|
#include "phydm_precomp.h"
|
|
|
|
|
|
u8
|
|
odm_get_auto_channel_select_result(
|
|
void *dm_void,
|
|
u8 band
|
|
)
|
|
{
|
|
struct dm_struct *dm = (struct dm_struct *)dm_void;
|
|
struct acs_info *acs = &dm->dm_acs;
|
|
|
|
PHYDM_DBG(dm, ODM_COMP_API, "%s ======>\n", __func__);
|
|
|
|
#if (DM_ODM_SUPPORT_TYPE & (ODM_WIN | ODM_CE))
|
|
if (band == ODM_BAND_2_4G) {
|
|
PHYDM_DBG(dm, ODM_COMP_API, "clean_CH_2g=%d\n", acs->clean_channel_2g);
|
|
return (u8)acs->clean_channel_2g;
|
|
} else {
|
|
PHYDM_DBG(dm, ODM_COMP_API, "clean_CH_5g=%d\n", acs->clean_channel_5g);
|
|
return (u8)acs->clean_channel_5g;
|
|
}
|
|
#else
|
|
return (u8)acs->clean_channel_2g;
|
|
#endif
|
|
|
|
}
|
|
|
|
void
|
|
odm_auto_channel_select_init(
|
|
void *dm_void
|
|
)
|
|
{
|
|
#if (DM_ODM_SUPPORT_TYPE & (ODM_WIN | ODM_CE))
|
|
struct dm_struct *dm = (struct dm_struct *)dm_void;
|
|
struct acs_info *acs = &dm->dm_acs;
|
|
u8 i;
|
|
|
|
if (!(dm->support_ability & ODM_BB_ENV_MONITOR))
|
|
return;
|
|
|
|
if (acs->is_force_acs_result)
|
|
return;
|
|
|
|
PHYDM_DBG(dm, ODM_COMP_API, "%s ======>\n", __func__);
|
|
|
|
acs->clean_channel_2g = 1;
|
|
acs->clean_channel_5g = 36;
|
|
|
|
for (i = 0; i < ODM_MAX_CHANNEL_2G; ++i) {
|
|
acs->channel_info_2g[0][i] = 0;
|
|
acs->channel_info_2g[1][i] = 0;
|
|
}
|
|
|
|
if (dm->support_ic_type & ODM_IC_11AC_SERIES) {
|
|
for (i = 0; i < ODM_MAX_CHANNEL_5G; ++i) {
|
|
acs->channel_info_5g[0][i] = 0;
|
|
acs->channel_info_5g[1][i] = 0;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void
|
|
odm_auto_channel_select_reset(
|
|
void *dm_void
|
|
)
|
|
{
|
|
#if (DM_ODM_SUPPORT_TYPE & (ODM_WIN | ODM_CE))
|
|
struct dm_struct *dm = (struct dm_struct *)dm_void;
|
|
struct acs_info *acs = &dm->dm_acs;
|
|
struct ccx_info *ccx_info = &dm->dm_ccx_info;
|
|
|
|
if (!(dm->support_ability & ODM_BB_ENV_MONITOR))
|
|
return;
|
|
|
|
if (acs->is_force_acs_result)
|
|
return;
|
|
|
|
PHYDM_DBG(dm, ODM_COMP_API, "%s ======>\n", __func__);
|
|
|
|
ccx_info->nhm_period = 0x1388; /*20ms*/
|
|
phydm_nhm_setting(dm, SET_NHM_SETTING);
|
|
phydm_nhm_trigger(dm);
|
|
#endif
|
|
}
|
|
|
|
void
|
|
odm_auto_channel_select(
|
|
void *dm_void,
|
|
u8 channel
|
|
)
|
|
{
|
|
#if (DM_ODM_SUPPORT_TYPE & (ODM_WIN | ODM_CE))
|
|
struct dm_struct *dm = (struct dm_struct *)dm_void;
|
|
struct acs_info *acs = &dm->dm_acs;
|
|
struct ccx_info *ccx_info = &dm->dm_ccx_info;
|
|
u8 channel_idx = 0, search_idx = 0;
|
|
u8 noisy_nhm_th = 0x52;
|
|
u8 i, noisy_nhm_th_index, low_pwr_cnt = 0;
|
|
u16 max_score = 0;
|
|
|
|
PHYDM_DBG(dm, ODM_COMP_API, "%s ======>\n", __func__);
|
|
|
|
if (!(dm->support_ability & ODM_BB_ENV_MONITOR)) {
|
|
PHYDM_DBG(dm, DBG_DIG, "Return: Not support\n");
|
|
return;
|
|
}
|
|
|
|
if (acs->is_force_acs_result) {
|
|
PHYDM_DBG(dm, DBG_DIG, "Force clean CH{2G,5G}={%d,%d}\n",
|
|
acs->clean_channel_2g, acs->clean_channel_5g);
|
|
return;
|
|
}
|
|
|
|
PHYDM_DBG(dm, ODM_COMP_API, "CH=%d\n", channel);
|
|
|
|
phydm_get_nhm_result(dm);
|
|
noisy_nhm_th_index = (noisy_nhm_th - ccx_info->nhm_th[0]) << 2;
|
|
|
|
for (i = 0; i <= 11; i++) {
|
|
if (i <= noisy_nhm_th_index)
|
|
low_pwr_cnt += ccx_info->nhm_result[i];
|
|
}
|
|
|
|
ccx_info->nhm_period = 0x2710;
|
|
phydm_nhm_setting(dm, SET_NHM_SETTING);
|
|
|
|
if (channel >= 1 && channel <= 14) {
|
|
channel_idx = channel - 1;
|
|
acs->channel_info_2g[1][channel_idx]++;
|
|
|
|
if (acs->channel_info_2g[1][channel_idx] >= 2)
|
|
acs->channel_info_2g[0][channel_idx] = (acs->channel_info_2g[0][channel_idx] >> 1) +
|
|
(acs->channel_info_2g[0][channel_idx] >> 2) + (low_pwr_cnt >> 2);
|
|
else
|
|
acs->channel_info_2g[0][channel_idx] = low_pwr_cnt;
|
|
|
|
PHYDM_DBG(dm, ODM_COMP_API, "low_pwr_cnt = %d\n", low_pwr_cnt);
|
|
PHYDM_DBG(dm, ODM_COMP_API, "CH_Info[0][%d]=%d, CH_Info[1][%d]=%d\n", channel_idx, acs->channel_info_2g[0][channel_idx], channel_idx, acs->channel_info_2g[1][channel_idx]);
|
|
|
|
for (search_idx = 0; search_idx < ODM_MAX_CHANNEL_2G; search_idx++) {
|
|
if (acs->channel_info_2g[1][search_idx] != 0 && acs->channel_info_2g[0][search_idx] >= max_score) {
|
|
max_score = acs->channel_info_2g[0][search_idx];
|
|
acs->clean_channel_2g = search_idx + 1;
|
|
}
|
|
}
|
|
PHYDM_DBG(dm, ODM_COMP_API, "clean_CH_2g=%d, max_score=%d\n",
|
|
acs->clean_channel_2g, max_score);
|
|
|
|
} else if (channel >= 36) {
|
|
/* Need to do */
|
|
acs->clean_channel_5g = channel;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
boolean
|
|
phydm_acs_check(
|
|
void *dm_void
|
|
)
|
|
{
|
|
#if (DM_ODM_SUPPORT_TYPE == ODM_AP)
|
|
struct dm_struct *dm = (struct dm_struct *)dm_void;
|
|
struct rtl8192cd_priv *priv = dm->priv;
|
|
|
|
if ((priv->auto_channel != 0) && (priv->auto_channel != 2)) /* if struct acs_info running, do not do FA/CCA counter read */
|
|
return true;
|
|
else
|
|
return false;
|
|
#else
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
#if (DM_ODM_SUPPORT_TYPE & ODM_AP)
|
|
|
|
void
|
|
phydm_auto_channel_select_setting_ap(
|
|
void *dm_void,
|
|
u32 setting, /* 0: STORE_DEFAULT_NHM_SETTING; 1: RESTORE_DEFAULT_NHM_SETTING, 2: ACS_NHM_SETTING */
|
|
u32 acs_step
|
|
)
|
|
{
|
|
struct dm_struct *dm = (struct dm_struct *)dm_void;
|
|
struct rtl8192cd_priv *priv = dm->priv;
|
|
struct acs_info *acs = &dm->dm_acs;
|
|
|
|
PHYDM_DBG(dm, ODM_COMP_API, "%s ======>\n", __func__);
|
|
|
|
/* 3 Store Default setting */
|
|
if (setting == STORE_DEFAULT_NHM_SETTING) {
|
|
PHYDM_DBG(dm, ODM_COMP_API, "STORE_DEFAULT_NHM_SETTING\n");
|
|
|
|
if (dm->support_ic_type & ODM_IC_11AC_SERIES) { /* store reg0x990, reg0x994, reg0x998, reg0x99c, Reg0x9a0 */
|
|
acs->reg0x990 = odm_read_4byte(dm, ODM_REG_CCX_PERIOD_11AC); /* reg0x990 */
|
|
acs->reg0x994 = odm_read_4byte(dm, ODM_REG_NHM_TH9_TH10_11AC); /* reg0x994 */
|
|
acs->reg0x998 = odm_read_4byte(dm, ODM_REG_NHM_TH3_TO_TH0_11AC); /* reg0x998 */
|
|
acs->reg0x99c = odm_read_4byte(dm, ODM_REG_NHM_TH7_TO_TH4_11AC); /* Reg0x99c */
|
|
acs->reg0x9a0 = odm_read_1byte(dm, ODM_REG_NHM_TH8_11AC); /* Reg0x9a0, u8 */
|
|
} else if (dm->support_ic_type & ODM_IC_11N_SERIES) {
|
|
acs->reg0x890 = odm_read_4byte(dm, ODM_REG_NHM_TH9_TH10_11N); /* reg0x890 */
|
|
acs->reg0x894 = odm_read_4byte(dm, ODM_REG_CCX_PERIOD_11N); /* reg0x894 */
|
|
acs->reg0x898 = odm_read_4byte(dm, ODM_REG_NHM_TH3_TO_TH0_11N); /* reg0x898 */
|
|
acs->reg0x89c = odm_read_4byte(dm, ODM_REG_NHM_TH7_TO_TH4_11N); /* Reg0x89c */
|
|
acs->reg0xe28 = odm_read_1byte(dm, ODM_REG_NHM_TH8_11N); /* Reg0xe28, u8 */
|
|
}
|
|
}
|
|
|
|
/* 3 Restore Default setting */
|
|
else if (setting == RESTORE_DEFAULT_NHM_SETTING) {
|
|
PHYDM_DBG(dm, ODM_COMP_API, "RESTORE_DEFAULT_NHM_SETTING\n");
|
|
|
|
if (dm->support_ic_type & ODM_IC_11AC_SERIES) { /* store reg0x990, reg0x994, reg0x998, reg0x99c, Reg0x9a0 */
|
|
odm_write_4byte(dm, ODM_REG_CCX_PERIOD_11AC, acs->reg0x990);
|
|
odm_write_4byte(dm, ODM_REG_NHM_TH9_TH10_11AC, acs->reg0x994);
|
|
odm_write_4byte(dm, ODM_REG_NHM_TH3_TO_TH0_11AC, acs->reg0x998);
|
|
odm_write_4byte(dm, ODM_REG_NHM_TH7_TO_TH4_11AC, acs->reg0x99c);
|
|
odm_write_1byte(dm, ODM_REG_NHM_TH8_11AC, acs->reg0x9a0);
|
|
} else if (dm->support_ic_type & ODM_IC_11N_SERIES) {
|
|
odm_write_4byte(dm, ODM_REG_NHM_TH9_TH10_11N, acs->reg0x890);
|
|
odm_write_4byte(dm, ODM_REG_CCX_PERIOD_11AC, acs->reg0x894);
|
|
odm_write_4byte(dm, ODM_REG_NHM_TH3_TO_TH0_11N, acs->reg0x898);
|
|
odm_write_4byte(dm, ODM_REG_NHM_TH7_TO_TH4_11N, acs->reg0x89c);
|
|
odm_write_1byte(dm, ODM_REG_NHM_TH8_11N, acs->reg0xe28);
|
|
}
|
|
}
|
|
|
|
/* 3 struct acs_info setting */
|
|
else if (setting == ACS_NHM_SETTING) {
|
|
PHYDM_DBG(dm, ODM_COMP_API, "ACS_NHM_SETTING\n");
|
|
u16 period;
|
|
period = 0x61a8;
|
|
acs->acs_step = acs_step;
|
|
|
|
if (dm->support_ic_type & ODM_IC_11AC_SERIES) {
|
|
/* 4 Set NHM period, 0x990[31:16]=0x61a8, Time duration for NHM unit: 4us, 0x61a8=100ms */
|
|
odm_write_2byte(dm, ODM_REG_CCX_PERIOD_11AC + 2, period);
|
|
/* 4 Set NHM ignore_cca=1, ignore_txon=1, ccx_en=0 */
|
|
odm_set_bb_reg(dm, ODM_REG_NHM_TH9_TH10_11AC, BIT(8) | BIT(9) | BIT(10), 3);
|
|
|
|
if (acs->acs_step == 0) {
|
|
/* 4 Set IGI */
|
|
odm_set_bb_reg(dm, 0xc50, BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) | BIT(6), 0x3E);
|
|
if (get_rf_mimo_mode(priv) != RF_1T1R)
|
|
odm_set_bb_reg(dm, 0xe50, BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) | BIT(6), 0x3E);
|
|
|
|
/* 4 Set struct acs_info NHM threshold */
|
|
odm_write_4byte(dm, ODM_REG_NHM_TH3_TO_TH0_11AC, 0x82786e64);
|
|
odm_write_4byte(dm, ODM_REG_NHM_TH7_TO_TH4_11AC, 0xffffff8c);
|
|
odm_write_1byte(dm, ODM_REG_NHM_TH8_11AC, 0xff);
|
|
odm_write_2byte(dm, ODM_REG_NHM_TH9_TH10_11AC + 2, 0xffff);
|
|
|
|
} else if (acs->acs_step == 1) {
|
|
/* 4 Set IGI */
|
|
odm_set_bb_reg(dm, 0xc50, BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) | BIT(6), 0x2A);
|
|
if (get_rf_mimo_mode(priv) != RF_1T1R)
|
|
odm_set_bb_reg(dm, 0xe50, BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) | BIT(6), 0x2A);
|
|
|
|
/* 4 Set struct acs_info NHM threshold */
|
|
odm_write_4byte(dm, ODM_REG_NHM_TH3_TO_TH0_11AC, 0x5a50463c);
|
|
odm_write_4byte(dm, ODM_REG_NHM_TH7_TO_TH4_11AC, 0xffffff64);
|
|
|
|
}
|
|
|
|
} else if (dm->support_ic_type & ODM_IC_11N_SERIES) {
|
|
/* 4 Set NHM period, 0x894[31:16]=0x61a8, Time duration for NHM unit: 4us, 0x61a8=100ms */
|
|
odm_write_2byte(dm, ODM_REG_CCX_PERIOD_11AC + 2, period);
|
|
/* 4 Set NHM ignore_cca=1, ignore_txon=1, ccx_en=0 */
|
|
odm_set_bb_reg(dm, ODM_REG_NHM_TH9_TH10_11N, BIT(8) | BIT(9) | BIT(10), 3);
|
|
|
|
if (acs->acs_step == 0) {
|
|
/* 4 Set IGI */
|
|
odm_set_bb_reg(dm, 0xc50, BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) | BIT(6), 0x3E);
|
|
if (get_rf_mimo_mode(priv) != RF_1T1R)
|
|
odm_set_bb_reg(dm, 0xc58, BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) | BIT(6), 0x3E);
|
|
|
|
/* 4 Set struct acs_info NHM threshold */
|
|
odm_write_4byte(dm, ODM_REG_NHM_TH3_TO_TH0_11N, 0x82786e64);
|
|
odm_write_4byte(dm, ODM_REG_NHM_TH7_TO_TH4_11N, 0xffffff8c);
|
|
odm_write_1byte(dm, ODM_REG_NHM_TH8_11N, 0xff);
|
|
odm_write_2byte(dm, ODM_REG_NHM_TH9_TH10_11N + 2, 0xffff);
|
|
|
|
} else if (acs->acs_step == 1) {
|
|
/* 4 Set IGI */
|
|
odm_set_bb_reg(dm, 0xc50, BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) | BIT(6), 0x2A);
|
|
if (get_rf_mimo_mode(priv) != RF_1T1R)
|
|
odm_set_bb_reg(dm, 0xc58, BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) | BIT(6), 0x2A);
|
|
|
|
/* 4 Set struct acs_info NHM threshold */
|
|
odm_write_4byte(dm, ODM_REG_NHM_TH3_TO_TH0_11N, 0x5a50463c);
|
|
odm_write_4byte(dm, ODM_REG_NHM_TH7_TO_TH4_11N, 0xffffff64);
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
void
|
|
phydm_get_nhm_statistics_ap(
|
|
void *dm_void,
|
|
u32 idx, /* @ 2G, Real channel number = idx+1 */
|
|
u32 acs_step
|
|
)
|
|
{
|
|
struct dm_struct *dm = (struct dm_struct *)dm_void;
|
|
struct rtl8192cd_priv *priv = dm->priv;
|
|
struct acs_info *acs = &dm->dm_acs;
|
|
u32 value32 = 0;
|
|
u8 i;
|
|
|
|
acs->acs_step = acs_step;
|
|
|
|
if (dm->support_ic_type & ODM_IC_11N_SERIES) {
|
|
/* 4 Check if NHM result is ready */
|
|
for (i = 0; i < 20; i++) {
|
|
ODM_delay_ms(1);
|
|
if (odm_get_bb_reg(dm, REG_FPGA0_PSD_REPORT, BIT(17)))
|
|
break;
|
|
}
|
|
|
|
/* 4 Get NHM Statistics */
|
|
if (acs->acs_step == 1) {
|
|
value32 = odm_read_4byte(dm, ODM_REG_NHM_CNT7_TO_CNT4_11N);
|
|
|
|
acs->nhm_cnt[idx][9] = (value32 & MASKBYTE1) >> 8;
|
|
acs->nhm_cnt[idx][8] = (value32 & MASKBYTE0);
|
|
|
|
value32 = odm_read_4byte(dm, ODM_REG_NHM_CNT_11N); /* ODM_REG_NHM_CNT3_TO_CNT0_11N */
|
|
|
|
acs->nhm_cnt[idx][7] = (value32 & MASKBYTE3) >> 24;
|
|
acs->nhm_cnt[idx][6] = (value32 & MASKBYTE2) >> 16;
|
|
acs->nhm_cnt[idx][5] = (value32 & MASKBYTE1) >> 8;
|
|
|
|
} else if (acs->acs_step == 2) {
|
|
value32 = odm_read_4byte(dm, ODM_REG_NHM_CNT_11N); /* ODM_REG_NHM_CNT3_TO_CNT0_11N */
|
|
|
|
acs->nhm_cnt[idx][4] = odm_read_1byte(dm, ODM_REG_NHM_CNT7_TO_CNT4_11N);
|
|
acs->nhm_cnt[idx][3] = (value32 & MASKBYTE3) >> 24;
|
|
acs->nhm_cnt[idx][2] = (value32 & MASKBYTE2) >> 16;
|
|
acs->nhm_cnt[idx][1] = (value32 & MASKBYTE1) >> 8;
|
|
acs->nhm_cnt[idx][0] = (value32 & MASKBYTE0);
|
|
}
|
|
} else if (dm->support_ic_type & ODM_IC_11AC_SERIES) {
|
|
/* 4 Check if NHM result is ready */
|
|
for (i = 0; i < 20; i++) {
|
|
ODM_delay_ms(1);
|
|
if (odm_get_bb_reg(dm, ODM_REG_NHM_DUR_READY_11AC, BIT(16)))
|
|
break;
|
|
}
|
|
|
|
if (acs->acs_step == 1) {
|
|
value32 = odm_read_4byte(dm, ODM_REG_NHM_CNT7_TO_CNT4_11AC);
|
|
|
|
acs->nhm_cnt[idx][9] = (value32 & MASKBYTE1) >> 8;
|
|
acs->nhm_cnt[idx][8] = (value32 & MASKBYTE0);
|
|
|
|
value32 = odm_read_4byte(dm, ODM_REG_NHM_CNT_11AC); /* ODM_REG_NHM_CNT3_TO_CNT0_11AC */
|
|
|
|
acs->nhm_cnt[idx][7] = (value32 & MASKBYTE3) >> 24;
|
|
acs->nhm_cnt[idx][6] = (value32 & MASKBYTE2) >> 16;
|
|
acs->nhm_cnt[idx][5] = (value32 & MASKBYTE1) >> 8;
|
|
|
|
} else if (acs->acs_step == 2) {
|
|
value32 = odm_read_4byte(dm, ODM_REG_NHM_CNT_11AC); /* ODM_REG_NHM_CNT3_TO_CNT0_11AC */
|
|
|
|
acs->nhm_cnt[idx][4] = odm_read_1byte(dm, ODM_REG_NHM_CNT7_TO_CNT4_11AC);
|
|
acs->nhm_cnt[idx][3] = (value32 & MASKBYTE3) >> 24;
|
|
acs->nhm_cnt[idx][2] = (value32 & MASKBYTE2) >> 16;
|
|
acs->nhm_cnt[idx][1] = (value32 & MASKBYTE1) >> 8;
|
|
acs->nhm_cnt[idx][0] = (value32 & MASKBYTE0);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/* #define ACS_DEBUG_INFO */ /* acs debug default off */
|
|
#if 0
|
|
int phydm_AutoChannelSelectAP(
|
|
void *dm_void,
|
|
u32 ACS_Type, /* 0: RXCount_Type, 1:NHM_Type */
|
|
u32 available_chnl_num /* amount of all channels */
|
|
)
|
|
{
|
|
struct dm_struct *dm = (struct dm_struct *)dm_void;
|
|
struct acs_info *acs = &dm->dm_acs;
|
|
struct rtl8192cd_priv *priv = dm->priv;
|
|
|
|
static u32 score2G[MAX_2G_CHANNEL_NUM], score5G[MAX_5G_CHANNEL_NUM];
|
|
u32 score[MAX_BSS_NUM], use_nhm = 0;
|
|
u32 minScore = 0xffffffff;
|
|
u32 tmpScore, tmpIdx = 0;
|
|
u32 traffic_check = 0;
|
|
u32 fa_count_weighting = 1;
|
|
int i, j, idx = 0, idx_2G_end = -1, idx_5G_begin = -1, minChan = 0;
|
|
struct bss_desc *pBss = NULL;
|
|
|
|
#ifdef _DEBUG_RTL8192CD_
|
|
char tmpbuf[400];
|
|
int len = 0;
|
|
#endif
|
|
|
|
memset(score2G, '\0', sizeof(score2G));
|
|
memset(score5G, '\0', sizeof(score5G));
|
|
|
|
for (i = 0; i < priv->available_chnl_num; i++) {
|
|
if (priv->available_chnl[i] <= 14)
|
|
idx_2G_end = i;
|
|
else
|
|
break;
|
|
}
|
|
|
|
for (i = 0; i < priv->available_chnl_num; i++) {
|
|
if (priv->available_chnl[i] > 14) {
|
|
idx_5G_begin = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* DELETE */
|
|
#ifndef CONFIG_RTL_NEW_AUTOCH
|
|
for (i = 0; i < priv->site_survey->count; i++) {
|
|
pBss = &priv->site_survey->bss[i];
|
|
for (idx = 0; idx < priv->available_chnl_num; idx++) {
|
|
if (pBss->channel == priv->available_chnl[idx]) {
|
|
if (pBss->channel <= 14)
|
|
setChannelScore(idx, score2G, 0, MAX_2G_CHANNEL_NUM - 1);
|
|
else
|
|
score5G[idx - idx_5G_begin] += 5;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (idx_2G_end >= 0)
|
|
for (i = 0; i <= idx_2G_end; i++)
|
|
score[i] = score2G[i];
|
|
if (idx_5G_begin >= 0)
|
|
for (i = idx_5G_begin; i < priv->available_chnl_num; i++)
|
|
score[i] = score5G[i - idx_5G_begin];
|
|
|
|
#ifdef CONFIG_RTL_NEW_AUTOCH
|
|
{
|
|
u32 y, ch_begin = 0, ch_end = priv->available_chnl_num;
|
|
|
|
u32 do_ap_check = 1, ap_ratio = 0;
|
|
|
|
if (idx_2G_end >= 0)
|
|
ch_end = idx_2G_end + 1;
|
|
if (idx_5G_begin >= 0)
|
|
ch_begin = idx_5G_begin;
|
|
|
|
#ifdef ACS_DEBUG_INFO/* for debug */
|
|
printk("\n");
|
|
for (y = ch_begin; y < ch_end; y++)
|
|
printk("1. init: chnl[%d] 20M_rx[%d] 40M_rx[%d] fa_cnt[%d] score[%d]\n",
|
|
priv->available_chnl[y],
|
|
priv->chnl_ss_mac_rx_count[y],
|
|
priv->chnl_ss_mac_rx_count_40M[y],
|
|
priv->chnl_ss_fa_count[y],
|
|
score[y]);
|
|
printk("\n");
|
|
#endif
|
|
|
|
#if defined(CONFIG_RTL_88E_SUPPORT) || defined(CONFIG_WLAN_HAL_8192EE)
|
|
if (dm->support_ic_type & (ODM_RTL8188E | ODM_RTL8192E) && priv->pmib->dot11RFEntry.acs_type) {
|
|
u32 tmp_score[MAX_BSS_NUM];
|
|
memcpy(tmp_score, score, sizeof(score));
|
|
if (find_clean_channel(priv, ch_begin, ch_end, tmp_score)) {
|
|
/* memcpy(score, tmp_score, sizeof(score)); */
|
|
#ifdef _DEBUG_RTL8192CD_
|
|
printk("!! Found clean channel, select minimum FA channel\n");
|
|
#endif
|
|
goto USE_CLN_CH;
|
|
}
|
|
#ifdef _DEBUG_RTL8192CD_
|
|
printk("!! Not found clean channel, use NHM algorithm\n");
|
|
#endif
|
|
use_nhm = 1;
|
|
USE_CLN_CH:
|
|
for (y = ch_begin; y < ch_end; y++) {
|
|
for (i = 0; i <= 9; i++) {
|
|
u32 val32 = priv->nhm_cnt[y][i];
|
|
for (j = 0; j < i; j++)
|
|
val32 *= 3;
|
|
score[y] += val32;
|
|
}
|
|
|
|
#ifdef _DEBUG_RTL8192CD_
|
|
printk("nhm_cnt_%d: H<-[ %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d]->L, score: %d\n",
|
|
y + 1, priv->nhm_cnt[y][9], priv->nhm_cnt[y][8], priv->nhm_cnt[y][7],
|
|
priv->nhm_cnt[y][6], priv->nhm_cnt[y][5], priv->nhm_cnt[y][4],
|
|
priv->nhm_cnt[y][3], priv->nhm_cnt[y][2], priv->nhm_cnt[y][1],
|
|
priv->nhm_cnt[y][0], score[y]);
|
|
#endif
|
|
}
|
|
|
|
if (!use_nhm)
|
|
memcpy(score, tmp_score, sizeof(score));
|
|
|
|
goto choose_ch;
|
|
}
|
|
#endif
|
|
|
|
/* For each channel, weighting behind channels with MAC RX counter */
|
|
/* For each channel, weighting the channel with FA counter */
|
|
|
|
for (y = ch_begin; y < ch_end; y++) {
|
|
score[y] += 8 * priv->chnl_ss_mac_rx_count[y];
|
|
if (priv->chnl_ss_mac_rx_count[y] > 30)
|
|
do_ap_check = 0;
|
|
if (priv->chnl_ss_mac_rx_count[y] > MAC_RX_COUNT_THRESHOLD)
|
|
traffic_check = 1;
|
|
|
|
#ifdef RTK_5G_SUPPORT
|
|
if (*dm->band_type == ODM_BAND_2_4G)
|
|
#endif
|
|
{
|
|
if ((int)(y - 4) >= (int)ch_begin)
|
|
score[y - 4] += 2 * priv->chnl_ss_mac_rx_count[y];
|
|
if ((int)(y - 3) >= (int)ch_begin)
|
|
score[y - 3] += 8 * priv->chnl_ss_mac_rx_count[y];
|
|
if ((int)(y - 2) >= (int)ch_begin)
|
|
score[y - 2] += 8 * priv->chnl_ss_mac_rx_count[y];
|
|
if ((int)(y - 1) >= (int)ch_begin)
|
|
score[y - 1] += 10 * priv->chnl_ss_mac_rx_count[y];
|
|
if ((int)(y + 1) < (int)ch_end)
|
|
score[y + 1] += 10 * priv->chnl_ss_mac_rx_count[y];
|
|
if ((int)(y + 2) < (int)ch_end)
|
|
score[y + 2] += 8 * priv->chnl_ss_mac_rx_count[y];
|
|
if ((int)(y + 3) < (int)ch_end)
|
|
score[y + 3] += 8 * priv->chnl_ss_mac_rx_count[y];
|
|
if ((int)(y + 4) < (int)ch_end)
|
|
score[y + 4] += 2 * priv->chnl_ss_mac_rx_count[y];
|
|
}
|
|
|
|
/* this is for CH_LOAD caculation */
|
|
if (priv->chnl_ss_cca_count[y] > priv->chnl_ss_fa_count[y])
|
|
priv->chnl_ss_cca_count[y] -= priv->chnl_ss_fa_count[y];
|
|
else
|
|
priv->chnl_ss_cca_count[y] = 0;
|
|
}
|
|
|
|
#ifdef ACS_DEBUG_INFO/* for debug */
|
|
printk("\n");
|
|
for (y = ch_begin; y < ch_end; y++)
|
|
printk("2. after 20M check: chnl[%d] score[%d]\n", priv->available_chnl[y], score[y]);
|
|
printk("\n");
|
|
#endif
|
|
|
|
for (y = ch_begin; y < ch_end; y++) {
|
|
if (priv->chnl_ss_mac_rx_count_40M[y]) {
|
|
score[y] += 5 * priv->chnl_ss_mac_rx_count_40M[y];
|
|
if (priv->chnl_ss_mac_rx_count_40M[y] > 30)
|
|
do_ap_check = 0;
|
|
if (priv->chnl_ss_mac_rx_count_40M[y] > MAC_RX_COUNT_THRESHOLD)
|
|
traffic_check = 1;
|
|
|
|
#ifdef RTK_5G_SUPPORT
|
|
if (*dm->band_type == ODM_BAND_2_4G)
|
|
#endif
|
|
{
|
|
if ((int)(y - 6) >= (int)ch_begin)
|
|
score[y - 6] += 1 * priv->chnl_ss_mac_rx_count_40M[y];
|
|
if ((int)(y - 5) >= (int)ch_begin)
|
|
score[y - 5] += 4 * priv->chnl_ss_mac_rx_count_40M[y];
|
|
if ((int)(y - 4) >= (int)ch_begin)
|
|
score[y - 4] += 4 * priv->chnl_ss_mac_rx_count_40M[y];
|
|
if ((int)(y - 3) >= (int)ch_begin)
|
|
score[y - 3] += 5 * priv->chnl_ss_mac_rx_count_40M[y];
|
|
if ((int)(y - 2) >= (int)ch_begin)
|
|
score[y - 2] += (5 * priv->chnl_ss_mac_rx_count_40M[y]) / 2;
|
|
if ((int)(y - 1) >= (int)ch_begin)
|
|
score[y - 1] += 5 * priv->chnl_ss_mac_rx_count_40M[y];
|
|
if ((int)(y + 1) < (int)ch_end)
|
|
score[y + 1] += 5 * priv->chnl_ss_mac_rx_count_40M[y];
|
|
if ((int)(y + 2) < (int)ch_end)
|
|
score[y + 2] += (5 * priv->chnl_ss_mac_rx_count_40M[y]) / 2;
|
|
if ((int)(y + 3) < (int)ch_end)
|
|
score[y + 3] += 5 * priv->chnl_ss_mac_rx_count_40M[y];
|
|
if ((int)(y + 4) < (int)ch_end)
|
|
score[y + 4] += 4 * priv->chnl_ss_mac_rx_count_40M[y];
|
|
if ((int)(y + 5) < (int)ch_end)
|
|
score[y + 5] += 4 * priv->chnl_ss_mac_rx_count_40M[y];
|
|
if ((int)(y + 6) < (int)ch_end)
|
|
score[y + 6] += 1 * priv->chnl_ss_mac_rx_count_40M[y];
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef ACS_DEBUG_INFO/* for debug */
|
|
printk("\n");
|
|
for (y = ch_begin; y < ch_end; y++)
|
|
printk("3. after 40M check: chnl[%d] score[%d]\n", priv->available_chnl[y], score[y]);
|
|
printk("\n");
|
|
printk("4. do_ap_check=%d traffic_check=%d\n", do_ap_check, traffic_check);
|
|
printk("\n");
|
|
#endif
|
|
|
|
if (traffic_check == 0)
|
|
fa_count_weighting = 5;
|
|
else
|
|
fa_count_weighting = 1;
|
|
|
|
for (y = ch_begin; y < ch_end; y++)
|
|
score[y] += fa_count_weighting * priv->chnl_ss_fa_count[y];
|
|
|
|
#ifdef ACS_DEBUG_INFO/* for debug */
|
|
printk("\n");
|
|
for (y = ch_begin; y < ch_end; y++)
|
|
printk("5. after fa check: chnl[%d] score[%d]\n", priv->available_chnl[y], score[y]);
|
|
printk("\n");
|
|
#endif
|
|
|
|
if (do_ap_check) {
|
|
for (i = 0; i < priv->site_survey->count; i++) {
|
|
pBss = &priv->site_survey->bss[i];
|
|
for (y = ch_begin; y < ch_end; y++) {
|
|
if (pBss->channel == priv->available_chnl[y]) {
|
|
if (pBss->channel <= 14) {
|
|
#ifdef ACS_DEBUG_INFO/* for debug */
|
|
printk("\n");
|
|
printk("chnl[%d] has ap rssi=%d bw[0x%02x]\n",
|
|
pBss->channel, pBss->rssi, pBss->t_stamp[1]);
|
|
printk("\n");
|
|
#endif
|
|
if (pBss->rssi > 60)
|
|
ap_ratio = 4;
|
|
else if (pBss->rssi > 35)
|
|
ap_ratio = 2;
|
|
else
|
|
ap_ratio = 1;
|
|
|
|
if ((pBss->t_stamp[1] & 0x6) == 0) {
|
|
score[y] += 50 * ap_ratio;
|
|
if ((int)(y - 4) >= (int)ch_begin)
|
|
score[y - 4] += 10 * ap_ratio;
|
|
if ((int)(y - 3) >= (int)ch_begin)
|
|
score[y - 3] += 20 * ap_ratio;
|
|
if ((int)(y - 2) >= (int)ch_begin)
|
|
score[y - 2] += 30 * ap_ratio;
|
|
if ((int)(y - 1) >= (int)ch_begin)
|
|
score[y - 1] += 40 * ap_ratio;
|
|
if ((int)(y + 1) < (int)ch_end)
|
|
score[y + 1] += 40 * ap_ratio;
|
|
if ((int)(y + 2) < (int)ch_end)
|
|
score[y + 2] += 30 * ap_ratio;
|
|
if ((int)(y + 3) < (int)ch_end)
|
|
score[y + 3] += 20 * ap_ratio;
|
|
if ((int)(y + 4) < (int)ch_end)
|
|
score[y + 4] += 10 * ap_ratio;
|
|
} else if ((pBss->t_stamp[1] & 0x4) == 0) {
|
|
score[y] += 50 * ap_ratio;
|
|
if ((int)(y - 3) >= (int)ch_begin)
|
|
score[y - 3] += 20 * ap_ratio;
|
|
if ((int)(y - 2) >= (int)ch_begin)
|
|
score[y - 2] += 30 * ap_ratio;
|
|
if ((int)(y - 1) >= (int)ch_begin)
|
|
score[y - 1] += 40 * ap_ratio;
|
|
if ((int)(y + 1) < (int)ch_end)
|
|
score[y + 1] += 50 * ap_ratio;
|
|
if ((int)(y + 2) < (int)ch_end)
|
|
score[y + 2] += 50 * ap_ratio;
|
|
if ((int)(y + 3) < (int)ch_end)
|
|
score[y + 3] += 50 * ap_ratio;
|
|
if ((int)(y + 4) < (int)ch_end)
|
|
score[y + 4] += 50 * ap_ratio;
|
|
if ((int)(y + 5) < (int)ch_end)
|
|
score[y + 5] += 40 * ap_ratio;
|
|
if ((int)(y + 6) < (int)ch_end)
|
|
score[y + 6] += 30 * ap_ratio;
|
|
if ((int)(y + 7) < (int)ch_end)
|
|
score[y + 7] += 20 * ap_ratio;
|
|
} else {
|
|
score[y] += 50 * ap_ratio;
|
|
if ((int)(y - 7) >= (int)ch_begin)
|
|
score[y - 7] += 20 * ap_ratio;
|
|
if ((int)(y - 6) >= (int)ch_begin)
|
|
score[y - 6] += 30 * ap_ratio;
|
|
if ((int)(y - 5) >= (int)ch_begin)
|
|
score[y - 5] += 40 * ap_ratio;
|
|
if ((int)(y - 4) >= (int)ch_begin)
|
|
score[y - 4] += 50 * ap_ratio;
|
|
if ((int)(y - 3) >= (int)ch_begin)
|
|
score[y - 3] += 50 * ap_ratio;
|
|
if ((int)(y - 2) >= (int)ch_begin)
|
|
score[y - 2] += 50 * ap_ratio;
|
|
if ((int)(y - 1) >= (int)ch_begin)
|
|
score[y - 1] += 50 * ap_ratio;
|
|
if ((int)(y + 1) < (int)ch_end)
|
|
score[y + 1] += 40 * ap_ratio;
|
|
if ((int)(y + 2) < (int)ch_end)
|
|
score[y + 2] += 30 * ap_ratio;
|
|
if ((int)(y + 3) < (int)ch_end)
|
|
score[y + 3] += 20 * ap_ratio;
|
|
}
|
|
} else {
|
|
if ((pBss->t_stamp[1] & 0x6) == 0)
|
|
score[y] += 500;
|
|
else if ((pBss->t_stamp[1] & 0x4) == 0) {
|
|
score[y] += 500;
|
|
if ((int)(y + 1) < (int)ch_end)
|
|
score[y + 1] += 500;
|
|
} else {
|
|
score[y] += 500;
|
|
if ((int)(y - 1) >= (int)ch_begin)
|
|
score[y - 1] += 500;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef ACS_DEBUG_INFO/* for debug */
|
|
printk("\n");
|
|
for (y = ch_begin; y < ch_end; y++)
|
|
printk("6. after ap check: chnl[%d]:%d\n", priv->available_chnl[y], score[y]);
|
|
printk("\n");
|
|
#endif
|
|
|
|
#ifdef SS_CH_LOAD_PROC
|
|
|
|
/* caculate noise level -- suggested by wilson */
|
|
for (y = ch_begin; y < ch_end; y++) {
|
|
int fa_lv = 0, cca_lv = 0;
|
|
if (priv->chnl_ss_fa_count[y] > 1000)
|
|
fa_lv = 100;
|
|
else if (priv->chnl_ss_fa_count[y] > 500)
|
|
fa_lv = 34 * (priv->chnl_ss_fa_count[y] - 500) / 500 + 66;
|
|
else if (priv->chnl_ss_fa_count[y] > 200)
|
|
fa_lv = 33 * (priv->chnl_ss_fa_count[y] - 200) / 300 + 33;
|
|
else if (priv->chnl_ss_fa_count[y] > 100)
|
|
fa_lv = 18 * (priv->chnl_ss_fa_count[y] - 100) / 100 + 15;
|
|
else
|
|
fa_lv = 15 * priv->chnl_ss_fa_count[y] / 100;
|
|
if (priv->chnl_ss_cca_count[y] > 400)
|
|
cca_lv = 100;
|
|
else if (priv->chnl_ss_cca_count[y] > 200)
|
|
cca_lv = 34 * (priv->chnl_ss_cca_count[y] - 200) / 200 + 66;
|
|
else if (priv->chnl_ss_cca_count[y] > 80)
|
|
cca_lv = 33 * (priv->chnl_ss_cca_count[y] - 80) / 120 + 33;
|
|
else if (priv->chnl_ss_cca_count[y] > 40)
|
|
cca_lv = 18 * (priv->chnl_ss_cca_count[y] - 40) / 40 + 15;
|
|
else
|
|
cca_lv = 15 * priv->chnl_ss_cca_count[y] / 40;
|
|
|
|
priv->chnl_ss_load[y] = (((fa_lv > cca_lv) ? fa_lv : cca_lv) * 75 + ((score[y] > 100) ? 100 : score[y]) * 25) / 100;
|
|
|
|
DEBUG_INFO("ch:%d f=%d (%d), c=%d (%d), fl=%d, cl=%d, sc=%d, cu=%d\n",
|
|
priv->available_chnl[y],
|
|
priv->chnl_ss_fa_count[y], fa_thd,
|
|
priv->chnl_ss_cca_count[y], cca_thd,
|
|
fa_lv,
|
|
cca_lv,
|
|
score[y],
|
|
priv->chnl_ss_load[y]);
|
|
|
|
}
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
choose_ch:
|
|
|
|
#ifdef DFS
|
|
/* heavy weighted DFS channel */
|
|
if (idx_5G_begin >= 0) {
|
|
for (i = idx_5G_begin; i < priv->available_chnl_num; i++) {
|
|
if (!priv->pmib->dot11DFSEntry.disable_DFS && is_DFS_channel(priv->available_chnl[i])
|
|
&& (score[i] != 0xffffffff))
|
|
score[i] += 1600;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
/* prevent Auto channel selecting wrong channel in 40M mode----------------- */
|
|
if ((priv->pmib->dot11BssType.net_work_type & WIRELESS_11N)
|
|
&& priv->pshare->is_40m_bw) {
|
|
#if 0
|
|
if (GET_MIB(priv)->dot11nConfigEntry.dot11n2ndChOffset == 1) {
|
|
/* Upper Primary channel, cannot select the two lowest channels */
|
|
if (priv->pmib->dot11BssType.net_work_type & WIRELESS_11G) {
|
|
score[0] = 0xffffffff;
|
|
score[1] = 0xffffffff;
|
|
score[2] = 0xffffffff;
|
|
score[3] = 0xffffffff;
|
|
score[4] = 0xffffffff;
|
|
|
|
score[13] = 0xffffffff;
|
|
score[12] = 0xffffffff;
|
|
score[11] = 0xffffffff;
|
|
}
|
|
|
|
/* if (priv->pmib->dot11BssType.net_work_type & WIRELESS_11A) { */
|
|
/* score[idx_5G_begin] = 0xffffffff; */
|
|
/* score[idx_5G_begin + 1] = 0xffffffff; */
|
|
/* } */
|
|
} else if (GET_MIB(priv)->dot11nConfigEntry.dot11n2ndChOffset == 2) {
|
|
/* Lower Primary channel, cannot select the two highest channels */
|
|
if (priv->pmib->dot11BssType.net_work_type & WIRELESS_11G) {
|
|
score[0] = 0xffffffff;
|
|
score[1] = 0xffffffff;
|
|
score[2] = 0xffffffff;
|
|
|
|
score[13] = 0xffffffff;
|
|
score[12] = 0xffffffff;
|
|
score[11] = 0xffffffff;
|
|
score[10] = 0xffffffff;
|
|
score[9] = 0xffffffff;
|
|
}
|
|
|
|
/* if (priv->pmib->dot11BssType.net_work_type & WIRELESS_11A) { */
|
|
/* score[priv->available_chnl_num - 2] = 0xffffffff; */
|
|
/* score[priv->available_chnl_num - 1] = 0xffffffff; */
|
|
/* } */
|
|
}
|
|
#endif
|
|
for (i = 0; i <= idx_2G_end; ++i)
|
|
if (priv->available_chnl[i] == 14)
|
|
score[i] = 0xffffffff; /* mask chan14 */
|
|
|
|
#ifdef RTK_5G_SUPPORT
|
|
if (idx_5G_begin >= 0) {
|
|
for (i = idx_5G_begin; i < priv->available_chnl_num; i++) {
|
|
int ch = priv->available_chnl[i];
|
|
if (priv->available_chnl[i] > 144)
|
|
--ch;
|
|
if ((ch % 4) || ch == 140 || ch == 164) /* mask ch 140, ch 165, ch 184... */
|
|
score[i] = 0xffffffff;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
}
|
|
|
|
if (priv->pmib->dot11RFEntry.disable_ch1213) {
|
|
for (i = 0; i <= idx_2G_end; ++i) {
|
|
int ch = priv->available_chnl[i];
|
|
if ((ch == 12) || (ch == 13))
|
|
score[i] = 0xffffffff;
|
|
}
|
|
}
|
|
|
|
if (((priv->pmib->dot11StationConfigEntry.dot11RegDomain == DOMAIN_GLOBAL) ||
|
|
(priv->pmib->dot11StationConfigEntry.dot11RegDomain == DOMAIN_WORLD_WIDE)) &&
|
|
(idx_2G_end >= 11) && (idx_2G_end < 14)) {
|
|
score[13] = 0xffffffff; /* mask chan14 */
|
|
score[12] = 0xffffffff; /* mask chan13 */
|
|
score[11] = 0xffffffff; /* mask chan12 */
|
|
}
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
|
|
#ifdef _DEBUG_RTL8192CD_
|
|
for (i = 0; i < priv->available_chnl_num; i++)
|
|
len += sprintf(tmpbuf + len, "ch%d:%u ", priv->available_chnl[i], score[i]);
|
|
strcat(tmpbuf, "\n");
|
|
panic_printk("%s", tmpbuf);
|
|
|
|
#endif
|
|
|
|
if ((*dm->band_type == ODM_BAND_5G)
|
|
&& (priv->pmib->dot11nConfigEntry.dot11nUse40M == CHANNEL_WIDTH_80)) {
|
|
for (i = 0; i < priv->available_chnl_num; i++) {
|
|
if (is80MChannel(priv->available_chnl, priv->available_chnl_num, priv->available_chnl[i])) {
|
|
tmpScore = 0;
|
|
for (j = 0; j < 4; j++) {
|
|
if ((tmpScore != 0xffffffff) && (score[i + j] != 0xffffffff))
|
|
tmpScore += score[i + j];
|
|
else
|
|
tmpScore = 0xffffffff;
|
|
}
|
|
tmpScore = tmpScore / 4;
|
|
if (minScore > tmpScore) {
|
|
minScore = tmpScore;
|
|
|
|
tmpScore = 0xffffffff;
|
|
for (j = 0; j < 4; j++) {
|
|
if (score[i + j] < tmpScore) {
|
|
tmpScore = score[i + j];
|
|
tmpIdx = i + j;
|
|
}
|
|
}
|
|
|
|
idx = tmpIdx;
|
|
}
|
|
i += 3;
|
|
}
|
|
}
|
|
if (minScore == 0xffffffff) {
|
|
/* there is no 80M channels */
|
|
priv->pshare->is_40m_bw = CHANNEL_WIDTH_20;
|
|
for (i = 0; i < priv->available_chnl_num; i++) {
|
|
if (score[i] < minScore) {
|
|
minScore = score[i];
|
|
idx = i;
|
|
}
|
|
}
|
|
}
|
|
} else if ((*dm->band_type == ODM_BAND_5G)
|
|
&& (priv->pmib->dot11nConfigEntry.dot11nUse40M == CHANNEL_WIDTH_40)) {
|
|
for (i = 0; i < priv->available_chnl_num; i++) {
|
|
if (is40MChannel(priv->available_chnl, priv->available_chnl_num, priv->available_chnl[i])) {
|
|
tmpScore = 0;
|
|
for (j = 0; j < 2; j++) {
|
|
if ((tmpScore != 0xffffffff) && (score[i + j] != 0xffffffff))
|
|
tmpScore += score[i + j];
|
|
else
|
|
tmpScore = 0xffffffff;
|
|
}
|
|
tmpScore = tmpScore / 2;
|
|
if (minScore > tmpScore) {
|
|
minScore = tmpScore;
|
|
|
|
tmpScore = 0xffffffff;
|
|
for (j = 0; j < 2; j++) {
|
|
if (score[i + j] < tmpScore) {
|
|
tmpScore = score[i + j];
|
|
tmpIdx = i + j;
|
|
}
|
|
}
|
|
|
|
idx = tmpIdx;
|
|
}
|
|
i += 1;
|
|
}
|
|
}
|
|
if (minScore == 0xffffffff) {
|
|
/* there is no 40M channels */
|
|
priv->pshare->is_40m_bw = CHANNEL_WIDTH_20;
|
|
for (i = 0; i < priv->available_chnl_num; i++) {
|
|
if (score[i] < minScore) {
|
|
minScore = score[i];
|
|
idx = i;
|
|
}
|
|
}
|
|
}
|
|
} else if ((*dm->band_type == ODM_BAND_2_4G)
|
|
&& (priv->pmib->dot11nConfigEntry.dot11nUse40M == CHANNEL_WIDTH_40)
|
|
&& (priv->available_chnl_num >= 8)) {
|
|
u32 groupScore[14];
|
|
|
|
memset(groupScore, 0xff, sizeof(groupScore));
|
|
for (i = 0; i < priv->available_chnl_num - 4; i++) {
|
|
if (score[i] != 0xffffffff && score[i + 4] != 0xffffffff) {
|
|
groupScore[i] = score[i] + score[i + 4];
|
|
DEBUG_INFO("groupScore, ch %d,%d: %d\n", i + 1, i + 5, groupScore[i]);
|
|
if (groupScore[i] < minScore) {
|
|
#ifdef AUTOCH_SS_SPEEDUP
|
|
if (priv->pmib->miscEntry.autoch_1611_enable) {
|
|
if (priv->available_chnl[i] == 1 || priv->available_chnl[i] == 6 || priv->available_chnl[i] == 11) {
|
|
minScore = groupScore[i];
|
|
idx = i;
|
|
}
|
|
} else
|
|
#endif
|
|
{
|
|
minScore = groupScore[i];
|
|
idx = i;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (score[idx] < score[idx + 4]) {
|
|
GET_MIB(priv)->dot11nConfigEntry.dot11n2ndChOffset = HT_2NDCH_OFFSET_ABOVE;
|
|
priv->pshare->offset_2nd_chan = HT_2NDCH_OFFSET_ABOVE;
|
|
} else {
|
|
idx = idx + 4;
|
|
GET_MIB(priv)->dot11nConfigEntry.dot11n2ndChOffset = HT_2NDCH_OFFSET_BELOW;
|
|
priv->pshare->offset_2nd_chan = HT_2NDCH_OFFSET_BELOW;
|
|
}
|
|
} else {
|
|
for (i = 0; i < priv->available_chnl_num; i++) {
|
|
if (score[i] < minScore) {
|
|
#ifdef AUTOCH_SS_SPEEDUP
|
|
if (priv->pmib->miscEntry.autoch_1611_enable) {
|
|
if (priv->available_chnl[i] == 1 || priv->available_chnl[i] == 6 || priv->available_chnl[i] == 11) {
|
|
minScore = score[i];
|
|
idx = i;
|
|
}
|
|
} else
|
|
#endif
|
|
{
|
|
minScore = score[i];
|
|
idx = i;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (IS_A_CUT_8881A(priv) &&
|
|
(priv->pmib->dot11nConfigEntry.dot11nUse40M == CHANNEL_WIDTH_80)) {
|
|
if ((priv->available_chnl[idx] == 36) ||
|
|
(priv->available_chnl[idx] == 52) ||
|
|
(priv->available_chnl[idx] == 100) ||
|
|
(priv->available_chnl[idx] == 116) ||
|
|
(priv->available_chnl[idx] == 132) ||
|
|
(priv->available_chnl[idx] == 149) ||
|
|
(priv->available_chnl[idx] == 165))
|
|
idx++;
|
|
else if ((priv->available_chnl[idx] == 48) ||
|
|
(priv->available_chnl[idx] == 64) ||
|
|
(priv->available_chnl[idx] == 112) ||
|
|
(priv->available_chnl[idx] == 128) ||
|
|
(priv->available_chnl[idx] == 144) ||
|
|
(priv->available_chnl[idx] == 161) ||
|
|
(priv->available_chnl[idx] == 177))
|
|
idx--;
|
|
}
|
|
|
|
minChan = priv->available_chnl[idx];
|
|
|
|
/* skip channel 14 if don't support ofdm */
|
|
if ((priv->pmib->dot11RFEntry.disable_ch14_ofdm) &&
|
|
(minChan == 14)) {
|
|
score[idx] = 0xffffffff;
|
|
|
|
minScore = 0xffffffff;
|
|
for (i = 0; i < priv->available_chnl_num; i++) {
|
|
if (score[i] < minScore) {
|
|
minScore = score[i];
|
|
idx = i;
|
|
}
|
|
}
|
|
minChan = priv->available_chnl[idx];
|
|
}
|
|
|
|
#if 0
|
|
/* Check if selected channel available for 80M/40M BW or NOT ? */
|
|
if (*dm->band_type == ODM_BAND_5G) {
|
|
if (priv->pmib->dot11nConfigEntry.dot11nUse40M == CHANNEL_WIDTH_80) {
|
|
if (!is80MChannel(priv->available_chnl, priv->available_chnl_num, minChan)) {
|
|
/* priv->pmib->dot11n_config_entry.dot11nUse40M = CHANNEL_WIDTH_40; */
|
|
priv->pshare->is_40m_bw = CHANNEL_WIDTH_40;
|
|
}
|
|
}
|
|
|
|
if (priv->pmib->dot11nConfigEntry.dot11nUse40M == CHANNEL_WIDTH_40) {
|
|
if (!is40MChannel(priv->available_chnl, priv->available_chnl_num, minChan)) {
|
|
/* priv->pmib->dot11n_config_entry.dot11nUse40M = CHANNEL_WIDTH_20; */
|
|
priv->pshare->is_40m_bw = CHANNEL_WIDTH_20;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifdef CONFIG_RTL_NEW_AUTOCH
|
|
RTL_W32(RXERR_RPT, RXERR_RPT_RST);
|
|
#endif
|
|
|
|
/* auto adjust contro-sideband */
|
|
if ((priv->pmib->dot11BssType.net_work_type & WIRELESS_11N)
|
|
&& (priv->pshare->is_40m_bw == 1 || priv->pshare->is_40m_bw == 2)) {
|
|
#ifdef RTK_5G_SUPPORT
|
|
if (*dm->band_type == ODM_BAND_5G) {
|
|
if ((minChan > 144) ? ((minChan - 1) % 8) : (minChan % 8)) {
|
|
GET_MIB(priv)->dot11nConfigEntry.dot11n2ndChOffset = HT_2NDCH_OFFSET_ABOVE;
|
|
priv->pshare->offset_2nd_chan = HT_2NDCH_OFFSET_ABOVE;
|
|
} else {
|
|
GET_MIB(priv)->dot11nConfigEntry.dot11n2ndChOffset = HT_2NDCH_OFFSET_BELOW;
|
|
priv->pshare->offset_2nd_chan = HT_2NDCH_OFFSET_BELOW;
|
|
}
|
|
|
|
} else
|
|
#endif
|
|
{
|
|
#if 0
|
|
#ifdef CONFIG_RTL_NEW_AUTOCH
|
|
unsigned int ch_max;
|
|
|
|
if (priv->available_chnl[idx_2G_end] >= 13)
|
|
ch_max = 13;
|
|
else
|
|
ch_max = priv->available_chnl[idx_2G_end];
|
|
|
|
if ((minChan >= 5) && (minChan <= (ch_max - 5))) {
|
|
if (score[minChan + 4] > score[minChan - 4]) { /* what if some channels were cancelled? */
|
|
GET_MIB(priv)->dot11nConfigEntry.dot11n2ndChOffset = HT_2NDCH_OFFSET_BELOW;
|
|
priv->pshare->offset_2nd_chan = HT_2NDCH_OFFSET_BELOW;
|
|
} else {
|
|
GET_MIB(priv)->dot11nConfigEntry.dot11n2ndChOffset = HT_2NDCH_OFFSET_ABOVE;
|
|
priv->pshare->offset_2nd_chan = HT_2NDCH_OFFSET_ABOVE;
|
|
}
|
|
} else
|
|
#endif
|
|
{
|
|
if (minChan < 5) {
|
|
GET_MIB(priv)->dot11nConfigEntry.dot11n2ndChOffset = HT_2NDCH_OFFSET_ABOVE;
|
|
priv->pshare->offset_2nd_chan = HT_2NDCH_OFFSET_ABOVE;
|
|
} else if (minChan > 7) {
|
|
GET_MIB(priv)->dot11nConfigEntry.dot11n2ndChOffset = HT_2NDCH_OFFSET_BELOW;
|
|
priv->pshare->offset_2nd_chan = HT_2NDCH_OFFSET_BELOW;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
/* ----------------------- */
|
|
|
|
#if defined(__ECOS) && defined(CONFIG_SDIO_HCI)
|
|
panic_printk("Auto channel choose ch:%d\n", minChan);
|
|
#else
|
|
#ifdef _DEBUG_RTL8192CD_
|
|
panic_printk("Auto channel choose ch:%d\n", minChan);
|
|
#endif
|
|
#endif
|
|
#ifdef ACS_DEBUG_INFO/* for debug */
|
|
printk("7. minChan:%d 2nd_offset:%d\n", minChan, priv->pshare->offset_2nd_chan);
|
|
#endif
|
|
|
|
return minChan;
|
|
}
|
|
#endif
|
|
|
|
#endif
|