xref: /wlan-dirver/qca-wifi-host-cmn/target_if/regulatory/src/target_if_reg.c (revision 45a38684b07295822dc8eba39e293408f203eec8)
1 /*
2  * Copyright (c) 2017-2020 The Linux Foundation. All rights reserved.
3  *
4  *
5  * Permission to use, copy, modify, and/or distribute this software for
6  * any purpose with or without fee is hereby granted, provided that the
7  * above copyright notice and this permission notice appear in all
8  * copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17  * PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 /**
21  * DOC: target_if_reg.c
22  * This file contains regulatory target interfaces.
23  */
24 
25 #include <wmi_unified_api.h>
26 #include <reg_services_public_struct.h>
27 #include <wlan_reg_tgt_api.h>
28 #include <target_if.h>
29 #include <target_if_reg.h>
30 #include <wmi_unified_reg_api.h>
31 #include <qdf_platform.h>
32 #include <target_if_reg_11d.h>
33 #include <target_if_reg_lte.h>
34 #include <wlan_reg_ucfg_api.h>
35 
36 /**
37  * get_chan_list_cc_event_id() - Get chan_list_cc event i
38  *
39  * Return: Event id
40  */
41 static inline uint32_t get_chan_list_cc_event_id(void)
42 {
43 	return wmi_reg_chan_list_cc_event_id;
44 }
45 
46 /**
47  * tgt_if_regulatory_is_regdb_offloaded() - Check if regdb is offloaded
48  * @psoc: Pointer to psoc
49  *
50  * Return: true if regdb if offloaded, else false
51  */
52 static bool tgt_if_regulatory_is_regdb_offloaded(struct wlan_objmgr_psoc *psoc)
53 {
54 	struct wlan_lmac_if_reg_rx_ops *reg_rx_ops;
55 
56 	wmi_unified_t wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
57 
58 	reg_rx_ops = target_if_regulatory_get_rx_ops(psoc);
59 	if (!reg_rx_ops) {
60 		target_if_err("reg_rx_ops is NULL");
61 		return false;
62 	}
63 
64 	if (!wmi_handle)
65 		return false;
66 
67 	if (reg_rx_ops->reg_ignore_fw_reg_offload_ind &&
68 	    reg_rx_ops->reg_ignore_fw_reg_offload_ind(psoc)) {
69 		target_if_debug("User disabled regulatory offload from ini");
70 		return 0;
71 	}
72 
73 	return wmi_service_enabled(wmi_handle, wmi_service_regulatory_db);
74 }
75 
76 /**
77  * tgt_if_regulatory_is_6ghz_supported() - Check if 6ghz is supported
78  * @psoc: Pointer to psoc
79  *
80  * Return: true if regdb if offloaded, else false
81  */
82 static bool tgt_if_regulatory_is_6ghz_supported(struct wlan_objmgr_psoc *psoc)
83 {
84 	wmi_unified_t wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
85 
86 	if (!wmi_handle)
87 		return false;
88 
89 	return wmi_service_enabled(wmi_handle, wmi_service_6ghz_support);
90 }
91 
92 /**
93  * tgt_if_regulatory_is_5dot9_ghz_supported() - Check if 5.9ghz is supported
94  * @psoc: Pointer to psoc
95  *
96  * Return: true if regdb if offloaded, else false
97  */
98 static bool
99 tgt_if_regulatory_is_5dot9_ghz_supported(struct wlan_objmgr_psoc *psoc)
100 {
101 	wmi_unified_t wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
102 
103 	if (!wmi_handle)
104 		return false;
105 
106 	return wmi_service_enabled(wmi_handle, wmi_service_5dot9_ghz_support);
107 }
108 
109 /**
110  * tgt_if_regulatory_is_there_serv_ready_extn() - Check for service ready
111  * extension
112  * @psoc: Pointer to psoc object
113  *
114  * Return: true if service ready extension is present, else false.
115  */
116 static bool tgt_if_regulatory_is_there_serv_ready_extn(
117 		struct wlan_objmgr_psoc *psoc)
118 {
119 	wmi_unified_t wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
120 
121 	if (!wmi_handle)
122 		return false;
123 
124 	return wmi_service_enabled(wmi_handle, wmi_service_ext_msg);
125 }
126 
127 /**
128  * target_if_regulatory_get_rx_ops() - Get regdb rx ops
129  * @psoc: Pointer to psoc object
130  *
131  * Return: Reg rx_ops
132  */
133 struct wlan_lmac_if_reg_rx_ops *
134 target_if_regulatory_get_rx_ops(struct wlan_objmgr_psoc *psoc)
135 {
136 	struct wlan_lmac_if_rx_ops *rx_ops;
137 
138 	rx_ops = wlan_psoc_get_lmac_if_rxops(psoc);
139 	if (!rx_ops) {
140 		target_if_err("rx_ops is NULL");
141 		return NULL;
142 	}
143 
144 	return &rx_ops->reg_rx_ops;
145 }
146 
147 QDF_STATUS target_if_reg_set_offloaded_info(struct wlan_objmgr_psoc *psoc)
148 {
149 	struct wlan_lmac_if_reg_rx_ops *reg_rx_ops;
150 
151 	reg_rx_ops = target_if_regulatory_get_rx_ops(psoc);
152 	if (!reg_rx_ops) {
153 		target_if_err("reg_rx_ops is NULL");
154 		return QDF_STATUS_E_FAILURE;
155 	}
156 
157 	if (reg_rx_ops->reg_set_regdb_offloaded)
158 		reg_rx_ops->reg_set_regdb_offloaded(
159 				psoc,
160 				tgt_if_regulatory_is_regdb_offloaded(psoc));
161 
162 	if (reg_rx_ops->reg_set_11d_offloaded)
163 		reg_rx_ops->reg_set_11d_offloaded(
164 				psoc, tgt_if_regulatory_is_11d_offloaded(psoc));
165 
166 	return QDF_STATUS_SUCCESS;
167 }
168 
169 QDF_STATUS target_if_reg_set_6ghz_info(struct wlan_objmgr_psoc *psoc)
170 {
171 	struct wlan_lmac_if_reg_rx_ops *reg_rx_ops;
172 
173 	reg_rx_ops = target_if_regulatory_get_rx_ops(psoc);
174 	if (!reg_rx_ops) {
175 		target_if_err("reg_rx_ops is NULL");
176 		return QDF_STATUS_E_FAILURE;
177 	}
178 
179 	if (reg_rx_ops->reg_set_6ghz_supported)
180 		reg_rx_ops->reg_set_6ghz_supported(
181 			psoc,
182 			tgt_if_regulatory_is_6ghz_supported(psoc));
183 
184 	return QDF_STATUS_SUCCESS;
185 }
186 
187 QDF_STATUS target_if_reg_set_5dot9_ghz_info(struct wlan_objmgr_psoc *psoc)
188 {
189 	struct wlan_lmac_if_reg_rx_ops *reg_rx_ops;
190 
191 	reg_rx_ops = target_if_regulatory_get_rx_ops(psoc);
192 	if (!reg_rx_ops) {
193 		target_if_err("reg_rx_ops is NULL");
194 		return QDF_STATUS_E_FAILURE;
195 	}
196 
197 	if (reg_rx_ops->reg_set_5dot9_ghz_supported)
198 		reg_rx_ops->reg_set_5dot9_ghz_supported(
199 			psoc,
200 			tgt_if_regulatory_is_5dot9_ghz_supported(psoc));
201 
202 	return QDF_STATUS_SUCCESS;
203 }
204 
205 /**
206  * tgt_reg_chan_list_update_handler() - Channel list update handler
207  * @handle: scn handle
208  * @event_buf: pointer to event buffer
209  * @len: buffer length
210  *
211  * Return: 0 on success
212  */
213 static int tgt_reg_chan_list_update_handler(ol_scn_t handle, uint8_t *event_buf,
214 					    uint32_t len)
215 {
216 	struct wlan_objmgr_psoc *psoc;
217 	struct wlan_lmac_if_reg_rx_ops *reg_rx_ops;
218 	struct cur_regulatory_info *reg_info;
219 	QDF_STATUS status;
220 	struct wmi_unified *wmi_handle;
221 	int ret_val = 0;
222 
223 	TARGET_IF_ENTER();
224 
225 	psoc = target_if_get_psoc_from_scn_hdl(handle);
226 	if (!psoc) {
227 		target_if_err("psoc ptr is NULL");
228 		return -EINVAL;
229 	}
230 
231 	reg_rx_ops = target_if_regulatory_get_rx_ops(psoc);
232 	if (!reg_rx_ops) {
233 		target_if_err("reg_rx_ops is NULL");
234 		return -EINVAL;
235 	}
236 
237 	if (!reg_rx_ops->master_list_handler) {
238 		target_if_err("master_list_handler is NULL");
239 		return -EINVAL;
240 	}
241 
242 	wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
243 	if (!wmi_handle) {
244 		target_if_err("invalid wmi handle");
245 		return -EINVAL;
246 	}
247 
248 	reg_info = qdf_mem_malloc(sizeof(*reg_info));
249 	if (!reg_info)
250 		return -ENOMEM;
251 
252 	if (wmi_extract_reg_chan_list_update_event(wmi_handle,
253 						   event_buf, reg_info, len)
254 	    != QDF_STATUS_SUCCESS) {
255 		target_if_err("Extraction of channel list event failed");
256 		ret_val = -EFAULT;
257 		goto clean;
258 	}
259 
260 	if (reg_info->phy_id >= PSOC_MAX_PHY_REG_CAP) {
261 		target_if_err_rl("phy_id %d is out of bounds",
262 				 reg_info->phy_id);
263 		ret_val = -EFAULT;
264 		goto clean;
265 	}
266 
267 	reg_info->psoc = psoc;
268 
269 	status = reg_rx_ops->master_list_handler(reg_info);
270 	if (status != QDF_STATUS_SUCCESS) {
271 		target_if_err("Failed to process master channel list handler");
272 		ret_val = -EFAULT;
273 	}
274 
275 clean:
276 	qdf_mem_free(reg_info->reg_rules_2g_ptr);
277 	qdf_mem_free(reg_info->reg_rules_5g_ptr);
278 	qdf_mem_free(reg_info);
279 
280 	TARGET_IF_EXIT();
281 
282 	return ret_val;
283 }
284 
285 /**
286  * tgt_if_regulatory_register_master_list_handler() - Register master channel
287  * list
288  * @psoc: Pointer to psoc
289  * @arg: Pointer to argument list
290  *
291  * Return: QDF_STATUS
292  */
293 static QDF_STATUS tgt_if_regulatory_register_master_list_handler(
294 	struct wlan_objmgr_psoc *psoc, void *arg)
295 {
296 	wmi_unified_t wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
297 
298 	if (!wmi_handle)
299 		return QDF_STATUS_E_FAILURE;
300 
301 	return wmi_unified_register_event_handler(
302 			wmi_handle, wmi_reg_chan_list_cc_event_id,
303 			tgt_reg_chan_list_update_handler, WMI_RX_WORK_CTX);
304 }
305 
306 /**
307  * tgt_if_regulatory_unregister_master_list_handler() - Unregister master
308  * channel list
309  * @psoc: Pointer to psoc
310  * @arg: Pointer to argument list
311  *
312  * Return: QDF_STATUS
313  */
314 static QDF_STATUS tgt_if_regulatory_unregister_master_list_handler(
315 	struct wlan_objmgr_psoc *psoc, void *arg)
316 {
317 	wmi_unified_t wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
318 
319 	if (!wmi_handle)
320 		return QDF_STATUS_E_FAILURE;
321 
322 	return wmi_unified_unregister_event_handler(
323 			wmi_handle, wmi_reg_chan_list_cc_event_id);
324 }
325 
326 /**
327  * tgt_if_regulatory_set_country_code() - Set country code
328  * @psoc: Pointer to psoc
329  * @arg: Pointer to argument list
330  *
331  * Return: QDF_STATUS
332  */
333 static QDF_STATUS tgt_if_regulatory_set_country_code(
334 	struct wlan_objmgr_psoc *psoc, void *arg)
335 {
336 	wmi_unified_t wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
337 
338 	if (!wmi_handle)
339 		return QDF_STATUS_E_FAILURE;
340 
341 	return wmi_unified_set_country_cmd_send(wmi_handle, arg);
342 }
343 
344 /**
345  * tgt_if_regulatory_set_user_country_code() - Set user country code
346  * @psoc: Pointer to psoc
347  * @pdev_id: Pdev id
348  * @rd: Pointer to regdomain structure
349  *
350  * Return: QDF_STATUS
351  */
352 static QDF_STATUS tgt_if_regulatory_set_user_country_code(
353 	struct wlan_objmgr_psoc *psoc, uint8_t pdev_id, struct cc_regdmn_s *rd)
354 {
355 	wmi_unified_t wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
356 
357 	if (!wmi_handle)
358 		return QDF_STATUS_E_FAILURE;
359 
360 	if (wmi_unified_set_user_country_code_cmd_send(
361 				wmi_handle, pdev_id, rd) != QDF_STATUS_SUCCESS
362 			) {
363 		target_if_err("Set user country code failed");
364 		return QDF_STATUS_E_FAILURE;
365 	}
366 
367 	return QDF_STATUS_SUCCESS;
368 }
369 
370 QDF_STATUS tgt_if_regulatory_modify_freq_range(struct wlan_objmgr_psoc *psoc)
371 {
372 	struct wlan_psoc_host_hal_reg_capabilities_ext *reg_cap;
373 
374 	reg_cap = ucfg_reg_get_hal_reg_cap(psoc);
375 	if (!reg_cap) {
376 		target_if_err("reg cap is NULL");
377 		return QDF_STATUS_E_FAILURE;
378 	}
379 
380 	if (!(reg_cap->wireless_modes & WMI_HOST_REGDMN_MODE_11A)) {
381 		reg_cap->low_5ghz_chan = 0;
382 		reg_cap->high_5ghz_chan = 0;
383 	}
384 
385 	if (!(reg_cap->wireless_modes &
386 	     (WMI_HOST_REGDMN_MODE_11B | WMI_HOST_REGDMN_MODE_PUREG))) {
387 		reg_cap->low_2ghz_chan = 0;
388 		reg_cap->high_2ghz_chan = 0;
389 	}
390 
391 	target_if_debug("phy_id = %d - low_2ghz_chan = %d high_2ghz_chan = %d low_5ghz_chan = %d high_5ghz_chan = %d",
392 			reg_cap->phy_id,
393 			reg_cap->low_2ghz_chan,
394 			reg_cap->high_2ghz_chan,
395 			reg_cap->low_5ghz_chan,
396 			reg_cap->high_5ghz_chan);
397 
398 	return QDF_STATUS_SUCCESS;
399 }
400 
401 #ifdef CONFIG_REG_CLIENT
402 /**
403  * tgt_if_regulatory_send_ctl_info() - Send CTL info to firmware
404  * @psoc: Pointer to psoc
405  * @params: Pointer to reg control params
406  *
407  * Return: QDF_STATUS
408  */
409 static QDF_STATUS
410 tgt_if_regulatory_send_ctl_info(struct wlan_objmgr_psoc *psoc,
411 				struct reg_ctl_params *params)
412 {
413 	wmi_unified_t wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
414 
415 	if (!wmi_handle)
416 		return QDF_STATUS_E_FAILURE;
417 
418 	return wmi_unified_send_regdomain_info_to_fw_cmd(wmi_handle,
419 							 params->regd,
420 							 params->regd_2g,
421 							 params->regd_5g,
422 							 params->ctl_2g,
423 							 params->ctl_5g);
424 }
425 #else
426 static QDF_STATUS
427 tgt_if_regulatory_send_ctl_info(struct wlan_objmgr_psoc *psoc,
428 				struct reg_ctl_params *params)
429 {
430 	return QDF_STATUS_SUCCESS;
431 }
432 #endif
433 
434 /**
435  * tgt_if_regulatory_get_phy_id_from_pdev_id() - Get phy_id from pdev_id
436  * @psoc: Pointer to psoc
437  * @pdev_id: Pdev id
438  * @phy_id: phy_id
439  *
440  * Return: QDF_STATUS
441  */
442 static QDF_STATUS tgt_if_regulatory_get_phy_id_from_pdev_id(
443 	struct wlan_objmgr_psoc *psoc, uint8_t pdev_id, uint8_t *phy_id)
444 {
445 	struct target_psoc_info *tgt_if_handle = psoc->tgt_if_handle;
446 	uint8_t ret;
447 
448 	if (pdev_id >= WLAN_UMAC_MAX_PDEVS) {
449 		target_if_err("pdev_id is greater than WLAN_UMAC_MAX_PDEVS");
450 		return QDF_STATUS_E_FAILURE;
451 	}
452 
453 	/* By default pdev_id and phy_id have one to one mapping */
454 	*phy_id = pdev_id;
455 
456 	if (!(tgt_if_handle &&
457 	      tgt_if_handle->info.is_pdevid_to_phyid_map))
458 		return QDF_STATUS_SUCCESS;
459 
460 	ret = tgt_if_handle->info.pdev_id_to_phy_id_map[pdev_id];
461 
462 	if (ret < PSOC_MAX_PHY_REG_CAP) {
463 		*phy_id = ret;
464 	} else {
465 		target_if_err("phy_id is greater than PSOC_MAX_PHY_REG_CAP");
466 		return QDF_STATUS_E_FAILURE;
467 	}
468 
469 	return QDF_STATUS_SUCCESS;
470 }
471 
472 /**
473  * tgt_if_regulatory_get_pdev_id_from_phy_id() - Get pdev_id for phy_id
474  * @psoc: Pointer to psoc
475  * @phy_id: Phy id
476  * @pdev_id: Pdev id
477  *
478  * Return: QDF_STATUS
479  */
480 static QDF_STATUS tgt_if_regulatory_get_pdev_id_from_phy_id(
481 	struct wlan_objmgr_psoc *psoc, uint8_t phy_id, uint8_t *pdev_id)
482 {
483 	struct target_psoc_info *tgt_if_handle = psoc->tgt_if_handle;
484 	uint8_t i;
485 
486 	if (phy_id >= PSOC_MAX_PHY_REG_CAP) {
487 		target_if_err("phy_id is greater than PSOC_MAX_PHY_REG_CAP");
488 		return QDF_STATUS_E_FAILURE;
489 	}
490 
491 	/* By default pdev_id and phy_id have one to one mapping */
492 	*pdev_id = phy_id;
493 
494 	if (!(tgt_if_handle &&
495 	      tgt_if_handle->info.is_pdevid_to_phyid_map))
496 		return QDF_STATUS_SUCCESS;
497 
498 	for (i = 0; i < WLAN_UMAC_MAX_PDEVS; i++) {
499 		if (tgt_if_handle->info.pdev_id_to_phy_id_map[i] == phy_id)
500 			break;
501 	}
502 
503 	if (i < WLAN_UMAC_MAX_PDEVS) {
504 		*pdev_id = i;
505 	} else {
506 		target_if_err("pdev_id is greater than WLAN_UMAC_MAX_PDEVS");
507 		return QDF_STATUS_E_FAILURE;
508 	}
509 
510 	return QDF_STATUS_SUCCESS;
511 }
512 
513 QDF_STATUS target_if_register_regulatory_tx_ops(
514 		struct wlan_lmac_if_tx_ops *tx_ops)
515 {
516 	struct wlan_lmac_if_reg_tx_ops *reg_ops = &tx_ops->reg_ops;
517 
518 	reg_ops->register_master_handler =
519 		tgt_if_regulatory_register_master_list_handler;
520 
521 	reg_ops->unregister_master_handler =
522 		tgt_if_regulatory_unregister_master_list_handler;
523 
524 	reg_ops->set_country_code = tgt_if_regulatory_set_country_code;
525 
526 	reg_ops->fill_umac_legacy_chanlist = NULL;
527 
528 	reg_ops->set_country_failed = NULL;
529 
530 	reg_ops->register_11d_new_cc_handler =
531 		tgt_if_regulatory_register_11d_new_cc_handler;
532 
533 	reg_ops->unregister_11d_new_cc_handler =
534 		tgt_if_regulatory_unregister_11d_new_cc_handler;
535 
536 	reg_ops->start_11d_scan = tgt_if_regulatory_start_11d_scan;
537 
538 	reg_ops->stop_11d_scan = tgt_if_regulatory_stop_11d_scan;
539 
540 	reg_ops->is_there_serv_ready_extn =
541 		tgt_if_regulatory_is_there_serv_ready_extn;
542 
543 	reg_ops->set_user_country_code =
544 		tgt_if_regulatory_set_user_country_code;
545 
546 	reg_ops->register_ch_avoid_event_handler =
547 		tgt_if_regulatory_register_ch_avoid_event_handler;
548 
549 	reg_ops->unregister_ch_avoid_event_handler =
550 		tgt_if_regulatory_unregister_ch_avoid_event_handler;
551 
552 	reg_ops->send_ctl_info = tgt_if_regulatory_send_ctl_info;
553 
554 	reg_ops->get_phy_id_from_pdev_id =
555 			tgt_if_regulatory_get_phy_id_from_pdev_id;
556 
557 	reg_ops->get_pdev_id_from_phy_id =
558 			tgt_if_regulatory_get_pdev_id_from_phy_id;
559 
560 	return QDF_STATUS_SUCCESS;
561 }
562