xref: /wlan-dirver/qca-wifi-host-cmn/htc/htc.c (revision 19ceffca9d494f2431432fa8123aa187c91cb4fb)
1 /*
2  * Copyright (c) 2013-2021 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2022 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 "htc_debug.h"
21 #include "htc_internal.h"
22 #include "htc_credit_history.h"
23 #include "htc_hang_event.h"
24 #include <hif.h>
25 #include <qdf_nbuf.h>           /* qdf_nbuf_t */
26 #include <qdf_types.h>          /* qdf_print */
27 
28 #define MAX_HTC_RX_BUNDLE  2
29 
30 #if defined(WLAN_DEBUG) || defined(DEBUG)
31 static ATH_DEBUG_MASK_DESCRIPTION g_htc_debug_description[] = {
32 	{ATH_DEBUG_SEND, "Send"},
33 	{ATH_DEBUG_RECV, "Recv"},
34 	{ATH_DEBUG_SYNC, "Sync"},
35 	{ATH_DEBUG_DUMP, "Dump Data (RX or TX)"},
36 	{ATH_DEBUG_SETUP, "Setup"},
37 };
38 
39 ATH_DEBUG_INSTANTIATE_MODULE_VAR(htc,
40 				 "htc",
41 				 "Host Target Communications",
42 				 ATH_DEBUG_MASK_DEFAULTS | ATH_DEBUG_INFO |
43 				 ATH_DEBUG_SETUP,
44 				 ATH_DEBUG_DESCRIPTION_COUNT
45 					 (g_htc_debug_description),
46 				 g_htc_debug_description);
47 
48 #endif
49 
50 #if defined(WMI_MULTI_MAC_SVC)
51 static const uint32_t svc_id[] = {WMI_CONTROL_SVC, WMI_CONTROL_SVC_WMAC1,
52 						WMI_CONTROL_SVC_WMAC2};
53 #else
54 static const uint32_t svc_id[] = {WMI_CONTROL_SVC};
55 #endif
56 
57 extern unsigned int htc_credit_flow;
58 
59 static void reset_endpoint_states(HTC_TARGET *target);
60 
61 static void destroy_htc_tx_ctrl_packet(HTC_PACKET *pPacket)
62 {
63 	qdf_nbuf_t netbuf;
64 
65 	netbuf = (qdf_nbuf_t) GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket);
66 	if (netbuf)
67 		qdf_nbuf_free(netbuf);
68 	qdf_mem_free(pPacket);
69 }
70 
71 static HTC_PACKET *build_htc_tx_ctrl_packet(qdf_device_t osdev)
72 {
73 	HTC_PACKET *pPacket = NULL;
74 	qdf_nbuf_t netbuf;
75 
76 	do {
77 		pPacket = (HTC_PACKET *) qdf_mem_malloc(sizeof(HTC_PACKET));
78 		if (!pPacket)
79 			break;
80 		netbuf = qdf_nbuf_alloc(osdev, HTC_CONTROL_BUFFER_SIZE,
81 					20, 4, true);
82 		if (!netbuf) {
83 			qdf_mem_free(pPacket);
84 			pPacket = NULL;
85 			break;
86 		}
87 		SET_HTC_PACKET_NET_BUF_CONTEXT(pPacket, netbuf);
88 	} while (false);
89 
90 	return pPacket;
91 }
92 
93 void htc_free_control_tx_packet(HTC_TARGET *target, HTC_PACKET *pPacket)
94 {
95 
96 #ifdef TODO_FIXME
97 	LOCK_HTC(target);
98 	HTC_PACKET_ENQUEUE(&target->ControlBufferTXFreeList, pPacket);
99 	UNLOCK_HTC(target);
100 	/* TODO_FIXME netbufs cannot be RESET! */
101 #else
102 	destroy_htc_tx_ctrl_packet(pPacket);
103 #endif
104 
105 }
106 
107 HTC_PACKET *htc_alloc_control_tx_packet(HTC_TARGET *target)
108 {
109 #ifdef TODO_FIXME
110 	HTC_PACKET *pPacket;
111 
112 	LOCK_HTC(target);
113 	pPacket = htc_packet_dequeue(&target->ControlBufferTXFreeList);
114 	UNLOCK_HTC(target);
115 
116 	return pPacket;
117 #else
118 	return build_htc_tx_ctrl_packet(target->osdev);
119 #endif
120 }
121 
122 /* Set the target failure handling callback */
123 void htc_set_target_failure_callback(HTC_HANDLE HTCHandle,
124 				     HTC_TARGET_FAILURE Callback)
125 {
126 	HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
127 
128 	target->HTCInitInfo.TargetFailure = Callback;
129 }
130 
131 void htc_dump(HTC_HANDLE HTCHandle, uint8_t CmdId, bool start)
132 {
133 	HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
134 
135 	hif_dump(target->hif_dev, CmdId, start);
136 }
137 
138 void htc_ce_tasklet_debug_dump(HTC_HANDLE htc_handle)
139 {
140 	HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(htc_handle);
141 
142 	if (!target->hif_dev)
143 		return;
144 
145 	hif_display_stats(target->hif_dev);
146 }
147 
148 /* cleanup the HTC instance */
149 static void htc_cleanup(HTC_TARGET *target)
150 {
151 	HTC_PACKET *pPacket;
152 	int i;
153 	HTC_ENDPOINT *endpoint;
154 	HTC_PACKET_QUEUE *pkt_queue;
155 	qdf_nbuf_t netbuf;
156 
157 	while (htc_dec_return_runtime_cnt((void *)target) >= 0) {
158 		hif_pm_runtime_put(target->hif_dev, RTPM_ID_HTC);
159 		hif_pm_runtime_update_stats(target->hif_dev, RTPM_ID_HTC,
160 					    HIF_PM_HTC_STATS_PUT_HTC_CLEANUP);
161 	}
162 
163 	if (target->hif_dev) {
164 		hif_detach_htc(target->hif_dev);
165 		hif_mask_interrupt_call(target->hif_dev);
166 		target->hif_dev = NULL;
167 	}
168 
169 	while (true) {
170 		pPacket = allocate_htc_packet_container(target);
171 		if (!pPacket)
172 			break;
173 		qdf_mem_free(pPacket);
174 	}
175 
176 	LOCK_HTC_TX(target);
177 	pPacket = target->pBundleFreeList;
178 	target->pBundleFreeList = NULL;
179 	UNLOCK_HTC_TX(target);
180 	while (pPacket) {
181 		HTC_PACKET *pPacketTmp = (HTC_PACKET *) pPacket->ListLink.pNext;
182 		netbuf = GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket);
183 		if (netbuf)
184 			qdf_nbuf_free(netbuf);
185 		pkt_queue = pPacket->pContext;
186 		if (pkt_queue)
187 			qdf_mem_free(pkt_queue);
188 		qdf_mem_free(pPacket);
189 		pPacket = pPacketTmp;
190 	}
191 
192 #ifdef TODO_FIXME
193 	while (true) {
194 		pPacket = htc_alloc_control_tx_packet(target);
195 		if (!pPacket)
196 			break;
197 		netbuf = (qdf_nbuf_t) GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket);
198 		if (netbuf)
199 			qdf_nbuf_free(netbuf);
200 		qdf_mem_free(pPacket);
201 	}
202 #endif
203 
204 	htc_flush_endpoint_txlookupQ(target, ENDPOINT_0, true);
205 
206 	qdf_spinlock_destroy(&target->HTCLock);
207 	qdf_spinlock_destroy(&target->HTCRxLock);
208 	qdf_spinlock_destroy(&target->HTCTxLock);
209 	for (i = 0; i < ENDPOINT_MAX; i++) {
210 		endpoint = &target->endpoint[i];
211 		qdf_spinlock_destroy(&endpoint->lookup_queue_lock);
212 	}
213 
214 	/* free our instance */
215 	qdf_mem_free(target);
216 }
217 
218 #ifdef FEATURE_RUNTIME_PM
219 /**
220  * htc_runtime_pm_init(): runtime pm related intialization
221  *
222  * need to initialize a work item.
223  */
224 static void htc_runtime_pm_init(HTC_TARGET *target)
225 {
226 	qdf_create_work(0, &target->queue_kicker, htc_kick_queues, target);
227 }
228 
229 /**
230  * htc_runtime_suspend() - runtime suspend HTC
231  *
232  * @htc_ctx: HTC context pointer
233  *
234  * This is a dummy function for symmetry.
235  *
236  * Return: 0 for success
237  */
238 int htc_runtime_suspend(HTC_HANDLE htc_ctx)
239 {
240 	return 0;
241 }
242 
243 /**
244  * htc_runtime_resume(): resume htc
245  *
246  * The htc message queue needs to be kicked off after
247  * a runtime resume.  Otherwise messages would get stuck.
248  *
249  * @htc_ctx: HTC context pointer
250  *
251  * Return: 0 for success;
252  */
253 int htc_runtime_resume(HTC_HANDLE htc_ctx)
254 {
255 	HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(htc_ctx);
256 
257 	if (!target)
258 		return 0;
259 
260 	qdf_sched_work(0, &target->queue_kicker);
261 	return 0;
262 }
263 
264 /**
265  * htc_runtime_pm_deinit(): runtime pm related de-intialization
266  *
267  * need to de-initialize the work item.
268  *
269  * @target: HTC target pointer
270  *
271  */
272 static void htc_runtime_pm_deinit(HTC_TARGET *target)
273 {
274 	if (!target)
275 		return;
276 
277 	qdf_destroy_work(0, &target->queue_kicker);
278 }
279 
280 int32_t htc_dec_return_runtime_cnt(HTC_HANDLE htc)
281 {
282 	HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(htc);
283 
284 	return qdf_atomic_dec_return(&target->htc_runtime_cnt);
285 }
286 
287 /**
288  * htc_init_runtime_cnt: Initialize htc runtime count
289  * @htc: HTC handle
290  *
291  * Return: None
292  */
293 static inline
294 void htc_init_runtime_cnt(HTC_TARGET *target)
295 {
296 	qdf_atomic_init(&target->htc_runtime_cnt);
297 }
298 #else
299 static inline void htc_runtime_pm_init(HTC_TARGET *target) { }
300 static inline void htc_runtime_pm_deinit(HTC_TARGET *target) { }
301 
302 static inline
303 void htc_init_runtime_cnt(HTC_TARGET *target)
304 {
305 }
306 #endif
307 
308 #if defined(DEBUG_HL_LOGGING) && defined(CONFIG_HL_SUPPORT)
309 static
310 void htc_update_rx_bundle_stats(void *ctx, uint8_t no_of_pkt_in_bundle)
311 {
312 	HTC_TARGET *target = (HTC_TARGET *)ctx;
313 
314 	no_of_pkt_in_bundle--;
315 	if (target && (no_of_pkt_in_bundle < HTC_MAX_MSG_PER_BUNDLE_RX))
316 		target->rx_bundle_stats[no_of_pkt_in_bundle]++;
317 }
318 #else
319 static
320 void htc_update_rx_bundle_stats(void *ctx, uint8_t no_of_pkt_in_bundle)
321 {
322 }
323 #endif
324 
325 #ifdef WLAN_DEBUG_LINK_VOTE
326 static qdf_atomic_t htc_link_vote_ids[HTC_LINK_VOTE_INVALID_MAX_USER_ID];
327 
328 static void htc_init_link_vote_ids(void)
329 {
330 	uint32_t i;
331 
332 	for (i = HTC_LINK_VOTE_INVALID_MIN_USER_ID;
333 	     i < HTC_LINK_VOTE_INVALID_MAX_USER_ID; i++)
334 		qdf_atomic_init(&htc_link_vote_ids[i]);
335 }
336 
337 void htc_log_link_user_votes(void)
338 {
339 	uint32_t i;
340 	uint32_t link_vote;
341 
342 	for (i = HTC_LINK_VOTE_INVALID_MIN_USER_ID + 1;
343 	     i < HTC_LINK_VOTE_INVALID_MAX_USER_ID; i++) {
344 		link_vote = qdf_atomic_read(&htc_link_vote_ids[i]);
345 		if (link_vote)
346 			HTC_NOFL_INFO("Link vote %d user id: %d",
347 				      link_vote, i);
348 	}
349 }
350 
351 void htc_vote_link_down(HTC_HANDLE htc_handle, enum htc_link_vote_user_id id)
352 {
353 	HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(htc_handle);
354 
355 	if (!target->hif_dev)
356 		return;
357 	if (id >= HTC_LINK_VOTE_INVALID_MAX_USER_ID ||
358 	    id <= HTC_LINK_VOTE_INVALID_MIN_USER_ID) {
359 		HTC_ERROR("invalid id: %d", id);
360 		return;
361 	}
362 
363 	hif_vote_link_down(target->hif_dev);
364 	qdf_atomic_dec(&htc_link_vote_ids[id]);
365 }
366 
367 void htc_vote_link_up(HTC_HANDLE htc_handle, enum htc_link_vote_user_id id)
368 {
369 	HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(htc_handle);
370 
371 	if (!target->hif_dev)
372 		return;
373 	if (id >= HTC_LINK_VOTE_INVALID_MAX_USER_ID ||
374 	    id <= HTC_LINK_VOTE_INVALID_MIN_USER_ID) {
375 		HTC_ERROR("invalid link vote user id: %d", id);
376 		return;
377 	}
378 
379 	hif_vote_link_up(target->hif_dev);
380 	qdf_atomic_inc(&htc_link_vote_ids[id]);
381 }
382 #else
383 static inline
384 void htc_init_link_vote_ids(void)
385 {
386 }
387 #endif
388 
389 /* registered target arrival callback from the HIF layer */
390 HTC_HANDLE htc_create(void *ol_sc, struct htc_init_info *pInfo,
391 			qdf_device_t osdev, uint32_t con_mode)
392 {
393 	struct hif_msg_callbacks htcCallbacks;
394 	HTC_ENDPOINT *pEndpoint = NULL;
395 	HTC_TARGET *target = NULL;
396 	int i;
397 
398 	if (!ol_sc) {
399 		HTC_ERROR("%s: ol_sc = NULL", __func__);
400 		return NULL;
401 	}
402 	HTC_TRACE("+htc_create ..  HIF :%pK", ol_sc);
403 
404 	A_REGISTER_MODULE_DEBUG_INFO(htc);
405 
406 	target = (HTC_TARGET *) qdf_mem_malloc(sizeof(HTC_TARGET));
407 	if (!target)
408 		return NULL;
409 
410 	htc_runtime_pm_init(target);
411 	htc_credit_history_init();
412 	qdf_spinlock_create(&target->HTCLock);
413 	qdf_spinlock_create(&target->HTCRxLock);
414 	qdf_spinlock_create(&target->HTCTxLock);
415 	for (i = 0; i < ENDPOINT_MAX; i++) {
416 		pEndpoint = &target->endpoint[i];
417 		qdf_spinlock_create(&pEndpoint->lookup_queue_lock);
418 	}
419 	target->is_nodrop_pkt = false;
420 	target->htc_hdr_length_check = false;
421 	target->wmi_ep_count = 1;
422 
423 	do {
424 		qdf_mem_copy(&target->HTCInitInfo, pInfo,
425 			     sizeof(struct htc_init_info));
426 		target->host_handle = pInfo->pContext;
427 		target->osdev = osdev;
428 		target->con_mode = con_mode;
429 
430 		/* If htc_ready_timeout_ms is not configured from CFG,
431 		 * assign the default timeout value here.
432 		 */
433 
434 		if (!target->HTCInitInfo.htc_ready_timeout_ms)
435 			target->HTCInitInfo.htc_ready_timeout_ms =
436 							HTC_CONTROL_RX_TIMEOUT;
437 
438 		reset_endpoint_states(target);
439 
440 		INIT_HTC_PACKET_QUEUE(&target->ControlBufferTXFreeList);
441 
442 		for (i = 0; i < HTC_PACKET_CONTAINER_ALLOCATION; i++) {
443 			HTC_PACKET *pPacket = (HTC_PACKET *)
444 					qdf_mem_malloc(sizeof(HTC_PACKET));
445 			if (pPacket)
446 				free_htc_packet_container(target, pPacket);
447 		}
448 
449 #ifdef TODO_FIXME
450 		for (i = 0; i < NUM_CONTROL_TX_BUFFERS; i++) {
451 			pPacket = build_htc_tx_ctrl_packet();
452 			if (!pPacket)
453 				break;
454 			htc_free_control_tx_packet(target, pPacket);
455 		}
456 #endif
457 
458 		/* setup HIF layer callbacks */
459 		qdf_mem_zero(&htcCallbacks, sizeof(struct hif_msg_callbacks));
460 		htcCallbacks.Context = target;
461 		htcCallbacks.rxCompletionHandler = htc_rx_completion_handler;
462 		htcCallbacks.txCompletionHandler = htc_tx_completion_handler;
463 		htcCallbacks.txResourceAvailHandler =
464 						 htc_tx_resource_avail_handler;
465 		htcCallbacks.fwEventHandler = htc_fw_event_handler;
466 		htcCallbacks.update_bundle_stats = htc_update_rx_bundle_stats;
467 		target->hif_dev = ol_sc;
468 
469 		/* Get HIF default pipe for HTC message exchange */
470 		pEndpoint = &target->endpoint[ENDPOINT_0];
471 
472 		hif_post_init(target->hif_dev, target, &htcCallbacks);
473 		hif_get_default_pipe(target->hif_dev, &pEndpoint->UL_PipeID,
474 				     &pEndpoint->DL_PipeID);
475 		hif_set_initial_wakeup_cb(target->hif_dev,
476 					  pInfo->target_initial_wakeup_cb,
477 					  pInfo->target_psoc);
478 
479 	} while (false);
480 
481 	htc_recv_init(target);
482 	htc_init_runtime_cnt(target);
483 
484 	HTC_TRACE("-htc_create: (0x%pK)", target);
485 
486 	htc_hang_event_notifier_register(target);
487 
488 	htc_init_link_vote_ids();
489 
490 	return (HTC_HANDLE) target;
491 }
492 
493 void htc_destroy(HTC_HANDLE HTCHandle)
494 {
495 	HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
496 
497 	AR_DEBUG_PRINTF(ATH_DEBUG_TRC,
498 			("+htc_destroy ..  Destroying :0x%pK\n", target));
499 	htc_hang_event_notifier_unregister();
500 	hif_stop(htc_get_hif_device(HTCHandle));
501 	if (target)
502 		htc_cleanup(target);
503 	AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("-htc_destroy\n"));
504 	htc_credit_history_deinit();
505 }
506 
507 /* get the low level HIF device for the caller , the caller may wish to do low
508  * level HIF requests
509  */
510 void *htc_get_hif_device(HTC_HANDLE HTCHandle)
511 {
512 	HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
513 
514 	return target->hif_dev;
515 }
516 
517 static void htc_control_tx_complete(void *Context, HTC_PACKET *pPacket)
518 {
519 	HTC_TARGET *target = (HTC_TARGET *) Context;
520 
521 	AR_DEBUG_PRINTF(ATH_DEBUG_TRC,
522 			("+-htc_control_tx_complete 0x%pK (l:%d)\n", pPacket,
523 			 pPacket->ActualLength));
524 	htc_free_control_tx_packet(target, pPacket);
525 }
526 
527 /* TODO, this is just a temporary max packet size */
528 #define MAX_MESSAGE_SIZE 1536
529 
530 /**
531  * htc_setup_epping_credit_allocation() - allocate credits/HTC buffers to WMI
532  * @scn: pointer to hif_opaque_softc
533  * @pEntry: pointer to tx credit allocation entry
534  * @credits: number of credits
535  *
536  * Return: None
537  */
538 static void
539 htc_setup_epping_credit_allocation(struct hif_opaque_softc *scn,
540 			   struct htc_service_tx_credit_allocation *pEntry,
541 			   int credits)
542 {
543 	switch (hif_get_bus_type(scn)) {
544 	case QDF_BUS_TYPE_PCI:
545 	case QDF_BUS_TYPE_USB:
546 		pEntry++;
547 		pEntry->service_id = WMI_DATA_BE_SVC;
548 		pEntry->CreditAllocation = (credits >> 1);
549 
550 		pEntry++;
551 		pEntry->service_id = WMI_DATA_BK_SVC;
552 		pEntry->CreditAllocation = (credits >> 1);
553 		break;
554 	case QDF_BUS_TYPE_SDIO:
555 		pEntry++;
556 		pEntry->service_id = WMI_DATA_BE_SVC;
557 		pEntry->CreditAllocation = credits;
558 		break;
559 	default:
560 		break;
561 	}
562 }
563 
564 /**
565  * htc_setup_target_buffer_assignments() - setup target buffer assignments
566  * @target: HTC Target Pointer
567  *
568  * Return: A_STATUS
569  */
570 static
571 A_STATUS htc_setup_target_buffer_assignments(HTC_TARGET *target)
572 {
573 	struct htc_service_tx_credit_allocation *pEntry;
574 	A_STATUS status;
575 	int credits;
576 	int creditsPerMaxMsg;
577 
578 	creditsPerMaxMsg = MAX_MESSAGE_SIZE / target->TargetCreditSize;
579 	if (MAX_MESSAGE_SIZE % target->TargetCreditSize)
580 		creditsPerMaxMsg++;
581 
582 	/* TODO, this should be configured by the caller! */
583 
584 	credits = target->TotalTransmitCredits;
585 	pEntry = &target->ServiceTxAllocTable[0];
586 
587 	status = A_OK;
588 	/*
589 	 * Allocate all credists/HTC buffers to WMI.
590 	 * no buffers are used/required for data. data always
591 	 * remains on host.
592 	 */
593 	if (HTC_IS_EPPING_ENABLED(target->con_mode)) {
594 		pEntry++;
595 		pEntry->service_id = WMI_CONTROL_SVC;
596 		pEntry->CreditAllocation = credits;
597 		/* endpoint ping is a testing tool directly on top of HTC in
598 		 * both target and host sides.
599 		 * In target side, the endppint ping fw has no wlan stack and
600 		 * FW mboxping app directly sits on HTC and it simply drops
601 		 * or loops back TX packets. For rx perf, FW mboxping app
602 		 * generates packets and passes packets to HTC to send to host.
603 		 * There is no WMI message exchanges between host and target
604 		 * in endpoint ping case.
605 		 * In host side, the endpoint ping driver is a Ethernet driver
606 		 * and it directly sits on HTC. Only HIF, HTC, QDF, ADF are
607 		 * used by the endpoint ping driver. There is no wifi stack
608 		 * at all in host side also. For tx perf use case,
609 		 * the user space mboxping app sends the raw packets to endpoint
610 		 * ping driver and it directly forwards to HTC for transmission
611 		 * to stress the bus. For the rx perf, HTC passes the received
612 		 * packets to endpoint ping driver and it is passed to the user
613 		 * space through the Ethernet interface.
614 		 * For credit allocation, in SDIO bus case, only BE service is
615 		 * used for tx/rx perf testing so that all credits are given
616 		 * to BE service. In PCIe and USB bus case, endpoint ping uses
617 		 * both BE and BK services to stress the bus so that the total
618 		 * credits are equally distributed to BE and BK services.
619 		 */
620 
621 		htc_setup_epping_credit_allocation(target->hif_dev,
622 						   pEntry, credits);
623 	} else {
624 		int i;
625 		uint32_t max_wmi_svc = (sizeof(svc_id) / sizeof(uint32_t));
626 
627 		if ((target->wmi_ep_count == 0) ||
628 				(target->wmi_ep_count > max_wmi_svc))
629 			return A_ERROR;
630 
631 		/*
632 		 * Divide credit among number of endpoints for WMI
633 		 */
634 		credits = credits / target->wmi_ep_count;
635 		for (i = 0; i < target->wmi_ep_count; i++) {
636 			status = A_OK;
637 			pEntry++;
638 			pEntry->service_id = svc_id[i];
639 			pEntry->CreditAllocation = credits;
640 		}
641 	}
642 
643 	if (A_SUCCESS(status)) {
644 		int i;
645 
646 		for (i = 0; i < HTC_MAX_SERVICE_ALLOC_ENTRIES; i++) {
647 			if (target->ServiceTxAllocTable[i].service_id != 0) {
648 				AR_DEBUG_PRINTF(ATH_DEBUG_INIT,
649 						("SVS Index : %d TX : 0x%2.2X : alloc:%d",
650 						 i,
651 						 target->ServiceTxAllocTable[i].
652 						 service_id,
653 						 target->ServiceTxAllocTable[i].
654 						 CreditAllocation));
655 			}
656 		}
657 	}
658 
659 	return status;
660 }
661 
662 uint8_t htc_get_credit_allocation(HTC_TARGET *target, uint16_t service_id)
663 {
664 	uint8_t allocation = 0;
665 	int i;
666 
667 	for (i = 0; i < HTC_MAX_SERVICE_ALLOC_ENTRIES; i++) {
668 		if (target->ServiceTxAllocTable[i].service_id == service_id) {
669 			allocation =
670 				target->ServiceTxAllocTable[i].CreditAllocation;
671 		}
672 	}
673 
674 	if (0 == allocation) {
675 		AR_DEBUG_PRINTF(ATH_DEBUG_RSVD1,
676 			("HTC Service TX : 0x%2.2X : allocation is zero!\n",
677 				 service_id));
678 	}
679 
680 	return allocation;
681 }
682 
683 QDF_STATUS htc_wait_target(HTC_HANDLE HTCHandle)
684 {
685 	QDF_STATUS status = QDF_STATUS_SUCCESS;
686 	HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
687 	HTC_READY_EX_MSG *pReadyMsg;
688 	struct htc_service_connect_req connect;
689 	struct htc_service_connect_resp resp;
690 	HTC_READY_MSG *rdy_msg;
691 	uint16_t htc_rdy_msg_id;
692 	uint8_t i = 0;
693 	HTC_PACKET *rx_bundle_packet, *temp_bundle_packet;
694 
695 	AR_DEBUG_PRINTF(ATH_DEBUG_TRC,
696 			("htc_wait_target - Enter (target:0x%pK)\n", HTCHandle));
697 	AR_DEBUG_PRINTF(ATH_DEBUG_RSVD1, ("+HWT\n"));
698 
699 	do {
700 
701 		status = hif_start(target->hif_dev);
702 		if (QDF_IS_STATUS_ERROR(status)) {
703 			AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
704 					("hif_start failed\n"));
705 			break;
706 		}
707 
708 		status = htc_wait_recv_ctrl_message(target);
709 
710 		if (QDF_IS_STATUS_ERROR(status))
711 			break;
712 
713 		if (target->CtrlResponseLength < (sizeof(HTC_READY_EX_MSG))) {
714 			AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
715 					("Invalid HTC Ready Msg Len:%d!\n",
716 					 target->CtrlResponseLength));
717 			status = QDF_STATUS_E_BADMSG;
718 			break;
719 		}
720 
721 		pReadyMsg = (HTC_READY_EX_MSG *) target->CtrlResponseBuffer;
722 
723 		rdy_msg = &pReadyMsg->Version2_0_Info;
724 		htc_rdy_msg_id =
725 			HTC_GET_FIELD(rdy_msg, HTC_READY_MSG, MESSAGEID);
726 		if (htc_rdy_msg_id != HTC_MSG_READY_ID) {
727 			AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
728 					("Invalid HTC Ready Msg : 0x%X!\n",
729 					 htc_rdy_msg_id));
730 			status = QDF_STATUS_E_BADMSG;
731 			break;
732 		}
733 
734 		target->TotalTransmitCredits = HTC_GET_FIELD(rdy_msg,
735 						HTC_READY_MSG, CREDITCOUNT);
736 		if (target->HTCInitInfo.cfg_wmi_credit_cnt &&
737 			(target->HTCInitInfo.cfg_wmi_credit_cnt <
738 						target->TotalTransmitCredits))
739 			/*
740 			 * If INI configured value is less than FW advertised,
741 			 * then use INI configured value, otherwise use FW
742 			 * advertised.
743 			 */
744 			target->TotalTransmitCredits =
745 				target->HTCInitInfo.cfg_wmi_credit_cnt;
746 
747 		target->TargetCreditSize =
748 			(int)HTC_GET_FIELD(rdy_msg, HTC_READY_MSG, CREDITSIZE);
749 		target->MaxMsgsPerHTCBundle =
750 			(uint8_t) pReadyMsg->MaxMsgsPerHTCBundle;
751 		UPDATE_ALT_CREDIT(target, pReadyMsg->AltDataCreditSize);
752 		/* for old fw this value is set to 0. But the minimum value
753 		 * should be 1, i.e., no bundling
754 		 */
755 		if (target->MaxMsgsPerHTCBundle < 1)
756 			target->MaxMsgsPerHTCBundle = 1;
757 
758 		AR_DEBUG_PRINTF(ATH_DEBUG_INIT,
759 				("Target Ready! TX resource : %d size:%d, MaxMsgsPerHTCBundle = %d",
760 				 target->TotalTransmitCredits,
761 				 target->TargetCreditSize,
762 				 target->MaxMsgsPerHTCBundle));
763 
764 		if ((0 == target->TotalTransmitCredits)
765 		    || (0 == target->TargetCreditSize)) {
766 			status = QDF_STATUS_E_ABORTED;
767 			break;
768 		}
769 
770 		/* Allocate expected number of RX bundle buffer allocation */
771 		if (HTC_RX_BUNDLE_ENABLED(target)) {
772 			temp_bundle_packet = NULL;
773 			for (i = 0; i < MAX_HTC_RX_BUNDLE; i++) {
774 				rx_bundle_packet =
775 					allocate_htc_bundle_packet(target);
776 				if (rx_bundle_packet)
777 					rx_bundle_packet->ListLink.pNext =
778 						(DL_LIST *)temp_bundle_packet;
779 				else
780 					break;
781 
782 				temp_bundle_packet = rx_bundle_packet;
783 			}
784 			LOCK_HTC_TX(target);
785 			target->pBundleFreeList = temp_bundle_packet;
786 			UNLOCK_HTC_TX(target);
787 		}
788 
789 		/* done processing */
790 		target->CtrlResponseProcessing = false;
791 
792 		htc_setup_target_buffer_assignments(target);
793 
794 		/* setup our pseudo HTC control endpoint connection */
795 		qdf_mem_zero(&connect, sizeof(connect));
796 		qdf_mem_zero(&resp, sizeof(resp));
797 		connect.EpCallbacks.pContext = target;
798 		connect.EpCallbacks.EpTxComplete = htc_control_tx_complete;
799 		connect.EpCallbacks.EpRecv = htc_control_rx_complete;
800 		connect.MaxSendQueueDepth = NUM_CONTROL_TX_BUFFERS;
801 		connect.service_id = HTC_CTRL_RSVD_SVC;
802 
803 		/* connect fake service */
804 		status = htc_connect_service((HTC_HANDLE) target,
805 					     &connect, &resp);
806 
807 	} while (false);
808 
809 	AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("htc_wait_target - Exit (%d)\n",
810 			status));
811 	AR_DEBUG_PRINTF(ATH_DEBUG_RSVD1, ("-HWT\n"));
812 	return status;
813 }
814 
815 /* start HTC, this is called after all services are connected */
816 static A_STATUS htc_config_target_hif_pipe(HTC_TARGET *target)
817 {
818 
819 	return A_OK;
820 }
821 
822 static void reset_endpoint_states(HTC_TARGET *target)
823 {
824 	HTC_ENDPOINT *pEndpoint;
825 	int i;
826 
827 	for (i = ENDPOINT_0; i < ENDPOINT_MAX; i++) {
828 		pEndpoint = &target->endpoint[i];
829 		pEndpoint->service_id = 0;
830 		pEndpoint->MaxMsgLength = 0;
831 		pEndpoint->MaxTxQueueDepth = 0;
832 		pEndpoint->Id = i;
833 		INIT_HTC_PACKET_QUEUE(&pEndpoint->TxQueue);
834 		INIT_HTC_PACKET_QUEUE(&pEndpoint->TxLookupQueue);
835 		INIT_HTC_PACKET_QUEUE(&pEndpoint->RxBufferHoldQueue);
836 		pEndpoint->target = target;
837 		pEndpoint->TxCreditFlowEnabled = (bool)htc_credit_flow;
838 		pEndpoint->num_requeues_warn = 0;
839 		pEndpoint->total_num_requeues = 0;
840 		qdf_atomic_init(&pEndpoint->TxProcessCount);
841 	}
842 }
843 
844 /**
845  * htc_start() - Main HTC function to trigger HTC start
846  * @HTCHandle: pointer to HTC handle
847  *
848  * Return: QDF_STATUS_SUCCESS for success or an appropriate QDF_STATUS error
849  */
850 QDF_STATUS htc_start(HTC_HANDLE HTCHandle)
851 {
852 	qdf_nbuf_t netbuf;
853 	QDF_STATUS status = QDF_STATUS_SUCCESS;
854 	HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
855 	HTC_SETUP_COMPLETE_EX_MSG *pSetupComp;
856 	HTC_PACKET *pSendPacket;
857 
858 	AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("htc_start Enter\n"));
859 
860 	do {
861 
862 		htc_config_target_hif_pipe(target);
863 
864 		/* allocate a buffer to send */
865 		pSendPacket = htc_alloc_control_tx_packet(target);
866 		if (!pSendPacket) {
867 			AR_DEBUG_ASSERT(false);
868 			qdf_print("%s: allocControlTxPacket failed",
869 				  __func__);
870 			status = QDF_STATUS_E_NOMEM;
871 			break;
872 		}
873 
874 		netbuf =
875 		   (qdf_nbuf_t) GET_HTC_PACKET_NET_BUF_CONTEXT(pSendPacket);
876 		/* assemble setup complete message */
877 		qdf_nbuf_put_tail(netbuf, sizeof(HTC_SETUP_COMPLETE_EX_MSG));
878 		pSetupComp =
879 			(HTC_SETUP_COMPLETE_EX_MSG *) qdf_nbuf_data(netbuf);
880 		qdf_mem_zero(pSetupComp, sizeof(HTC_SETUP_COMPLETE_EX_MSG));
881 
882 		HTC_SET_FIELD(pSetupComp, HTC_SETUP_COMPLETE_EX_MSG,
883 			      MESSAGEID, HTC_MSG_SETUP_COMPLETE_EX_ID);
884 
885 		if (!htc_credit_flow) {
886 			AR_DEBUG_PRINTF(ATH_DEBUG_TRC,
887 					("HTC will not use TX credit flow control"));
888 			pSetupComp->SetupFlags |=
889 				HTC_SETUP_COMPLETE_FLAGS_DISABLE_TX_CREDIT_FLOW;
890 		} else {
891 			AR_DEBUG_PRINTF(ATH_DEBUG_TRC,
892 					("HTC using TX credit flow control"));
893 		}
894 
895 		if ((hif_get_bus_type(target->hif_dev) == QDF_BUS_TYPE_SDIO) ||
896 					(hif_get_bus_type(target->hif_dev) ==
897 							 QDF_BUS_TYPE_USB)) {
898 			if (HTC_RX_BUNDLE_ENABLED(target))
899 			pSetupComp->SetupFlags |=
900 				HTC_SETUP_COMPLETE_FLAGS_ENABLE_BUNDLE_RECV;
901 			hif_set_bundle_mode(target->hif_dev, true,
902 				HTC_MAX_MSG_PER_BUNDLE_RX);
903 			pSetupComp->MaxMsgsPerBundledRecv = HTC_MAX_MSG_PER_BUNDLE_RX;
904 		}
905 
906 		SET_HTC_PACKET_INFO_TX(pSendPacket,
907 				       NULL,
908 				       (uint8_t *) pSetupComp,
909 				       sizeof(HTC_SETUP_COMPLETE_EX_MSG),
910 				       ENDPOINT_0, HTC_SERVICE_TX_PACKET_TAG);
911 
912 		status = htc_send_pkt((HTC_HANDLE) target, pSendPacket);
913 		if (QDF_IS_STATUS_ERROR(status))
914 			break;
915 	} while (false);
916 
917 	AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("htc_start Exit\n"));
918 	return status;
919 }
920 
921 /*flush all queued buffers for surpriseremove case*/
922 void htc_flush_surprise_remove(HTC_HANDLE HTCHandle)
923 {
924 	HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
925 	int i;
926 	HTC_ENDPOINT *pEndpoint;
927 #ifdef RX_SG_SUPPORT
928 	qdf_nbuf_t netbuf;
929 	qdf_nbuf_queue_t *rx_sg_queue = &target->RxSgQueue;
930 #endif
931 
932 	AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("+htc_flush_surprise_remove\n"));
933 
934 	/* cleanup endpoints */
935 	for (i = 0; i < ENDPOINT_MAX; i++) {
936 		pEndpoint = &target->endpoint[i];
937 		htc_flush_rx_hold_queue(target, pEndpoint);
938 		htc_flush_endpoint_tx(target, pEndpoint, HTC_TX_PACKET_TAG_ALL);
939 	}
940 
941 	hif_flush_surprise_remove(target->hif_dev);
942 
943 #ifdef RX_SG_SUPPORT
944 	LOCK_HTC_RX(target);
945 	while ((netbuf = qdf_nbuf_queue_remove(rx_sg_queue)) != NULL)
946 		qdf_nbuf_free(netbuf);
947 	RESET_RX_SG_CONFIG(target);
948 	UNLOCK_HTC_RX(target);
949 #endif
950 
951 	reset_endpoint_states(target);
952 
953 	AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("-htc_flush_surprise_remove\n"));
954 }
955 
956 /* stop HTC communications, i.e. stop interrupt reception, and flush all queued
957  * buffers
958  */
959 void htc_stop(HTC_HANDLE HTCHandle)
960 {
961 	HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
962 	int i;
963 	HTC_ENDPOINT *endpoint;
964 #ifdef RX_SG_SUPPORT
965 	qdf_nbuf_t netbuf;
966 	qdf_nbuf_queue_t *rx_sg_queue = &target->RxSgQueue;
967 #endif
968 
969 	AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("+htc_stop\n"));
970 
971 	htc_runtime_pm_deinit(target);
972 
973 	HTC_INFO("%s: endpoints cleanup\n", __func__);
974 	/* cleanup endpoints */
975 	for (i = 0; i < ENDPOINT_MAX; i++) {
976 		endpoint = &target->endpoint[i];
977 		htc_flush_rx_hold_queue(target, endpoint);
978 		htc_flush_endpoint_tx(target, endpoint, HTC_TX_PACKET_TAG_ALL);
979 		if (endpoint->ul_is_polled) {
980 			qdf_timer_stop(&endpoint->ul_poll_timer);
981 			qdf_timer_free(&endpoint->ul_poll_timer);
982 		}
983 	}
984 
985 	/* Note: htc_flush_endpoint_tx for all endpoints should be called before
986 	 * hif_stop - otherwise htc_tx_completion_handler called from
987 	 * hif_send_buffer_cleanup_on_pipe for residual tx frames in HIF layer,
988 	 * might queue the packet again to HIF Layer - which could cause tx
989 	 * buffer leak
990 	 */
991 
992 	HTC_INFO("%s: stopping hif layer\n", __func__);
993 	hif_stop(target->hif_dev);
994 
995 #ifdef RX_SG_SUPPORT
996 	LOCK_HTC_RX(target);
997 	while ((netbuf = qdf_nbuf_queue_remove(rx_sg_queue)) != NULL)
998 		qdf_nbuf_free(netbuf);
999 	RESET_RX_SG_CONFIG(target);
1000 	UNLOCK_HTC_RX(target);
1001 #endif
1002 
1003 	/**
1004 	 * In SSR case, HTC tx completion callback for wmi will be blocked
1005 	 * by TARGET_STATUS_RESET and HTC packets will be left unfreed on
1006 	 * lookup queue.
1007 	 *
1008 	 * In case of target failing to send wmi_ready_event, the htc connect
1009 	 * msg buffer will be left unmapped and not freed. So calling the
1010 	 * completion handler for this buffer will handle this scenario.
1011 	 */
1012 	HTC_INFO("%s: flush endpoints Tx lookup queue\n", __func__);
1013 	for (i = 0; i < ENDPOINT_MAX; i++) {
1014 		endpoint = &target->endpoint[i];
1015 		if (endpoint->service_id == WMI_CONTROL_SVC)
1016 			htc_flush_endpoint_txlookupQ(target, i, false);
1017 		else if (endpoint->service_id == HTC_CTRL_RSVD_SVC)
1018 			htc_flush_endpoint_txlookupQ(target, i, true);
1019 	}
1020 	HTC_INFO("%s: resetting endpoints state\n", __func__);
1021 
1022 	reset_endpoint_states(target);
1023 
1024 	AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("-htc_stop\n"));
1025 }
1026 
1027 void htc_dump_credit_states(HTC_HANDLE HTCHandle)
1028 {
1029 	HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
1030 	HTC_ENDPOINT *pEndpoint;
1031 	int i;
1032 
1033 	for (i = 0; i < ENDPOINT_MAX; i++) {
1034 		pEndpoint = &target->endpoint[i];
1035 		if (0 == pEndpoint->service_id)
1036 			continue;
1037 
1038 		AR_DEBUG_PRINTF(ATH_DEBUG_ANY,
1039 			("--- EP : %d  service_id: 0x%X    --------------\n",
1040 				 pEndpoint->Id, pEndpoint->service_id));
1041 		AR_DEBUG_PRINTF(ATH_DEBUG_ANY,
1042 				(" TxCredits          : %d\n",
1043 				 pEndpoint->TxCredits));
1044 		AR_DEBUG_PRINTF(ATH_DEBUG_ANY,
1045 				(" TxCreditSize       : %d\n",
1046 				 pEndpoint->TxCreditSize));
1047 		AR_DEBUG_PRINTF(ATH_DEBUG_ANY,
1048 				(" TxCreditsPerMaxMsg : %d\n",
1049 				 pEndpoint->TxCreditsPerMaxMsg));
1050 		AR_DEBUG_PRINTF(ATH_DEBUG_ANY,
1051 				(" TxQueueDepth       : %d\n",
1052 				 HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue)));
1053 		AR_DEBUG_PRINTF(ATH_DEBUG_ANY,
1054 				("----------------------------------------\n"));
1055 	}
1056 }
1057 
1058 bool htc_get_endpoint_statistics(HTC_HANDLE HTCHandle,
1059 				   HTC_ENDPOINT_ID Endpoint,
1060 				   enum htc_endpoint_stat_action Action,
1061 				   struct htc_endpoint_stats *pStats)
1062 {
1063 #ifdef HTC_EP_STAT_PROFILING
1064 	HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
1065 	bool clearStats = false;
1066 	bool sample = false;
1067 
1068 	switch (Action) {
1069 	case HTC_EP_STAT_SAMPLE:
1070 		sample = true;
1071 		break;
1072 	case HTC_EP_STAT_SAMPLE_AND_CLEAR:
1073 		sample = true;
1074 		clearStats = true;
1075 		break;
1076 	case HTC_EP_STAT_CLEAR:
1077 		clearStats = true;
1078 		break;
1079 	default:
1080 		break;
1081 	}
1082 
1083 	A_ASSERT(Endpoint < ENDPOINT_MAX);
1084 
1085 	/* lock out TX and RX while we sample and/or clear */
1086 	LOCK_HTC_TX(target);
1087 	LOCK_HTC_RX(target);
1088 
1089 	if (sample) {
1090 		A_ASSERT(pStats);
1091 		/* return the stats to the caller */
1092 		qdf_mem_copy(pStats, &target->endpoint[Endpoint].endpoint_stats,
1093 			 sizeof(struct htc_endpoint_stats));
1094 	}
1095 
1096 	if (clearStats) {
1097 		/* reset stats */
1098 		qdf_mem_zero(&target->endpoint[Endpoint].endpoint_stats,
1099 			  sizeof(struct htc_endpoint_stats));
1100 	}
1101 
1102 	UNLOCK_HTC_RX(target);
1103 	UNLOCK_HTC_TX(target);
1104 
1105 	return true;
1106 #else
1107 	return false;
1108 #endif
1109 }
1110 
1111 void *htc_get_targetdef(HTC_HANDLE htc_handle)
1112 {
1113 	HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(htc_handle);
1114 
1115 	return hif_get_targetdef(target->hif_dev);
1116 }
1117 
1118 #ifdef IPA_OFFLOAD
1119 /**
1120  * htc_ipa_get_ce_resource() - get uc resource on lower layer
1121  * @htc_handle: htc context
1122  * @ce_sr_base_paddr: copyengine source ring base physical address
1123  * @ce_sr_ring_size: copyengine source ring size
1124  * @ce_reg_paddr: copyengine register physical address
1125  *
1126  * Return: None
1127  */
1128 void htc_ipa_get_ce_resource(HTC_HANDLE htc_handle,
1129 			     qdf_shared_mem_t **ce_sr,
1130 			     uint32_t *ce_sr_ring_size,
1131 			     qdf_dma_addr_t *ce_reg_paddr)
1132 {
1133 	HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(htc_handle);
1134 
1135 	if (target->hif_dev)
1136 		hif_ipa_get_ce_resource(target->hif_dev,
1137 					ce_sr, ce_sr_ring_size, ce_reg_paddr);
1138 }
1139 #endif /* IPA_OFFLOAD */
1140 
1141 #if defined(DEBUG_HL_LOGGING) && defined(CONFIG_HL_SUPPORT)
1142 
1143 void htc_dump_bundle_stats(HTC_HANDLE HTCHandle)
1144 {
1145 	HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
1146 	int total, i;
1147 
1148 	total = 0;
1149 	for (i = 0; i < HTC_MAX_MSG_PER_BUNDLE_RX; i++)
1150 		total += target->rx_bundle_stats[i];
1151 
1152 	if (total) {
1153 		AR_DEBUG_PRINTF(ATH_DEBUG_ANY, ("RX Bundle stats:\n"));
1154 		AR_DEBUG_PRINTF(ATH_DEBUG_ANY, ("Total RX packets: %d\n",
1155 						total));
1156 		AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (
1157 				"Number of bundle: Number of packets\n"));
1158 		for (i = 0; i < HTC_MAX_MSG_PER_BUNDLE_RX; i++)
1159 			AR_DEBUG_PRINTF(ATH_DEBUG_ANY,
1160 					("%10d:%10d(%2d%s)\n", (i+1),
1161 					 target->rx_bundle_stats[i],
1162 					 ((target->rx_bundle_stats[i]*100)/
1163 					  total), "%"));
1164 	}
1165 
1166 
1167 	total = 0;
1168 	for (i = 0; i < HTC_MAX_MSG_PER_BUNDLE_TX; i++)
1169 		total += target->tx_bundle_stats[i];
1170 
1171 	if (total) {
1172 		AR_DEBUG_PRINTF(ATH_DEBUG_ANY, ("TX Bundle stats:\n"));
1173 		AR_DEBUG_PRINTF(ATH_DEBUG_ANY, ("Total TX packets: %d\n",
1174 						total));
1175 		AR_DEBUG_PRINTF(ATH_DEBUG_ANY,
1176 				("Number of bundle: Number of packets\n"));
1177 		for (i = 0; i < HTC_MAX_MSG_PER_BUNDLE_TX; i++)
1178 			AR_DEBUG_PRINTF(ATH_DEBUG_ANY,
1179 					("%10d:%10d(%2d%s)\n", (i+1),
1180 					 target->tx_bundle_stats[i],
1181 					 ((target->tx_bundle_stats[i]*100)/
1182 					  total), "%"));
1183 	}
1184 }
1185 
1186 void htc_clear_bundle_stats(HTC_HANDLE HTCHandle)
1187 {
1188 	HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
1189 
1190 	qdf_mem_zero(&target->rx_bundle_stats, sizeof(target->rx_bundle_stats));
1191 	qdf_mem_zero(&target->tx_bundle_stats, sizeof(target->tx_bundle_stats));
1192 }
1193 #endif
1194 
1195 /**
1196  * htc_can_suspend_link - API to query HIF for link status
1197  * @htc_handle: HTC Handle
1198  *
1199  * API for upper layers to call HIF to query if the link can suspend
1200  *
1201  * Return: void
1202  */
1203 bool htc_can_suspend_link(HTC_HANDLE htc_handle)
1204 {
1205 	HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(htc_handle);
1206 
1207 	if (!target->hif_dev)
1208 		return false;
1209 
1210 	return hif_can_suspend_link(target->hif_dev);
1211 }
1212 
1213 #ifdef FEATURE_RUNTIME_PM
1214 int htc_pm_runtime_get(HTC_HANDLE htc_handle)
1215 {
1216 	HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(htc_handle);
1217 
1218 	return hif_pm_runtime_get(target->hif_dev,
1219 				  RTPM_ID_HTC, false);
1220 }
1221 
1222 int htc_pm_runtime_put(HTC_HANDLE htc_handle)
1223 {
1224 	HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(htc_handle);
1225 
1226 	hif_pm_runtime_update_stats(target->hif_dev, RTPM_ID_HTC,
1227 				    HIF_PM_HTC_STATS_PUT_HTT_RESPONSE);
1228 	return hif_pm_runtime_put(target->hif_dev, RTPM_ID_HTC);
1229 }
1230 #endif
1231 
1232 /**
1233  * htc_set_wmi_endpoint_count: Set number of WMI endpoint
1234  * @htc_handle: HTC handle
1235  * @wmi_ep_count: WMI enpoint count
1236  *
1237  * return: None
1238  */
1239 void htc_set_wmi_endpoint_count(HTC_HANDLE htc_handle, uint8_t wmi_ep_count)
1240 {
1241 	HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(htc_handle);
1242 
1243 	target->wmi_ep_count = wmi_ep_count;
1244 }
1245 
1246 /**
1247  * htc_get_wmi_endpoint_count: Get number of WMI endpoint
1248  * @htc_handle: HTC handle
1249  *
1250  * return: WMI enpoint count
1251  */
1252 uint8_t htc_get_wmi_endpoint_count(HTC_HANDLE htc_handle)
1253 {
1254 	HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(htc_handle);
1255 
1256 	return target->wmi_ep_count;
1257 }
1258