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