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