729 lines
20 KiB
C
729 lines
20 KiB
C
/******************************************************************************
|
|
*
|
|
* Copyright(c) 2007 - 2022 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.
|
|
*
|
|
*****************************************************************************/
|
|
#define _HAL_PWR_TABLE_C_
|
|
|
|
#include <drv_types.h>
|
|
#include <hal_data.h>
|
|
|
|
#if CONFIG_TXPWR_LIMIT
|
|
const char *const _txpwr_lmt_rs_str[] = {
|
|
[TXPWR_LMT_RS_CCK] = "CCK",
|
|
[TXPWR_LMT_RS_OFDM] = "OFDM",
|
|
[TXPWR_LMT_RS_HT] = "HT",
|
|
[TXPWR_LMT_RS_VHT] = "VHT",
|
|
[TXPWR_LMT_RS_NUM] = "UNKNOWN",
|
|
};
|
|
|
|
void hal_txpwr_lmt_reg_exc_add_with_nlen(struct hal_com_data *hal_data, const char *country, u8 domain, const char *reg_name, u32 nlen)
|
|
{
|
|
struct txpwr_lmt_tb_t *tb = &hal_data->txpwr_lmt_tb;
|
|
struct lmt_reg_exc *ent;
|
|
|
|
if (!reg_name || !nlen) {
|
|
rtw_warn_on(1);
|
|
goto exit;
|
|
}
|
|
|
|
ent = rtw_zmalloc(sizeof(struct lmt_reg_exc) + nlen + 1);
|
|
if (!ent)
|
|
goto exit;
|
|
|
|
_rtw_init_listhead(&ent->list);
|
|
if (country)
|
|
_rtw_memcpy(ent->country, country, 2);
|
|
ent->domain = domain;
|
|
_rtw_memcpy(ent->reg_name, reg_name, nlen);
|
|
|
|
_rtw_mutex_lock_interruptible(&tb->lock);
|
|
|
|
rtw_list_insert_tail(&ent->list, &tb->reg_exc_list);
|
|
tb->reg_exc_num++;
|
|
|
|
_rtw_mutex_unlock(&tb->lock);
|
|
|
|
exit:
|
|
return;
|
|
}
|
|
|
|
void hal_txpwr_lmt_reg_exc_add(struct hal_com_data *hal_data, const char *country, u8 domain, const char *reg_name)
|
|
{
|
|
hal_txpwr_lmt_reg_exc_add_with_nlen(hal_data, country, domain, reg_name, strlen(reg_name));
|
|
}
|
|
|
|
static struct lmt_reg_exc *_hal_txpwr_lmt_reg_exc_search(struct hal_com_data *hal_data, const char *country, u8 domain)
|
|
{
|
|
struct txpwr_lmt_tb_t *tb = &hal_data->txpwr_lmt_tb;
|
|
struct lmt_reg_exc *ent;
|
|
_list *cur, *head;
|
|
u8 match = 0;
|
|
|
|
head = &tb->reg_exc_list;
|
|
cur = get_next(head);
|
|
|
|
while ((rtw_end_of_queue_search(head, cur)) == _FALSE) {
|
|
u8 has_country;
|
|
|
|
ent = LIST_CONTAINOR(cur, struct lmt_reg_exc, list);
|
|
cur = get_next(cur);
|
|
has_country = (ent->country[0] == '\0' && ent->country[1] == '\0') ? 0 : 1;
|
|
|
|
/* entry has country condition to match */
|
|
if (has_country) {
|
|
if (!country)
|
|
continue;
|
|
if (ent->country[0] != country[0]
|
|
|| ent->country[1] != country[1])
|
|
continue;
|
|
}
|
|
|
|
/* entry has domain condition to match */
|
|
if (ent->domain != 0xFF) {
|
|
if (domain == 0xFF)
|
|
continue;
|
|
if (ent->domain != domain)
|
|
continue;
|
|
}
|
|
|
|
match = 1;
|
|
break;
|
|
}
|
|
|
|
if (match)
|
|
return ent;
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
struct lmt_reg_exc *hal_txpwr_lmt_reg_exc_search(struct hal_com_data *hal_data, const char *country, u8 domain)
|
|
{
|
|
struct txpwr_lmt_tb_t *tb = &hal_data->txpwr_lmt_tb;
|
|
struct lmt_reg_exc *ent;
|
|
|
|
_rtw_mutex_lock_interruptible(&tb->lock);
|
|
ent = _hal_txpwr_lmt_reg_exc_search(hal_data, country, domain);
|
|
_rtw_mutex_unlock(&tb->lock);
|
|
|
|
return ent;
|
|
}
|
|
|
|
void hal_txpwr_lmt_reg_exc_list_free(struct hal_com_data *hal_data)
|
|
{
|
|
struct txpwr_lmt_tb_t *tb = &hal_data->txpwr_lmt_tb;
|
|
struct lmt_reg_exc *ent;
|
|
_list *cur, *head;
|
|
|
|
_rtw_mutex_lock_interruptible(&tb->lock);
|
|
|
|
head = &tb->reg_exc_list;
|
|
cur = get_next(head);
|
|
|
|
while ((rtw_end_of_queue_search(head, cur)) == _FALSE) {
|
|
ent = LIST_CONTAINOR(cur, struct lmt_reg_exc, list);
|
|
cur = get_next(cur);
|
|
rtw_list_delete(&ent->list);
|
|
rtw_mfree((u8 *)ent, sizeof(struct lmt_reg_exc) + strlen(ent->reg_name) + 1);
|
|
}
|
|
tb->reg_exc_num = 0;
|
|
|
|
_rtw_mutex_unlock(&tb->lock);
|
|
}
|
|
|
|
static void _dump_txpwr_lmt_reg_exc_list(void *sel, struct hal_com_data *hal_data)
|
|
{
|
|
struct txpwr_lmt_tb_t *tb = &hal_data->txpwr_lmt_tb;
|
|
struct lmt_reg_exc *ent;
|
|
_list *cur, *head;
|
|
|
|
RTW_PRINT_SEL(sel, "reg_exc_num:%u\n", tb->reg_exc_num);
|
|
|
|
if (!tb->reg_exc_num)
|
|
goto exit;
|
|
|
|
RTW_PRINT_SEL(sel, "%-7s %-6s %-8s\n", "country", "domain", "reg_name");
|
|
|
|
head = &tb->reg_exc_list;
|
|
cur = get_next(head);
|
|
|
|
while ((rtw_end_of_queue_search(head, cur)) == _FALSE) {
|
|
u8 has_country;
|
|
|
|
ent = LIST_CONTAINOR(cur, struct lmt_reg_exc, list);
|
|
cur = get_next(cur);
|
|
has_country = (ent->country[0] == '\0' && ent->country[1] == '\0') ? 0 : 1;
|
|
|
|
RTW_PRINT_SEL(sel, " %c%c 0x%02x %s\n"
|
|
, has_country ? ent->country[0] : '-'
|
|
, has_country ? ent->country[1] : '-'
|
|
, ent->domain
|
|
, ent->reg_name
|
|
);
|
|
}
|
|
|
|
exit:
|
|
return;
|
|
}
|
|
|
|
void dump_txpwr_lmt_reg_exc_list(void *sel, struct hal_com_data *hal_data)
|
|
{
|
|
struct txpwr_lmt_tb_t *tb = &hal_data->txpwr_lmt_tb;
|
|
|
|
_rtw_mutex_lock_interruptible(&tb->lock);
|
|
_dump_txpwr_lmt_reg_exc_list(sel, hal_data);
|
|
_rtw_mutex_unlock(&tb->lock);
|
|
}
|
|
|
|
/* search matcing first, if not found, alloc one */
|
|
void hal_txpwr_lmt_reg_add_with_nlen(struct hal_com_data *hal_data, const char *name, u32 nlen
|
|
, u8 band, u8 bw, u8 tlrs, u8 ntx_idx, u8 ch_idx, s8 lmt)
|
|
{
|
|
struct hal_spec_t *hal_spec = &hal_data->hal_spec;
|
|
struct txpwr_lmt_tb_t *tb = &hal_data->txpwr_lmt_tb;
|
|
struct lmt_reg *ent;
|
|
_list *cur, *head;
|
|
s8 pre_lmt;
|
|
u8 ch;
|
|
|
|
if (!name || !nlen) {
|
|
rtw_warn_on(1);
|
|
goto exit;
|
|
}
|
|
|
|
_rtw_mutex_lock_interruptible(&tb->lock);
|
|
|
|
/* search for existed entry */
|
|
head = &tb->reg_list;
|
|
cur = get_next(head);
|
|
while ((rtw_end_of_queue_search(head, cur)) == _FALSE) {
|
|
ent = LIST_CONTAINOR(cur, struct lmt_reg, list);
|
|
cur = get_next(cur);
|
|
|
|
if (strlen(ent->name) == nlen
|
|
&& _rtw_memcmp(ent->name, name, nlen) == _TRUE)
|
|
goto chk_lmt_val;
|
|
}
|
|
|
|
/* alloc new one */
|
|
ent = rtw_zvmalloc(sizeof(struct lmt_reg) + nlen + 1);
|
|
if (!ent)
|
|
goto release_lock;
|
|
|
|
_rtw_init_listhead(&ent->list);
|
|
_rtw_memcpy(ent->name, name, nlen);
|
|
{
|
|
u8 j, k, l, m;
|
|
|
|
for (j = 0; j < MAX_2_4G_BANDWIDTH_NUM; ++j)
|
|
for (k = 0; k < TXPWR_LMT_RS_NUM_2G; ++k)
|
|
for (m = 0; m < CENTER_CH_2G_NUM; ++m)
|
|
for (l = 0; l < MAX_TX_COUNT; ++l)
|
|
ent->lmt_2g[j][k][m][l] = hal_spec->txgi_max;
|
|
#if CONFIG_IEEE80211_BAND_5GHZ
|
|
for (j = 0; j < MAX_5G_BANDWIDTH_NUM; ++j)
|
|
for (k = 0; k < TXPWR_LMT_RS_NUM_5G; ++k)
|
|
for (m = 0; m < CENTER_CH_5G_ALL_NUM; ++m)
|
|
for (l = 0; l < MAX_TX_COUNT; ++l)
|
|
ent->lmt_5g[j][k][m][l] = hal_spec->txgi_max;
|
|
#endif
|
|
}
|
|
|
|
rtw_list_insert_tail(&ent->list, &tb->reg_list);
|
|
tb->reg_num++;
|
|
|
|
chk_lmt_val:
|
|
if (band == BAND_ON_2_4G) {
|
|
pre_lmt = ent->lmt_2g[bw][tlrs][ch_idx][ntx_idx];
|
|
ch = ch_idx + 1;
|
|
}
|
|
#if CONFIG_IEEE80211_BAND_5GHZ
|
|
else if (band == BAND_ON_5G) {
|
|
pre_lmt = ent->lmt_5g[bw][tlrs - 1][ch_idx][ntx_idx];
|
|
ch = center_ch_5g_all[ch_idx];
|
|
}
|
|
#endif
|
|
else
|
|
goto release_lock;
|
|
|
|
if (pre_lmt != hal_spec->txgi_max)
|
|
RTW_PRINT("duplicate txpwr_lmt for [%s][%s][%s][%s][%uT][%d]\n"
|
|
, name, band_str(band), ch_width_str(bw), txpwr_lmt_rs_str(tlrs), ntx_idx + 1, ch);
|
|
|
|
lmt = rtw_min(pre_lmt, lmt);
|
|
if (band == BAND_ON_2_4G)
|
|
ent->lmt_2g[bw][tlrs][ch_idx][ntx_idx] = lmt;
|
|
#if CONFIG_IEEE80211_BAND_5GHZ
|
|
else if (band == BAND_ON_5G)
|
|
ent->lmt_5g[bw][tlrs - 1][ch_idx][ntx_idx] = lmt;
|
|
#endif
|
|
|
|
if (0)
|
|
RTW_PRINT("%s, %4s, %6s, %7s, %uT, ch%3d = %d\n"
|
|
, name, band_str(band), ch_width_str(bw), txpwr_lmt_rs_str(tlrs), ntx_idx + 1
|
|
, ch, lmt);
|
|
|
|
release_lock:
|
|
_rtw_mutex_unlock(&tb->lock);
|
|
|
|
exit:
|
|
return;
|
|
}
|
|
|
|
void hal_txpwr_lmt_reg_add(struct hal_com_data *hal_data, const char *name
|
|
, u8 band, u8 bw, u8 tlrs, u8 ntx_idx, u8 ch_idx, s8 lmt)
|
|
{
|
|
hal_txpwr_lmt_reg_add_with_nlen(hal_data, name, strlen(name)
|
|
, band, bw, tlrs, ntx_idx, ch_idx, lmt);
|
|
}
|
|
|
|
struct lmt_reg *_hal_txpwr_lmt_reg_get_by_name(struct hal_com_data *hal_data, const char *name)
|
|
{
|
|
struct txpwr_lmt_tb_t *tb = &hal_data->txpwr_lmt_tb;
|
|
struct lmt_reg *ent;
|
|
_list *cur, *head;
|
|
u8 found = 0;
|
|
|
|
head = &tb->reg_list;
|
|
cur = get_next(head);
|
|
|
|
while ((rtw_end_of_queue_search(head, cur)) == _FALSE) {
|
|
ent = LIST_CONTAINOR(cur, struct lmt_reg, list);
|
|
cur = get_next(cur);
|
|
|
|
if (strcmp(ent->name, name) == 0) {
|
|
found = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (found)
|
|
return ent;
|
|
return NULL;
|
|
}
|
|
|
|
struct lmt_reg *hal_txpwr_lmt_reg_get_by_name(struct hal_com_data *hal_data, const char *name)
|
|
{
|
|
struct txpwr_lmt_tb_t *tb = &hal_data->txpwr_lmt_tb;
|
|
struct lmt_reg *ent;
|
|
|
|
_rtw_mutex_lock_interruptible(&tb->lock);
|
|
ent = _hal_txpwr_lmt_reg_get_by_name(hal_data, name);
|
|
_rtw_mutex_unlock(&tb->lock);
|
|
|
|
return ent;
|
|
}
|
|
|
|
static void hal_txpwr_clear_current_lmt_reg_names(struct hal_com_data *hal_data, enum band_type band)
|
|
{
|
|
struct txpwr_lmt_tb_t *tb = &hal_data->txpwr_lmt_tb;
|
|
|
|
if (band >= BAND_MAX)
|
|
return;
|
|
|
|
if (tb->cur_reg_names[band]) {
|
|
rtw_mfree(tb->cur_reg_names[band], tb->cur_reg_names_len[band]);
|
|
tb->cur_reg_names[band] = NULL;
|
|
}
|
|
tb->cur_reg_names_len[band] = 0;
|
|
}
|
|
|
|
static void hal_txpwr_clear_all_current_lmt_reg_names(struct hal_com_data *hal_data)
|
|
{
|
|
u8 band;
|
|
|
|
for (band = 0; band < BAND_MAX; band++)
|
|
hal_txpwr_clear_current_lmt_reg_names(hal_data, band);
|
|
}
|
|
|
|
void hal_txpwr_set_current_lmt_regs(struct hal_com_data *hal_data, enum band_type band, char *names, int names_len)
|
|
{
|
|
struct txpwr_lmt_tb_t *tb = &hal_data->txpwr_lmt_tb;
|
|
|
|
if (band >= BAND_MAX)
|
|
return;
|
|
|
|
_rtw_mutex_lock_interruptible(&tb->lock);
|
|
|
|
hal_txpwr_clear_current_lmt_reg_names(hal_data, band);
|
|
|
|
if (names && names_len) {
|
|
tb->cur_reg_names[band] = rtw_malloc(names_len);
|
|
if (tb->cur_reg_names[band]) {
|
|
_rtw_memcpy(tb->cur_reg_names[band], names, names_len);
|
|
tb->cur_reg_names_len[band] = names_len;
|
|
}
|
|
}
|
|
|
|
_rtw_mutex_unlock(&tb->lock);
|
|
}
|
|
|
|
void hal_txpwr_get_current_lmt_regs(struct hal_com_data *hal_data, enum band_type band, char **names, int *names_len)
|
|
{
|
|
struct txpwr_lmt_tb_t *tb = &hal_data->txpwr_lmt_tb;
|
|
|
|
if (!names || !names_len)
|
|
return;
|
|
|
|
*names = NULL;
|
|
*names_len = 0;
|
|
|
|
if (band >= BAND_MAX)
|
|
return;
|
|
|
|
_rtw_mutex_lock_interruptible(&tb->lock);
|
|
|
|
if (tb->cur_reg_names[band] && tb->cur_reg_names_len[band]) {
|
|
*names = rtw_malloc(tb->cur_reg_names_len[band]);
|
|
if (*names) {
|
|
_rtw_memcpy(*names, tb->cur_reg_names[band], tb->cur_reg_names_len[band]);
|
|
*names_len = tb->cur_reg_names_len[band];
|
|
}
|
|
}
|
|
|
|
_rtw_mutex_unlock(&tb->lock);
|
|
}
|
|
|
|
bool hal_txpwr_is_current_lmt_reg(struct hal_com_data *hal_data, const char *name)
|
|
{
|
|
struct txpwr_lmt_tb_t *tb = &hal_data->txpwr_lmt_tb;
|
|
int band;
|
|
const char *reg_names, *pos;
|
|
int reg_names_len;
|
|
|
|
for (band = 0; band < BAND_MAX; band++) {
|
|
reg_names = tb->cur_reg_names[band];
|
|
reg_names_len = tb->cur_reg_names_len[band];
|
|
if (!reg_names)
|
|
continue;
|
|
ustrs_for_each_str(reg_names, reg_names_len, pos) {
|
|
if (strcmp(name, pos) == 0)
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void hal_txpwr_lmt_reg_list_free(struct hal_com_data *hal_data)
|
|
{
|
|
struct txpwr_lmt_tb_t *tb = &hal_data->txpwr_lmt_tb;
|
|
struct lmt_reg *ent;
|
|
_list *cur, *head;
|
|
|
|
_rtw_mutex_lock_interruptible(&tb->lock);
|
|
|
|
head = &tb->reg_list;
|
|
cur = get_next(head);
|
|
|
|
while ((rtw_end_of_queue_search(head, cur)) == _FALSE) {
|
|
ent = LIST_CONTAINOR(cur, struct lmt_reg, list);
|
|
cur = get_next(cur);
|
|
rtw_list_delete(&ent->list);
|
|
rtw_vmfree((u8 *)ent, sizeof(struct lmt_reg) + strlen(ent->name) + 1);
|
|
}
|
|
tb->reg_num = 0;
|
|
|
|
hal_txpwr_clear_all_current_lmt_reg_names(hal_data);
|
|
|
|
_rtw_mutex_unlock(&tb->lock);
|
|
}
|
|
|
|
void hal_txpwr_lmt_tb_init(struct hal_com_data *hal_data)
|
|
{
|
|
struct txpwr_lmt_tb_t *tb = &hal_data->txpwr_lmt_tb;
|
|
|
|
_rtw_mutex_init(&tb->lock);
|
|
_rtw_init_listhead(&tb->reg_exc_list);
|
|
_rtw_init_listhead(&tb->reg_list);
|
|
}
|
|
|
|
void hal_txpwr_lmt_tb_deinit(struct hal_com_data *hal_data)
|
|
{
|
|
struct txpwr_lmt_tb_t *tb = &hal_data->txpwr_lmt_tb;
|
|
|
|
hal_txpwr_lmt_reg_exc_list_free(hal_data);
|
|
hal_txpwr_lmt_reg_list_free(hal_data);
|
|
_rtw_mutex_free(&tb->lock);
|
|
}
|
|
|
|
void dump_txpwr_lmt(void *sel, _adapter *adapter)
|
|
{
|
|
#define TMP_STR_LEN 16
|
|
struct hal_com_data *hal_data = GET_HAL_DATA(adapter);
|
|
struct hal_spec_t *hal_spec = GET_HAL_SPEC(adapter);
|
|
struct txpwr_lmt_tb_t *tb = &hal_data->txpwr_lmt_tb;
|
|
char fmt[16];
|
|
char tmp_str[TMP_STR_LEN];
|
|
s8 *lmt_idx = NULL;
|
|
int bw, band, ch_num, tlrs, ntx_idx, rs, i, path;
|
|
u8 ch, n, rfpath_num;
|
|
|
|
_rtw_mutex_lock_interruptible(&tb->lock);
|
|
|
|
_dump_txpwr_lmt_reg_exc_list(sel, hal_data);
|
|
RTW_PRINT_SEL(sel, "\n");
|
|
|
|
if (!tb->reg_num)
|
|
goto release_lock;
|
|
|
|
lmt_idx = rtw_malloc(sizeof(s8) * RF_PATH_MAX * tb->reg_num);
|
|
if (!lmt_idx) {
|
|
RTW_ERR("%s alloc fail\n", __func__);
|
|
goto release_lock;
|
|
}
|
|
|
|
RTW_PRINT_SEL(sel, "lmt_2g_cck_ofdm_state:0x%02x\n", tb->lmt_2g_cck_ofdm_state);
|
|
#if CONFIG_IEEE80211_BAND_5GHZ
|
|
if (IS_HARDWARE_TYPE_JAGUAR_ALL(adapter)) {
|
|
RTW_PRINT_SEL(sel, "lmt_5g_cck_ofdm_state:0x%02x\n", tb->lmt_5g_cck_ofdm_state);
|
|
RTW_PRINT_SEL(sel, "lmt_5g_20_40_ref:0x%02x\n", tb->lmt_5g_20_40_ref);
|
|
}
|
|
#endif
|
|
RTW_PRINT_SEL(sel, "\n");
|
|
|
|
for (band = BAND_ON_2_4G; band <= BAND_ON_5G; band++) {
|
|
if (!hal_is_band_support(adapter, band))
|
|
continue;
|
|
|
|
rfpath_num = (band == BAND_ON_2_4G ? hal_spec->rfpath_num_2g : hal_spec->rfpath_num_5g);
|
|
|
|
for (bw = 0; bw < MAX_5G_BANDWIDTH_NUM; bw++) {
|
|
|
|
if (bw >= CHANNEL_WIDTH_160)
|
|
break;
|
|
if (band == BAND_ON_2_4G && bw >= CHANNEL_WIDTH_80)
|
|
break;
|
|
|
|
if (band == BAND_ON_2_4G)
|
|
ch_num = CENTER_CH_2G_NUM;
|
|
#if CONFIG_IEEE80211_BAND_5GHZ
|
|
else if (band == BAND_ON_5G)
|
|
ch_num = center_chs_5g_num(bw);
|
|
#endif
|
|
else
|
|
ch_num = 0;
|
|
|
|
if (ch_num == 0) {
|
|
rtw_warn_on(1);
|
|
break;
|
|
}
|
|
|
|
for (tlrs = TXPWR_LMT_RS_CCK; tlrs < TXPWR_LMT_RS_NUM; tlrs++) {
|
|
|
|
if (band == BAND_ON_2_4G && tlrs == TXPWR_LMT_RS_VHT)
|
|
continue;
|
|
if (band == BAND_ON_5G && tlrs == TXPWR_LMT_RS_CCK)
|
|
continue;
|
|
if (bw > CHANNEL_WIDTH_20 && (tlrs == TXPWR_LMT_RS_CCK || tlrs == TXPWR_LMT_RS_OFDM))
|
|
continue;
|
|
if (bw > CHANNEL_WIDTH_40 && tlrs == TXPWR_LMT_RS_HT)
|
|
continue;
|
|
if (tlrs == TXPWR_LMT_RS_VHT && !IS_HARDWARE_TYPE_JAGUAR_ALL(adapter))
|
|
continue;
|
|
|
|
for (ntx_idx = RF_1TX; ntx_idx < MAX_TX_COUNT; ntx_idx++) {
|
|
struct lmt_reg *ent;
|
|
_list *cur, *head;
|
|
|
|
if (ntx_idx + 1 > hal_data->max_tx_cnt)
|
|
continue;
|
|
|
|
/* bypass CCK multi-TX is not defined */
|
|
if (tlrs == TXPWR_LMT_RS_CCK && ntx_idx > RF_1TX) {
|
|
if (band == BAND_ON_2_4G
|
|
&& !(tb->lmt_2g_cck_ofdm_state & (TXPWR_LMT_HAS_CCK_1T << ntx_idx)))
|
|
continue;
|
|
}
|
|
|
|
/* bypass OFDM multi-TX is not defined */
|
|
if (tlrs == TXPWR_LMT_RS_OFDM && ntx_idx > RF_1TX) {
|
|
if (band == BAND_ON_2_4G
|
|
&& !(tb->lmt_2g_cck_ofdm_state & (TXPWR_LMT_HAS_OFDM_1T << ntx_idx)))
|
|
continue;
|
|
#if CONFIG_IEEE80211_BAND_5GHZ
|
|
if (band == BAND_ON_5G
|
|
&& !(tb->lmt_5g_cck_ofdm_state & (TXPWR_LMT_HAS_OFDM_1T << ntx_idx)))
|
|
continue;
|
|
#endif
|
|
}
|
|
|
|
/* bypass 5G 20M, 40M pure reference */
|
|
#if CONFIG_IEEE80211_BAND_5GHZ
|
|
if (band == BAND_ON_5G && (bw == CHANNEL_WIDTH_20 || bw == CHANNEL_WIDTH_40)) {
|
|
if (tb->lmt_5g_20_40_ref == TXPWR_LMT_REF_HT_FROM_VHT) {
|
|
if (tlrs == TXPWR_LMT_RS_HT)
|
|
continue;
|
|
} else if (tb->lmt_5g_20_40_ref == TXPWR_LMT_REF_VHT_FROM_HT) {
|
|
if (tlrs == TXPWR_LMT_RS_VHT && bw <= CHANNEL_WIDTH_40)
|
|
continue;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/* choose n-SS mapping rate section to get lmt diff value */
|
|
if (tlrs == TXPWR_LMT_RS_CCK)
|
|
rs = CCK;
|
|
else if (tlrs == TXPWR_LMT_RS_OFDM)
|
|
rs = OFDM;
|
|
else if (tlrs == TXPWR_LMT_RS_HT)
|
|
rs = HT_1SS + ntx_idx;
|
|
else if (tlrs == TXPWR_LMT_RS_VHT)
|
|
rs = VHT_1SS + ntx_idx;
|
|
else {
|
|
RTW_ERR("%s invalid tlrs %u\n", __func__, tlrs);
|
|
continue;
|
|
}
|
|
|
|
RTW_PRINT_SEL(sel, "[%s][%s][%s][%uT]\n"
|
|
, band_str(band)
|
|
, ch_width_str(bw)
|
|
, txpwr_lmt_rs_str(tlrs)
|
|
, ntx_idx + 1
|
|
);
|
|
|
|
/* header for limit in db */
|
|
RTW_PRINT_SEL(sel, "%3s ", "ch");
|
|
|
|
head = &tb->reg_list;
|
|
cur = get_next(head);
|
|
while ((rtw_end_of_queue_search(head, cur)) == _FALSE) {
|
|
ent = LIST_CONTAINOR(cur, struct lmt_reg, list);
|
|
cur = get_next(cur);
|
|
|
|
sprintf(fmt, "%%%zus%%s ", strlen(ent->name) >= 6 ? 1 : 6 - strlen(ent->name));
|
|
snprintf(tmp_str, TMP_STR_LEN, fmt
|
|
, hal_txpwr_is_current_lmt_reg(hal_data, ent->name) ? "*" : ""
|
|
, ent->name);
|
|
_RTW_PRINT_SEL(sel, "%s", tmp_str);
|
|
}
|
|
sprintf(fmt, "%%%zus%%s ", strlen(txpwr_lmt_str(TXPWR_LMT_WW)) >= 6 ? 1 : 6 - strlen(txpwr_lmt_str(TXPWR_LMT_WW)));
|
|
snprintf(tmp_str, TMP_STR_LEN, fmt
|
|
, hal_txpwr_is_current_lmt_reg(hal_data, txpwr_lmt_str(TXPWR_LMT_WW)) ? "*" : ""
|
|
, txpwr_lmt_str(TXPWR_LMT_WW));
|
|
_RTW_PRINT_SEL(sel, "%s", tmp_str);
|
|
|
|
/* header for limit offset */
|
|
for (path = 0; path < RF_PATH_MAX; path++) {
|
|
if (path >= rfpath_num)
|
|
break;
|
|
_RTW_PRINT_SEL(sel, "|");
|
|
head = &tb->reg_list;
|
|
cur = get_next(head);
|
|
while ((rtw_end_of_queue_search(head, cur)) == _FALSE) {
|
|
ent = LIST_CONTAINOR(cur, struct lmt_reg, list);
|
|
cur = get_next(cur);
|
|
_RTW_PRINT_SEL(sel, "%3c "
|
|
, hal_txpwr_is_current_lmt_reg(hal_data, ent->name) ? rf_path_char(path) : ' ');
|
|
}
|
|
_RTW_PRINT_SEL(sel, "%3c "
|
|
, hal_txpwr_is_current_lmt_reg(hal_data, txpwr_lmt_str(TXPWR_LMT_WW)) ? rf_path_char(path) : ' ');
|
|
}
|
|
_RTW_PRINT_SEL(sel, "\n");
|
|
|
|
for (n = 0; n < ch_num; n++) {
|
|
s8 lmt;
|
|
s8 lmt_offset;
|
|
u8 base;
|
|
|
|
if (band == BAND_ON_2_4G)
|
|
ch = n + 1;
|
|
#if CONFIG_IEEE80211_BAND_5GHZ
|
|
else if (band == BAND_ON_5G)
|
|
ch = center_chs_5g(bw, n);
|
|
#endif
|
|
else
|
|
ch = 0;
|
|
|
|
if (ch == 0) {
|
|
rtw_warn_on(1);
|
|
break;
|
|
}
|
|
|
|
/* dump limit in dBm */
|
|
RTW_PRINT_SEL(sel, "%3u ", ch);
|
|
head = &tb->reg_list;
|
|
cur = get_next(head);
|
|
while ((rtw_end_of_queue_search(head, cur)) == _FALSE) {
|
|
ent = LIST_CONTAINOR(cur, struct lmt_reg, list);
|
|
cur = get_next(cur);
|
|
lmt = phy_get_txpwr_lmt(adapter, ent->name, band, bw, tlrs, ntx_idx, ch, 0);
|
|
txpwr_idx_get_dbm_str(lmt, hal_spec->txgi_max, hal_spec->txgi_pdbm, strlen(ent->name), tmp_str, TMP_STR_LEN);
|
|
_RTW_PRINT_SEL(sel, "%s ", tmp_str);
|
|
}
|
|
lmt = phy_get_txpwr_lmt(adapter, txpwr_lmt_str(TXPWR_LMT_WW), band, bw, tlrs, ntx_idx, ch, 0);
|
|
txpwr_idx_get_dbm_str(lmt, hal_spec->txgi_max, hal_spec->txgi_pdbm, strlen(txpwr_lmt_str(TXPWR_LMT_WW)), tmp_str, TMP_STR_LEN);
|
|
_RTW_PRINT_SEL(sel, "%s ", tmp_str);
|
|
|
|
/* dump limit offset of each path */
|
|
for (path = RF_PATH_A; path < RF_PATH_MAX; path++) {
|
|
if (path >= rfpath_num)
|
|
break;
|
|
|
|
base = phy_get_target_txpwr(adapter, band, path, rs);
|
|
|
|
_RTW_PRINT_SEL(sel, "|");
|
|
head = &tb->reg_list;
|
|
cur = get_next(head);
|
|
i = 0;
|
|
while ((rtw_end_of_queue_search(head, cur)) == _FALSE) {
|
|
ent = LIST_CONTAINOR(cur, struct lmt_reg, list);
|
|
cur = get_next(cur);
|
|
lmt_offset = phy_get_txpwr_lmt_diff(adapter, ent->name, band, bw, path, rs, tlrs, ntx_idx, ch, 0);
|
|
if (lmt_offset == hal_spec->txgi_max) {
|
|
*(lmt_idx + i * RF_PATH_MAX + path) = hal_spec->txgi_max;
|
|
_RTW_PRINT_SEL(sel, "%3s ", "NA");
|
|
} else {
|
|
*(lmt_idx + i * RF_PATH_MAX + path) = lmt_offset + base;
|
|
_RTW_PRINT_SEL(sel, "%3d ", lmt_offset);
|
|
}
|
|
i++;
|
|
}
|
|
lmt_offset = phy_get_txpwr_lmt_diff(adapter, txpwr_lmt_str(TXPWR_LMT_WW), band, bw, path, rs, tlrs, ntx_idx, ch, 0);
|
|
if (lmt_offset == hal_spec->txgi_max)
|
|
_RTW_PRINT_SEL(sel, "%3s ", "NA");
|
|
else
|
|
_RTW_PRINT_SEL(sel, "%3d ", lmt_offset);
|
|
|
|
}
|
|
|
|
/* compare limit_idx of each path, print 'x' when mismatch */
|
|
if (rfpath_num > 1) {
|
|
for (i = 0; i < tb->reg_num; i++) {
|
|
for (path = 0; path < RF_PATH_MAX; path++) {
|
|
if (path >= rfpath_num)
|
|
break;
|
|
if (*(lmt_idx + i * RF_PATH_MAX + path) != *(lmt_idx + i * RF_PATH_MAX + ((path + 1) % rfpath_num)))
|
|
break;
|
|
}
|
|
if (path >= rfpath_num)
|
|
_RTW_PRINT_SEL(sel, " ");
|
|
else
|
|
_RTW_PRINT_SEL(sel, "x");
|
|
}
|
|
}
|
|
_RTW_PRINT_SEL(sel, "\n");
|
|
|
|
}
|
|
RTW_PRINT_SEL(sel, "\n");
|
|
}
|
|
} /* loop for rate sections */
|
|
} /* loop for bandwidths */
|
|
} /* loop for bands */
|
|
|
|
if (lmt_idx)
|
|
rtw_mfree(lmt_idx, sizeof(s8) * RF_PATH_MAX * tb->reg_num);
|
|
|
|
release_lock:
|
|
_rtw_mutex_unlock(&tb->lock);
|
|
}
|
|
#endif /* CONFIG_TXPWR_LIMIT */ |