xref: /wlan-dirver/qca-wifi-host-cmn/target_if/regulatory/src/target_if_reg.c (revision 6d768494e5ce14eb1603a695c86739d12ecc6ec2)
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_there_serv_ready_extn() - Check for service ready
94  * extension
95  * @psoc: Pointer to psoc object
96  *
97  * Return: true if service ready extension is present, else false.
98  */
99 static bool tgt_if_regulatory_is_there_serv_ready_extn(
100 		struct wlan_objmgr_psoc *psoc)
101 {
102 	wmi_unified_t wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
103 
104 	if (!wmi_handle)
105 		return false;
106 
107 	return wmi_service_enabled(wmi_handle, wmi_service_ext_msg);
108 }
109 
110 /**
111  * target_if_regulatory_get_rx_ops() - Get regdb rx ops
112  * @psoc: Pointer to psoc object
113  *
114  * Return: Reg rx_ops
115  */
116 struct wlan_lmac_if_reg_rx_ops *
117 target_if_regulatory_get_rx_ops(struct wlan_objmgr_psoc *psoc)
118 {
119 	struct wlan_lmac_if_rx_ops *rx_ops;
120 
121 	rx_ops = wlan_psoc_get_lmac_if_rxops(psoc);
122 	if (!rx_ops) {
123 		target_if_err("rx_ops is NULL");
124 		return NULL;
125 	}
126 
127 	return &rx_ops->reg_rx_ops;
128 }
129 
130 QDF_STATUS target_if_reg_set_offloaded_info(struct wlan_objmgr_psoc *psoc)
131 {
132 	struct wlan_lmac_if_reg_rx_ops *reg_rx_ops;
133 
134 	reg_rx_ops = target_if_regulatory_get_rx_ops(psoc);
135 	if (!reg_rx_ops) {
136 		target_if_err("reg_rx_ops is NULL");
137 		return QDF_STATUS_E_FAILURE;
138 	}
139 
140 	if (reg_rx_ops->reg_set_regdb_offloaded)
141 		reg_rx_ops->reg_set_regdb_offloaded(
142 				psoc,
143 				tgt_if_regulatory_is_regdb_offloaded(psoc));
144 
145 	if (reg_rx_ops->reg_set_11d_offloaded)
146 		reg_rx_ops->reg_set_11d_offloaded(
147 				psoc, tgt_if_regulatory_is_11d_offloaded(psoc));
148 
149 	return QDF_STATUS_SUCCESS;
150 }
151 
152 QDF_STATUS target_if_reg_set_6ghz_info(struct wlan_objmgr_psoc *psoc)
153 {
154 	struct wlan_lmac_if_reg_rx_ops *reg_rx_ops;
155 
156 	reg_rx_ops = target_if_regulatory_get_rx_ops(psoc);
157 	if (!reg_rx_ops) {
158 		target_if_err("reg_rx_ops is NULL");
159 		return QDF_STATUS_E_FAILURE;
160 	}
161 
162 	if (reg_rx_ops->reg_set_6ghz_supported)
163 		reg_rx_ops->reg_set_6ghz_supported(
164 			psoc,
165 			tgt_if_regulatory_is_6ghz_supported(psoc));
166 
167 	return QDF_STATUS_SUCCESS;
168 }
169 
170 /**
171  * tgt_reg_chan_list_update_handler() - Channel list update handler
172  * @handle: scn handle
173  * @event_buf: pointer to event buffer
174  * @len: buffer length
175  *
176  * Return: 0 on success
177  */
178 static int tgt_reg_chan_list_update_handler(ol_scn_t handle, uint8_t *event_buf,
179 					    uint32_t len)
180 {
181 	struct wlan_objmgr_psoc *psoc;
182 	struct wlan_lmac_if_reg_rx_ops *reg_rx_ops;
183 	struct cur_regulatory_info *reg_info;
184 	QDF_STATUS status;
185 	struct wmi_unified *wmi_handle;
186 	int ret_val = 0;
187 
188 	TARGET_IF_ENTER();
189 
190 	psoc = target_if_get_psoc_from_scn_hdl(handle);
191 	if (!psoc) {
192 		target_if_err("psoc ptr is NULL");
193 		return -EINVAL;
194 	}
195 
196 	reg_rx_ops = target_if_regulatory_get_rx_ops(psoc);
197 	if (!reg_rx_ops) {
198 		target_if_err("reg_rx_ops is NULL");
199 		return -EINVAL;
200 	}
201 
202 	if (!reg_rx_ops->master_list_handler) {
203 		target_if_err("master_list_handler is NULL");
204 		return -EINVAL;
205 	}
206 
207 	wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
208 	if (!wmi_handle) {
209 		target_if_err("invalid wmi handle");
210 		return -EINVAL;
211 	}
212 
213 	reg_info = qdf_mem_malloc(sizeof(*reg_info));
214 	if (!reg_info)
215 		return -ENOMEM;
216 
217 	if (wmi_extract_reg_chan_list_update_event(wmi_handle,
218 						   event_buf, reg_info, len)
219 	    != QDF_STATUS_SUCCESS) {
220 		target_if_err("Extraction of channel list event failed");
221 		ret_val = -EFAULT;
222 		goto clean;
223 	}
224 
225 	if (reg_info->phy_id >= PSOC_MAX_PHY_REG_CAP) {
226 		target_if_err_rl("phy_id %d is out of bounds",
227 				 reg_info->phy_id);
228 		ret_val = -EFAULT;
229 		goto clean;
230 	}
231 
232 	reg_info->psoc = psoc;
233 
234 	status = reg_rx_ops->master_list_handler(reg_info);
235 	if (status != QDF_STATUS_SUCCESS) {
236 		target_if_err("Failed to process master channel list handler");
237 		ret_val = -EFAULT;
238 	}
239 
240 clean:
241 	qdf_mem_free(reg_info->reg_rules_2g_ptr);
242 	qdf_mem_free(reg_info->reg_rules_5g_ptr);
243 	qdf_mem_free(reg_info);
244 
245 	TARGET_IF_EXIT();
246 
247 	return ret_val;
248 }
249 
250 /**
251  * tgt_if_regulatory_register_master_list_handler() - Register master channel
252  * list
253  * @psoc: Pointer to psoc
254  * @arg: Pointer to argument list
255  *
256  * Return: QDF_STATUS
257  */
258 static QDF_STATUS tgt_if_regulatory_register_master_list_handler(
259 	struct wlan_objmgr_psoc *psoc, void *arg)
260 {
261 	wmi_unified_t wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
262 
263 	if (!wmi_handle)
264 		return QDF_STATUS_E_FAILURE;
265 
266 	return wmi_unified_register_event_handler(
267 			wmi_handle, wmi_reg_chan_list_cc_event_id,
268 			tgt_reg_chan_list_update_handler, WMI_RX_WORK_CTX);
269 }
270 
271 /**
272  * tgt_if_regulatory_unregister_master_list_handler() - Unregister master
273  * channel list
274  * @psoc: Pointer to psoc
275  * @arg: Pointer to argument list
276  *
277  * Return: QDF_STATUS
278  */
279 static QDF_STATUS tgt_if_regulatory_unregister_master_list_handler(
280 	struct wlan_objmgr_psoc *psoc, void *arg)
281 {
282 	wmi_unified_t wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
283 
284 	if (!wmi_handle)
285 		return QDF_STATUS_E_FAILURE;
286 
287 	return wmi_unified_unregister_event_handler(
288 			wmi_handle, wmi_reg_chan_list_cc_event_id);
289 }
290 
291 /**
292  * tgt_if_regulatory_set_country_code() - Set country code
293  * @psoc: Pointer to psoc
294  * @arg: Pointer to argument list
295  *
296  * Return: QDF_STATUS
297  */
298 static QDF_STATUS tgt_if_regulatory_set_country_code(
299 	struct wlan_objmgr_psoc *psoc, void *arg)
300 {
301 	wmi_unified_t wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
302 
303 	if (!wmi_handle)
304 		return QDF_STATUS_E_FAILURE;
305 
306 	return wmi_unified_set_country_cmd_send(wmi_handle, arg);
307 }
308 
309 /**
310  * tgt_if_regulatory_set_user_country_code() - Set user country code
311  * @psoc: Pointer to psoc
312  * @pdev_id: Pdev id
313  * @rd: Pointer to regdomain structure
314  *
315  * Return: QDF_STATUS
316  */
317 static QDF_STATUS tgt_if_regulatory_set_user_country_code(
318 	struct wlan_objmgr_psoc *psoc, uint8_t pdev_id, struct cc_regdmn_s *rd)
319 {
320 	wmi_unified_t wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
321 
322 	if (!wmi_handle)
323 		return QDF_STATUS_E_FAILURE;
324 
325 	if (wmi_unified_set_user_country_code_cmd_send(
326 				wmi_handle, pdev_id, rd) != QDF_STATUS_SUCCESS
327 			) {
328 		target_if_err("Set user country code failed");
329 		return QDF_STATUS_E_FAILURE;
330 	}
331 
332 	return QDF_STATUS_SUCCESS;
333 }
334 
335 QDF_STATUS tgt_if_regulatory_modify_freq_range(struct wlan_objmgr_psoc *psoc)
336 {
337 	struct wlan_psoc_host_hal_reg_capabilities_ext *reg_cap;
338 
339 	reg_cap = ucfg_reg_get_hal_reg_cap(psoc);
340 	if (!reg_cap) {
341 		target_if_err("reg cap is NULL");
342 		return QDF_STATUS_E_FAILURE;
343 	}
344 
345 	if (!(reg_cap->wireless_modes & WMI_HOST_REGDMN_MODE_11A)) {
346 		reg_cap->low_5ghz_chan = 0;
347 		reg_cap->high_5ghz_chan = 0;
348 	}
349 
350 	if (!(reg_cap->wireless_modes &
351 	     (WMI_HOST_REGDMN_MODE_11B | WMI_HOST_REGDMN_MODE_PUREG))) {
352 		reg_cap->low_2ghz_chan = 0;
353 		reg_cap->high_2ghz_chan = 0;
354 	}
355 
356 	target_if_debug("phy_id = %d - low_2ghz_chan = %d high_2ghz_chan = %d low_5ghz_chan = %d high_5ghz_chan = %d",
357 			reg_cap->phy_id,
358 			reg_cap->low_2ghz_chan,
359 			reg_cap->high_2ghz_chan,
360 			reg_cap->low_5ghz_chan,
361 			reg_cap->high_5ghz_chan);
362 
363 	return QDF_STATUS_SUCCESS;
364 }
365 
366 #ifdef CONFIG_REG_CLIENT
367 /**
368  * tgt_if_regulatory_send_ctl_info() - Send CTL info to firmware
369  * @psoc: Pointer to psoc
370  * @params: Pointer to reg control params
371  *
372  * Return: QDF_STATUS
373  */
374 static QDF_STATUS
375 tgt_if_regulatory_send_ctl_info(struct wlan_objmgr_psoc *psoc,
376 				struct reg_ctl_params *params)
377 {
378 	wmi_unified_t wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
379 
380 	if (!wmi_handle)
381 		return QDF_STATUS_E_FAILURE;
382 
383 	return wmi_unified_send_regdomain_info_to_fw_cmd(wmi_handle,
384 							 params->regd,
385 							 params->regd_2g,
386 							 params->regd_5g,
387 							 params->ctl_2g,
388 							 params->ctl_5g);
389 }
390 #else
391 static QDF_STATUS
392 tgt_if_regulatory_send_ctl_info(struct wlan_objmgr_psoc *psoc,
393 				struct reg_ctl_params *params)
394 {
395 	return QDF_STATUS_SUCCESS;
396 }
397 #endif
398 
399 /**
400  * tgt_if_regulatory_get_phy_id_from_pdev_id() - Get phy_id from pdev_id
401  * @psoc: Pointer to psoc
402  * @pdev_id: Pdev id
403  * @phy_id: phy_id
404  *
405  * Return: QDF_STATUS
406  */
407 static QDF_STATUS tgt_if_regulatory_get_phy_id_from_pdev_id(
408 	struct wlan_objmgr_psoc *psoc, uint8_t pdev_id, uint8_t *phy_id)
409 {
410 	struct target_psoc_info *tgt_if_handle = psoc->tgt_if_handle;
411 	uint8_t ret;
412 
413 	if (pdev_id >= WLAN_UMAC_MAX_PDEVS) {
414 		target_if_err("pdev_id is greater than WLAN_UMAC_MAX_PDEVS");
415 		return QDF_STATUS_E_FAILURE;
416 	}
417 
418 	/* By default pdev_id and phy_id have one to one mapping */
419 	*phy_id = pdev_id;
420 
421 	if (!(tgt_if_handle &&
422 	      tgt_if_handle->info.is_pdevid_to_phyid_map))
423 		return QDF_STATUS_SUCCESS;
424 
425 	ret = tgt_if_handle->info.pdev_id_to_phy_id_map[pdev_id];
426 
427 	if (ret < PSOC_MAX_PHY_REG_CAP) {
428 		*phy_id = ret;
429 	} else {
430 		target_if_err("phy_id is greater than PSOC_MAX_PHY_REG_CAP");
431 		return QDF_STATUS_E_FAILURE;
432 	}
433 
434 	return QDF_STATUS_SUCCESS;
435 }
436 
437 /**
438  * tgt_if_regulatory_get_pdev_id_from_phy_id() - Get pdev_id for phy_id
439  * @psoc: Pointer to psoc
440  * @phy_id: Phy id
441  * @pdev_id: Pdev id
442  *
443  * Return: QDF_STATUS
444  */
445 static QDF_STATUS tgt_if_regulatory_get_pdev_id_from_phy_id(
446 	struct wlan_objmgr_psoc *psoc, uint8_t phy_id, uint8_t *pdev_id)
447 {
448 	struct target_psoc_info *tgt_if_handle = psoc->tgt_if_handle;
449 	uint8_t i;
450 
451 	if (phy_id >= PSOC_MAX_PHY_REG_CAP) {
452 		target_if_err("phy_id is greater than PSOC_MAX_PHY_REG_CAP");
453 		return QDF_STATUS_E_FAILURE;
454 	}
455 
456 	/* By default pdev_id and phy_id have one to one mapping */
457 	*pdev_id = phy_id;
458 
459 	if (!(tgt_if_handle &&
460 	      tgt_if_handle->info.is_pdevid_to_phyid_map))
461 		return QDF_STATUS_SUCCESS;
462 
463 	for (i = 0; i < WLAN_UMAC_MAX_PDEVS; i++) {
464 		if (tgt_if_handle->info.pdev_id_to_phy_id_map[i] == phy_id)
465 			break;
466 	}
467 
468 	if (i < WLAN_UMAC_MAX_PDEVS) {
469 		*pdev_id = i;
470 	} else {
471 		target_if_err("pdev_id is greater than WLAN_UMAC_MAX_PDEVS");
472 		return QDF_STATUS_E_FAILURE;
473 	}
474 
475 	return QDF_STATUS_SUCCESS;
476 }
477 
478 QDF_STATUS target_if_register_regulatory_tx_ops(
479 		struct wlan_lmac_if_tx_ops *tx_ops)
480 {
481 	struct wlan_lmac_if_reg_tx_ops *reg_ops = &tx_ops->reg_ops;
482 
483 	reg_ops->register_master_handler =
484 		tgt_if_regulatory_register_master_list_handler;
485 
486 	reg_ops->unregister_master_handler =
487 		tgt_if_regulatory_unregister_master_list_handler;
488 
489 	reg_ops->set_country_code = tgt_if_regulatory_set_country_code;
490 
491 	reg_ops->fill_umac_legacy_chanlist = NULL;
492 
493 	reg_ops->set_country_failed = NULL;
494 
495 	reg_ops->register_11d_new_cc_handler =
496 		tgt_if_regulatory_register_11d_new_cc_handler;
497 
498 	reg_ops->unregister_11d_new_cc_handler =
499 		tgt_if_regulatory_unregister_11d_new_cc_handler;
500 
501 	reg_ops->start_11d_scan = tgt_if_regulatory_start_11d_scan;
502 
503 	reg_ops->stop_11d_scan = tgt_if_regulatory_stop_11d_scan;
504 
505 	reg_ops->is_there_serv_ready_extn =
506 		tgt_if_regulatory_is_there_serv_ready_extn;
507 
508 	reg_ops->set_user_country_code =
509 		tgt_if_regulatory_set_user_country_code;
510 
511 	reg_ops->register_ch_avoid_event_handler =
512 		tgt_if_regulatory_register_ch_avoid_event_handler;
513 
514 	reg_ops->unregister_ch_avoid_event_handler =
515 		tgt_if_regulatory_unregister_ch_avoid_event_handler;
516 
517 	reg_ops->send_ctl_info = tgt_if_regulatory_send_ctl_info;
518 
519 	reg_ops->get_phy_id_from_pdev_id =
520 			tgt_if_regulatory_get_phy_id_from_pdev_id;
521 
522 	reg_ops->get_pdev_id_from_phy_id =
523 			tgt_if_regulatory_get_pdev_id_from_phy_id;
524 
525 	return QDF_STATUS_SUCCESS;
526 }
527