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