static void HTT_RX_FRAG_SET_LAST_MSDU( struct htt_pdev_t *pdev, adf_nbuf_t msg) { u_int32_t *msg_word; unsigned num_msdu_bytes; adf_nbuf_t msdu; struct htt_host_rx_desc_base *rx_desc; int start_idx; u_int8_t *p_fw_msdu_rx_desc = 0; msg_word = (u_int32_t *) adf_nbuf_data(msg); num_msdu_bytes = HTT_RX_FRAG_IND_FW_RX_DESC_BYTES_GET(*(msg_word + HTT_RX_FRAG_IND_HDR_PREFIX_SIZE32)); /* * 1 word for the message header, * 1 word to specify the number of MSDU bytes, * 1 word for every 4 MSDU bytes (round up), * 1 word for the MPDU range header */ pdev->rx_mpdu_range_offset_words = 3 + ((num_msdu_bytes + 3) >> 2); pdev->rx_ind_msdu_byte_idx = 0; p_fw_msdu_rx_desc = ((u_int8_t *)(msg_word) + HTT_ENDIAN_BYTE_IDX_SWAP(HTT_RX_FRAG_IND_FW_DESC_BYTE_OFFSET)); /* * Fix for EV126710, in which BSOD occurs due to last_msdu bit * not set while the next pointer is deliberately set to NULL * before calling ol_rx_pn_check_base() * * For fragment frames, the HW may not have set the last_msdu bit * in the rx descriptor, but the SW expects this flag to be set, * since each fragment is in a separate MPDU. Thus, set the flag here, * just in case the HW didn't. */ start_idx = pdev->rx_ring.sw_rd_idx.msdu_payld; msdu = pdev->rx_ring.buf.netbufs_ring[start_idx]; adf_nbuf_set_pktlen(msdu, HTT_RX_BUF_SIZE); adf_nbuf_unmap(pdev->osdev, msdu, ADF_OS_DMA_FROM_DEVICE); rx_desc = htt_rx_desc(msdu); *((u_int8_t *) &rx_desc->fw_desc.u.val) = *p_fw_msdu_rx_desc; rx_desc->msdu_end.last_msdu = 1; adf_nbuf_map(pdev->osdev, msdu, ADF_OS_DMA_FROM_DEVICE); }
wmi_buf_t wmi_buf_alloc(wmi_unified_t wmi_handle, u_int16_t len) { wmi_buf_t wmi_buf; if (roundup(len + WMI_MIN_HEAD_ROOM, 4) > wmi_handle->max_msg_len) { VOS_ASSERT(0); return NULL; } wmi_buf = adf_nbuf_alloc(NULL, roundup(len + WMI_MIN_HEAD_ROOM, 4), WMI_MIN_HEAD_ROOM, 4, FALSE); if (!wmi_buf) return NULL; /* Clear the wmi buffer */ OS_MEMZERO(adf_nbuf_data(wmi_buf), len); /* * Set the length of the buffer to match the allocation size. */ adf_nbuf_set_pktlen(wmi_buf, len); return wmi_buf; }
A_STATUS HTCRxCompletionHandler( void *Context, adf_nbuf_t netbuf, a_uint8_t pipeID) { A_STATUS status = A_OK; HTC_FRAME_HDR *HtcHdr; HTC_TARGET *target = (HTC_TARGET *)Context; a_uint8_t *netdata; a_uint32_t netlen; HTC_ENDPOINT *pEndpoint; HTC_PACKET *pPacket; A_UINT16 payloadLen; a_uint32_t trailerlen = 0; A_UINT8 htc_ep_id; #ifdef RX_SG_SUPPORT LOCK_HTC_RX(target); if (target->IsRxSgInprogress) { target->CurRxSgTotalLen += adf_nbuf_len(netbuf); adf_nbuf_queue_add(&target->RxSgQueue, netbuf); if (target->CurRxSgTotalLen == target->ExpRxSgTotalLen) { netbuf = RxSgToSingleNetbuf(target); if (netbuf == NULL) { UNLOCK_HTC_RX(target); goto _out; } } else { netbuf = NULL; UNLOCK_HTC_RX(target); goto _out; } } UNLOCK_HTC_RX(target); #endif netdata = adf_nbuf_data(netbuf); netlen = adf_nbuf_len(netbuf); HtcHdr = (HTC_FRAME_HDR *)netdata; do { htc_ep_id = HTC_GET_FIELD(HtcHdr, HTC_FRAME_HDR, ENDPOINTID); if (htc_ep_id >= ENDPOINT_MAX) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("HTC Rx: invalid EndpointID=%d\n",htc_ep_id)); DebugDumpBytes((A_UINT8 *)HtcHdr,sizeof(HTC_FRAME_HDR),"BAD HTC Header"); status = A_ERROR; VOS_BUG(0); break; } pEndpoint = &target->EndPoint[htc_ep_id]; /* * If this endpoint that received a message from the target has * a to-target HIF pipe whose send completions are polled rather * than interrupt-driven, this is a good point to ask HIF to check * whether it has any completed sends to handle. */ if (pEndpoint->ul_is_polled) { HTCSendCompleteCheck(pEndpoint, 1); } payloadLen = HTC_GET_FIELD(HtcHdr, HTC_FRAME_HDR, PAYLOADLEN); if (netlen < (payloadLen + HTC_HDR_LENGTH)) { #ifdef RX_SG_SUPPORT LOCK_HTC_RX(target); target->IsRxSgInprogress = TRUE; adf_nbuf_queue_init(&target->RxSgQueue); adf_nbuf_queue_add(&target->RxSgQueue, netbuf); target->ExpRxSgTotalLen = (payloadLen + HTC_HDR_LENGTH); target->CurRxSgTotalLen += netlen; UNLOCK_HTC_RX(target); netbuf = NULL; break; #else AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("HTC Rx: insufficient length, got:%d expected =%zu\n", netlen, payloadLen + HTC_HDR_LENGTH)); DebugDumpBytes((A_UINT8 *)HtcHdr,sizeof(HTC_FRAME_HDR),"BAD RX packet length"); status = A_ERROR; VOS_BUG(0); break; #endif } #ifdef HTC_EP_STAT_PROFILING LOCK_HTC_RX(target); INC_HTC_EP_STAT(pEndpoint,RxReceived,1); UNLOCK_HTC_RX(target); #endif //if (IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)) { { A_UINT8 temp; /* get flags to check for trailer */ temp = HTC_GET_FIELD(HtcHdr, HTC_FRAME_HDR, FLAGS); if (temp & HTC_FLAGS_RECV_TRAILER) { /* extract the trailer length */ temp = HTC_GET_FIELD(HtcHdr, HTC_FRAME_HDR, CONTROLBYTES0); if ((temp < sizeof(HTC_RECORD_HDR)) || (temp > payloadLen)) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("HTCRxCompletionHandler, invalid header (payloadlength should be :%d, CB[0] is:%d) \n", payloadLen, temp)); status = A_EPROTO; break; } trailerlen = temp; /* process trailer data that follows HDR + application payload */ status = HTCProcessTrailer(target, ((A_UINT8 *)HtcHdr + HTC_HDR_LENGTH + payloadLen - temp), temp, htc_ep_id); if (A_FAILED(status)) { break; } } } if (((int)payloadLen - (int)trailerlen) <= 0) { /* zero length packet with trailer data, just drop these */ break; } if (htc_ep_id == ENDPOINT_0) { A_UINT16 message_id; HTC_UNKNOWN_MSG *htc_msg; int wow_nack = 0; /* remove HTC header */ adf_nbuf_pull_head(netbuf, HTC_HDR_LENGTH); netdata = adf_nbuf_data(netbuf); netlen = adf_nbuf_len(netbuf); htc_msg = (HTC_UNKNOWN_MSG*)netdata; message_id = HTC_GET_FIELD(htc_msg, HTC_UNKNOWN_MSG, MESSAGEID); switch (message_id) { default: /* handle HTC control message */ if (target->CtrlResponseProcessing) { /* this is a fatal error, target should not be sending unsolicited messages * on the endpoint 0 */ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("HTC Rx Ctrl still processing\n")); status = A_ERROR; VOS_BUG(FALSE); break; } LOCK_HTC_RX(target); target->CtrlResponseLength = min((int)netlen,HTC_MAX_CONTROL_MESSAGE_LENGTH); A_MEMCPY(target->CtrlResponseBuffer,netdata,target->CtrlResponseLength); /* Requester will clear this flag */ target->CtrlResponseProcessing = TRUE; UNLOCK_HTC_RX(target); adf_os_complete(&target->CtrlResponseValid); break; case HTC_MSG_SEND_SUSPEND_COMPLETE: wow_nack = 0; LOCK_HTC_CREDIT(target); htc_credit_record(HTC_SUSPEND_ACK, pEndpoint->TxCredits, HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue)); UNLOCK_HTC_CREDIT(target); target->HTCInitInfo.TargetSendSuspendComplete((void *)&wow_nack); HTCsuspendwow(target); break; case HTC_MSG_NACK_SUSPEND: wow_nack = 1; LOCK_HTC_CREDIT(target); htc_credit_record(HTC_SUSPEND_NACK, pEndpoint->TxCredits, HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue)); UNLOCK_HTC_CREDIT(target); target->HTCInitInfo.TargetSendSuspendComplete((void *)&wow_nack); break; } adf_nbuf_free(netbuf); netbuf = NULL; break; } /* the current message based HIF architecture allocates net bufs for recv packets * since this layer bridges that HIF to upper layers , which expects HTC packets, * we form the packets here * TODO_FIXME */ pPacket = AllocateHTCPacketContainer(target); if (NULL == pPacket) { status = A_NO_RESOURCE; break; } pPacket->Status = A_OK; pPacket->Endpoint = htc_ep_id; pPacket->pPktContext = netbuf; pPacket->pBuffer = adf_nbuf_data(netbuf) + HTC_HDR_LENGTH; pPacket->ActualLength = netlen - HTC_HEADER_LEN - trailerlen; adf_nbuf_pull_head(netbuf, HTC_HEADER_LEN); adf_nbuf_set_pktlen(netbuf, pPacket->ActualLength); RecvPacketCompletion(target,pEndpoint,pPacket); /* recover the packet container */ FreeHTCPacketContainer(target,pPacket); netbuf = NULL; } while(FALSE); #ifdef RX_SG_SUPPORT _out: #endif if (netbuf != NULL) { adf_nbuf_free(netbuf); } return status; }