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