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