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