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