blob: d56f6e509741f7c129c4f1da196269888003b6a2 [file] [log] [blame]
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001/*
Yue Maec9e71c2016-02-26 18:52:20 -08002 * Copyright (c) 2013-2016 The Linux Foundation. All rights reserved.
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08003 *
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"
Vishwajith Upendra70f8b6e2016-03-01 16:28:23 +053030#include <qdf_nbuf.h> /* qdf_nbuf_t */
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -080031
Leo Chang19a7dd22015-11-13 13:35:15 -080032/* HTC Control message receive timeout msec */
33#define HTC_CONTROL_RX_TIMEOUT 3000
34
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -080035#ifdef DEBUG
Yue Mab16cf302016-03-08 18:30:25 -080036void debug_dump_bytes(uint8_t *buffer, uint16_t length, char *pDescription)
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -080037{
Yue Mab16cf302016-03-08 18:30:25 -080038 int8_t stream[60];
39 int8_t byteOffsetStr[10];
40 uint32_t i;
41 uint16_t offset, count, byteOffset;
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -080042
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);
Yue Mab16cf302016-03-08 18:30:25 -080061 qdf_mem_zero(stream, 60);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -080062 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
Yue Mab16cf302016-03-08 18:30:25 -080075void debug_dump_bytes(uint8_t *buffer, uint16_t length, char *pDescription)
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -080076{
77}
78#endif
79
80static A_STATUS htc_process_trailer(HTC_TARGET *target,
Yue Mab16cf302016-03-08 18:30:25 -080081 uint8_t *pBuffer,
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -080082 int Length, HTC_ENDPOINT_ID FromEndpoint);
83
84static 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
133static 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
142void 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
149void htc_unblock_recv(HTC_HANDLE HTCHandle)
150{
151 /* TODO find the Need in new model */
152}
153
154void htc_enable_recv(HTC_HANDLE HTCHandle)
155{
156
157 /* TODO find the Need in new model */
158}
159
160void htc_disable_recv(HTC_HANDLE HTCHandle)
161{
162
163 /* TODO find the Need in new model */
164}
165
166int htc_get_num_recv_buffers(HTC_HANDLE HTCHandle, HTC_ENDPOINT_ID Endpoint)
167{
168 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
Houston Hoffman29573d92015-10-20 17:49:44 -0700169 HTC_ENDPOINT *pEndpoint = &target->endpoint[Endpoint];
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800170 return HTC_PACKET_QUEUE_DEPTH(&pEndpoint->RxBufferHoldQueue);
171}
172
173HTC_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
193void 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
Vishwajith Upendra70f8b6e2016-03-01 16:28:23 +0530210qdf_nbuf_t rx_sg_to_single_netbuf(HTC_TARGET *target)
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800211{
Vishwajith Upendra70f8b6e2016-03-01 16:28:23 +0530212 qdf_nbuf_t skb;
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800213 uint8_t *anbdata;
214 uint8_t *anbdata_new;
215 uint32_t anblen;
Vishwajith Upendra70f8b6e2016-03-01 16:28:23 +0530216 qdf_nbuf_t new_skb = NULL;
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800217 uint32_t sg_queue_len;
Vishwajith Upendra70f8b6e2016-03-01 16:28:23 +0530218 qdf_nbuf_queue_t *rx_sg_queue = &target->RxSgQueue;
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800219
Vishwajith Upendra70f8b6e2016-03-01 16:28:23 +0530220 sg_queue_len = qdf_nbuf_queue_len(rx_sg_queue);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800221
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
Vishwajith Upendra70f8b6e2016-03-01 16:28:23 +0530228 new_skb = qdf_nbuf_alloc(target->ExpRxSgTotalLen, 0, 4, false);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800229 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
Vishwajith Upendra70f8b6e2016-03-01 16:28:23 +0530236 qdf_nbuf_peek_header(new_skb, &anbdata_new, &anblen);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800237
Vishwajith Upendra70f8b6e2016-03-01 16:28:23 +0530238 skb = qdf_nbuf_queue_remove(rx_sg_queue);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800239 do {
Vishwajith Upendra70f8b6e2016-03-01 16:28:23 +0530240 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);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800246 } while (skb != NULL);
247
248 RESET_RX_SG_CONFIG(target);
249 return new_skb;
250
251_failed:
252
Vishwajith Upendra70f8b6e2016-03-01 16:28:23 +0530253 while ((skb = qdf_nbuf_queue_remove(rx_sg_queue)) != NULL)
254 qdf_nbuf_free(skb);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800255
256 RESET_RX_SG_CONFIG(target);
257 return NULL;
258}
259#endif
260
Vishwajith Upendra70f8b6e2016-03-01 16:28:23 +0530261QDF_STATUS htc_rx_completion_handler(void *Context, qdf_nbuf_t netbuf,
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800262 uint8_t pipeID)
263{
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +0530264 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800265 HTC_FRAME_HDR *HtcHdr;
266 HTC_TARGET *target = (HTC_TARGET *) Context;
267 uint8_t *netdata;
268 uint32_t netlen;
269 HTC_ENDPOINT *pEndpoint;
270 HTC_PACKET *pPacket;
Yue Mab16cf302016-03-08 18:30:25 -0800271 uint16_t payloadLen;
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800272 uint32_t trailerlen = 0;
Yue Mab16cf302016-03-08 18:30:25 -0800273 uint8_t htc_ep_id;
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800274
275#ifdef RX_SG_SUPPORT
276 LOCK_HTC_RX(target);
277 if (target->IsRxSgInprogress) {
Vishwajith Upendra70f8b6e2016-03-01 16:28:23 +0530278 target->CurRxSgTotalLen += qdf_nbuf_len(netbuf);
279 qdf_nbuf_queue_add(&target->RxSgQueue, netbuf);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800280 if (target->CurRxSgTotalLen == target->ExpRxSgTotalLen) {
281 netbuf = rx_sg_to_single_netbuf(target);
282 if (netbuf == NULL) {
283 UNLOCK_HTC_RX(target);
284 goto _out;
285 }
286 } else {
287 netbuf = NULL;
288 UNLOCK_HTC_RX(target);
289 goto _out;
290 }
291 }
292 UNLOCK_HTC_RX(target);
293#endif
294
Vishwajith Upendra70f8b6e2016-03-01 16:28:23 +0530295 netdata = qdf_nbuf_data(netbuf);
296 netlen = qdf_nbuf_len(netbuf);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800297
298 HtcHdr = (HTC_FRAME_HDR *) netdata;
299
300 do {
301
302 htc_ep_id = HTC_GET_FIELD(HtcHdr, HTC_FRAME_HDR, ENDPOINTID);
303
304 if (htc_ep_id >= ENDPOINT_MAX) {
305 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
306 ("HTC Rx: invalid EndpointID=%d\n",
307 htc_ep_id));
Yue Mab16cf302016-03-08 18:30:25 -0800308 debug_dump_bytes((uint8_t *) HtcHdr,
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800309 sizeof(HTC_FRAME_HDR), "BAD HTC Header");
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +0530310 status = QDF_STATUS_E_FAILURE;
311 QDF_BUG(0);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800312 break;
313 }
314
Houston Hoffman29573d92015-10-20 17:49:44 -0700315 pEndpoint = &target->endpoint[htc_ep_id];
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800316
317 /*
318 * If this endpoint that received a message from the target has
319 * a to-target HIF pipe whose send completions are polled rather
320 * than interrupt-driven, this is a good point to ask HIF to check
321 * whether it has any completed sends to handle.
322 */
323 if (pEndpoint->ul_is_polled) {
324 htc_send_complete_check(pEndpoint, 1);
325 }
326
327 payloadLen = HTC_GET_FIELD(HtcHdr, HTC_FRAME_HDR, PAYLOADLEN);
328
329 if (netlen < (payloadLen + HTC_HDR_LENGTH)) {
330#ifdef RX_SG_SUPPORT
331 LOCK_HTC_RX(target);
332 target->IsRxSgInprogress = true;
Vishwajith Upendra70f8b6e2016-03-01 16:28:23 +0530333 qdf_nbuf_queue_init(&target->RxSgQueue);
334 qdf_nbuf_queue_add(&target->RxSgQueue, netbuf);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800335 target->ExpRxSgTotalLen = (payloadLen + HTC_HDR_LENGTH);
336 target->CurRxSgTotalLen += netlen;
337 UNLOCK_HTC_RX(target);
338 netbuf = NULL;
339 break;
340#else
341 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
342 ("HTC Rx: insufficient length, got:%d expected =%zu\n",
343 netlen, payloadLen + HTC_HDR_LENGTH));
Yue Mab16cf302016-03-08 18:30:25 -0800344 debug_dump_bytes((uint8_t *) HtcHdr,
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800345 sizeof(HTC_FRAME_HDR),
346 "BAD RX packet length");
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +0530347 status = QDF_STATUS_E_FAILURE;
348 QDF_BUG(0);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800349 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 {
Yue Mab16cf302016-03-08 18:30:25 -0800360 uint8_t temp;
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800361 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));
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +0530374 status = QDF_STATUS_E_INVAL;
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800375 break;
376 }
377
378 trailerlen = temp;
379 /* process trailer data that follows HDR + application payload */
380 temp_status = htc_process_trailer(target,
Yue Mab16cf302016-03-08 18:30:25 -0800381 ((uint8_t *) HtcHdr +
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800382 HTC_HDR_LENGTH +
383 payloadLen - temp),
384 temp, htc_ep_id);
385 if (A_FAILED(temp_status)) {
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +0530386 status = QDF_STATUS_E_FAILURE;
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800387 break;
388 }
389
390 }
391 }
392
393 if (((int)payloadLen - (int)trailerlen) <= 0) {
394 /* zero length packet with trailer data, just drop these */
395 break;
396 }
397
398 if (htc_ep_id == ENDPOINT_0) {
Yue Mab16cf302016-03-08 18:30:25 -0800399 uint16_t message_id;
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800400 HTC_UNKNOWN_MSG *htc_msg;
Houston Hoffman61fad9f2016-04-14 17:09:37 -0700401 bool wow_nack;
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800402
403 /* remove HTC header */
Vishwajith Upendra70f8b6e2016-03-01 16:28:23 +0530404 qdf_nbuf_pull_head(netbuf, HTC_HDR_LENGTH);
405 netdata = qdf_nbuf_data(netbuf);
406 netlen = qdf_nbuf_len(netbuf);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800407
408 htc_msg = (HTC_UNKNOWN_MSG *) netdata;
409 message_id =
410 HTC_GET_FIELD(htc_msg, HTC_UNKNOWN_MSG, MESSAGEID);
411
412 switch (message_id) {
413 default:
414 /* handle HTC control message */
415 if (target->CtrlResponseProcessing) {
416 /* this is a fatal error, target should not be sending unsolicited messages
417 * on the endpoint 0 */
418 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
419 ("HTC Rx Ctrl still processing\n"));
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +0530420 status = QDF_STATUS_E_FAILURE;
421 QDF_BUG(false);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800422 break;
423 }
424
425 LOCK_HTC_RX(target);
426 target->CtrlResponseLength =
427 min((int)netlen,
428 HTC_MAX_CONTROL_MESSAGE_LENGTH);
Yue Mab16cf302016-03-08 18:30:25 -0800429 qdf_mem_copy(target->CtrlResponseBuffer,
430 netdata,
431 target->CtrlResponseLength);
Prashanth Bhatta53047572015-11-05 11:43:17 -0800432
433 /* Requester will clear this flag */
434 target->CtrlResponseProcessing = true;
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800435 UNLOCK_HTC_RX(target);
436
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +0530437 qdf_event_set(&target->ctrl_response_valid);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800438 break;
439 case HTC_MSG_SEND_SUSPEND_COMPLETE:
Houston Hoffman61fad9f2016-04-14 17:09:37 -0700440 wow_nack = false;
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800441 LOCK_HTC_CREDIT(target);
442 htc_credit_record(HTC_SUSPEND_ACK,
443 pEndpoint->TxCredits,
444 HTC_PACKET_QUEUE_DEPTH(
445 &pEndpoint->TxQueue));
446 UNLOCK_HTC_CREDIT(target);
Houston Hoffman61fad9f2016-04-14 17:09:37 -0700447 target->HTCInitInfo.TargetSendSuspendComplete(
448 target->HTCInitInfo.pContext,
449 wow_nack);
450
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800451 break;
452 case HTC_MSG_NACK_SUSPEND:
Houston Hoffman61fad9f2016-04-14 17:09:37 -0700453 wow_nack = true;
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800454 LOCK_HTC_CREDIT(target);
455 htc_credit_record(HTC_SUSPEND_ACK,
456 pEndpoint->TxCredits,
457 HTC_PACKET_QUEUE_DEPTH(
458 &pEndpoint->TxQueue));
459 UNLOCK_HTC_CREDIT(target);
460
Houston Hoffman61fad9f2016-04-14 17:09:37 -0700461 target->HTCInitInfo.TargetSendSuspendComplete(
462 target->HTCInitInfo.pContext,
463 wow_nack);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800464 break;
465 }
466
Vishwajith Upendra70f8b6e2016-03-01 16:28:23 +0530467 qdf_nbuf_free(netbuf);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800468 netbuf = NULL;
469 break;
470 }
471
472 /* the current message based HIF architecture allocates net bufs for recv packets
473 * since this layer bridges that HIF to upper layers , which expects HTC packets,
474 * we form the packets here
475 * TODO_FIXME */
476 pPacket = allocate_htc_packet_container(target);
477 if (NULL == pPacket) {
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +0530478 status = QDF_STATUS_E_RESOURCES;
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800479 break;
480 }
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +0530481 pPacket->Status = QDF_STATUS_SUCCESS;
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800482 pPacket->Endpoint = htc_ep_id;
483 pPacket->pPktContext = netbuf;
Vishwajith Upendra70f8b6e2016-03-01 16:28:23 +0530484 pPacket->pBuffer = qdf_nbuf_data(netbuf) + HTC_HDR_LENGTH;
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800485 pPacket->ActualLength = netlen - HTC_HEADER_LEN - trailerlen;
486
Vishwajith Upendra70f8b6e2016-03-01 16:28:23 +0530487 qdf_nbuf_pull_head(netbuf, HTC_HEADER_LEN);
488 qdf_nbuf_set_pktlen(netbuf, pPacket->ActualLength);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800489
490 recv_packet_completion(target, pEndpoint, pPacket);
491 /* recover the packet container */
492 free_htc_packet_container(target, pPacket);
493 netbuf = NULL;
494
495 } while (false);
496
497#ifdef RX_SG_SUPPORT
498_out:
499#endif
500
501 if (netbuf != NULL) {
Vishwajith Upendra70f8b6e2016-03-01 16:28:23 +0530502 qdf_nbuf_free(netbuf);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800503 }
504
505 return status;
506
507}
508
509A_STATUS htc_add_receive_pkt_multiple(HTC_HANDLE HTCHandle,
510 HTC_PACKET_QUEUE *pPktQueue)
511{
512 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
513 HTC_ENDPOINT *pEndpoint;
514 HTC_PACKET *pFirstPacket;
515 A_STATUS status = A_OK;
516 HTC_PACKET *pPacket;
517
518 pFirstPacket = htc_get_pkt_at_head(pPktQueue);
519
520 if (NULL == pFirstPacket) {
521 A_ASSERT(false);
522 return A_EINVAL;
523 }
524
525 AR_DEBUG_ASSERT(pFirstPacket->Endpoint < ENDPOINT_MAX);
526
527 AR_DEBUG_PRINTF(ATH_DEBUG_RECV,
528 ("+- htc_add_receive_pkt_multiple : endPointId: %d, cnt:%d, length: %d\n",
529 pFirstPacket->Endpoint,
530 HTC_PACKET_QUEUE_DEPTH(pPktQueue),
531 pFirstPacket->BufferLength));
532
Houston Hoffman29573d92015-10-20 17:49:44 -0700533 pEndpoint = &target->endpoint[pFirstPacket->Endpoint];
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800534
535 LOCK_HTC_RX(target);
536
537 do {
538
539 if (HTC_STOPPING(target)) {
540 status = A_ERROR;
541 break;
542 }
543
544 /* store receive packets */
545 HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(&pEndpoint->RxBufferHoldQueue,
546 pPktQueue);
547
548 } while (false);
549
550 UNLOCK_HTC_RX(target);
551
552 if (A_FAILED(status)) {
553 /* walk through queue and mark each one canceled */
554 HTC_PACKET_QUEUE_ITERATE_ALLOW_REMOVE(pPktQueue, pPacket) {
555 pPacket->Status = A_ECANCELED;
556 }
557 HTC_PACKET_QUEUE_ITERATE_END;
558
559 do_recv_completion(pEndpoint, pPktQueue);
560 }
561
562 return status;
563}
564
565A_STATUS htc_add_receive_pkt(HTC_HANDLE HTCHandle, HTC_PACKET *pPacket)
566{
567 HTC_PACKET_QUEUE queue;
568 INIT_HTC_PACKET_QUEUE_AND_ADD(&queue, pPacket);
569 return htc_add_receive_pkt_multiple(HTCHandle, &queue);
570}
571
572void htc_flush_rx_hold_queue(HTC_TARGET *target, HTC_ENDPOINT *pEndpoint)
573{
574 HTC_PACKET *pPacket;
575 HTC_PACKET_QUEUE container;
576
577 LOCK_HTC_RX(target);
578
579 while (1) {
580 pPacket = htc_packet_dequeue(&pEndpoint->RxBufferHoldQueue);
581 if (NULL == pPacket) {
582 break;
583 }
584 UNLOCK_HTC_RX(target);
585 pPacket->Status = A_ECANCELED;
586 pPacket->ActualLength = 0;
587 AR_DEBUG_PRINTF(ATH_DEBUG_RECV,
588 (" Flushing RX packet:%p, length:%d, ep:%d \n",
589 pPacket, pPacket->BufferLength,
590 pPacket->Endpoint));
591 INIT_HTC_PACKET_QUEUE_AND_ADD(&container, pPacket);
592 /* give the packet back */
593 do_recv_completion(pEndpoint, &container);
594 LOCK_HTC_RX(target);
595 }
596
597 UNLOCK_HTC_RX(target);
598}
599
600void htc_recv_init(HTC_TARGET *target)
601{
Leo Chang19a7dd22015-11-13 13:35:15 -0800602 /* Initialize ctrl_response_valid to block */
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +0530603 qdf_event_create(&target->ctrl_response_valid);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800604}
605
606/* polling routine to wait for a control packet to be received */
607A_STATUS htc_wait_recv_ctrl_message(HTC_TARGET *target)
608{
609/* int count = HTC_TARGET_MAX_RESPONSE_POLL; */
610
611 AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("+HTCWaitCtrlMessageRecv\n"));
612
613 /* Wait for BMI request/response transaction to complete */
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +0530614 if (qdf_wait_single_event(&target->ctrl_response_valid,
615 qdf_system_msecs_to_ticks(HTC_CONTROL_RX_TIMEOUT))) {
616 QDF_BUG(0);
Leo Chang19a7dd22015-11-13 13:35:15 -0800617 return A_ERROR;
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800618 }
619
620 LOCK_HTC_RX(target);
621 /* caller will clear this flag */
622 target->CtrlResponseProcessing = true;
623
624 UNLOCK_HTC_RX(target);
625
626#if 0
627 while (count > 0) {
628
629 LOCK_HTC_RX(target);
630
631 if (target->CtrlResponseValid) {
632 target->CtrlResponseValid = false;
633 /* caller will clear this flag */
634 target->CtrlResponseProcessing = true;
635 UNLOCK_HTC_RX(target);
636 break;
637 }
638
639 UNLOCK_HTC_RX(target);
640
641 count--;
642 A_MSLEEP(HTC_TARGET_RESPONSE_POLL_MS);
643 }
644
645 if (count <= 0) {
646 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
647 ("-HTCWaitCtrlMessageRecv: Timeout!\n"));
648 return A_ECOMM;
649 }
650#endif
651
652 AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("-HTCWaitCtrlMessageRecv success\n"));
653 return A_OK;
654}
655
656static A_STATUS htc_process_trailer(HTC_TARGET *target,
Yue Mab16cf302016-03-08 18:30:25 -0800657 uint8_t *pBuffer,
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800658 int Length, HTC_ENDPOINT_ID FromEndpoint)
659{
660 HTC_RECORD_HDR *pRecord;
Yue Mab16cf302016-03-08 18:30:25 -0800661 uint8_t htc_rec_id;
662 uint8_t htc_rec_len;
663 uint8_t *pRecordBuf;
664 uint8_t *pOrigBuffer;
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800665 int origLength;
666 A_STATUS status;
667
668 AR_DEBUG_PRINTF(ATH_DEBUG_RECV,
669 ("+htc_process_trailer (length:%d) \n", Length));
670
671 if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_RECV)) {
672 AR_DEBUG_PRINTBUF(pBuffer, Length, "Recv Trailer");
673 }
674
675 pOrigBuffer = pBuffer;
676 origLength = Length;
677 status = A_OK;
678
679 while (Length > 0) {
680
681 if (Length < sizeof(HTC_RECORD_HDR)) {
682 status = A_EPROTO;
683 break;
684 }
685 /* these are byte aligned structs */
686 pRecord = (HTC_RECORD_HDR *) pBuffer;
687 Length -= sizeof(HTC_RECORD_HDR);
688 pBuffer += sizeof(HTC_RECORD_HDR);
689
690 htc_rec_len = HTC_GET_FIELD(pRecord, HTC_RECORD_HDR, LENGTH);
691 htc_rec_id = HTC_GET_FIELD(pRecord, HTC_RECORD_HDR, RECORDID);
692
693 if (htc_rec_len > Length) {
694 /* no room left in buffer for record */
695 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
696 (" invalid record length: %d (id:%d) buffer has: %d bytes left \n",
697 htc_rec_len, htc_rec_id, Length));
698 status = A_EPROTO;
699 break;
700 }
701 /* start of record follows the header */
702 pRecordBuf = pBuffer;
703
704 switch (htc_rec_id) {
705 case HTC_RECORD_CREDITS:
706 AR_DEBUG_ASSERT(htc_rec_len >=
707 sizeof(HTC_CREDIT_REPORT));
708 htc_process_credit_rpt(target,
709 (HTC_CREDIT_REPORT *) pRecordBuf,
710 htc_rec_len /
711 (sizeof(HTC_CREDIT_REPORT)),
712 FromEndpoint);
713 break;
714
715#ifdef HIF_SDIO
716 case HTC_RECORD_LOOKAHEAD:
717 /* Process in HIF layer */
718 break;
719
720 case HTC_RECORD_LOOKAHEAD_BUNDLE:
721 /* Process in HIF layer */
722 break;
723#endif /* HIF_SDIO */
724
725 default:
726 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
727 (" HTC unhandled record: id:%d length:%d \n",
728 htc_rec_id, htc_rec_len));
729 break;
730 }
731
732 if (A_FAILED(status)) {
733 break;
734 }
735
736 /* advance buffer past this record for next time around */
737 pBuffer += htc_rec_len;
738 Length -= htc_rec_len;
739 }
740
741 if (A_FAILED(status)) {
742 debug_dump_bytes(pOrigBuffer, origLength, "BAD Recv Trailer");
743 }
744
745 AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("-htc_process_trailer \n"));
746 return status;
747
748}