1*4882a593Smuzhiyun /******************************************************************************
2*4882a593Smuzhiyun *
3*4882a593Smuzhiyun * Copyright(c) 2020 Realtek Corporation.
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * This program is free software; you can redistribute it and/or modify it
6*4882a593Smuzhiyun * under the terms of version 2 of the GNU General Public License as
7*4882a593Smuzhiyun * published by the Free Software Foundation.
8*4882a593Smuzhiyun *
9*4882a593Smuzhiyun * This program is distributed in the hope that it will be useful, but WITHOUT
10*4882a593Smuzhiyun * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11*4882a593Smuzhiyun * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12*4882a593Smuzhiyun * more details.
13*4882a593Smuzhiyun *
14*4882a593Smuzhiyun *****************************************************************************/
15*4882a593Smuzhiyun #include "phl_headers.h"
16*4882a593Smuzhiyun #include "phl_scan_instance.h"
17*4882a593Smuzhiyun #include "phl_scan.h"
18*4882a593Smuzhiyun #include "phl_regulation.h"
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun enum {
21*4882a593Smuzhiyun ACTIVE_PERIOD_MIN = 40,
22*4882a593Smuzhiyun ACTIVE_PERIOD_DEFAULT = 60,
23*4882a593Smuzhiyun ACTIVE_PERIOD_MAX = 80
24*4882a593Smuzhiyun };
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun enum {
27*4882a593Smuzhiyun PASSIVE_PERIOD_MIN = 50,
28*4882a593Smuzhiyun PASSIVE_PERIOD_DEFAULT = 80,
29*4882a593Smuzhiyun PASSIVE_PERIOD_MAX = 110
30*4882a593Smuzhiyun };
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun struct rtw_pickup_channel {
33*4882a593Smuzhiyun enum band_type band;
34*4882a593Smuzhiyun u8 channel;
35*4882a593Smuzhiyun u8 property;
36*4882a593Smuzhiyun u8 picked;
37*4882a593Smuzhiyun };
38*4882a593Smuzhiyun
39*4882a593Smuzhiyun struct rtw_pickup_chplan_group {
40*4882a593Smuzhiyun u32 cnt;
41*4882a593Smuzhiyun struct rtw_pickup_channel ch[MAX_CH_NUM_GROUP];
42*4882a593Smuzhiyun };
43*4882a593Smuzhiyun
_set_inst_ch(enum period_strategy strategy,struct instance_channel * dest,enum band_type band,u8 channel,u8 property)44*4882a593Smuzhiyun static void _set_inst_ch(enum period_strategy strategy,
45*4882a593Smuzhiyun struct instance_channel *dest,
46*4882a593Smuzhiyun enum band_type band,
47*4882a593Smuzhiyun u8 channel, u8 property)
48*4882a593Smuzhiyun {
49*4882a593Smuzhiyun u8 max_t[2] = {PASSIVE_PERIOD_MAX, ACTIVE_PERIOD_MAX};
50*4882a593Smuzhiyun u8 min_t[2] = {PASSIVE_PERIOD_MIN, ACTIVE_PERIOD_MIN};
51*4882a593Smuzhiyun u8 def_t[2] = {PASSIVE_PERIOD_DEFAULT, ACTIVE_PERIOD_DEFAULT};
52*4882a593Smuzhiyun
53*4882a593Smuzhiyun dest->band = band;
54*4882a593Smuzhiyun dest->channel = channel;
55*4882a593Smuzhiyun dest->property = property;
56*4882a593Smuzhiyun dest->mode = NORMAL_SCAN_MODE;
57*4882a593Smuzhiyun dest->bw = CHANNEL_WIDTH_20;
58*4882a593Smuzhiyun dest->offset = CHAN_OFFSET_NO_EXT;
59*4882a593Smuzhiyun
60*4882a593Smuzhiyun /* active or passive */
61*4882a593Smuzhiyun if ((dest->property & CH_PASSIVE) ||
62*4882a593Smuzhiyun (dest->property & CH_DFS))
63*4882a593Smuzhiyun dest->active = 0;
64*4882a593Smuzhiyun else
65*4882a593Smuzhiyun dest->active = 1;
66*4882a593Smuzhiyun
67*4882a593Smuzhiyun if (strategy & PERIOD_ALL_MAX)
68*4882a593Smuzhiyun dest->period = max_t[dest->active];
69*4882a593Smuzhiyun else if (strategy & PERIOD_ALL_MIN)
70*4882a593Smuzhiyun dest->period = min_t[dest->active];
71*4882a593Smuzhiyun else {
72*4882a593Smuzhiyun if ((strategy & PERIOD_MIN_DFS) &&
73*4882a593Smuzhiyun (dest->property & CH_DFS))
74*4882a593Smuzhiyun dest->period = min_t[dest->active];
75*4882a593Smuzhiyun else
76*4882a593Smuzhiyun dest->period = def_t[dest->active];
77*4882a593Smuzhiyun }
78*4882a593Smuzhiyun
79*4882a593Smuzhiyun PHL_INFO("[REGU], pick channel %d, active=%d, period=%d\n",
80*4882a593Smuzhiyun dest->channel, dest->active, dest->period);
81*4882a593Smuzhiyun }
82*4882a593Smuzhiyun
_pick_active_channels(struct rtw_pickup_chplan_group * group,struct instance_strategy * strategy,struct instance * inst)83*4882a593Smuzhiyun static void _pick_active_channels(struct rtw_pickup_chplan_group *group,
84*4882a593Smuzhiyun struct instance_strategy *strategy,
85*4882a593Smuzhiyun struct instance *inst)
86*4882a593Smuzhiyun {
87*4882a593Smuzhiyun struct instance_channel *dest = NULL;
88*4882a593Smuzhiyun struct rtw_pickup_channel *src = NULL;
89*4882a593Smuzhiyun u32 i = 0;
90*4882a593Smuzhiyun
91*4882a593Smuzhiyun dest = &inst->ch[inst->cnt];
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun for (i = 0; i < group->cnt; i++) {
94*4882a593Smuzhiyun src = &group->ch[i];
95*4882a593Smuzhiyun
96*4882a593Smuzhiyun if (src->picked)
97*4882a593Smuzhiyun continue;
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun if (!(src->property & CH_PASSIVE) &&
100*4882a593Smuzhiyun !(src->property & CH_DFS) ) {
101*4882a593Smuzhiyun _set_inst_ch(strategy->period, dest,
102*4882a593Smuzhiyun src->band,
103*4882a593Smuzhiyun src->channel,
104*4882a593Smuzhiyun src->property);
105*4882a593Smuzhiyun inst->cnt++;
106*4882a593Smuzhiyun dest++;
107*4882a593Smuzhiyun src->picked = 1;
108*4882a593Smuzhiyun }
109*4882a593Smuzhiyun }
110*4882a593Smuzhiyun }
111*4882a593Smuzhiyun
_pick_the_rest_channels(struct rtw_pickup_chplan_group * group,struct instance_strategy * strategy,struct instance * inst)112*4882a593Smuzhiyun static void _pick_the_rest_channels(struct rtw_pickup_chplan_group *group,
113*4882a593Smuzhiyun struct instance_strategy *strategy,
114*4882a593Smuzhiyun struct instance *inst)
115*4882a593Smuzhiyun {
116*4882a593Smuzhiyun struct instance_channel *dest = NULL;
117*4882a593Smuzhiyun struct rtw_pickup_channel *src = NULL;
118*4882a593Smuzhiyun u32 i = 0;
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun dest = &inst->ch[inst->cnt];
121*4882a593Smuzhiyun
122*4882a593Smuzhiyun for (i = 0; i < group->cnt; i++) {
123*4882a593Smuzhiyun src = &group->ch[i];
124*4882a593Smuzhiyun
125*4882a593Smuzhiyun if (!src->picked) {
126*4882a593Smuzhiyun _set_inst_ch(strategy->period, dest,
127*4882a593Smuzhiyun src->band,
128*4882a593Smuzhiyun src->channel,
129*4882a593Smuzhiyun src->property);
130*4882a593Smuzhiyun inst->cnt++;
131*4882a593Smuzhiyun dest++;
132*4882a593Smuzhiyun src->picked = 1;
133*4882a593Smuzhiyun }
134*4882a593Smuzhiyun }
135*4882a593Smuzhiyun }
136*4882a593Smuzhiyun
_pick_5ghz_channels(struct rtw_pickup_chplan_group * group,struct instance_strategy * strategy,struct instance * inst)137*4882a593Smuzhiyun static void _pick_5ghz_channels(struct rtw_pickup_chplan_group *group,
138*4882a593Smuzhiyun struct instance_strategy *strategy,
139*4882a593Smuzhiyun struct instance *inst)
140*4882a593Smuzhiyun {
141*4882a593Smuzhiyun u8 order = strategy->order;
142*4882a593Smuzhiyun u8 i = 0;
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun if (order & ORDER_ACTIVE_PRIOR) {
145*4882a593Smuzhiyun for (i = FREQ_GROUP_5GHZ_BAND1;
146*4882a593Smuzhiyun i <= FREQ_GROUP_5GHZ_BAND4; i++) {
147*4882a593Smuzhiyun _pick_active_channels(&group[i], strategy, inst);
148*4882a593Smuzhiyun }
149*4882a593Smuzhiyun }
150*4882a593Smuzhiyun
151*4882a593Smuzhiyun for (i = FREQ_GROUP_5GHZ_BAND1;
152*4882a593Smuzhiyun i <= FREQ_GROUP_5GHZ_BAND4; i++) {
153*4882a593Smuzhiyun _pick_the_rest_channels(&group[i], strategy, inst);
154*4882a593Smuzhiyun }
155*4882a593Smuzhiyun }
156*4882a593Smuzhiyun
_pick_2ghz_channels(struct rtw_pickup_chplan_group * group,struct instance_strategy * strategy,struct instance * inst)157*4882a593Smuzhiyun static void _pick_2ghz_channels(struct rtw_pickup_chplan_group *group,
158*4882a593Smuzhiyun struct instance_strategy *strategy,
159*4882a593Smuzhiyun struct instance *inst)
160*4882a593Smuzhiyun {
161*4882a593Smuzhiyun u8 order = strategy->order;
162*4882a593Smuzhiyun
163*4882a593Smuzhiyun if (order & ORDER_ACTIVE_PRIOR)
164*4882a593Smuzhiyun _pick_active_channels(&group[FREQ_GROUP_2GHZ],
165*4882a593Smuzhiyun strategy, inst);
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun _pick_the_rest_channels(&group[FREQ_GROUP_2GHZ],
168*4882a593Smuzhiyun strategy, inst);
169*4882a593Smuzhiyun }
170*4882a593Smuzhiyun
_pick_6ghz_channels(struct rtw_pickup_chplan_group * group,struct instance_strategy * strategy,struct instance * inst)171*4882a593Smuzhiyun static void _pick_6ghz_channels(struct rtw_pickup_chplan_group *group,
172*4882a593Smuzhiyun struct instance_strategy *strategy,
173*4882a593Smuzhiyun struct instance *inst)
174*4882a593Smuzhiyun {
175*4882a593Smuzhiyun _pick_the_rest_channels(&group[FREQ_GROUP_6GHZ_PSC],
176*4882a593Smuzhiyun strategy, inst);
177*4882a593Smuzhiyun }
178*4882a593Smuzhiyun
_generate_instance(struct rtw_pickup_chplan_group * group,struct instance_strategy * strategy,struct instance * inst)179*4882a593Smuzhiyun static void _generate_instance(
180*4882a593Smuzhiyun struct rtw_pickup_chplan_group *group,
181*4882a593Smuzhiyun struct instance_strategy *strategy,
182*4882a593Smuzhiyun struct instance *inst)
183*4882a593Smuzhiyun {
184*4882a593Smuzhiyun u8 order = strategy->order;
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun inst->cnt = 0;
187*4882a593Smuzhiyun if (order & ORDER_5GHZ_PRIOR) {
188*4882a593Smuzhiyun _pick_5ghz_channels(group, strategy, inst);
189*4882a593Smuzhiyun _pick_2ghz_channels(group, strategy, inst);
190*4882a593Smuzhiyun } else {
191*4882a593Smuzhiyun _pick_2ghz_channels(group, strategy, inst);
192*4882a593Smuzhiyun _pick_5ghz_channels(group, strategy, inst);
193*4882a593Smuzhiyun }
194*4882a593Smuzhiyun
195*4882a593Smuzhiyun _pick_6ghz_channels(group, strategy, inst);
196*4882a593Smuzhiyun }
197*4882a593Smuzhiyun
_select_channels_by_group(struct instance_strategy * strategy,struct rtw_regulation_chplan * plan,struct rtw_pickup_chplan_group * group)198*4882a593Smuzhiyun static void _select_channels_by_group(struct instance_strategy *strategy,
199*4882a593Smuzhiyun struct rtw_regulation_chplan *plan,
200*4882a593Smuzhiyun struct rtw_pickup_chplan_group *group)
201*4882a593Smuzhiyun {
202*4882a593Smuzhiyun u8 skip = strategy->skip;
203*4882a593Smuzhiyun u8 chnl = 0, property = 0, gpidx = 0, keep = 0;
204*4882a593Smuzhiyun enum band_type band = BAND_ON_24G;
205*4882a593Smuzhiyun u32 i = 0;
206*4882a593Smuzhiyun
207*4882a593Smuzhiyun for (i = 0; i < plan->cnt; i++) {
208*4882a593Smuzhiyun band = plan->ch[i].band;
209*4882a593Smuzhiyun chnl = plan->ch[i].channel;
210*4882a593Smuzhiyun property = plan->ch[i].property;
211*4882a593Smuzhiyun keep = 0;
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun /* skip passive channels */
214*4882a593Smuzhiyun if ((skip & SKIP_PASSIVE) && (property & CH_PASSIVE))
215*4882a593Smuzhiyun continue;
216*4882a593Smuzhiyun
217*4882a593Smuzhiyun /* skip DFS channels */
218*4882a593Smuzhiyun if ((skip & SKIP_DFS) && (property & CH_DFS))
219*4882a593Smuzhiyun continue;
220*4882a593Smuzhiyun
221*4882a593Smuzhiyun if ((BAND_2GHZ(band)) && !(skip & SKIP_2GHZ)) {
222*4882a593Smuzhiyun gpidx = FREQ_GROUP_2GHZ;
223*4882a593Smuzhiyun keep = 1;
224*4882a593Smuzhiyun } else if ((BAND_5GHZ(band)) && !(skip & SKIP_5GHZ)) {
225*4882a593Smuzhiyun if (CH_5GHZ_BAND1(chnl))
226*4882a593Smuzhiyun gpidx = FREQ_GROUP_5GHZ_BAND1;
227*4882a593Smuzhiyun else if (CH_5GHZ_BAND2(chnl))
228*4882a593Smuzhiyun gpidx = FREQ_GROUP_5GHZ_BAND2;
229*4882a593Smuzhiyun else if (CH_5GHZ_BAND3(chnl))
230*4882a593Smuzhiyun gpidx = FREQ_GROUP_5GHZ_BAND3;
231*4882a593Smuzhiyun else if (CH_5GHZ_BAND4(chnl))
232*4882a593Smuzhiyun gpidx = FREQ_GROUP_5GHZ_BAND4;
233*4882a593Smuzhiyun else
234*4882a593Smuzhiyun continue;
235*4882a593Smuzhiyun keep = 1;
236*4882a593Smuzhiyun } else if ((BAND_6GHZ(band)) && !(skip & SKIP_6GHZ)) {
237*4882a593Smuzhiyun gpidx = FREQ_GROUP_6GHZ_PSC;
238*4882a593Smuzhiyun keep = 1;
239*4882a593Smuzhiyun }
240*4882a593Smuzhiyun
241*4882a593Smuzhiyun if (keep) {
242*4882a593Smuzhiyun group[gpidx].ch[group[gpidx].cnt].band = band;
243*4882a593Smuzhiyun group[gpidx].ch[group[gpidx].cnt].channel = chnl;
244*4882a593Smuzhiyun group[gpidx].ch[group[gpidx].cnt].property = property;
245*4882a593Smuzhiyun group[gpidx].ch[group[gpidx].cnt].picked = 0;
246*4882a593Smuzhiyun group[gpidx].cnt++;
247*4882a593Smuzhiyun PHL_INFO("[REGU], keep group-%d channel %d, cnt=%d\n",
248*4882a593Smuzhiyun gpidx, chnl, group[gpidx].cnt);
249*4882a593Smuzhiyun }
250*4882a593Smuzhiyun }
251*4882a593Smuzhiyun }
252*4882a593Smuzhiyun
rtw_phl_generate_scan_instance(struct instance_strategy * strategy,struct rtw_regulation_chplan * chplan,struct instance * inst)253*4882a593Smuzhiyun bool rtw_phl_generate_scan_instance(struct instance_strategy *strategy,
254*4882a593Smuzhiyun struct rtw_regulation_chplan *chplan,
255*4882a593Smuzhiyun struct instance *inst)
256*4882a593Smuzhiyun {
257*4882a593Smuzhiyun struct rtw_pickup_chplan_group group[FREQ_GROUP_MAX] = {0};
258*4882a593Smuzhiyun u32 i = 0;
259*4882a593Smuzhiyun
260*4882a593Smuzhiyun if (!strategy || !inst || !chplan)
261*4882a593Smuzhiyun return false;
262*4882a593Smuzhiyun
263*4882a593Smuzhiyun PHL_INFO("[REGU], Generate Scan Instance, strategy [skip=0x%x, order=0x%x, period=0x%x] \n",
264*4882a593Smuzhiyun strategy->skip, strategy->order, strategy->period);
265*4882a593Smuzhiyun PHL_INFO("[REGU], Channel Plan Source : \n");
266*4882a593Smuzhiyun
267*4882a593Smuzhiyun for (i = 0; i < chplan->cnt; i++) {
268*4882a593Smuzhiyun PHL_INFO("[REGU], %d. band=%d, ch=%d, dfs=%d, passive=%d (property=0x%x)\n",
269*4882a593Smuzhiyun i + 1, chplan->ch[i].band, chplan->ch[i].channel,
270*4882a593Smuzhiyun ((chplan->ch[i].property & CH_DFS) ? 1 : 0),
271*4882a593Smuzhiyun ((chplan->ch[i].property & CH_PASSIVE) ? 1 : 0),
272*4882a593Smuzhiyun chplan->ch[i].property);
273*4882a593Smuzhiyun }
274*4882a593Smuzhiyun
275*4882a593Smuzhiyun /* step1 : remove "skip channels" and select channels into groups */
276*4882a593Smuzhiyun _select_channels_by_group(strategy, chplan, group);
277*4882a593Smuzhiyun
278*4882a593Smuzhiyun
279*4882a593Smuzhiyun /* step2 : generate instance by strategy */
280*4882a593Smuzhiyun _generate_instance(group, strategy, inst);
281*4882a593Smuzhiyun
282*4882a593Smuzhiyun PHL_INFO("[REGU], Output Scan Instance : \n");
283*4882a593Smuzhiyun for (i = 0; i < inst->cnt; i++) {
284*4882a593Smuzhiyun PHL_INFO("[REGU], %d. band=%d, ch=%d, active=%d, period=%d \n",
285*4882a593Smuzhiyun i + 1, inst->ch[i].band,
286*4882a593Smuzhiyun inst->ch[i].channel,
287*4882a593Smuzhiyun inst->ch[i].active,
288*4882a593Smuzhiyun inst->ch[i].period);
289*4882a593Smuzhiyun }
290*4882a593Smuzhiyun
291*4882a593Smuzhiyun return true;
292*4882a593Smuzhiyun }
293*4882a593Smuzhiyun
rtw_phl_scan_instance_insert_ch(void * phl,struct instance * inst,enum band_type band,u8 channel,u8 strategy_period)294*4882a593Smuzhiyun bool rtw_phl_scan_instance_insert_ch(void *phl, struct instance *inst,
295*4882a593Smuzhiyun enum band_type band, u8 channel,
296*4882a593Smuzhiyun u8 strategy_period)
297*4882a593Smuzhiyun {
298*4882a593Smuzhiyun struct rtw_regulation_channel ch = {0};
299*4882a593Smuzhiyun struct instance_channel *dest = NULL;
300*4882a593Smuzhiyun
301*4882a593Smuzhiyun if (!phl || !inst)
302*4882a593Smuzhiyun return false;
303*4882a593Smuzhiyun
304*4882a593Smuzhiyun if (inst->cnt >= MAX_SCAN_INSTANCE)
305*4882a593Smuzhiyun return false;
306*4882a593Smuzhiyun
307*4882a593Smuzhiyun if (rtw_phl_regulation_query_ch(phl, band, channel, &ch)) {
308*4882a593Smuzhiyun dest = &inst->ch[inst->cnt];
309*4882a593Smuzhiyun _set_inst_ch(strategy_period, dest,
310*4882a593Smuzhiyun ch.band, ch.channel, ch.property);
311*4882a593Smuzhiyun inst->cnt++;
312*4882a593Smuzhiyun return true;
313*4882a593Smuzhiyun }
314*4882a593Smuzhiyun
315*4882a593Smuzhiyun return false;
316*4882a593Smuzhiyun }
317*4882a593Smuzhiyun
318*4882a593Smuzhiyun
319*4882a593Smuzhiyun
320