android13/external/wifi_driver/rtl8852be/phl/phl_scan_instance.c

320 lines
7.9 KiB
C

/******************************************************************************
*
* Copyright(c) 2020 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.
*
*****************************************************************************/
#include "phl_headers.h"
#include "phl_scan_instance.h"
#include "phl_scan.h"
#include "phl_regulation.h"
enum {
ACTIVE_PERIOD_MIN = 40,
ACTIVE_PERIOD_DEFAULT = 60,
ACTIVE_PERIOD_MAX = 80
};
enum {
PASSIVE_PERIOD_MIN = 50,
PASSIVE_PERIOD_DEFAULT = 80,
PASSIVE_PERIOD_MAX = 110
};
struct rtw_pickup_channel {
enum band_type band;
u8 channel;
u8 property;
u8 picked;
};
struct rtw_pickup_chplan_group {
u32 cnt;
struct rtw_pickup_channel ch[MAX_CH_NUM_GROUP];
};
static void _set_inst_ch(enum period_strategy strategy,
struct instance_channel *dest,
enum band_type band,
u8 channel, u8 property)
{
u8 max_t[2] = {PASSIVE_PERIOD_MAX, ACTIVE_PERIOD_MAX};
u8 min_t[2] = {PASSIVE_PERIOD_MIN, ACTIVE_PERIOD_MIN};
u8 def_t[2] = {PASSIVE_PERIOD_DEFAULT, ACTIVE_PERIOD_DEFAULT};
dest->band = band;
dest->channel = channel;
dest->property = property;
dest->mode = NORMAL_SCAN_MODE;
dest->bw = CHANNEL_WIDTH_20;
dest->offset = CHAN_OFFSET_NO_EXT;
/* active or passive */
if ((dest->property & CH_PASSIVE) ||
(dest->property & CH_DFS))
dest->active = 0;
else
dest->active = 1;
if (strategy & PERIOD_ALL_MAX)
dest->period = max_t[dest->active];
else if (strategy & PERIOD_ALL_MIN)
dest->period = min_t[dest->active];
else {
if ((strategy & PERIOD_MIN_DFS) &&
(dest->property & CH_DFS))
dest->period = min_t[dest->active];
else
dest->period = def_t[dest->active];
}
PHL_INFO("[REGU], pick channel %d, active=%d, period=%d\n",
dest->channel, dest->active, dest->period);
}
static void _pick_active_channels(struct rtw_pickup_chplan_group *group,
struct instance_strategy *strategy,
struct instance *inst)
{
struct instance_channel *dest = NULL;
struct rtw_pickup_channel *src = NULL;
u32 i = 0;
dest = &inst->ch[inst->cnt];
for (i = 0; i < group->cnt; i++) {
src = &group->ch[i];
if (src->picked)
continue;
if (!(src->property & CH_PASSIVE) &&
!(src->property & CH_DFS) ) {
_set_inst_ch(strategy->period, dest,
src->band,
src->channel,
src->property);
inst->cnt++;
dest++;
src->picked = 1;
}
}
}
static void _pick_the_rest_channels(struct rtw_pickup_chplan_group *group,
struct instance_strategy *strategy,
struct instance *inst)
{
struct instance_channel *dest = NULL;
struct rtw_pickup_channel *src = NULL;
u32 i = 0;
dest = &inst->ch[inst->cnt];
for (i = 0; i < group->cnt; i++) {
src = &group->ch[i];
if (!src->picked) {
_set_inst_ch(strategy->period, dest,
src->band,
src->channel,
src->property);
inst->cnt++;
dest++;
src->picked = 1;
}
}
}
static void _pick_5ghz_channels(struct rtw_pickup_chplan_group *group,
struct instance_strategy *strategy,
struct instance *inst)
{
u8 order = strategy->order;
u8 i = 0;
if (order & ORDER_ACTIVE_PRIOR) {
for (i = FREQ_GROUP_5GHZ_BAND1;
i <= FREQ_GROUP_5GHZ_BAND4; i++) {
_pick_active_channels(&group[i], strategy, inst);
}
}
for (i = FREQ_GROUP_5GHZ_BAND1;
i <= FREQ_GROUP_5GHZ_BAND4; i++) {
_pick_the_rest_channels(&group[i], strategy, inst);
}
}
static void _pick_2ghz_channels(struct rtw_pickup_chplan_group *group,
struct instance_strategy *strategy,
struct instance *inst)
{
u8 order = strategy->order;
if (order & ORDER_ACTIVE_PRIOR)
_pick_active_channels(&group[FREQ_GROUP_2GHZ],
strategy, inst);
_pick_the_rest_channels(&group[FREQ_GROUP_2GHZ],
strategy, inst);
}
static void _pick_6ghz_channels(struct rtw_pickup_chplan_group *group,
struct instance_strategy *strategy,
struct instance *inst)
{
_pick_the_rest_channels(&group[FREQ_GROUP_6GHZ_PSC],
strategy, inst);
}
static void _generate_instance(
struct rtw_pickup_chplan_group *group,
struct instance_strategy *strategy,
struct instance *inst)
{
u8 order = strategy->order;
inst->cnt = 0;
if (order & ORDER_5GHZ_PRIOR) {
_pick_5ghz_channels(group, strategy, inst);
_pick_2ghz_channels(group, strategy, inst);
} else {
_pick_2ghz_channels(group, strategy, inst);
_pick_5ghz_channels(group, strategy, inst);
}
_pick_6ghz_channels(group, strategy, inst);
}
static void _select_channels_by_group(struct instance_strategy *strategy,
struct rtw_regulation_chplan *plan,
struct rtw_pickup_chplan_group *group)
{
u8 skip = strategy->skip;
u8 chnl = 0, property = 0, gpidx = 0, keep = 0;
enum band_type band = BAND_ON_24G;
u32 i = 0;
for (i = 0; i < plan->cnt; i++) {
band = plan->ch[i].band;
chnl = plan->ch[i].channel;
property = plan->ch[i].property;
keep = 0;
/* skip passive channels */
if ((skip & SKIP_PASSIVE) && (property & CH_PASSIVE))
continue;
/* skip DFS channels */
if ((skip & SKIP_DFS) && (property & CH_DFS))
continue;
if ((BAND_2GHZ(band)) && !(skip & SKIP_2GHZ)) {
gpidx = FREQ_GROUP_2GHZ;
keep = 1;
} else if ((BAND_5GHZ(band)) && !(skip & SKIP_5GHZ)) {
if (CH_5GHZ_BAND1(chnl))
gpidx = FREQ_GROUP_5GHZ_BAND1;
else if (CH_5GHZ_BAND2(chnl))
gpidx = FREQ_GROUP_5GHZ_BAND2;
else if (CH_5GHZ_BAND3(chnl))
gpidx = FREQ_GROUP_5GHZ_BAND3;
else if (CH_5GHZ_BAND4(chnl))
gpidx = FREQ_GROUP_5GHZ_BAND4;
else
continue;
keep = 1;
} else if ((BAND_6GHZ(band)) && !(skip & SKIP_6GHZ)) {
gpidx = FREQ_GROUP_6GHZ_PSC;
keep = 1;
}
if (keep) {
group[gpidx].ch[group[gpidx].cnt].band = band;
group[gpidx].ch[group[gpidx].cnt].channel = chnl;
group[gpidx].ch[group[gpidx].cnt].property = property;
group[gpidx].ch[group[gpidx].cnt].picked = 0;
group[gpidx].cnt++;
PHL_INFO("[REGU], keep group-%d channel %d, cnt=%d\n",
gpidx, chnl, group[gpidx].cnt);
}
}
}
bool rtw_phl_generate_scan_instance(struct instance_strategy *strategy,
struct rtw_regulation_chplan *chplan,
struct instance *inst)
{
struct rtw_pickup_chplan_group group[FREQ_GROUP_MAX] = {0};
u32 i = 0;
if (!strategy || !inst || !chplan)
return false;
PHL_INFO("[REGU], Generate Scan Instance, strategy [skip=0x%x, order=0x%x, period=0x%x] \n",
strategy->skip, strategy->order, strategy->period);
PHL_INFO("[REGU], Channel Plan Source : \n");
for (i = 0; i < chplan->cnt; i++) {
PHL_INFO("[REGU], %d. band=%d, ch=%d, dfs=%d, passive=%d (property=0x%x)\n",
i + 1, chplan->ch[i].band, chplan->ch[i].channel,
((chplan->ch[i].property & CH_DFS) ? 1 : 0),
((chplan->ch[i].property & CH_PASSIVE) ? 1 : 0),
chplan->ch[i].property);
}
/* step1 : remove "skip channels" and select channels into groups */
_select_channels_by_group(strategy, chplan, group);
/* step2 : generate instance by strategy */
_generate_instance(group, strategy, inst);
PHL_INFO("[REGU], Output Scan Instance : \n");
for (i = 0; i < inst->cnt; i++) {
PHL_INFO("[REGU], %d. band=%d, ch=%d, active=%d, period=%d \n",
i + 1, inst->ch[i].band,
inst->ch[i].channel,
inst->ch[i].active,
inst->ch[i].period);
}
return true;
}
bool rtw_phl_scan_instance_insert_ch(void *phl, struct instance *inst,
enum band_type band, u8 channel,
u8 strategy_period)
{
struct rtw_regulation_channel ch = {0};
struct instance_channel *dest = NULL;
if (!phl || !inst)
return false;
if (inst->cnt >= MAX_SCAN_INSTANCE)
return false;
if (rtw_phl_regulation_query_ch(phl, band, channel, &ch)) {
dest = &inst->ch[inst->cnt];
_set_inst_ch(strategy_period, dest,
ch.band, ch.channel, ch.property);
inst->cnt++;
return true;
}
return false;
}