1 /*
2  * Copyright (c) 2013-2021 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2022-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 "htc_debug.h"
21 #include "htc_internal.h"
22 #include "htc_credit_history.h"
23 #include <qdf_mem.h>            /* qdf_mem_malloc */
24 #include <qdf_nbuf.h>           /* qdf_nbuf_t */
25 #include "qdf_module.h"
26 
27 /* #define USB_HIF_SINGLE_PIPE_DATA_SCHED */
28 /* #ifdef USB_HIF_SINGLE_PIPE_DATA_SCHED */
29 #define DATA_EP_SIZE 4
30 /* #endif */
31 #define HTC_DATA_RESOURCE_THRS 256
32 #define HTC_DATA_MINDESC_PERPACKET 2
33 
34 /* maximum number of requeue attempts before print */
35 #define MAX_REQUEUE_WARN 5
36 
37 enum HTC_SEND_QUEUE_RESULT {
38 	HTC_SEND_QUEUE_OK = 0,  /* packet was queued */
39 	HTC_SEND_QUEUE_DROP = 1, /* this packet should be dropped */
40 };
41 
42 #ifndef DEBUG_CREDIT
43 #define DEBUG_CREDIT 0
44 #endif
45 
46 #if DEBUG_CREDIT
47 /* bit mask to enable debug certain endpoint */
48 static unsigned int ep_debug_mask =
49 	(1 << ENDPOINT_0) | (1 << ENDPOINT_1) | (1 << ENDPOINT_2);
50 #endif
51 
52 #ifdef QCA_WIFI_EMULATION
53 #define HTC_EMULATION_DELAY_IN_MS 20
54 /**
55  * htc_add_emulation_delay() - Adds a delay in before proceeding, only for
56  *                             emulation
57  *
58  * Return: None
59  */
htc_add_emulation_delay(void)60 static inline void htc_add_emulation_delay(void)
61 {
62 	qdf_mdelay(HTC_EMULATION_DELAY_IN_MS);
63 }
64 #else
htc_add_emulation_delay(void)65 static inline void htc_add_emulation_delay(void)
66 {
67 }
68 #endif
69 
htc_dump_counter_info(HTC_HANDLE HTCHandle)70 void htc_dump_counter_info(HTC_HANDLE HTCHandle)
71 {
72 	HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
73 
74 	if (!target)
75 		return;
76 
77 	AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
78 			("\n%s: ce_send_cnt = %d, TX_comp_cnt = %d\n",
79 			 __func__, target->ce_send_cnt, target->TX_comp_cnt));
80 }
81 
htc_get_tx_queue_depth(HTC_HANDLE htc_handle,HTC_ENDPOINT_ID endpoint_id)82 int htc_get_tx_queue_depth(HTC_HANDLE htc_handle, HTC_ENDPOINT_ID endpoint_id)
83 {
84 	HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(htc_handle);
85 	HTC_ENDPOINT *endpoint = &target->endpoint[endpoint_id];
86 
87 	return HTC_PACKET_QUEUE_DEPTH(&endpoint->TxQueue);
88 }
89 qdf_export_symbol(htc_get_tx_queue_depth);
90 
htc_get_control_endpoint_tx_host_credits(HTC_HANDLE HTCHandle,int * credits)91 void htc_get_control_endpoint_tx_host_credits(HTC_HANDLE HTCHandle,
92 					      int *credits)
93 {
94 	HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
95 	HTC_ENDPOINT *pEndpoint;
96 	int i;
97 
98 	if (!credits || !target) {
99 		AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("%s: invalid args", __func__));
100 		return;
101 	}
102 
103 	*credits = 0;
104 	LOCK_HTC_TX(target);
105 	for (i = 0; i < ENDPOINT_MAX; i++) {
106 		pEndpoint = &target->endpoint[i];
107 		if (pEndpoint->service_id == WMI_CONTROL_SVC) {
108 			*credits = pEndpoint->TxCredits;
109 			break;
110 		}
111 	}
112 	UNLOCK_HTC_TX(target);
113 }
114 
restore_tx_packet(HTC_TARGET * target,HTC_PACKET * pPacket)115 static inline void restore_tx_packet(HTC_TARGET *target, HTC_PACKET *pPacket)
116 {
117 	qdf_nbuf_t netbuf = GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket);
118 
119 	if (pPacket->PktInfo.AsTx.Flags & HTC_TX_PACKET_FLAG_FIXUP_NETBUF) {
120 		qdf_nbuf_unmap(target->osdev, netbuf, QDF_DMA_TO_DEVICE);
121 		pPacket->PktInfo.AsTx.Flags &= ~HTC_TX_PACKET_FLAG_FIXUP_NETBUF;
122 	}
123 	if (pPacket->PktInfo.AsTx.Flags &
124 		HTC_TX_PACKET_FLAG_HTC_HEADER_IN_NETBUF_DATA) {
125 		qdf_nbuf_pull_head(netbuf, sizeof(HTC_FRAME_HDR));
126 		pPacket->PktInfo.AsTx.Flags &=
127 			~HTC_TX_PACKET_FLAG_HTC_HEADER_IN_NETBUF_DATA;
128 	}
129 }
130 
send_packet_completion(HTC_TARGET * target,HTC_PACKET * pPacket)131 static void send_packet_completion(HTC_TARGET *target, HTC_PACKET *pPacket)
132 {
133 	HTC_ENDPOINT *pEndpoint = &target->endpoint[pPacket->Endpoint];
134 	HTC_EP_SEND_PKT_COMPLETE EpTxComplete;
135 
136 	if ((pPacket->PktInfo.AsTx.Flags & HTC_TX_PACKET_FLAG_FIXUP_NETBUF) &&
137 	    (!IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)))
138 		target->nbuf_nfc_unmap_count++;
139 
140 	restore_tx_packet(target, pPacket);
141 
142 	/*
143 	 * In case of SSR, we cannot call the upper layer completion
144 	 * callbacks, hence just free the nbuf and HTC packet here.
145 	 */
146 	if (target->hif_dev && hif_get_target_status(target->hif_dev)) {
147 		htc_free_control_tx_packet(target, pPacket);
148 		return;
149 	}
150 
151 	/* do completion */
152 	AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
153 			("HTC calling ep %d send complete callback on packet %pK\n",
154 			 pEndpoint->Id, pPacket));
155 
156 	EpTxComplete = pEndpoint->EpCallBacks.EpTxComplete;
157 	if (EpTxComplete)
158 		EpTxComplete(pEndpoint->EpCallBacks.pContext, pPacket);
159 	else
160 		qdf_nbuf_free(pPacket->pPktContext);
161 
162 
163 }
164 
165 #ifdef FEATURE_RUNTIME_PM
166 /**
167  * log_packet_info() - Log HTC packet information
168  *
169  * @target: handle of HTC context
170  * @pPacket: handle of HTC packet
171  *
172  * Return: None
173  */
log_packet_info(HTC_TARGET * target,HTC_PACKET * pPacket)174 static void log_packet_info(HTC_TARGET *target, HTC_PACKET *pPacket)
175 {
176 	HTC_ENDPOINT *pEndpoint = &target->endpoint[pPacket->Endpoint];
177 	HTC_EP_LOG_PKT ep_log_pkt;
178 	qdf_nbuf_t netbuf = GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket);
179 
180 	ep_log_pkt = pEndpoint->EpCallBacks.ep_log_pkt;
181 	if (ep_log_pkt) {
182 		qdf_nbuf_pull_head(netbuf, sizeof(HTC_FRAME_HDR));
183 		ep_log_pkt(pEndpoint->EpCallBacks.pContext, pPacket);
184 		qdf_nbuf_push_head(netbuf, sizeof(HTC_FRAME_HDR));
185 	}
186 }
187 
188 /**
189  * htc_inc_htt_runtime_cnt() - Increment htc htt runtime count
190  * @target: handle of HTC context
191  *
192  * Return: None
193  */
194 static inline
htc_inc_htt_runtime_cnt(HTC_TARGET * target)195 void htc_inc_htt_runtime_cnt(HTC_TARGET *target)
196 {
197 	qdf_atomic_inc(&target->htc_htt_runtime_cnt);
198 }
199 #else
log_packet_info(HTC_TARGET * target,HTC_PACKET * pPacket)200 static void log_packet_info(HTC_TARGET *target, HTC_PACKET *pPacket)
201 {
202 }
203 
204 static inline
htc_inc_htt_runtime_cnt(HTC_TARGET * target)205 void htc_inc_htt_runtime_cnt(HTC_TARGET *target)
206 {
207 }
208 #endif
209 
htc_send_complete_check_cleanup(void * context)210 void htc_send_complete_check_cleanup(void *context)
211 {
212 	HTC_ENDPOINT *pEndpoint = (HTC_ENDPOINT *) context;
213 
214 	htc_send_complete_check(pEndpoint, 1);
215 }
216 
allocate_htc_bundle_packet(HTC_TARGET * target)217 HTC_PACKET *allocate_htc_bundle_packet(HTC_TARGET *target)
218 {
219 	HTC_PACKET *pPacket;
220 	HTC_PACKET_QUEUE *pQueueSave;
221 	qdf_nbuf_t netbuf;
222 
223 	LOCK_HTC_TX(target);
224 	if (!target->pBundleFreeList) {
225 		UNLOCK_HTC_TX(target);
226 		netbuf = qdf_nbuf_alloc(NULL,
227 					target->MaxMsgsPerHTCBundle *
228 					target->TargetCreditSize, 0, 4, false);
229 		AR_DEBUG_ASSERT(netbuf);
230 		if (!netbuf)
231 			return NULL;
232 		pPacket = qdf_mem_malloc(sizeof(HTC_PACKET));
233 		AR_DEBUG_ASSERT(pPacket);
234 		if (!pPacket) {
235 			qdf_nbuf_free(netbuf);
236 			return NULL;
237 		}
238 		pQueueSave = qdf_mem_malloc(sizeof(HTC_PACKET_QUEUE));
239 		AR_DEBUG_ASSERT(pQueueSave);
240 		if (!pQueueSave) {
241 			qdf_nbuf_free(netbuf);
242 			qdf_mem_free(pPacket);
243 			return NULL;
244 		}
245 		INIT_HTC_PACKET_QUEUE(pQueueSave);
246 		pPacket->pContext = pQueueSave;
247 		SET_HTC_PACKET_NET_BUF_CONTEXT(pPacket, netbuf);
248 		pPacket->pBuffer = qdf_nbuf_data(netbuf);
249 		pPacket->BufferLength = qdf_nbuf_len(netbuf);
250 
251 		/* store the original head room so that we can restore this
252 		 * when we "free" the packet.
253 		 * free packet puts the packet back on the free list
254 		 */
255 		pPacket->netbufOrigHeadRoom = qdf_nbuf_headroom(netbuf);
256 		return pPacket;
257 	}
258 	/* already done malloc - restore from free list */
259 	pPacket = target->pBundleFreeList;
260 	AR_DEBUG_ASSERT(pPacket);
261 	if (!pPacket) {
262 		UNLOCK_HTC_TX(target);
263 		return NULL;
264 	}
265 	target->pBundleFreeList = (HTC_PACKET *) pPacket->ListLink.pNext;
266 	UNLOCK_HTC_TX(target);
267 	pPacket->ListLink.pNext = NULL;
268 
269 	return pPacket;
270 }
271 
free_htc_bundle_packet(HTC_TARGET * target,HTC_PACKET * pPacket)272 void free_htc_bundle_packet(HTC_TARGET *target, HTC_PACKET *pPacket)
273 {
274 	uint32_t curentHeadRoom;
275 	qdf_nbuf_t netbuf;
276 	HTC_PACKET_QUEUE *pQueueSave;
277 
278 	netbuf = GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket);
279 	AR_DEBUG_ASSERT(netbuf);
280 	if (!netbuf) {
281 		AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
282 				("\n%s: Invalid netbuf in HTC Packet\n",
283 				__func__));
284 		return;
285 	}
286 	/* HIF adds data to the headroom section of the nbuf, restore their
287 	 * original size. If this is not done, headroom keeps shrinking with
288 	 * every HIF send and eventually HIF ends up doing another malloc big
289 	 * enough to store the data + its header
290 	 */
291 
292 	curentHeadRoom = qdf_nbuf_headroom(netbuf);
293 	qdf_nbuf_pull_head(netbuf,
294 			   pPacket->netbufOrigHeadRoom - curentHeadRoom);
295 	qdf_nbuf_trim_tail(netbuf, qdf_nbuf_len(netbuf));
296 
297 	/* restore the pBuffer pointer. HIF changes this */
298 	pPacket->pBuffer = qdf_nbuf_data(netbuf);
299 	pPacket->BufferLength = qdf_nbuf_len(netbuf);
300 
301 	/* restore queue */
302 	pQueueSave = (HTC_PACKET_QUEUE *) pPacket->pContext;
303 	if (qdf_unlikely(!pQueueSave)) {
304 		AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
305 				("\n%s: Invalid pQueueSave in HTC Packet\n",
306 				__func__));
307 		AR_DEBUG_ASSERT(pQueueSave);
308 	} else
309 		INIT_HTC_PACKET_QUEUE(pQueueSave);
310 
311 	LOCK_HTC_TX(target);
312 	if (!target->pBundleFreeList) {
313 		target->pBundleFreeList = pPacket;
314 		pPacket->ListLink.pNext = NULL;
315 	} else {
316 		pPacket->ListLink.pNext = (DL_LIST *) target->pBundleFreeList;
317 		target->pBundleFreeList = pPacket;
318 	}
319 	UNLOCK_HTC_TX(target);
320 }
321 
322 #if defined(DEBUG_HL_LOGGING) && defined(CONFIG_HL_SUPPORT)
323 
324 /**
325  * htc_send_update_tx_bundle_stats() - update tx bundle stats depends
326  *				on max bundle size
327  * @target: hif context
328  * @data_len: tx data len
329  * @TxCreditSize: endpoint tx credit size
330  *
331  * Return: None
332  */
333 static inline void
htc_send_update_tx_bundle_stats(HTC_TARGET * target,qdf_size_t data_len,int TxCreditSize)334 htc_send_update_tx_bundle_stats(HTC_TARGET *target,
335 				qdf_size_t data_len,
336 				int TxCreditSize)
337 {
338 	int index = ((data_len + TxCreditSize - 1) / TxCreditSize) - 1;
339 
340 	if (index < HTC_MAX_MSG_PER_BUNDLE_TX)
341 		target->tx_bundle_stats[index]++;
342 }
343 
344 /**
345  * htc_issue_tx_bundle_stats_inc() - increment in tx bundle stats
346  *				on max bundle size
347  * @target: hif context
348  *
349  * Return: None
350  */
351 static inline void
htc_issue_tx_bundle_stats_inc(HTC_TARGET * target)352 htc_issue_tx_bundle_stats_inc(HTC_TARGET *target)
353 {
354 	target->tx_bundle_stats[0]++;
355 }
356 #else
357 
358 static inline void
htc_send_update_tx_bundle_stats(HTC_TARGET * target,qdf_size_t data_len,int TxCreditSize)359 htc_send_update_tx_bundle_stats(HTC_TARGET *target,
360 				qdf_size_t data_len,
361 				int TxCreditSize)
362 {
363 }
364 
365 static inline void
htc_issue_tx_bundle_stats_inc(HTC_TARGET * target)366 htc_issue_tx_bundle_stats_inc(HTC_TARGET *target)
367 {
368 }
369 #endif
370 
371 #if defined(HIF_USB) || defined(HIF_SDIO)
372 #ifdef ENABLE_BUNDLE_TX
htc_send_bundled_netbuf(HTC_TARGET * target,HTC_ENDPOINT * pEndpoint,unsigned char * pBundleBuffer,HTC_PACKET * pPacketTx)373 static QDF_STATUS htc_send_bundled_netbuf(HTC_TARGET *target,
374 					HTC_ENDPOINT *pEndpoint,
375 					unsigned char *pBundleBuffer,
376 					HTC_PACKET *pPacketTx)
377 {
378 	qdf_size_t data_len;
379 	QDF_STATUS status;
380 	qdf_nbuf_t bundleBuf;
381 	uint32_t data_attr = 0;
382 
383 	bundleBuf = GET_HTC_PACKET_NET_BUF_CONTEXT(pPacketTx);
384 	data_len = pBundleBuffer - qdf_nbuf_data(bundleBuf);
385 	qdf_nbuf_put_tail(bundleBuf, data_len);
386 	SET_HTC_PACKET_INFO_TX(pPacketTx,
387 			       target,
388 			       pBundleBuffer,
389 			       data_len,
390 			       pEndpoint->Id, HTC_TX_PACKET_TAG_BUNDLED);
391 	LOCK_HTC_TX(target);
392 	HTC_PACKET_ENQUEUE(&pEndpoint->TxLookupQueue, pPacketTx);
393 	pEndpoint->ul_outstanding_cnt++;
394 	UNLOCK_HTC_TX(target);
395 #if DEBUG_BUNDLE
396 	qdf_print(" Send bundle EP%d buffer size:0x%x, total:0x%x, count:%d.",
397 		  pEndpoint->Id,
398 		  pEndpoint->TxCreditSize,
399 		  data_len, data_len / pEndpoint->TxCreditSize);
400 #endif
401 
402 	htc_send_update_tx_bundle_stats(target, data_len,
403 					pEndpoint->TxCreditSize);
404 
405 	status = hif_send_head(target->hif_dev,
406 			       pEndpoint->UL_PipeID,
407 			       pEndpoint->Id, data_len,
408 			       bundleBuf, data_attr);
409 	if (qdf_unlikely(QDF_IS_STATUS_ERROR(status))) {
410 		HTC_PACKET_QUEUE requeue;
411 
412 		qdf_print("hif_send_head failed(len=%zu).", data_len);
413 		INIT_HTC_PACKET_QUEUE(&requeue);
414 		LOCK_HTC_TX(target);
415 		pEndpoint->ul_outstanding_cnt--;
416 		HTC_PACKET_REMOVE(&pEndpoint->TxLookupQueue, pPacketTx);
417 
418 		if (pPacketTx->PktInfo.AsTx.Tag == HTC_TX_PACKET_TAG_BUNDLED) {
419 			HTC_PACKET *temp_packet;
420 			HTC_PACKET_QUEUE *packet_queue =
421 				(HTC_PACKET_QUEUE *)pPacketTx->pContext;
422 
423 			HTC_PACKET_QUEUE_ITERATE_ALLOW_REMOVE(packet_queue,
424 							      temp_packet) {
425 				HTC_PACKET_ENQUEUE(&requeue, temp_packet);
426 			} HTC_PACKET_QUEUE_ITERATE_END;
427 
428 			UNLOCK_HTC_TX(target);
429 			free_htc_bundle_packet(target, pPacketTx);
430 			LOCK_HTC_TX(target);
431 
432 		} else {
433 			HTC_PACKET_ENQUEUE(&requeue, pPacketTx);
434 		}
435 
436 		HTC_PACKET_QUEUE_TRANSFER_TO_HEAD(&pEndpoint->TxQueue,
437 						  &requeue);
438 		UNLOCK_HTC_TX(target);
439 	}
440 	return status;
441 }
442 
443 #ifdef QCA_TX_PADDING_CREDIT_SUPPORT
444 #define SDIO_BLOCK_SIZE		512
htc_tx_pad_credit_avail(HTC_ENDPOINT * ep)445 static int htc_tx_pad_credit_avail(HTC_ENDPOINT *ep)
446 {
447 	int ret = 0;
448 
449 	if (!ep || !ep->EpCallBacks.pContext ||
450 	    !ep->EpCallBacks.ep_padding_credit_update)
451 		return 1;
452 
453 	ret = ep->EpCallBacks.ep_padding_credit_update(ep->EpCallBacks.pContext,
454 						       0);
455 
456 	if (ret < 2)
457 		AR_DEBUG_PRINTF(ATH_DEBUG_INFO, ("%s ret %d\n", __func__, ret));
458 
459 	return ret;
460 }
461 
htc_handle_extra_tx_credit(HTC_ENDPOINT * ep,HTC_PACKET * p_last_htc_pkt,unsigned char * p_last_pkt_bundle_buffer,unsigned char ** p_bundle_buffer,int tot_data_len)462 static bool htc_handle_extra_tx_credit(HTC_ENDPOINT *ep,
463 				       HTC_PACKET *p_last_htc_pkt,
464 				       unsigned char *p_last_pkt_bundle_buffer,
465 				       unsigned char **p_bundle_buffer,
466 				       int tot_data_len)
467 {
468 	bool extra_tx_credit = FALSE;
469 	HTC_FRAME_HDR *p_htc_hdr;
470 	int first_buf_bundled_len = 0, last_buf_len = 0;
471 	int sdio_pad = 0, free_space = 0;
472 	int (*update_ep_padding_credit)(void *, int);
473 
474 	update_ep_padding_credit = ep->EpCallBacks.ep_padding_credit_update;
475 
476 	AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
477 			("%s Tot data_len = %d\n", __func__, tot_data_len));
478 
479 	if (!p_last_htc_pkt)
480 		return extra_tx_credit;
481 
482 	last_buf_len = (p_last_htc_pkt->ActualLength + HTC_HDR_LENGTH);
483 	if (tot_data_len != last_buf_len) {
484 		first_buf_bundled_len = tot_data_len - ep->TxCreditSize;
485 		free_space = tot_data_len -
486 					(first_buf_bundled_len + last_buf_len);
487 	} else {
488 		free_space = ep->TxCreditSize - tot_data_len;
489 	}
490 
491 	sdio_pad = SDIO_BLOCK_SIZE - ((first_buf_bundled_len + last_buf_len) %
492 			SDIO_BLOCK_SIZE);
493 
494 	AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
495 			("%s first_buf_bundled_len = %d last_buf_len = %d\n",
496 			__func__, first_buf_bundled_len, last_buf_len));
497 
498 	AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
499 			("%s sdio_pad = %d free_space = %d\n", __func__,
500 			sdio_pad, free_space));
501 
502 	if (sdio_pad <= free_space) {
503 		if (p_bundle_buffer && *p_bundle_buffer) {
504 			/* Align Tx bundled buf to avoid a extra Padding buf */
505 			*p_bundle_buffer -= (free_space - sdio_pad);
506 		}
507 	} else {
508 		/* Extra Padding Buffer needed, consume extra tx credit */
509 		AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
510 				("%s Used a Tx credit for Padding Buffer\n",
511 				 __func__));
512 		p_htc_hdr = (HTC_FRAME_HDR *)(p_last_pkt_bundle_buffer);
513 		p_htc_hdr->Flags |= HTC_FLAGS_PADDING_CHECK;
514 		extra_tx_credit = TRUE;
515 		if (ep->EpCallBacks.ep_padding_credit_update) {
516 			/* Decrement 1 credit at host,
517 			 * due to extra tx credit consumed by padding buffer
518 			 */
519 			update_ep_padding_credit(ep->EpCallBacks.pContext, -1);
520 		}
521 	}
522 	return extra_tx_credit;
523 }
524 #else
htc_tx_pad_credit_avail(HTC_ENDPOINT * ep)525 static int htc_tx_pad_credit_avail(HTC_ENDPOINT *ep)
526 {
527 	return 1;
528 }
529 
htc_handle_extra_tx_credit(HTC_ENDPOINT * ep,HTC_PACKET * p_last_htc_pkt,unsigned char * p_last_pkt_bundle_buffer,unsigned char ** p_bundle_buffer,int tot_data_len)530 static bool htc_handle_extra_tx_credit(HTC_ENDPOINT *ep,
531 				       HTC_PACKET *p_last_htc_pkt,
532 				       unsigned char *p_last_pkt_bundle_buffer,
533 				       unsigned char **p_bundle_buffer,
534 				       int tot_data_len)
535 {
536 	return FALSE;
537 }
538 #endif
539 
540 /**
541  * htc_issue_packets_bundle() - HTC function to send bundle packets from a queue
542  * @target: HTC target on which packets need to be sent
543  * @pEndpoint: logical endpoint on which packets needs to be sent
544  * @pPktQueue: HTC packet queue containing the list of packets to be sent
545  *
546  * Return: void
547  */
htc_issue_packets_bundle(HTC_TARGET * target,HTC_ENDPOINT * pEndpoint,HTC_PACKET_QUEUE * pPktQueue)548 static void htc_issue_packets_bundle(HTC_TARGET *target,
549 				     HTC_ENDPOINT *pEndpoint,
550 				     HTC_PACKET_QUEUE *pPktQueue)
551 {
552 	int i, frag_count, nbytes;
553 	qdf_nbuf_t netbuf, bundleBuf;
554 	unsigned char *pBundleBuffer = NULL;
555 	HTC_PACKET *pPacket = NULL, *pPacketTx = NULL;
556 	HTC_FRAME_HDR *pHtcHdr;
557 	int last_credit_pad = 0;
558 	int creditPad, creditRemainder, transferLength, bundlesSpaceRemaining =
559 		0;
560 	HTC_PACKET_QUEUE *pQueueSave = NULL;
561 	HTC_PACKET *p_last_htc_pkt = NULL;
562 	unsigned char *p_last_pkt_bundle_buffer = NULL;
563 
564 	bundlesSpaceRemaining =
565 		target->MaxMsgsPerHTCBundle * pEndpoint->TxCreditSize;
566 	pPacketTx = allocate_htc_bundle_packet(target);
567 	if (!pPacketTx) {
568 		/* good time to panic */
569 		AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
570 				("allocate_htc_bundle_packet failed\n"));
571 		AR_DEBUG_ASSERT(false);
572 		return;
573 	}
574 	bundleBuf = GET_HTC_PACKET_NET_BUF_CONTEXT(pPacketTx);
575 	pBundleBuffer = qdf_nbuf_data(bundleBuf);
576 	pQueueSave = (HTC_PACKET_QUEUE *) pPacketTx->pContext;
577 	while (1) {
578 		if (pEndpoint->EpCallBacks.ep_padding_credit_update) {
579 			if (htc_tx_pad_credit_avail(pEndpoint) < 1)
580 				break;
581 		}
582 		pPacket = htc_packet_dequeue(pPktQueue);
583 		if (!pPacket)
584 			break;
585 		creditPad = 0;
586 		transferLength = pPacket->ActualLength + HTC_HDR_LENGTH;
587 		creditRemainder = transferLength % pEndpoint->TxCreditSize;
588 		if (creditRemainder != 0) {
589 			if (transferLength < pEndpoint->TxCreditSize) {
590 				creditPad = pEndpoint->TxCreditSize -
591 					    transferLength;
592 			} else {
593 				creditPad = creditRemainder;
594 			}
595 			transferLength += creditPad;
596 		}
597 
598 		if (bundlesSpaceRemaining < transferLength) {
599 			htc_handle_extra_tx_credit(pEndpoint, p_last_htc_pkt,
600 						   p_last_pkt_bundle_buffer,
601 						   &pBundleBuffer,
602 						   pBundleBuffer -
603 						   qdf_nbuf_data(bundleBuf));
604 
605 			/* send out previous buffer */
606 			htc_send_bundled_netbuf(target, pEndpoint,
607 						pBundleBuffer - last_credit_pad,
608 						pPacketTx);
609 			/* One packet has been dequeued from sending queue when enter
610 			 * this loop, so need to add 1 back for this checking.
611 			 */
612 			if ((HTC_PACKET_QUEUE_DEPTH(pPktQueue) + 1) <
613 			    HTC_MIN_MSG_PER_BUNDLE) {
614 				HTC_PACKET_ENQUEUE_TO_HEAD(pPktQueue, pPacket);
615 				return;
616 			}
617 			bundlesSpaceRemaining =
618 				target->MaxMsgsPerHTCBundle *
619 				pEndpoint->TxCreditSize;
620 			pPacketTx = allocate_htc_bundle_packet(target);
621 			if (!pPacketTx) {
622 				HTC_PACKET_ENQUEUE_TO_HEAD(pPktQueue, pPacket);
623 				/* good time to panic */
624 				AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
625 						("allocate_htc_bundle_packet failed\n"));
626 				AR_DEBUG_ASSERT(false);
627 				return;
628 			}
629 			bundleBuf = GET_HTC_PACKET_NET_BUF_CONTEXT(pPacketTx);
630 			pBundleBuffer = qdf_nbuf_data(bundleBuf);
631 			pQueueSave = (HTC_PACKET_QUEUE *) pPacketTx->pContext;
632 		}
633 
634 		p_last_htc_pkt = pPacket;
635 		p_last_pkt_bundle_buffer = pBundleBuffer;
636 
637 		bundlesSpaceRemaining -= transferLength;
638 		netbuf = GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket);
639 
640 		if (hif_get_bus_type(target->hif_dev) != QDF_BUS_TYPE_USB) {
641 			pHtcHdr = (HTC_FRAME_HDR *)qdf_nbuf_get_frag_vaddr(
642 								netbuf, 0);
643 			HTC_WRITE32(pHtcHdr,
644 				SM(pPacket->ActualLength,
645 				HTC_FRAME_HDR_PAYLOADLEN) |
646 				SM(pPacket->PktInfo.AsTx.SendFlags |
647 				HTC_FLAGS_SEND_BUNDLE,
648 				HTC_FRAME_HDR_FLAGS) |
649 				SM(pPacket->Endpoint,
650 				HTC_FRAME_HDR_ENDPOINTID));
651 			HTC_WRITE32((uint32_t *) pHtcHdr + 1,
652 				SM(pPacket->PktInfo.AsTx.SeqNo,
653 				HTC_FRAME_HDR_CONTROLBYTES1) | SM(creditPad,
654 				HTC_FRAME_HDR_RESERVED));
655 			pHtcHdr->reserved = creditPad;
656 		}
657 		frag_count = qdf_nbuf_get_num_frags(netbuf);
658 		nbytes = pPacket->ActualLength + HTC_HDR_LENGTH;
659 		for (i = 0; i < frag_count && nbytes > 0; i++) {
660 			int frag_len = qdf_nbuf_get_frag_len(netbuf, i);
661 			unsigned char *frag_addr =
662 				qdf_nbuf_get_frag_vaddr(netbuf, i);
663 			if (frag_len > nbytes)
664 				frag_len = nbytes;
665 			qdf_mem_copy(pBundleBuffer, frag_addr, frag_len);
666 			nbytes -= frag_len;
667 			pBundleBuffer += frag_len;
668 		}
669 		HTC_PACKET_ENQUEUE(pQueueSave, pPacket);
670 		pBundleBuffer += creditPad;
671 
672 		/* last one can't be packed. */
673 		if (hif_get_bus_type(target->hif_dev) == QDF_BUS_TYPE_USB)
674 			last_credit_pad = creditPad;
675 	}
676 	/* send out remaining buffer */
677 	if (pBundleBuffer != qdf_nbuf_data(bundleBuf)) {
678 		htc_handle_extra_tx_credit(pEndpoint, p_last_htc_pkt,
679 					   p_last_pkt_bundle_buffer,
680 					   &pBundleBuffer,
681 					   pBundleBuffer -
682 					   qdf_nbuf_data(bundleBuf));
683 
684 		htc_send_bundled_netbuf(target, pEndpoint,
685 					pBundleBuffer - last_credit_pad,
686 					pPacketTx);
687 	} else {
688 		free_htc_bundle_packet(target, pPacketTx);
689 	}
690 }
691 #endif /* ENABLE_BUNDLE_TX */
692 #else
htc_tx_pad_credit_avail(HTC_ENDPOINT * ep)693 static int htc_tx_pad_credit_avail(HTC_ENDPOINT *ep)
694 {
695 	return 1;
696 }
697 
698 bool htc_handle_extra_tx_credit(HTC_ENDPOINT *ep,
699 				HTC_PACKET *p_last_htc_pkt,
700 				unsigned char *p_last_pkt_bundle_buffer,
701 				unsigned char **p_bundle_buffer,
702 				int tot_data_len);
htc_handle_extra_tx_credit(HTC_ENDPOINT * ep,HTC_PACKET * p_last_htc_pkt,unsigned char * p_last_pkt_bundle_buffer,unsigned char ** p_bundle_buffer,int tot_data_len)703 bool htc_handle_extra_tx_credit(HTC_ENDPOINT *ep,
704 				HTC_PACKET *p_last_htc_pkt,
705 				unsigned char *p_last_pkt_bundle_buffer,
706 				unsigned char **p_bundle_buffer,
707 				int tot_data_len)
708 {
709 	return FALSE;
710 }
711 
htc_issue_packets_bundle(HTC_TARGET * target,HTC_ENDPOINT * pEndpoint,HTC_PACKET_QUEUE * pPktQueue)712 static void htc_issue_packets_bundle(HTC_TARGET *target,
713 				     HTC_ENDPOINT *pEndpoint,
714 				     HTC_PACKET_QUEUE *pPktQueue)
715 {
716 }
717 #endif
718 
719 /**
720  * htc_issue_packets() - HTC function to send packets from a queue
721  * @target: HTC target on which packets need to be sent
722  * @pEndpoint: logical endpoint on which packets needs to be sent
723  * @pPktQueue: HTC packet queue containing the list of packets to be sent
724  *
725  * Return: QDF_STATUS_SUCCESS on success and error QDF status on failure
726  */
htc_issue_packets(HTC_TARGET * target,HTC_ENDPOINT * pEndpoint,HTC_PACKET_QUEUE * pPktQueue)727 static QDF_STATUS htc_issue_packets(HTC_TARGET *target,
728 				  HTC_ENDPOINT *pEndpoint,
729 				  HTC_PACKET_QUEUE *pPktQueue)
730 {
731 	QDF_STATUS status = QDF_STATUS_SUCCESS;
732 	qdf_nbuf_t netbuf;
733 	HTC_PACKET *pPacket = NULL;
734 	uint16_t payloadLen;
735 	HTC_FRAME_HDR *pHtcHdr;
736 	uint32_t data_attr = 0;
737 	enum qdf_bus_type bus_type;
738 	QDF_STATUS ret;
739 	bool rt_put = false;
740 	bool used_extra_tx_credit = false;
741 	uint8_t *buf = NULL;
742 	int (*update_ep_padding_credit)(void *, int);
743 	void *ctx = NULL;
744 	bool rt_put_in_resp;
745 	int32_t sys_state = HIF_SYSTEM_PM_STATE_ON;
746 
747 	update_ep_padding_credit =
748 			pEndpoint->EpCallBacks.ep_padding_credit_update;
749 
750 	bus_type = hif_get_bus_type(target->hif_dev);
751 
752 	AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
753 			("+htc_issue_packets: Queue: %pK, Pkts %d\n", pPktQueue,
754 			 HTC_PACKET_QUEUE_DEPTH(pPktQueue)));
755 	while (true) {
756 		rt_put_in_resp = false;
757 		if (HTC_TX_BUNDLE_ENABLED(target) &&
758 		    HTC_PACKET_QUEUE_DEPTH(pPktQueue) >=
759 		    HTC_MIN_MSG_PER_BUNDLE) {
760 			switch (bus_type) {
761 			case QDF_BUS_TYPE_SDIO:
762 				if (!IS_TX_CREDIT_FLOW_ENABLED(pEndpoint))
763 					break;
764 				if (update_ep_padding_credit) {
765 					if (htc_tx_pad_credit_avail
766 					    (pEndpoint) < 1)
767 						break;
768 				}
769 				fallthrough;
770 			case QDF_BUS_TYPE_USB:
771 				htc_issue_packets_bundle(target,
772 							pEndpoint,
773 							pPktQueue);
774 				break;
775 			default:
776 				break;
777 			}
778 		}
779 		/* if not bundling or there was a packet that could not be
780 		 * placed in a bundle, and send it by normal way
781 		 */
782 		if (pEndpoint->EpCallBacks.ep_padding_credit_update) {
783 			if (htc_tx_pad_credit_avail(pEndpoint) < 1) {
784 				status = QDF_STATUS_E_FAILURE;
785 				break;
786 			}
787 		}
788 
789 		pPacket = htc_packet_dequeue(pPktQueue);
790 		if (!pPacket) {
791 			/* local queue is fully drained */
792 			break;
793 		}
794 
795 		netbuf = GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket);
796 		AR_DEBUG_ASSERT(netbuf);
797 		/* Non-credit enabled endpoints have been mapped and setup by
798 		 * now, so no need to revisit the HTC headers
799 		 */
800 		if (IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)) {
801 
802 			payloadLen = pPacket->ActualLength;
803 			/* setup HTC frame header */
804 
805 			pHtcHdr = (HTC_FRAME_HDR *)
806 				qdf_nbuf_get_frag_vaddr(netbuf, 0);
807 			if (qdf_unlikely(!pHtcHdr)) {
808 				AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
809 						("%s Invalid pHtcHdr\n",
810 						 __func__));
811 				AR_DEBUG_ASSERT(pHtcHdr);
812 				status = QDF_STATUS_E_FAILURE;
813 				break;
814 			}
815 
816 			HTC_WRITE32(pHtcHdr,
817 					SM(payloadLen,
818 						HTC_FRAME_HDR_PAYLOADLEN) |
819 					SM(pPacket->PktInfo.AsTx.SendFlags,
820 						HTC_FRAME_HDR_FLAGS) |
821 					SM(pPacket->Endpoint,
822 						HTC_FRAME_HDR_ENDPOINTID));
823 			HTC_WRITE32(((uint32_t *) pHtcHdr) + 1,
824 				    SM(pPacket->PktInfo.AsTx.SeqNo,
825 				       HTC_FRAME_HDR_CONTROLBYTES1));
826 
827 			/*
828 			 * Now that the HTC frame header has been added, the
829 			 * netbuf can be mapped.  This only applies to non-data
830 			 * frames, since data frames were already mapped as they
831 			 * entered into the driver.
832 			 */
833 			ret = qdf_nbuf_map(target->osdev,
834 				GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket),
835 				QDF_DMA_TO_DEVICE);
836 			if (ret != QDF_STATUS_SUCCESS) {
837 				AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
838 					("%s nbuf Map Fail Endpnt %pK\n",
839 					__func__, pEndpoint));
840 				HTC_PACKET_ENQUEUE_TO_HEAD(pPktQueue, pPacket);
841 				status = QDF_STATUS_E_FAILURE;
842 				break;
843 			}
844 			pPacket->PktInfo.AsTx.Flags |=
845 				HTC_TX_PACKET_FLAG_FIXUP_NETBUF;
846 		}
847 
848 		if (!pEndpoint->async_update) {
849 			LOCK_HTC_TX(target);
850 		}
851 		/* store in look up queue to match completions */
852 		HTC_PACKET_ENQUEUE(&pEndpoint->TxLookupQueue, pPacket);
853 		INC_HTC_EP_STAT(pEndpoint, TxIssued, 1);
854 		pEndpoint->ul_outstanding_cnt++;
855 		if (!pEndpoint->async_update) {
856 			UNLOCK_HTC_TX(target);
857 			hif_send_complete_check(target->hif_dev,
858 					pEndpoint->UL_PipeID, false);
859 		}
860 
861 		if (pPacket->PktInfo.AsTx.Tag == HTC_TX_PACKET_SYSTEM_SUSPEND) {
862 			sys_state = hif_system_pm_get_state(target->hif_dev);
863 			hif_system_pm_set_state_suspending(target->hif_dev);
864 		}
865 
866 		htc_packet_set_magic_cookie(pPacket, HTC_PACKET_MAGIC_COOKIE);
867 		/*
868 		 * For HTT messages without a response from fw,
869 		 *   do the runtime put here.
870 		 * otherwise runtime put will be done when the fw response comes
871 		 */
872 		if (pPacket->PktInfo.AsTx.Tag == HTC_TX_PACKET_TAG_RUNTIME_PUT) {
873 			rt_put = true;
874 		} else if (pPacket->PktInfo.AsTx.Tag ==
875 			 HTC_TX_PACKET_TAG_RTPM_PUT_RC) {
876 			rt_put_in_resp = true;
877 			htc_inc_htt_runtime_cnt(target);
878 		}
879 
880 #if DEBUG_BUNDLE
881 		qdf_print(" Send single EP%d buffer size:0x%x, total:0x%x.",
882 			  pEndpoint->Id,
883 			  pEndpoint->TxCreditSize,
884 			  HTC_HDR_LENGTH + pPacket->ActualLength);
885 #endif
886 		buf = (uint8_t *)qdf_nbuf_get_frag_vaddr(netbuf, 0);
887 		used_extra_tx_credit =
888 			htc_handle_extra_tx_credit(pEndpoint, pPacket, buf,
889 						   NULL, pPacket->ActualLength +
890 						   HTC_HDR_LENGTH);
891 
892 		status = hif_send_head(target->hif_dev,
893 				       pEndpoint->UL_PipeID, pEndpoint->Id,
894 				       HTC_HDR_LENGTH + pPacket->ActualLength,
895 				       netbuf, data_attr);
896 
897 		if (status != QDF_STATUS_SUCCESS) {
898 			if (rt_put_in_resp)
899 				htc_dec_return_htt_runtime_cnt((void *)target);
900 
901 			if (pPacket->PktInfo.AsTx.Tag ==
902 			    HTC_TX_PACKET_SYSTEM_SUSPEND)
903 				__hif_system_pm_set_state(target->hif_dev,
904 							  sys_state);
905 
906 			if (pEndpoint->EpCallBacks.ep_padding_credit_update) {
907 				if (used_extra_tx_credit) {
908 					ctx = pEndpoint->EpCallBacks.pContext;
909 					update_ep_padding_credit(ctx, 1);
910 				}
911 			}
912 		}
913 
914 		htc_issue_tx_bundle_stats_inc(target);
915 
916 		target->ce_send_cnt++;
917 		pEndpoint->htc_send_cnt++;
918 
919 		if (qdf_unlikely(QDF_IS_STATUS_ERROR(status))) {
920 			if (status != QDF_STATUS_E_RESOURCES) {
921 				/* TODO : if more than 1 endpoint maps to the
922 				 * same PipeID it is possible to run out of
923 				 * resources in the HIF layer. Don't emit the
924 				 * error
925 				 */
926 				AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
927 						("hif_send Failed status:%d\n",
928 						 status));
929 			} else {
930 				if (target->htc_pkt_dbg) {
931 					if (pEndpoint->num_requeues_warn >
932 						MAX_REQUEUE_WARN) {
933 						hif_print_napi_stats(target->hif_dev);
934 					}
935 				}
936 			}
937 
938 			/* only unmap if we mapped in this function */
939 			if (IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)) {
940 				qdf_nbuf_unmap(target->osdev,
941 					GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket),
942 					QDF_DMA_TO_DEVICE);
943 				pPacket->PktInfo.AsTx.Flags &=
944 					~HTC_TX_PACKET_FLAG_FIXUP_NETBUF;
945 			}
946 
947 			if (!pEndpoint->async_update) {
948 				LOCK_HTC_TX(target);
949 			}
950 			target->ce_send_cnt--;
951 			pEndpoint->htc_send_cnt--;
952 			pEndpoint->ul_outstanding_cnt--;
953 			HTC_PACKET_REMOVE(&pEndpoint->TxLookupQueue, pPacket);
954 			htc_packet_set_magic_cookie(pPacket, 0);
955 			/* put it back into the callers queue */
956 			HTC_PACKET_ENQUEUE_TO_HEAD(pPktQueue, pPacket);
957 			/* reclaim credits */
958 			HTC_PACKET_QUEUE_ITERATE_ALLOW_REMOVE(pPktQueue,
959 							      pPacket) {
960 			    pEndpoint->TxCredits +=
961 				pPacket->PktInfo.AsTx.CreditsUsed;
962 			} HTC_PACKET_QUEUE_ITERATE_END;
963 			if (!pEndpoint->async_update) {
964 				UNLOCK_HTC_TX(target);
965 			}
966 			break;
967 		}
968 		if (rt_put) {
969 			hif_rtpm_put(HIF_RTPM_PUT_ASYNC, HIF_RTPM_ID_HTT);
970 			rt_put = false;
971 		}
972 	}
973 
974 	if (qdf_unlikely(QDF_IS_STATUS_ERROR(status))) {
975 		if (((status == QDF_STATUS_E_RESOURCES) &&
976 		     (pEndpoint->num_requeues_warn > MAX_REQUEUE_WARN)) ||
977 		     (status != QDF_STATUS_E_RESOURCES)) {
978 			QDF_TRACE(QDF_MODULE_ID_HIF, QDF_TRACE_LEVEL_INFO,
979 				  "failed pkt:0x%pK status:%d endpoint:%d",
980 				  pPacket, status, pEndpoint->Id);
981 		}
982 
983 	}
984 
985 	AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-htc_issue_packets\n"));
986 
987 	return status;
988 }
989 
990 #ifdef FEATURE_RUNTIME_PM
991 /**
992  * extract_htc_pm_packets() - move pm packets from endpoint into queue
993  * @endpoint: which endpoint to extract packets from
994  * @queue: a queue to store extracted packets in.
995  *
996  * remove pm packets from the endpoint's tx queue.
997  * queue them into a queue
998  */
extract_htc_pm_packets(HTC_ENDPOINT * endpoint,HTC_PACKET_QUEUE * queue)999 static void extract_htc_pm_packets(HTC_ENDPOINT *endpoint,
1000 				HTC_PACKET_QUEUE *queue)
1001 {
1002 	HTC_PACKET *packet;
1003 
1004 	/* only WMI endpoint has power management packets */
1005 	if (endpoint->service_id != WMI_CONTROL_SVC)
1006 		return;
1007 
1008 	ITERATE_OVER_LIST_ALLOW_REMOVE(&endpoint->TxQueue.QueueHead, packet,
1009 			HTC_PACKET, ListLink) {
1010 		if (packet->PktInfo.AsTx.Tag == HTC_TX_PACKET_TAG_AUTO_PM) {
1011 			HTC_PACKET_REMOVE(&endpoint->TxQueue, packet);
1012 			HTC_PACKET_ENQUEUE(queue, packet);
1013 		}
1014 	} ITERATE_END
1015 }
1016 
1017 /**
1018  * queue_htc_pm_packets() - queue pm packets with priority
1019  * @endpoint: endpoint to queue packets to
1020  * @queue: queue of pm packets to enqueue
1021  *
1022  * suspend resume packets get special treatment & priority.
1023  * need to queue them at the front of the queue.
1024  */
queue_htc_pm_packets(HTC_ENDPOINT * endpoint,HTC_PACKET_QUEUE * queue)1025 static void queue_htc_pm_packets(HTC_ENDPOINT *endpoint,
1026 				 HTC_PACKET_QUEUE *queue)
1027 {
1028 	if (endpoint->service_id != WMI_CONTROL_SVC)
1029 		return;
1030 
1031 	HTC_PACKET_QUEUE_TRANSFER_TO_HEAD(&endpoint->TxQueue, queue);
1032 }
1033 
1034 /**
1035  * htc_dec_wmi_runtime_cnt: Decrement htc wmi runtime count
1036  * @target: HTC target
1037  * @rtpm_code: RTPM code
1038  *
1039  * Return: None
1040  */
1041 static inline
htc_dec_wmi_runtime_cnt(HTC_TARGET * target,uint8_t rtpm_code)1042 void htc_dec_wmi_runtime_cnt(HTC_TARGET *target, uint8_t rtpm_code)
1043 {
1044 	if (rtpm_code == HIF_RTPM_ID_WMI)
1045 		qdf_atomic_dec(&target->htc_wmi_runtime_cnt);
1046 }
1047 
1048 /**
1049  * htc_inc_wmi_runtime_cnt: Increment htc wmi runtime count
1050  * @target: HTC target
1051  * @rtpm_code: RTPM code
1052  *
1053  * Return: None
1054  */
1055 static inline
htc_inc_wmi_runtime_cnt(HTC_TARGET * target,uint8_t rtpm_code)1056 void htc_inc_wmi_runtime_cnt(HTC_TARGET *target, uint8_t rtpm_code)
1057 {
1058 	if (rtpm_code == HIF_RTPM_ID_WMI)
1059 		qdf_atomic_inc(&target->htc_wmi_runtime_cnt);
1060 }
1061 #else
extract_htc_pm_packets(HTC_ENDPOINT * endpoint,HTC_PACKET_QUEUE * queue)1062 static void extract_htc_pm_packets(HTC_ENDPOINT *endpoint,
1063 		HTC_PACKET_QUEUE *queue)
1064 {}
1065 
queue_htc_pm_packets(HTC_ENDPOINT * endpoint,HTC_PACKET_QUEUE * queue)1066 static void queue_htc_pm_packets(HTC_ENDPOINT *endpoint,
1067 		HTC_PACKET_QUEUE *queue)
1068 {}
1069 
1070 static inline
htc_dec_wmi_runtime_cnt(HTC_TARGET * target,uint8_t rtpm_code)1071 void htc_dec_wmi_runtime_cnt(HTC_TARGET *target, uint8_t rtpm_code)
1072 {
1073 }
1074 
1075 static inline
htc_inc_wmi_runtime_cnt(HTC_TARGET * target,uint8_t rtpm_code)1076 void htc_inc_wmi_runtime_cnt(HTC_TARGET *target, uint8_t rtpm_code)
1077 {
1078 }
1079 #endif
1080 
1081 /**
1082  * htc_send_pkts_get_rtpm_id() - get runtime pm dbgid by service_id
1083  * @service_id: service for endpoint
1084  *
1085  * For service_id HTT_DATA_MSG_SVC, HTT message donot have a tx complete
1086  * from CE level, so they need runtime put which only can happen in fw
1087  * response. runtime put will happens at 2 ways.
1088  *    1 if packet tag HTC_TX_PACKET_TAG_RUNTIME_PUT, runtime put
1089  *      will be just in htc_issue_packets. as such pkt doesn't have
1090  *      a response from fw.
1091  *    2 other pkt must have a response from fw, it will be handled
1092  *      by fw response using htc_pm_runtime_put.
1093  *
1094  * For other service_id, they have tx_completion from CE, so they will be
1095  * handled in htc_tx_completion_handler, except packet tag as
1096  * HTC_TX_PACKET_TAG_AUTO_PM, pm related wmi cmd don't need a runtime
1097  * put/get.
1098  *
1099  *
1100  * Return: rtpm id to trace who used it
1101  */
1102 static unsigned int
htc_send_pkts_get_rtpm_id(HTC_SERVICE_ID service_id)1103 htc_send_pkts_get_rtpm_id(HTC_SERVICE_ID service_id)
1104 {
1105 	if (service_id == HTT_DATA_MSG_SVC)
1106 		return HIF_RTPM_ID_HTT;
1107 	else
1108 		return HIF_RTPM_ID_WMI;
1109 }
1110 
1111 #ifdef SYSTEM_PM_CHECK
1112 /**
1113  * extract_htc_system_resume_pkts() - Move system pm resume packets from
1114  *                                    endpoint into queue
1115  * @endpoint: which endpoint to extract packets from
1116  * @queue: a queue to store extracted packets in.
1117  *
1118  * Remove pm packets from the endpoint's tx queue and enqueue
1119  * them into a queue
1120  */
extract_htc_system_resume_pkts(HTC_ENDPOINT * endpoint,HTC_PACKET_QUEUE * queue)1121 static void extract_htc_system_resume_pkts(HTC_ENDPOINT *endpoint,
1122 					   HTC_PACKET_QUEUE *queue)
1123 {
1124 	HTC_PACKET *packet;
1125 
1126 	/* only WMI endpoint has power management packets */
1127 	if (endpoint->service_id != WMI_CONTROL_SVC)
1128 		return;
1129 
1130 	ITERATE_OVER_LIST_ALLOW_REMOVE(&endpoint->TxQueue.QueueHead, packet,
1131 				       HTC_PACKET, ListLink) {
1132 		if (packet->PktInfo.AsTx.Tag == HTC_TX_PACKET_SYSTEM_RESUME) {
1133 			HTC_PACKET_REMOVE(&endpoint->TxQueue, packet);
1134 			HTC_PACKET_ENQUEUE(queue, packet);
1135 		}
1136 	} ITERATE_END
1137 }
1138 #else
1139 static inline
extract_htc_system_resume_pkts(HTC_ENDPOINT * endpoint,HTC_PACKET_QUEUE * queue)1140 void extract_htc_system_resume_pkts(HTC_ENDPOINT *endpoint,
1141 				    HTC_PACKET_QUEUE *queue)
1142 {
1143 }
1144 #endif
1145 
1146 /**
1147  * get_htc_send_packets_credit_based() - get packets based on available credits
1148  * @target: HTC target on which packets need to be sent
1149  * @pEndpoint: logical endpoint on which packets needs to be sent
1150  * @pQueue: HTC packet queue containing the list of packets to be sent
1151  *
1152  * Get HTC send packets from TX queue on an endpoint based on available credits.
1153  * The function moves the packets from TX queue of the endpoint to pQueue.
1154  *
1155  * Return: None
1156  */
get_htc_send_packets_credit_based(HTC_TARGET * target,HTC_ENDPOINT * pEndpoint,HTC_PACKET_QUEUE * pQueue)1157 static void get_htc_send_packets_credit_based(HTC_TARGET *target,
1158 					      HTC_ENDPOINT *pEndpoint,
1159 					      HTC_PACKET_QUEUE *pQueue)
1160 {
1161 	int creditsRequired;
1162 	int remainder;
1163 	uint8_t sendFlags;
1164 	HTC_PACKET *pPacket;
1165 	unsigned int transferLength;
1166 	HTC_PACKET_QUEUE *tx_queue;
1167 	HTC_PACKET_QUEUE pm_queue;
1168 	bool do_pm_get = false;
1169 	unsigned int rtpm_code = 0;
1170 	int ret;
1171 	HTC_PACKET_QUEUE sys_pm_queue;
1172 	bool sys_pm_check = false;
1173 
1174 	/*** NOTE : the TX lock is held when this function is called ***/
1175 	AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
1176 			("+get_htc_send_packets_credit_based\n"));
1177 
1178 	INIT_HTC_PACKET_QUEUE(&pm_queue);
1179 	extract_htc_pm_packets(pEndpoint, &pm_queue);
1180 	if (HTC_QUEUE_EMPTY(&pm_queue)) {
1181 		do_pm_get = true;
1182 
1183 		INIT_HTC_PACKET_QUEUE(&sys_pm_queue);
1184 		extract_htc_system_resume_pkts(pEndpoint, &sys_pm_queue);
1185 		if (HTC_QUEUE_EMPTY(&sys_pm_queue)) {
1186 			tx_queue = &pEndpoint->TxQueue;
1187 			sys_pm_check = true;
1188 		} else {
1189 			tx_queue = &sys_pm_queue;
1190 		}
1191 	} else {
1192 		tx_queue = &pm_queue;
1193 	}
1194 
1195 	/* loop until we can grab as many packets out of the queue as we can */
1196 	while (true) {
1197 		if (do_pm_get) {
1198 			rtpm_code = htc_send_pkts_get_rtpm_id(
1199 							pEndpoint->service_id);
1200 			ret = hif_rtpm_get(HIF_RTPM_GET_ASYNC, rtpm_code);
1201 			if (ret) {
1202 				/* bus suspended, runtime resume issued */
1203 				if (HTC_PACKET_QUEUE_DEPTH(pQueue) > 0)
1204 					AR_DEBUG_PRINTF(ATH_DEBUG_WARN,
1205 							(" pQueue depth: %d\n",
1206 							 HTC_PACKET_QUEUE_DEPTH(pQueue)));
1207 
1208 				pPacket = htc_get_pkt_at_head(tx_queue);
1209 				if (!pPacket ||
1210 				    (pPacket->Endpoint >= ENDPOINT_MAX) ||
1211 				    (pPacket->Endpoint <= ENDPOINT_UNUSED))
1212 					break;
1213 				log_packet_info(target, pPacket);
1214 				break;
1215 			}
1216 			htc_inc_wmi_runtime_cnt(target, rtpm_code);
1217 		}
1218 
1219 		sendFlags = 0;
1220 		/* get packet at head, but don't remove it */
1221 		pPacket = htc_get_pkt_at_head(tx_queue);
1222 		if (!pPacket) {
1223 			if (do_pm_get) {
1224 				hif_rtpm_put(HIF_RTPM_PUT_ASYNC, rtpm_code);
1225 				htc_dec_wmi_runtime_cnt(target, rtpm_code);
1226 			}
1227 			break;
1228 		}
1229 
1230 		if (sys_pm_check &&
1231 		    hif_system_pm_state_check(target->hif_dev)) {
1232 			if (do_pm_get) {
1233 				hif_rtpm_put(HIF_RTPM_PUT_ASYNC, rtpm_code);
1234 				htc_dec_wmi_runtime_cnt(target, rtpm_code);
1235 			}
1236 			break;
1237 		}
1238 
1239 		AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
1240 				(" Got head packet:%pK , Queue Depth: %d\n",
1241 				 pPacket,
1242 				 HTC_PACKET_QUEUE_DEPTH(tx_queue)));
1243 
1244 		transferLength = pPacket->ActualLength + HTC_HDR_LENGTH;
1245 
1246 		if (transferLength <= pEndpoint->TxCreditSize) {
1247 			creditsRequired = 1;
1248 		} else {
1249 			/* figure out how many credits this message requires */
1250 			creditsRequired =
1251 				transferLength / pEndpoint->TxCreditSize;
1252 			remainder = transferLength % pEndpoint->TxCreditSize;
1253 
1254 			if (remainder)
1255 				creditsRequired++;
1256 		}
1257 
1258 		AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
1259 				(" Credits Required:%d   Got:%d\n",
1260 				 creditsRequired, pEndpoint->TxCredits));
1261 
1262 		if (pEndpoint->Id == ENDPOINT_0) {
1263 			/*
1264 			 * endpoint 0 is special, it always has a credit and
1265 			 * does not require credit based flow control
1266 			 */
1267 			creditsRequired = 0;
1268 		} else {
1269 
1270 			if (pEndpoint->TxCredits < creditsRequired) {
1271 #if DEBUG_CREDIT
1272 				AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
1273 						("EP%d,No Credit now.%d < %d\n",
1274 						 pEndpoint->Id,
1275 						 pEndpoint->TxCredits,
1276 						 creditsRequired));
1277 #endif
1278 				if (do_pm_get) {
1279 					hif_rtpm_put(HIF_RTPM_PUT_ASYNC,
1280 						     rtpm_code);
1281 					htc_dec_wmi_runtime_cnt(target,
1282 								rtpm_code);
1283 				}
1284 
1285 				break;
1286 			}
1287 
1288 			pEndpoint->TxCredits -= creditsRequired;
1289 			INC_HTC_EP_STAT(pEndpoint, TxCreditsConsummed,
1290 					creditsRequired);
1291 
1292 			/* check if we need credits back from the target */
1293 			if (pEndpoint->TxCredits <=
1294 			    pEndpoint->TxCreditsPerMaxMsg) {
1295 				/* tell the target we need credits ASAP! */
1296 				sendFlags |= HTC_FLAGS_NEED_CREDIT_UPDATE;
1297 				if (pEndpoint->service_id == WMI_CONTROL_SVC) {
1298 					htc_credit_record(HTC_REQUEST_CREDIT,
1299 							  pEndpoint->TxCredits,
1300 							  HTC_PACKET_QUEUE_DEPTH
1301 							  (tx_queue));
1302 					hif_latency_detect_credit_record_time(
1303 						HIF_REQUEST_CREDIT,
1304 						target->hif_dev);
1305 				}
1306 				INC_HTC_EP_STAT(pEndpoint,
1307 						TxCreditLowIndications, 1);
1308 #if DEBUG_CREDIT
1309 				AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
1310 						(" EP%d Needs Credits\n",
1311 						 pEndpoint->Id));
1312 #endif
1313 			}
1314 		}
1315 
1316 		/* now we can fully dequeue */
1317 		pPacket = htc_packet_dequeue(tx_queue);
1318 		if (pPacket) {
1319 			/* save the number of credits this packet consumed */
1320 			pPacket->PktInfo.AsTx.CreditsUsed = creditsRequired;
1321 			/* save send flags */
1322 			pPacket->PktInfo.AsTx.SendFlags = sendFlags;
1323 
1324 			/* queue this packet into the caller's queue */
1325 			HTC_PACKET_ENQUEUE(pQueue, pPacket);
1326 		}
1327 	}
1328 
1329 	if (!HTC_QUEUE_EMPTY(&pm_queue))
1330 		queue_htc_pm_packets(pEndpoint, &pm_queue);
1331 
1332 	AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
1333 			("-get_htc_send_packets_credit_based\n"));
1334 
1335 }
1336 
get_htc_send_packets(HTC_TARGET * target,HTC_ENDPOINT * pEndpoint,HTC_PACKET_QUEUE * pQueue,int Resources)1337 static void get_htc_send_packets(HTC_TARGET *target,
1338 				 HTC_ENDPOINT *pEndpoint,
1339 				 HTC_PACKET_QUEUE *pQueue, int Resources)
1340 {
1341 
1342 	HTC_PACKET *pPacket;
1343 	HTC_PACKET_QUEUE *tx_queue;
1344 	HTC_PACKET_QUEUE pm_queue;
1345 	bool do_pm_get = false;
1346 	unsigned int rtpm_code = 0;
1347 	int ret;
1348 
1349 	/*** NOTE : the TX lock is held when this function is called ***/
1350 	AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
1351 			("+get_htc_send_packets %d resources\n", Resources));
1352 
1353 	INIT_HTC_PACKET_QUEUE(&pm_queue);
1354 	extract_htc_pm_packets(pEndpoint, &pm_queue);
1355 	if (HTC_QUEUE_EMPTY(&pm_queue)) {
1356 		tx_queue = &pEndpoint->TxQueue;
1357 		do_pm_get = true;
1358 	} else {
1359 		tx_queue = &pm_queue;
1360 	}
1361 
1362 	/* loop until we can grab as many packets out of the queue as we can */
1363 	while (Resources > 0) {
1364 		int num_frags;
1365 
1366 		if (do_pm_get) {
1367 			rtpm_code =
1368 				htc_send_pkts_get_rtpm_id(
1369 							pEndpoint->service_id);
1370 			ret = hif_rtpm_get(HIF_RTPM_GET_ASYNC, rtpm_code);
1371 			if (ret) {
1372 				/* bus suspended, runtime resume issued */
1373 				QDF_ASSERT(HTC_PACKET_QUEUE_DEPTH(pQueue) == 0);
1374 				pPacket = htc_get_pkt_at_head(tx_queue);
1375 				if (!pPacket ||
1376 				    (pPacket->Endpoint >= ENDPOINT_MAX) ||
1377 				    (pPacket->Endpoint <= ENDPOINT_UNUSED))
1378 					break;
1379 				log_packet_info(target, pPacket);
1380 				break;
1381 			}
1382 			htc_inc_wmi_runtime_cnt(target, rtpm_code);
1383 
1384 		}
1385 
1386 		ret = hif_system_pm_state_check(target->hif_dev);
1387 		if (ret) {
1388 			if (do_pm_get) {
1389 				hif_rtpm_put(HIF_RTPM_PUT_ASYNC, rtpm_code);
1390 				htc_dec_wmi_runtime_cnt(target, rtpm_code);
1391 			}
1392 			break;
1393 		}
1394 
1395 		pPacket = htc_packet_dequeue(tx_queue);
1396 		if (!pPacket) {
1397 			if (do_pm_get) {
1398 				hif_rtpm_put(HIF_RTPM_PUT_ASYNC, rtpm_code);
1399 				htc_dec_wmi_runtime_cnt(target, rtpm_code);
1400 			}
1401 			break;
1402 		}
1403 
1404 		AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
1405 				(" Got packet:%pK , New Queue Depth: %d\n",
1406 				 pPacket,
1407 				 HTC_PACKET_QUEUE_DEPTH(tx_queue)));
1408 		/* For non-credit path the sequence number is already embedded
1409 		 * in the constructed HTC header
1410 		 */
1411 		pPacket->PktInfo.AsTx.SendFlags = 0;
1412 		pPacket->PktInfo.AsTx.CreditsUsed = 0;
1413 		/* queue this packet into the caller's queue */
1414 		HTC_PACKET_ENQUEUE(pQueue, pPacket);
1415 
1416 		/*
1417 		 * FIX THIS:
1418 		 * For now, avoid calling qdf_nbuf_get_num_frags before calling
1419 		 * qdf_nbuf_map, because the MacOS version of qdf_nbuf_t doesn't
1420 		 * support qdf_nbuf_get_num_frags until after qdf_nbuf_map has
1421 		 * been done.
1422 		 * Assume that the non-data netbufs, i.e. WMI message netbufs,
1423 		 * consist of a single fragment.
1424 		 */
1425 		/* WMI messages are in a single-fragment network buf */
1426 		num_frags =
1427 			(pPacket->PktInfo.AsTx.
1428 			 Flags & HTC_TX_PACKET_FLAG_FIXUP_NETBUF) ? 1 :
1429 			qdf_nbuf_get_num_frags(GET_HTC_PACKET_NET_BUF_CONTEXT
1430 						       (pPacket));
1431 		Resources -= num_frags;
1432 	}
1433 
1434 	if (!HTC_QUEUE_EMPTY(&pm_queue))
1435 		queue_htc_pm_packets(pEndpoint, &pm_queue);
1436 
1437 	AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-get_htc_send_packets\n"));
1438 
1439 }
1440 
1441 /**
1442  * htc_try_send() - Send packets in a queue on an endpoint
1443  * @target: HTC target on which packets need to be sent
1444  * @pEndpoint: logical endpoint on which packets needs to be sent
1445  * @pCallersSendQueue: packet queue containing the list of packets to be sent
1446  *
1447  * Return: enum HTC_SEND_QUEUE_RESULT indicates whether the packet was queued to
1448  *         be sent or the packet should be dropped by the upper layer
1449  */
htc_try_send(HTC_TARGET * target,HTC_ENDPOINT * pEndpoint,HTC_PACKET_QUEUE * pCallersSendQueue)1450 static enum HTC_SEND_QUEUE_RESULT htc_try_send(HTC_TARGET *target,
1451 					  HTC_ENDPOINT *pEndpoint,
1452 					  HTC_PACKET_QUEUE *pCallersSendQueue)
1453 {
1454 	/* temp queue to hold packets at various stages */
1455 	HTC_PACKET_QUEUE sendQueue;
1456 	HTC_PACKET *pPacket;
1457 	int tx_resources;
1458 	int overflow;
1459 	enum HTC_SEND_QUEUE_RESULT result = HTC_SEND_QUEUE_OK;
1460 	QDF_STATUS status;
1461 
1462 	AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("+htc_try_send (Queue:%pK Depth:%d)\n",
1463 					 pCallersSendQueue,
1464 					 (pCallersSendQueue ==
1465 					  NULL) ? 0 :
1466 					 HTC_PACKET_QUEUE_DEPTH
1467 						 (pCallersSendQueue)));
1468 
1469 	/* init the local send queue */
1470 	INIT_HTC_PACKET_QUEUE(&sendQueue);
1471 
1472 	do {
1473 
1474 		/* caller didn't provide a queue, just wants us to check
1475 		 * queues and send
1476 		 */
1477 		if (!pCallersSendQueue)
1478 			break;
1479 
1480 		if (HTC_QUEUE_EMPTY(pCallersSendQueue)) {
1481 			/* empty queue */
1482 			OL_ATH_HTC_PKT_ERROR_COUNT_INCR(target,
1483 							HTC_PKT_Q_EMPTY);
1484 			result = HTC_SEND_QUEUE_DROP;
1485 			break;
1486 		}
1487 
1488 		if (HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue) >=
1489 		    pEndpoint->MaxTxQueueDepth) {
1490 			/* we've already overflowed */
1491 			overflow = HTC_PACKET_QUEUE_DEPTH(pCallersSendQueue);
1492 		} else {
1493 			/* figure out how much we will overflow by */
1494 			overflow = HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue);
1495 			overflow += HTC_PACKET_QUEUE_DEPTH(pCallersSendQueue);
1496 			/* get how much we will overflow the TX queue by */
1497 			overflow -= pEndpoint->MaxTxQueueDepth;
1498 		}
1499 
1500 		/* if overflow is negative or zero, we are okay */
1501 		if (overflow > 0) {
1502 			AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
1503 					("Endpoint %d, TX queue will overflow :%d , Tx Depth:%d, Max:%d\n",
1504 					 pEndpoint->Id, overflow,
1505 					 HTC_PACKET_QUEUE_DEPTH(&pEndpoint->
1506 								TxQueue),
1507 					 pEndpoint->MaxTxQueueDepth));
1508 		}
1509 		if ((overflow <= 0)
1510 		    || (!pEndpoint->EpCallBacks.EpSendFull)) {
1511 			/* all packets will fit or caller did not provide send
1512 			 * full indication handler
1513 			 * just move all of them to local sendQueue object
1514 			 */
1515 			HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(&sendQueue,
1516 							  pCallersSendQueue);
1517 		} else {
1518 			int i;
1519 			int goodPkts =
1520 				HTC_PACKET_QUEUE_DEPTH(pCallersSendQueue) -
1521 				overflow;
1522 
1523 			A_ASSERT(goodPkts >= 0);
1524 			/* we have overflowed and callback is provided. Dequeue
1525 			 * all non-overflow packets into the sendqueue
1526 			 */
1527 			for (i = 0; i < goodPkts; i++) {
1528 				/* pop off caller's queue */
1529 				pPacket = htc_packet_dequeue(pCallersSendQueue);
1530 				A_ASSERT(pPacket);
1531 				if (pPacket)
1532 					/* insert into local queue */
1533 					HTC_PACKET_ENQUEUE(&sendQueue,
1534 							   pPacket);
1535 			}
1536 
1537 			/* the caller's queue has all the packets that won't fit
1538 			 * walk through the caller's queue and indicate each one
1539 			 * to the send full handler
1540 			 */
1541 			ITERATE_OVER_LIST_ALLOW_REMOVE(&pCallersSendQueue->
1542 						       QueueHead, pPacket,
1543 						       HTC_PACKET, ListLink) {
1544 
1545 				AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
1546 						("Indicating overflowed TX packet: %pK\n",
1547 						 pPacket));
1548 				/*
1549 				 * Remove headroom reserved for HTC_FRAME_HDR
1550 				 * before giving the packet back to the user via
1551 				 * the EpSendFull callback.
1552 				 */
1553 				qdf_nbuf_pull_head
1554 					(GET_HTC_PACKET_NET_BUF_CONTEXT
1555 						(pPacket),
1556 					sizeof(HTC_FRAME_HDR));
1557 				pPacket->PktInfo.AsTx.Flags &=
1558 					~HTC_TX_PACKET_FLAG_HTC_HEADER_IN_NETBUF_DATA;
1559 
1560 				if (pEndpoint->EpCallBacks.
1561 				    EpSendFull(pEndpoint->EpCallBacks.pContext,
1562 					       pPacket) == HTC_SEND_FULL_DROP) {
1563 					/* callback wants the packet dropped */
1564 					INC_HTC_EP_STAT(pEndpoint, TxDropped,
1565 							1);
1566 					/* leave this one in the caller's queue
1567 					 * for cleanup
1568 					 */
1569 				} else {
1570 					/* callback wants to keep this packet,
1571 					 * remove from caller's queue
1572 					 */
1573 					HTC_PACKET_REMOVE(pCallersSendQueue,
1574 							  pPacket);
1575 					/* put it in the send queue
1576 					 * add HTC_FRAME_HDR space reservation
1577 					 * again
1578 					 */
1579 					qdf_nbuf_push_head
1580 						(GET_HTC_PACKET_NET_BUF_CONTEXT
1581 							(pPacket),
1582 						sizeof(HTC_FRAME_HDR));
1583 					pPacket->PktInfo.AsTx.Flags |=
1584 						HTC_TX_PACKET_FLAG_HTC_HEADER_IN_NETBUF_DATA;
1585 
1586 					HTC_PACKET_ENQUEUE(&sendQueue, pPacket);
1587 				}
1588 
1589 			}
1590 			ITERATE_END;
1591 
1592 			if (HTC_QUEUE_EMPTY(&sendQueue)) {
1593 				/* no packets made it in, caller will cleanup */
1594 				OL_ATH_HTC_PKT_ERROR_COUNT_INCR(target,
1595 							HTC_SEND_Q_EMPTY);
1596 				result = HTC_SEND_QUEUE_DROP;
1597 				break;
1598 			}
1599 		}
1600 
1601 	} while (false);
1602 
1603 	if (result != HTC_SEND_QUEUE_OK) {
1604 		AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-htc_try_send: %d\n",
1605 			result));
1606 		return result;
1607 	}
1608 
1609 	LOCK_HTC_TX(target);
1610 
1611 	if (!HTC_QUEUE_EMPTY(&sendQueue)) {
1612 		if (target->is_nodrop_pkt) {
1613 			/*
1614 			 * nodrop pkts have higher priority than normal pkts,
1615 			 * insert nodrop pkt to head for proper
1616 			 * start/termination of test.
1617 			 */
1618 			HTC_PACKET_QUEUE_TRANSFER_TO_HEAD(&pEndpoint->TxQueue,
1619 					&sendQueue);
1620 			target->is_nodrop_pkt = false;
1621 		} else {
1622 			/* transfer packets to tail */
1623 			HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(&pEndpoint->TxQueue,
1624 					&sendQueue);
1625 			A_ASSERT(HTC_QUEUE_EMPTY(&sendQueue));
1626 			INIT_HTC_PACKET_QUEUE(&sendQueue);
1627 		}
1628 	}
1629 
1630 	/* increment tx processing count on entry */
1631 	if (qdf_atomic_inc_return(&pEndpoint->TxProcessCount) > 1) {
1632 		/* another thread or task is draining the TX queues on this
1633 		 * endpoint that thread will reset the tx processing count when
1634 		 * the queue is drained
1635 		 */
1636 		qdf_atomic_dec(&pEndpoint->TxProcessCount);
1637 		UNLOCK_HTC_TX(target);
1638 		AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-htc_try_send (busy)\n"));
1639 		return HTC_SEND_QUEUE_OK;
1640 	}
1641 
1642 	/***** beyond this point only 1 thread may enter ******/
1643 
1644 	/* now drain the endpoint TX queue for transmission as long as we have
1645 	 * enough transmit resources
1646 	 */
1647 	if (!IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)) {
1648 		tx_resources =
1649 			hif_get_free_queue_number(target->hif_dev,
1650 						  pEndpoint->UL_PipeID);
1651 	} else {
1652 		tx_resources = 0;
1653 	}
1654 
1655 	while (true) {
1656 
1657 		if (HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue) == 0)
1658 			break;
1659 
1660 		if (pEndpoint->async_update &&
1661 			(!IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)) &&
1662 			(!tx_resources)) {
1663 			hif_schedule_ce_tasklet(target->hif_dev,
1664 						pEndpoint->UL_PipeID);
1665 			break;
1666 		}
1667 
1668 		if (IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)) {
1669 #if DEBUG_CREDIT
1670 			int cred = pEndpoint->TxCredits;
1671 #endif
1672 			/* credit based mechanism provides flow control based on
1673 			 * target transmit resource availability, we assume that
1674 			 * the HIF layer will always have bus resources greater
1675 			 * than target transmit resources
1676 			 */
1677 			get_htc_send_packets_credit_based(target, pEndpoint,
1678 							  &sendQueue);
1679 #if DEBUG_CREDIT
1680 			if (ep_debug_mask & (1 << pEndpoint->Id)) {
1681 				if (cred - pEndpoint->TxCredits > 0) {
1682 					AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
1683 						(" <HTC> Decrease EP%d %d - %d = %d credits.\n",
1684 							 pEndpoint->Id, cred,
1685 							 cred -
1686 							 pEndpoint->TxCredits,
1687 							 pEndpoint->TxCredits));
1688 				}
1689 			}
1690 #endif
1691 		} else {
1692 
1693 		/*
1694 		* Header and payload belongs to the different fragments and
1695 		* consume 2 resource for one HTC package but USB combine into
1696 		* one transfer.And one WMI message only consumes one single
1697 		* resource.
1698 		*/
1699 			if (HTC_TX_BUNDLE_ENABLED(target) && tx_resources &&
1700 				hif_get_bus_type(target->hif_dev) ==
1701 						QDF_BUS_TYPE_USB) {
1702 				if (pEndpoint->service_id ==
1703 					WMI_CONTROL_SVC)
1704 					tx_resources =
1705 					    HTC_MAX_MSG_PER_BUNDLE_TX;
1706 				else
1707 					tx_resources =
1708 					    (HTC_MAX_MSG_PER_BUNDLE_TX * 2);
1709 			}
1710 			/* get all the packets for this endpoint that we can for
1711 			 * this pass
1712 			 */
1713 			get_htc_send_packets(target, pEndpoint, &sendQueue,
1714 					     tx_resources);
1715 		}
1716 
1717 		if (HTC_PACKET_QUEUE_DEPTH(&sendQueue) == 0) {
1718 			/* didn't get any packets due to a lack of resources or
1719 			 * TX queue was drained
1720 			 */
1721 			break;
1722 		}
1723 
1724 		if (!pEndpoint->async_update)
1725 			UNLOCK_HTC_TX(target);
1726 
1727 		/* send what we can */
1728 		status = htc_issue_packets(target, pEndpoint, &sendQueue);
1729 		if (status) {
1730 			int i;
1731 			unsigned int rtpm_code;
1732 
1733 			result = HTC_SEND_QUEUE_DROP;
1734 
1735 			switch (status) {
1736 			case  QDF_STATUS_E_RESOURCES:
1737 				if (pEndpoint->num_requeues_warn <= MAX_REQUEUE_WARN) {
1738 					pEndpoint->num_requeues_warn++;
1739 					pEndpoint->total_num_requeues++;
1740 					break;
1741 				} else {
1742 					pEndpoint->total_num_requeues++;
1743 					pEndpoint->num_requeues_warn = 0;
1744 				}
1745 				fallthrough;
1746 			default:
1747 				QDF_TRACE(QDF_MODULE_ID_HIF, QDF_TRACE_LEVEL_INFO,
1748 					  "htc_issue_packets, failed status:%d"
1749 					  "endpoint:%d, put it back to head of"
1750 					  "callersSendQueue", result, pEndpoint->Id);
1751 				break;
1752 			}
1753 
1754 			rtpm_code = htc_send_pkts_get_rtpm_id(
1755 							pEndpoint->service_id);
1756 			for (i = HTC_PACKET_QUEUE_DEPTH(&sendQueue); i > 0; i--) {
1757 				hif_rtpm_put(HIF_RTPM_PUT_ASYNC, rtpm_code);
1758 				htc_dec_wmi_runtime_cnt(target, rtpm_code);
1759 			}
1760 
1761 			if (!pEndpoint->async_update) {
1762 				LOCK_HTC_TX(target);
1763 			}
1764 			HTC_PACKET_QUEUE_TRANSFER_TO_HEAD(&pEndpoint->TxQueue,
1765 							  &sendQueue);
1766 			break;
1767 		}  else {
1768 			if (pEndpoint->num_requeues_warn)
1769 				pEndpoint->num_requeues_warn = 0;
1770 		}
1771 
1772 		if (!IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)) {
1773 			tx_resources =
1774 				hif_get_free_queue_number(target->hif_dev,
1775 							  pEndpoint->UL_PipeID);
1776 		}
1777 
1778 		if (!pEndpoint->async_update) {
1779 			LOCK_HTC_TX(target);
1780 		}
1781 
1782 	}
1783 
1784 	/* done with this endpoint, we can clear the count */
1785 	qdf_atomic_init(&pEndpoint->TxProcessCount);
1786 
1787 	UNLOCK_HTC_TX(target);
1788 
1789 	AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-htc_try_send:\n"));
1790 
1791 	return HTC_SEND_QUEUE_OK;
1792 }
1793 
1794 #ifdef USB_HIF_SINGLE_PIPE_DATA_SCHED
htc_send_pkts_sched_check(HTC_HANDLE HTCHandle,HTC_ENDPOINT_ID id)1795 static uint16_t htc_send_pkts_sched_check(HTC_HANDLE HTCHandle,
1796 					  HTC_ENDPOINT_ID id)
1797 {
1798 	HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
1799 	HTC_ENDPOINT *pEndpoint;
1800 	HTC_ENDPOINT_ID eid;
1801 	HTC_PACKET_QUEUE *pTxQueue;
1802 	uint16_t resources;
1803 	uint16_t acQueueStatus[DATA_EP_SIZE] = { 0, 0, 0, 0 };
1804 
1805 	if (id < ENDPOINT_2 || id > ENDPOINT_5)
1806 		return 1;
1807 
1808 	for (eid = ENDPOINT_2; eid <= ENDPOINT_5; eid++) {
1809 		pEndpoint = &target->endpoint[eid];
1810 		pTxQueue = &pEndpoint->TxQueue;
1811 
1812 		if (HTC_QUEUE_EMPTY(pTxQueue))
1813 			acQueueStatus[eid - 2] = 1;
1814 	}
1815 
1816 	switch (id) {
1817 	case ENDPOINT_2:        /* BE */
1818 		return acQueueStatus[0] && acQueueStatus[2]
1819 			&& acQueueStatus[3];
1820 	case ENDPOINT_3:        /* BK */
1821 		return acQueueStatus[0] && acQueueStatus[1] && acQueueStatus[2]
1822 			&& acQueueStatus[3];
1823 	case ENDPOINT_4:        /* VI */
1824 		return acQueueStatus[2] && acQueueStatus[3];
1825 	case ENDPOINT_5:        /* VO */
1826 		return acQueueStatus[3];
1827 	default:
1828 		return 0;
1829 	}
1830 
1831 }
1832 
htc_send_pkts_sched_queue(HTC_TARGET * target,HTC_PACKET_QUEUE * pPktQueue,HTC_ENDPOINT_ID eid)1833 static A_STATUS htc_send_pkts_sched_queue(HTC_TARGET *target,
1834 					  HTC_PACKET_QUEUE *pPktQueue,
1835 					  HTC_ENDPOINT_ID eid)
1836 {
1837 	HTC_ENDPOINT *pEndpoint;
1838 	HTC_PACKET_QUEUE *pTxQueue;
1839 	HTC_PACKET *pPacket;
1840 	int goodPkts;
1841 
1842 	pEndpoint = &target->endpoint[eid];
1843 	pTxQueue = &pEndpoint->TxQueue;
1844 
1845 	LOCK_HTC_TX(target);
1846 
1847 	goodPkts =
1848 		pEndpoint->MaxTxQueueDepth -
1849 		HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue);
1850 
1851 	if (goodPkts > 0) {
1852 		while (!HTC_QUEUE_EMPTY(pPktQueue)) {
1853 			pPacket = htc_packet_dequeue(pPktQueue);
1854 			HTC_PACKET_ENQUEUE(pTxQueue, pPacket);
1855 			goodPkts--;
1856 
1857 			if (goodPkts <= 0)
1858 				break;
1859 		}
1860 	}
1861 
1862 	if (HTC_PACKET_QUEUE_DEPTH(pPktQueue)) {
1863 		ITERATE_OVER_LIST_ALLOW_REMOVE(&pPktQueue->QueueHead, pPacket,
1864 					       HTC_PACKET, ListLink) {
1865 
1866 			if (pEndpoint->EpCallBacks.
1867 			    EpSendFull(pEndpoint->EpCallBacks.pContext,
1868 				       pPacket) == HTC_SEND_FULL_DROP) {
1869 				INC_HTC_EP_STAT(pEndpoint, TxDropped, 1);
1870 			} else {
1871 				HTC_PACKET_REMOVE(pPktQueue, pPacket);
1872 				HTC_PACKET_ENQUEUE(pTxQueue, pPacket);
1873 			}
1874 		}
1875 		ITERATE_END;
1876 	}
1877 
1878 	UNLOCK_HTC_TX(target);
1879 
1880 	return A_OK;
1881 }
1882 
1883 #endif
1884 
__htc_send_pkt(HTC_HANDLE HTCHandle,HTC_PACKET * pPacket)1885 static inline QDF_STATUS __htc_send_pkt(HTC_HANDLE HTCHandle,
1886 				HTC_PACKET *pPacket)
1887 {
1888 	HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
1889 	HTC_ENDPOINT *pEndpoint;
1890 	HTC_PACKET_QUEUE pPktQueue;
1891 	qdf_nbuf_t netbuf;
1892 	HTC_FRAME_HDR *htc_hdr;
1893 	QDF_STATUS status;
1894 
1895 	AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
1896 			("+__htc_send_pkt\n"));
1897 
1898 	/* get packet at head to figure out which endpoint these packets will
1899 	 * go into
1900 	 */
1901 	if (!pPacket) {
1902 		OL_ATH_HTC_PKT_ERROR_COUNT_INCR(target, GET_HTC_PKT_Q_FAIL);
1903 		AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-__htc_send_pkt\n"));
1904 		return QDF_STATUS_E_INVAL;
1905 	}
1906 
1907 	if ((pPacket->Endpoint >= ENDPOINT_MAX) ||
1908 	    (pPacket->Endpoint <= ENDPOINT_UNUSED)) {
1909 		AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
1910 			("%s endpoint is invalid\n", __func__));
1911 		AR_DEBUG_ASSERT(0);
1912 		return QDF_STATUS_E_INVAL;
1913 	}
1914 	pEndpoint = &target->endpoint[pPacket->Endpoint];
1915 
1916 	if (!pEndpoint->service_id) {
1917 		AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("%s service_id is invalid\n",
1918 								__func__));
1919 		return QDF_STATUS_E_INVAL;
1920 	}
1921 
1922 #ifdef HTC_EP_STAT_PROFILING
1923 	LOCK_HTC_TX(target);
1924 	INC_HTC_EP_STAT(pEndpoint, TxPosted, 1);
1925 	UNLOCK_HTC_TX(target);
1926 #endif
1927 
1928 	/* provide room in each packet's netbuf for the HTC frame header */
1929 	netbuf = GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket);
1930 	AR_DEBUG_ASSERT(netbuf);
1931 	if (!netbuf)
1932 		return QDF_STATUS_E_INVAL;
1933 
1934 	qdf_nbuf_push_head(netbuf, sizeof(HTC_FRAME_HDR));
1935 	pPacket->PktInfo.AsTx.Flags |=
1936 		HTC_TX_PACKET_FLAG_HTC_HEADER_IN_NETBUF_DATA;
1937 	/* setup HTC frame header */
1938 	htc_hdr = (HTC_FRAME_HDR *)qdf_nbuf_get_frag_vaddr(netbuf, 0);
1939 	AR_DEBUG_ASSERT(htc_hdr);
1940 	if (!htc_hdr)
1941 		return QDF_STATUS_E_INVAL;
1942 
1943 	HTC_WRITE32(htc_hdr,
1944 		    SM(pPacket->ActualLength,
1945 		       HTC_FRAME_HDR_PAYLOADLEN) |
1946 		    SM(pPacket->Endpoint,
1947 		       HTC_FRAME_HDR_ENDPOINTID));
1948 	LOCK_HTC_TX(target);
1949 
1950 	pPacket->PktInfo.AsTx.SeqNo = pEndpoint->SeqNo;
1951 	pEndpoint->SeqNo++;
1952 
1953 	HTC_WRITE32(((uint32_t *)htc_hdr) + 1,
1954 		    SM(pPacket->PktInfo.AsTx.SeqNo,
1955 		       HTC_FRAME_HDR_CONTROLBYTES1));
1956 
1957 	UNLOCK_HTC_TX(target);
1958 
1959 	/*
1960 	 * For flow control enabled endpoints mapping is done in
1961 	 * htc_issue_packets and for non flow control enabled endpoints
1962 	 * its done here.
1963 	 */
1964 	if (!IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)) {
1965 		pPacket->PktInfo.AsTx.Flags |= HTC_TX_PACKET_FLAG_FIXUP_NETBUF;
1966 		status = qdf_nbuf_map(target->osdev,
1967 				      GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket),
1968 				      QDF_DMA_TO_DEVICE);
1969 		if (status == QDF_STATUS_SUCCESS) {
1970 			target->nbuf_nfc_map_count++;
1971 		} else {
1972 			AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
1973 					("%s: nbuf map failed, endpoint %pK, seq_no. %d\n",
1974 					 __func__, pEndpoint, pEndpoint->SeqNo));
1975 			return status;
1976 		}
1977 	}
1978 
1979 	INIT_HTC_PACKET_QUEUE_AND_ADD(&pPktQueue, pPacket);
1980 #ifdef USB_HIF_SINGLE_PIPE_DATA_SCHED
1981 	if (!htc_send_pkts_sched_check(HTCHandle, pEndpoint->Id))
1982 		htc_send_pkts_sched_queue(HTCHandle, &pPktQueue, pEndpoint->Id);
1983 	else
1984 		htc_try_send(target, pEndpoint, &pPktQueue);
1985 #else
1986 	htc_try_send(target, pEndpoint, &pPktQueue);
1987 #endif
1988 
1989 	/* do completion on any packets that couldn't get in */
1990 	while (!HTC_QUEUE_EMPTY(&pPktQueue)) {
1991 		pPacket = htc_packet_dequeue(&pPktQueue);
1992 
1993 		if (HTC_STOPPING(target))
1994 			pPacket->Status = QDF_STATUS_E_CANCELED;
1995 		else
1996 			pPacket->Status = QDF_STATUS_E_RESOURCES;
1997 
1998 		send_packet_completion(target, pPacket);
1999 	}
2000 
2001 	AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-__htc_send_pkt\n"));
2002 
2003 	return QDF_STATUS_SUCCESS;
2004 }
2005 
2006 #ifdef CUSTOM_CB_SCHEDULER_SUPPORT
2007 /**
2008  * htc_get_endpoint_ul_pipeid() - Helper API to get uplink pipe ID
2009  * @htc_handle: HTC handle
2010  * @endpoint_id: Endpoint ID
2011  * @ul_pipeid: Pointer to uplink pipe ID
2012  *
2013  * return: QDF_STATUS
2014  */
2015 static QDF_STATUS
htc_get_endpoint_ul_pipeid(HTC_HANDLE htc_handle,HTC_ENDPOINT_ID endpoint_id,uint8_t * ul_pipeid)2016 htc_get_endpoint_ul_pipeid(HTC_HANDLE htc_handle, HTC_ENDPOINT_ID endpoint_id,
2017 			   uint8_t *ul_pipeid)
2018 {
2019 	HTC_TARGET *target;
2020 	HTC_ENDPOINT *end_point;
2021 
2022 	if (!htc_handle) {
2023 		AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
2024 				("%s: HTCHandle is NULL\n", __func__));
2025 		return QDF_STATUS_E_NULL_VALUE;
2026 	}
2027 	target = GET_HTC_TARGET_FROM_HANDLE(htc_handle);
2028 
2029 	if (endpoint_id >= ENDPOINT_MAX || endpoint_id <= ENDPOINT_UNUSED) {
2030 		AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
2031 				("%s endpoint is invalid\n", __func__));
2032 		AR_DEBUG_ASSERT(0);
2033 		return QDF_STATUS_E_INVAL;
2034 	}
2035 	end_point = &target->endpoint[endpoint_id];
2036 
2037 	if (!end_point->service_id) {
2038 		AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("%s service_id is invalid\n",
2039 						 __func__));
2040 		return QDF_STATUS_E_INVAL;
2041 	}
2042 
2043 	*ul_pipeid = end_point->UL_PipeID;
2044 
2045 	return QDF_STATUS_SUCCESS;
2046 }
2047 
2048 QDF_STATUS
htc_register_custom_cb(HTC_HANDLE htc_handle,HTC_ENDPOINT_ID endpoint_id,void (* custom_cb)(void *),void * custom_cb_context)2049 htc_register_custom_cb(HTC_HANDLE htc_handle, HTC_ENDPOINT_ID endpoint_id,
2050 		       void (*custom_cb)(void *), void *custom_cb_context)
2051 {
2052 	QDF_STATUS status = QDF_STATUS_SUCCESS;
2053 	uint8_t ul_pipeid;
2054 
2055 	AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("+%s\n", __func__));
2056 
2057 	status = htc_get_endpoint_ul_pipeid(htc_handle, endpoint_id,
2058 					    &ul_pipeid);
2059 	if (QDF_IS_STATUS_ERROR(status)) {
2060 		AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("%s Failed to get ul pipeid\n",
2061 						 __func__));
2062 		goto exit;
2063 	}
2064 
2065 	status = hif_register_ce_custom_cb(htc_get_hif_device(htc_handle),
2066 					   ul_pipeid, custom_cb,
2067 					   custom_cb_context);
2068 	if (QDF_IS_STATUS_ERROR(status)) {
2069 		AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("%s Failed to register cb\n",
2070 						 __func__));
2071 		goto exit;
2072 	}
2073 
2074 exit:
2075 	AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-%s\n", __func__));
2076 
2077 	return status;
2078 }
2079 
2080 QDF_STATUS
htc_unregister_custom_cb(HTC_HANDLE htc_handle,HTC_ENDPOINT_ID endpoint_id)2081 htc_unregister_custom_cb(HTC_HANDLE htc_handle, HTC_ENDPOINT_ID endpoint_id)
2082 {
2083 	QDF_STATUS status = QDF_STATUS_SUCCESS;
2084 	uint8_t ul_pipeid;
2085 
2086 	AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("+%s\n", __func__));
2087 
2088 	status = htc_get_endpoint_ul_pipeid(htc_handle, endpoint_id,
2089 					    &ul_pipeid);
2090 	if (QDF_IS_STATUS_ERROR(status)) {
2091 		AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("%s Failed to get ul pipeid\n",
2092 						 __func__));
2093 		goto exit;
2094 	}
2095 
2096 	status = hif_unregister_ce_custom_cb(htc_get_hif_device(htc_handle),
2097 					     ul_pipeid);
2098 	if (QDF_IS_STATUS_ERROR(status)) {
2099 		AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("%s Failed to unregister cb\n",
2100 						 __func__));
2101 		status = QDF_STATUS_E_INVAL;
2102 		goto exit;
2103 	}
2104 
2105 exit:
2106 	AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-%s\n", __func__));
2107 
2108 	return status;
2109 }
2110 
2111 QDF_STATUS
htc_enable_custom_cb(HTC_HANDLE htc_handle,HTC_ENDPOINT_ID endpoint_id)2112 htc_enable_custom_cb(HTC_HANDLE htc_handle, HTC_ENDPOINT_ID endpoint_id)
2113 {
2114 	QDF_STATUS status = QDF_STATUS_SUCCESS;
2115 	uint8_t ul_pipeid;
2116 
2117 	AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("+%s\n", __func__));
2118 
2119 	status = htc_get_endpoint_ul_pipeid(htc_handle, endpoint_id,
2120 					    &ul_pipeid);
2121 	if (QDF_IS_STATUS_ERROR(status)) {
2122 		AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("%s Failed to get ul pipeid\n",
2123 						 __func__));
2124 		goto exit;
2125 	}
2126 
2127 	status = hif_enable_ce_custom_cb(htc_get_hif_device(htc_handle),
2128 					 ul_pipeid);
2129 	if (QDF_IS_STATUS_ERROR(status)) {
2130 		AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("%s Failed to enable cb\n",
2131 						 __func__));
2132 		status = QDF_STATUS_E_INVAL;
2133 		goto exit;
2134 	}
2135 
2136 exit:
2137 	AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-%s\n", __func__));
2138 
2139 	return status;
2140 }
2141 
2142 QDF_STATUS
htc_disable_custom_cb(HTC_HANDLE htc_handle,HTC_ENDPOINT_ID endpoint_id)2143 htc_disable_custom_cb(HTC_HANDLE htc_handle, HTC_ENDPOINT_ID endpoint_id)
2144 {
2145 	QDF_STATUS status = QDF_STATUS_SUCCESS;
2146 	uint8_t ul_pipeid;
2147 
2148 	AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("+%s\n", __func__));
2149 
2150 	status = htc_get_endpoint_ul_pipeid(htc_handle, endpoint_id,
2151 					    &ul_pipeid);
2152 	if (QDF_IS_STATUS_ERROR(status)) {
2153 		AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("%s Failed to get ul pipeid\n",
2154 						 __func__));
2155 		goto exit;
2156 	}
2157 
2158 	status = hif_disable_ce_custom_cb(htc_get_hif_device(htc_handle),
2159 					  ul_pipeid);
2160 	if (QDF_IS_STATUS_ERROR(status)) {
2161 		AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("%s Failed to disable cb\n",
2162 						 __func__));
2163 		status = QDF_STATUS_E_INVAL;
2164 		goto exit;
2165 	}
2166 
2167 exit:
2168 	AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-%s\n", __func__));
2169 
2170 	return status;
2171 }
2172 #endif /* CUSTOM_CB_SCHEDULER_SUPPORT */
2173 
2174 /* HTC API - htc_send_pkt */
htc_send_pkt(HTC_HANDLE htc_handle,HTC_PACKET * htc_packet)2175 QDF_STATUS htc_send_pkt(HTC_HANDLE htc_handle, HTC_PACKET *htc_packet)
2176 {
2177 	if (!htc_handle) {
2178 		AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
2179 				("%s: HTCHandle is NULL \n", __func__));
2180 		return QDF_STATUS_E_FAILURE;
2181 	}
2182 
2183 	if (!htc_packet) {
2184 		AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
2185 				("%s: pPacket is NULL \n", __func__));
2186 		return QDF_STATUS_E_FAILURE;
2187 	}
2188 
2189 	AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
2190 			("+-htc_send_pkt: Enter endPointId: %d, buffer: %pK, length: %d\n",
2191 			 htc_packet->Endpoint, htc_packet->pBuffer,
2192 			 htc_packet->ActualLength));
2193 	return __htc_send_pkt(htc_handle, htc_packet);
2194 }
2195 qdf_export_symbol(htc_send_pkt);
2196 
2197 #ifdef ATH_11AC_TXCOMPACT
2198 /**
2199  * htc_send_data_pkt() - send single data packet on an endpoint
2200  * @htc_hdl: pointer to HTC handle
2201  * @netbuf: network buffer containing the data to be sent
2202  * @ep_id: endpoint identifier
2203  * @actual_length: length of data that needs to be transmitted
2204  *
2205  * Return: QDF_STATUS_SUCCESS for success or an appropriate QDF_STATUS error
2206  */
htc_send_data_pkt(HTC_HANDLE htc_hdl,qdf_nbuf_t netbuf,int ep_id,int actual_length)2207 QDF_STATUS htc_send_data_pkt(HTC_HANDLE htc_hdl, qdf_nbuf_t netbuf, int ep_id,
2208 			     int actual_length)
2209 {
2210 	HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(htc_hdl);
2211 	HTC_ENDPOINT *pEndpoint;
2212 	HTC_FRAME_HDR *p_htc_hdr;
2213 	QDF_STATUS status = QDF_STATUS_SUCCESS;
2214 	int tx_resources;
2215 	uint32_t data_attr = 0;
2216 	int htc_payload_len = actual_length;
2217 	unsigned int rtpm_code;
2218 
2219 	pEndpoint = &target->endpoint[ep_id];
2220 
2221 	tx_resources = hif_get_free_queue_number(target->hif_dev,
2222 						 pEndpoint->UL_PipeID);
2223 
2224 	if (tx_resources < HTC_DATA_RESOURCE_THRS) {
2225 		if (pEndpoint->ul_is_polled) {
2226 			hif_send_complete_check(pEndpoint->target->hif_dev,
2227 						pEndpoint->UL_PipeID, 1);
2228 			tx_resources =
2229 				hif_get_free_queue_number(target->hif_dev,
2230 							  pEndpoint->UL_PipeID);
2231 		}
2232 		if (tx_resources < HTC_DATA_MINDESC_PERPACKET)
2233 			return QDF_STATUS_E_FAILURE;
2234 	}
2235 
2236 	rtpm_code = htc_send_pkts_get_rtpm_id(
2237 					pEndpoint->service_id);
2238 	if (hif_rtpm_get(HIF_RTPM_GET_ASYNC, rtpm_code))
2239 		return QDF_STATUS_E_FAILURE;
2240 
2241 	p_htc_hdr = (HTC_FRAME_HDR *)qdf_nbuf_get_frag_vaddr(netbuf, 0);
2242 	AR_DEBUG_ASSERT(p_htc_hdr);
2243 
2244 	data_attr = qdf_nbuf_data_attr_get(netbuf);
2245 
2246 	if (target->htc_hdr_length_check)
2247 		htc_payload_len = actual_length - HTC_HEADER_LEN;
2248 
2249 	HTC_WRITE32(p_htc_hdr, SM(htc_payload_len, HTC_FRAME_HDR_PAYLOADLEN)
2250 		    | SM(ep_id, HTC_FRAME_HDR_ENDPOINTID));
2251 	/*
2252 	 * If the HIF pipe for the data endpoint is polled rather than
2253 	 * interrupt-driven, this is a good point to check whether any
2254 	 * data previously sent through the HIF pipe have finished being
2255 	 * sent.
2256 	 * Since this may result in callbacks to htc_tx_completion_handler,
2257 	 * which can take the HTC tx lock, make the hif_send_complete_check
2258 	 * call before acquiring the HTC tx lock.
2259 	 * Call hif_send_complete_check directly, rather than calling
2260 	 * htc_send_complete_check, and call the PollTimerStart separately
2261 	 * after calling hif_send_head, so the timer will be started to
2262 	 * check for completion of the new outstanding download (in the
2263 	 * unexpected event that other polling calls don't catch it).
2264 	 */
2265 
2266 	LOCK_HTC_TX(target);
2267 
2268 	HTC_WRITE32(((uint32_t *)p_htc_hdr) + 1,
2269 		    SM(pEndpoint->SeqNo, HTC_FRAME_HDR_CONTROLBYTES1));
2270 
2271 	pEndpoint->SeqNo++;
2272 
2273 	QDF_NBUF_UPDATE_TX_PKT_COUNT(netbuf, QDF_NBUF_TX_PKT_HTC);
2274 	DPTRACE(qdf_dp_trace(netbuf, QDF_DP_TRACE_HTC_PACKET_PTR_RECORD,
2275 		QDF_TRACE_DEFAULT_PDEV_ID, qdf_nbuf_data_addr(netbuf),
2276 		sizeof(qdf_nbuf_data(netbuf)), QDF_TX));
2277 	status = hif_send_head(target->hif_dev,
2278 			       pEndpoint->UL_PipeID,
2279 			       pEndpoint->Id, actual_length, netbuf, data_attr);
2280 
2281 	UNLOCK_HTC_TX(target);
2282 	return status;
2283 }
2284 #else                           /*ATH_11AC_TXCOMPACT */
2285 
2286 /**
2287  * htc_send_data_pkt() - htc_send_data_pkt
2288  * @HTCHandle: pointer to HTC handle
2289  * @pPacket: pointer to HTC_PACKET
2290  * @more_data: indicates whether more data is to follow
2291  *
2292  * Return: QDF_STATUS_SUCCESS for success or an appropriate QDF_STATUS error
2293  */
htc_send_data_pkt(HTC_HANDLE HTCHandle,HTC_PACKET * pPacket,uint8_t more_data)2294 QDF_STATUS htc_send_data_pkt(HTC_HANDLE HTCHandle, HTC_PACKET *pPacket,
2295 			   uint8_t more_data)
2296 {
2297 	HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
2298 	HTC_ENDPOINT *pEndpoint;
2299 	HTC_FRAME_HDR *pHtcHdr;
2300 	HTC_PACKET_QUEUE sendQueue;
2301 	qdf_nbuf_t netbuf = NULL;
2302 	int tx_resources;
2303 	QDF_STATUS status = QDF_STATUS_SUCCESS;
2304 	uint32_t data_attr = 0;
2305 	bool used_extra_tx_credit = false;
2306 
2307 	if (pPacket) {
2308 		if ((pPacket->Endpoint >= ENDPOINT_MAX) ||
2309 		   (pPacket->Endpoint <= ENDPOINT_UNUSED)) {
2310 			AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
2311 				("%s endpoint is invalid\n", __func__));
2312 			AR_DEBUG_ASSERT(0);
2313 			return QDF_STATUS_E_INVAL;
2314 		}
2315 		pEndpoint = &target->endpoint[pPacket->Endpoint];
2316 
2317 		/* add HTC_FRAME_HDR in the initial fragment */
2318 		netbuf = GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket);
2319 		pHtcHdr = (HTC_FRAME_HDR *) qdf_nbuf_get_frag_vaddr(netbuf, 0);
2320 		AR_DEBUG_ASSERT(pHtcHdr);
2321 
2322 		HTC_WRITE32(pHtcHdr,
2323 				SM(pPacket->ActualLength,
2324 				       HTC_FRAME_HDR_PAYLOADLEN) |
2325 				SM(pPacket->PktInfo.AsTx.SendFlags,
2326 					HTC_FRAME_HDR_FLAGS) |
2327 				SM(pPacket->Endpoint,
2328 					HTC_FRAME_HDR_ENDPOINTID));
2329 		/*
2330 		 * If the HIF pipe for the data endpoint is polled rather than
2331 		 * interrupt-driven, this is a good point to check whether any
2332 		 * data previously sent through the HIF pipe have finished being
2333 		 * sent. Since this may result in callbacks to
2334 		 * htc_tx_completion_handler, which can take the HTC tx lock,
2335 		 * make the hif_send_complete_check call before acquiring the
2336 		 * HTC tx lock.
2337 		 * Call hif_send_complete_check directly, rather than calling
2338 		 * htc_send_complete_check, and call the PollTimerStart
2339 		 * separately after calling hif_send_head, so the timer will be
2340 		 * started to check for completion of the new outstanding
2341 		 * download (in the unexpected event that other polling calls
2342 		 * don't catch it).
2343 		 */
2344 		if (pEndpoint->ul_is_polled) {
2345 			htc_send_complete_poll_timer_stop(pEndpoint);
2346 			hif_send_complete_check(pEndpoint->target->hif_dev,
2347 						pEndpoint->UL_PipeID, 0);
2348 		}
2349 
2350 		LOCK_HTC_TX(target);
2351 
2352 		pPacket->PktInfo.AsTx.SeqNo = pEndpoint->SeqNo;
2353 		pEndpoint->SeqNo++;
2354 
2355 		HTC_WRITE32(((uint32_t *) pHtcHdr) + 1,
2356 			    SM(pPacket->PktInfo.AsTx.SeqNo,
2357 			       HTC_FRAME_HDR_CONTROLBYTES1));
2358 
2359 		/* append new packet to pEndpoint->TxQueue */
2360 		HTC_PACKET_ENQUEUE(&pEndpoint->TxQueue, pPacket);
2361 		if (HTC_TX_BUNDLE_ENABLED(target) && (more_data)) {
2362 			UNLOCK_HTC_TX(target);
2363 			return QDF_STATUS_SUCCESS;
2364 		}
2365 
2366 		QDF_NBUF_UPDATE_TX_PKT_COUNT(netbuf, QDF_NBUF_TX_PKT_HTC);
2367 		DPTRACE(qdf_dp_trace(netbuf, QDF_DP_TRACE_HTC_PACKET_PTR_RECORD,
2368 			  QDF_TRACE_DEFAULT_PDEV_ID, qdf_nbuf_data_addr(netbuf),
2369 				sizeof(qdf_nbuf_data(netbuf)), QDF_TX));
2370 	} else {
2371 		LOCK_HTC_TX(target);
2372 		pEndpoint = &target->endpoint[1];
2373 	}
2374 
2375 	/* increment tx processing count on entry */
2376 	qdf_atomic_inc(&pEndpoint->TxProcessCount);
2377 	if (qdf_atomic_read(&pEndpoint->TxProcessCount) > 1) {
2378 		/*
2379 		 * Another thread or task is draining the TX queues on this
2380 		 * endpoint. That thread will reset the tx processing count when
2381 		 * the queue is drained.
2382 		 */
2383 		qdf_atomic_dec(&pEndpoint->TxProcessCount);
2384 		UNLOCK_HTC_TX(target);
2385 		return QDF_STATUS_SUCCESS;
2386 	}
2387 
2388 	/***** beyond this point only 1 thread may enter ******/
2389 
2390 	INIT_HTC_PACKET_QUEUE(&sendQueue);
2391 	if (IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)) {
2392 #if DEBUG_CREDIT
2393 		int cred = pEndpoint->TxCredits;
2394 #endif
2395 		get_htc_send_packets_credit_based(target, pEndpoint,
2396 						 &sendQueue);
2397 #if DEBUG_CREDIT
2398 		if (ep_debug_mask & (1 << pEndpoint->Id)) {
2399 			if (cred - pEndpoint->TxCredits > 0) {
2400 				AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
2401 						(" <HTC> Decrease EP%d %d - %d = %d credits.\n",
2402 						 pEndpoint->Id, cred,
2403 						 cred - pEndpoint->TxCredits,
2404 						 pEndpoint->TxCredits));
2405 			}
2406 		}
2407 #endif
2408 		UNLOCK_HTC_TX(target);
2409 	}
2410 
2411 	else if (HTC_TX_BUNDLE_ENABLED(target)) {
2412 		if (hif_get_bus_type(target->hif_dev) == QDF_BUS_TYPE_USB) {
2413 			if (hif_get_free_queue_number(target->hif_dev,
2414 						      pEndpoint->UL_PipeID))
2415 				/*
2416 				 * Header and payload belongs to the different
2417 				 * fragments and consume 2 resource for one HTC
2418 				 * package but USB combine into one transfer.
2419 				 */
2420 				get_htc_send_packets(target, pEndpoint,
2421 						     &sendQueue,
2422 						     HTC_MAX_MSG_PER_BUNDLE_TX
2423 						     * 2);
2424 		} else {
2425 			/* Dequeue max packets from endpoint tx queue */
2426 			get_htc_send_packets(target, pEndpoint, &sendQueue,
2427 					     HTC_MAX_TX_BUNDLE_SEND_LIMIT);
2428 		}
2429 		UNLOCK_HTC_TX(target);
2430 	} else {
2431 		/*
2432 		 * Now drain the endpoint TX queue for transmission as long as
2433 		 * we have enough transmit resources
2434 		 */
2435 		tx_resources =
2436 			hif_get_free_queue_number(target->hif_dev,
2437 						  pEndpoint->UL_PipeID);
2438 		get_htc_send_packets(target, pEndpoint, &sendQueue,
2439 				     tx_resources);
2440 		UNLOCK_HTC_TX(target);
2441 	}
2442 
2443 	/* send what we can */
2444 	while (true) {
2445 		if (HTC_TX_BUNDLE_ENABLED(target) &&
2446 		    (HTC_PACKET_QUEUE_DEPTH(&sendQueue) >=
2447 		     HTC_MIN_MSG_PER_BUNDLE) &&
2448 		    (hif_get_bus_type(target->hif_dev) == QDF_BUS_TYPE_SDIO ||
2449 		     hif_get_bus_type(target->hif_dev) == QDF_BUS_TYPE_USB)) {
2450 			if (pEndpoint->EpCallBacks.ep_padding_credit_update) {
2451 				if (htc_tx_pad_credit_avail(pEndpoint) < 1) {
2452 					status = QDF_STATUS_E_RESOURCES;
2453 					/* put the sendQueue back at the front
2454 					 * of pEndpoint->TxQueue
2455 					 */
2456 					LOCK_HTC_TX(target);
2457 					HTC_PACKET_QUEUE_TRANSFER_TO_HEAD(
2458 							&pEndpoint->TxQueue,
2459 							&sendQueue);
2460 					UNLOCK_HTC_TX(target);
2461 					break;
2462 				}
2463 			}
2464 			htc_issue_packets_bundle(target, pEndpoint, &sendQueue);
2465 		}
2466 		if (pEndpoint->EpCallBacks.ep_padding_credit_update) {
2467 			if (htc_tx_pad_credit_avail(pEndpoint) < 1) {
2468 				status = QDF_STATUS_E_RESOURCES;
2469 				/* put the sendQueue back at the front
2470 				 * of pEndpoint->TxQueue
2471 				 */
2472 				LOCK_HTC_TX(target);
2473 				HTC_PACKET_QUEUE_TRANSFER_TO_HEAD(
2474 							&pEndpoint->TxQueue,
2475 							&sendQueue);
2476 				UNLOCK_HTC_TX(target);
2477 				break;
2478 			}
2479 		}
2480 		pPacket = htc_packet_dequeue(&sendQueue);
2481 		if (!pPacket)
2482 			break;
2483 		netbuf = GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket);
2484 		pHtcHdr = (HTC_FRAME_HDR *)qdf_nbuf_get_frag_vaddr(netbuf, 0);
2485 
2486 		LOCK_HTC_TX(target);
2487 		/* store in look up queue to match completions */
2488 		HTC_PACKET_ENQUEUE(&pEndpoint->TxLookupQueue, pPacket);
2489 		INC_HTC_EP_STAT(pEndpoint, TxIssued, 1);
2490 		pEndpoint->ul_outstanding_cnt++;
2491 		UNLOCK_HTC_TX(target);
2492 
2493 		used_extra_tx_credit =
2494 				htc_handle_extra_tx_credit(pEndpoint, pPacket,
2495 							   (uint8_t *)pHtcHdr,
2496 							   NULL,
2497 							   pPacket->ActualLength
2498 							   + HTC_HDR_LENGTH);
2499 
2500 		status = hif_send_head(target->hif_dev,
2501 				       pEndpoint->UL_PipeID,
2502 				       pEndpoint->Id,
2503 				       HTC_HDR_LENGTH + pPacket->ActualLength,
2504 				       netbuf, data_attr);
2505 		if (status != QDF_STATUS_SUCCESS) {
2506 			if (pEndpoint->EpCallBacks.ep_padding_credit_update) {
2507 				if (used_extra_tx_credit) {
2508 					pEndpoint->EpCallBacks.
2509 					ep_padding_credit_update
2510 					(pEndpoint->EpCallBacks.pContext, 1);
2511 				}
2512 			}
2513 		}
2514 #if DEBUG_BUNDLE
2515 		qdf_print(" Send single EP%d buffer size:0x%x, total:0x%x.",
2516 			  pEndpoint->Id,
2517 			  pEndpoint->TxCreditSize,
2518 			  HTC_HDR_LENGTH + pPacket->ActualLength);
2519 #endif
2520 
2521 		htc_issue_tx_bundle_stats_inc(target);
2522 
2523 		if (qdf_unlikely(QDF_IS_STATUS_ERROR(status))) {
2524 			LOCK_HTC_TX(target);
2525 			pEndpoint->ul_outstanding_cnt--;
2526 			/* remove this packet from the tx completion queue */
2527 			HTC_PACKET_REMOVE(&pEndpoint->TxLookupQueue, pPacket);
2528 
2529 			/*
2530 			 * Don't bother reclaiming credits - HTC flow control
2531 			 * is not applicable to tx data.
2532 			 * In LL systems, there is no download flow control,
2533 			 * since there's virtually no download delay.
2534 			 * In HL systems, the txrx SW explicitly performs the
2535 			 * tx flow control.
2536 			 */
2537 			/* pEndpoint->TxCredits +=
2538 			 * pPacket->PktInfo.AsTx.CreditsUsed;
2539 			 */
2540 
2541 			/* put this frame back at the front of the sendQueue */
2542 			HTC_PACKET_ENQUEUE_TO_HEAD(&sendQueue, pPacket);
2543 
2544 			/* put the sendQueue back at the front of
2545 			 * pEndpoint->TxQueue
2546 			 */
2547 			HTC_PACKET_QUEUE_TRANSFER_TO_HEAD(&pEndpoint->TxQueue,
2548 							  &sendQueue);
2549 			UNLOCK_HTC_TX(target);
2550 			break;  /* still need to reset TxProcessCount */
2551 		}
2552 	}
2553 	/* done with this endpoint, we can clear the count */
2554 	qdf_atomic_init(&pEndpoint->TxProcessCount);
2555 
2556 	if (pEndpoint->ul_is_polled) {
2557 		/*
2558 		 * Start a cleanup timer to poll for download completion.
2559 		 * The download completion should be noticed promptly from
2560 		 * other polling calls, but the timer provides a safety net
2561 		 * in case other polling calls don't occur as expected.
2562 		 */
2563 		htc_send_complete_poll_timer_start(pEndpoint);
2564 	}
2565 
2566 	return status;
2567 }
2568 #endif /*ATH_11AC_TXCOMPACT */
2569 qdf_export_symbol(htc_send_data_pkt);
2570 
2571 /*
2572  * In the adapted HIF layer, qdf_nbuf_t are passed between HIF and HTC,
2573  * since upper layers expects HTC_PACKET containers we use the completed netbuf
2574  * and lookup its corresponding HTC packet buffer from a lookup list.
2575  * This is extra overhead that can be fixed by re-aligning HIF interfaces
2576  * with HTC.
2577  *
2578  */
htc_lookup_tx_packet(HTC_TARGET * target,HTC_ENDPOINT * pEndpoint,qdf_nbuf_t netbuf)2579 static HTC_PACKET *htc_lookup_tx_packet(HTC_TARGET *target,
2580 					HTC_ENDPOINT *pEndpoint,
2581 					qdf_nbuf_t netbuf)
2582 {
2583 	HTC_PACKET *pPacket = NULL;
2584 	HTC_PACKET *pFoundPacket = NULL;
2585 	HTC_PACKET_QUEUE lookupQueue;
2586 
2587 	INIT_HTC_PACKET_QUEUE(&lookupQueue);
2588 	LOCK_HTC_EP_TX_LOOKUP(pEndpoint);
2589 
2590 	LOCK_HTC_TX(target);
2591 	/* mark that HIF has indicated the send complete for another packet */
2592 	pEndpoint->ul_outstanding_cnt--;
2593 
2594 	/* Dequeue first packet directly because of in-order completion */
2595 	pPacket = htc_packet_dequeue(&pEndpoint->TxLookupQueue);
2596 	if (qdf_unlikely(!pPacket)) {
2597 		UNLOCK_HTC_TX(target);
2598 		UNLOCK_HTC_EP_TX_LOOKUP(pEndpoint);
2599 		return NULL;
2600 	}
2601 	if (netbuf == (qdf_nbuf_t) GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket)) {
2602 		UNLOCK_HTC_TX(target);
2603 		UNLOCK_HTC_EP_TX_LOOKUP(pEndpoint);
2604 		return pPacket;
2605 	}
2606 	HTC_PACKET_ENQUEUE(&lookupQueue, pPacket);
2607 
2608 	/*
2609 	 * Move TX lookup queue to temp queue because most of packets that are
2610 	 * not index 0 are not top 10 packets.
2611 	 */
2612 	HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(&lookupQueue,
2613 					  &pEndpoint->TxLookupQueue);
2614 
2615 	ITERATE_OVER_LIST_ALLOW_REMOVE(&lookupQueue.QueueHead, pPacket,
2616 				       HTC_PACKET, ListLink) {
2617 
2618 		if (!pPacket) {
2619 			pFoundPacket = pPacket;
2620 			break;
2621 		}
2622 		/* check for removal */
2623 		if (netbuf ==
2624 		    (qdf_nbuf_t) GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket)) {
2625 			/* found it */
2626 			HTC_PACKET_REMOVE(&lookupQueue, pPacket);
2627 			pFoundPacket = pPacket;
2628 			break;
2629 		}
2630 
2631 	}
2632 	ITERATE_END;
2633 
2634 	HTC_PACKET_QUEUE_TRANSFER_TO_HEAD(&pEndpoint->TxLookupQueue,
2635 					  &lookupQueue);
2636 	UNLOCK_HTC_TX(target);
2637 	UNLOCK_HTC_EP_TX_LOOKUP(pEndpoint);
2638 
2639 	return pFoundPacket;
2640 }
2641 
2642 /**
2643  * htc_tx_completion_handler() - htc tx completion handler
2644  * @Context: pointer to HTC_TARGET structure
2645  * @netbuf: pointer to netbuf for which completion handler is being called
2646  * @EpID: end point Id on which the packet was sent
2647  * @toeplitz_hash_result: toeplitz hash result
2648  *
2649  * Return: QDF_STATUS_SUCCESS for success or an appropriate QDF_STATUS error
2650  */
htc_tx_completion_handler(void * Context,qdf_nbuf_t netbuf,unsigned int EpID,uint32_t toeplitz_hash_result)2651 QDF_STATUS htc_tx_completion_handler(void *Context,
2652 				   qdf_nbuf_t netbuf, unsigned int EpID,
2653 				   uint32_t toeplitz_hash_result)
2654 {
2655 	HTC_TARGET *target = (HTC_TARGET *) Context;
2656 	HTC_ENDPOINT *pEndpoint;
2657 	HTC_PACKET *pPacket;
2658 #ifdef USB_HIF_SINGLE_PIPE_DATA_SCHED
2659 	HTC_ENDPOINT_ID eid[DATA_EP_SIZE] = { ENDPOINT_5, ENDPOINT_4,
2660 		ENDPOINT_2, ENDPOINT_3 };
2661 	int epidIdx;
2662 	uint16_t resourcesThresh[DATA_EP_SIZE]; /* urb resources */
2663 	uint16_t resources;
2664 	uint16_t resourcesMax;
2665 #endif
2666 
2667 	pEndpoint = &target->endpoint[EpID];
2668 	target->TX_comp_cnt++;
2669 	pEndpoint->htc_comp_cnt++;
2670 
2671 	do {
2672 		pPacket = htc_lookup_tx_packet(target, pEndpoint, netbuf);
2673 		if (!pPacket) {
2674 			qdf_rl_err("HTC TX lookup failed!");
2675 			/* may have already been flushed and freed */
2676 			netbuf = NULL;
2677 			break;
2678 		}
2679 		if (pPacket->PktInfo.AsTx.Tag != HTC_TX_PACKET_TAG_AUTO_PM &&
2680 		    pPacket->PktInfo.AsTx.Tag != HTC_TX_PACKET_TAG_RUNTIME_PUT &&
2681 		    pPacket->PktInfo.AsTx.Tag != HTC_TX_PACKET_TAG_RTPM_PUT_RC) {
2682 			hif_rtpm_put(HIF_RTPM_PUT_ASYNC, HIF_RTPM_ID_WMI);
2683 			htc_dec_wmi_runtime_cnt(target, HIF_RTPM_ID_WMI);
2684 		}
2685 
2686 
2687 		if (pPacket->PktInfo.AsTx.Tag == HTC_TX_PACKET_TAG_BUNDLED) {
2688 			HTC_PACKET *pPacketTemp;
2689 			HTC_PACKET_QUEUE *pQueueSave =
2690 				(HTC_PACKET_QUEUE *) pPacket->pContext;
2691 			HTC_PACKET_QUEUE_ITERATE_ALLOW_REMOVE(pQueueSave,
2692 							      pPacketTemp) {
2693 				pPacket->Status = QDF_STATUS_SUCCESS;
2694 				send_packet_completion(target, pPacketTemp);
2695 			}
2696 			HTC_PACKET_QUEUE_ITERATE_END;
2697 			free_htc_bundle_packet(target, pPacket);
2698 
2699 			if (hif_get_bus_type(target->hif_dev) ==
2700 					     QDF_BUS_TYPE_USB) {
2701 				if (!IS_TX_CREDIT_FLOW_ENABLED(pEndpoint))
2702 					htc_try_send(target, pEndpoint, NULL);
2703 			}
2704 
2705 			return QDF_STATUS_SUCCESS;
2706 		}
2707 		/* will be giving this buffer back to upper layers */
2708 		netbuf = NULL;
2709 		pPacket->Status = QDF_STATUS_SUCCESS;
2710 		send_packet_completion(target, pPacket);
2711 
2712 	} while (false);
2713 
2714 	if (!IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)) {
2715 		/* note: when using TX credit flow, the re-checking of queues
2716 		 * happens when credits flow back from the target. In the non-TX
2717 		 * credit case, we recheck after the packet completes
2718 		 */
2719 		if ((qdf_atomic_read(&pEndpoint->TxProcessCount) == 0) ||
2720 				(!pEndpoint->async_update)) {
2721 			htc_try_send(target, pEndpoint, NULL);
2722 		}
2723 	}
2724 
2725 	return QDF_STATUS_SUCCESS;
2726 }
2727 
2728 #ifdef WLAN_FEATURE_FASTPATH
2729 /**
2730  * htc_ctrl_msg_cmpl() - checks for tx completion for the endpoint specified
2731  * @htc_pdev: pointer to the htc context
2732  * @htc_ep_id: end point id
2733  *
2734  * checks HTC tx completion
2735  *
2736  * Return: none
2737  */
htc_ctrl_msg_cmpl(HTC_HANDLE htc_pdev,HTC_ENDPOINT_ID htc_ep_id)2738 void htc_ctrl_msg_cmpl(HTC_HANDLE htc_pdev, HTC_ENDPOINT_ID htc_ep_id)
2739 {
2740 	HTC_TARGET      *target = GET_HTC_TARGET_FROM_HANDLE(htc_pdev);
2741 	HTC_ENDPOINT    *pendpoint = &target->endpoint[htc_ep_id];
2742 
2743 	htc_send_complete_check(pendpoint, 1);
2744 }
2745 qdf_export_symbol(htc_ctrl_msg_cmpl);
2746 #endif
2747 
2748 /* callback when TX resources become available */
htc_tx_resource_avail_handler(void * context,uint8_t pipeID)2749 void htc_tx_resource_avail_handler(void *context, uint8_t pipeID)
2750 {
2751 	int i;
2752 	HTC_TARGET *target = (HTC_TARGET *) context;
2753 	HTC_ENDPOINT *pEndpoint = NULL;
2754 
2755 	for (i = 0; i < ENDPOINT_MAX; i++) {
2756 		pEndpoint = &target->endpoint[i];
2757 		if (pEndpoint->service_id != 0) {
2758 			if (pEndpoint->UL_PipeID == pipeID)
2759 				break;
2760 		}
2761 	}
2762 
2763 	if (i >= ENDPOINT_MAX) {
2764 		AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
2765 				("Invalid pipe indicated for TX resource avail : %d!\n",
2766 				 pipeID));
2767 		return;
2768 	}
2769 
2770 	AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
2771 			("HIF indicated more resources for pipe:%d\n",
2772 			 pipeID));
2773 
2774 	htc_try_send(target, pEndpoint, NULL);
2775 }
2776 
2777 #ifdef FEATURE_RUNTIME_PM
2778 /**
2779  * htc_kick_queues() - resumes tx transactions of suspended endpoints
2780  * @context: pointer to the htc target context
2781  *
2782  * Iterates through the endpoints and provides a context to empty queues
2783  * int the hif layer when they are stalled due to runtime suspend.
2784  *
2785  * Return: none
2786  */
htc_kick_queues(void * context)2787 void htc_kick_queues(void *context)
2788 {
2789 	int i;
2790 	HTC_TARGET *target = (HTC_TARGET *)context;
2791 	HTC_ENDPOINT *endpoint = NULL;
2792 
2793 	if (hif_rtpm_get(HIF_RTPM_GET_SYNC, HIF_RTPM_ID_HTT))
2794 		return;
2795 
2796 	for (i = 0; i < ENDPOINT_MAX; i++) {
2797 		endpoint = &target->endpoint[i];
2798 
2799 		if (endpoint->service_id == 0)
2800 			continue;
2801 
2802 		if (endpoint->EpCallBacks.ep_resume_tx_queue)
2803 			endpoint->EpCallBacks.ep_resume_tx_queue(
2804 					endpoint->EpCallBacks.pContext);
2805 
2806 		htc_try_send(target, endpoint, NULL);
2807 	}
2808 
2809 	hif_fastpath_resume(target->hif_dev);
2810 
2811 	hif_rtpm_put(HIF_RTPM_PUT_ASYNC, HIF_RTPM_ID_HTT);
2812 }
2813 #endif
2814 
2815 /* flush endpoint TX queue */
htc_flush_endpoint_tx(HTC_TARGET * target,HTC_ENDPOINT * pEndpoint,HTC_TX_TAG Tag)2816 void htc_flush_endpoint_tx(HTC_TARGET *target, HTC_ENDPOINT *pEndpoint,
2817 			   HTC_TX_TAG Tag)
2818 {
2819 	HTC_PACKET *pPacket;
2820 
2821 	LOCK_HTC_TX(target);
2822 	while (HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue)) {
2823 		pPacket = htc_packet_dequeue(&pEndpoint->TxQueue);
2824 
2825 		if (pPacket) {
2826 			/* let the sender know the packet was not delivered */
2827 			pPacket->Status = QDF_STATUS_E_CANCELED;
2828 			send_packet_completion(target, pPacket);
2829 		}
2830 	}
2831 	UNLOCK_HTC_TX(target);
2832 }
2833 
2834 /* flush pending entries in endpoint TX Lookup queue */
htc_flush_endpoint_txlookupQ(HTC_TARGET * target,HTC_ENDPOINT_ID endpoint_id,bool call_ep_callback)2835 void htc_flush_endpoint_txlookupQ(HTC_TARGET *target,
2836 				  HTC_ENDPOINT_ID endpoint_id,
2837 				  bool call_ep_callback)
2838 {
2839 	HTC_PACKET *packet;
2840 	HTC_ENDPOINT *endpoint;
2841 
2842 	endpoint = &target->endpoint[endpoint_id];
2843 
2844 	if (!endpoint && endpoint->service_id == 0)
2845 		return;
2846 
2847 	LOCK_HTC_TX(target);
2848 	while (HTC_PACKET_QUEUE_DEPTH(&endpoint->TxLookupQueue)) {
2849 		packet = htc_packet_dequeue(&endpoint->TxLookupQueue);
2850 
2851 		if (packet) {
2852 			if (call_ep_callback == true) {
2853 				packet->Status = QDF_STATUS_E_CANCELED;
2854 				send_packet_completion(target, packet);
2855 			} else {
2856 				qdf_mem_free(packet);
2857 			}
2858 		}
2859 	}
2860 	UNLOCK_HTC_TX(target);
2861 }
2862 
2863 /* HTC API to flush an endpoint's TX queue*/
htc_flush_endpoint(HTC_HANDLE HTCHandle,HTC_ENDPOINT_ID Endpoint,HTC_TX_TAG Tag)2864 void htc_flush_endpoint(HTC_HANDLE HTCHandle, HTC_ENDPOINT_ID Endpoint,
2865 			HTC_TX_TAG Tag)
2866 {
2867 	HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
2868 	HTC_ENDPOINT *pEndpoint = &target->endpoint[Endpoint];
2869 
2870 	if (pEndpoint->service_id == 0) {
2871 		AR_DEBUG_ASSERT(false);
2872 		/* not in use.. */
2873 		return;
2874 	}
2875 
2876 	htc_flush_endpoint_tx(target, pEndpoint, Tag);
2877 }
2878 
2879 /* HTC API to indicate activity to the credit distribution function */
htc_indicate_activity_change(HTC_HANDLE HTCHandle,HTC_ENDPOINT_ID Endpoint,bool Active)2880 void htc_indicate_activity_change(HTC_HANDLE HTCHandle,
2881 				  HTC_ENDPOINT_ID Endpoint, bool Active)
2882 {
2883 	/*  TODO */
2884 }
2885 
htc_is_endpoint_active(HTC_HANDLE HTCHandle,HTC_ENDPOINT_ID Endpoint)2886 bool htc_is_endpoint_active(HTC_HANDLE HTCHandle, HTC_ENDPOINT_ID Endpoint)
2887 {
2888 	return true;
2889 }
2890 
htc_set_pkt_dbg(HTC_HANDLE handle,A_BOOL dbg_flag)2891 void htc_set_pkt_dbg(HTC_HANDLE handle, A_BOOL dbg_flag)
2892 {
2893 	HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(handle);
2894 
2895 	target->htc_pkt_dbg = dbg_flag;
2896 }
2897 
htc_set_nodrop_pkt(HTC_HANDLE HTCHandle,A_BOOL isNodropPkt)2898 void htc_set_nodrop_pkt(HTC_HANDLE HTCHandle, A_BOOL isNodropPkt)
2899 {
2900 	HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
2901 
2902 	target->is_nodrop_pkt = isNodropPkt;
2903 }
2904 
htc_enable_hdr_length_check(HTC_HANDLE htc_hdl,bool htc_hdr_length_check)2905 void htc_enable_hdr_length_check(HTC_HANDLE htc_hdl, bool htc_hdr_length_check)
2906 {
2907 	HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(htc_hdl);
2908 
2909 	target->htc_hdr_length_check = htc_hdr_length_check;
2910 }
2911 
2912 /**
2913  * htc_process_credit_rpt() - process credit report, call distribution function
2914  * @target: pointer to HTC_TARGET
2915  * @pRpt: pointer to HTC_CREDIT_REPORT
2916  * @NumEntries: number of entries in credit report
2917  * @FromEndpoint: endpoint for which  credit report is received
2918  *
2919  * Return: A_OK for success or an appropriate A_STATUS error
2920  */
htc_process_credit_rpt(HTC_TARGET * target,HTC_CREDIT_REPORT * pRpt,int NumEntries,HTC_ENDPOINT_ID FromEndpoint)2921 void htc_process_credit_rpt(HTC_TARGET *target, HTC_CREDIT_REPORT *pRpt,
2922 			    int NumEntries, HTC_ENDPOINT_ID FromEndpoint)
2923 {
2924 	int i;
2925 	HTC_ENDPOINT *pEndpoint;
2926 	int totalCredits = 0;
2927 	uint8_t rpt_credits, rpt_ep_id;
2928 
2929 	AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
2930 			("+htc_process_credit_rpt, Credit Report Entries:%d\n",
2931 			 NumEntries));
2932 
2933 	/* lock out TX while we update credits */
2934 	LOCK_HTC_TX(target);
2935 
2936 	for (i = 0; i < NumEntries; i++, pRpt++) {
2937 
2938 		rpt_ep_id = HTC_GET_FIELD(pRpt, HTC_CREDIT_REPORT, ENDPOINTID);
2939 
2940 		if (rpt_ep_id >= ENDPOINT_MAX) {
2941 			AR_DEBUG_ASSERT(false);
2942 			break;
2943 		}
2944 
2945 		rpt_credits = HTC_GET_FIELD(pRpt, HTC_CREDIT_REPORT, CREDITS);
2946 
2947 		pEndpoint = &target->endpoint[rpt_ep_id];
2948 #if DEBUG_CREDIT
2949 		if (ep_debug_mask & (1 << pEndpoint->Id)) {
2950 			AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
2951 					(" <HTC> Increase EP%d %d + %d = %d credits\n",
2952 					 rpt_ep_id, pEndpoint->TxCredits,
2953 					 rpt_credits,
2954 					 pEndpoint->TxCredits + rpt_credits));
2955 		}
2956 #endif
2957 
2958 #ifdef HTC_EP_STAT_PROFILING
2959 
2960 		INC_HTC_EP_STAT(pEndpoint, TxCreditRpts, 1);
2961 		INC_HTC_EP_STAT(pEndpoint, TxCreditsReturned, rpt_credits);
2962 
2963 		if (FromEndpoint == rpt_ep_id) {
2964 			/* this credit report arrived on the same endpoint
2965 			 * indicating it arrived in an RX packet
2966 			 */
2967 			INC_HTC_EP_STAT(pEndpoint, TxCreditsFromRx,
2968 					rpt_credits);
2969 			INC_HTC_EP_STAT(pEndpoint, TxCreditRptsFromRx, 1);
2970 		} else if (FromEndpoint == ENDPOINT_0) {
2971 			/* this credit arrived on endpoint 0 as a NULL msg */
2972 			INC_HTC_EP_STAT(pEndpoint, TxCreditsFromEp0,
2973 					rpt_credits);
2974 			INC_HTC_EP_STAT(pEndpoint, TxCreditRptsFromEp0, 1);
2975 		} else {
2976 			/* arrived on another endpoint */
2977 			INC_HTC_EP_STAT(pEndpoint, TxCreditsFromOther,
2978 					rpt_credits);
2979 			INC_HTC_EP_STAT(pEndpoint, TxCreditRptsFromOther, 1);
2980 		}
2981 
2982 #endif
2983 
2984 		if (pEndpoint->service_id == WMI_CONTROL_SVC) {
2985 			htc_credit_record(HTC_PROCESS_CREDIT_REPORT,
2986 					  pEndpoint->TxCredits + rpt_credits,
2987 					  HTC_PACKET_QUEUE_DEPTH(&pEndpoint->
2988 							TxQueue));
2989 			hif_latency_detect_credit_record_time(
2990 					HIF_PROCESS_CREDIT_REPORT,
2991 					target->hif_dev);
2992 		}
2993 
2994 		pEndpoint->TxCredits += rpt_credits;
2995 
2996 		if (pEndpoint->TxCredits
2997 		    && HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue)) {
2998 			UNLOCK_HTC_TX(target);
2999 #ifdef ATH_11AC_TXCOMPACT
3000 			htc_try_send(target, pEndpoint, NULL);
3001 #else
3002 			if (pEndpoint->service_id == HTT_DATA_MSG_SVC)
3003 				htc_send_data_pkt((HTC_HANDLE)target, NULL, 0);
3004 			else
3005 				htc_try_send(target, pEndpoint, NULL);
3006 #endif
3007 			LOCK_HTC_TX(target);
3008 		}
3009 		totalCredits += rpt_credits;
3010 	}
3011 
3012 	AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
3013 			("  Report indicated %d credits to distribute\n",
3014 			 totalCredits));
3015 
3016 	UNLOCK_HTC_TX(target);
3017 
3018 	AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-htc_process_credit_rpt\n"));
3019 }
3020 
3021 /* function to fetch stats from htc layer*/
ieee80211_ioctl_get_htc_stats(HTC_HANDLE HTCHandle)3022 struct ol_ath_htc_stats *ieee80211_ioctl_get_htc_stats(HTC_HANDLE HTCHandle)
3023 {
3024 	HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
3025 
3026 	return &(target->htc_pkt_stats);
3027 }
3028 
3029 #ifdef SYSTEM_PM_CHECK
htc_system_resume(HTC_HANDLE htc)3030 void htc_system_resume(HTC_HANDLE htc)
3031 {
3032 	HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(htc);
3033 	HTC_ENDPOINT *endpoint = NULL;
3034 	int i;
3035 
3036 	if (!target)
3037 		return;
3038 
3039 	for (i = 0; i < ENDPOINT_MAX; i++) {
3040 		endpoint = &target->endpoint[i];
3041 
3042 		if (endpoint->service_id == 0)
3043 			continue;
3044 
3045 		htc_try_send(target, endpoint, NULL);
3046 	}
3047 }
3048 #endif
3049