xref: /wlan-dirver/qca-wifi-host-cmn/htc/htc_recv.c (revision 2b03e92990e6da4ef5296c3d23ef18d4f90f13f2)
1 /*
2  * Copyright (c) 2013-2021 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2023-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_nbuf.h>           /* qdf_nbuf_t */
24 #include <wbuff.h>
25 
26 #if defined(WLAN_DEBUG) || defined(DEBUG)
27 void debug_dump_bytes(uint8_t *buffer, uint16_t length, char *pDescription)
28 {
29 	int8_t stream[60];
30 	int8_t byteOffsetStr[10];
31 	uint32_t i;
32 	uint16_t offset, count, byteOffset;
33 
34 	A_PRINTF("<---------Dumping %d Bytes : %s ------>\n", length,
35 		 pDescription);
36 
37 	count = 0;
38 	offset = 0;
39 	byteOffset = 0;
40 	for (i = 0; i < length; i++) {
41 		A_SNPRINTF(stream + offset, (sizeof(stream) - offset),
42 			   "%02X ", buffer[i]);
43 		count++;
44 		offset += 3;
45 
46 		if (count == 16) {
47 			count = 0;
48 			offset = 0;
49 			A_SNPRINTF(byteOffsetStr, sizeof(byteOffsetStr), "%4.4X",
50 				   byteOffset);
51 			A_PRINTF("[%s]: %s\n", byteOffsetStr, stream);
52 			qdf_mem_zero(stream, 60);
53 			byteOffset += 16;
54 		}
55 	}
56 
57 	if (offset != 0) {
58 		A_SNPRINTF(byteOffsetStr, sizeof(byteOffsetStr), "%4.4X",
59 			   byteOffset);
60 		A_PRINTF("[%s]: %s\n", byteOffsetStr, stream);
61 	}
62 
63 	A_PRINTF("<------------------------------------------------->\n");
64 }
65 #else
66 void debug_dump_bytes(uint8_t *buffer, uint16_t length, char *pDescription)
67 {
68 }
69 #endif
70 
71 static A_STATUS htc_process_trailer(HTC_TARGET *target,
72 				    uint8_t *pBuffer,
73 				    int Length, HTC_ENDPOINT_ID FromEndpoint);
74 
75 #ifdef WLAN_FEATURE_CE_RX_BUFFER_REUSE
76 static void htc_rx_nbuf_free(qdf_nbuf_t nbuf)
77 {
78 	nbuf = wbuff_buff_put(nbuf);
79 	if (nbuf)
80 		qdf_nbuf_free(nbuf);
81 }
82 #else
83 static inline void htc_rx_nbuf_free(qdf_nbuf_t nbuf)
84 {
85 	return qdf_nbuf_free(nbuf);
86 }
87 #endif
88 
89 static void do_recv_completion_pkt(HTC_ENDPOINT *pEndpoint,
90 				   HTC_PACKET *pPacket)
91 {
92 	if (!pEndpoint->EpCallBacks.EpRecv) {
93 		AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
94 				("HTC ep %d has NULL recv callback on packet %pK\n",
95 				 pEndpoint->Id,
96 				 pPacket));
97 		if (pPacket)
98 			htc_rx_nbuf_free(pPacket->pPktContext);
99 	} else {
100 		AR_DEBUG_PRINTF(ATH_DEBUG_RECV,
101 				("HTC calling ep %d recv callback on packet %pK\n",
102 				 pEndpoint->Id, pPacket));
103 		pEndpoint->EpCallBacks.EpRecv(pEndpoint->EpCallBacks.pContext,
104 					      pPacket);
105 	}
106 }
107 
108 static void do_recv_completion(HTC_ENDPOINT *pEndpoint,
109 			       HTC_PACKET_QUEUE *pQueueToIndicate)
110 {
111 	HTC_PACKET *pPacket;
112 
113 	if (HTC_QUEUE_EMPTY(pQueueToIndicate)) {
114 		/* nothing to indicate */
115 		return;
116 	}
117 
118 	while (!HTC_QUEUE_EMPTY(pQueueToIndicate)) {
119 		pPacket = htc_packet_dequeue(pQueueToIndicate);
120 		do_recv_completion_pkt(pEndpoint, pPacket);
121 	}
122 }
123 
124 void htc_control_rx_complete(void *Context, HTC_PACKET *pPacket)
125 {
126 	/* TODO, can't really receive HTC control messages yet.... */
127 	AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
128 			("Invalid call to  htc_control_rx_complete\n"));
129 }
130 
131 void htc_unblock_recv(HTC_HANDLE HTCHandle)
132 {
133 	/* TODO  find the Need in new model */
134 }
135 
136 void htc_enable_recv(HTC_HANDLE HTCHandle)
137 {
138 
139 	/* TODO  find the Need in new model */
140 }
141 
142 void htc_disable_recv(HTC_HANDLE HTCHandle)
143 {
144 
145 	/* TODO  find the Need in new model */
146 }
147 
148 int htc_get_num_recv_buffers(HTC_HANDLE HTCHandle, HTC_ENDPOINT_ID Endpoint)
149 {
150 	HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
151 
152 	HTC_ENDPOINT *pEndpoint = &target->endpoint[Endpoint];
153 	return HTC_PACKET_QUEUE_DEPTH(&pEndpoint->RxBufferHoldQueue);
154 }
155 
156 HTC_PACKET *allocate_htc_packet_container(HTC_TARGET *target)
157 {
158 	HTC_PACKET *pPacket;
159 
160 	LOCK_HTC_RX(target);
161 
162 	if (!target->pHTCPacketStructPool) {
163 		UNLOCK_HTC_RX(target);
164 		return NULL;
165 	}
166 
167 	pPacket = target->pHTCPacketStructPool;
168 	target->pHTCPacketStructPool = (HTC_PACKET *) pPacket->ListLink.pNext;
169 
170 	UNLOCK_HTC_RX(target);
171 
172 	pPacket->ListLink.pNext = NULL;
173 	return pPacket;
174 }
175 
176 void free_htc_packet_container(HTC_TARGET *target, HTC_PACKET *pPacket)
177 {
178 	pPacket->ListLink.pPrev = NULL;
179 
180 	LOCK_HTC_RX(target);
181 	if (!target->pHTCPacketStructPool) {
182 		target->pHTCPacketStructPool = pPacket;
183 		pPacket->ListLink.pNext = NULL;
184 	} else {
185 		pPacket->ListLink.pNext =
186 			(DL_LIST *) target->pHTCPacketStructPool;
187 		target->pHTCPacketStructPool = pPacket;
188 	}
189 
190 	UNLOCK_HTC_RX(target);
191 }
192 
193 #ifdef RX_SG_SUPPORT
194 qdf_nbuf_t rx_sg_to_single_netbuf(HTC_TARGET *target)
195 {
196 	qdf_nbuf_t skb;
197 	uint8_t *anbdata;
198 	uint8_t *anbdata_new;
199 	uint32_t anblen;
200 	qdf_nbuf_t new_skb = NULL;
201 	uint32_t sg_queue_len;
202 	qdf_nbuf_queue_t *rx_sg_queue = &target->RxSgQueue;
203 
204 	sg_queue_len = qdf_nbuf_queue_len(rx_sg_queue);
205 
206 	if (sg_queue_len <= 1) {
207 		AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
208 				("rx_sg_to_single_netbuf: invalid sg queue len %u\n"));
209 		goto _failed;
210 	}
211 
212 	new_skb = qdf_nbuf_alloc(target->ExpRxSgTotalLen, 0, 4, false);
213 	if (!new_skb) {
214 		AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
215 				("rx_sg_to_single_netbuf: can't allocate %u size netbuf\n",
216 				 target->ExpRxSgTotalLen));
217 		goto _failed;
218 	}
219 
220 	qdf_nbuf_peek_header(new_skb, &anbdata_new, &anblen);
221 
222 	skb = qdf_nbuf_queue_remove(rx_sg_queue);
223 	do {
224 		qdf_nbuf_peek_header(skb, &anbdata, &anblen);
225 		qdf_mem_copy(anbdata_new, anbdata, qdf_nbuf_len(skb));
226 		qdf_nbuf_put_tail(new_skb, qdf_nbuf_len(skb));
227 		anbdata_new += qdf_nbuf_len(skb);
228 		htc_rx_nbuf_free(skb);
229 		skb = qdf_nbuf_queue_remove(rx_sg_queue);
230 	} while (skb);
231 
232 	RESET_RX_SG_CONFIG(target);
233 	return new_skb;
234 
235 _failed:
236 
237 	while ((skb = qdf_nbuf_queue_remove(rx_sg_queue)) != NULL)
238 		htc_rx_nbuf_free(skb);
239 
240 	RESET_RX_SG_CONFIG(target);
241 	return NULL;
242 }
243 #endif
244 
245 QDF_STATUS htc_rx_completion_handler(void *Context, qdf_nbuf_t netbuf,
246 				   uint8_t pipeID)
247 {
248 	QDF_STATUS status = QDF_STATUS_SUCCESS;
249 	HTC_FRAME_HDR *HtcHdr;
250 	HTC_TARGET *target = (HTC_TARGET *) Context;
251 	uint8_t *netdata;
252 	uint32_t netlen;
253 	HTC_ENDPOINT *pEndpoint, *currendpoint;
254 	HTC_PACKET *pPacket;
255 	uint16_t payloadLen;
256 	uint32_t trailerlen = 0;
257 	uint8_t htc_ep_id;
258 	int i;
259 #ifdef HTC_MSG_WAKEUP_FROM_SUSPEND_ID
260 	struct htc_init_info *info;
261 #endif
262 
263 #ifdef RX_SG_SUPPORT
264 	LOCK_HTC_RX(target);
265 	if (target->IsRxSgInprogress) {
266 		target->CurRxSgTotalLen += qdf_nbuf_len(netbuf);
267 		qdf_nbuf_queue_add(&target->RxSgQueue, netbuf);
268 		if (target->CurRxSgTotalLen == target->ExpRxSgTotalLen) {
269 			netbuf = rx_sg_to_single_netbuf(target);
270 			if (!netbuf) {
271 				UNLOCK_HTC_RX(target);
272 				goto _out;
273 			}
274 		} else {
275 			netbuf = NULL;
276 			UNLOCK_HTC_RX(target);
277 			goto _out;
278 		}
279 	}
280 	UNLOCK_HTC_RX(target);
281 #endif
282 
283 	netdata = qdf_nbuf_data(netbuf);
284 	netlen = qdf_nbuf_len(netbuf);
285 
286 	HtcHdr = (HTC_FRAME_HDR *) netdata;
287 
288 	do {
289 
290 		htc_ep_id = HTC_GET_FIELD(HtcHdr, HTC_FRAME_HDR, ENDPOINTID);
291 
292 		if (htc_ep_id >= ENDPOINT_MAX) {
293 			AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
294 					("HTC Rx: invalid EndpointID=%d\n",
295 					 htc_ep_id));
296 			debug_dump_bytes((uint8_t *) HtcHdr,
297 					sizeof(HTC_FRAME_HDR),
298 					"BAD HTC Header");
299 			status = QDF_STATUS_E_FAILURE;
300 			DPTRACE(qdf_dp_trace(
301 					    netbuf,
302 					    QDF_DP_TRACE_HTC_PACKET_PTR_RECORD,
303 					    QDF_TRACE_DEFAULT_PDEV_ID,
304 					    qdf_nbuf_data_addr(netbuf),
305 					    sizeof(qdf_nbuf_data(netbuf)),
306 					    QDF_RX));
307 			break;
308 		}
309 
310 		pEndpoint = &target->endpoint[htc_ep_id];
311 
312 		/*
313 		 * If this endpoint that received a message from the target has
314 		 * a to-target HIF pipe whose send completions are polled rather
315 		 * than interrupt driven, this is a good point to ask HIF to
316 		 * check whether it has any completed sends to handle.
317 		 */
318 		if (pEndpoint->ul_is_polled) {
319 			for (i = 0; i < ENDPOINT_MAX; i++) {
320 				currendpoint = &target->endpoint[i];
321 				if ((currendpoint->DL_PipeID ==
322 				     pEndpoint->DL_PipeID) &&
323 				    currendpoint->ul_is_polled) {
324 					htc_send_complete_check(currendpoint,
325 								1);
326 				}
327 			}
328 		}
329 
330 		payloadLen = HTC_GET_FIELD(HtcHdr, HTC_FRAME_HDR, PAYLOADLEN);
331 
332 		if (netlen < (payloadLen + HTC_HDR_LENGTH)) {
333 #ifdef RX_SG_SUPPORT
334 			LOCK_HTC_RX(target);
335 			target->IsRxSgInprogress = true;
336 			qdf_nbuf_queue_init(&target->RxSgQueue);
337 			qdf_nbuf_queue_add(&target->RxSgQueue, netbuf);
338 			target->ExpRxSgTotalLen = (payloadLen + HTC_HDR_LENGTH);
339 			target->CurRxSgTotalLen += netlen;
340 			UNLOCK_HTC_RX(target);
341 			netbuf = NULL;
342 			break;
343 #else
344 			AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
345 					("HTC Rx: insufficient length, got:%d expected =%zu\n",
346 					 netlen, payloadLen + HTC_HDR_LENGTH));
347 			debug_dump_bytes((uint8_t *) HtcHdr,
348 					 sizeof(HTC_FRAME_HDR),
349 					 "BAD RX packet length");
350 			status = QDF_STATUS_E_FAILURE;
351 			DPTRACE(qdf_dp_trace(
352 					    netbuf,
353 					    QDF_DP_TRACE_HTC_PACKET_PTR_RECORD,
354 					    QDF_TRACE_DEFAULT_PDEV_ID,
355 					    qdf_nbuf_data_addr(netbuf),
356 					    sizeof(qdf_nbuf_data(netbuf)),
357 					    QDF_RX));
358 			break;
359 #endif
360 		}
361 #ifdef HTC_EP_STAT_PROFILING
362 		LOCK_HTC_RX(target);
363 		INC_HTC_EP_STAT(pEndpoint, RxReceived, 1);
364 		UNLOCK_HTC_RX(target);
365 #endif
366 
367 		/* if (IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)) { */
368 		{
369 			uint8_t temp;
370 			A_STATUS temp_status;
371 			/* get flags to check for trailer */
372 			temp = HTC_GET_FIELD(HtcHdr, HTC_FRAME_HDR, FLAGS);
373 			if (temp & HTC_FLAGS_RECV_TRAILER) {
374 				/* extract the trailer length */
375 				temp =
376 					HTC_GET_FIELD(HtcHdr, HTC_FRAME_HDR,
377 						      CONTROLBYTES0);
378 				if ((temp < sizeof(HTC_RECORD_HDR))
379 				    || (temp > payloadLen)) {
380 					AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
381 						("htc_rx_completion_handler, invalid header (payloadlength should be :%d, CB[0] is:%d)\n",
382 						payloadLen, temp));
383 					status = QDF_STATUS_E_INVAL;
384 					break;
385 				}
386 
387 				trailerlen = temp;
388 				/* process trailer data that follows HDR +
389 				 * application payload
390 				 */
391 				temp_status = htc_process_trailer(target,
392 						((uint8_t *) HtcHdr +
393 							HTC_HDR_LENGTH +
394 							payloadLen - temp),
395 						temp, htc_ep_id);
396 				if (A_FAILED(temp_status)) {
397 					status = QDF_STATUS_E_FAILURE;
398 					break;
399 				}
400 
401 			}
402 		}
403 
404 		if (((int)payloadLen - (int)trailerlen) <= 0) {
405 			/* 0 length packet with trailer data, just drop these */
406 			break;
407 		}
408 
409 		if (htc_ep_id == ENDPOINT_0) {
410 			uint16_t message_id;
411 			HTC_UNKNOWN_MSG *htc_msg;
412 			bool wow_nack;
413 			uint16_t reason_code;
414 
415 			/* remove HTC header */
416 			qdf_nbuf_pull_head(netbuf, HTC_HDR_LENGTH);
417 			netdata = qdf_nbuf_data(netbuf);
418 			netlen = qdf_nbuf_len(netbuf);
419 
420 			htc_msg = (HTC_UNKNOWN_MSG *) netdata;
421 			message_id = HTC_GET_FIELD(htc_msg, HTC_UNKNOWN_MSG,
422 						   MESSAGEID);
423 
424 			switch (message_id) {
425 			default:
426 				/* handle HTC control message */
427 				if (target->CtrlResponseProcessing) {
428 					/* this is a fatal error, target should
429 					 * not be sending unsolicited messages
430 					 * on the endpoint 0
431 					 */
432 					AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
433 							("HTC Rx Ctrl still processing\n"));
434 					status = QDF_STATUS_E_FAILURE;
435 					QDF_BUG(false);
436 					break;
437 				}
438 
439 				LOCK_HTC_RX(target);
440 				target->CtrlResponseLength =
441 					min((int)netlen,
442 					    HTC_MAX_CONTROL_MESSAGE_LENGTH);
443 				qdf_mem_copy(target->CtrlResponseBuffer,
444 					     netdata,
445 					     target->CtrlResponseLength);
446 
447 				/* Requester will clear this flag */
448 				target->CtrlResponseProcessing = true;
449 				UNLOCK_HTC_RX(target);
450 				qdf_event_set(&target->ctrl_response_valid);
451 				break;
452 #ifdef HTC_MSG_WAKEUP_FROM_SUSPEND_ID
453 			case HTC_MSG_WAKEUP_FROM_SUSPEND_ID:
454 				AR_DEBUG_PRINTF(ATH_DEBUG_ANY,
455 					("Received initial wake up"));
456 				htc_credit_record(HTC_INITIAL_WAKE_UP,
457 					pEndpoint->TxCredits,
458 					HTC_PACKET_QUEUE_DEPTH(
459 					&pEndpoint->TxQueue));
460 				info = &target->HTCInitInfo;
461 				if (info && info->target_initial_wakeup_cb)
462 					info->target_initial_wakeup_cb(
463 						info->target_psoc);
464 				else
465 					AR_DEBUG_PRINTF(ATH_DEBUG_ANY,
466 						("No initial wake up cb"));
467 				break;
468 #endif
469 			case HTC_MSG_SEND_SUSPEND_COMPLETE:
470 				wow_nack = false;
471 				reason_code = 0;
472 				htc_credit_record(HTC_SUSPEND_ACK,
473 					pEndpoint->TxCredits,
474 					HTC_PACKET_QUEUE_DEPTH(
475 					&pEndpoint->TxQueue));
476 				target->HTCInitInfo.TargetSendSuspendComplete(
477 					target->HTCInitInfo.target_psoc,
478 					wow_nack, reason_code);
479 
480 				break;
481 			case HTC_MSG_NACK_SUSPEND:
482 				wow_nack = true;
483 				reason_code = HTC_GET_FIELD(htc_msg,
484 							    HTC_UNKNOWN_MSG,
485 							    METADATA);
486 				htc_credit_record(HTC_SUSPEND_ACK,
487 					pEndpoint->TxCredits,
488 					HTC_PACKET_QUEUE_DEPTH(
489 					&pEndpoint->TxQueue));
490 				target->HTCInitInfo.TargetSendSuspendComplete(
491 					target->HTCInitInfo.target_psoc,
492 					wow_nack, reason_code);
493 				break;
494 			}
495 
496 			htc_rx_nbuf_free(netbuf);
497 			netbuf = NULL;
498 			break;
499 		}
500 
501 		/* the current message based HIF architecture allocates net bufs
502 		 * for recv packets since this layer bridges that HIF to upper
503 		 * layers , which expects HTC packets, we form the packets here
504 		 * TODO_FIXME
505 		 */
506 		pPacket = allocate_htc_packet_container(target);
507 		if (!pPacket) {
508 			status = QDF_STATUS_E_RESOURCES;
509 			break;
510 		}
511 		pPacket->Status = QDF_STATUS_SUCCESS;
512 		pPacket->Endpoint = htc_ep_id;
513 		pPacket->pPktContext = netbuf;
514 		pPacket->pBuffer = qdf_nbuf_data(netbuf) + HTC_HDR_LENGTH;
515 		pPacket->ActualLength = netlen - HTC_HEADER_LEN - trailerlen;
516 
517 		qdf_nbuf_pull_head(netbuf, HTC_HEADER_LEN);
518 		qdf_nbuf_set_pktlen(netbuf, pPacket->ActualLength);
519 
520 		do_recv_completion_pkt(pEndpoint, pPacket);
521 
522 		/* recover the packet container */
523 		free_htc_packet_container(target, pPacket);
524 
525 		netbuf = NULL;
526 
527 	} while (false);
528 
529 #ifdef RX_SG_SUPPORT
530 _out:
531 #endif
532 
533 	if (netbuf)
534 		htc_rx_nbuf_free(netbuf);
535 
536 	return status;
537 
538 }
539 
540 A_STATUS htc_add_receive_pkt_multiple(HTC_HANDLE HTCHandle,
541 				      HTC_PACKET_QUEUE *pPktQueue)
542 {
543 	HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
544 	HTC_ENDPOINT *pEndpoint;
545 	HTC_PACKET *pFirstPacket;
546 	A_STATUS status = A_OK;
547 	HTC_PACKET *pPacket;
548 
549 	pFirstPacket = htc_get_pkt_at_head(pPktQueue);
550 
551 	if (!pFirstPacket) {
552 		A_ASSERT(false);
553 		return A_EINVAL;
554 	}
555 
556 	if (pFirstPacket->Endpoint >= ENDPOINT_MAX) {
557 		A_ASSERT(false);
558 		return A_EINVAL;
559 	}
560 
561 	AR_DEBUG_PRINTF(ATH_DEBUG_RECV,
562 			("+- htc_add_receive_pkt_multiple : endPointId: %d, cnt:%d, length: %d\n",
563 			 pFirstPacket->Endpoint,
564 			 HTC_PACKET_QUEUE_DEPTH(pPktQueue),
565 			 pFirstPacket->BufferLength));
566 
567 	pEndpoint = &target->endpoint[pFirstPacket->Endpoint];
568 
569 	LOCK_HTC_RX(target);
570 
571 	do {
572 
573 		if (HTC_STOPPING(target)) {
574 			status = A_ERROR;
575 			break;
576 		}
577 
578 		/* store receive packets */
579 		HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(&pEndpoint->RxBufferHoldQueue,
580 						  pPktQueue);
581 
582 	} while (false);
583 
584 	UNLOCK_HTC_RX(target);
585 
586 	if (A_FAILED(status)) {
587 		/* walk through queue and mark each one canceled */
588 		HTC_PACKET_QUEUE_ITERATE_ALLOW_REMOVE(pPktQueue, pPacket) {
589 			pPacket->Status = QDF_STATUS_E_CANCELED;
590 		}
591 		HTC_PACKET_QUEUE_ITERATE_END;
592 
593 		do_recv_completion(pEndpoint, pPktQueue);
594 	}
595 
596 	return status;
597 }
598 
599 void htc_flush_rx_hold_queue(HTC_TARGET *target, HTC_ENDPOINT *pEndpoint)
600 {
601 	HTC_PACKET *pPacket;
602 
603 	LOCK_HTC_RX(target);
604 
605 	while (1) {
606 		pPacket = htc_packet_dequeue(&pEndpoint->RxBufferHoldQueue);
607 		if (!pPacket)
608 			break;
609 		UNLOCK_HTC_RX(target);
610 		pPacket->Status = QDF_STATUS_E_CANCELED;
611 		pPacket->ActualLength = 0;
612 		AR_DEBUG_PRINTF(ATH_DEBUG_RECV,
613 				("Flushing RX packet:%pK, length:%d, ep:%d\n",
614 				 pPacket, pPacket->BufferLength,
615 				 pPacket->Endpoint));
616 		/* give the packet back */
617 		do_recv_completion_pkt(pEndpoint, pPacket);
618 		LOCK_HTC_RX(target);
619 	}
620 
621 	UNLOCK_HTC_RX(target);
622 }
623 
624 void htc_recv_init(HTC_TARGET *target)
625 {
626 	/* Initialize ctrl_response_valid to block */
627 	qdf_event_create(&target->ctrl_response_valid);
628 }
629 
630 /* polling routine to wait for a control packet to be received */
631 QDF_STATUS htc_wait_recv_ctrl_message(HTC_TARGET *target)
632 {
633 /*    int count = HTC_TARGET_MAX_RESPONSE_POLL; */
634 
635 	AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("+HTCWaitCtrlMessageRecv\n"));
636 
637 	/* Wait for BMI request/response transaction to complete */
638 	if (qdf_wait_single_event(&target->ctrl_response_valid,
639 				  (target->HTCInitInfo.htc_ready_timeout_ms))) {
640 		AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
641 			("Failed to receive control message\n"));
642 		return QDF_STATUS_E_FAILURE;
643 	}
644 
645 	LOCK_HTC_RX(target);
646 	/* caller will clear this flag */
647 	target->CtrlResponseProcessing = true;
648 
649 	UNLOCK_HTC_RX(target);
650 
651 	AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("-HTCWaitCtrlMessageRecv success\n"));
652 	return QDF_STATUS_SUCCESS;
653 }
654 
655 static A_STATUS htc_process_trailer(HTC_TARGET *target,
656 				    uint8_t *pBuffer,
657 				    int Length, HTC_ENDPOINT_ID FromEndpoint)
658 {
659 	HTC_RECORD_HDR *pRecord;
660 	uint8_t htc_rec_id;
661 	uint8_t htc_rec_len;
662 	uint8_t *pRecordBuf;
663 	uint8_t *pOrigBuffer;
664 	int origLength;
665 	A_STATUS status;
666 
667 	AR_DEBUG_PRINTF(ATH_DEBUG_RECV,
668 			("+htc_process_trailer (length:%d)\n", Length));
669 
670 	if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_RECV))
671 		AR_DEBUG_PRINTBUF(pBuffer, Length, "Recv Trailer");
672 
673 	pOrigBuffer = pBuffer;
674 	origLength = Length;
675 	status = A_OK;
676 
677 	while (Length > 0) {
678 
679 		if (Length < sizeof(HTC_RECORD_HDR)) {
680 			status = A_EPROTO;
681 			break;
682 		}
683 		/* these are byte aligned structs */
684 		pRecord = (HTC_RECORD_HDR *) pBuffer;
685 		Length -= sizeof(HTC_RECORD_HDR);
686 		pBuffer += sizeof(HTC_RECORD_HDR);
687 
688 		htc_rec_len = HTC_GET_FIELD(pRecord, HTC_RECORD_HDR, LENGTH);
689 		htc_rec_id = HTC_GET_FIELD(pRecord, HTC_RECORD_HDR, RECORDID);
690 
691 		if (htc_rec_len > Length) {
692 			/* no room left in buffer for record */
693 			AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
694 					("invalid record length: %d (id:%d) buffer has: %d bytes left\n",
695 					 htc_rec_len, htc_rec_id, Length));
696 			status = A_EPROTO;
697 			break;
698 		}
699 		/* start of record follows the header */
700 		pRecordBuf = pBuffer;
701 
702 		switch (htc_rec_id) {
703 		case HTC_RECORD_CREDITS:
704 			AR_DEBUG_ASSERT(htc_rec_len >=
705 					sizeof(HTC_CREDIT_REPORT));
706 			htc_process_credit_rpt(target,
707 					       (HTC_CREDIT_REPORT *) pRecordBuf,
708 					       htc_rec_len /
709 					       (sizeof(HTC_CREDIT_REPORT)),
710 					       FromEndpoint);
711 			break;
712 
713 #ifdef HIF_SDIO
714 		case HTC_RECORD_LOOKAHEAD:
715 			/* Process in HIF layer */
716 			break;
717 
718 		case HTC_RECORD_LOOKAHEAD_BUNDLE:
719 			/* Process in HIF layer */
720 			break;
721 #endif /* HIF_SDIO */
722 
723 		default:
724 			AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
725 					("HTC unhandled record: id:%d length:%d\n",
726 					 htc_rec_id, htc_rec_len));
727 			break;
728 		}
729 
730 		if (A_FAILED(status)) {
731 			break;
732 		}
733 
734 		/* advance buffer past this record for next time around */
735 		pBuffer += htc_rec_len;
736 		Length -= htc_rec_len;
737 	}
738 
739 	if (A_FAILED(status))
740 		debug_dump_bytes(pOrigBuffer, origLength, "BAD Recv Trailer");
741 
742 	AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("-htc_process_trailer\n"));
743 	return status;
744 
745 }
746