Path: blob/master/ALFA-W1F1/RTL8814AU/core/rtw_rf.c
1307 views
/******************************************************************************1*2* Copyright(c) 2007 - 2017 Realtek Corporation.3*4* This program is free software; you can redistribute it and/or modify it5* under the terms of version 2 of the GNU General Public License as6* published by the Free Software Foundation.7*8* This program is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for11* more details.12*13*****************************************************************************/14#define _RTW_RF_C_1516#include <drv_types.h>17#include <hal_data.h>1819u8 center_ch_2g[CENTER_CH_2G_NUM] = {20/* G00 */1, 2,21/* G01 */3, 4, 5,22/* G02 */6, 7, 8,23/* G03 */9, 10, 11,24/* G04 */12, 13,25/* G05 */1426};2728u8 center_ch_2g_40m[CENTER_CH_2G_40M_NUM] = {293,304,315,326,337,348,359,3610,3711,38};3940u8 op_chs_of_cch_2g_40m[CENTER_CH_2G_40M_NUM][2] = {41{1, 5}, /* 3 */42{2, 6}, /* 4 */43{3, 7}, /* 5 */44{4, 8}, /* 6 */45{5, 9}, /* 7 */46{6, 10}, /* 8 */47{7, 11}, /* 9 */48{8, 12}, /* 10 */49{9, 13}, /* 11 */50};5152u8 center_ch_5g_all[CENTER_CH_5G_ALL_NUM] = {53/* G00 */36, 38, 40,5442,55/* G01 */44, 46, 48,56/* 50, */57/* G02 */52, 54, 56,5858,59/* G03 */60, 62, 64,60/* G04 */100, 102, 104,61106,62/* G05 */108, 110, 112,63/* 114, */64/* G06 */116, 118, 120,65122,66/* G07 */124, 126, 128,67/* G08 */132, 134, 136,68138,69/* G09 */140, 142, 144,70/* G10 */149, 151, 153,71155,72/* G11 */157, 159, 161,73/* 163, */74/* G12 */165, 167, 169,75171,76/* G13 */173, 175, 17777};7879u8 center_ch_5g_20m[CENTER_CH_5G_20M_NUM] = {80/* G00 */36, 40,81/* G01 */44, 48,82/* G02 */52, 56,83/* G03 */60, 64,84/* G04 */100, 104,85/* G05 */108, 112,86/* G06 */116, 120,87/* G07 */124, 128,88/* G08 */132, 136,89/* G09 */140, 144,90/* G10 */149, 153,91/* G11 */157, 161,92/* G12 */165, 169,93/* G13 */173, 17794};9596u8 center_ch_5g_40m[CENTER_CH_5G_40M_NUM] = {97/* G00 */38,98/* G01 */46,99/* G02 */54,100/* G03 */62,101/* G04 */102,102/* G05 */110,103/* G06 */118,104/* G07 */126,105/* G08 */134,106/* G09 */142,107/* G10 */151,108/* G11 */159,109/* G12 */167,110/* G13 */175111};112113u8 center_ch_5g_20m_40m[CENTER_CH_5G_20M_NUM + CENTER_CH_5G_40M_NUM] = {114/* G00 */36, 38, 40,115/* G01 */44, 46, 48,116/* G02 */52, 54, 56,117/* G03 */60, 62, 64,118/* G04 */100, 102, 104,119/* G05 */108, 110, 112,120/* G06 */116, 118, 120,121/* G07 */124, 126, 128,122/* G08 */132, 134, 136,123/* G09 */140, 142, 144,124/* G10 */149, 151, 153,125/* G11 */157, 159, 161,126/* G12 */165, 167, 169,127/* G13 */173, 175, 177128};129130u8 op_chs_of_cch_5g_40m[CENTER_CH_5G_40M_NUM][2] = {131{36, 40}, /* 38 */132{44, 48}, /* 46 */133{52, 56}, /* 54 */134{60, 64}, /* 62 */135{100, 104}, /* 102 */136{108, 112}, /* 110 */137{116, 120}, /* 118 */138{124, 128}, /* 126 */139{132, 136}, /* 134 */140{140, 144}, /* 142 */141{149, 153}, /* 151 */142{157, 161}, /* 159 */143{165, 169}, /* 167 */144{173, 177}, /* 175 */145};146147u8 center_ch_5g_80m[CENTER_CH_5G_80M_NUM] = {148/* G00 ~ G01*/42,149/* G02 ~ G03*/58,150/* G04 ~ G05*/106,151/* G06 ~ G07*/122,152/* G08 ~ G09*/138,153/* G10 ~ G11*/155,154/* G12 ~ G13*/171155};156157u8 op_chs_of_cch_5g_80m[CENTER_CH_5G_80M_NUM][4] = {158{36, 40, 44, 48}, /* 42 */159{52, 56, 60, 64}, /* 58 */160{100, 104, 108, 112}, /* 106 */161{116, 120, 124, 128}, /* 122 */162{132, 136, 140, 144}, /* 138 */163{149, 153, 157, 161}, /* 155 */164{165, 169, 173, 177}, /* 171 */165};166167u8 center_ch_5g_160m[CENTER_CH_5G_160M_NUM] = {168/* G00 ~ G03*/50,169/* G04 ~ G07*/114,170/* G10 ~ G13*/163171};172173u8 op_chs_of_cch_5g_160m[CENTER_CH_5G_160M_NUM][8] = {174{36, 40, 44, 48, 52, 56, 60, 64}, /* 50 */175{100, 104, 108, 112, 116, 120, 124, 128}, /* 114 */176{149, 153, 157, 161, 165, 169, 173, 177}, /* 163 */177};178179struct center_chs_ent_t {180u8 ch_num;181u8 *chs;182};183184struct center_chs_ent_t center_chs_2g_by_bw[] = {185{CENTER_CH_2G_NUM, center_ch_2g},186{CENTER_CH_2G_40M_NUM, center_ch_2g_40m},187};188189struct center_chs_ent_t center_chs_5g_by_bw[] = {190{CENTER_CH_5G_20M_NUM, center_ch_5g_20m},191{CENTER_CH_5G_40M_NUM, center_ch_5g_40m},192{CENTER_CH_5G_80M_NUM, center_ch_5g_80m},193{CENTER_CH_5G_160M_NUM, center_ch_5g_160m},194};195196/*197* Get center channel of smaller bandwidth by @param cch, @param bw, @param offset198* @cch: the given center channel199* @bw: the given bandwidth200* @offset: the given primary SC offset of the given bandwidth201*202* return center channel of smaller bandiwdth if valid, or 0203*/204u8 rtw_get_scch_by_cch_offset(u8 cch, u8 bw, u8 offset)205{206u8 t_cch = 0;207208if (bw == CHANNEL_WIDTH_20) {209t_cch = cch;210goto exit;211}212213if (offset == HAL_PRIME_CHNL_OFFSET_DONT_CARE) {214rtw_warn_on(1);215goto exit;216}217218/* 2.4G, 40MHz */219if (cch >= 3 && cch <= 11 && bw == CHANNEL_WIDTH_40) {220t_cch = (offset == HAL_PRIME_CHNL_OFFSET_UPPER) ? cch + 2 : cch - 2;221goto exit;222}223224/* 5G, 160MHz */225if (cch >= 50 && cch <= 163 && bw == CHANNEL_WIDTH_160) {226t_cch = (offset == HAL_PRIME_CHNL_OFFSET_UPPER) ? cch + 8 : cch - 8;227goto exit;228229/* 5G, 80MHz */230} else if (cch >= 42 && cch <= 171 && bw == CHANNEL_WIDTH_80) {231t_cch = (offset == HAL_PRIME_CHNL_OFFSET_UPPER) ? cch + 4 : cch - 4;232goto exit;233234/* 5G, 40MHz */235} else if (cch >= 38 && cch <= 175 && bw == CHANNEL_WIDTH_40) {236t_cch = (offset == HAL_PRIME_CHNL_OFFSET_UPPER) ? cch + 2 : cch - 2;237goto exit;238239} else {240rtw_warn_on(1);241goto exit;242}243244exit:245return t_cch;246}247248struct op_chs_ent_t {249u8 ch_num;250u8 *chs;251};252253struct op_chs_ent_t op_chs_of_cch_2g_by_bw[] = {254{1, center_ch_2g},255{2, (u8 *)op_chs_of_cch_2g_40m},256};257258struct op_chs_ent_t op_chs_of_cch_5g_by_bw[] = {259{1, center_ch_5g_20m},260{2, (u8 *)op_chs_of_cch_5g_40m},261{4, (u8 *)op_chs_of_cch_5g_80m},262{8, (u8 *)op_chs_of_cch_5g_160m},263};264265inline u8 center_chs_2g_num(u8 bw)266{267if (bw > CHANNEL_WIDTH_40)268return 0;269270return center_chs_2g_by_bw[bw].ch_num;271}272273inline u8 center_chs_2g(u8 bw, u8 id)274{275if (bw > CHANNEL_WIDTH_40)276return 0;277278if (id >= center_chs_2g_num(bw))279return 0;280281return center_chs_2g_by_bw[bw].chs[id];282}283284inline u8 center_chs_5g_num(u8 bw)285{286if (bw > CHANNEL_WIDTH_80)287return 0;288289return center_chs_5g_by_bw[bw].ch_num;290}291292inline u8 center_chs_5g(u8 bw, u8 id)293{294if (bw > CHANNEL_WIDTH_80)295return 0;296297if (id >= center_chs_5g_num(bw))298return 0;299300return center_chs_5g_by_bw[bw].chs[id];301}302303/*304* Get available op channels by @param cch, @param bw305* @cch: the given center channel306* @bw: the given bandwidth307* @op_chs: the pointer to return pointer of op channel array308* @op_ch_num: the pointer to return pointer of op channel number309*310* return valid (1) or not (0)311*/312u8 rtw_get_op_chs_by_cch_bw(u8 cch, u8 bw, u8 **op_chs, u8 *op_ch_num)313{314int i;315struct center_chs_ent_t *c_chs_ent = NULL;316struct op_chs_ent_t *op_chs_ent = NULL;317u8 valid = 1;318319if (cch <= 14320&& bw <= CHANNEL_WIDTH_40321) {322c_chs_ent = ¢er_chs_2g_by_bw[bw];323op_chs_ent = &op_chs_of_cch_2g_by_bw[bw];324} else if (cch >= 36 && cch <= 177325&& bw <= CHANNEL_WIDTH_160326) {327c_chs_ent = ¢er_chs_5g_by_bw[bw];328op_chs_ent = &op_chs_of_cch_5g_by_bw[bw];329} else {330valid = 0;331goto exit;332}333334for (i = 0; i < c_chs_ent->ch_num; i++)335if (cch == *(c_chs_ent->chs + i))336break;337338if (i == c_chs_ent->ch_num) {339valid = 0;340goto exit;341}342343*op_chs = op_chs_ent->chs + op_chs_ent->ch_num * i;344*op_ch_num = op_chs_ent->ch_num;345346exit:347return valid;348}349350u8 rtw_get_ch_group(u8 ch, u8 *group, u8 *cck_group)351{352BAND_TYPE band = BAND_MAX;353s8 gp = -1, cck_gp = -1;354355if (ch <= 14) {356band = BAND_ON_2_4G;357358if (1 <= ch && ch <= 2)359gp = 0;360else if (3 <= ch && ch <= 5)361gp = 1;362else if (6 <= ch && ch <= 8)363gp = 2;364else if (9 <= ch && ch <= 11)365gp = 3;366else if (12 <= ch && ch <= 14)367gp = 4;368else369band = BAND_MAX;370371if (ch == 14)372cck_gp = 5;373else374cck_gp = gp;375} else {376band = BAND_ON_5G;377378if (36 <= ch && ch <= 42)379gp = 0;380else if (44 <= ch && ch <= 48)381gp = 1;382else if (50 <= ch && ch <= 58)383gp = 2;384else if (60 <= ch && ch <= 64)385gp = 3;386else if (100 <= ch && ch <= 106)387gp = 4;388else if (108 <= ch && ch <= 114)389gp = 5;390else if (116 <= ch && ch <= 122)391gp = 6;392else if (124 <= ch && ch <= 130)393gp = 7;394else if (132 <= ch && ch <= 138)395gp = 8;396else if (140 <= ch && ch <= 144)397gp = 9;398else if (149 <= ch && ch <= 155)399gp = 10;400else if (157 <= ch && ch <= 161)401gp = 11;402else if (165 <= ch && ch <= 171)403gp = 12;404else if (173 <= ch && ch <= 177)405gp = 13;406else407band = BAND_MAX;408}409410if (band == BAND_MAX411|| (band == BAND_ON_2_4G && cck_gp == -1)412|| gp == -1413) {414RTW_WARN("%s invalid channel:%u", __func__, ch);415rtw_warn_on(1);416goto exit;417}418419if (group)420*group = gp;421if (cck_group && band == BAND_ON_2_4G)422*cck_group = cck_gp;423424exit:425return band;426}427428int rtw_ch2freq(int chan)429{430/* see 802.11 17.3.8.3.2 and Annex J431* there are overlapping channel numbers in 5GHz and 2GHz bands */432433/*434* RTK: don't consider the overlapping channel numbers: 5G channel <= 14,435* because we don't support it. simply judge from channel number436*/437438if (chan >= 1 && chan <= 14) {439if (chan == 14)440return 2484;441else if (chan < 14)442return 2407 + chan * 5;443} else if (chan >= 36 && chan <= 177)444return 5000 + chan * 5;445446return 0; /* not supported */447}448449int rtw_freq2ch(int freq)450{451/* see 802.11 17.3.8.3.2 and Annex J */452if (freq == 2484)453return 14;454else if (freq < 2484)455return (freq - 2407) / 5;456else if (freq >= 4910 && freq <= 4980)457return (freq - 4000) / 5;458else if (freq <= 45000) /* DMG band lower limit */459return (freq - 5000) / 5;460else if (freq >= 58320 && freq <= 64800)461return (freq - 56160) / 2160;462else463return 0;464}465466bool rtw_chbw_to_freq_range(u8 ch, u8 bw, u8 offset, u32 *hi, u32 *lo)467{468u8 c_ch;469u32 freq;470u32 hi_ret = 0, lo_ret = 0;471bool valid = _FALSE;472473if (hi)474*hi = 0;475if (lo)476*lo = 0;477478c_ch = rtw_get_center_ch(ch, bw, offset);479freq = rtw_ch2freq(c_ch);480481if (!freq) {482rtw_warn_on(1);483goto exit;484}485486if (bw == CHANNEL_WIDTH_80) {487hi_ret = freq + 40;488lo_ret = freq - 40;489} else if (bw == CHANNEL_WIDTH_40) {490hi_ret = freq + 20;491lo_ret = freq - 20;492} else if (bw == CHANNEL_WIDTH_20) {493hi_ret = freq + 10;494lo_ret = freq - 10;495} else496rtw_warn_on(1);497498if (hi)499*hi = hi_ret;500if (lo)501*lo = lo_ret;502503valid = _TRUE;504505exit:506return valid;507}508509const char *const _ch_width_str[CHANNEL_WIDTH_MAX] = {510"20MHz",511"40MHz",512"80MHz",513"160MHz",514"80_80MHz",515"5MHz",516"10MHz",517};518519const u8 _ch_width_to_bw_cap[CHANNEL_WIDTH_MAX] = {520BW_CAP_20M,521BW_CAP_40M,522BW_CAP_80M,523BW_CAP_160M,524BW_CAP_80_80M,525BW_CAP_5M,526BW_CAP_10M,527};528529const char *const _band_str[] = {530"2.4G",531"5G",532"BOTH",533"BAND_MAX",534};535536const u8 _band_to_band_cap[] = {537BAND_CAP_2G,538BAND_CAP_5G,5390,5400,541};542543const u8 _rf_type_to_rf_tx_cnt[] = {5441, /*RF_1T1R*/5451, /*RF_1T2R*/5462, /*RF_2T2R*/5472, /*RF_2T3R*/5482, /*RF_2T4R*/5493, /*RF_3T3R*/5503, /*RF_3T4R*/5514, /*RF_4T4R*/5521, /*RF_TYPE_MAX*/553};554555const u8 _rf_type_to_rf_rx_cnt[] = {5561, /*RF_1T1R*/5572, /*RF_1T2R*/5582, /*RF_2T2R*/5593, /*RF_2T3R*/5604, /*RF_2T4R*/5613, /*RF_3T3R*/5624, /*RF_3T4R*/5634, /*RF_4T4R*/5641, /*RF_TYPE_MAX*/565};566567const char *const _rf_type_to_rfpath_str[] = {568"RF_1T1R",569"RF_1T2R",570"RF_2T2R",571"RF_2T3R",572"RF_2T4R",573"RF_3T3R",574"RF_3T4R",575"RF_4T4R",576"RF_TYPE_MAX"577};578579void rf_type_to_default_trx_bmp(enum rf_type rf, enum bb_path *tx, enum bb_path *rx)580{581switch (rf) {582case RF_1T1R:583*tx = BB_PATH_A;584*rx = BB_PATH_A;585break;586case RF_1T2R:587*tx = BB_PATH_A;588*rx = BB_PATH_AB;589break;590case RF_2T2R:591*tx = BB_PATH_AB;592*rx = BB_PATH_AB;593break;594case RF_2T3R:595*tx = BB_PATH_AB;596*rx = BB_PATH_ABC;597break;598case RF_2T4R:599*tx = BB_PATH_AB;600*rx = BB_PATH_ABCD;601break;602case RF_3T3R:603*tx = BB_PATH_ABC;604*rx = BB_PATH_ABC;605break;606case RF_3T4R:607*tx = BB_PATH_ABC;608*rx = BB_PATH_ABCD;609break;610case RF_4T4R:611*tx = BB_PATH_ABCD;612*rx = BB_PATH_ABCD;613break;614default:615*tx = BB_PATH_A;616*rx = BB_PATH_A;617break;618}619}620621static const u8 _trx_num_to_rf_type[RF_PATH_MAX][RF_PATH_MAX] = {622{RF_1T1R, RF_1T2R, RF_TYPE_MAX, RF_TYPE_MAX},623{RF_TYPE_MAX, RF_2T2R, RF_2T3R, RF_2T4R},624{RF_TYPE_MAX, RF_TYPE_MAX, RF_3T3R, RF_3T4R},625{RF_TYPE_MAX, RF_TYPE_MAX, RF_TYPE_MAX, RF_4T4R},626};627628enum rf_type trx_num_to_rf_type(u8 tx_num, u8 rx_num)629{630if (tx_num > 0 && tx_num <= RF_PATH_MAX && rx_num > 0 && rx_num <= RF_PATH_MAX)631return _trx_num_to_rf_type[tx_num - 1][rx_num - 1];632return RF_TYPE_MAX;633}634635enum rf_type trx_bmp_to_rf_type(u8 tx_bmp, u8 rx_bmp)636{637u8 tx_num = 0;638u8 rx_num = 0;639int i;640641for (i = 0; i < RF_PATH_MAX; i++) {642if (tx_bmp >> i & BIT0)643tx_num++;644if (rx_bmp >> i & BIT0)645rx_num++;646}647648return trx_num_to_rf_type(tx_num, rx_num);649}650651bool rf_type_is_a_in_b(enum rf_type a, enum rf_type b)652{653return rf_type_to_rf_tx_cnt(a) <= rf_type_to_rf_tx_cnt(b)654&& rf_type_to_rf_rx_cnt(a) <= rf_type_to_rf_rx_cnt(b);655}656657static void rtw_path_bmp_limit_from_higher(u8 *bmp, u8 *bmp_bit_cnt, u8 bit_cnt_lmt)658{659int i;660661for (i = RF_PATH_MAX - 1; *bmp_bit_cnt > bit_cnt_lmt && i >= 0; i--) {662if (*bmp & BIT(i)) {663*bmp &= ~BIT(i);664(*bmp_bit_cnt)--;665}666}667}668669u8 rtw_restrict_trx_path_bmp_by_rftype(u8 trx_path_bmp, enum rf_type type, u8 *tx_num, u8 *rx_num)670{671u8 bmp_tx = (trx_path_bmp & 0xF0) >> 4;672u8 bmp_rx = trx_path_bmp & 0x0F;673u8 bmp_tx_num = 0, bmp_rx_num = 0;674u8 tx_num_lmt, rx_num_lmt;675enum rf_type ret_type = RF_TYPE_MAX;676int i, j;677678for (i = 0; i < RF_PATH_MAX; i++) {679if (bmp_tx & BIT(i))680bmp_tx_num++;681if (bmp_rx & BIT(i))682bmp_rx_num++;683}684685/* limit higher bit first according to input type */686tx_num_lmt = rf_type_to_rf_tx_cnt(type);687rx_num_lmt = rf_type_to_rf_rx_cnt(type);688rtw_path_bmp_limit_from_higher(&bmp_tx, &bmp_tx_num, tx_num_lmt);689rtw_path_bmp_limit_from_higher(&bmp_rx, &bmp_rx_num, rx_num_lmt);690691/* search for valid rf_type (larger RX prefer) */692for (j = bmp_rx_num; j > 0; j--) {693for (i = bmp_tx_num; i > 0; i--) {694ret_type = trx_num_to_rf_type(i, j);695if (RF_TYPE_VALID(ret_type)) {696rtw_path_bmp_limit_from_higher(&bmp_tx, &bmp_tx_num, i);697rtw_path_bmp_limit_from_higher(&bmp_rx, &bmp_rx_num, j);698if (tx_num)699*tx_num = bmp_tx_num;700if (rx_num)701*rx_num = bmp_rx_num;702goto exit;703}704}705}706707exit:708return RF_TYPE_VALID(ret_type) ? ((bmp_tx << 4) | bmp_rx) : 0x00;709}710711/* config to non N-TX value, path with lower index prefer */712void tx_path_nss_set_default(enum bb_path txpath_nss[], u8 txpath_num_nss[], u8 txpath)713{714int i, j;715u8 cnt;716717for (i = 4; i > 0; i--) {718cnt = 0;719txpath_nss[i - 1] = 0;720for (j = 0; j < RF_PATH_MAX; j++) {721if (txpath & BIT(j)) {722txpath_nss[i - 1] |= BIT(j);723if (++cnt == i)724break;725}726}727txpath_num_nss[i - 1] = i;728}729}730731/* config to full N-TX value */732void tx_path_nss_set_full_tx(enum bb_path txpath_nss[], u8 txpath_num_nss[], u8 txpath)733{734u8 tx_num = 0;735int i;736737for (i = 0; i < RF_PATH_MAX; i++)738if (txpath & BIT(i))739tx_num++;740741for (i = 4; i > 0; i--) {742txpath_nss[i - 1] = txpath;743txpath_num_nss[i - 1] = tx_num;744}745}746747const char *const _regd_str[] = {748"NONE",749"FCC",750"MKK",751"ETSI",752"IC",753"KCC",754"ACMA",755"CHILE",756"MEXICO",757"WW",758};759760#if CONFIG_TXPWR_LIMIT761void _dump_regd_exc_list(void *sel, struct rf_ctl_t *rfctl)762{763struct regd_exc_ent *ent;764_list *cur, *head;765766RTW_PRINT_SEL(sel, "regd_exc_num:%u\n", rfctl->regd_exc_num);767768if (!rfctl->regd_exc_num)769goto exit;770771RTW_PRINT_SEL(sel, "%-7s %-6s %-9s\n", "country", "domain", "regd_name");772773head = &rfctl->reg_exc_list;774cur = get_next(head);775776while ((rtw_end_of_queue_search(head, cur)) == _FALSE) {777u8 has_country;778779ent = LIST_CONTAINOR(cur, struct regd_exc_ent, list);780cur = get_next(cur);781has_country = (ent->country[0] == '\0' && ent->country[1] == '\0') ? 0 : 1;782783RTW_PRINT_SEL(sel, " %c%c 0x%02x %s\n"784, has_country ? ent->country[0] : '0'785, has_country ? ent->country[1] : '0'786, ent->domain787, ent->regd_name788);789}790791exit:792return;793}794795inline void dump_regd_exc_list(void *sel, struct rf_ctl_t *rfctl)796{797_irqL irqL;798799_enter_critical_mutex(&rfctl->txpwr_lmt_mutex, &irqL);800_dump_regd_exc_list(sel, rfctl);801_exit_critical_mutex(&rfctl->txpwr_lmt_mutex, &irqL);802}803804void rtw_regd_exc_add_with_nlen(struct rf_ctl_t *rfctl, const char *country, u8 domain, const char *regd_name, u32 nlen)805{806struct regd_exc_ent *ent;807_irqL irqL;808809if (!regd_name || !nlen) {810rtw_warn_on(1);811goto exit;812}813814ent = (struct regd_exc_ent *)rtw_zmalloc(sizeof(struct regd_exc_ent) + nlen + 1);815if (!ent)816goto exit;817818_rtw_init_listhead(&ent->list);819if (country)820_rtw_memcpy(ent->country, country, 2);821ent->domain = domain;822_rtw_memcpy(ent->regd_name, regd_name, nlen);823824_enter_critical_mutex(&rfctl->txpwr_lmt_mutex, &irqL);825826rtw_list_insert_tail(&ent->list, &rfctl->reg_exc_list);827rfctl->regd_exc_num++;828829_exit_critical_mutex(&rfctl->txpwr_lmt_mutex, &irqL);830831exit:832return;833}834835inline void rtw_regd_exc_add(struct rf_ctl_t *rfctl, const char *country, u8 domain, const char *regd_name)836{837rtw_regd_exc_add_with_nlen(rfctl, country, domain, regd_name, strlen(regd_name));838}839840struct regd_exc_ent *_rtw_regd_exc_search(struct rf_ctl_t *rfctl, const char *country, u8 domain)841{842struct regd_exc_ent *ent;843_list *cur, *head;844u8 match = 0;845846head = &rfctl->reg_exc_list;847cur = get_next(head);848849while ((rtw_end_of_queue_search(head, cur)) == _FALSE) {850u8 has_country;851852ent = LIST_CONTAINOR(cur, struct regd_exc_ent, list);853cur = get_next(cur);854has_country = (ent->country[0] == '\0' && ent->country[1] == '\0') ? 0 : 1;855856/* entry has country condition to match */857if (has_country) {858if (!country)859continue;860if (ent->country[0] != country[0]861|| ent->country[1] != country[1])862continue;863}864865/* entry has domain condition to match */866if (ent->domain != 0xFF) {867if (domain == 0xFF)868continue;869if (ent->domain != domain)870continue;871}872873match = 1;874break;875}876877if (match)878return ent;879else880return NULL;881}882883inline struct regd_exc_ent *rtw_regd_exc_search(struct rf_ctl_t *rfctl, const char *country, u8 domain)884{885struct regd_exc_ent *ent;886_irqL irqL;887888_enter_critical_mutex(&rfctl->txpwr_lmt_mutex, &irqL);889ent = _rtw_regd_exc_search(rfctl, country, domain);890_exit_critical_mutex(&rfctl->txpwr_lmt_mutex, &irqL);891892return ent;893}894895void rtw_regd_exc_list_free(struct rf_ctl_t *rfctl)896{897struct regd_exc_ent *ent;898_irqL irqL;899_list *cur, *head;900901_enter_critical_mutex(&rfctl->txpwr_lmt_mutex, &irqL);902903head = &rfctl->reg_exc_list;904cur = get_next(head);905906while ((rtw_end_of_queue_search(head, cur)) == _FALSE) {907ent = LIST_CONTAINOR(cur, struct regd_exc_ent, list);908cur = get_next(cur);909rtw_list_delete(&ent->list);910rtw_mfree((u8 *)ent, sizeof(struct regd_exc_ent) + strlen(ent->regd_name) + 1);911}912rfctl->regd_exc_num = 0;913914_exit_critical_mutex(&rfctl->txpwr_lmt_mutex, &irqL);915}916917void dump_txpwr_lmt(void *sel, _adapter *adapter)918{919#define TMP_STR_LEN 16920struct rf_ctl_t *rfctl = adapter_to_rfctl(adapter);921HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter);922struct hal_spec_t *hal_spec = GET_HAL_SPEC(adapter);923_irqL irqL;924char fmt[16];925char tmp_str[TMP_STR_LEN];926s8 *lmt_idx = NULL;927int bw, band, ch_num, tlrs, ntx_idx, rs, i, path;928u8 ch, n, rfpath_num;929930_enter_critical_mutex(&rfctl->txpwr_lmt_mutex, &irqL);931932_dump_regd_exc_list(sel, rfctl);933RTW_PRINT_SEL(sel, "\n");934935if (!rfctl->txpwr_regd_num)936goto release_lock;937938lmt_idx = rtw_malloc(sizeof(s8) * RF_PATH_MAX * rfctl->txpwr_regd_num);939if (!lmt_idx) {940RTW_ERR("%s alloc fail\n", __func__);941goto release_lock;942}943944RTW_PRINT_SEL(sel, "txpwr_lmt_2g_cck_ofdm_state:0x%02x\n", rfctl->txpwr_lmt_2g_cck_ofdm_state);945#ifdef CONFIG_IEEE80211_BAND_5GHZ946if (IS_HARDWARE_TYPE_JAGUAR_ALL(adapter)) {947RTW_PRINT_SEL(sel, "txpwr_lmt_5g_cck_ofdm_state:0x%02x\n", rfctl->txpwr_lmt_5g_cck_ofdm_state);948RTW_PRINT_SEL(sel, "txpwr_lmt_5g_20_40_ref:0x%02x\n", rfctl->txpwr_lmt_5g_20_40_ref);949}950#endif951RTW_PRINT_SEL(sel, "\n");952953for (band = BAND_ON_2_4G; band <= BAND_ON_5G; band++) {954if (!hal_is_band_support(adapter, band))955continue;956957rfpath_num = (band == BAND_ON_2_4G ? hal_spec->rfpath_num_2g : hal_spec->rfpath_num_5g);958959for (bw = 0; bw < MAX_5G_BANDWIDTH_NUM; bw++) {960961if (bw >= CHANNEL_WIDTH_160)962break;963if (band == BAND_ON_2_4G && bw >= CHANNEL_WIDTH_80)964break;965966if (band == BAND_ON_2_4G)967ch_num = CENTER_CH_2G_NUM;968else969ch_num = center_chs_5g_num(bw);970971if (ch_num == 0) {972rtw_warn_on(1);973break;974}975976for (tlrs = TXPWR_LMT_RS_CCK; tlrs < TXPWR_LMT_RS_NUM; tlrs++) {977978if (band == BAND_ON_2_4G && tlrs == TXPWR_LMT_RS_VHT)979continue;980if (band == BAND_ON_5G && tlrs == TXPWR_LMT_RS_CCK)981continue;982if (bw > CHANNEL_WIDTH_20 && (tlrs == TXPWR_LMT_RS_CCK || tlrs == TXPWR_LMT_RS_OFDM))983continue;984if (bw > CHANNEL_WIDTH_40 && tlrs == TXPWR_LMT_RS_HT)985continue;986if (tlrs == TXPWR_LMT_RS_VHT && !IS_HARDWARE_TYPE_JAGUAR_ALL(adapter))987continue;988989for (ntx_idx = RF_1TX; ntx_idx < MAX_TX_COUNT; ntx_idx++) {990struct txpwr_lmt_ent *ent;991_list *cur, *head;992993if (ntx_idx + 1 > hal_data->max_tx_cnt)994continue;995996/* bypass CCK multi-TX is not defined */997if (tlrs == TXPWR_LMT_RS_CCK && ntx_idx > RF_1TX) {998if (band == BAND_ON_2_4G999&& !(rfctl->txpwr_lmt_2g_cck_ofdm_state & (TXPWR_LMT_HAS_CCK_1T << ntx_idx)))1000continue;1001}10021003/* bypass OFDM multi-TX is not defined */1004if (tlrs == TXPWR_LMT_RS_OFDM && ntx_idx > RF_1TX) {1005if (band == BAND_ON_2_4G1006&& !(rfctl->txpwr_lmt_2g_cck_ofdm_state & (TXPWR_LMT_HAS_OFDM_1T << ntx_idx)))1007continue;1008#ifdef CONFIG_IEEE80211_BAND_5GHZ1009if (band == BAND_ON_5G1010&& !(rfctl->txpwr_lmt_5g_cck_ofdm_state & (TXPWR_LMT_HAS_OFDM_1T << ntx_idx)))1011continue;1012#endif1013}10141015/* bypass 5G 20M, 40M pure reference */1016#ifdef CONFIG_IEEE80211_BAND_5GHZ1017if (band == BAND_ON_5G && (bw == CHANNEL_WIDTH_20 || bw == CHANNEL_WIDTH_40)) {1018if (rfctl->txpwr_lmt_5g_20_40_ref == TXPWR_LMT_REF_HT_FROM_VHT) {1019if (tlrs == TXPWR_LMT_RS_HT)1020continue;1021} else if (rfctl->txpwr_lmt_5g_20_40_ref == TXPWR_LMT_REF_VHT_FROM_HT) {1022if (tlrs == TXPWR_LMT_RS_VHT && bw <= CHANNEL_WIDTH_40)1023continue;1024}1025}1026#endif10271028/* choose n-SS mapping rate section to get lmt diff value */1029if (tlrs == TXPWR_LMT_RS_CCK)1030rs = CCK;1031else if (tlrs == TXPWR_LMT_RS_OFDM)1032rs = OFDM;1033else if (tlrs == TXPWR_LMT_RS_HT)1034rs = HT_1SS + ntx_idx;1035else if (tlrs == TXPWR_LMT_RS_VHT)1036rs = VHT_1SS + ntx_idx;1037else {1038RTW_ERR("%s invalid tlrs %u\n", __func__, tlrs);1039continue;1040}10411042RTW_PRINT_SEL(sel, "[%s][%s][%s][%uT]\n"1043, band_str(band)1044, ch_width_str(bw)1045, txpwr_lmt_rs_str(tlrs)1046, ntx_idx + 11047);10481049/* header for limit in db */1050RTW_PRINT_SEL(sel, "%3s ", "ch");10511052head = &rfctl->txpwr_lmt_list;1053cur = get_next(head);1054while ((rtw_end_of_queue_search(head, cur)) == _FALSE) {1055ent = LIST_CONTAINOR(cur, struct txpwr_lmt_ent, list);1056cur = get_next(cur);10571058sprintf(fmt, "%%%zus%%s ", strlen(ent->regd_name) >= 6 ? 1 : 6 - strlen(ent->regd_name));1059snprintf(tmp_str, TMP_STR_LEN, fmt1060, strcmp(ent->regd_name, rfctl->regd_name) == 0 ? "*" : ""1061, ent->regd_name);1062_RTW_PRINT_SEL(sel, "%s", tmp_str);1063}1064sprintf(fmt, "%%%zus%%s ", strlen(regd_str(TXPWR_LMT_WW)) >= 6 ? 1 : 6 - strlen(regd_str(TXPWR_LMT_WW)));1065snprintf(tmp_str, TMP_STR_LEN, fmt1066, strcmp(rfctl->regd_name, regd_str(TXPWR_LMT_WW)) == 0 ? "*" : ""1067, regd_str(TXPWR_LMT_WW));1068_RTW_PRINT_SEL(sel, "%s", tmp_str);10691070/* header for limit offset */1071for (path = 0; path < RF_PATH_MAX; path++) {1072if (path >= rfpath_num)1073break;1074_RTW_PRINT_SEL(sel, "|");1075head = &rfctl->txpwr_lmt_list;1076cur = get_next(head);1077while ((rtw_end_of_queue_search(head, cur)) == _FALSE) {1078ent = LIST_CONTAINOR(cur, struct txpwr_lmt_ent, list);1079cur = get_next(cur);1080_RTW_PRINT_SEL(sel, "%3c "1081, strcmp(ent->regd_name, rfctl->regd_name) == 0 ? rf_path_char(path) : ' ');1082}1083_RTW_PRINT_SEL(sel, "%3c "1084, strcmp(rfctl->regd_name, regd_str(TXPWR_LMT_WW)) == 0 ? rf_path_char(path) : ' ');1085}1086_RTW_PRINT_SEL(sel, "\n");10871088for (n = 0; n < ch_num; n++) {1089s8 lmt;1090s8 lmt_offset;1091u8 base;10921093if (band == BAND_ON_2_4G)1094ch = n + 1;1095else1096ch = center_chs_5g(bw, n);10971098if (ch == 0) {1099rtw_warn_on(1);1100break;1101}11021103/* dump limit in db */1104RTW_PRINT_SEL(sel, "%3u ", ch);1105head = &rfctl->txpwr_lmt_list;1106cur = get_next(head);1107while ((rtw_end_of_queue_search(head, cur)) == _FALSE) {1108ent = LIST_CONTAINOR(cur, struct txpwr_lmt_ent, list);1109cur = get_next(cur);1110lmt = phy_get_txpwr_lmt_abs(adapter, ent->regd_name, band, bw, tlrs, ntx_idx, ch, 0);1111if (lmt == hal_spec->txgi_max) {1112sprintf(fmt, "%%%zus ", strlen(ent->regd_name) >= 6 ? strlen(ent->regd_name) + 1 : 6);1113snprintf(tmp_str, TMP_STR_LEN, fmt, "NA");1114_RTW_PRINT_SEL(sel, "%s", tmp_str);1115} else if (lmt > -hal_spec->txgi_pdbm && lmt < 0) { /* -0.xx */1116sprintf(fmt, "%%%zus-0.%%d ", strlen(ent->regd_name) >= 6 ? strlen(ent->regd_name) - 4 : 1);1117snprintf(tmp_str, TMP_STR_LEN, fmt, "", (rtw_abs(lmt) % hal_spec->txgi_pdbm) * 100 / hal_spec->txgi_pdbm);1118_RTW_PRINT_SEL(sel, "%s", tmp_str);1119} else if (lmt % hal_spec->txgi_pdbm) { /* d.xx */1120sprintf(fmt, "%%%zud.%%d ", strlen(ent->regd_name) >= 6 ? strlen(ent->regd_name) - 2 : 3);1121snprintf(tmp_str, TMP_STR_LEN, fmt, lmt / hal_spec->txgi_pdbm, (rtw_abs(lmt) % hal_spec->txgi_pdbm) * 100 / hal_spec->txgi_pdbm);1122_RTW_PRINT_SEL(sel, "%s", tmp_str);1123} else { /* d */1124sprintf(fmt, "%%%zud ", strlen(ent->regd_name) >= 6 ? strlen(ent->regd_name) + 1 : 6);1125snprintf(tmp_str, TMP_STR_LEN, fmt, lmt / hal_spec->txgi_pdbm);1126_RTW_PRINT_SEL(sel, "%s", tmp_str);1127}1128}1129lmt = phy_get_txpwr_lmt_abs(adapter, regd_str(TXPWR_LMT_WW), band, bw, tlrs, ntx_idx, ch, 0);1130if (lmt == hal_spec->txgi_max) {1131sprintf(fmt, "%%%zus ", strlen(regd_str(TXPWR_LMT_WW)) >= 6 ? strlen(regd_str(TXPWR_LMT_WW)) + 1 : 6);1132snprintf(tmp_str, TMP_STR_LEN, fmt, "NA");1133_RTW_PRINT_SEL(sel, "%s", tmp_str);1134} else if (lmt > -hal_spec->txgi_pdbm && lmt < 0) { /* -0.xx */1135sprintf(fmt, "%%%zus-0.%%d ", strlen(regd_str(TXPWR_LMT_WW)) >= 6 ? strlen(regd_str(TXPWR_LMT_WW)) - 4 : 1);1136snprintf(tmp_str, TMP_STR_LEN, fmt, "", (rtw_abs(lmt) % hal_spec->txgi_pdbm) * 100 / hal_spec->txgi_pdbm);1137_RTW_PRINT_SEL(sel, "%s", tmp_str);1138} else if (lmt % hal_spec->txgi_pdbm) { /* d.xx */1139sprintf(fmt, "%%%zud.%%d ", strlen(regd_str(TXPWR_LMT_WW)) >= 6 ? strlen(regd_str(TXPWR_LMT_WW)) - 2 : 3);1140snprintf(tmp_str, TMP_STR_LEN, fmt, lmt / hal_spec->txgi_pdbm, (rtw_abs(lmt) % hal_spec->txgi_pdbm) * 100 / hal_spec->txgi_pdbm);1141_RTW_PRINT_SEL(sel, "%s", tmp_str);1142} else { /* d */1143sprintf(fmt, "%%%zud ", strlen(regd_str(TXPWR_LMT_WW)) >= 6 ? strlen(regd_str(TXPWR_LMT_WW)) + 1 : 6);1144snprintf(tmp_str, TMP_STR_LEN, fmt, lmt / hal_spec->txgi_pdbm);1145_RTW_PRINT_SEL(sel, "%s", tmp_str);1146}11471148/* dump limit offset of each path */1149for (path = RF_PATH_A; path < RF_PATH_MAX; path++) {1150if (path >= rfpath_num)1151break;11521153#ifdef CONFIG_USE_TSSI1154base = PHY_GetTxPowerByRateOriginal(adapter, band, path, MGN_MCS7);1155#else1156base = PHY_GetTxPowerByRateBase(adapter, band, path, rs);1157#endif11581159_RTW_PRINT_SEL(sel, "|");1160head = &rfctl->txpwr_lmt_list;1161cur = get_next(head);1162i = 0;1163while ((rtw_end_of_queue_search(head, cur)) == _FALSE) {1164ent = LIST_CONTAINOR(cur, struct txpwr_lmt_ent, list);1165cur = get_next(cur);1166lmt_offset = phy_get_txpwr_lmt(adapter, ent->regd_name, band, bw, path, rs, ntx_idx, ch, 0);1167if (lmt_offset == hal_spec->txgi_max) {1168*(lmt_idx + i * RF_PATH_MAX + path) = hal_spec->txgi_max;1169_RTW_PRINT_SEL(sel, "%3s ", "NA");1170} else {1171*(lmt_idx + i * RF_PATH_MAX + path) = lmt_offset + base;1172_RTW_PRINT_SEL(sel, "%3d ", lmt_offset);1173}1174i++;1175}1176lmt_offset = phy_get_txpwr_lmt(adapter, regd_str(TXPWR_LMT_WW), band, bw, path, rs, ntx_idx, ch, 0);1177if (lmt_offset == hal_spec->txgi_max)1178_RTW_PRINT_SEL(sel, "%3s ", "NA");1179else1180_RTW_PRINT_SEL(sel, "%3d ", lmt_offset);11811182}11831184/* compare limit_idx of each path, print 'x' when mismatch */1185if (rfpath_num > 1) {1186for (i = 0; i < rfctl->txpwr_regd_num; i++) {1187for (path = 0; path < RF_PATH_MAX; path++) {1188if (path >= rfpath_num)1189break;1190if (*(lmt_idx + i * RF_PATH_MAX + path) != *(lmt_idx + i * RF_PATH_MAX + ((path + 1) % rfpath_num)))1191break;1192}1193if (path >= rfpath_num)1194_RTW_PRINT_SEL(sel, " ");1195else1196_RTW_PRINT_SEL(sel, "x");1197}1198}1199_RTW_PRINT_SEL(sel, "\n");12001201}1202RTW_PRINT_SEL(sel, "\n");1203}1204} /* loop for rate sections */1205} /* loop for bandwidths */1206} /* loop for bands */12071208if (lmt_idx)1209rtw_mfree(lmt_idx, sizeof(s8) * RF_PATH_MAX * rfctl->txpwr_regd_num);12101211release_lock:1212_exit_critical_mutex(&rfctl->txpwr_lmt_mutex, &irqL);1213}12141215/* search matcing first, if not found, alloc one */1216void rtw_txpwr_lmt_add_with_nlen(struct rf_ctl_t *rfctl, const char *regd_name, u32 nlen1217, u8 band, u8 bw, u8 tlrs, u8 ntx_idx, u8 ch_idx, s8 lmt)1218{1219struct hal_spec_t *hal_spec = GET_HAL_SPEC(dvobj_get_primary_adapter(rfctl_to_dvobj(rfctl)));1220struct txpwr_lmt_ent *ent;1221_irqL irqL;1222_list *cur, *head;1223s8 pre_lmt;12241225if (!regd_name || !nlen) {1226rtw_warn_on(1);1227goto exit;1228}12291230_enter_critical_mutex(&rfctl->txpwr_lmt_mutex, &irqL);12311232/* search for existed entry */1233head = &rfctl->txpwr_lmt_list;1234cur = get_next(head);1235while ((rtw_end_of_queue_search(head, cur)) == _FALSE) {1236ent = LIST_CONTAINOR(cur, struct txpwr_lmt_ent, list);1237cur = get_next(cur);12381239if (strlen(ent->regd_name) == nlen1240&& _rtw_memcmp(ent->regd_name, regd_name, nlen) == _TRUE)1241goto chk_lmt_val;1242}12431244/* alloc new one */1245ent = (struct txpwr_lmt_ent *)rtw_zvmalloc(sizeof(struct txpwr_lmt_ent) + nlen + 1);1246if (!ent)1247goto release_lock;12481249_rtw_init_listhead(&ent->list);1250_rtw_memcpy(ent->regd_name, regd_name, nlen);1251{1252u8 j, k, l, m;12531254for (j = 0; j < MAX_2_4G_BANDWIDTH_NUM; ++j)1255for (k = 0; k < TXPWR_LMT_RS_NUM_2G; ++k)1256for (m = 0; m < CENTER_CH_2G_NUM; ++m)1257for (l = 0; l < MAX_TX_COUNT; ++l)1258ent->lmt_2g[j][k][m][l] = hal_spec->txgi_max;1259#ifdef CONFIG_IEEE80211_BAND_5GHZ1260for (j = 0; j < MAX_5G_BANDWIDTH_NUM; ++j)1261for (k = 0; k < TXPWR_LMT_RS_NUM_5G; ++k)1262for (m = 0; m < CENTER_CH_5G_ALL_NUM; ++m)1263for (l = 0; l < MAX_TX_COUNT; ++l)1264ent->lmt_5g[j][k][m][l] = hal_spec->txgi_max;1265#endif1266}12671268rtw_list_insert_tail(&ent->list, &rfctl->txpwr_lmt_list);1269rfctl->txpwr_regd_num++;12701271chk_lmt_val:1272if (band == BAND_ON_2_4G)1273pre_lmt = ent->lmt_2g[bw][tlrs][ch_idx][ntx_idx];1274#ifdef CONFIG_IEEE80211_BAND_5GHZ1275else if (band == BAND_ON_5G)1276pre_lmt = ent->lmt_5g[bw][tlrs - 1][ch_idx][ntx_idx];1277#endif1278else1279goto release_lock;12801281if (pre_lmt != hal_spec->txgi_max)1282RTW_PRINT("duplicate txpwr_lmt for [%s][%s][%s][%s][%uT][%d]\n"1283, regd_name, band_str(band), ch_width_str(bw), txpwr_lmt_rs_str(tlrs), ntx_idx + 11284, band == BAND_ON_2_4G ? ch_idx + 1 : center_ch_5g_all[ch_idx]);12851286lmt = rtw_min(pre_lmt, lmt);1287if (band == BAND_ON_2_4G)1288ent->lmt_2g[bw][tlrs][ch_idx][ntx_idx] = lmt;1289#ifdef CONFIG_IEEE80211_BAND_5GHZ1290else if (band == BAND_ON_5G)1291ent->lmt_5g[bw][tlrs - 1][ch_idx][ntx_idx] = lmt;1292#endif12931294if (0)1295RTW_PRINT("%s, %4s, %6s, %7s, %uT, ch%3d = %d\n"1296, regd_name, band_str(band), ch_width_str(bw), txpwr_lmt_rs_str(tlrs), ntx_idx + 11297, band == BAND_ON_2_4G ? ch_idx + 1 : center_ch_5g_all[ch_idx]1298, lmt);12991300release_lock:1301_exit_critical_mutex(&rfctl->txpwr_lmt_mutex, &irqL);13021303exit:1304return;1305}13061307inline void rtw_txpwr_lmt_add(struct rf_ctl_t *rfctl, const char *regd_name1308, u8 band, u8 bw, u8 tlrs, u8 ntx_idx, u8 ch_idx, s8 lmt)1309{1310rtw_txpwr_lmt_add_with_nlen(rfctl, regd_name, strlen(regd_name)1311, band, bw, tlrs, ntx_idx, ch_idx, lmt);1312}13131314struct txpwr_lmt_ent *_rtw_txpwr_lmt_get_by_name(struct rf_ctl_t *rfctl, const char *regd_name)1315{1316struct txpwr_lmt_ent *ent;1317_list *cur, *head;1318u8 found = 0;13191320head = &rfctl->txpwr_lmt_list;1321cur = get_next(head);13221323while ((rtw_end_of_queue_search(head, cur)) == _FALSE) {1324ent = LIST_CONTAINOR(cur, struct txpwr_lmt_ent, list);1325cur = get_next(cur);13261327if (strcmp(ent->regd_name, regd_name) == 0) {1328found = 1;1329break;1330}1331}13321333if (found)1334return ent;1335return NULL;1336}13371338inline struct txpwr_lmt_ent *rtw_txpwr_lmt_get_by_name(struct rf_ctl_t *rfctl, const char *regd_name)1339{1340struct txpwr_lmt_ent *ent;1341_irqL irqL;13421343_enter_critical_mutex(&rfctl->txpwr_lmt_mutex, &irqL);1344ent = _rtw_txpwr_lmt_get_by_name(rfctl, regd_name);1345_exit_critical_mutex(&rfctl->txpwr_lmt_mutex, &irqL);13461347return ent;1348}13491350void rtw_txpwr_lmt_list_free(struct rf_ctl_t *rfctl)1351{1352struct txpwr_lmt_ent *ent;1353_irqL irqL;1354_list *cur, *head;13551356_enter_critical_mutex(&rfctl->txpwr_lmt_mutex, &irqL);13571358head = &rfctl->txpwr_lmt_list;1359cur = get_next(head);13601361while ((rtw_end_of_queue_search(head, cur)) == _FALSE) {1362ent = LIST_CONTAINOR(cur, struct txpwr_lmt_ent, list);1363cur = get_next(cur);1364if (ent->regd_name == rfctl->regd_name)1365rfctl->regd_name = regd_str(TXPWR_LMT_NONE);1366rtw_list_delete(&ent->list);1367rtw_vmfree((u8 *)ent, sizeof(struct txpwr_lmt_ent) + strlen(ent->regd_name) + 1);1368}1369rfctl->txpwr_regd_num = 0;13701371_exit_critical_mutex(&rfctl->txpwr_lmt_mutex, &irqL);1372}1373#endif /* CONFIG_TXPWR_LIMIT */13741375int rtw_ch_to_bb_gain_sel(int ch)1376{1377int sel = -1;13781379if (ch >= 1 && ch <= 14)1380sel = BB_GAIN_2G;1381#ifdef CONFIG_IEEE80211_BAND_5GHZ1382else if (ch >= 36 && ch < 48)1383sel = BB_GAIN_5GLB1;1384else if (ch >= 52 && ch <= 64)1385sel = BB_GAIN_5GLB2;1386else if (ch >= 100 && ch <= 120)1387sel = BB_GAIN_5GMB1;1388else if (ch >= 124 && ch <= 144)1389sel = BB_GAIN_5GMB2;1390else if (ch >= 149 && ch <= 177)1391sel = BB_GAIN_5GHB;1392#endif13931394return sel;1395}13961397s8 rtw_rf_get_kfree_tx_gain_offset(_adapter *padapter, u8 path, u8 ch)1398{1399s8 kfree_offset = 0;14001401#ifdef CONFIG_RF_POWER_TRIM1402struct kfree_data_t *kfree_data = GET_KFREE_DATA(padapter);1403s8 bb_gain_sel = rtw_ch_to_bb_gain_sel(ch);14041405if (bb_gain_sel < BB_GAIN_2G || bb_gain_sel >= BB_GAIN_NUM) {1406rtw_warn_on(1);1407goto exit;1408}14091410if (kfree_data->flag & KFREE_FLAG_ON) {1411kfree_offset = kfree_data->bb_gain[bb_gain_sel][path];1412if (IS_HARDWARE_TYPE_8723D(padapter))1413RTW_INFO("%s path:%s, ch:%u, bb_gain_sel:%d, kfree_offset:%d\n"1414, __func__, (path == 0)?"S1":"S0",1415ch, bb_gain_sel, kfree_offset);1416else1417RTW_INFO("%s path:%u, ch:%u, bb_gain_sel:%d, kfree_offset:%d\n"1418, __func__, path, ch, bb_gain_sel, kfree_offset);1419}1420exit:1421#endif /* CONFIG_RF_POWER_TRIM */1422return kfree_offset;1423}14241425void rtw_rf_set_tx_gain_offset(_adapter *adapter, u8 path, s8 offset)1426{1427#if !defined(CONFIG_RTL8814A) && !defined(CONFIG_RTL8822B) && !defined(CONFIG_RTL8821C) && !defined(CONFIG_RTL8822C)1428u8 write_value;1429#endif1430u8 target_path = 0;1431u32 val32 = 0;14321433if (IS_HARDWARE_TYPE_8723D(adapter)) {1434target_path = RF_PATH_A; /*in 8723D case path means S0/S1*/1435if (path == PPG_8723D_S1)1436RTW_INFO("kfree gain_offset 0x55:0x%x ",1437rtw_hal_read_rfreg(adapter, target_path, 0x55, 0xffffffff));1438else if (path == PPG_8723D_S0)1439RTW_INFO("kfree gain_offset 0x65:0x%x ",1440rtw_hal_read_rfreg(adapter, target_path, 0x65, 0xffffffff));1441} else {1442target_path = path;1443RTW_INFO("kfree gain_offset 0x55:0x%x ", rtw_hal_read_rfreg(adapter, target_path, 0x55, 0xffffffff));1444}14451446switch (rtw_get_chip_type(adapter)) {1447#ifdef CONFIG_RTL8723D1448case RTL8723D:1449write_value = RF_TX_GAIN_OFFSET_8723D(offset);1450if (path == PPG_8723D_S1)1451rtw_hal_write_rfreg(adapter, target_path, 0x55, 0x0f8000, write_value);1452else if (path == PPG_8723D_S0)1453rtw_hal_write_rfreg(adapter, target_path, 0x65, 0x0f8000, write_value);1454break;1455#endif /* CONFIG_RTL8723D */1456#ifdef CONFIG_RTL8703B1457case RTL8703B:1458write_value = RF_TX_GAIN_OFFSET_8703B(offset);1459rtw_hal_write_rfreg(adapter, target_path, 0x55, 0x0fc000, write_value);1460break;1461#endif /* CONFIG_RTL8703B */1462#ifdef CONFIG_RTL8188F1463case RTL8188F:1464write_value = RF_TX_GAIN_OFFSET_8188F(offset);1465rtw_hal_write_rfreg(adapter, target_path, 0x55, 0x0fc000, write_value);1466break;1467#endif /* CONFIG_RTL8188F */1468#ifdef CONFIG_RTL8188GTV1469case RTL8188GTV:1470write_value = RF_TX_GAIN_OFFSET_8188GTV(offset);1471rtw_hal_write_rfreg(adapter, target_path, 0x55, 0x0fc000, write_value);1472break;1473#endif /* CONFIG_RTL8188GTV */1474#ifdef CONFIG_RTL8192E1475case RTL8192E:1476write_value = RF_TX_GAIN_OFFSET_8192E(offset);1477rtw_hal_write_rfreg(adapter, target_path, 0x55, 0x0f8000, write_value);1478break;1479#endif /* CONFIG_RTL8188F */14801481#ifdef CONFIG_RTL8821A1482case RTL8821:1483write_value = RF_TX_GAIN_OFFSET_8821A(offset);1484rtw_hal_write_rfreg(adapter, target_path, 0x55, 0x0f8000, write_value);1485break;1486#endif /* CONFIG_RTL8821A */1487#if defined(CONFIG_RTL8814A) || defined(CONFIG_RTL8822B) || defined(CONFIG_RTL8821C) || defined(CONFIG_RTL8192F) || defined(CONFIG_RTL8822C)1488case RTL8814A:1489case RTL8822B:1490case RTL8822C:1491case RTL8821C:1492case RTL8192F:1493RTW_INFO("\nkfree by PhyDM on the sw CH. path %d\n", path);1494break;1495#endif /* CONFIG_RTL8814A || CONFIG_RTL8822B || CONFIG_RTL8821C */14961497default:1498rtw_warn_on(1);1499break;1500}15011502if (IS_HARDWARE_TYPE_8723D(adapter)) {1503if (path == PPG_8723D_S1)1504val32 = rtw_hal_read_rfreg(adapter, target_path, 0x55, 0xffffffff);1505else if (path == PPG_8723D_S0)1506val32 = rtw_hal_read_rfreg(adapter, target_path, 0x65, 0xffffffff);1507} else {1508val32 = rtw_hal_read_rfreg(adapter, target_path, 0x55, 0xffffffff);1509}1510RTW_INFO(" after :0x%x\n", val32);1511}15121513void rtw_rf_apply_tx_gain_offset(_adapter *adapter, u8 ch)1514{1515HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter);1516s8 kfree_offset = 0;1517s8 tx_pwr_track_offset = 0; /* TODO: 8814A should consider tx pwr track when setting tx gain offset */1518s8 total_offset;1519int i, total = 0;15201521if (IS_HARDWARE_TYPE_8723D(adapter))1522total = 2; /* S1 and S0 */1523else1524total = hal_data->NumTotalRFPath;15251526for (i = 0; i < total; i++) {1527kfree_offset = rtw_rf_get_kfree_tx_gain_offset(adapter, i, ch);1528total_offset = kfree_offset + tx_pwr_track_offset;1529rtw_rf_set_tx_gain_offset(adapter, i, total_offset);1530}1531}15321533inline u8 rtw_is_dfs_range(u32 hi, u32 lo)1534{1535return rtw_is_range_overlap(hi, lo, 5720 + 10, 5260 - 10);1536}15371538u8 rtw_is_dfs_ch(u8 ch)1539{1540u32 hi, lo;15411542if (!rtw_chbw_to_freq_range(ch, CHANNEL_WIDTH_20, HAL_PRIME_CHNL_OFFSET_DONT_CARE, &hi, &lo))1543return 0;15441545return rtw_is_dfs_range(hi, lo);1546}15471548u8 rtw_is_dfs_chbw(u8 ch, u8 bw, u8 offset)1549{1550u32 hi, lo;15511552if (!rtw_chbw_to_freq_range(ch, bw, offset, &hi, &lo))1553return 0;15541555return rtw_is_dfs_range(hi, lo);1556}15571558bool rtw_is_long_cac_range(u32 hi, u32 lo, u8 dfs_region)1559{1560return (dfs_region == PHYDM_DFS_DOMAIN_ETSI && rtw_is_range_overlap(hi, lo, 5650, 5600)) ? _TRUE : _FALSE;1561}15621563bool rtw_is_long_cac_ch(u8 ch, u8 bw, u8 offset, u8 dfs_region)1564{1565u32 hi, lo;15661567if (rtw_chbw_to_freq_range(ch, bw, offset, &hi, &lo) == _FALSE)1568return _FALSE;15691570return rtw_is_long_cac_range(hi, lo, dfs_region) ? _TRUE : _FALSE;1571}157215731574