xref: /wlan-dirver/qca-wifi-host-cmn/hif/src/hif_main.c (revision 332fc3b9ebc8904452cc5549ba2e3fbdd76a8472)
1 /*
2  * Copyright (c) 2015-2021 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2021-2024 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 #include "targcfg.h"
21 #include "qdf_lock.h"
22 #include "qdf_status.h"
23 #include "qdf_status.h"
24 #include <qdf_atomic.h>         /* qdf_atomic_read */
25 #include <targaddrs.h>
26 #include "hif_io32.h"
27 #include <hif.h>
28 #include <target_type.h>
29 #include "regtable.h"
30 #define ATH_MODULE_NAME hif
31 #include <a_debug.h>
32 #include "hif_main.h"
33 #include "hif_hw_version.h"
34 #if (defined(HIF_PCI) || defined(HIF_SNOC) || defined(HIF_AHB) || \
35      defined(HIF_IPCI))
36 #include "ce_tasklet.h"
37 #include "ce_api.h"
38 #endif
39 #include "qdf_trace.h"
40 #include "qdf_status.h"
41 #include "hif_debug.h"
42 #include "mp_dev.h"
43 #if defined(QCA_WIFI_QCA8074) || defined(QCA_WIFI_QCA6018) || \
44 	defined(QCA_WIFI_QCA5018) || defined(QCA_WIFI_QCA9574) || \
45 	defined(QCA_WIFI_QCA5332)
46 #include "hal_api.h"
47 #endif
48 #include "hif_napi.h"
49 #include "hif_unit_test_suspend_i.h"
50 #include "qdf_module.h"
51 #ifdef HIF_CE_LOG_INFO
52 #include <qdf_notifier.h>
53 #include <qdf_hang_event_notifier.h>
54 #endif
55 #include <linux/cpumask.h>
56 
57 #include <pld_common.h>
58 #include "ce_internal.h"
59 #include <qdf_tracepoint.h>
60 #include "qdf_ssr_driver_dump.h"
61 
62 void hif_dump(struct hif_opaque_softc *hif_ctx, uint8_t cmd_id, bool start)
63 {
64 	hif_trigger_dump(hif_ctx, cmd_id, start);
65 }
66 
67 /**
68  * hif_get_target_id(): hif_get_target_id
69  * @scn: scn
70  *
71  * Return the virtual memory base address to the caller
72  *
73  * @scn: hif_softc
74  *
75  * Return: A_target_id_t
76  */
77 A_target_id_t hif_get_target_id(struct hif_softc *scn)
78 {
79 	return scn->mem;
80 }
81 
82 /**
83  * hif_get_targetdef(): hif_get_targetdef
84  * @hif_ctx: hif context
85  *
86  * Return: void *
87  */
88 void *hif_get_targetdef(struct hif_opaque_softc *hif_ctx)
89 {
90 	struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
91 
92 	return scn->targetdef;
93 }
94 
95 #ifdef FORCE_WAKE
96 #ifndef QCA_WIFI_WCN6450
97 void hif_srng_init_phase(struct hif_opaque_softc *hif_ctx,
98 			 bool init_phase)
99 {
100 	struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
101 
102 	if (ce_srng_based(scn))
103 		hal_set_init_phase(scn->hal_soc, init_phase);
104 }
105 #else
106 void hif_srng_init_phase(struct hif_opaque_softc *hif_ctx,
107 			 bool init_phase)
108 {
109 	struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
110 
111 	hal_set_init_phase(scn->hal_soc, init_phase);
112 }
113 #endif
114 #endif /* FORCE_WAKE */
115 
116 #ifdef HIF_IPCI
117 void hif_shutdown_notifier_cb(void *hif_ctx)
118 {
119 	struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
120 
121 	scn->recovery = true;
122 }
123 #endif
124 
125 /**
126  * hif_vote_link_down(): unvote for link up
127  * @hif_ctx: hif context
128  *
129  * Call hif_vote_link_down to release a previous request made using
130  * hif_vote_link_up. A hif_vote_link_down call should only be made
131  * after a corresponding hif_vote_link_up, otherwise you could be
132  * negating a vote from another source. When no votes are present
133  * hif will not guarantee the linkstate after hif_bus_suspend.
134  *
135  * SYNCHRONIZE WITH hif_vote_link_up by only calling in MC thread
136  * and initialization deinitialization sequencences.
137  *
138  * Return: n/a
139  */
140 void hif_vote_link_down(struct hif_opaque_softc *hif_ctx)
141 {
142 	struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
143 
144 	QDF_BUG(scn);
145 	if (scn->linkstate_vote == 0)
146 		QDF_DEBUG_PANIC("linkstate_vote(%d) has already been 0",
147 				scn->linkstate_vote);
148 
149 	scn->linkstate_vote--;
150 	hif_info("Down_linkstate_vote %d", scn->linkstate_vote);
151 	if (scn->linkstate_vote == 0)
152 		hif_bus_prevent_linkdown(scn, false);
153 }
154 
155 /**
156  * hif_vote_link_up(): vote to prevent bus from suspending
157  * @hif_ctx: hif context
158  *
159  * Makes hif guarantee that fw can message the host normally
160  * during suspend.
161  *
162  * SYNCHRONIZE WITH hif_vote_link_up by only calling in MC thread
163  * and initialization deinitialization sequencences.
164  *
165  * Return: n/a
166  */
167 void hif_vote_link_up(struct hif_opaque_softc *hif_ctx)
168 {
169 	struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
170 
171 	QDF_BUG(scn);
172 	scn->linkstate_vote++;
173 	hif_info("Up_linkstate_vote %d", scn->linkstate_vote);
174 	if (scn->linkstate_vote == 1)
175 		hif_bus_prevent_linkdown(scn, true);
176 }
177 
178 /**
179  * hif_can_suspend_link(): query if hif is permitted to suspend the link
180  * @hif_ctx: hif context
181  *
182  * Hif will ensure that the link won't be suspended if the upperlayers
183  * don't want it to.
184  *
185  * SYNCHRONIZATION: MC thread is stopped before bus suspend thus
186  * we don't need extra locking to ensure votes dont change while
187  * we are in the process of suspending or resuming.
188  *
189  * Return: false if hif will guarantee link up during suspend.
190  */
191 bool hif_can_suspend_link(struct hif_opaque_softc *hif_ctx)
192 {
193 	struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
194 
195 	QDF_BUG(scn);
196 	return scn->linkstate_vote == 0;
197 }
198 
199 /**
200  * hif_hia_item_address(): hif_hia_item_address
201  * @target_type: target_type
202  * @item_offset: item_offset
203  *
204  * Return: n/a
205  */
206 uint32_t hif_hia_item_address(uint32_t target_type, uint32_t item_offset)
207 {
208 	switch (target_type) {
209 	case TARGET_TYPE_AR6002:
210 		return AR6002_HOST_INTEREST_ADDRESS + item_offset;
211 	case TARGET_TYPE_AR6003:
212 		return AR6003_HOST_INTEREST_ADDRESS + item_offset;
213 	case TARGET_TYPE_AR6004:
214 		return AR6004_HOST_INTEREST_ADDRESS + item_offset;
215 	case TARGET_TYPE_AR6006:
216 		return AR6006_HOST_INTEREST_ADDRESS + item_offset;
217 	case TARGET_TYPE_AR9888:
218 		return AR9888_HOST_INTEREST_ADDRESS + item_offset;
219 	case TARGET_TYPE_AR6320:
220 	case TARGET_TYPE_AR6320V2:
221 		return AR6320_HOST_INTEREST_ADDRESS + item_offset;
222 	case TARGET_TYPE_ADRASTEA:
223 		/* ADRASTEA doesn't have a host interest address */
224 		ASSERT(0);
225 		return 0;
226 	case TARGET_TYPE_AR900B:
227 		return AR900B_HOST_INTEREST_ADDRESS + item_offset;
228 	case TARGET_TYPE_QCA9984:
229 		return QCA9984_HOST_INTEREST_ADDRESS + item_offset;
230 	case TARGET_TYPE_QCA9888:
231 		return QCA9888_HOST_INTEREST_ADDRESS + item_offset;
232 
233 	default:
234 		ASSERT(0);
235 		return 0;
236 	}
237 }
238 
239 /**
240  * hif_max_num_receives_reached() - check max receive is reached
241  * @scn: HIF Context
242  * @count: unsigned int.
243  *
244  * Output check status as bool
245  *
246  * Return: bool
247  */
248 bool hif_max_num_receives_reached(struct hif_softc *scn, unsigned int count)
249 {
250 	if (QDF_IS_EPPING_ENABLED(hif_get_conparam(scn)))
251 		return count > 120;
252 	else
253 		return count > MAX_NUM_OF_RECEIVES;
254 }
255 
256 /**
257  * init_buffer_count() - initial buffer count
258  * @maxSize: qdf_size_t
259  *
260  * routine to modify the initial buffer count to be allocated on an os
261  * platform basis. Platform owner will need to modify this as needed
262  *
263  * Return: qdf_size_t
264  */
265 qdf_size_t init_buffer_count(qdf_size_t maxSize)
266 {
267 	return maxSize;
268 }
269 
270 /**
271  * hif_save_htc_htt_config_endpoint() - save htt_tx_endpoint
272  * @hif_ctx: hif context
273  * @htc_htt_tx_endpoint: htt_tx_endpoint
274  *
275  * Return: void
276  */
277 void hif_save_htc_htt_config_endpoint(struct hif_opaque_softc *hif_ctx,
278 							int htc_htt_tx_endpoint)
279 {
280 	struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
281 
282 	if (!scn) {
283 		hif_err("scn or scn->hif_sc is NULL!");
284 		return;
285 	}
286 
287 	scn->htc_htt_tx_endpoint = htc_htt_tx_endpoint;
288 }
289 qdf_export_symbol(hif_save_htc_htt_config_endpoint);
290 
291 static const struct qwlan_hw qwlan_hw_list[] = {
292 	{
293 		.id = AR6320_REV1_VERSION,
294 		.subid = 0,
295 		.name = "QCA6174_REV1",
296 	},
297 	{
298 		.id = AR6320_REV1_1_VERSION,
299 		.subid = 0x1,
300 		.name = "QCA6174_REV1_1",
301 	},
302 	{
303 		.id = AR6320_REV1_3_VERSION,
304 		.subid = 0x2,
305 		.name = "QCA6174_REV1_3",
306 	},
307 	{
308 		.id = AR6320_REV2_1_VERSION,
309 		.subid = 0x4,
310 		.name = "QCA6174_REV2_1",
311 	},
312 	{
313 		.id = AR6320_REV2_1_VERSION,
314 		.subid = 0x5,
315 		.name = "QCA6174_REV2_2",
316 	},
317 	{
318 		.id = AR6320_REV3_VERSION,
319 		.subid = 0x6,
320 		.name = "QCA6174_REV2.3",
321 	},
322 	{
323 		.id = AR6320_REV3_VERSION,
324 		.subid = 0x8,
325 		.name = "QCA6174_REV3",
326 	},
327 	{
328 		.id = AR6320_REV3_VERSION,
329 		.subid = 0x9,
330 		.name = "QCA6174_REV3_1",
331 	},
332 	{
333 		.id = AR6320_REV3_2_VERSION,
334 		.subid = 0xA,
335 		.name = "AR6320_REV3_2_VERSION",
336 	},
337 	{
338 		.id = QCA6390_V1,
339 		.subid = 0x0,
340 		.name = "QCA6390_V1",
341 	},
342 	{
343 		.id = QCA6490_V1,
344 		.subid = 0x0,
345 		.name = "QCA6490_V1",
346 	},
347 	{
348 		.id = WCN3990_v1,
349 		.subid = 0x0,
350 		.name = "WCN3990_V1",
351 	},
352 	{
353 		.id = WCN3990_v2,
354 		.subid = 0x0,
355 		.name = "WCN3990_V2",
356 	},
357 	{
358 		.id = WCN3990_v2_1,
359 		.subid = 0x0,
360 		.name = "WCN3990_V2.1",
361 	},
362 	{
363 		.id = WCN3998,
364 		.subid = 0x0,
365 		.name = "WCN3998",
366 	},
367 	{
368 		.id = QCA9379_REV1_VERSION,
369 		.subid = 0xC,
370 		.name = "QCA9379_REV1",
371 	},
372 	{
373 		.id = QCA9379_REV1_VERSION,
374 		.subid = 0xD,
375 		.name = "QCA9379_REV1_1",
376 	},
377 	{
378 		.id = MANGO_V1,
379 		.subid = 0xF,
380 		.name = "MANGO_V1",
381 	},
382 	{
383 		.id = PEACH_V1,
384 		.subid = 0,
385 		.name = "PEACH_V1",
386 	},
387 
388 	{
389 		.id = KIWI_V1,
390 		.subid = 0,
391 		.name = "KIWI_V1",
392 	},
393 	{
394 		.id = KIWI_V2,
395 		.subid = 0,
396 		.name = "KIWI_V2",
397 	},
398 	{
399 		.id = WCN6750_V1,
400 		.subid = 0,
401 		.name = "WCN6750_V1",
402 	},
403 	{
404 		.id = WCN6750_V2,
405 		.subid = 0,
406 		.name = "WCN6750_V2",
407 	},
408 	{
409 		.id = WCN6450_V1,
410 		.subid = 0,
411 		.name = "WCN6450_V1",
412 	},
413 	{
414 		.id = QCA6490_v2_1,
415 		.subid = 0,
416 		.name = "QCA6490",
417 	},
418 	{
419 		.id = QCA6490_v2,
420 		.subid = 0,
421 		.name = "QCA6490",
422 	},
423 	{
424 		.id = WCN3990_TALOS,
425 		.subid = 0,
426 		.name = "WCN3990",
427 	},
428 	{
429 		.id = WCN3990_MOOREA,
430 		.subid = 0,
431 		.name = "WCN3990",
432 	},
433 	{
434 		.id = WCN3990_SAIPAN,
435 		.subid = 0,
436 		.name = "WCN3990",
437 	},
438 	{
439 		.id = WCN3990_RENNELL,
440 		.subid = 0,
441 		.name = "WCN3990",
442 	},
443 	{
444 		.id = WCN3990_BITRA,
445 		.subid = 0,
446 		.name = "WCN3990",
447 	},
448 	{
449 		.id = WCN3990_DIVAR,
450 		.subid = 0,
451 		.name = "WCN3990",
452 	},
453 	{
454 		.id = WCN3990_ATHERTON,
455 		.subid = 0,
456 		.name = "WCN3990",
457 	},
458 	{
459 		.id = WCN3990_STRAIT,
460 		.subid = 0,
461 		.name = "WCN3990",
462 	},
463 	{
464 		.id = WCN3990_NETRANI,
465 		.subid = 0,
466 		.name = "WCN3990",
467 	},
468 	{
469 		.id = WCN3990_CLARENCE,
470 		.subid = 0,
471 		.name = "WCN3990",
472 	}
473 };
474 
475 /**
476  * hif_get_hw_name(): get a human readable name for the hardware
477  * @info: Target Info
478  *
479  * Return: human readable name for the underlying wifi hardware.
480  */
481 static const char *hif_get_hw_name(struct hif_target_info *info)
482 {
483 	int i;
484 
485 	hif_debug("target version = %d, target revision = %d",
486 		  info->target_version,
487 		  info->target_revision);
488 
489 	if (info->hw_name)
490 		return info->hw_name;
491 
492 	for (i = 0; i < ARRAY_SIZE(qwlan_hw_list); i++) {
493 		if (info->target_version == qwlan_hw_list[i].id &&
494 		    info->target_revision == qwlan_hw_list[i].subid) {
495 			return qwlan_hw_list[i].name;
496 		}
497 	}
498 
499 	info->hw_name = qdf_mem_malloc(64);
500 	if (!info->hw_name)
501 		return "Unknown Device (nomem)";
502 
503 	i = qdf_snprint(info->hw_name, 64, "HW_VERSION=%x.",
504 			info->target_version);
505 	if (i < 0)
506 		return "Unknown Device (snprintf failure)";
507 	else
508 		return info->hw_name;
509 }
510 
511 /**
512  * hif_get_hw_info(): hif_get_hw_info
513  * @scn: scn
514  * @version: version
515  * @revision: revision
516  * @target_name: target name
517  *
518  * Return: n/a
519  */
520 void hif_get_hw_info(struct hif_opaque_softc *scn, u32 *version, u32 *revision,
521 			const char **target_name)
522 {
523 	struct hif_target_info *info = hif_get_target_info_handle(scn);
524 	struct hif_softc *sc = HIF_GET_SOFTC(scn);
525 
526 	if (sc->bus_type == QDF_BUS_TYPE_USB)
527 		hif_usb_get_hw_info(sc);
528 
529 	*version = info->target_version;
530 	*revision = info->target_revision;
531 	*target_name = hif_get_hw_name(info);
532 }
533 
534 /**
535  * hif_get_dev_ba(): API to get device base address.
536  * @hif_handle: hif handle
537  *
538  * Return: device base address
539  */
540 void *hif_get_dev_ba(struct hif_opaque_softc *hif_handle)
541 {
542 	struct hif_softc *scn = (struct hif_softc *)hif_handle;
543 
544 	return scn->mem;
545 }
546 qdf_export_symbol(hif_get_dev_ba);
547 
548 /**
549  * hif_get_dev_ba_ce(): API to get device ce base address.
550  * @hif_handle: hif handle
551  *
552  * Return: dev mem base address for CE
553  */
554 void *hif_get_dev_ba_ce(struct hif_opaque_softc *hif_handle)
555 {
556 	struct hif_softc *scn = (struct hif_softc *)hif_handle;
557 
558 	return scn->mem_ce;
559 }
560 
561 qdf_export_symbol(hif_get_dev_ba_ce);
562 
563 /**
564  * hif_get_dev_ba_pmm(): API to get device pmm base address.
565  * @hif_handle: scn
566  *
567  * Return: dev mem base address for PMM
568  */
569 
570 void *hif_get_dev_ba_pmm(struct hif_opaque_softc *hif_handle)
571 {
572 	struct hif_softc *scn = (struct hif_softc *)hif_handle;
573 
574 	return scn->mem_pmm_base;
575 }
576 
577 qdf_export_symbol(hif_get_dev_ba_pmm);
578 
579 uint32_t hif_get_soc_version(struct hif_opaque_softc *hif_handle)
580 {
581 	struct hif_softc *scn = (struct hif_softc *)hif_handle;
582 
583 	return scn->target_info.soc_version;
584 }
585 
586 qdf_export_symbol(hif_get_soc_version);
587 
588 /**
589  * hif_get_dev_ba_cmem(): API to get device ce base address.
590  * @hif_handle: hif handle
591  *
592  * Return: dev mem base address for CMEM
593  */
594 void *hif_get_dev_ba_cmem(struct hif_opaque_softc *hif_handle)
595 {
596 	struct hif_softc *scn = (struct hif_softc *)hif_handle;
597 
598 	return scn->mem_cmem;
599 }
600 
601 qdf_export_symbol(hif_get_dev_ba_cmem);
602 
603 #ifdef FEATURE_RUNTIME_PM
604 void hif_runtime_prevent_linkdown(struct hif_softc *scn, bool is_get)
605 {
606 	if (is_get)
607 		qdf_runtime_pm_prevent_suspend(&scn->prevent_linkdown_lock);
608 	else
609 		qdf_runtime_pm_allow_suspend(&scn->prevent_linkdown_lock);
610 }
611 
612 static inline
613 void hif_rtpm_lock_init(struct hif_softc *scn)
614 {
615 	qdf_runtime_lock_init(&scn->prevent_linkdown_lock);
616 }
617 
618 static inline
619 void hif_rtpm_lock_deinit(struct hif_softc *scn)
620 {
621 	qdf_runtime_lock_deinit(&scn->prevent_linkdown_lock);
622 }
623 #else
624 static inline
625 void hif_rtpm_lock_init(struct hif_softc *scn)
626 {
627 }
628 
629 static inline
630 void hif_rtpm_lock_deinit(struct hif_softc *scn)
631 {
632 }
633 #endif
634 
635 #ifdef WLAN_CE_INTERRUPT_THRESHOLD_CONFIG
636 /**
637  * hif_get_interrupt_threshold_cfg_from_psoc() - Retrieve ini cfg from psoc
638  * @scn: hif context
639  * @psoc: psoc objmgr handle
640  *
641  * Return: None
642  */
643 static inline
644 void hif_get_interrupt_threshold_cfg_from_psoc(struct hif_softc *scn,
645 					       struct wlan_objmgr_psoc *psoc)
646 {
647 	if (psoc) {
648 		scn->ini_cfg.ce_status_ring_timer_threshold =
649 			cfg_get(psoc,
650 				CFG_CE_STATUS_RING_TIMER_THRESHOLD);
651 		scn->ini_cfg.ce_status_ring_batch_count_threshold =
652 			cfg_get(psoc,
653 				CFG_CE_STATUS_RING_BATCH_COUNT_THRESHOLD);
654 	}
655 }
656 #else
657 static inline
658 void hif_get_interrupt_threshold_cfg_from_psoc(struct hif_softc *scn,
659 					       struct wlan_objmgr_psoc *psoc)
660 {
661 }
662 #endif /* WLAN_CE_INTERRUPT_THRESHOLD_CONFIG */
663 
664 /**
665  * hif_get_cfg_from_psoc() - Retrieve ini cfg from psoc
666  * @scn: hif context
667  * @psoc: psoc objmgr handle
668  *
669  * Return: None
670  */
671 static inline
672 void hif_get_cfg_from_psoc(struct hif_softc *scn,
673 			   struct wlan_objmgr_psoc *psoc)
674 {
675 	if (psoc) {
676 		scn->ini_cfg.disable_wake_irq =
677 			cfg_get(psoc, CFG_DISABLE_WAKE_IRQ);
678 		/**
679 		 * Wake IRQ can't share the same IRQ with the copy engines
680 		 * In one MSI mode, we don't know whether wake IRQ is triggered
681 		 * or not in wake IRQ handler. known issue CR 2055359
682 		 * If you want to support Wake IRQ. Please allocate at least
683 		 * 2 MSI vector. The first is for wake IRQ while the others
684 		 * share the second vector
685 		 */
686 		if (pld_is_one_msi(scn->qdf_dev->dev)) {
687 			hif_debug("Disable wake IRQ once it is one MSI mode");
688 			scn->ini_cfg.disable_wake_irq = true;
689 		}
690 		hif_get_interrupt_threshold_cfg_from_psoc(scn, psoc);
691 	}
692 }
693 
694 #if defined(HIF_CE_LOG_INFO) || defined(HIF_BUS_LOG_INFO)
695 /**
696  * hif_recovery_notifier_cb - Recovery notifier callback to log
697  *  hang event data
698  * @block: notifier block
699  * @state: state
700  * @data: notifier data
701  *
702  * Return: status
703  */
704 static
705 int hif_recovery_notifier_cb(struct notifier_block *block, unsigned long state,
706 			     void *data)
707 {
708 	struct qdf_notifer_data *notif_data = data;
709 	qdf_notif_block *notif_block;
710 	struct hif_softc *hif_handle;
711 	bool bus_id_invalid;
712 
713 	if (!data || !block)
714 		return -EINVAL;
715 
716 	notif_block = qdf_container_of(block, qdf_notif_block, notif_block);
717 
718 	hif_handle = notif_block->priv_data;
719 	if (!hif_handle)
720 		return -EINVAL;
721 
722 	bus_id_invalid = hif_log_bus_info(hif_handle, notif_data->hang_data,
723 					  &notif_data->offset);
724 	if (bus_id_invalid)
725 		return NOTIFY_STOP_MASK;
726 
727 	hif_log_ce_info(hif_handle, notif_data->hang_data,
728 			&notif_data->offset);
729 
730 	return 0;
731 }
732 
733 /**
734  * hif_register_recovery_notifier - Register hif recovery notifier
735  * @hif_handle: hif handle
736  *
737  * Return: status
738  */
739 static
740 QDF_STATUS hif_register_recovery_notifier(struct hif_softc *hif_handle)
741 {
742 	qdf_notif_block *hif_notifier;
743 
744 	if (!hif_handle)
745 		return QDF_STATUS_E_FAILURE;
746 
747 	hif_notifier = &hif_handle->hif_recovery_notifier;
748 
749 	hif_notifier->notif_block.notifier_call = hif_recovery_notifier_cb;
750 	hif_notifier->priv_data = hif_handle;
751 	return qdf_hang_event_register_notifier(hif_notifier);
752 }
753 
754 /**
755  * hif_unregister_recovery_notifier - Un-register hif recovery notifier
756  * @hif_handle: hif handle
757  *
758  * Return: status
759  */
760 static
761 QDF_STATUS hif_unregister_recovery_notifier(struct hif_softc *hif_handle)
762 {
763 	qdf_notif_block *hif_notifier = &hif_handle->hif_recovery_notifier;
764 
765 	return qdf_hang_event_unregister_notifier(hif_notifier);
766 }
767 #else
768 static inline
769 QDF_STATUS hif_register_recovery_notifier(struct hif_softc *hif_handle)
770 {
771 	return QDF_STATUS_SUCCESS;
772 }
773 
774 static inline
775 QDF_STATUS hif_unregister_recovery_notifier(struct hif_softc *hif_handle)
776 {
777 	return QDF_STATUS_SUCCESS;
778 }
779 #endif
780 
781 #if defined(HIF_CPU_PERF_AFFINE_MASK) || \
782 	defined(FEATURE_ENABLE_CE_DP_IRQ_AFFINE)
783 /**
784  * __hif_cpu_hotplug_notify() - CPU hotplug event handler
785  * @context: HIF context
786  * @cpu: CPU Id of the CPU generating the event
787  * @cpu_up: true if the CPU is online
788  *
789  * Return: None
790  */
791 static void __hif_cpu_hotplug_notify(void *context,
792 				     uint32_t cpu, bool cpu_up)
793 {
794 	struct hif_softc *scn = context;
795 
796 	if (!scn)
797 		return;
798 	if (hif_is_driver_unloading(scn) || hif_is_recovery_in_progress(scn))
799 		return;
800 
801 	if (cpu_up) {
802 		hif_config_irq_set_perf_affinity_hint(GET_HIF_OPAQUE_HDL(scn));
803 		hif_debug("Setting affinity for online CPU: %d", cpu);
804 	} else {
805 		hif_debug("Skip setting affinity for offline CPU: %d", cpu);
806 	}
807 }
808 
809 /**
810  * hif_cpu_hotplug_notify - cpu core up/down notification
811  * handler
812  * @context: HIF context
813  * @cpu: CPU generating the event
814  * @cpu_up: true if the CPU is online
815  *
816  * Return: None
817  */
818 static void hif_cpu_hotplug_notify(void *context, uint32_t cpu, bool cpu_up)
819 {
820 	struct qdf_op_sync *op_sync;
821 
822 	if (qdf_op_protect(&op_sync))
823 		return;
824 
825 	__hif_cpu_hotplug_notify(context, cpu, cpu_up);
826 
827 	qdf_op_unprotect(op_sync);
828 }
829 
830 static void hif_cpu_online_cb(void *context, uint32_t cpu)
831 {
832 	hif_cpu_hotplug_notify(context, cpu, true);
833 }
834 
835 static void hif_cpu_before_offline_cb(void *context, uint32_t cpu)
836 {
837 	hif_cpu_hotplug_notify(context, cpu, false);
838 }
839 
840 static void hif_cpuhp_register(struct hif_softc *scn)
841 {
842 	if (!scn) {
843 		hif_info_high("cannot register hotplug notifiers");
844 		return;
845 	}
846 	qdf_cpuhp_register(&scn->cpuhp_event_handle,
847 			   scn,
848 			   hif_cpu_online_cb,
849 			   hif_cpu_before_offline_cb);
850 }
851 
852 static void hif_cpuhp_unregister(struct hif_softc *scn)
853 {
854 	if (!scn) {
855 		hif_info_high("cannot unregister hotplug notifiers");
856 		return;
857 	}
858 	qdf_cpuhp_unregister(&scn->cpuhp_event_handle);
859 }
860 
861 #else
862 static void hif_cpuhp_register(struct hif_softc *scn)
863 {
864 }
865 
866 static void hif_cpuhp_unregister(struct hif_softc *scn)
867 {
868 }
869 #endif /* ifdef HIF_CPU_PERF_AFFINE_MASK */
870 
871 #ifdef HIF_DETECTION_LATENCY_ENABLE
872 /*
873  * Bitmask to control enablement of latency detection for the tasklets,
874  * bit-X represents for tasklet of WLAN_CE_X.
875  */
876 #ifndef DETECTION_LATENCY_TASKLET_MASK
877 #define DETECTION_LATENCY_TASKLET_MASK (BIT(2) | BIT(7))
878 #endif
879 
880 static inline int
881 __hif_tasklet_latency(struct hif_softc *scn, bool from_timer, int idx)
882 {
883 	qdf_time_t sched_time =
884 		scn->latency_detect.tasklet_info[idx].sched_time;
885 	qdf_time_t exec_time =
886 		scn->latency_detect.tasklet_info[idx].exec_time;
887 	qdf_time_t curr_time = qdf_system_ticks();
888 	uint32_t threshold = scn->latency_detect.threshold;
889 	qdf_time_t expect_exec_time =
890 		sched_time + qdf_system_msecs_to_ticks(threshold);
891 
892 	/* 2 kinds of check here.
893 	 * from_timer==true:  check if tasklet stall
894 	 * from_timer==false: check tasklet execute comes late
895 	 */
896 	if (from_timer ?
897 	    (qdf_system_time_after(sched_time, exec_time) &&
898 	     qdf_system_time_after(curr_time, expect_exec_time)) :
899 	    qdf_system_time_after(exec_time, expect_exec_time)) {
900 		hif_err("tasklet[%d] latency detected: from_timer %d, curr_time %lu, sched_time %lu, exec_time %lu, threshold %ums, timeout %ums, cpu_id %d, called: %ps",
901 			idx, from_timer, curr_time, sched_time,
902 			exec_time, threshold,
903 			scn->latency_detect.timeout,
904 			qdf_get_cpu(), (void *)_RET_IP_);
905 		qdf_trigger_self_recovery(NULL,
906 					  QDF_TASKLET_CREDIT_LATENCY_DETECT);
907 		return -ETIMEDOUT;
908 	}
909 
910 	return 0;
911 }
912 
913 /**
914  * hif_tasklet_latency_detect_enabled() - check whether latency detect
915  * is enabled for the tasklet which is specified by idx
916  * @scn: HIF opaque context
917  * @idx: CE id
918  *
919  * Return: true if latency detect is enabled for the specified tasklet,
920  * false otherwise.
921  */
922 static inline bool
923 hif_tasklet_latency_detect_enabled(struct hif_softc *scn, int idx)
924 {
925 	if (QDF_GLOBAL_MISSION_MODE != hif_get_conparam(scn))
926 		return false;
927 
928 	if (!scn->latency_detect.enable_detection)
929 		return false;
930 
931 	if (idx < 0 || idx >= HIF_TASKLET_IN_MONITOR ||
932 	    !qdf_test_bit(idx, scn->latency_detect.tasklet_bmap))
933 		return false;
934 
935 	return true;
936 }
937 
938 void hif_tasklet_latency_record_exec(struct hif_softc *scn, int idx)
939 {
940 	if (!hif_tasklet_latency_detect_enabled(scn, idx))
941 		return;
942 
943 	/*
944 	 * hif_set_enable_detection(true) might come between
945 	 * hif_tasklet_latency_record_sched() and
946 	 * hif_tasklet_latency_record_exec() during wlan startup, then the
947 	 * sched_time is 0 but exec_time is not, and hit the timeout case in
948 	 * __hif_tasklet_latency().
949 	 * To avoid such issue, skip exec_time recording if sched_time has not
950 	 * been recorded.
951 	 */
952 	if (!scn->latency_detect.tasklet_info[idx].sched_time)
953 		return;
954 
955 	scn->latency_detect.tasklet_info[idx].exec_time = qdf_system_ticks();
956 	__hif_tasklet_latency(scn, false, idx);
957 }
958 
959 void hif_tasklet_latency_record_sched(struct hif_softc *scn, int idx)
960 {
961 	if (!hif_tasklet_latency_detect_enabled(scn, idx))
962 		return;
963 
964 	scn->latency_detect.tasklet_info[idx].sched_cpuid = qdf_get_cpu();
965 	scn->latency_detect.tasklet_info[idx].sched_time = qdf_system_ticks();
966 }
967 
968 static inline void hif_credit_latency(struct hif_softc *scn, bool from_timer)
969 {
970 	qdf_time_t credit_request_time =
971 		scn->latency_detect.credit_request_time;
972 	qdf_time_t credit_report_time = scn->latency_detect.credit_report_time;
973 	qdf_time_t curr_jiffies = qdf_system_ticks();
974 	uint32_t threshold = scn->latency_detect.threshold;
975 	int cpu_id = qdf_get_cpu();
976 
977 	/* 2 kinds of check here.
978 	 * from_timer==true:  check if credit report stall
979 	 * from_timer==false: check credit report comes late
980 	 */
981 
982 	if ((from_timer ?
983 	     qdf_system_time_after(credit_request_time, credit_report_time) :
984 	     qdf_system_time_after(credit_report_time, credit_request_time)) &&
985 	    qdf_system_time_after(curr_jiffies,
986 				  credit_request_time +
987 				  qdf_system_msecs_to_ticks(threshold))) {
988 		hif_err("credit report latency: from timer %d, curr_jiffies %lu, credit_request_time %lu, credit_report_time %lu, threshold %ums, timeout %ums, cpu_id %d, called: %ps",
989 			from_timer, curr_jiffies, credit_request_time,
990 			credit_report_time, threshold,
991 			scn->latency_detect.timeout,
992 			cpu_id, (void *)_RET_IP_);
993 		goto latency;
994 	}
995 	return;
996 
997 latency:
998 	qdf_trigger_self_recovery(NULL, QDF_TASKLET_CREDIT_LATENCY_DETECT);
999 }
1000 
1001 static inline void hif_tasklet_latency(struct hif_softc *scn, bool from_timer)
1002 {
1003 	int i, ret;
1004 
1005 	for (i = 0; i < HIF_TASKLET_IN_MONITOR; i++) {
1006 		if (!qdf_test_bit(i, scn->latency_detect.tasklet_bmap))
1007 			continue;
1008 
1009 		ret = __hif_tasklet_latency(scn, from_timer, i);
1010 		if (ret)
1011 			return;
1012 	}
1013 }
1014 
1015 /**
1016  * hif_check_detection_latency(): to check if latency for tasklet/credit
1017  *
1018  * @scn: hif context
1019  * @from_timer: if called from timer handler
1020  * @bitmap_type: indicate if check tasklet or credit
1021  *
1022  * Return: none
1023  */
1024 void hif_check_detection_latency(struct hif_softc *scn,
1025 				 bool from_timer,
1026 				 uint32_t bitmap_type)
1027 {
1028 	if (QDF_GLOBAL_MISSION_MODE != hif_get_conparam(scn))
1029 		return;
1030 
1031 	if (!scn->latency_detect.enable_detection)
1032 		return;
1033 
1034 	if (bitmap_type & BIT(HIF_DETECT_TASKLET))
1035 		hif_tasklet_latency(scn, from_timer);
1036 
1037 	if (bitmap_type & BIT(HIF_DETECT_CREDIT))
1038 		hif_credit_latency(scn, from_timer);
1039 }
1040 
1041 static void hif_latency_detect_timeout_handler(void *arg)
1042 {
1043 	struct hif_softc *scn = (struct hif_softc *)arg;
1044 	int next_cpu, i;
1045 	qdf_cpu_mask cpu_mask = {0};
1046 	struct hif_latency_detect *detect = &scn->latency_detect;
1047 
1048 	hif_check_detection_latency(scn, true,
1049 				    BIT(HIF_DETECT_TASKLET) |
1050 				    BIT(HIF_DETECT_CREDIT));
1051 
1052 	/* it need to make sure timer start on a different cpu,
1053 	 * so it can detect the tasklet schedule stall, but there
1054 	 * is still chance that, after timer has been started, then
1055 	 * irq/tasklet happens on the same cpu, then tasklet will
1056 	 * execute before softirq timer, if this tasklet stall, the
1057 	 * timer can't detect it, we can accept this as a limitation,
1058 	 * if tasklet stall, anyway other place will detect it, just
1059 	 * a little later.
1060 	 */
1061 	qdf_cpumask_copy(&cpu_mask, (const qdf_cpu_mask *)cpu_active_mask);
1062 	for (i = 0; i < HIF_TASKLET_IN_MONITOR; i++) {
1063 		if (!qdf_test_bit(i, detect->tasklet_bmap))
1064 			continue;
1065 
1066 		qdf_cpumask_clear_cpu(detect->tasklet_info[i].sched_cpuid,
1067 				      &cpu_mask);
1068 	}
1069 
1070 	next_cpu = cpumask_first(&cpu_mask);
1071 	if (qdf_unlikely(next_cpu >= nr_cpu_ids)) {
1072 		hif_debug("start timer on local");
1073 		/* it doesn't found a available cpu, start on local cpu*/
1074 		qdf_timer_mod(&detect->timer, detect->timeout);
1075 	} else {
1076 		qdf_timer_start_on(&detect->timer, detect->timeout, next_cpu);
1077 	}
1078 }
1079 
1080 static void hif_latency_detect_timer_init(struct hif_softc *scn)
1081 {
1082 	scn->latency_detect.timeout =
1083 		DETECTION_TIMER_TIMEOUT;
1084 	scn->latency_detect.threshold =
1085 		DETECTION_LATENCY_THRESHOLD;
1086 
1087 	hif_info("timer timeout %u, latency threshold %u",
1088 		 scn->latency_detect.timeout,
1089 		 scn->latency_detect.threshold);
1090 
1091 	scn->latency_detect.is_timer_started = false;
1092 
1093 	qdf_timer_init(NULL,
1094 		       &scn->latency_detect.timer,
1095 		       &hif_latency_detect_timeout_handler,
1096 		       scn,
1097 		       QDF_TIMER_TYPE_SW_SPIN);
1098 }
1099 
1100 static void hif_latency_detect_timer_deinit(struct hif_softc *scn)
1101 {
1102 	hif_info("deinit timer");
1103 	qdf_timer_free(&scn->latency_detect.timer);
1104 }
1105 
1106 static void hif_latency_detect_init(struct hif_softc *scn)
1107 {
1108 	uint32_t tasklet_mask;
1109 	int i;
1110 
1111 	if (QDF_GLOBAL_MISSION_MODE != hif_get_conparam(scn))
1112 		return;
1113 
1114 	tasklet_mask = DETECTION_LATENCY_TASKLET_MASK;
1115 	hif_info("tasklet mask is 0x%x", tasklet_mask);
1116 	for (i = 0; i < HIF_TASKLET_IN_MONITOR; i++) {
1117 		if (BIT(i) & tasklet_mask)
1118 			qdf_set_bit(i, scn->latency_detect.tasklet_bmap);
1119 	}
1120 
1121 	hif_latency_detect_timer_init(scn);
1122 }
1123 
1124 static void hif_latency_detect_deinit(struct hif_softc *scn)
1125 {
1126 	int i;
1127 
1128 	if (QDF_GLOBAL_MISSION_MODE != hif_get_conparam(scn))
1129 		return;
1130 
1131 	hif_latency_detect_timer_deinit(scn);
1132 	for (i = 0; i < HIF_TASKLET_IN_MONITOR; i++)
1133 		qdf_clear_bit(i, scn->latency_detect.tasklet_bmap);
1134 }
1135 
1136 void hif_latency_detect_timer_start(struct hif_opaque_softc *hif_ctx)
1137 {
1138 	struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
1139 
1140 	if (QDF_GLOBAL_MISSION_MODE != hif_get_conparam(scn))
1141 		return;
1142 
1143 	hif_debug_rl("start timer");
1144 	if (scn->latency_detect.is_timer_started) {
1145 		hif_info("timer has been started");
1146 		return;
1147 	}
1148 
1149 	qdf_timer_start(&scn->latency_detect.timer,
1150 			scn->latency_detect.timeout);
1151 	scn->latency_detect.is_timer_started = true;
1152 }
1153 
1154 void hif_latency_detect_timer_stop(struct hif_opaque_softc *hif_ctx)
1155 {
1156 	struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
1157 
1158 	if (QDF_GLOBAL_MISSION_MODE != hif_get_conparam(scn))
1159 		return;
1160 
1161 	hif_debug_rl("stop timer");
1162 
1163 	qdf_timer_sync_cancel(&scn->latency_detect.timer);
1164 	scn->latency_detect.is_timer_started = false;
1165 }
1166 
1167 void hif_latency_detect_credit_record_time(
1168 	enum hif_credit_exchange_type type,
1169 	struct hif_opaque_softc *hif_ctx)
1170 {
1171 	struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
1172 
1173 	if (!scn) {
1174 		hif_err("Could not do runtime put, scn is null");
1175 		return;
1176 	}
1177 
1178 	if (QDF_GLOBAL_MISSION_MODE != hif_get_conparam(scn))
1179 		return;
1180 
1181 	if (HIF_REQUEST_CREDIT == type)
1182 		scn->latency_detect.credit_request_time = qdf_system_ticks();
1183 	else if (HIF_PROCESS_CREDIT_REPORT == type)
1184 		scn->latency_detect.credit_report_time = qdf_system_ticks();
1185 
1186 	hif_check_detection_latency(scn, false, BIT(HIF_DETECT_CREDIT));
1187 }
1188 
1189 void hif_set_enable_detection(struct hif_opaque_softc *hif_ctx, bool value)
1190 {
1191 	struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
1192 
1193 	if (!scn) {
1194 		hif_err("Could not do runtime put, scn is null");
1195 		return;
1196 	}
1197 
1198 	if (QDF_GLOBAL_MISSION_MODE != hif_get_conparam(scn))
1199 		return;
1200 
1201 	scn->latency_detect.enable_detection = value;
1202 }
1203 #else
1204 static inline void hif_latency_detect_init(struct hif_softc *scn)
1205 {}
1206 
1207 static inline void hif_latency_detect_deinit(struct hif_softc *scn)
1208 {}
1209 #endif
1210 
1211 #ifdef WLAN_FEATURE_AFFINITY_MGR
1212 #define AFFINITY_THRESHOLD 5000000
1213 static inline void
1214 hif_affinity_mgr_init(struct hif_softc *scn, struct wlan_objmgr_psoc *psoc)
1215 {
1216 	unsigned int cpus;
1217 	qdf_cpu_mask allowed_mask = {0};
1218 
1219 	scn->affinity_mgr_supported =
1220 		(cfg_get(psoc, CFG_IRQ_AFFINE_AUDIO_USE_CASE) &&
1221 		qdf_walt_get_cpus_taken_supported());
1222 
1223 	hif_info("Affinity Manager supported: %d", scn->affinity_mgr_supported);
1224 
1225 	if (!scn->affinity_mgr_supported)
1226 		return;
1227 
1228 	scn->time_threshold = AFFINITY_THRESHOLD;
1229 	qdf_for_each_possible_cpu(cpus)
1230 		if (qdf_topology_physical_package_id(cpus) ==
1231 			CPU_CLUSTER_TYPE_LITTLE)
1232 			qdf_cpumask_set_cpu(cpus, &allowed_mask);
1233 	qdf_cpumask_copy(&scn->allowed_mask, &allowed_mask);
1234 }
1235 #else
1236 static inline void
1237 hif_affinity_mgr_init(struct hif_softc *scn, struct wlan_objmgr_psoc *psoc)
1238 {
1239 }
1240 #endif
1241 
1242 #ifdef FEATURE_DIRECT_LINK
1243 /**
1244  * hif_init_direct_link_rcv_pipe_num(): Initialize the direct link receive
1245  *  pipe number
1246  * @scn: hif context
1247  *
1248  * Return: None
1249  */
1250 static inline
1251 void hif_init_direct_link_rcv_pipe_num(struct hif_softc *scn)
1252 {
1253 	scn->dl_recv_pipe_num = INVALID_PIPE_NO;
1254 }
1255 #else
1256 static inline
1257 void hif_init_direct_link_rcv_pipe_num(struct hif_softc *scn)
1258 {
1259 }
1260 #endif
1261 
1262 struct hif_opaque_softc *hif_open(qdf_device_t qdf_ctx,
1263 				  uint32_t mode,
1264 				  enum qdf_bus_type bus_type,
1265 				  struct hif_driver_state_callbacks *cbk,
1266 				  struct wlan_objmgr_psoc *psoc)
1267 {
1268 	struct hif_softc *scn;
1269 	QDF_STATUS status = QDF_STATUS_SUCCESS;
1270 	int bus_context_size = hif_bus_get_context_size(bus_type);
1271 
1272 	if (bus_context_size == 0) {
1273 		hif_err("context size 0 not allowed");
1274 		return NULL;
1275 	}
1276 
1277 	scn = (struct hif_softc *)qdf_mem_malloc(bus_context_size);
1278 	if (!scn)
1279 		return GET_HIF_OPAQUE_HDL(scn);
1280 
1281 	scn->qdf_dev = qdf_ctx;
1282 	scn->hif_con_param = mode;
1283 	qdf_atomic_init(&scn->active_tasklet_cnt);
1284 	qdf_atomic_init(&scn->active_oom_work_cnt);
1285 
1286 	qdf_atomic_init(&scn->active_grp_tasklet_cnt);
1287 	qdf_atomic_init(&scn->link_suspended);
1288 	qdf_atomic_init(&scn->tasklet_from_intr);
1289 	hif_system_pm_set_state_on(GET_HIF_OPAQUE_HDL(scn));
1290 	qdf_mem_copy(&scn->callbacks, cbk,
1291 		     sizeof(struct hif_driver_state_callbacks));
1292 	scn->bus_type  = bus_type;
1293 
1294 	hif_allow_ep_vote_access(GET_HIF_OPAQUE_HDL(scn));
1295 	hif_get_cfg_from_psoc(scn, psoc);
1296 
1297 	hif_set_event_hist_mask(GET_HIF_OPAQUE_HDL(scn));
1298 	status = hif_bus_open(scn, bus_type);
1299 	if (status != QDF_STATUS_SUCCESS) {
1300 		hif_err("hif_bus_open error = %d, bus_type = %d",
1301 			status, bus_type);
1302 		qdf_mem_free(scn);
1303 		scn = NULL;
1304 		goto out;
1305 	}
1306 
1307 	hif_rtpm_lock_init(scn);
1308 
1309 	hif_cpuhp_register(scn);
1310 	hif_latency_detect_init(scn);
1311 	hif_affinity_mgr_init(scn, psoc);
1312 	hif_init_direct_link_rcv_pipe_num(scn);
1313 	hif_ce_desc_history_log_register(scn);
1314 	hif_desc_history_log_register();
1315 	qdf_ssr_driver_dump_register_region("hif", scn, sizeof(*scn));
1316 
1317 out:
1318 	return GET_HIF_OPAQUE_HDL(scn);
1319 }
1320 
1321 #ifdef ADRASTEA_RRI_ON_DDR
1322 /**
1323  * hif_uninit_rri_on_ddr(): free consistent memory allocated for rri
1324  * @scn: hif context
1325  *
1326  * Return: none
1327  */
1328 void hif_uninit_rri_on_ddr(struct hif_softc *scn)
1329 {
1330 	if (scn->vaddr_rri_on_ddr)
1331 		qdf_mem_free_consistent(scn->qdf_dev, scn->qdf_dev->dev,
1332 					RRI_ON_DDR_MEM_SIZE,
1333 					scn->vaddr_rri_on_ddr,
1334 					scn->paddr_rri_on_ddr, 0);
1335 	scn->vaddr_rri_on_ddr = NULL;
1336 }
1337 #endif
1338 
1339 /**
1340  * hif_close(): hif_close
1341  * @hif_ctx: hif_ctx
1342  *
1343  * Return: n/a
1344  */
1345 void hif_close(struct hif_opaque_softc *hif_ctx)
1346 {
1347 	struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
1348 
1349 	if (!scn) {
1350 		hif_err("hif_opaque_softc is NULL");
1351 		return;
1352 	}
1353 
1354 	qdf_ssr_driver_dump_unregister_region("hif");
1355 	hif_desc_history_log_unregister();
1356 	hif_ce_desc_history_log_unregister();
1357 	hif_latency_detect_deinit(scn);
1358 
1359 	if (scn->athdiag_procfs_inited) {
1360 		athdiag_procfs_remove();
1361 		scn->athdiag_procfs_inited = false;
1362 	}
1363 
1364 	if (scn->target_info.hw_name) {
1365 		char *hw_name = scn->target_info.hw_name;
1366 
1367 		scn->target_info.hw_name = "ErrUnloading";
1368 		qdf_mem_free(hw_name);
1369 	}
1370 
1371 	hif_uninit_rri_on_ddr(scn);
1372 	hif_cleanup_static_buf_to_target(scn);
1373 	hif_cpuhp_unregister(scn);
1374 	hif_rtpm_lock_deinit(scn);
1375 
1376 	hif_bus_close(scn);
1377 
1378 	qdf_mem_free(scn);
1379 }
1380 
1381 /**
1382  * hif_get_num_active_grp_tasklets() - get the number of active
1383  *		datapath group tasklets pending to be completed.
1384  * @scn: HIF context
1385  *
1386  * Returns: the number of datapath group tasklets which are active
1387  */
1388 static inline int hif_get_num_active_grp_tasklets(struct hif_softc *scn)
1389 {
1390 	return qdf_atomic_read(&scn->active_grp_tasklet_cnt);
1391 }
1392 
1393 #if (defined(QCA_WIFI_QCA8074) || defined(QCA_WIFI_QCA6018) || \
1394 	defined(QCA_WIFI_QCA6290) || defined(QCA_WIFI_QCA6390) || \
1395 	defined(QCA_WIFI_QCN9000) || defined(QCA_WIFI_QCA6490) || \
1396 	defined(QCA_WIFI_QCA6750) || defined(QCA_WIFI_QCA5018) || \
1397 	defined(QCA_WIFI_KIWI) || defined(QCA_WIFI_QCN9224) || \
1398 	defined(QCA_WIFI_QCN6432) || \
1399 	defined(QCA_WIFI_QCA9574)) || defined(QCA_WIFI_QCA5332)
1400 /**
1401  * hif_get_num_pending_work() - get the number of entries in
1402  *		the workqueue pending to be completed.
1403  * @scn: HIF context
1404  *
1405  * Returns: the number of tasklets which are active
1406  */
1407 static inline int hif_get_num_pending_work(struct hif_softc *scn)
1408 {
1409 	return hal_get_reg_write_pending_work(scn->hal_soc);
1410 }
1411 #elif defined(FEATURE_HIF_DELAYED_REG_WRITE)
1412 static inline int hif_get_num_pending_work(struct hif_softc *scn)
1413 {
1414 	return qdf_atomic_read(&scn->active_work_cnt);
1415 }
1416 #else
1417 
1418 static inline int hif_get_num_pending_work(struct hif_softc *scn)
1419 {
1420 	return 0;
1421 }
1422 #endif
1423 
1424 QDF_STATUS hif_try_complete_tasks(struct hif_softc *scn)
1425 {
1426 	uint32_t task_drain_wait_cnt = 0;
1427 	int tasklet = 0, grp_tasklet = 0, work = 0, oom_work = 0;
1428 
1429 	while ((tasklet = hif_get_num_active_tasklets(scn)) ||
1430 	       (grp_tasklet = hif_get_num_active_grp_tasklets(scn)) ||
1431 	       (work = hif_get_num_pending_work(scn)) ||
1432 		(oom_work = hif_get_num_active_oom_work(scn))) {
1433 		if (++task_drain_wait_cnt > HIF_TASK_DRAIN_WAIT_CNT) {
1434 			hif_err("pending tasklets %d grp tasklets %d work %d oom work %d",
1435 				tasklet, grp_tasklet, work, oom_work);
1436 			/*
1437 			 * There is chance of OOM thread getting scheduled
1438 			 * continuously or execution get delayed during low
1439 			 * memory state. So avoid panic and prevent suspend
1440 			 * if OOM thread is unable to complete pending
1441 			 * work.
1442 			 */
1443 			if (oom_work)
1444 				hif_err("OOM thread is still pending %d tasklets %d grp tasklets %d work %d",
1445 					oom_work, tasklet, grp_tasklet, work);
1446 			else
1447 				QDF_DEBUG_PANIC("Complete tasks takes more than %u ms: tasklets %d grp tasklets %d work %d oom_work %d",
1448 						HIF_TASK_DRAIN_WAIT_CNT * 10,
1449 						tasklet, grp_tasklet, work,
1450 						oom_work);
1451 			return QDF_STATUS_E_FAULT;
1452 		}
1453 		hif_info("waiting for tasklets %d grp tasklets %d work %d oom_work %d",
1454 			 tasklet, grp_tasklet, work, oom_work);
1455 		msleep(10);
1456 	}
1457 
1458 	return QDF_STATUS_SUCCESS;
1459 }
1460 
1461 QDF_STATUS hif_try_complete_dp_tasks(struct hif_opaque_softc *hif_ctx)
1462 {
1463 	struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
1464 	uint32_t task_drain_wait_cnt = 0;
1465 	int grp_tasklet = 0, work = 0;
1466 
1467 	while ((grp_tasklet = hif_get_num_active_grp_tasklets(scn)) ||
1468 	       (work = hif_get_num_pending_work(scn))) {
1469 		if (++task_drain_wait_cnt > HIF_TASK_DRAIN_WAIT_CNT) {
1470 			hif_err("pending grp tasklets %d work %d",
1471 				grp_tasklet, work);
1472 			QDF_DEBUG_PANIC("Complete tasks takes more than %u ms: grp tasklets %d work %d",
1473 					HIF_TASK_DRAIN_WAIT_CNT * 10,
1474 					grp_tasklet, work);
1475 			return QDF_STATUS_E_FAULT;
1476 		}
1477 		hif_info("waiting for grp tasklets %d work %d",
1478 			 grp_tasklet, work);
1479 		msleep(10);
1480 	}
1481 
1482 	return QDF_STATUS_SUCCESS;
1483 }
1484 
1485 #ifdef HIF_HAL_REG_ACCESS_SUPPORT
1486 void hif_reg_window_write(struct hif_softc *scn, uint32_t offset,
1487 			  uint32_t value)
1488 {
1489 	hal_write32_mb(scn->hal_soc, offset, value);
1490 }
1491 
1492 uint32_t hif_reg_window_read(struct hif_softc *scn, uint32_t offset)
1493 {
1494 	return hal_read32_mb(scn->hal_soc, offset);
1495 }
1496 #endif
1497 
1498 #if defined(HIF_IPCI) && defined(FEATURE_HAL_DELAYED_REG_WRITE)
1499 QDF_STATUS hif_try_prevent_ep_vote_access(struct hif_opaque_softc *hif_ctx)
1500 {
1501 	struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
1502 	uint32_t work_drain_wait_cnt = 0;
1503 	uint32_t wait_cnt = 0;
1504 	int work = 0;
1505 
1506 	qdf_atomic_set(&scn->dp_ep_vote_access,
1507 		       HIF_EP_VOTE_ACCESS_DISABLE);
1508 	qdf_atomic_set(&scn->ep_vote_access,
1509 		       HIF_EP_VOTE_ACCESS_DISABLE);
1510 
1511 	while ((work = hif_get_num_pending_work(scn))) {
1512 		if (++work_drain_wait_cnt > HIF_WORK_DRAIN_WAIT_CNT) {
1513 			qdf_atomic_set(&scn->dp_ep_vote_access,
1514 				       HIF_EP_VOTE_ACCESS_ENABLE);
1515 			qdf_atomic_set(&scn->ep_vote_access,
1516 				       HIF_EP_VOTE_ACCESS_ENABLE);
1517 			hif_err("timeout wait for pending work %d ", work);
1518 			return QDF_STATUS_E_FAULT;
1519 		}
1520 		qdf_sleep(10);
1521 	}
1522 
1523 	if (pld_is_pci_ep_awake(scn->qdf_dev->dev) == -ENOTSUPP)
1524 	return QDF_STATUS_SUCCESS;
1525 
1526 	while (pld_is_pci_ep_awake(scn->qdf_dev->dev)) {
1527 		if (++wait_cnt > HIF_EP_WAKE_RESET_WAIT_CNT) {
1528 			hif_err("Release EP vote is not proceed by Fw");
1529 			return QDF_STATUS_E_FAULT;
1530 		}
1531 		qdf_sleep(5);
1532 	}
1533 
1534 	return QDF_STATUS_SUCCESS;
1535 }
1536 
1537 void hif_set_ep_intermediate_vote_access(struct hif_opaque_softc *hif_ctx)
1538 {
1539 	struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
1540 	uint8_t vote_access;
1541 
1542 	vote_access = qdf_atomic_read(&scn->ep_vote_access);
1543 
1544 	if (vote_access != HIF_EP_VOTE_ACCESS_DISABLE)
1545 		hif_info("EP vote changed from:%u to intermediate state",
1546 			 vote_access);
1547 
1548 	if (QDF_IS_STATUS_ERROR(hif_try_prevent_ep_vote_access(hif_ctx)))
1549 		QDF_BUG(0);
1550 
1551 	qdf_atomic_set(&scn->ep_vote_access,
1552 		       HIF_EP_VOTE_INTERMEDIATE_ACCESS);
1553 }
1554 
1555 void hif_allow_ep_vote_access(struct hif_opaque_softc *hif_ctx)
1556 {
1557 	struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
1558 
1559 	qdf_atomic_set(&scn->dp_ep_vote_access,
1560 		       HIF_EP_VOTE_ACCESS_ENABLE);
1561 	qdf_atomic_set(&scn->ep_vote_access,
1562 		       HIF_EP_VOTE_ACCESS_ENABLE);
1563 }
1564 
1565 void hif_set_ep_vote_access(struct hif_opaque_softc *hif_ctx,
1566 			    uint8_t type, uint8_t access)
1567 {
1568 	struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
1569 
1570 	if (type == HIF_EP_VOTE_DP_ACCESS)
1571 		qdf_atomic_set(&scn->dp_ep_vote_access, access);
1572 	else
1573 		qdf_atomic_set(&scn->ep_vote_access, access);
1574 }
1575 
1576 uint8_t hif_get_ep_vote_access(struct hif_opaque_softc *hif_ctx,
1577 			       uint8_t type)
1578 {
1579 	struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
1580 
1581 	if (type == HIF_EP_VOTE_DP_ACCESS)
1582 		return qdf_atomic_read(&scn->dp_ep_vote_access);
1583 	else
1584 		return qdf_atomic_read(&scn->ep_vote_access);
1585 }
1586 #endif
1587 
1588 #ifdef FEATURE_HIF_DELAYED_REG_WRITE
1589 #ifdef MEMORY_DEBUG
1590 #define HIF_REG_WRITE_QUEUE_LEN 128
1591 #else
1592 #define HIF_REG_WRITE_QUEUE_LEN 32
1593 #endif
1594 
1595 /**
1596  * hif_print_reg_write_stats() - Print hif delayed reg write stats
1597  * @hif_ctx: hif opaque handle
1598  *
1599  * Return: None
1600  */
1601 void hif_print_reg_write_stats(struct hif_opaque_softc *hif_ctx)
1602 {
1603 	struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
1604 	struct CE_state *ce_state;
1605 	uint32_t *hist;
1606 	int i;
1607 
1608 	hist = scn->wstats.sched_delay;
1609 	hif_debug("wstats: enq %u deq %u coal %u direct %u q_depth %u max_q %u sched-delay hist %u %u %u %u",
1610 		  qdf_atomic_read(&scn->wstats.enqueues),
1611 		  scn->wstats.dequeues,
1612 		  qdf_atomic_read(&scn->wstats.coalesces),
1613 		  qdf_atomic_read(&scn->wstats.direct),
1614 		  qdf_atomic_read(&scn->wstats.q_depth),
1615 		  scn->wstats.max_q_depth,
1616 		  hist[HIF_REG_WRITE_SCHED_DELAY_SUB_100us],
1617 		  hist[HIF_REG_WRITE_SCHED_DELAY_SUB_1000us],
1618 		  hist[HIF_REG_WRITE_SCHED_DELAY_SUB_5000us],
1619 		  hist[HIF_REG_WRITE_SCHED_DELAY_GT_5000us]);
1620 
1621 	for (i = 0; i < scn->ce_count; i++) {
1622 		ce_state = scn->ce_id_to_state[i];
1623 		if (!ce_state)
1624 			continue;
1625 
1626 		hif_debug("ce%d: enq %u deq %u coal %u direct %u",
1627 			  i, ce_state->wstats.enqueues,
1628 			  ce_state->wstats.dequeues,
1629 			  ce_state->wstats.coalesces,
1630 			  ce_state->wstats.direct);
1631 	}
1632 }
1633 
1634 /**
1635  * hif_is_reg_write_tput_level_high() - throughput level for delayed reg writes
1636  * @scn: hif_softc pointer
1637  *
1638  * Return: true if throughput is high, else false.
1639  */
1640 static inline bool hif_is_reg_write_tput_level_high(struct hif_softc *scn)
1641 {
1642 	int bw_level = hif_get_bandwidth_level(GET_HIF_OPAQUE_HDL(scn));
1643 
1644 	return (bw_level >= PLD_BUS_WIDTH_MEDIUM) ? true : false;
1645 }
1646 
1647 /**
1648  * hif_reg_write_fill_sched_delay_hist() - fill reg write delay histogram
1649  * @scn: hif_softc pointer
1650  * @delay_us: delay in us
1651  *
1652  * Return: None
1653  */
1654 static inline void hif_reg_write_fill_sched_delay_hist(struct hif_softc *scn,
1655 						       uint64_t delay_us)
1656 {
1657 	uint32_t *hist;
1658 
1659 	hist = scn->wstats.sched_delay;
1660 
1661 	if (delay_us < 100)
1662 		hist[HIF_REG_WRITE_SCHED_DELAY_SUB_100us]++;
1663 	else if (delay_us < 1000)
1664 		hist[HIF_REG_WRITE_SCHED_DELAY_SUB_1000us]++;
1665 	else if (delay_us < 5000)
1666 		hist[HIF_REG_WRITE_SCHED_DELAY_SUB_5000us]++;
1667 	else
1668 		hist[HIF_REG_WRITE_SCHED_DELAY_GT_5000us]++;
1669 }
1670 
1671 /**
1672  * hif_process_reg_write_q_elem() - process a register write queue element
1673  * @scn: hif_softc pointer
1674  * @q_elem: pointer to hal register write queue element
1675  *
1676  * Return: The value which was written to the address
1677  */
1678 static int32_t
1679 hif_process_reg_write_q_elem(struct hif_softc *scn,
1680 			     struct hif_reg_write_q_elem *q_elem)
1681 {
1682 	struct CE_state *ce_state = q_elem->ce_state;
1683 	uint32_t write_val = -1;
1684 
1685 	qdf_spin_lock_bh(&ce_state->ce_index_lock);
1686 
1687 	ce_state->reg_write_in_progress = false;
1688 	ce_state->wstats.dequeues++;
1689 
1690 	if (ce_state->src_ring) {
1691 		q_elem->dequeue_val = ce_state->src_ring->write_index;
1692 		hal_write32_mb(scn->hal_soc, ce_state->ce_wrt_idx_offset,
1693 			       ce_state->src_ring->write_index);
1694 		write_val = ce_state->src_ring->write_index;
1695 	} else if (ce_state->dest_ring) {
1696 		q_elem->dequeue_val = ce_state->dest_ring->write_index;
1697 		hal_write32_mb(scn->hal_soc, ce_state->ce_wrt_idx_offset,
1698 			       ce_state->dest_ring->write_index);
1699 		write_val = ce_state->dest_ring->write_index;
1700 	} else {
1701 		hif_debug("invalid reg write received");
1702 		qdf_assert(0);
1703 	}
1704 
1705 	q_elem->valid = 0;
1706 	ce_state->last_dequeue_time = q_elem->dequeue_time;
1707 
1708 	qdf_spin_unlock_bh(&ce_state->ce_index_lock);
1709 
1710 	return write_val;
1711 }
1712 
1713 /**
1714  * hif_reg_write_work() - Worker to process delayed writes
1715  * @arg: hif_softc pointer
1716  *
1717  * Return: None
1718  */
1719 static void hif_reg_write_work(void *arg)
1720 {
1721 	struct hif_softc *scn = arg;
1722 	struct hif_reg_write_q_elem *q_elem;
1723 	uint32_t offset;
1724 	uint64_t delta_us;
1725 	int32_t q_depth, write_val;
1726 	uint32_t num_processed = 0;
1727 	int32_t ring_id;
1728 
1729 	q_elem = &scn->reg_write_queue[scn->read_idx];
1730 	q_elem->work_scheduled_time = qdf_get_log_timestamp();
1731 	q_elem->cpu_id = qdf_get_cpu();
1732 
1733 	/* Make sure q_elem consistent in the memory for multi-cores */
1734 	qdf_rmb();
1735 	if (!q_elem->valid)
1736 		return;
1737 
1738 	q_depth = qdf_atomic_read(&scn->wstats.q_depth);
1739 	if (q_depth > scn->wstats.max_q_depth)
1740 		scn->wstats.max_q_depth =  q_depth;
1741 
1742 	if (hif_prevent_link_low_power_states(GET_HIF_OPAQUE_HDL(scn))) {
1743 		scn->wstats.prevent_l1_fails++;
1744 		return;
1745 	}
1746 
1747 	while (true) {
1748 		qdf_rmb();
1749 		if (!q_elem->valid)
1750 			break;
1751 
1752 		qdf_rmb();
1753 		q_elem->dequeue_time = qdf_get_log_timestamp();
1754 		ring_id = q_elem->ce_state->id;
1755 		offset = q_elem->offset;
1756 		delta_us = qdf_log_timestamp_to_usecs(q_elem->dequeue_time -
1757 						      q_elem->enqueue_time);
1758 		hif_reg_write_fill_sched_delay_hist(scn, delta_us);
1759 
1760 		scn->wstats.dequeues++;
1761 		qdf_atomic_dec(&scn->wstats.q_depth);
1762 
1763 		write_val = hif_process_reg_write_q_elem(scn, q_elem);
1764 		hif_debug("read_idx %u ce_id %d offset 0x%x dequeue_val %d",
1765 			  scn->read_idx, ring_id, offset, write_val);
1766 
1767 		qdf_trace_dp_del_reg_write(ring_id, q_elem->enqueue_val,
1768 					   q_elem->dequeue_val,
1769 					   q_elem->enqueue_time,
1770 					   q_elem->dequeue_time);
1771 		num_processed++;
1772 		scn->read_idx = (scn->read_idx + 1) &
1773 					(HIF_REG_WRITE_QUEUE_LEN - 1);
1774 		q_elem = &scn->reg_write_queue[scn->read_idx];
1775 	}
1776 
1777 	hif_allow_link_low_power_states(GET_HIF_OPAQUE_HDL(scn));
1778 
1779 	/*
1780 	 * Decrement active_work_cnt by the number of elements dequeued after
1781 	 * hif_allow_link_low_power_states.
1782 	 * This makes sure that hif_try_complete_tasks will wait till we make
1783 	 * the bus access in hif_allow_link_low_power_states. This will avoid
1784 	 * race condition between delayed register worker and bus suspend
1785 	 * (system suspend or runtime suspend).
1786 	 *
1787 	 * The following decrement should be done at the end!
1788 	 */
1789 	qdf_atomic_sub(num_processed, &scn->active_work_cnt);
1790 }
1791 
1792 /**
1793  * hif_delayed_reg_write_deinit() - De-Initialize delayed reg write processing
1794  * @scn: hif_softc pointer
1795  *
1796  * De-initialize main data structures to process register writes in a delayed
1797  * workqueue.
1798  *
1799  * Return: None
1800  */
1801 static void hif_delayed_reg_write_deinit(struct hif_softc *scn)
1802 {
1803 	qdf_flush_work(&scn->reg_write_work);
1804 	qdf_disable_work(&scn->reg_write_work);
1805 	qdf_flush_workqueue(0, scn->reg_write_wq);
1806 	qdf_destroy_workqueue(0, scn->reg_write_wq);
1807 	qdf_mem_free(scn->reg_write_queue);
1808 }
1809 
1810 /**
1811  * hif_delayed_reg_write_init() - Initialization function for delayed reg writes
1812  * @scn: hif_softc pointer
1813  *
1814  * Initialize main data structures to process register writes in a delayed
1815  * workqueue.
1816  */
1817 
1818 static QDF_STATUS hif_delayed_reg_write_init(struct hif_softc *scn)
1819 {
1820 	qdf_atomic_init(&scn->active_work_cnt);
1821 	scn->reg_write_wq =
1822 		qdf_alloc_high_prior_ordered_workqueue("hif_register_write_wq");
1823 	qdf_create_work(0, &scn->reg_write_work, hif_reg_write_work, scn);
1824 	scn->reg_write_queue = qdf_mem_malloc(HIF_REG_WRITE_QUEUE_LEN *
1825 					      sizeof(*scn->reg_write_queue));
1826 	if (!scn->reg_write_queue) {
1827 		hif_err("unable to allocate memory for delayed reg write");
1828 		QDF_BUG(0);
1829 		return QDF_STATUS_E_NOMEM;
1830 	}
1831 
1832 	/* Initial value of indices */
1833 	scn->read_idx = 0;
1834 	qdf_atomic_set(&scn->write_idx, -1);
1835 
1836 	return QDF_STATUS_SUCCESS;
1837 }
1838 
1839 static void hif_reg_write_enqueue(struct hif_softc *scn,
1840 				  struct CE_state *ce_state,
1841 				  uint32_t value)
1842 {
1843 	struct hif_reg_write_q_elem *q_elem;
1844 	uint32_t write_idx;
1845 
1846 	if (ce_state->reg_write_in_progress) {
1847 		hif_debug("Already in progress ce_id %d offset 0x%x value %u",
1848 			  ce_state->id, ce_state->ce_wrt_idx_offset, value);
1849 		qdf_atomic_inc(&scn->wstats.coalesces);
1850 		ce_state->wstats.coalesces++;
1851 		return;
1852 	}
1853 
1854 	write_idx = qdf_atomic_inc_return(&scn->write_idx);
1855 	write_idx = write_idx & (HIF_REG_WRITE_QUEUE_LEN - 1);
1856 
1857 	q_elem = &scn->reg_write_queue[write_idx];
1858 	if (q_elem->valid) {
1859 		hif_err("queue full");
1860 		QDF_BUG(0);
1861 		return;
1862 	}
1863 
1864 	qdf_atomic_inc(&scn->wstats.enqueues);
1865 	ce_state->wstats.enqueues++;
1866 
1867 	qdf_atomic_inc(&scn->wstats.q_depth);
1868 
1869 	q_elem->ce_state = ce_state;
1870 	q_elem->offset = ce_state->ce_wrt_idx_offset;
1871 	q_elem->enqueue_val = value;
1872 	q_elem->enqueue_time = qdf_get_log_timestamp();
1873 
1874 	/*
1875 	 * Before the valid flag is set to true, all the other
1876 	 * fields in the q_elem needs to be updated in memory.
1877 	 * Else there is a chance that the dequeuing worker thread
1878 	 * might read stale entries and process incorrect srng.
1879 	 */
1880 	qdf_wmb();
1881 	q_elem->valid = true;
1882 
1883 	/*
1884 	 * After all other fields in the q_elem has been updated
1885 	 * in memory successfully, the valid flag needs to be updated
1886 	 * in memory in time too.
1887 	 * Else there is a chance that the dequeuing worker thread
1888 	 * might read stale valid flag and the work will be bypassed
1889 	 * for this round. And if there is no other work scheduled
1890 	 * later, this hal register writing won't be updated any more.
1891 	 */
1892 	qdf_wmb();
1893 
1894 	ce_state->reg_write_in_progress  = true;
1895 	qdf_atomic_inc(&scn->active_work_cnt);
1896 
1897 	hif_debug("write_idx %u ce_id %d offset 0x%x value %u",
1898 		  write_idx, ce_state->id, ce_state->ce_wrt_idx_offset, value);
1899 
1900 	qdf_queue_work(scn->qdf_dev, scn->reg_write_wq,
1901 		       &scn->reg_write_work);
1902 }
1903 
1904 void hif_delayed_reg_write(struct hif_softc *scn, uint32_t ctrl_addr,
1905 			   uint32_t val)
1906 {
1907 	struct CE_state *ce_state;
1908 	int ce_id = COPY_ENGINE_ID(ctrl_addr);
1909 
1910 	ce_state = scn->ce_id_to_state[ce_id];
1911 
1912 	if (!ce_state->htt_tx_data && !ce_state->htt_rx_data) {
1913 		hif_reg_write_enqueue(scn, ce_state, val);
1914 		return;
1915 	}
1916 
1917 	if (hif_is_reg_write_tput_level_high(scn) ||
1918 	    (PLD_MHI_STATE_L0 == pld_get_mhi_state(scn->qdf_dev->dev))) {
1919 		hal_write32_mb(scn->hal_soc, ce_state->ce_wrt_idx_offset, val);
1920 		qdf_atomic_inc(&scn->wstats.direct);
1921 		ce_state->wstats.direct++;
1922 	} else {
1923 		hif_reg_write_enqueue(scn, ce_state, val);
1924 	}
1925 }
1926 #else
1927 static inline QDF_STATUS hif_delayed_reg_write_init(struct hif_softc *scn)
1928 {
1929 	return QDF_STATUS_SUCCESS;
1930 }
1931 
1932 static inline void  hif_delayed_reg_write_deinit(struct hif_softc *scn)
1933 {
1934 }
1935 #endif
1936 
1937 #if defined(QCA_WIFI_WCN6450)
1938 static QDF_STATUS hif_hal_attach(struct hif_softc *scn)
1939 {
1940 	scn->hal_soc = hal_attach(hif_softc_to_hif_opaque_softc(scn),
1941 				  scn->qdf_dev);
1942 	if (!scn->hal_soc)
1943 		return QDF_STATUS_E_FAILURE;
1944 
1945 	return QDF_STATUS_SUCCESS;
1946 }
1947 
1948 static QDF_STATUS hif_hal_detach(struct hif_softc *scn)
1949 {
1950 	hal_detach(scn->hal_soc);
1951 	scn->hal_soc = NULL;
1952 
1953 	return QDF_STATUS_SUCCESS;
1954 }
1955 #elif (defined(QCA_WIFI_QCA8074) || defined(QCA_WIFI_QCA6018) || \
1956 	defined(QCA_WIFI_QCA6290) || defined(QCA_WIFI_QCA6390) || \
1957 	defined(QCA_WIFI_QCN9000) || defined(QCA_WIFI_QCA6490) || \
1958 	defined(QCA_WIFI_QCA6750) || defined(QCA_WIFI_QCA5018) || \
1959 	defined(QCA_WIFI_KIWI) || defined(QCA_WIFI_QCN9224) || \
1960 	defined(QCA_WIFI_QCA9574)) || defined(QCA_WIFI_QCA5332)
1961 static QDF_STATUS hif_hal_attach(struct hif_softc *scn)
1962 {
1963 	if (ce_srng_based(scn)) {
1964 		scn->hal_soc = hal_attach(
1965 					hif_softc_to_hif_opaque_softc(scn),
1966 					scn->qdf_dev);
1967 		if (!scn->hal_soc)
1968 			return QDF_STATUS_E_FAILURE;
1969 	}
1970 
1971 	return QDF_STATUS_SUCCESS;
1972 }
1973 
1974 static QDF_STATUS hif_hal_detach(struct hif_softc *scn)
1975 {
1976 	if (ce_srng_based(scn)) {
1977 		hal_detach(scn->hal_soc);
1978 		scn->hal_soc = NULL;
1979 	}
1980 
1981 	return QDF_STATUS_SUCCESS;
1982 }
1983 #else
1984 static QDF_STATUS hif_hal_attach(struct hif_softc *scn)
1985 {
1986 	return QDF_STATUS_SUCCESS;
1987 }
1988 
1989 static QDF_STATUS hif_hal_detach(struct hif_softc *scn)
1990 {
1991 	return QDF_STATUS_SUCCESS;
1992 }
1993 #endif
1994 
1995 int hif_init_dma_mask(struct device *dev, enum qdf_bus_type bus_type)
1996 {
1997 	int ret;
1998 
1999 	switch (bus_type) {
2000 	case QDF_BUS_TYPE_IPCI:
2001 		ret = qdf_set_dma_coherent_mask(dev,
2002 						DMA_COHERENT_MASK_DEFAULT);
2003 		if (ret) {
2004 			hif_err("Failed to set dma mask error = %d", ret);
2005 			return ret;
2006 		}
2007 
2008 		break;
2009 	default:
2010 		/* Follow the existing sequence for other targets */
2011 		break;
2012 	}
2013 
2014 	return 0;
2015 }
2016 
2017 /**
2018  * hif_enable(): hif_enable
2019  * @hif_ctx: hif_ctx
2020  * @dev: dev
2021  * @bdev: bus dev
2022  * @bid: bus ID
2023  * @bus_type: bus type
2024  * @type: enable type
2025  *
2026  * Return: QDF_STATUS
2027  */
2028 QDF_STATUS hif_enable(struct hif_opaque_softc *hif_ctx, struct device *dev,
2029 					  void *bdev,
2030 					  const struct hif_bus_id *bid,
2031 					  enum qdf_bus_type bus_type,
2032 					  enum hif_enable_type type)
2033 {
2034 	QDF_STATUS status;
2035 	struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
2036 
2037 	if (!scn) {
2038 		hif_err("hif_ctx = NULL");
2039 		return QDF_STATUS_E_NULL_VALUE;
2040 	}
2041 
2042 	status = hif_enable_bus(scn, dev, bdev, bid, type);
2043 	if (status != QDF_STATUS_SUCCESS) {
2044 		hif_err("hif_enable_bus error = %d", status);
2045 		return status;
2046 	}
2047 
2048 	status = hif_hal_attach(scn);
2049 	if (status != QDF_STATUS_SUCCESS) {
2050 		hif_err("hal attach failed");
2051 		goto disable_bus;
2052 	}
2053 
2054 	if (hif_delayed_reg_write_init(scn) != QDF_STATUS_SUCCESS) {
2055 		hif_err("unable to initialize delayed reg write");
2056 		goto hal_detach;
2057 	}
2058 
2059 	if (hif_bus_configure(scn)) {
2060 		hif_err("Target probe failed");
2061 		status = QDF_STATUS_E_FAILURE;
2062 		goto hal_detach;
2063 	}
2064 
2065 	hif_ut_suspend_init(scn);
2066 	hif_register_recovery_notifier(scn);
2067 	hif_latency_detect_timer_start(hif_ctx);
2068 
2069 	/*
2070 	 * Flag to avoid potential unallocated memory access from MSI
2071 	 * interrupt handler which could get scheduled as soon as MSI
2072 	 * is enabled, i.e to take care of the race due to the order
2073 	 * in where MSI is enabled before the memory, that will be
2074 	 * in interrupt handlers, is allocated.
2075 	 */
2076 
2077 	scn->hif_init_done = true;
2078 
2079 	hif_debug("OK");
2080 
2081 	return QDF_STATUS_SUCCESS;
2082 
2083 hal_detach:
2084 	hif_hal_detach(scn);
2085 disable_bus:
2086 	hif_disable_bus(scn);
2087 	return status;
2088 }
2089 
2090 void hif_disable(struct hif_opaque_softc *hif_ctx, enum hif_disable_type type)
2091 {
2092 	struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
2093 
2094 	if (!scn)
2095 		return;
2096 
2097 	hif_delayed_reg_write_deinit(scn);
2098 	hif_set_enable_detection(hif_ctx, false);
2099 	hif_latency_detect_timer_stop(hif_ctx);
2100 
2101 	hif_unregister_recovery_notifier(scn);
2102 
2103 	hif_nointrs(scn);
2104 	if (scn->hif_init_done == false)
2105 		hif_shutdown_device(hif_ctx);
2106 	else
2107 		hif_stop(hif_ctx);
2108 
2109 	hif_hal_detach(scn);
2110 
2111 	hif_disable_bus(scn);
2112 
2113 	hif_wlan_disable(scn);
2114 
2115 	scn->notice_send = false;
2116 
2117 	hif_debug("X");
2118 }
2119 
2120 #ifdef CE_TASKLET_DEBUG_ENABLE
2121 void hif_enable_ce_latency_stats(struct hif_opaque_softc *hif_ctx, uint8_t val)
2122 {
2123 	struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
2124 
2125 	if (!scn)
2126 		return;
2127 
2128 	scn->ce_latency_stats = val;
2129 }
2130 #endif
2131 
2132 void hif_display_stats(struct hif_opaque_softc *hif_ctx)
2133 {
2134 	hif_display_bus_stats(hif_ctx);
2135 }
2136 
2137 qdf_export_symbol(hif_display_stats);
2138 
2139 void hif_clear_stats(struct hif_opaque_softc *hif_ctx)
2140 {
2141 	hif_clear_bus_stats(hif_ctx);
2142 }
2143 
2144 /**
2145  * hif_crash_shutdown_dump_bus_register() - dump bus registers
2146  * @hif_ctx: hif_ctx
2147  *
2148  * Return: n/a
2149  */
2150 #if defined(TARGET_RAMDUMP_AFTER_KERNEL_PANIC) && defined(WLAN_FEATURE_BMI)
2151 
2152 static void hif_crash_shutdown_dump_bus_register(void *hif_ctx)
2153 {
2154 	struct hif_opaque_softc *scn = hif_ctx;
2155 
2156 	if (hif_check_soc_status(scn))
2157 		return;
2158 
2159 	if (hif_dump_registers(scn))
2160 		hif_err("Failed to dump bus registers!");
2161 }
2162 
2163 /**
2164  * hif_crash_shutdown(): hif_crash_shutdown
2165  *
2166  * This function is called by the platform driver to dump CE registers
2167  *
2168  * @hif_ctx: hif_ctx
2169  *
2170  * Return: n/a
2171  */
2172 void hif_crash_shutdown(struct hif_opaque_softc *hif_ctx)
2173 {
2174 	struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
2175 
2176 	if (!hif_ctx)
2177 		return;
2178 
2179 	if (scn->bus_type == QDF_BUS_TYPE_SNOC) {
2180 		hif_warn("RAM dump disabled for bustype %d", scn->bus_type);
2181 		return;
2182 	}
2183 
2184 	if (TARGET_STATUS_RESET == scn->target_status) {
2185 		hif_warn("Target is already asserted, ignore!");
2186 		return;
2187 	}
2188 
2189 	if (hif_is_load_or_unload_in_progress(scn)) {
2190 		hif_err("Load/unload is in progress, ignore!");
2191 		return;
2192 	}
2193 
2194 	hif_crash_shutdown_dump_bus_register(hif_ctx);
2195 	hif_set_target_status(hif_ctx, TARGET_STATUS_RESET);
2196 
2197 	if (ol_copy_ramdump(hif_ctx))
2198 		goto out;
2199 
2200 	hif_info("RAM dump collecting completed!");
2201 
2202 out:
2203 	return;
2204 }
2205 #else
2206 void hif_crash_shutdown(struct hif_opaque_softc *hif_ctx)
2207 {
2208 	hif_debug("Collecting target RAM dump disabled");
2209 }
2210 #endif /* TARGET_RAMDUMP_AFTER_KERNEL_PANIC */
2211 
2212 #ifdef QCA_WIFI_3_0
2213 /**
2214  * hif_check_fw_reg(): hif_check_fw_reg
2215  * @scn: scn
2216  *
2217  * Return: int
2218  */
2219 int hif_check_fw_reg(struct hif_opaque_softc *scn)
2220 {
2221 	return 0;
2222 }
2223 #endif
2224 
2225 /**
2226  * hif_read_phy_mem_base(): hif_read_phy_mem_base
2227  * @scn: scn
2228  * @phy_mem_base: physical mem base
2229  *
2230  * Return: n/a
2231  */
2232 void hif_read_phy_mem_base(struct hif_softc *scn, qdf_dma_addr_t *phy_mem_base)
2233 {
2234 	*phy_mem_base = scn->mem_pa;
2235 }
2236 qdf_export_symbol(hif_read_phy_mem_base);
2237 
2238 /**
2239  * hif_get_device_type(): hif_get_device_type
2240  * @device_id: device_id
2241  * @revision_id: revision_id
2242  * @hif_type: returned hif_type
2243  * @target_type: returned target_type
2244  *
2245  * Return: int
2246  */
2247 int hif_get_device_type(uint32_t device_id,
2248 			uint32_t revision_id,
2249 			uint32_t *hif_type, uint32_t *target_type)
2250 {
2251 	int ret = 0;
2252 
2253 	switch (device_id) {
2254 	case ADRASTEA_DEVICE_ID_P2_E12:
2255 
2256 		*hif_type = HIF_TYPE_ADRASTEA;
2257 		*target_type = TARGET_TYPE_ADRASTEA;
2258 		break;
2259 
2260 	case AR9888_DEVICE_ID:
2261 		*hif_type = HIF_TYPE_AR9888;
2262 		*target_type = TARGET_TYPE_AR9888;
2263 		break;
2264 
2265 	case AR6320_DEVICE_ID:
2266 		switch (revision_id) {
2267 		case AR6320_FW_1_1:
2268 		case AR6320_FW_1_3:
2269 			*hif_type = HIF_TYPE_AR6320;
2270 			*target_type = TARGET_TYPE_AR6320;
2271 			break;
2272 
2273 		case AR6320_FW_2_0:
2274 		case AR6320_FW_3_0:
2275 		case AR6320_FW_3_2:
2276 			*hif_type = HIF_TYPE_AR6320V2;
2277 			*target_type = TARGET_TYPE_AR6320V2;
2278 			break;
2279 
2280 		default:
2281 			hif_err("dev_id = 0x%x, rev_id = 0x%x",
2282 				device_id, revision_id);
2283 			ret = -ENODEV;
2284 			goto end;
2285 		}
2286 		break;
2287 
2288 	case AR9887_DEVICE_ID:
2289 		*hif_type = HIF_TYPE_AR9888;
2290 		*target_type = TARGET_TYPE_AR9888;
2291 		hif_info(" *********** AR9887 **************");
2292 		break;
2293 
2294 	case QCA9984_DEVICE_ID:
2295 		*hif_type = HIF_TYPE_QCA9984;
2296 		*target_type = TARGET_TYPE_QCA9984;
2297 		hif_info(" *********** QCA9984 *************");
2298 		break;
2299 
2300 	case QCA9888_DEVICE_ID:
2301 		*hif_type = HIF_TYPE_QCA9888;
2302 		*target_type = TARGET_TYPE_QCA9888;
2303 		hif_info(" *********** QCA9888 *************");
2304 		break;
2305 
2306 	case AR900B_DEVICE_ID:
2307 		*hif_type = HIF_TYPE_AR900B;
2308 		*target_type = TARGET_TYPE_AR900B;
2309 		hif_info(" *********** AR900B *************");
2310 		break;
2311 
2312 	case QCA8074_DEVICE_ID:
2313 		*hif_type = HIF_TYPE_QCA8074;
2314 		*target_type = TARGET_TYPE_QCA8074;
2315 		hif_info(" *********** QCA8074  *************");
2316 		break;
2317 
2318 	case QCA6290_EMULATION_DEVICE_ID:
2319 	case QCA6290_DEVICE_ID:
2320 		*hif_type = HIF_TYPE_QCA6290;
2321 		*target_type = TARGET_TYPE_QCA6290;
2322 		hif_info(" *********** QCA6290EMU *************");
2323 		break;
2324 
2325 	case QCN9000_DEVICE_ID:
2326 		*hif_type = HIF_TYPE_QCN9000;
2327 		*target_type = TARGET_TYPE_QCN9000;
2328 		hif_info(" *********** QCN9000 *************");
2329 		break;
2330 
2331 	case QCN9224_DEVICE_ID:
2332 		*hif_type = HIF_TYPE_QCN9224;
2333 		*target_type = TARGET_TYPE_QCN9224;
2334 		hif_info(" *********** QCN9224 *************");
2335 		break;
2336 
2337 	case QCN6122_DEVICE_ID:
2338 		*hif_type = HIF_TYPE_QCN6122;
2339 		*target_type = TARGET_TYPE_QCN6122;
2340 		hif_info(" *********** QCN6122 *************");
2341 		break;
2342 
2343 	case QCN9160_DEVICE_ID:
2344 		*hif_type = HIF_TYPE_QCN9160;
2345 		*target_type = TARGET_TYPE_QCN9160;
2346 		hif_info(" *********** QCN9160 *************");
2347 		break;
2348 
2349 	case QCN6432_DEVICE_ID:
2350 		*hif_type = HIF_TYPE_QCN6432;
2351 		*target_type = TARGET_TYPE_QCN6432;
2352 		hif_info(" *********** QCN6432 *************");
2353 		break;
2354 
2355 	case QCN7605_DEVICE_ID:
2356 	case QCN7605_COMPOSITE:
2357 	case QCN7605_STANDALONE:
2358 	case QCN7605_STANDALONE_V2:
2359 	case QCN7605_COMPOSITE_V2:
2360 		*hif_type = HIF_TYPE_QCN7605;
2361 		*target_type = TARGET_TYPE_QCN7605;
2362 		hif_info(" *********** QCN7605 *************");
2363 		break;
2364 
2365 	case QCA6390_DEVICE_ID:
2366 	case QCA6390_EMULATION_DEVICE_ID:
2367 		*hif_type = HIF_TYPE_QCA6390;
2368 		*target_type = TARGET_TYPE_QCA6390;
2369 		hif_info(" *********** QCA6390 *************");
2370 		break;
2371 
2372 	case QCA6490_DEVICE_ID:
2373 	case QCA6490_EMULATION_DEVICE_ID:
2374 		*hif_type = HIF_TYPE_QCA6490;
2375 		*target_type = TARGET_TYPE_QCA6490;
2376 		hif_info(" *********** QCA6490 *************");
2377 		break;
2378 
2379 	case QCA6750_DEVICE_ID:
2380 	case QCA6750_EMULATION_DEVICE_ID:
2381 		*hif_type = HIF_TYPE_QCA6750;
2382 		*target_type = TARGET_TYPE_QCA6750;
2383 		hif_info(" *********** QCA6750 *************");
2384 		break;
2385 
2386 	case KIWI_DEVICE_ID:
2387 		*hif_type = HIF_TYPE_KIWI;
2388 		*target_type = TARGET_TYPE_KIWI;
2389 		hif_info(" *********** KIWI *************");
2390 		break;
2391 
2392 	case MANGO_DEVICE_ID:
2393 		*hif_type = HIF_TYPE_MANGO;
2394 		*target_type = TARGET_TYPE_MANGO;
2395 		hif_info(" *********** MANGO *************");
2396 		break;
2397 
2398 	case PEACH_DEVICE_ID:
2399 		*hif_type = HIF_TYPE_PEACH;
2400 		*target_type = TARGET_TYPE_PEACH;
2401 		hif_info(" *********** PEACH *************");
2402 		break;
2403 
2404 	case QCA8074V2_DEVICE_ID:
2405 		*hif_type = HIF_TYPE_QCA8074V2;
2406 		*target_type = TARGET_TYPE_QCA8074V2;
2407 		hif_info(" *********** QCA8074V2 *************");
2408 		break;
2409 
2410 	case QCA6018_DEVICE_ID:
2411 	case RUMIM2M_DEVICE_ID_NODE0:
2412 	case RUMIM2M_DEVICE_ID_NODE1:
2413 	case RUMIM2M_DEVICE_ID_NODE2:
2414 	case RUMIM2M_DEVICE_ID_NODE3:
2415 	case RUMIM2M_DEVICE_ID_NODE4:
2416 	case RUMIM2M_DEVICE_ID_NODE5:
2417 		*hif_type = HIF_TYPE_QCA6018;
2418 		*target_type = TARGET_TYPE_QCA6018;
2419 		hif_info(" *********** QCA6018 *************");
2420 		break;
2421 
2422 	case QCA5018_DEVICE_ID:
2423 		*hif_type = HIF_TYPE_QCA5018;
2424 		*target_type = TARGET_TYPE_QCA5018;
2425 		hif_info(" *********** qca5018 *************");
2426 		break;
2427 
2428 	case QCA5332_DEVICE_ID:
2429 		*hif_type = HIF_TYPE_QCA5332;
2430 		*target_type = TARGET_TYPE_QCA5332;
2431 		hif_info(" *********** QCA5332 *************");
2432 		break;
2433 
2434 	case QCA9574_DEVICE_ID:
2435 		*hif_type = HIF_TYPE_QCA9574;
2436 		*target_type = TARGET_TYPE_QCA9574;
2437 		hif_info(" *********** QCA9574 *************");
2438 		break;
2439 
2440 	case WCN6450_DEVICE_ID:
2441 		*hif_type = HIF_TYPE_WCN6450;
2442 		*target_type = TARGET_TYPE_WCN6450;
2443 		hif_info(" *********** WCN6450 *************");
2444 		break;
2445 
2446 	default:
2447 		hif_err("Unsupported device ID = 0x%x!", device_id);
2448 		ret = -ENODEV;
2449 		break;
2450 	}
2451 
2452 	if (*target_type == TARGET_TYPE_UNKNOWN) {
2453 		hif_err("Unsupported target_type!");
2454 		ret = -ENODEV;
2455 	}
2456 end:
2457 	return ret;
2458 }
2459 
2460 /**
2461  * hif_get_bus_type() - return the bus type
2462  * @hif_hdl: HIF Context
2463  *
2464  * Return: enum qdf_bus_type
2465  */
2466 enum qdf_bus_type hif_get_bus_type(struct hif_opaque_softc *hif_hdl)
2467 {
2468 	struct hif_softc *scn = HIF_GET_SOFTC(hif_hdl);
2469 
2470 	return scn->bus_type;
2471 }
2472 
2473 /*
2474  * Target info and ini parameters are global to the driver
2475  * Hence these structures are exposed to all the modules in
2476  * the driver and they don't need to maintains multiple copies
2477  * of the same info, instead get the handle from hif and
2478  * modify them in hif
2479  */
2480 
2481 /**
2482  * hif_get_ini_handle() - API to get hif_config_param handle
2483  * @hif_ctx: HIF Context
2484  *
2485  * Return: pointer to hif_config_info
2486  */
2487 struct hif_config_info *hif_get_ini_handle(struct hif_opaque_softc *hif_ctx)
2488 {
2489 	struct hif_softc *sc = HIF_GET_SOFTC(hif_ctx);
2490 
2491 	return &sc->hif_config;
2492 }
2493 
2494 /**
2495  * hif_get_target_info_handle() - API to get hif_target_info handle
2496  * @hif_ctx: HIF context
2497  *
2498  * Return: Pointer to hif_target_info
2499  */
2500 struct hif_target_info *hif_get_target_info_handle(
2501 					struct hif_opaque_softc *hif_ctx)
2502 {
2503 	struct hif_softc *sc = HIF_GET_SOFTC(hif_ctx);
2504 
2505 	return &sc->target_info;
2506 
2507 }
2508 qdf_export_symbol(hif_get_target_info_handle);
2509 
2510 #ifdef RECEIVE_OFFLOAD
2511 void hif_offld_flush_cb_register(struct hif_opaque_softc *scn,
2512 				 void (offld_flush_handler)(void *))
2513 {
2514 	if (hif_napi_enabled(scn, -1))
2515 		hif_napi_rx_offld_flush_cb_register(scn, offld_flush_handler);
2516 	else
2517 		hif_err("NAPI not enabled");
2518 }
2519 qdf_export_symbol(hif_offld_flush_cb_register);
2520 
2521 void hif_offld_flush_cb_deregister(struct hif_opaque_softc *scn)
2522 {
2523 	if (hif_napi_enabled(scn, -1))
2524 		hif_napi_rx_offld_flush_cb_deregister(scn);
2525 	else
2526 		hif_err("NAPI not enabled");
2527 }
2528 qdf_export_symbol(hif_offld_flush_cb_deregister);
2529 
2530 int hif_get_rx_ctx_id(int ctx_id, struct hif_opaque_softc *hif_hdl)
2531 {
2532 	if (hif_napi_enabled(hif_hdl, -1))
2533 		return NAPI_PIPE2ID(ctx_id);
2534 	else
2535 		return ctx_id;
2536 }
2537 #else /* RECEIVE_OFFLOAD */
2538 int hif_get_rx_ctx_id(int ctx_id, struct hif_opaque_softc *hif_hdl)
2539 {
2540 	return 0;
2541 }
2542 qdf_export_symbol(hif_get_rx_ctx_id);
2543 #endif /* RECEIVE_OFFLOAD */
2544 
2545 #if defined(FEATURE_LRO)
2546 
2547 /**
2548  * hif_get_lro_info - Returns LRO instance for instance ID
2549  * @ctx_id: LRO instance ID
2550  * @hif_hdl: HIF Context
2551  *
2552  * Return: Pointer to LRO instance.
2553  */
2554 void *hif_get_lro_info(int ctx_id, struct hif_opaque_softc *hif_hdl)
2555 {
2556 	void *data;
2557 
2558 	if (hif_napi_enabled(hif_hdl, -1))
2559 		data = hif_napi_get_lro_info(hif_hdl, ctx_id);
2560 	else
2561 		data = hif_ce_get_lro_ctx(hif_hdl, ctx_id);
2562 
2563 	return data;
2564 }
2565 #endif
2566 
2567 /**
2568  * hif_get_target_status - API to get target status
2569  * @hif_ctx: HIF Context
2570  *
2571  * Return: enum hif_target_status
2572  */
2573 enum hif_target_status hif_get_target_status(struct hif_opaque_softc *hif_ctx)
2574 {
2575 	struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
2576 
2577 	return scn->target_status;
2578 }
2579 qdf_export_symbol(hif_get_target_status);
2580 
2581 /**
2582  * hif_set_target_status() - API to set target status
2583  * @hif_ctx: HIF Context
2584  * @status: Target Status
2585  *
2586  * Return: void
2587  */
2588 void hif_set_target_status(struct hif_opaque_softc *hif_ctx, enum
2589 			   hif_target_status status)
2590 {
2591 	struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
2592 
2593 	scn->target_status = status;
2594 }
2595 
2596 /**
2597  * hif_init_ini_config() - API to initialize HIF configuration parameters
2598  * @hif_ctx: HIF Context
2599  * @cfg: HIF Configuration
2600  *
2601  * Return: void
2602  */
2603 void hif_init_ini_config(struct hif_opaque_softc *hif_ctx,
2604 			 struct hif_config_info *cfg)
2605 {
2606 	struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
2607 
2608 	qdf_mem_copy(&scn->hif_config, cfg, sizeof(struct hif_config_info));
2609 }
2610 
2611 /**
2612  * hif_get_conparam() - API to get driver mode in HIF
2613  * @scn: HIF Context
2614  *
2615  * Return: driver mode of operation
2616  */
2617 uint32_t hif_get_conparam(struct hif_softc *scn)
2618 {
2619 	if (!scn)
2620 		return 0;
2621 
2622 	return scn->hif_con_param;
2623 }
2624 
2625 /**
2626  * hif_get_callbacks_handle() - API to get callbacks Handle
2627  * @scn: HIF Context
2628  *
2629  * Return: pointer to HIF Callbacks
2630  */
2631 struct hif_driver_state_callbacks *hif_get_callbacks_handle(
2632 							struct hif_softc *scn)
2633 {
2634 	return &scn->callbacks;
2635 }
2636 
2637 /**
2638  * hif_is_driver_unloading() - API to query upper layers if driver is unloading
2639  * @scn: HIF Context
2640  *
2641  * Return: True/False
2642  */
2643 bool hif_is_driver_unloading(struct hif_softc *scn)
2644 {
2645 	struct hif_driver_state_callbacks *cbk = hif_get_callbacks_handle(scn);
2646 
2647 	if (cbk && cbk->is_driver_unloading)
2648 		return cbk->is_driver_unloading(cbk->context);
2649 
2650 	return false;
2651 }
2652 
2653 /**
2654  * hif_is_load_or_unload_in_progress() - API to query upper layers if
2655  * load/unload in progress
2656  * @scn: HIF Context
2657  *
2658  * Return: True/False
2659  */
2660 bool hif_is_load_or_unload_in_progress(struct hif_softc *scn)
2661 {
2662 	struct hif_driver_state_callbacks *cbk = hif_get_callbacks_handle(scn);
2663 
2664 	if (cbk && cbk->is_load_unload_in_progress)
2665 		return cbk->is_load_unload_in_progress(cbk->context);
2666 
2667 	return false;
2668 }
2669 
2670 /**
2671  * hif_is_recovery_in_progress() - API to query upper layers if recovery in
2672  * progress
2673  * @scn: HIF Context
2674  *
2675  * Return: True/False
2676  */
2677 bool hif_is_recovery_in_progress(struct hif_softc *scn)
2678 {
2679 	struct hif_driver_state_callbacks *cbk = hif_get_callbacks_handle(scn);
2680 
2681 	if (cbk && cbk->is_recovery_in_progress)
2682 		return cbk->is_recovery_in_progress(cbk->context);
2683 
2684 	return false;
2685 }
2686 
2687 #if defined(HIF_PCI) || defined(HIF_SNOC) || defined(HIF_AHB) || \
2688     defined(HIF_IPCI)
2689 
2690 /**
2691  * hif_update_pipe_callback() - API to register pipe specific callbacks
2692  * @osc: Opaque softc
2693  * @pipeid: pipe id
2694  * @callbacks: callbacks to register
2695  *
2696  * Return: void
2697  */
2698 
2699 void hif_update_pipe_callback(struct hif_opaque_softc *osc,
2700 					u_int8_t pipeid,
2701 					struct hif_msg_callbacks *callbacks)
2702 {
2703 	struct hif_softc *scn = HIF_GET_SOFTC(osc);
2704 	struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn);
2705 	struct HIF_CE_pipe_info *pipe_info;
2706 
2707 	QDF_BUG(pipeid < CE_COUNT_MAX);
2708 
2709 	hif_debug("pipeid: %d", pipeid);
2710 
2711 	pipe_info = &hif_state->pipe_info[pipeid];
2712 
2713 	qdf_mem_copy(&pipe_info->pipe_callbacks,
2714 			callbacks, sizeof(pipe_info->pipe_callbacks));
2715 }
2716 qdf_export_symbol(hif_update_pipe_callback);
2717 
2718 /**
2719  * hif_is_target_ready() - API to query if target is in ready state
2720  * progress
2721  * @scn: HIF Context
2722  *
2723  * Return: True/False
2724  */
2725 bool hif_is_target_ready(struct hif_softc *scn)
2726 {
2727 	struct hif_driver_state_callbacks *cbk = hif_get_callbacks_handle(scn);
2728 
2729 	if (cbk && cbk->is_target_ready)
2730 		return cbk->is_target_ready(cbk->context);
2731 	/*
2732 	 * if callback is not registered then there is no way to determine
2733 	 * if target is ready. In-such case return true to indicate that
2734 	 * target is ready.
2735 	 */
2736 	return true;
2737 }
2738 qdf_export_symbol(hif_is_target_ready);
2739 
2740 int hif_get_bandwidth_level(struct hif_opaque_softc *hif_handle)
2741 {
2742 	struct hif_softc *scn = HIF_GET_SOFTC(hif_handle);
2743 	struct hif_driver_state_callbacks *cbk = hif_get_callbacks_handle(scn);
2744 
2745 	if (cbk && cbk->get_bandwidth_level)
2746 		return cbk->get_bandwidth_level(cbk->context);
2747 
2748 	return 0;
2749 }
2750 
2751 qdf_export_symbol(hif_get_bandwidth_level);
2752 
2753 #ifdef DP_MEM_PRE_ALLOC
2754 void *hif_mem_alloc_consistent_unaligned(struct hif_softc *scn,
2755 					 qdf_size_t size,
2756 					 qdf_dma_addr_t *paddr,
2757 					 uint32_t ring_type,
2758 					 uint8_t *is_mem_prealloc)
2759 {
2760 	void *vaddr = NULL;
2761 	struct hif_driver_state_callbacks *cbk =
2762 				hif_get_callbacks_handle(scn);
2763 
2764 	*is_mem_prealloc = false;
2765 	if (cbk && cbk->prealloc_get_consistent_mem_unaligned) {
2766 		vaddr = cbk->prealloc_get_consistent_mem_unaligned(size,
2767 								   paddr,
2768 								   ring_type);
2769 		if (vaddr) {
2770 			*is_mem_prealloc = true;
2771 			goto end;
2772 		}
2773 	}
2774 
2775 	vaddr = qdf_mem_alloc_consistent(scn->qdf_dev,
2776 					 scn->qdf_dev->dev,
2777 					 size,
2778 					 paddr);
2779 end:
2780 	dp_info("%s va_unaligned %pK pa_unaligned %pK size %d ring_type %d",
2781 		*is_mem_prealloc ? "pre-alloc" : "dynamic-alloc", vaddr,
2782 		(void *)*paddr, (int)size, ring_type);
2783 
2784 	return vaddr;
2785 }
2786 
2787 void hif_mem_free_consistent_unaligned(struct hif_softc *scn,
2788 				       qdf_size_t size,
2789 				       void *vaddr,
2790 				       qdf_dma_addr_t paddr,
2791 				       qdf_dma_context_t memctx,
2792 				       uint8_t is_mem_prealloc)
2793 {
2794 	struct hif_driver_state_callbacks *cbk =
2795 				hif_get_callbacks_handle(scn);
2796 
2797 	if (is_mem_prealloc) {
2798 		if (cbk && cbk->prealloc_put_consistent_mem_unaligned) {
2799 			cbk->prealloc_put_consistent_mem_unaligned(vaddr);
2800 		} else {
2801 			dp_warn("dp_prealloc_put_consistent_unligned NULL");
2802 			QDF_BUG(0);
2803 		}
2804 	} else {
2805 		qdf_mem_free_consistent(scn->qdf_dev, scn->qdf_dev->dev,
2806 					size, vaddr, paddr, memctx);
2807 	}
2808 }
2809 
2810 void hif_prealloc_get_multi_pages(struct hif_softc *scn, uint32_t desc_type,
2811 				  qdf_size_t elem_size, uint16_t elem_num,
2812 				  struct qdf_mem_multi_page_t *pages,
2813 				  bool cacheable)
2814 {
2815 	struct hif_driver_state_callbacks *cbk =
2816 			hif_get_callbacks_handle(scn);
2817 
2818 	if (cbk && cbk->prealloc_get_multi_pages)
2819 		cbk->prealloc_get_multi_pages(desc_type, elem_size, elem_num,
2820 					      pages, cacheable);
2821 
2822 	if (!pages->num_pages)
2823 		qdf_mem_multi_pages_alloc(scn->qdf_dev, pages,
2824 					  elem_size, elem_num, 0, cacheable);
2825 }
2826 
2827 void hif_prealloc_put_multi_pages(struct hif_softc *scn, uint32_t desc_type,
2828 				  struct qdf_mem_multi_page_t *pages,
2829 				  bool cacheable)
2830 {
2831 	struct hif_driver_state_callbacks *cbk =
2832 			hif_get_callbacks_handle(scn);
2833 
2834 	if (cbk && cbk->prealloc_put_multi_pages &&
2835 	    pages->is_mem_prealloc)
2836 		cbk->prealloc_put_multi_pages(desc_type, pages);
2837 
2838 	if (!pages->is_mem_prealloc)
2839 		qdf_mem_multi_pages_free(scn->qdf_dev, pages, 0,
2840 					 cacheable);
2841 }
2842 #endif
2843 
2844 /**
2845  * hif_batch_send() - API to access hif specific function
2846  * ce_batch_send.
2847  * @osc: HIF Context
2848  * @msdu: list of msdus to be sent
2849  * @transfer_id: transfer id
2850  * @len: downloaded length
2851  * @sendhead:
2852  *
2853  * Return: list of msds not sent
2854  */
2855 qdf_nbuf_t hif_batch_send(struct hif_opaque_softc *osc, qdf_nbuf_t msdu,
2856 		uint32_t transfer_id, u_int32_t len, uint32_t sendhead)
2857 {
2858 	void *ce_tx_hdl = hif_get_ce_handle(osc, CE_HTT_TX_CE);
2859 
2860 	if (!ce_tx_hdl)
2861 		return NULL;
2862 
2863 	return ce_batch_send((struct CE_handle *)ce_tx_hdl, msdu, transfer_id,
2864 			len, sendhead);
2865 }
2866 qdf_export_symbol(hif_batch_send);
2867 
2868 /**
2869  * hif_update_tx_ring() - API to access hif specific function
2870  * ce_update_tx_ring.
2871  * @osc: HIF Context
2872  * @num_htt_cmpls: number of htt compl received.
2873  *
2874  * Return: void
2875  */
2876 void hif_update_tx_ring(struct hif_opaque_softc *osc, u_int32_t num_htt_cmpls)
2877 {
2878 	void *ce_tx_hdl = hif_get_ce_handle(osc, CE_HTT_TX_CE);
2879 
2880 	ce_update_tx_ring(ce_tx_hdl, num_htt_cmpls);
2881 }
2882 qdf_export_symbol(hif_update_tx_ring);
2883 
2884 
2885 /**
2886  * hif_send_single() - API to access hif specific function
2887  * ce_send_single.
2888  * @osc: HIF Context
2889  * @msdu : msdu to be sent
2890  * @transfer_id: transfer id
2891  * @len : downloaded length
2892  *
2893  * Return: msdu sent status
2894  */
2895 QDF_STATUS hif_send_single(struct hif_opaque_softc *osc, qdf_nbuf_t msdu,
2896 			   uint32_t transfer_id, u_int32_t len)
2897 {
2898 	void *ce_tx_hdl = hif_get_ce_handle(osc, CE_HTT_TX_CE);
2899 
2900 	if (!ce_tx_hdl)
2901 		return QDF_STATUS_E_NULL_VALUE;
2902 
2903 	return ce_send_single((struct CE_handle *)ce_tx_hdl, msdu, transfer_id,
2904 			len);
2905 }
2906 qdf_export_symbol(hif_send_single);
2907 #endif
2908 
2909 /**
2910  * hif_reg_write() - API to access hif specific function
2911  * hif_write32_mb.
2912  * @hif_ctx : HIF Context
2913  * @offset : offset on which value has to be written
2914  * @value : value to be written
2915  *
2916  * Return: None
2917  */
2918 void hif_reg_write(struct hif_opaque_softc *hif_ctx, uint32_t offset,
2919 		uint32_t value)
2920 {
2921 	struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
2922 
2923 	hif_write32_mb(scn, scn->mem + offset, value);
2924 
2925 }
2926 qdf_export_symbol(hif_reg_write);
2927 
2928 /**
2929  * hif_reg_read() - API to access hif specific function
2930  * hif_read32_mb.
2931  * @hif_ctx : HIF Context
2932  * @offset : offset from which value has to be read
2933  *
2934  * Return: Read value
2935  */
2936 uint32_t hif_reg_read(struct hif_opaque_softc *hif_ctx, uint32_t offset)
2937 {
2938 
2939 	struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
2940 
2941 	return hif_read32_mb(scn, scn->mem + offset);
2942 }
2943 qdf_export_symbol(hif_reg_read);
2944 
2945 /**
2946  * hif_ramdump_handler(): generic ramdump handler
2947  * @scn: struct hif_opaque_softc
2948  *
2949  * Return: None
2950  */
2951 void hif_ramdump_handler(struct hif_opaque_softc *scn)
2952 {
2953 	if (hif_get_bus_type(scn) == QDF_BUS_TYPE_USB)
2954 		hif_usb_ramdump_handler(scn);
2955 }
2956 
2957 hif_pm_wake_irq_type hif_pm_get_wake_irq_type(struct hif_opaque_softc *hif_ctx)
2958 {
2959 	struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
2960 
2961 	return scn->wake_irq_type;
2962 }
2963 
2964 irqreturn_t hif_wake_interrupt_handler(int irq, void *context)
2965 {
2966 	struct hif_softc *scn = context;
2967 
2968 	hif_info("wake interrupt received on irq %d", irq);
2969 
2970 	hif_rtpm_set_monitor_wake_intr(0);
2971 	hif_rtpm_request_resume();
2972 
2973 	if (scn->initial_wakeup_cb)
2974 		scn->initial_wakeup_cb(scn->initial_wakeup_priv);
2975 
2976 	if (hif_is_ut_suspended(scn))
2977 		hif_ut_fw_resume(scn);
2978 
2979 	qdf_pm_system_wakeup();
2980 
2981 	return IRQ_HANDLED;
2982 }
2983 
2984 void hif_set_initial_wakeup_cb(struct hif_opaque_softc *hif_ctx,
2985 			       void (*callback)(void *),
2986 			       void *priv)
2987 {
2988 	struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
2989 
2990 	scn->initial_wakeup_cb = callback;
2991 	scn->initial_wakeup_priv = priv;
2992 }
2993 
2994 void hif_set_ce_service_max_yield_time(struct hif_opaque_softc *hif,
2995 				       uint32_t ce_service_max_yield_time)
2996 {
2997 	struct hif_softc *hif_ctx = HIF_GET_SOFTC(hif);
2998 
2999 	hif_ctx->ce_service_max_yield_time =
3000 		ce_service_max_yield_time * 1000;
3001 }
3002 
3003 unsigned long long
3004 hif_get_ce_service_max_yield_time(struct hif_opaque_softc *hif)
3005 {
3006 	struct hif_softc *hif_ctx = HIF_GET_SOFTC(hif);
3007 
3008 	return hif_ctx->ce_service_max_yield_time;
3009 }
3010 
3011 void hif_set_ce_service_max_rx_ind_flush(struct hif_opaque_softc *hif,
3012 				       uint8_t ce_service_max_rx_ind_flush)
3013 {
3014 	struct hif_softc *hif_ctx = HIF_GET_SOFTC(hif);
3015 
3016 	if (ce_service_max_rx_ind_flush == 0 ||
3017 	    ce_service_max_rx_ind_flush > MSG_FLUSH_NUM)
3018 		hif_ctx->ce_service_max_rx_ind_flush = MSG_FLUSH_NUM;
3019 	else
3020 		hif_ctx->ce_service_max_rx_ind_flush =
3021 						ce_service_max_rx_ind_flush;
3022 }
3023 
3024 #ifdef SYSTEM_PM_CHECK
3025 void __hif_system_pm_set_state(struct hif_opaque_softc *hif,
3026 			       enum hif_system_pm_state state)
3027 {
3028 	struct hif_softc *hif_ctx = HIF_GET_SOFTC(hif);
3029 
3030 	qdf_atomic_set(&hif_ctx->sys_pm_state, state);
3031 }
3032 
3033 int32_t hif_system_pm_get_state(struct hif_opaque_softc *hif)
3034 {
3035 	struct hif_softc *hif_ctx = HIF_GET_SOFTC(hif);
3036 
3037 	return qdf_atomic_read(&hif_ctx->sys_pm_state);
3038 }
3039 
3040 int hif_system_pm_state_check(struct hif_opaque_softc *hif)
3041 {
3042 	struct hif_softc *hif_ctx = HIF_GET_SOFTC(hif);
3043 	int32_t sys_pm_state;
3044 
3045 	if (!hif_ctx) {
3046 		hif_err("hif context is null");
3047 		return -EFAULT;
3048 	}
3049 
3050 	sys_pm_state = qdf_atomic_read(&hif_ctx->sys_pm_state);
3051 	if (sys_pm_state == HIF_SYSTEM_PM_STATE_BUS_SUSPENDING ||
3052 	    sys_pm_state == HIF_SYSTEM_PM_STATE_BUS_SUSPENDED) {
3053 		hif_info("Triggering system wakeup");
3054 		qdf_pm_system_wakeup();
3055 		return -EAGAIN;
3056 	}
3057 
3058 	return 0;
3059 }
3060 #endif
3061 #ifdef WLAN_FEATURE_AFFINITY_MGR
3062 /*
3063  * hif_audio_cpu_affinity_allowed() - Check if audio cpu affinity allowed
3064  *
3065  * @scn: hif handle
3066  * @cfg: hif affinity manager configuration for IRQ
3067  * @audio_taken_cpu: Current CPUs which are taken by audio.
3068  * @current_time: Current system time.
3069  *
3070  * This API checks for 2 conditions
3071  *  1) Last audio taken mask and current taken mask are different
3072  *  2) Last time when IRQ was affined away due to audio taken CPUs is
3073  *     more than time threshold (5 Seconds in current case).
3074  * If both condition satisfies then only return true.
3075  *
3076  * Return: bool: true if it is allowed to affine away audio taken cpus.
3077  */
3078 static inline bool
3079 hif_audio_cpu_affinity_allowed(struct hif_softc *scn,
3080 			       struct hif_cpu_affinity *cfg,
3081 			       qdf_cpu_mask audio_taken_cpu,
3082 			       uint64_t current_time)
3083 {
3084 	if (!qdf_cpumask_equal(&audio_taken_cpu, &cfg->walt_taken_mask) &&
3085 	    (qdf_log_timestamp_to_usecs(current_time -
3086 			 cfg->last_affined_away)
3087 		< scn->time_threshold))
3088 		return false;
3089 	return true;
3090 }
3091 
3092 /*
3093  * hif_affinity_mgr_check_update_mask() - Check if cpu mask need to be updated
3094  *
3095  * @scn: hif handle
3096  * @cfg: hif affinity manager configuration for IRQ
3097  * @audio_taken_cpu: Current CPUs which are taken by audio.
3098  * @cpu_mask: CPU mask which need to be updated.
3099  * @current_time: Current system time.
3100  *
3101  * This API checks if Pro audio use case is running and if cpu_mask need
3102  * to be updated
3103  *
3104  * Return: QDF_STATUS
3105  */
3106 static inline QDF_STATUS
3107 hif_affinity_mgr_check_update_mask(struct hif_softc *scn,
3108 				   struct hif_cpu_affinity *cfg,
3109 				   qdf_cpu_mask audio_taken_cpu,
3110 				   qdf_cpu_mask *cpu_mask,
3111 				   uint64_t current_time)
3112 {
3113 	qdf_cpu_mask allowed_mask;
3114 
3115 	/*
3116 	 * Case 1: audio_taken_mask is empty
3117 	 *   Check if passed cpu_mask and wlan_requested_mask is same or not.
3118 	 *      If both mask are different copy wlan_requested_mask(IRQ affinity
3119 	 *      mask requested by WLAN) to cpu_mask.
3120 	 *
3121 	 * Case 2: audio_taken_mask is not empty
3122 	 *   1. Only allow update if last time when IRQ was affined away due to
3123 	 *      audio taken CPUs is more than 5 seconds or update is requested
3124 	 *      by WLAN
3125 	 *   2. Only allow silver cores to be affined away.
3126 	 *   3. Check if any allowed CPUs for audio use case is set in cpu_mask.
3127 	 *       i. If any CPU mask is set, mask out that CPU from the cpu_mask
3128 	 *       ii. If after masking out audio taken cpu(Silver cores) cpu_mask
3129 	 *           is empty, set mask to all cpu except cpus taken by audio.
3130 	 * Example:
3131 	 *| Audio mask | mask allowed | cpu_mask | WLAN req mask | new cpu_mask|
3132 	 *|  0x00      |       0x00   |   0x0C   |       0x0C    |      0x0C   |
3133 	 *|  0x00      |       0x00   |   0x03   |       0x03    |      0x03   |
3134 	 *|  0x00      |       0x00   |   0xFC   |       0x03    |      0x03   |
3135 	 *|  0x00      |       0x00   |   0x03   |       0x0C    |      0x0C   |
3136 	 *|  0x0F      |       0x03   |   0x0C   |       0x0C    |      0x0C   |
3137 	 *|  0x0F      |       0x03   |   0x03   |       0x03    |      0xFC   |
3138 	 *|  0x03      |       0x03   |   0x0C   |       0x0C    |      0x0C   |
3139 	 *|  0x03      |       0x03   |   0x03   |       0x03    |      0xFC   |
3140 	 *|  0x03      |       0x03   |   0xFC   |       0x03    |      0xFC   |
3141 	 *|  0xF0      |       0x00   |   0x0C   |       0x0C    |      0x0C   |
3142 	 *|  0xF0      |       0x00   |   0x03   |       0x03    |      0x03   |
3143 	 */
3144 
3145 	/* Check if audio taken mask is empty*/
3146 	if (qdf_likely(qdf_cpumask_empty(&audio_taken_cpu))) {
3147 		/* If CPU mask requested by WLAN for the IRQ and
3148 		 * cpu_mask passed CPU mask set for IRQ is different
3149 		 * Copy requested mask into cpu_mask and return
3150 		 */
3151 		if (qdf_unlikely(!qdf_cpumask_equal(cpu_mask,
3152 						    &cfg->wlan_requested_mask))) {
3153 			qdf_cpumask_copy(cpu_mask, &cfg->wlan_requested_mask);
3154 			return QDF_STATUS_SUCCESS;
3155 		}
3156 		return QDF_STATUS_E_ALREADY;
3157 	}
3158 
3159 	if (!(hif_audio_cpu_affinity_allowed(scn, cfg, audio_taken_cpu,
3160 					     current_time) ||
3161 	      cfg->update_requested))
3162 		return QDF_STATUS_E_AGAIN;
3163 
3164 	/* Only allow Silver cores to be affine away */
3165 	qdf_cpumask_and(&allowed_mask, &scn->allowed_mask, &audio_taken_cpu);
3166 	if (qdf_cpumask_intersects(cpu_mask, &allowed_mask)) {
3167 		/* If any of taken CPU(Silver cores) mask is set in cpu_mask,
3168 		 *  mask out the audio taken CPUs from the cpu_mask.
3169 		 */
3170 		qdf_cpumask_andnot(cpu_mask, &cfg->wlan_requested_mask,
3171 				   &allowed_mask);
3172 		/* If cpu_mask is empty set it to all CPUs
3173 		 * except taken by audio(Silver cores)
3174 		 */
3175 		if (qdf_unlikely(qdf_cpumask_empty(cpu_mask)))
3176 			qdf_cpumask_complement(cpu_mask, &allowed_mask);
3177 		return QDF_STATUS_SUCCESS;
3178 	}
3179 
3180 	return QDF_STATUS_E_ALREADY;
3181 }
3182 
3183 static inline QDF_STATUS
3184 hif_check_and_affine_irq(struct hif_softc *scn, struct hif_cpu_affinity *cfg,
3185 			 qdf_cpu_mask audio_taken_cpu, qdf_cpu_mask cpu_mask,
3186 			 uint64_t current_time)
3187 {
3188 	QDF_STATUS status;
3189 
3190 	status = hif_affinity_mgr_check_update_mask(scn, cfg,
3191 						    audio_taken_cpu,
3192 						    &cpu_mask,
3193 						    current_time);
3194 	/* Set IRQ affinity if CPU mask was updated */
3195 	if (QDF_IS_STATUS_SUCCESS(status)) {
3196 		status = hif_irq_set_affinity_hint(cfg->irq,
3197 						   &cpu_mask);
3198 		if (QDF_IS_STATUS_SUCCESS(status)) {
3199 			/* Store audio taken CPU mask */
3200 			qdf_cpumask_copy(&cfg->walt_taken_mask,
3201 					 &audio_taken_cpu);
3202 			/* Store CPU mask which was set for IRQ*/
3203 			qdf_cpumask_copy(&cfg->current_irq_mask,
3204 					 &cpu_mask);
3205 			/* Set time when IRQ affinity was updated */
3206 			cfg->last_updated = current_time;
3207 			if (hif_audio_cpu_affinity_allowed(scn, cfg,
3208 							   audio_taken_cpu,
3209 							   current_time))
3210 				/* If CPU mask was updated due to CPU
3211 				 * taken by audio, update
3212 				 * last_affined_away time
3213 				 */
3214 				cfg->last_affined_away = current_time;
3215 		}
3216 	}
3217 
3218 	return status;
3219 }
3220 
3221 void hif_affinity_mgr_affine_irq(struct hif_softc *scn)
3222 {
3223 	bool audio_affinity_allowed = false;
3224 	int i, j, ce_id;
3225 	uint64_t current_time;
3226 	char cpu_str[10];
3227 	QDF_STATUS status;
3228 	qdf_cpu_mask cpu_mask, audio_taken_cpu;
3229 	struct HIF_CE_state *hif_state;
3230 	struct hif_exec_context *hif_ext_group;
3231 	struct CE_attr *host_ce_conf;
3232 	struct HIF_CE_state *ce_sc;
3233 	struct hif_cpu_affinity *cfg;
3234 
3235 	if (!scn->affinity_mgr_supported)
3236 		return;
3237 
3238 	current_time = hif_get_log_timestamp();
3239 	/* Get CPU mask for audio taken CPUs */
3240 	audio_taken_cpu = qdf_walt_get_cpus_taken();
3241 
3242 	ce_sc = HIF_GET_CE_STATE(scn);
3243 	host_ce_conf = ce_sc->host_ce_config;
3244 	for (ce_id = 0; ce_id < scn->ce_count; ce_id++) {
3245 		if (host_ce_conf[ce_id].flags & CE_ATTR_DISABLE_INTR)
3246 			continue;
3247 		cfg = &scn->ce_irq_cpu_mask[ce_id];
3248 		qdf_cpumask_copy(&cpu_mask, &cfg->current_irq_mask);
3249 		status =
3250 			hif_check_and_affine_irq(scn, cfg, audio_taken_cpu,
3251 						 cpu_mask, current_time);
3252 		if (QDF_IS_STATUS_SUCCESS(status))
3253 			audio_affinity_allowed = true;
3254 	}
3255 
3256 	hif_state = HIF_GET_CE_STATE(scn);
3257 	for (i = 0; i < hif_state->hif_num_extgroup; i++) {
3258 		hif_ext_group = hif_state->hif_ext_group[i];
3259 		for (j = 0; j < hif_ext_group->numirq; j++) {
3260 			cfg = &scn->irq_cpu_mask[hif_ext_group->grp_id][j];
3261 			qdf_cpumask_copy(&cpu_mask, &cfg->current_irq_mask);
3262 			status =
3263 				hif_check_and_affine_irq(scn, cfg, audio_taken_cpu,
3264 							 cpu_mask, current_time);
3265 			if (QDF_IS_STATUS_SUCCESS(status)) {
3266 				qdf_atomic_set(&hif_ext_group->force_napi_complete, -1);
3267 				audio_affinity_allowed = true;
3268 			}
3269 		}
3270 	}
3271 	if (audio_affinity_allowed) {
3272 		qdf_thread_cpumap_print_to_pagebuf(false, cpu_str,
3273 						   &audio_taken_cpu);
3274 		hif_info("Audio taken CPU mask: %s", cpu_str);
3275 	}
3276 }
3277 
3278 static inline QDF_STATUS
3279 hif_affinity_mgr_set_irq_affinity(struct hif_softc *scn, uint32_t irq,
3280 				  struct hif_cpu_affinity *cfg,
3281 				  qdf_cpu_mask *cpu_mask)
3282 {
3283 	uint64_t current_time;
3284 	char cpu_str[10];
3285 	QDF_STATUS status, mask_updated;
3286 	qdf_cpu_mask audio_taken_cpu = qdf_walt_get_cpus_taken();
3287 
3288 	current_time = hif_get_log_timestamp();
3289 	qdf_cpumask_copy(&cfg->wlan_requested_mask, cpu_mask);
3290 	cfg->update_requested = true;
3291 	mask_updated = hif_affinity_mgr_check_update_mask(scn, cfg,
3292 							  audio_taken_cpu,
3293 							  cpu_mask,
3294 							  current_time);
3295 	status = hif_irq_set_affinity_hint(irq, cpu_mask);
3296 	if (QDF_IS_STATUS_SUCCESS(status)) {
3297 		qdf_cpumask_copy(&cfg->walt_taken_mask, &audio_taken_cpu);
3298 		qdf_cpumask_copy(&cfg->current_irq_mask, cpu_mask);
3299 		if (QDF_IS_STATUS_SUCCESS(mask_updated)) {
3300 			cfg->last_updated = current_time;
3301 			if (hif_audio_cpu_affinity_allowed(scn, cfg,
3302 							   audio_taken_cpu,
3303 							   current_time)) {
3304 				cfg->last_affined_away = current_time;
3305 				qdf_thread_cpumap_print_to_pagebuf(false,
3306 								   cpu_str,
3307 								   &audio_taken_cpu);
3308 				hif_info_rl("Audio taken CPU mask: %s",
3309 					    cpu_str);
3310 			}
3311 		}
3312 	}
3313 	cfg->update_requested = false;
3314 	return status;
3315 }
3316 
3317 QDF_STATUS
3318 hif_affinity_mgr_set_qrg_irq_affinity(struct hif_softc *scn, uint32_t irq,
3319 				      uint32_t grp_id, uint32_t irq_index,
3320 				      qdf_cpu_mask *cpu_mask)
3321 {
3322 	struct hif_cpu_affinity *cfg;
3323 
3324 	if (!scn->affinity_mgr_supported)
3325 		return hif_irq_set_affinity_hint(irq, cpu_mask);
3326 
3327 	cfg = &scn->irq_cpu_mask[grp_id][irq_index];
3328 	return hif_affinity_mgr_set_irq_affinity(scn, irq, cfg, cpu_mask);
3329 }
3330 
3331 QDF_STATUS
3332 hif_affinity_mgr_set_ce_irq_affinity(struct hif_softc *scn, uint32_t irq,
3333 				     uint32_t ce_id, qdf_cpu_mask *cpu_mask)
3334 {
3335 	struct hif_cpu_affinity *cfg;
3336 
3337 	if (!scn->affinity_mgr_supported)
3338 		return hif_irq_set_affinity_hint(irq, cpu_mask);
3339 
3340 	cfg = &scn->ce_irq_cpu_mask[ce_id];
3341 	return hif_affinity_mgr_set_irq_affinity(scn, irq, cfg, cpu_mask);
3342 }
3343 
3344 void
3345 hif_affinity_mgr_init_ce_irq(struct hif_softc *scn, int id, int irq)
3346 {
3347 	unsigned int cpus;
3348 	qdf_cpu_mask cpu_mask = {0};
3349 	struct hif_cpu_affinity *cfg = NULL;
3350 
3351 	if (!scn->affinity_mgr_supported)
3352 		return;
3353 
3354 	/* Set CPU Mask to Silver core */
3355 	qdf_for_each_possible_cpu(cpus)
3356 		if (qdf_topology_physical_package_id(cpus) ==
3357 		    CPU_CLUSTER_TYPE_LITTLE)
3358 			qdf_cpumask_set_cpu(cpus, &cpu_mask);
3359 
3360 	cfg = &scn->ce_irq_cpu_mask[id];
3361 	qdf_cpumask_copy(&cfg->current_irq_mask, &cpu_mask);
3362 	qdf_cpumask_copy(&cfg->wlan_requested_mask, &cpu_mask);
3363 	cfg->irq = irq;
3364 	cfg->last_updated = 0;
3365 	cfg->last_affined_away = 0;
3366 	cfg->update_requested = false;
3367 }
3368 
3369 void
3370 hif_affinity_mgr_init_grp_irq(struct hif_softc *scn, int grp_id,
3371 			      int irq_num, int irq)
3372 {
3373 	unsigned int cpus;
3374 	qdf_cpu_mask cpu_mask = {0};
3375 	struct hif_cpu_affinity *cfg = NULL;
3376 
3377 	if (!scn->affinity_mgr_supported)
3378 		return;
3379 
3380 	/* Set CPU Mask to Silver core */
3381 	qdf_for_each_possible_cpu(cpus)
3382 		if (qdf_topology_physical_package_id(cpus) ==
3383 		    CPU_CLUSTER_TYPE_LITTLE)
3384 			qdf_cpumask_set_cpu(cpus, &cpu_mask);
3385 
3386 	cfg = &scn->irq_cpu_mask[grp_id][irq_num];
3387 	qdf_cpumask_copy(&cfg->current_irq_mask, &cpu_mask);
3388 	qdf_cpumask_copy(&cfg->wlan_requested_mask, &cpu_mask);
3389 	cfg->irq = irq;
3390 	cfg->last_updated = 0;
3391 	cfg->last_affined_away = 0;
3392 	cfg->update_requested = false;
3393 }
3394 #endif
3395 
3396 #if defined(HIF_CPU_PERF_AFFINE_MASK) || \
3397 	defined(FEATURE_ENABLE_CE_DP_IRQ_AFFINE)
3398 void hif_config_irq_set_perf_affinity_hint(
3399 	struct hif_opaque_softc *hif_ctx)
3400 {
3401 	struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
3402 
3403 	hif_config_irq_affinity(scn);
3404 }
3405 
3406 qdf_export_symbol(hif_config_irq_set_perf_affinity_hint);
3407 #endif
3408