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