xref: /wlan-dirver/qca-wifi-host-cmn/htc/htc_recv.c (revision 302a1d9701784af5f4797b1a9fe07ae820b51907)
1 /*
2  * Copyright (c) 2013-2018 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 == NULL) {
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 (NULL == 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 (NULL == 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 == NULL) {
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 != NULL);
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;
245 	HTC_PACKET *pPacket;
246 	uint16_t payloadLen;
247 	uint32_t trailerlen = 0;
248 	uint8_t htc_ep_id;
249 #ifdef HTC_MSG_WAKEUP_FROM_SUSPEND_ID
250 	struct htc_init_info *info;
251 #endif
252 
253 #ifdef RX_SG_SUPPORT
254 	LOCK_HTC_RX(target);
255 	if (target->IsRxSgInprogress) {
256 		target->CurRxSgTotalLen += qdf_nbuf_len(netbuf);
257 		qdf_nbuf_queue_add(&target->RxSgQueue, netbuf);
258 		if (target->CurRxSgTotalLen == target->ExpRxSgTotalLen) {
259 			netbuf = rx_sg_to_single_netbuf(target);
260 			if (netbuf == NULL) {
261 				UNLOCK_HTC_RX(target);
262 				goto _out;
263 			}
264 		} else {
265 			netbuf = NULL;
266 			UNLOCK_HTC_RX(target);
267 			goto _out;
268 		}
269 	}
270 	UNLOCK_HTC_RX(target);
271 #endif
272 
273 	netdata = qdf_nbuf_data(netbuf);
274 	netlen = qdf_nbuf_len(netbuf);
275 
276 	HtcHdr = (HTC_FRAME_HDR *) netdata;
277 
278 	do {
279 
280 		htc_ep_id = HTC_GET_FIELD(HtcHdr, HTC_FRAME_HDR, ENDPOINTID);
281 
282 		if (htc_ep_id >= ENDPOINT_MAX) {
283 			AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
284 					("HTC Rx: invalid EndpointID=%d\n",
285 					 htc_ep_id));
286 			debug_dump_bytes((uint8_t *) HtcHdr,
287 					sizeof(HTC_FRAME_HDR),
288 					"BAD HTC Header");
289 			status = QDF_STATUS_E_FAILURE;
290 			DPTRACE(qdf_dp_trace(
291 					    netbuf,
292 					    QDF_DP_TRACE_HTC_PACKET_PTR_RECORD,
293 					    QDF_TRACE_DEFAULT_PDEV_ID,
294 					    qdf_nbuf_data_addr(netbuf),
295 					    sizeof(qdf_nbuf_data(netbuf)),
296 					    QDF_RX));
297 			break;
298 		}
299 
300 		pEndpoint = &target->endpoint[htc_ep_id];
301 
302 		/*
303 		 * If this endpoint that received a message from the target has
304 		 * a to-target HIF pipe whose send completions are polled rather
305 		 * than interrupt driven, this is a good point to ask HIF to
306 		 * check whether it has any completed sends to handle.
307 		 */
308 		if (pEndpoint->ul_is_polled)
309 			htc_send_complete_check(pEndpoint, 1);
310 
311 		payloadLen = HTC_GET_FIELD(HtcHdr, HTC_FRAME_HDR, PAYLOADLEN);
312 
313 		if (netlen < (payloadLen + HTC_HDR_LENGTH)) {
314 #ifdef RX_SG_SUPPORT
315 			LOCK_HTC_RX(target);
316 			target->IsRxSgInprogress = true;
317 			qdf_nbuf_queue_init(&target->RxSgQueue);
318 			qdf_nbuf_queue_add(&target->RxSgQueue, netbuf);
319 			target->ExpRxSgTotalLen = (payloadLen + HTC_HDR_LENGTH);
320 			target->CurRxSgTotalLen += netlen;
321 			UNLOCK_HTC_RX(target);
322 			netbuf = NULL;
323 			break;
324 #else
325 			AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
326 					("HTC Rx: insufficient length, got:%d expected =%zu\n",
327 					 netlen, payloadLen + HTC_HDR_LENGTH));
328 			debug_dump_bytes((uint8_t *) HtcHdr,
329 					 sizeof(HTC_FRAME_HDR),
330 					 "BAD RX packet length");
331 			status = QDF_STATUS_E_FAILURE;
332 			DPTRACE(qdf_dp_trace(
333 					    netbuf,
334 					    QDF_DP_TRACE_HTC_PACKET_PTR_RECORD,
335 					    QDF_TRACE_DEFAULT_PDEV_ID,
336 					    qdf_nbuf_data_addr(netbuf),
337 					    sizeof(qdf_nbuf_data(netbuf)),
338 					    QDF_RX));
339 			break;
340 #endif
341 		}
342 #ifdef HTC_EP_STAT_PROFILING
343 		LOCK_HTC_RX(target);
344 		INC_HTC_EP_STAT(pEndpoint, RxReceived, 1);
345 		UNLOCK_HTC_RX(target);
346 #endif
347 
348 		/* if (IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)) { */
349 		{
350 			uint8_t temp;
351 			A_STATUS temp_status;
352 			/* get flags to check for trailer */
353 			temp = HTC_GET_FIELD(HtcHdr, HTC_FRAME_HDR, FLAGS);
354 			if (temp & HTC_FLAGS_RECV_TRAILER) {
355 				/* extract the trailer length */
356 				temp =
357 					HTC_GET_FIELD(HtcHdr, HTC_FRAME_HDR,
358 						      CONTROLBYTES0);
359 				if ((temp < sizeof(HTC_RECORD_HDR))
360 				    || (temp > payloadLen)) {
361 					AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
362 						("htc_rx_completion_handler, invalid header (payloadlength should be :%d, CB[0] is:%d)\n",
363 						payloadLen, temp));
364 					status = QDF_STATUS_E_INVAL;
365 					break;
366 				}
367 
368 				trailerlen = temp;
369 				/* process trailer data that follows HDR +
370 				 * application payload
371 				 */
372 				temp_status = htc_process_trailer(target,
373 						((uint8_t *) HtcHdr +
374 							HTC_HDR_LENGTH +
375 							payloadLen - temp),
376 						temp, htc_ep_id);
377 				if (A_FAILED(temp_status)) {
378 					status = QDF_STATUS_E_FAILURE;
379 					break;
380 				}
381 
382 			}
383 		}
384 
385 		if (((int)payloadLen - (int)trailerlen) <= 0) {
386 			/* 0 length packet with trailer data, just drop these */
387 			break;
388 		}
389 
390 		if (htc_ep_id == ENDPOINT_0) {
391 			uint16_t message_id;
392 			HTC_UNKNOWN_MSG *htc_msg;
393 			bool wow_nack;
394 
395 			/* remove HTC header */
396 			qdf_nbuf_pull_head(netbuf, HTC_HDR_LENGTH);
397 			netdata = qdf_nbuf_data(netbuf);
398 			netlen = qdf_nbuf_len(netbuf);
399 
400 			htc_msg = (HTC_UNKNOWN_MSG *) netdata;
401 			message_id = HTC_GET_FIELD(htc_msg, HTC_UNKNOWN_MSG,
402 						   MESSAGEID);
403 
404 			switch (message_id) {
405 			default:
406 				/* handle HTC control message */
407 				if (target->CtrlResponseProcessing) {
408 					/* this is a fatal error, target should
409 					 * not be sending unsolicited messages
410 					 * on the endpoint 0
411 					 */
412 					AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
413 							("HTC Rx Ctrl still processing\n"));
414 					status = QDF_STATUS_E_FAILURE;
415 					QDF_BUG(false);
416 					break;
417 				}
418 
419 				LOCK_HTC_RX(target);
420 				target->CtrlResponseLength =
421 					min((int)netlen,
422 					    HTC_MAX_CONTROL_MESSAGE_LENGTH);
423 				qdf_mem_copy(target->CtrlResponseBuffer,
424 					     netdata,
425 					     target->CtrlResponseLength);
426 
427 				/* Requester will clear this flag */
428 				target->CtrlResponseProcessing = true;
429 				UNLOCK_HTC_RX(target);
430 
431 				qdf_event_set(&target->ctrl_response_valid);
432 				break;
433 #ifdef HTC_MSG_WAKEUP_FROM_SUSPEND_ID
434 			case HTC_MSG_WAKEUP_FROM_SUSPEND_ID:
435 				AR_DEBUG_PRINTF(ATH_DEBUG_ANY,
436 					("Received initial wake up"));
437 				htc_credit_record(HTC_INITIAL_WAKE_UP,
438 					pEndpoint->TxCredits,
439 					HTC_PACKET_QUEUE_DEPTH(
440 					&pEndpoint->TxQueue));
441 				info = &target->HTCInitInfo;
442 				if (info && info->target_initial_wakeup_cb)
443 					info->target_initial_wakeup_cb(
444 						info->target_psoc);
445 				else
446 					AR_DEBUG_PRINTF(ATH_DEBUG_ANY,
447 						("No initial wake up cb"));
448 				break;
449 #endif
450 			case HTC_MSG_SEND_SUSPEND_COMPLETE:
451 				wow_nack = false;
452 				htc_credit_record(HTC_SUSPEND_ACK,
453 					pEndpoint->TxCredits,
454 					HTC_PACKET_QUEUE_DEPTH(
455 					&pEndpoint->TxQueue));
456 				target->HTCInitInfo.TargetSendSuspendComplete(
457 					target->HTCInitInfo.target_psoc,
458 					wow_nack);
459 
460 				break;
461 			case HTC_MSG_NACK_SUSPEND:
462 				wow_nack = true;
463 				htc_credit_record(HTC_SUSPEND_ACK,
464 					pEndpoint->TxCredits,
465 					HTC_PACKET_QUEUE_DEPTH(
466 					&pEndpoint->TxQueue));
467 				target->HTCInitInfo.TargetSendSuspendComplete(
468 					target->HTCInitInfo.target_psoc,
469 					wow_nack);
470 				break;
471 			}
472 
473 			qdf_nbuf_free(netbuf);
474 			netbuf = NULL;
475 			break;
476 		}
477 
478 		/* the current message based HIF architecture allocates net bufs
479 		 * for recv packets since this layer bridges that HIF to upper
480 		 * layers , which expects HTC packets, we form the packets here
481 		 * TODO_FIXME
482 		 */
483 		pPacket = allocate_htc_packet_container(target);
484 		if (NULL == pPacket) {
485 			status = QDF_STATUS_E_RESOURCES;
486 			break;
487 		}
488 		pPacket->Status = QDF_STATUS_SUCCESS;
489 		pPacket->Endpoint = htc_ep_id;
490 		pPacket->pPktContext = netbuf;
491 		pPacket->pBuffer = qdf_nbuf_data(netbuf) + HTC_HDR_LENGTH;
492 		pPacket->ActualLength = netlen - HTC_HEADER_LEN - trailerlen;
493 
494 		qdf_nbuf_pull_head(netbuf, HTC_HEADER_LEN);
495 		qdf_nbuf_set_pktlen(netbuf, pPacket->ActualLength);
496 
497 		do_recv_completion_pkt(pEndpoint, pPacket);
498 
499 		/* recover the packet container */
500 		free_htc_packet_container(target, pPacket);
501 
502 		netbuf = NULL;
503 
504 	} while (false);
505 
506 #ifdef RX_SG_SUPPORT
507 _out:
508 #endif
509 
510 	if (netbuf != NULL)
511 		qdf_nbuf_free(netbuf);
512 
513 	return status;
514 
515 }
516 
517 A_STATUS htc_add_receive_pkt_multiple(HTC_HANDLE HTCHandle,
518 				      HTC_PACKET_QUEUE *pPktQueue)
519 {
520 	HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
521 	HTC_ENDPOINT *pEndpoint;
522 	HTC_PACKET *pFirstPacket;
523 	A_STATUS status = A_OK;
524 	HTC_PACKET *pPacket;
525 
526 	pFirstPacket = htc_get_pkt_at_head(pPktQueue);
527 
528 	if (NULL == pFirstPacket) {
529 		A_ASSERT(false);
530 		return A_EINVAL;
531 	}
532 
533 	if (pFirstPacket->Endpoint >= ENDPOINT_MAX) {
534 		A_ASSERT(false);
535 		return A_EINVAL;
536 	}
537 
538 	AR_DEBUG_PRINTF(ATH_DEBUG_RECV,
539 			("+- htc_add_receive_pkt_multiple : endPointId: %d, cnt:%d, length: %d\n",
540 			 pFirstPacket->Endpoint,
541 			 HTC_PACKET_QUEUE_DEPTH(pPktQueue),
542 			 pFirstPacket->BufferLength));
543 
544 	pEndpoint = &target->endpoint[pFirstPacket->Endpoint];
545 
546 	LOCK_HTC_RX(target);
547 
548 	do {
549 
550 		if (HTC_STOPPING(target)) {
551 			status = A_ERROR;
552 			break;
553 		}
554 
555 		/* store receive packets */
556 		HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(&pEndpoint->RxBufferHoldQueue,
557 						  pPktQueue);
558 
559 	} while (false);
560 
561 	UNLOCK_HTC_RX(target);
562 
563 	if (A_FAILED(status)) {
564 		/* walk through queue and mark each one canceled */
565 		HTC_PACKET_QUEUE_ITERATE_ALLOW_REMOVE(pPktQueue, pPacket) {
566 			pPacket->Status = QDF_STATUS_E_CANCELED;
567 		}
568 		HTC_PACKET_QUEUE_ITERATE_END;
569 
570 		do_recv_completion(pEndpoint, pPktQueue);
571 	}
572 
573 	return status;
574 }
575 
576 void htc_flush_rx_hold_queue(HTC_TARGET *target, HTC_ENDPOINT *pEndpoint)
577 {
578 	HTC_PACKET *pPacket;
579 
580 	LOCK_HTC_RX(target);
581 
582 	while (1) {
583 		pPacket = htc_packet_dequeue(&pEndpoint->RxBufferHoldQueue);
584 		if (pPacket == NULL)
585 			break;
586 		UNLOCK_HTC_RX(target);
587 		pPacket->Status = QDF_STATUS_E_CANCELED;
588 		pPacket->ActualLength = 0;
589 		AR_DEBUG_PRINTF(ATH_DEBUG_RECV,
590 				("Flushing RX packet:%pK, length:%d, ep:%d\n",
591 				 pPacket, pPacket->BufferLength,
592 				 pPacket->Endpoint));
593 		/* give the packet back */
594 		do_recv_completion_pkt(pEndpoint, pPacket);
595 		LOCK_HTC_RX(target);
596 	}
597 
598 	UNLOCK_HTC_RX(target);
599 }
600 
601 void htc_recv_init(HTC_TARGET *target)
602 {
603 	/* Initialize ctrl_response_valid to block */
604 	qdf_event_create(&target->ctrl_response_valid);
605 }
606 
607 /* polling routine to wait for a control packet to be received */
608 QDF_STATUS htc_wait_recv_ctrl_message(HTC_TARGET *target)
609 {
610 /*    int count = HTC_TARGET_MAX_RESPONSE_POLL; */
611 
612 	AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("+HTCWaitCtrlMessageRecv\n"));
613 
614 	/* Wait for BMI request/response transaction to complete */
615 	if (qdf_wait_single_event(&target->ctrl_response_valid,
616 				  HTC_CONTROL_RX_TIMEOUT)) {
617 		AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
618 			("Failed to receive control message\n"));
619 		return QDF_STATUS_E_FAILURE;
620 	}
621 
622 	LOCK_HTC_RX(target);
623 	/* caller will clear this flag */
624 	target->CtrlResponseProcessing = true;
625 
626 	UNLOCK_HTC_RX(target);
627 
628 	AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("-HTCWaitCtrlMessageRecv success\n"));
629 	return QDF_STATUS_SUCCESS;
630 }
631 
632 static A_STATUS htc_process_trailer(HTC_TARGET *target,
633 				    uint8_t *pBuffer,
634 				    int Length, HTC_ENDPOINT_ID FromEndpoint)
635 {
636 	HTC_RECORD_HDR *pRecord;
637 	uint8_t htc_rec_id;
638 	uint8_t htc_rec_len;
639 	uint8_t *pRecordBuf;
640 	uint8_t *pOrigBuffer;
641 	int origLength;
642 	A_STATUS status;
643 
644 	AR_DEBUG_PRINTF(ATH_DEBUG_RECV,
645 			("+htc_process_trailer (length:%d)\n", Length));
646 
647 	if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_RECV))
648 		AR_DEBUG_PRINTBUF(pBuffer, Length, "Recv Trailer");
649 
650 	pOrigBuffer = pBuffer;
651 	origLength = Length;
652 	status = A_OK;
653 
654 	while (Length > 0) {
655 
656 		if (Length < sizeof(HTC_RECORD_HDR)) {
657 			status = A_EPROTO;
658 			break;
659 		}
660 		/* these are byte aligned structs */
661 		pRecord = (HTC_RECORD_HDR *) pBuffer;
662 		Length -= sizeof(HTC_RECORD_HDR);
663 		pBuffer += sizeof(HTC_RECORD_HDR);
664 
665 		htc_rec_len = HTC_GET_FIELD(pRecord, HTC_RECORD_HDR, LENGTH);
666 		htc_rec_id = HTC_GET_FIELD(pRecord, HTC_RECORD_HDR, RECORDID);
667 
668 		if (htc_rec_len > Length) {
669 			/* no room left in buffer for record */
670 			AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
671 					("invalid record length: %d (id:%d) buffer has: %d bytes left\n",
672 					 htc_rec_len, htc_rec_id, Length));
673 			status = A_EPROTO;
674 			break;
675 		}
676 		/* start of record follows the header */
677 		pRecordBuf = pBuffer;
678 
679 		switch (htc_rec_id) {
680 		case HTC_RECORD_CREDITS:
681 			AR_DEBUG_ASSERT(htc_rec_len >=
682 					sizeof(HTC_CREDIT_REPORT));
683 			htc_process_credit_rpt(target,
684 					       (HTC_CREDIT_REPORT *) pRecordBuf,
685 					       htc_rec_len /
686 					       (sizeof(HTC_CREDIT_REPORT)),
687 					       FromEndpoint);
688 			break;
689 
690 #ifdef HIF_SDIO
691 		case HTC_RECORD_LOOKAHEAD:
692 			/* Process in HIF layer */
693 			break;
694 
695 		case HTC_RECORD_LOOKAHEAD_BUNDLE:
696 			/* Process in HIF layer */
697 			break;
698 #endif /* HIF_SDIO */
699 
700 		default:
701 			AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
702 					("HTC unhandled record: id:%d length:%d\n",
703 					 htc_rec_id, htc_rec_len));
704 			break;
705 		}
706 
707 		if (A_FAILED(status)) {
708 			break;
709 		}
710 
711 		/* advance buffer past this record for next time around */
712 		pBuffer += htc_rec_len;
713 		Length -= htc_rec_len;
714 	}
715 
716 	if (A_FAILED(status))
717 		debug_dump_bytes(pOrigBuffer, origLength, "BAD Recv Trailer");
718 
719 	AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("-htc_process_trailer\n"));
720 	return status;
721 
722 }
723