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