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