1 /* 2 * Copyright (c) 2013-2021 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 #if defined(WLAN_DEBUG) || defined(DEBUG) 25 void debug_dump_bytes(uint8_t *buffer, uint16_t length, char *pDescription) 26 { 27 int8_t stream[60]; 28 int8_t byteOffsetStr[10]; 29 uint32_t i; 30 uint16_t offset, count, byteOffset; 31 32 A_PRINTF("<---------Dumping %d Bytes : %s ------>\n", length, 33 pDescription); 34 35 count = 0; 36 offset = 0; 37 byteOffset = 0; 38 for (i = 0; i < length; i++) { 39 A_SNPRINTF(stream + offset, (sizeof(stream) - offset), 40 "%02X ", buffer[i]); 41 count++; 42 offset += 3; 43 44 if (count == 16) { 45 count = 0; 46 offset = 0; 47 A_SNPRINTF(byteOffsetStr, sizeof(byteOffset), "%4.4X", 48 byteOffset); 49 A_PRINTF("[%s]: %s\n", byteOffsetStr, stream); 50 qdf_mem_zero(stream, 60); 51 byteOffset += 16; 52 } 53 } 54 55 if (offset != 0) { 56 A_SNPRINTF(byteOffsetStr, sizeof(byteOffset), "%4.4X", 57 byteOffset); 58 A_PRINTF("[%s]: %s\n", byteOffsetStr, stream); 59 } 60 61 A_PRINTF("<------------------------------------------------->\n"); 62 } 63 #else 64 void debug_dump_bytes(uint8_t *buffer, uint16_t length, char *pDescription) 65 { 66 } 67 #endif 68 69 static A_STATUS htc_process_trailer(HTC_TARGET *target, 70 uint8_t *pBuffer, 71 int Length, HTC_ENDPOINT_ID FromEndpoint); 72 73 static void do_recv_completion_pkt(HTC_ENDPOINT *pEndpoint, 74 HTC_PACKET *pPacket) 75 { 76 if (!pEndpoint->EpCallBacks.EpRecv) { 77 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, 78 ("HTC ep %d has NULL recv callback on packet %pK\n", 79 pEndpoint->Id, 80 pPacket)); 81 if (pPacket) 82 qdf_nbuf_free(pPacket->pPktContext); 83 } else { 84 AR_DEBUG_PRINTF(ATH_DEBUG_RECV, 85 ("HTC calling ep %d recv callback on packet %pK\n", 86 pEndpoint->Id, pPacket)); 87 pEndpoint->EpCallBacks.EpRecv(pEndpoint->EpCallBacks.pContext, 88 pPacket); 89 } 90 } 91 92 static void do_recv_completion(HTC_ENDPOINT *pEndpoint, 93 HTC_PACKET_QUEUE *pQueueToIndicate) 94 { 95 HTC_PACKET *pPacket; 96 97 if (HTC_QUEUE_EMPTY(pQueueToIndicate)) { 98 /* nothing to indicate */ 99 return; 100 } 101 102 while (!HTC_QUEUE_EMPTY(pQueueToIndicate)) { 103 pPacket = htc_packet_dequeue(pQueueToIndicate); 104 do_recv_completion_pkt(pEndpoint, pPacket); 105 } 106 } 107 108 void htc_control_rx_complete(void *Context, HTC_PACKET *pPacket) 109 { 110 /* TODO, can't really receive HTC control messages yet.... */ 111 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, 112 ("Invalid call to htc_control_rx_complete\n")); 113 } 114 115 void htc_unblock_recv(HTC_HANDLE HTCHandle) 116 { 117 /* TODO find the Need in new model */ 118 } 119 120 void htc_enable_recv(HTC_HANDLE HTCHandle) 121 { 122 123 /* TODO find the Need in new model */ 124 } 125 126 void htc_disable_recv(HTC_HANDLE HTCHandle) 127 { 128 129 /* TODO find the Need in new model */ 130 } 131 132 int htc_get_num_recv_buffers(HTC_HANDLE HTCHandle, HTC_ENDPOINT_ID Endpoint) 133 { 134 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); 135 136 HTC_ENDPOINT *pEndpoint = &target->endpoint[Endpoint]; 137 return HTC_PACKET_QUEUE_DEPTH(&pEndpoint->RxBufferHoldQueue); 138 } 139 140 HTC_PACKET *allocate_htc_packet_container(HTC_TARGET *target) 141 { 142 HTC_PACKET *pPacket; 143 144 LOCK_HTC_RX(target); 145 146 if (!target->pHTCPacketStructPool) { 147 UNLOCK_HTC_RX(target); 148 return NULL; 149 } 150 151 pPacket = target->pHTCPacketStructPool; 152 target->pHTCPacketStructPool = (HTC_PACKET *) pPacket->ListLink.pNext; 153 154 UNLOCK_HTC_RX(target); 155 156 pPacket->ListLink.pNext = NULL; 157 return pPacket; 158 } 159 160 void free_htc_packet_container(HTC_TARGET *target, HTC_PACKET *pPacket) 161 { 162 pPacket->ListLink.pPrev = NULL; 163 164 LOCK_HTC_RX(target); 165 if (!target->pHTCPacketStructPool) { 166 target->pHTCPacketStructPool = pPacket; 167 pPacket->ListLink.pNext = NULL; 168 } else { 169 pPacket->ListLink.pNext = 170 (DL_LIST *) target->pHTCPacketStructPool; 171 target->pHTCPacketStructPool = pPacket; 172 } 173 174 UNLOCK_HTC_RX(target); 175 } 176 177 #ifdef RX_SG_SUPPORT 178 qdf_nbuf_t rx_sg_to_single_netbuf(HTC_TARGET *target) 179 { 180 qdf_nbuf_t skb; 181 uint8_t *anbdata; 182 uint8_t *anbdata_new; 183 uint32_t anblen; 184 qdf_nbuf_t new_skb = NULL; 185 uint32_t sg_queue_len; 186 qdf_nbuf_queue_t *rx_sg_queue = &target->RxSgQueue; 187 188 sg_queue_len = qdf_nbuf_queue_len(rx_sg_queue); 189 190 if (sg_queue_len <= 1) { 191 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, 192 ("rx_sg_to_single_netbuf: invalid sg queue len %u\n")); 193 goto _failed; 194 } 195 196 new_skb = qdf_nbuf_alloc(target->ExpRxSgTotalLen, 0, 4, false); 197 if (!new_skb) { 198 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, 199 ("rx_sg_to_single_netbuf: can't allocate %u size netbuf\n", 200 target->ExpRxSgTotalLen)); 201 goto _failed; 202 } 203 204 qdf_nbuf_peek_header(new_skb, &anbdata_new, &anblen); 205 206 skb = qdf_nbuf_queue_remove(rx_sg_queue); 207 do { 208 qdf_nbuf_peek_header(skb, &anbdata, &anblen); 209 qdf_mem_copy(anbdata_new, anbdata, qdf_nbuf_len(skb)); 210 qdf_nbuf_put_tail(new_skb, qdf_nbuf_len(skb)); 211 anbdata_new += qdf_nbuf_len(skb); 212 qdf_nbuf_free(skb); 213 skb = qdf_nbuf_queue_remove(rx_sg_queue); 214 } while (skb); 215 216 RESET_RX_SG_CONFIG(target); 217 return new_skb; 218 219 _failed: 220 221 while ((skb = qdf_nbuf_queue_remove(rx_sg_queue)) != NULL) 222 qdf_nbuf_free(skb); 223 224 RESET_RX_SG_CONFIG(target); 225 return NULL; 226 } 227 #endif 228 229 QDF_STATUS htc_rx_completion_handler(void *Context, qdf_nbuf_t netbuf, 230 uint8_t pipeID) 231 { 232 QDF_STATUS status = QDF_STATUS_SUCCESS; 233 HTC_FRAME_HDR *HtcHdr; 234 HTC_TARGET *target = (HTC_TARGET *) Context; 235 uint8_t *netdata; 236 uint32_t netlen; 237 HTC_ENDPOINT *pEndpoint, *currendpoint; 238 HTC_PACKET *pPacket; 239 uint16_t payloadLen; 240 uint32_t trailerlen = 0; 241 uint8_t htc_ep_id; 242 int i; 243 #ifdef HTC_MSG_WAKEUP_FROM_SUSPEND_ID 244 struct htc_init_info *info; 245 #endif 246 247 #ifdef RX_SG_SUPPORT 248 LOCK_HTC_RX(target); 249 if (target->IsRxSgInprogress) { 250 target->CurRxSgTotalLen += qdf_nbuf_len(netbuf); 251 qdf_nbuf_queue_add(&target->RxSgQueue, netbuf); 252 if (target->CurRxSgTotalLen == target->ExpRxSgTotalLen) { 253 netbuf = rx_sg_to_single_netbuf(target); 254 if (!netbuf) { 255 UNLOCK_HTC_RX(target); 256 goto _out; 257 } 258 } else { 259 netbuf = NULL; 260 UNLOCK_HTC_RX(target); 261 goto _out; 262 } 263 } 264 UNLOCK_HTC_RX(target); 265 #endif 266 267 netdata = qdf_nbuf_data(netbuf); 268 netlen = qdf_nbuf_len(netbuf); 269 270 HtcHdr = (HTC_FRAME_HDR *) netdata; 271 272 do { 273 274 htc_ep_id = HTC_GET_FIELD(HtcHdr, HTC_FRAME_HDR, ENDPOINTID); 275 276 if (htc_ep_id >= ENDPOINT_MAX) { 277 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, 278 ("HTC Rx: invalid EndpointID=%d\n", 279 htc_ep_id)); 280 debug_dump_bytes((uint8_t *) HtcHdr, 281 sizeof(HTC_FRAME_HDR), 282 "BAD HTC Header"); 283 status = QDF_STATUS_E_FAILURE; 284 DPTRACE(qdf_dp_trace( 285 netbuf, 286 QDF_DP_TRACE_HTC_PACKET_PTR_RECORD, 287 QDF_TRACE_DEFAULT_PDEV_ID, 288 qdf_nbuf_data_addr(netbuf), 289 sizeof(qdf_nbuf_data(netbuf)), 290 QDF_RX)); 291 break; 292 } 293 294 pEndpoint = &target->endpoint[htc_ep_id]; 295 296 /* 297 * If this endpoint that received a message from the target has 298 * a to-target HIF pipe whose send completions are polled rather 299 * than interrupt driven, this is a good point to ask HIF to 300 * check whether it has any completed sends to handle. 301 */ 302 if (pEndpoint->ul_is_polled) { 303 for (i = 0; i < ENDPOINT_MAX; i++) { 304 currendpoint = &target->endpoint[i]; 305 if ((currendpoint->DL_PipeID == 306 pEndpoint->DL_PipeID) && 307 currendpoint->ul_is_polled) { 308 htc_send_complete_check(currendpoint, 309 1); 310 } 311 } 312 } 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 DPTRACE(qdf_dp_trace( 336 netbuf, 337 QDF_DP_TRACE_HTC_PACKET_PTR_RECORD, 338 QDF_TRACE_DEFAULT_PDEV_ID, 339 qdf_nbuf_data_addr(netbuf), 340 sizeof(qdf_nbuf_data(netbuf)), 341 QDF_RX)); 342 break; 343 #endif 344 } 345 #ifdef HTC_EP_STAT_PROFILING 346 LOCK_HTC_RX(target); 347 INC_HTC_EP_STAT(pEndpoint, RxReceived, 1); 348 UNLOCK_HTC_RX(target); 349 #endif 350 351 /* if (IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)) { */ 352 { 353 uint8_t temp; 354 A_STATUS temp_status; 355 /* get flags to check for trailer */ 356 temp = HTC_GET_FIELD(HtcHdr, HTC_FRAME_HDR, FLAGS); 357 if (temp & HTC_FLAGS_RECV_TRAILER) { 358 /* extract the trailer length */ 359 temp = 360 HTC_GET_FIELD(HtcHdr, HTC_FRAME_HDR, 361 CONTROLBYTES0); 362 if ((temp < sizeof(HTC_RECORD_HDR)) 363 || (temp > payloadLen)) { 364 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, 365 ("htc_rx_completion_handler, invalid header (payloadlength should be :%d, CB[0] is:%d)\n", 366 payloadLen, temp)); 367 status = QDF_STATUS_E_INVAL; 368 break; 369 } 370 371 trailerlen = temp; 372 /* process trailer data that follows HDR + 373 * application payload 374 */ 375 temp_status = htc_process_trailer(target, 376 ((uint8_t *) HtcHdr + 377 HTC_HDR_LENGTH + 378 payloadLen - temp), 379 temp, htc_ep_id); 380 if (A_FAILED(temp_status)) { 381 status = QDF_STATUS_E_FAILURE; 382 break; 383 } 384 385 } 386 } 387 388 if (((int)payloadLen - (int)trailerlen) <= 0) { 389 /* 0 length packet with trailer data, just drop these */ 390 break; 391 } 392 393 if (htc_ep_id == ENDPOINT_0) { 394 uint16_t message_id; 395 HTC_UNKNOWN_MSG *htc_msg; 396 bool wow_nack; 397 398 /* remove HTC header */ 399 qdf_nbuf_pull_head(netbuf, HTC_HDR_LENGTH); 400 netdata = qdf_nbuf_data(netbuf); 401 netlen = qdf_nbuf_len(netbuf); 402 403 htc_msg = (HTC_UNKNOWN_MSG *) netdata; 404 message_id = HTC_GET_FIELD(htc_msg, HTC_UNKNOWN_MSG, 405 MESSAGEID); 406 407 switch (message_id) { 408 default: 409 /* handle HTC control message */ 410 if (target->CtrlResponseProcessing) { 411 /* this is a fatal error, target should 412 * not be sending unsolicited messages 413 * on the endpoint 0 414 */ 415 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, 416 ("HTC Rx Ctrl still processing\n")); 417 status = QDF_STATUS_E_FAILURE; 418 QDF_BUG(false); 419 break; 420 } 421 422 LOCK_HTC_RX(target); 423 target->CtrlResponseLength = 424 min((int)netlen, 425 HTC_MAX_CONTROL_MESSAGE_LENGTH); 426 qdf_mem_copy(target->CtrlResponseBuffer, 427 netdata, 428 target->CtrlResponseLength); 429 430 /* Requester will clear this flag */ 431 target->CtrlResponseProcessing = true; 432 UNLOCK_HTC_RX(target); 433 qdf_event_set(&target->ctrl_response_valid); 434 break; 435 #ifdef HTC_MSG_WAKEUP_FROM_SUSPEND_ID 436 case HTC_MSG_WAKEUP_FROM_SUSPEND_ID: 437 AR_DEBUG_PRINTF(ATH_DEBUG_ANY, 438 ("Received initial wake up")); 439 htc_credit_record(HTC_INITIAL_WAKE_UP, 440 pEndpoint->TxCredits, 441 HTC_PACKET_QUEUE_DEPTH( 442 &pEndpoint->TxQueue)); 443 info = &target->HTCInitInfo; 444 if (info && info->target_initial_wakeup_cb) 445 info->target_initial_wakeup_cb( 446 info->target_psoc); 447 else 448 AR_DEBUG_PRINTF(ATH_DEBUG_ANY, 449 ("No initial wake up cb")); 450 break; 451 #endif 452 case HTC_MSG_SEND_SUSPEND_COMPLETE: 453 wow_nack = false; 454 htc_credit_record(HTC_SUSPEND_ACK, 455 pEndpoint->TxCredits, 456 HTC_PACKET_QUEUE_DEPTH( 457 &pEndpoint->TxQueue)); 458 target->HTCInitInfo.TargetSendSuspendComplete( 459 target->HTCInitInfo.target_psoc, 460 wow_nack); 461 462 break; 463 case HTC_MSG_NACK_SUSPEND: 464 wow_nack = true; 465 htc_credit_record(HTC_SUSPEND_ACK, 466 pEndpoint->TxCredits, 467 HTC_PACKET_QUEUE_DEPTH( 468 &pEndpoint->TxQueue)); 469 target->HTCInitInfo.TargetSendSuspendComplete( 470 target->HTCInitInfo.target_psoc, 471 wow_nack); 472 break; 473 } 474 475 qdf_nbuf_free(netbuf); 476 netbuf = NULL; 477 break; 478 } 479 480 /* the current message based HIF architecture allocates net bufs 481 * for recv packets since this layer bridges that HIF to upper 482 * layers , which expects HTC packets, we form the packets here 483 * TODO_FIXME 484 */ 485 pPacket = allocate_htc_packet_container(target); 486 if (!pPacket) { 487 status = QDF_STATUS_E_RESOURCES; 488 break; 489 } 490 pPacket->Status = QDF_STATUS_SUCCESS; 491 pPacket->Endpoint = htc_ep_id; 492 pPacket->pPktContext = netbuf; 493 pPacket->pBuffer = qdf_nbuf_data(netbuf) + HTC_HDR_LENGTH; 494 pPacket->ActualLength = netlen - HTC_HEADER_LEN - trailerlen; 495 496 qdf_nbuf_pull_head(netbuf, HTC_HEADER_LEN); 497 qdf_nbuf_set_pktlen(netbuf, pPacket->ActualLength); 498 499 do_recv_completion_pkt(pEndpoint, pPacket); 500 501 /* recover the packet container */ 502 free_htc_packet_container(target, pPacket); 503 504 netbuf = NULL; 505 506 } while (false); 507 508 #ifdef RX_SG_SUPPORT 509 _out: 510 #endif 511 512 if (netbuf) 513 qdf_nbuf_free(netbuf); 514 515 return status; 516 517 } 518 519 A_STATUS htc_add_receive_pkt_multiple(HTC_HANDLE HTCHandle, 520 HTC_PACKET_QUEUE *pPktQueue) 521 { 522 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); 523 HTC_ENDPOINT *pEndpoint; 524 HTC_PACKET *pFirstPacket; 525 A_STATUS status = A_OK; 526 HTC_PACKET *pPacket; 527 528 pFirstPacket = htc_get_pkt_at_head(pPktQueue); 529 530 if (!pFirstPacket) { 531 A_ASSERT(false); 532 return A_EINVAL; 533 } 534 535 if (pFirstPacket->Endpoint >= ENDPOINT_MAX) { 536 A_ASSERT(false); 537 return A_EINVAL; 538 } 539 540 AR_DEBUG_PRINTF(ATH_DEBUG_RECV, 541 ("+- htc_add_receive_pkt_multiple : endPointId: %d, cnt:%d, length: %d\n", 542 pFirstPacket->Endpoint, 543 HTC_PACKET_QUEUE_DEPTH(pPktQueue), 544 pFirstPacket->BufferLength)); 545 546 pEndpoint = &target->endpoint[pFirstPacket->Endpoint]; 547 548 LOCK_HTC_RX(target); 549 550 do { 551 552 if (HTC_STOPPING(target)) { 553 status = A_ERROR; 554 break; 555 } 556 557 /* store receive packets */ 558 HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(&pEndpoint->RxBufferHoldQueue, 559 pPktQueue); 560 561 } while (false); 562 563 UNLOCK_HTC_RX(target); 564 565 if (A_FAILED(status)) { 566 /* walk through queue and mark each one canceled */ 567 HTC_PACKET_QUEUE_ITERATE_ALLOW_REMOVE(pPktQueue, pPacket) { 568 pPacket->Status = QDF_STATUS_E_CANCELED; 569 } 570 HTC_PACKET_QUEUE_ITERATE_END; 571 572 do_recv_completion(pEndpoint, pPktQueue); 573 } 574 575 return status; 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) 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 (target->HTCInitInfo.htc_ready_timeout_ms))) { 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