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