1 /*
2 * Copyright (c) 2014-2021 The Linux Foundation. All rights reserved.
3 * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
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: reg_callbacks.c
22 * This file defines regulatory callback functions
23 */
24
25 #include <wlan_cmn.h>
26 #include <reg_services_public_struct.h>
27 #include <wlan_objmgr_psoc_obj.h>
28 #include <wlan_objmgr_pdev_obj.h>
29 #include "reg_priv_objs.h"
30 #include "reg_utils.h"
31 #include <scheduler_api.h>
32 #include "reg_callbacks.h"
33 #include "reg_services_common.h"
34 #include "reg_build_chan_list.h"
35
36 /**
37 * reg_call_chan_change_cbks() - Call registered callback functions on channel
38 * change.
39 * @psoc: Pointer to global psoc structure.
40 * @pdev: Pointer to global pdev structure.
41 * @ch_avoid_ind: if chan avoid indicated
42 * @avoid_info: chan avoid info if @ch_avoid_ind is true
43 */
reg_call_chan_change_cbks(struct wlan_objmgr_psoc * psoc,struct wlan_objmgr_pdev * pdev,bool ch_avoid_ind,struct avoid_freq_ind_data * avoid_info)44 static void reg_call_chan_change_cbks(struct wlan_objmgr_psoc *psoc,
45 struct wlan_objmgr_pdev *pdev,
46 bool ch_avoid_ind,
47 struct avoid_freq_ind_data *avoid_info)
48 {
49 struct chan_change_cbk_entry *cbk_list;
50 struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj;
51 struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj;
52 struct regulatory_channel *cur_chan_list;
53 uint32_t ctr;
54 struct avoid_freq_ind_data *avoid_freq_ind = NULL;
55 reg_chan_change_callback callback;
56 QDF_STATUS status;
57
58 psoc_priv_obj = reg_get_psoc_obj(psoc);
59 if (!IS_VALID_PSOC_REG_OBJ(psoc_priv_obj)) {
60 reg_alert("psoc reg component is NULL");
61 return;
62 }
63
64 pdev_priv_obj = reg_get_pdev_obj(pdev);
65 if (!IS_VALID_PDEV_REG_OBJ(pdev_priv_obj)) {
66 reg_alert("pdev reg component is NULL");
67 return;
68 }
69
70 cur_chan_list = qdf_mem_malloc(NUM_CHANNELS * sizeof(*cur_chan_list));
71 if (!cur_chan_list)
72 return;
73
74 status = reg_get_pwrmode_chan_list(pdev, cur_chan_list,
75 REG_CURRENT_PWR_MODE);
76 if (!QDF_IS_STATUS_SUCCESS(status)) {
77 qdf_mem_free(cur_chan_list);
78 return;
79 }
80 if (ch_avoid_ind)
81 avoid_freq_ind = avoid_info;
82
83 cbk_list = psoc_priv_obj->cbk_list;
84
85 for (ctr = 0; ctr < REG_MAX_CHAN_CHANGE_CBKS; ctr++) {
86 callback = NULL;
87 qdf_spin_lock_bh(&psoc_priv_obj->cbk_list_lock);
88 if (cbk_list[ctr].cbk)
89 callback = cbk_list[ctr].cbk;
90 qdf_spin_unlock_bh(&psoc_priv_obj->cbk_list_lock);
91 if (callback)
92 callback(psoc, pdev, cur_chan_list, avoid_freq_ind,
93 cbk_list[ctr].arg);
94 }
95 qdf_mem_free(cur_chan_list);
96 }
97
98 #ifdef FEATURE_WLAN_CH_AVOID_EXT
99 static inline void
reg_fill_freq_ext_payload(struct reg_sched_payload ** payload,struct wlan_regulatory_psoc_priv_obj * psoc_priv_obj)100 reg_fill_freq_ext_payload(struct reg_sched_payload **payload,
101 struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj)
102 {
103 (*payload)->ch_avoid_ind =
104 !!psoc_priv_obj->ch_avoid_ext_ind;
105 qdf_mem_copy(&(*payload)->avoid_info.freq_list,
106 &psoc_priv_obj->avoid_freq_ext_list,
107 sizeof(psoc_priv_obj->avoid_freq_ext_list));
108
109 psoc_priv_obj->ch_avoid_ext_ind = false;
110 }
111 #else
112 static inline void
reg_fill_freq_ext_payload(struct reg_sched_payload ** payload,struct wlan_regulatory_psoc_priv_obj * psoc_priv_obj)113 reg_fill_freq_ext_payload(struct reg_sched_payload **payload,
114 struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj)
115 {
116 }
117 #endif
118
119 /**
120 * reg_alloc_and_fill_payload() - Alloc and fill payload structure.
121 * @psoc: Pointer to global psoc structure.
122 * @pdev: Pointer to global pdev structure.
123 * @payload: output pointer to allocated payload buffer
124 */
reg_alloc_and_fill_payload(struct wlan_objmgr_psoc * psoc,struct wlan_objmgr_pdev * pdev,struct reg_sched_payload ** payload)125 static void reg_alloc_and_fill_payload(struct wlan_objmgr_psoc *psoc,
126 struct wlan_objmgr_pdev *pdev,
127 struct reg_sched_payload **payload)
128 {
129 struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj;
130
131 psoc_priv_obj = reg_get_psoc_obj(psoc);
132 if (!psoc_priv_obj) {
133 reg_err("reg psoc private obj is NULL");
134 *payload = NULL;
135 return;
136 }
137
138 *payload = qdf_mem_malloc(sizeof(**payload));
139 if (*payload) {
140 (*payload)->psoc = psoc;
141 (*payload)->pdev = pdev;
142 if (reg_check_coex_unsafe_nb_user_prefer(psoc)) {
143 reg_fill_freq_ext_payload(payload, psoc_priv_obj);
144 } else {
145 (*payload)->ch_avoid_ind =
146 !!psoc_priv_obj->ch_avoid_ind;
147 qdf_mem_copy(&(*payload)->avoid_info.freq_list,
148 &psoc_priv_obj->avoid_freq_list,
149 sizeof(psoc_priv_obj->avoid_freq_list));
150
151 psoc_priv_obj->ch_avoid_ind = false;
152 }
153 qdf_mem_copy(&(*payload)->avoid_info.chan_list,
154 &psoc_priv_obj->unsafe_chan_list,
155 sizeof(psoc_priv_obj->unsafe_chan_list));
156 }
157 }
158
159 /**
160 * reg_chan_change_flush_cbk_sb() - Flush south bound channel change callbacks.
161 * @msg: Pointer to scheduler msg structure.
162 */
reg_chan_change_flush_cbk_sb(struct scheduler_msg * msg)163 static QDF_STATUS reg_chan_change_flush_cbk_sb(struct scheduler_msg *msg)
164 {
165 struct reg_sched_payload *load = msg->bodyptr;
166 struct wlan_objmgr_psoc *psoc = load->psoc;
167 struct wlan_objmgr_pdev *pdev = load->pdev;
168
169 wlan_objmgr_pdev_release_ref(pdev, WLAN_REGULATORY_SB_ID);
170 wlan_objmgr_psoc_release_ref(psoc, WLAN_REGULATORY_SB_ID);
171 qdf_mem_free(load);
172
173 return QDF_STATUS_SUCCESS;
174 }
175
176 /**
177 * reg_sched_chan_change_cbks_sb() - Schedule south bound channel change
178 * callbacks.
179 * @msg: Pointer to scheduler msg structure.
180 */
reg_sched_chan_change_cbks_sb(struct scheduler_msg * msg)181 static QDF_STATUS reg_sched_chan_change_cbks_sb(struct scheduler_msg *msg)
182 {
183 struct reg_sched_payload *load = msg->bodyptr;
184 struct wlan_objmgr_psoc *psoc = load->psoc;
185 struct wlan_objmgr_pdev *pdev = load->pdev;
186
187 reg_call_chan_change_cbks(psoc, pdev, load->ch_avoid_ind,
188 &load->avoid_info);
189
190 wlan_objmgr_pdev_release_ref(pdev, WLAN_REGULATORY_SB_ID);
191 wlan_objmgr_psoc_release_ref(psoc, WLAN_REGULATORY_SB_ID);
192 qdf_mem_free(load);
193
194 return QDF_STATUS_SUCCESS;
195 }
196
197 /**
198 * reg_chan_change_flush_cbk_nb() - Flush north bound channel change callbacks.
199 * @msg: Pointer to scheduler msg structure.
200 */
reg_chan_change_flush_cbk_nb(struct scheduler_msg * msg)201 static QDF_STATUS reg_chan_change_flush_cbk_nb(struct scheduler_msg *msg)
202 {
203 struct reg_sched_payload *load = msg->bodyptr;
204 struct wlan_objmgr_psoc *psoc = load->psoc;
205 struct wlan_objmgr_pdev *pdev = load->pdev;
206
207 wlan_objmgr_pdev_release_ref(pdev, WLAN_REGULATORY_NB_ID);
208 wlan_objmgr_psoc_release_ref(psoc, WLAN_REGULATORY_NB_ID);
209 qdf_mem_free(load);
210
211 return QDF_STATUS_SUCCESS;
212 }
213
214 /**
215 * reg_sched_chan_change_cbks_nb() - Schedule north bound channel change
216 * callbacks.
217 * @msg: Pointer to scheduler msg structure.
218 */
reg_sched_chan_change_cbks_nb(struct scheduler_msg * msg)219 static QDF_STATUS reg_sched_chan_change_cbks_nb(struct scheduler_msg *msg)
220 {
221 struct reg_sched_payload *load = msg->bodyptr;
222 struct wlan_objmgr_psoc *psoc = load->psoc;
223 struct wlan_objmgr_pdev *pdev = load->pdev;
224
225 reg_call_chan_change_cbks(psoc, pdev, load->ch_avoid_ind,
226 &load->avoid_info);
227
228 wlan_objmgr_pdev_release_ref(pdev, WLAN_REGULATORY_NB_ID);
229 wlan_objmgr_psoc_release_ref(psoc, WLAN_REGULATORY_NB_ID);
230 qdf_mem_free(load);
231
232 return QDF_STATUS_SUCCESS;
233 }
234
reg_send_scheduler_msg_sb(struct wlan_objmgr_psoc * psoc,struct wlan_objmgr_pdev * pdev)235 QDF_STATUS reg_send_scheduler_msg_sb(struct wlan_objmgr_psoc *psoc,
236 struct wlan_objmgr_pdev *pdev)
237 {
238 struct scheduler_msg msg = {0};
239 struct reg_sched_payload *payload;
240 struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj;
241 QDF_STATUS status;
242
243 pdev_priv_obj = reg_get_pdev_obj(pdev);
244 if (!IS_VALID_PDEV_REG_OBJ(pdev_priv_obj)) {
245 reg_alert("pdev reg component is NULL");
246 return QDF_STATUS_E_FAILURE;
247 }
248
249 if (!pdev_priv_obj->pdev_opened) {
250 reg_err("hlos not initialized");
251 return QDF_STATUS_E_FAILURE;
252 }
253
254 if (!pdev_priv_obj->chan_list_recvd) {
255 reg_err("Empty channel list");
256 return QDF_STATUS_E_FAILURE;
257 }
258
259 status = wlan_objmgr_psoc_try_get_ref(psoc, WLAN_REGULATORY_SB_ID);
260 if (QDF_IS_STATUS_ERROR(status)) {
261 reg_err("error taking psoc ref cnt");
262 return status;
263 }
264
265 status = wlan_objmgr_pdev_try_get_ref(pdev, WLAN_REGULATORY_SB_ID);
266 if (QDF_IS_STATUS_ERROR(status)) {
267 wlan_objmgr_psoc_release_ref(psoc, WLAN_REGULATORY_SB_ID);
268 reg_err("error taking pdev ref cnt");
269 return status;
270 }
271
272 reg_alloc_and_fill_payload(psoc, pdev, &payload);
273 if (!payload) {
274 reg_err("malloc failed");
275 wlan_objmgr_pdev_release_ref(pdev, WLAN_REGULATORY_SB_ID);
276 wlan_objmgr_psoc_release_ref(psoc, WLAN_REGULATORY_SB_ID);
277 return QDF_STATUS_E_NOMEM;
278 }
279
280 msg.bodyptr = payload;
281 msg.callback = reg_sched_chan_change_cbks_sb;
282 msg.flush_callback = reg_chan_change_flush_cbk_sb;
283
284 status = scheduler_post_message(QDF_MODULE_ID_REGULATORY,
285 QDF_MODULE_ID_REGULATORY,
286 QDF_MODULE_ID_TARGET_IF, &msg);
287 if (QDF_IS_STATUS_ERROR(status)) {
288 wlan_objmgr_pdev_release_ref(pdev, WLAN_REGULATORY_SB_ID);
289 wlan_objmgr_psoc_release_ref(psoc, WLAN_REGULATORY_SB_ID);
290 qdf_mem_free(payload);
291 }
292
293 return status;
294 }
295
reg_send_scheduler_msg_nb(struct wlan_objmgr_psoc * psoc,struct wlan_objmgr_pdev * pdev)296 QDF_STATUS reg_send_scheduler_msg_nb(struct wlan_objmgr_psoc *psoc,
297 struct wlan_objmgr_pdev *pdev)
298 {
299 struct scheduler_msg msg = {0};
300 struct reg_sched_payload *payload;
301 struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj;
302 QDF_STATUS status;
303
304 pdev_priv_obj = reg_get_pdev_obj(pdev);
305 if (!IS_VALID_PDEV_REG_OBJ(pdev_priv_obj)) {
306 reg_alert("pdev reg component is NULL");
307 return QDF_STATUS_E_FAILURE;
308 }
309
310 if (!pdev_priv_obj->pdev_opened) {
311 reg_err("hlos not initialized");
312 return QDF_STATUS_E_FAILURE;
313 }
314
315 if (!pdev_priv_obj->chan_list_recvd) {
316 reg_err("Empty channel list");
317 return QDF_STATUS_E_FAILURE;
318 }
319
320 status = wlan_objmgr_psoc_try_get_ref(psoc, WLAN_REGULATORY_NB_ID);
321 if (QDF_IS_STATUS_ERROR(status)) {
322 reg_err("error taking psoc ref cnt");
323 return status;
324 }
325
326 status = wlan_objmgr_pdev_try_get_ref(pdev, WLAN_REGULATORY_NB_ID);
327 if (QDF_IS_STATUS_ERROR(status)) {
328 wlan_objmgr_psoc_release_ref(psoc, WLAN_REGULATORY_NB_ID);
329 reg_err("error taking pdev ref cnt");
330 return status;
331 }
332
333 reg_alloc_and_fill_payload(psoc, pdev, &payload);
334 if (!payload) {
335 reg_err("malloc failed");
336 wlan_objmgr_pdev_release_ref(pdev, WLAN_REGULATORY_NB_ID);
337 wlan_objmgr_psoc_release_ref(psoc, WLAN_REGULATORY_NB_ID);
338 return QDF_STATUS_E_NOMEM;
339 }
340 msg.bodyptr = payload;
341 msg.callback = reg_sched_chan_change_cbks_nb;
342 msg.flush_callback = reg_chan_change_flush_cbk_nb;
343
344 status = scheduler_post_message(QDF_MODULE_ID_REGULATORY,
345 QDF_MODULE_ID_REGULATORY,
346 QDF_MODULE_ID_OS_IF, &msg);
347 if (QDF_IS_STATUS_ERROR(status)) {
348 wlan_objmgr_pdev_release_ref(pdev, WLAN_REGULATORY_NB_ID);
349 wlan_objmgr_psoc_release_ref(psoc, WLAN_REGULATORY_NB_ID);
350 qdf_mem_free(payload);
351 }
352
353 return status;
354 }
355
reg_notify_sap_event(struct wlan_objmgr_pdev * pdev,bool sap_state)356 QDF_STATUS reg_notify_sap_event(struct wlan_objmgr_pdev *pdev,
357 bool sap_state)
358 {
359 struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj;
360 struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj;
361 struct wlan_objmgr_psoc *psoc;
362 QDF_STATUS status;
363
364 pdev_priv_obj = reg_get_pdev_obj(pdev);
365
366 if (!IS_VALID_PDEV_REG_OBJ(pdev_priv_obj)) {
367 reg_err("pdev reg component is NULL");
368 return QDF_STATUS_E_INVAL;
369 }
370
371 psoc = wlan_pdev_get_psoc(pdev);
372 if (!psoc) {
373 reg_err("psoc is NULL");
374 return QDF_STATUS_E_INVAL;
375 }
376
377 psoc_priv_obj = reg_get_psoc_obj(psoc);
378 if (!IS_VALID_PSOC_REG_OBJ(psoc_priv_obj)) {
379 reg_err("psoc reg component is NULL");
380 return QDF_STATUS_E_INVAL;
381 }
382
383 reg_info("sap_state: %d", sap_state);
384
385 if (pdev_priv_obj->sap_state == sap_state)
386 return QDF_STATUS_SUCCESS;
387
388 pdev_priv_obj->sap_state = sap_state;
389
390 reg_compute_pdev_current_chan_list(pdev_priv_obj);
391 status = reg_send_scheduler_msg_sb(psoc, pdev);
392
393 return status;
394 }
395
reg_register_chan_change_callback(struct wlan_objmgr_psoc * psoc,reg_chan_change_callback cbk,void * arg)396 void reg_register_chan_change_callback(struct wlan_objmgr_psoc *psoc,
397 reg_chan_change_callback cbk, void *arg)
398 {
399 struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj;
400 uint32_t count;
401
402 psoc_priv_obj = reg_get_psoc_obj(psoc);
403 if (!psoc_priv_obj) {
404 reg_err("reg psoc private obj is NULL");
405 return;
406 }
407
408 qdf_spin_lock_bh(&psoc_priv_obj->cbk_list_lock);
409 for (count = 0; count < REG_MAX_CHAN_CHANGE_CBKS; count++)
410 if (!psoc_priv_obj->cbk_list[count].cbk) {
411 psoc_priv_obj->cbk_list[count].cbk = cbk;
412 psoc_priv_obj->cbk_list[count].arg = arg;
413 psoc_priv_obj->num_chan_change_cbks++;
414 break;
415 }
416 qdf_spin_unlock_bh(&psoc_priv_obj->cbk_list_lock);
417
418 if (count == REG_MAX_CHAN_CHANGE_CBKS)
419 reg_err("callback list is full");
420 }
421
reg_register_ctry_change_callback(struct wlan_objmgr_psoc * psoc,reg_ctry_change_callback cbk)422 void reg_register_ctry_change_callback(struct wlan_objmgr_psoc *psoc,
423 reg_ctry_change_callback cbk)
424 {
425 struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj;
426
427 psoc_priv_obj = reg_get_psoc_obj(psoc);
428 if (!psoc_priv_obj) {
429 reg_err("reg psoc private obj is NULL");
430 return;
431 }
432
433 qdf_spin_lock_bh(&psoc_priv_obj->cbk_list_lock);
434 if (!psoc_priv_obj->cc_cbk.cbk)
435 psoc_priv_obj->cc_cbk.cbk = cbk;
436 qdf_spin_unlock_bh(&psoc_priv_obj->cbk_list_lock);
437 }
438
reg_unregister_chan_change_callback(struct wlan_objmgr_psoc * psoc,reg_chan_change_callback cbk)439 void reg_unregister_chan_change_callback(struct wlan_objmgr_psoc *psoc,
440 reg_chan_change_callback cbk)
441 {
442 struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj;
443 uint32_t count;
444
445 psoc_priv_obj = reg_get_psoc_obj(psoc);
446 if (!psoc_priv_obj) {
447 reg_err("reg psoc private obj is NULL");
448 return;
449 }
450
451 qdf_spin_lock_bh(&psoc_priv_obj->cbk_list_lock);
452 for (count = 0; count < REG_MAX_CHAN_CHANGE_CBKS; count++)
453 if (psoc_priv_obj->cbk_list[count].cbk == cbk) {
454 psoc_priv_obj->cbk_list[count].cbk = NULL;
455 psoc_priv_obj->num_chan_change_cbks--;
456 break;
457 }
458 qdf_spin_unlock_bh(&psoc_priv_obj->cbk_list_lock);
459
460 if (count == REG_MAX_CHAN_CHANGE_CBKS)
461 reg_err("callback not found in the list");
462 }
463
reg_unregister_ctry_change_callback(struct wlan_objmgr_psoc * psoc,reg_ctry_change_callback cbk)464 void reg_unregister_ctry_change_callback(struct wlan_objmgr_psoc *psoc,
465 reg_ctry_change_callback cbk)
466 {
467 struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj;
468
469 psoc_priv_obj = reg_get_psoc_obj(psoc);
470 if (!psoc_priv_obj) {
471 reg_err("reg psoc private obj is NULL");
472 return;
473 }
474
475 qdf_spin_lock_bh(&psoc_priv_obj->cbk_list_lock);
476 if (psoc_priv_obj->cc_cbk.cbk == cbk)
477 psoc_priv_obj->cc_cbk.cbk = NULL;
478 qdf_spin_unlock_bh(&psoc_priv_obj->cbk_list_lock);
479 }
480
481 void
reg_register_is_chan_connected_callback(struct wlan_objmgr_psoc * psoc,reg_get_connected_chan_for_mode_callback cbk)482 reg_register_is_chan_connected_callback(struct wlan_objmgr_psoc *psoc,
483 reg_get_connected_chan_for_mode_callback cbk)
484 {
485 struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj;
486
487 psoc_priv_obj = reg_get_psoc_obj(psoc);
488 if (!psoc_priv_obj) {
489 reg_err("reg psoc private obj is NULL");
490 return;
491 }
492
493 qdf_spin_lock_bh(&psoc_priv_obj->cbk_list_lock);
494 if (!psoc_priv_obj->conn_chan_cb.cbk)
495 psoc_priv_obj->conn_chan_cb.cbk = cbk;
496 qdf_spin_unlock_bh(&psoc_priv_obj->cbk_list_lock);
497 }
498
499 void
reg_unregister_is_chan_connected_callback(struct wlan_objmgr_psoc * psoc,reg_get_connected_chan_for_mode_callback cbk)500 reg_unregister_is_chan_connected_callback(struct wlan_objmgr_psoc *psoc,
501 reg_get_connected_chan_for_mode_callback cbk)
502 {
503 struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj;
504
505 psoc_priv_obj = reg_get_psoc_obj(psoc);
506 if (!psoc_priv_obj) {
507 reg_err("reg psoc private obj is NULL");
508 return;
509 }
510
511 qdf_spin_lock_bh(&psoc_priv_obj->cbk_list_lock);
512 if (psoc_priv_obj->conn_chan_cb.cbk == cbk)
513 psoc_priv_obj->conn_chan_cb.cbk = NULL;
514 qdf_spin_unlock_bh(&psoc_priv_obj->cbk_list_lock);
515 }
516