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