xref: /OK3568_Linux_fs/external/rkwifibt/drivers/rtl8852bs/phl/phl_scan_instance.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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