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