A_STATUS HTCTxEnqueuePkts(HTC_TARGET *target, HTC_ENDPOINT *pEndpoint, adf_nbuf_t hdr_buf, adf_nbuf_t buf) { //a_uint32_t i; A_STATUS status = A_OK; LOCK_HTC_TX(target); if (pEndpoint->TxBufCnt >= HTC_TX_QUEUE_SIZE) { UNLOCK_HTC_TX(target); //adf_os_print("HTC Tx queue is full!\n"); return A_NO_RESOURCE; } pEndpoint->HtcTxQueue[pEndpoint->TxQTail].hdr_buf = hdr_buf; if (hdr_buf == ADF_NBUF_NULL) { pEndpoint->HtcTxQueue[pEndpoint->TxQTail].hdr_bufLen = 0; } else { pEndpoint->HtcTxQueue[pEndpoint->TxQTail].hdr_bufLen = adf_nbuf_len(hdr_buf); } pEndpoint->HtcTxQueue[pEndpoint->TxQTail].buf = buf; pEndpoint->HtcTxQueue[pEndpoint->TxQTail].bufLen = adf_nbuf_len(buf); pEndpoint->TxQTail = (pEndpoint->TxQTail + 1) % HTC_TX_QUEUE_SIZE; pEndpoint->TxBufCnt += 1; UNLOCK_HTC_TX(target); return (status? A_ERROR : A_OK); }
adf_nbuf_t RxSgToSingleNetbuf(HTC_TARGET *target) { adf_nbuf_t skb; a_uint8_t *anbdata; a_uint8_t *anbdata_new; a_uint32_t anblen; adf_nbuf_t new_skb = NULL; a_uint32_t sg_queue_len; adf_nbuf_queue_t *rx_sg_queue = &target->RxSgQueue; sg_queue_len = adf_nbuf_queue_len(rx_sg_queue); if (sg_queue_len <= 1) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("RxSgToSingleNetbuf: invalid sg queue len %u\n")); goto _failed; } new_skb = adf_nbuf_alloc(target->ExpRxSgTotalLen, 0, 4, FALSE); if (new_skb == NULL) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("RxSgToSingleNetbuf: can't allocate %u size netbuf\n", target->ExpRxSgTotalLen)); goto _failed; } adf_nbuf_peek_header(new_skb, &anbdata_new, &anblen); skb = adf_nbuf_queue_remove(rx_sg_queue); do { adf_nbuf_peek_header(skb, &anbdata, &anblen); adf_os_mem_copy(anbdata_new, anbdata, adf_nbuf_len(skb)); adf_nbuf_put_tail(new_skb, adf_nbuf_len(skb)); anbdata_new += adf_nbuf_len(skb); adf_nbuf_free(skb); skb = adf_nbuf_queue_remove(rx_sg_queue); } while(skb != NULL); RESET_RX_SG_CONFIG(target); return new_skb; _failed: while ((skb = adf_nbuf_queue_remove(rx_sg_queue)) != NULL) { adf_nbuf_free(skb); } RESET_RX_SG_CONFIG(target); return NULL; }
static inline int htt_tx_send_base( htt_pdev_handle pdev, adf_nbuf_t msdu, u_int16_t msdu_id, int download_len, u_int8_t more_data) { struct htt_host_tx_desc_t *htt_host_tx_desc; struct htt_htc_pkt *pkt; int packet_len; HTC_ENDPOINT_ID ep_id; /* * The HTT tx descriptor was attached as the prefix fragment to the * msdu netbuf during the call to htt_tx_desc_init. * Retrieve it so we can provide its HTC header space to HTC. */ htt_host_tx_desc = (struct htt_host_tx_desc_t *) adf_nbuf_get_frag_vaddr(msdu, 0); pkt = htt_htc_pkt_alloc(pdev); if (!pkt) { return 1; /* failure */ } pkt->msdu_id = msdu_id; pkt->pdev_ctxt = pdev->txrx_pdev; /* packet length includes HTT tx desc frag added above */ packet_len = adf_nbuf_len(msdu); if (packet_len < download_len) { /* * This case of packet length being less than the nominal download * length can happen for a couple reasons: * In HL, the nominal download length is a large artificial value. * In LL, the frame may not have the optional header fields * accounted for in the nominal download size (LLC/SNAP header, * IPv4 or IPv6 header). */ download_len = packet_len; } ep_id = htt_tx_htt2_get_ep_id(pdev, msdu); SET_HTC_PACKET_INFO_TX( &pkt->htc_pkt, pdev->tx_send_complete_part2, (unsigned char *) htt_host_tx_desc, download_len - HTC_HDR_LENGTH, ep_id, 1); /* tag - not relevant here */ SET_HTC_PACKET_NET_BUF_CONTEXT(&pkt->htc_pkt, msdu); adf_nbuf_trace_update(msdu, "HT:T:"); HTCSendDataPkt(pdev->htc_pdev, &pkt->htc_pkt, more_data); return 0; /* success */ }
A_STATUS htt_h2t_sync_msg(struct htt_pdev_t *pdev, u_int8_t sync_cnt) { struct htt_htc_pkt *pkt; adf_nbuf_t msg; u_int32_t *msg_word; pkt = htt_htc_pkt_alloc(pdev); if (!pkt) { return A_NO_MEMORY; } /* show that this is not a tx frame download (not required, but helpful) */ pkt->msdu_id = HTT_TX_COMPL_INV_MSDU_ID; pkt->pdev_ctxt = NULL; /* not used during send-done callback */ msg = adf_nbuf_alloc( pdev->osdev, HTT_MSG_BUF_SIZE(HTT_H2T_SYNC_MSG_SZ), /* reserve room for HTC header */ HTC_HEADER_LEN + HTC_HDR_ALIGNMENT_PADDING, 4, FALSE); if (!msg) { htt_htc_pkt_free(pdev, pkt); return A_NO_MEMORY; } /* set the length of the message */ adf_nbuf_put_tail(msg, HTT_H2T_SYNC_MSG_SZ); /* fill in the message contents */ msg_word = (u_int32_t *) adf_nbuf_data(msg); /* rewind beyond alignment pad to get to the HTC header reserved area */ adf_nbuf_push_head(msg, HTC_HDR_ALIGNMENT_PADDING); *msg_word = 0; HTT_H2T_MSG_TYPE_SET(*msg_word, HTT_H2T_MSG_TYPE_SYNC); HTT_H2T_SYNC_COUNT_SET(*msg_word, sync_cnt); SET_HTC_PACKET_INFO_TX( &pkt->htc_pkt, htt_h2t_send_complete_free_netbuf, adf_nbuf_data(msg), adf_nbuf_len(msg), pdev->htc_endpoint, HTC_TX_PACKET_TAG_RUNTIME_PUT); SET_HTC_PACKET_NET_BUF_CONTEXT(&pkt->htc_pkt, msg); #ifdef ATH_11AC_TXCOMPACT if (HTCSendPkt(pdev->htc_pdev, &pkt->htc_pkt) == A_OK) htt_htc_misc_pkt_list_add(pdev, pkt); #else HTCSendPkt(pdev->htc_pdev, &pkt->htc_pkt); #endif if ((pdev->cfg.is_high_latency) && (!pdev->cfg.default_tx_comp_req)) { ol_tx_target_credit_update(pdev->txrx_pdev, -1); } return A_OK; }
/* WMI Event handler register API */ int wmi_unified_get_event_handler_ix(wmi_unified_t wmi_handle, WMI_EVT_ID event_id) { u_int32_t idx = 0; for (idx = 0; (idx < wmi_handle->max_event_idx && idx < WMI_UNIFIED_MAX_EVENT); ++idx) { if (wmi_handle->event_id[idx] == event_id && wmi_handle->event_handler[idx] != NULL ) { return idx; } } return -1; } int wmi_unified_register_event_handler(wmi_unified_t wmi_handle, WMI_EVT_ID event_id, wmi_unified_event_handler handler_func) { u_int32_t idx=0; if ( wmi_unified_get_event_handler_ix( wmi_handle, event_id) != -1) { printk("%s : event handler already registered 0x%x \n", __func__, event_id); return -1; } if ( wmi_handle->max_event_idx == WMI_UNIFIED_MAX_EVENT ) { printk("%s : no more event handlers 0x%x \n", __func__, event_id); return -1; } idx=wmi_handle->max_event_idx; wmi_handle->event_handler[idx] = handler_func; wmi_handle->event_id[idx] = event_id; wmi_handle->max_event_idx++; return 0; } int wmi_unified_unregister_event_handler(wmi_unified_t wmi_handle, WMI_EVT_ID event_id) { u_int32_t idx=0; if ( (idx = wmi_unified_get_event_handler_ix( wmi_handle, event_id)) == -1) { printk("%s : event handler is not registered: event id 0x%x \n", __func__, event_id); return -1; } wmi_handle->event_handler[idx] = NULL; wmi_handle->event_id[idx] = 0; --wmi_handle->max_event_idx; wmi_handle->event_handler[idx] = wmi_handle->event_handler[wmi_handle->max_event_idx]; wmi_handle->event_id[idx] = wmi_handle->event_id[wmi_handle->max_event_idx] ; return 0; } #if 0 /* currently not used */ static int wmi_unified_event_rx(struct wmi_unified *wmi_handle, wmi_buf_t evt_buf) { u_int32_t id; u_int8_t *event; u_int16_t len; int status = -1; u_int32_t idx = 0; ASSERT(evt_buf != NULL); id = WMI_GET_FIELD(adf_nbuf_data(evt_buf), WMI_CMD_HDR, COMMANDID); if (adf_nbuf_pull_head(evt_buf, sizeof(WMI_CMD_HDR)) == NULL) goto end; idx = wmi_unified_get_event_handler_ix(wmi_handle, id); if (idx == -1) { pr_err("%s : event handler is not registered: event id: 0x%x\n", __func__, id); goto end; } event = adf_nbuf_data(evt_buf); len = adf_nbuf_len(evt_buf); /* Call the WMI registered event handler */ status = wmi_handle->event_handler[idx](wmi_handle->scn_handle, event, len); end: adf_nbuf_free(evt_buf); return status; }
/* Scheduling the Queued packets in HTT which could not be sent out because of No CE desc*/ void htt_tx_sched(htt_pdev_handle pdev) { adf_nbuf_t msdu; int download_len = pdev->download_len; int packet_len; HTT_TX_NBUF_QUEUE_REMOVE(pdev, msdu); while (msdu != NULL){ int not_accepted; /* packet length includes HTT tx desc frag added above */ packet_len = adf_nbuf_len(msdu); if (packet_len < download_len) { /* * This case of packet length being less than the nominal download * length can happen for a couple reasons: * In HL, the nominal download length is a large artificial value. * In LL, the frame may not have the optional header fields * accounted for in the nominal download size (LLC/SNAP header, * IPv4 or IPv6 header). */ download_len = packet_len; } not_accepted = HTCSendDataPkt( pdev->htc_pdev, msdu, pdev->htc_endpoint, download_len); if (not_accepted) { HTT_TX_NBUF_QUEUE_INSERT_HEAD(pdev, msdu); return; } HTT_TX_NBUF_QUEUE_REMOVE(pdev, msdu); } }
int htt_h2t_ipa_uc_get_stats(struct htt_pdev_t *pdev) { struct htt_htc_pkt *pkt = NULL; adf_nbuf_t msg = NULL; u_int32_t *msg_word; /* New buffer alloc send */ pkt = htt_htc_pkt_alloc(pdev); if (!pkt) { return A_NO_MEMORY; } /* show that this is not a tx frame download (not required, * but helpful) */ pkt->msdu_id = HTT_TX_COMPL_INV_MSDU_ID; pkt->pdev_ctxt = NULL; /* not used during send-done callback */ msg = adf_nbuf_alloc( pdev->osdev, HTT_MSG_BUF_SIZE(HTT_WDI_IPA_OP_REQUEST_SZ), /* reserve room for HTC header */ HTC_HEADER_LEN + HTC_HDR_ALIGNMENT_PADDING, 4, FALSE); if (!msg) { htt_htc_pkt_free(pdev, pkt); return A_NO_MEMORY; } /* set the length of the message */ adf_nbuf_put_tail(msg, HTT_WDI_IPA_OP_REQUEST_SZ); /* rewind beyond alignment pad to get to the HTC header reserved area */ adf_nbuf_push_head(msg, HTC_HDR_ALIGNMENT_PADDING); /* fill in the message contents */ msg_word = (u_int32_t *) adf_nbuf_data(msg); *msg_word = 0; HTT_WDI_IPA_OP_REQUEST_OP_CODE_SET(*msg_word, HTT_WDI_IPA_OPCODE_DBG_STATS); HTT_H2T_MSG_TYPE_SET(*msg_word, HTT_H2T_MSG_TYPE_WDI_IPA_OP_REQ); SET_HTC_PACKET_INFO_TX( &pkt->htc_pkt, htt_h2t_send_complete_free_netbuf, adf_nbuf_data(msg), adf_nbuf_len(msg), pdev->htc_endpoint, 1); /* tag - not relevant here */ SET_HTC_PACKET_NET_BUF_CONTEXT(&pkt->htc_pkt, msg); #ifdef ATH_11AC_TXCOMPACT if (HTCSendPkt(pdev->htc_pdev, &pkt->htc_pkt) == A_OK) htt_htc_misc_pkt_list_add(pdev, pkt); #else HTCSendPkt(pdev->htc_pdev, &pkt->htc_pkt); #endif return A_OK; }
void epping_tx_dup_pkt(epping_adapter_t *pAdapter, HTC_ENDPOINT_ID eid, adf_nbuf_t skb) { struct epping_cookie * cookie = NULL; int skb_len, ret; adf_nbuf_t new_skb; cookie = epping_alloc_cookie(pAdapter->pEpping_ctx); if (cookie == NULL) { EPPING_LOG(VOS_TRACE_LEVEL_FATAL, "%s: epping_alloc_cookie returns no resource\n", __func__); return; } new_skb = adf_nbuf_copy(skb); if (!new_skb) { EPPING_LOG(VOS_TRACE_LEVEL_FATAL, "%s: adf_nbuf_copy returns no resource\n", __func__); epping_free_cookie(pAdapter->pEpping_ctx, cookie); return; } SET_HTC_PACKET_INFO_TX(&cookie->HtcPkt, cookie, adf_nbuf_data(skb), adf_nbuf_len(new_skb), eid, 0); SET_HTC_PACKET_NET_BUF_CONTEXT(&cookie->HtcPkt, new_skb); skb_len = (int)adf_nbuf_len(new_skb); /* send the packet */ ret = HTCSendPkt(pAdapter->pEpping_ctx->HTCHandle, &cookie->HtcPkt); if (ret != A_OK) { EPPING_LOG(VOS_TRACE_LEVEL_FATAL, "%s: HTCSendPkt failed, ret = %d\n", __func__, ret); epping_free_cookie(pAdapter->pEpping_ctx, cookie); adf_nbuf_free(new_skb); return; } pAdapter->stats.tx_bytes += skb_len; ++pAdapter->stats.tx_packets; if (((pAdapter->stats.tx_packets + pAdapter->stats.tx_dropped) % EPPING_STATS_LOG_COUNT) == 0 && (pAdapter->stats.tx_packets || pAdapter->stats.tx_dropped)) { epping_log_stats(pAdapter, __func__); } }
static inline HTC_ENDPOINT_ID htt_tx_htt2_get_ep_id( htt_pdev_handle pdev, adf_nbuf_t msdu) { /* * TX HTT2 service mainly for small sized frame and check if * this candidate frame allow or not. */ if ((pdev->htc_tx_htt2_endpoint != ENDPOINT_UNUSED) && adf_nbuf_get_tx_parallel_dnload_frm(msdu) && (adf_nbuf_len(msdu) < pdev->htc_tx_htt2_max_size)) return pdev->htc_tx_htt2_endpoint; else return pdev->htc_endpoint; }
static inline A_STATUS ol_tx_copy_native_wifi_header( adf_nbuf_t msdu, u_int8_t *hdsize, u_int8_t *localbuf) { struct ieee80211_frame *wh = (struct ieee80211_frame*)adf_nbuf_data(msdu); if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS) { *hdsize = sizeof(struct ieee80211_frame_addr4); } else { *hdsize = sizeof(struct ieee80211_frame); } if (adf_nbuf_len(msdu) < *hdsize) { return A_ERROR; } adf_os_mem_copy(localbuf, wh, *hdsize); return A_OK; }
int htt_tx_send_std( htt_pdev_handle pdev, adf_nbuf_t msdu, u_int16_t msdu_id) { int download_len = pdev->download_len; int packet_len; /* packet length includes HTT tx desc frag added above */ packet_len = adf_nbuf_len(msdu); if (packet_len < download_len) { /* * This case of packet length being less than the nominal download * length can happen for a couple reasons: * In HL, the nominal download length is a large artificial value. * In LL, the frame may not have the optional header fields * accounted for in the nominal download size (LLC/SNAP header, * IPv4 or IPv6 header). */ download_len = packet_len; } if (adf_nbuf_queue_len(&pdev->txnbufq) > 0) { HTT_TX_NBUF_QUEUE_ADD(pdev, msdu); htt_tx_sched(pdev); return 0; } adf_nbuf_trace_update(msdu, "HT:T:"); if (HTCSendDataPkt(pdev->htc_pdev, msdu, pdev->htc_endpoint, download_len)){ HTT_TX_NBUF_QUEUE_ADD(pdev, msdu); } return 0; /* success */ }
/* * Call netif_stop_queue frequently will impact the mboxping tx t-put. * Return HTC_SEND_FULL_KEEP directly in epping_tx_queue_full to avoid. */ return HTC_SEND_FULL_KEEP; } #endif /* HIF_SDIO */ void epping_tx_complete_multiple(void *ctx, HTC_PACKET_QUEUE *pPacketQueue) { epping_context_t *pEpping_ctx = (epping_context_t *)ctx; epping_adapter_t *pAdapter = pEpping_ctx->epping_adapter; struct net_device* dev = pAdapter->dev; A_STATUS status; HTC_ENDPOINT_ID eid; adf_nbuf_t pktSkb; struct epping_cookie *cookie; A_BOOL flushing = FALSE; adf_nbuf_queue_t skb_queue; HTC_PACKET *htc_pkt; adf_nbuf_queue_init(&skb_queue); adf_os_spin_lock_bh(&pAdapter->data_lock); while (!HTC_QUEUE_EMPTY(pPacketQueue)) { htc_pkt = HTC_PACKET_DEQUEUE(pPacketQueue); if (htc_pkt == NULL) break; status=htc_pkt->Status; eid=htc_pkt->Endpoint; pktSkb=GET_HTC_PACKET_NET_BUF_CONTEXT(htc_pkt); cookie = htc_pkt->pPktContext; if (!pktSkb) { EPPING_LOG(VOS_TRACE_LEVEL_ERROR, "%s: pktSkb is NULL", __func__); ASSERT(0); } else { if (htc_pkt->pBuffer != adf_nbuf_data(pktSkb)) { EPPING_LOG(VOS_TRACE_LEVEL_ERROR, "%s: htc_pkt buffer not equal to skb->data", __func__); ASSERT(0); } /* add this to the list, use faster non-lock API */ adf_nbuf_queue_add(&skb_queue,pktSkb); if (A_SUCCESS(status)) if (htc_pkt->ActualLength != adf_nbuf_len(pktSkb)) { EPPING_LOG(VOS_TRACE_LEVEL_ERROR, "%s: htc_pkt length not equal to skb->len", __func__); ASSERT(0); } } EPPING_LOG(VOS_TRACE_LEVEL_INFO, "%s skb=%p data=%p len=0x%x eid=%d ", __func__, pktSkb, htc_pkt->pBuffer, htc_pkt->ActualLength, eid); if (A_FAILED(status)) { if (status == A_ECANCELED) { /* a packet was flushed */ flushing = TRUE; } if (status != A_NO_RESOURCE) { printk("%s() -TX ERROR, status: 0x%x\n", __func__, status); } } else { EPPING_LOG(VOS_TRACE_LEVEL_INFO, "%s: OK\n", __func__); flushing = FALSE; } epping_free_cookie(pAdapter->pEpping_ctx, cookie); } adf_os_spin_unlock_bh(&pAdapter->data_lock); /* free all skbs in our local list */ while (adf_nbuf_queue_len(&skb_queue)) { /* use non-lock version */ pktSkb = adf_nbuf_queue_remove(&skb_queue); if (pktSkb == NULL) break; adf_nbuf_tx_free(pktSkb, ADF_NBUF_PKT_ERROR); pEpping_ctx->total_tx_acks++; } if (!flushing) { netif_wake_queue(dev); } }
static int epping_tx_send_int(adf_nbuf_t skb, epping_adapter_t *pAdapter) { EPPING_HEADER *eppingHdr = (EPPING_HEADER *)adf_nbuf_data(skb); HTC_ENDPOINT_ID eid = ENDPOINT_UNUSED; struct epping_cookie * cookie = NULL; A_UINT8 ac = 0; A_STATUS ret = A_OK; int skb_len; EPPING_HEADER tmpHdr = *eppingHdr; /* allocate resource for this packet */ cookie = epping_alloc_cookie(pAdapter->pEpping_ctx); /* no resource */ if (cookie == NULL) { EPPING_LOG(VOS_TRACE_LEVEL_FATAL, "%s: epping_alloc_cookie returns no resource\n", __func__); return -1; } if (enb_tx_dump) epping_hex_dump((void *)eppingHdr, skb->len, __func__); /* * a quirk of linux, the payload of the frame is 32-bit aligned and thus * the addition of the HTC header will mis-align the start of the HTC * frame, so we add some padding which will be stripped off in the target */ if (EPPING_ALIGNMENT_PAD > 0) { A_NETBUF_PUSH(skb, EPPING_ALIGNMENT_PAD); } /* prepare ep/HTC information */ ac = eppingHdr->StreamNo_h; eid = pAdapter->pEpping_ctx->EppingEndpoint[ac]; if (eid < 0 || eid >= EPPING_MAX_NUM_EPIDS) { EPPING_LOG(VOS_TRACE_LEVEL_FATAL, "%s: invalid eid = %d, ac = %d\n", __func__, eid, ac); return -1; } if (tmpHdr.Cmd_h == EPPING_CMD_RESET_RECV_CNT || tmpHdr.Cmd_h == EPPING_CMD_CONT_RX_START) { epping_set_kperf_flag(pAdapter, eid, tmpHdr.CmdBuffer_t[0]); } if (pAdapter->pEpping_ctx->kperf[eid]) { switch (tmpHdr.Cmd_h) { case EPPING_CMD_NO_ECHO: #ifdef HIF_PCI epping_tx_copier_schedule(pAdapter->pEpping_ctx, eid, skb); #endif /* HIF_PCI */ break; default: break; } } if (pAdapter->pEpping_ctx->kperf[eid] && tmpHdr.Cmd_h == EPPING_CMD_NO_ECHO) { epping_tx_dup_pkt(pAdapter, eid, skb); } SET_HTC_PACKET_INFO_TX(&cookie->HtcPkt, cookie, adf_nbuf_data(skb), adf_nbuf_len(skb), eid, 0); SET_HTC_PACKET_NET_BUF_CONTEXT(&cookie->HtcPkt, skb); skb_len = skb->len; /* send the packet */ ret = HTCSendPkt(pAdapter->pEpping_ctx->HTCHandle, &cookie->HtcPkt); epping_log_packet(pAdapter, &tmpHdr, ret, __func__); if (ret != A_OK) { EPPING_LOG(VOS_TRACE_LEVEL_FATAL, "%s: HTCSendPkt failed, status = %d\n", __func__, ret); epping_free_cookie(pAdapter->pEpping_ctx, cookie); return -1; } pAdapter->stats.tx_bytes += skb_len; ++pAdapter->stats.tx_packets; if (((pAdapter->stats.tx_packets + pAdapter->stats.tx_dropped) % EPPING_STATS_LOG_COUNT) == 0 && (pAdapter->stats.tx_packets || pAdapter->stats.tx_dropped)) { epping_log_stats(pAdapter, __func__); } return 0; }
static void WMIRecvMessageHandler(HTC_ENDPOINT_ID EndPt, adf_nbuf_t hdr_buf, adf_nbuf_t pHTCBuf, void *arg) { void *pContext; WMI_SVC_CONTEXT *pWMI = (WMI_SVC_CONTEXT *)arg; WMI_DISPATCH_TABLE *pCurrentTable; WMI_DISPATCH_ENTRY*pCurrentEntry; WMI_CMD_HANDLER pCmdHandler; A_UINT8* pCmdBuffer; int i; A_UINT16 cmd; A_UINT16 seq; int length; a_uint8_t *anbdata; a_uint32_t anblen; WMI_CMD_HDR *cmdHdr; adf_os_assert(hdr_buf == ADF_NBUF_NULL); do { length = adf_nbuf_len(pHTCBuf); if (length < sizeof(WMI_CMD_HDR)) { break; } adf_nbuf_peek_header(pHTCBuf, &anbdata, &anblen); pCurrentTable = pWMI->pDispatchHead; length = length - sizeof(WMI_CMD_HDR); cmdHdr = (WMI_CMD_HDR *)anbdata; cmd = adf_os_ntohs(cmdHdr->commandId); seq = adf_os_ntohs(cmdHdr->seqNo); pCmdBuffer = anbdata + sizeof(WMI_CMD_HDR); pCmdHandler = NULL; while (pCurrentTable != NULL) { pContext = pCurrentTable->pContext; pCurrentEntry = pCurrentTable->pTable; /* scan table entries */ for (i = 0; i < pCurrentTable->NumberOfEntries; i++, pCurrentEntry++) { if (pCurrentEntry->CmdID == cmd) { /* found a match */ pCmdHandler = pCurrentEntry->pCmdHandler; /* optionally check length */ if ((pCurrentEntry->CheckLength != 0) && (length < pCurrentEntry->CheckLength)) { /* do not process command */ pCmdHandler = NULL; } /* end search */ break; } } if (pCmdHandler != NULL) { /* found a handler */ break; } /* scan next table */ pCurrentTable = pCurrentTable->pNext; } if (NULL == pCmdHandler) { break; } /* if we get here, we have a command handler to dispatch */ /* call dispatch function */ pCmdHandler(pContext, cmd, seq, pCmdBuffer, length); } while (FALSE); /* Invalidate the buffer (including HTC header). Note : we only need to invalidate up to the portion * that was used (cache invalidate will also round up to the nearest cache line). * The rest of the buffer should still be coherent. * */ HTC_ReturnBuffers(pWMI->HtcHandle, EndPt, pHTCBuf); }
void __wmi_control_rx(struct wmi_unified *wmi_handle, wmi_buf_t evt_buf) { u_int32_t id; u_int8_t *data; u_int32_t len; void *wmi_cmd_struct_ptr = NULL; int tlv_ok_status = 0; id = WMI_GET_FIELD(adf_nbuf_data(evt_buf), WMI_CMD_HDR, COMMANDID); if (adf_nbuf_pull_head(evt_buf, sizeof(WMI_CMD_HDR)) == NULL) goto end; data = adf_nbuf_data(evt_buf); len = adf_nbuf_len(evt_buf); /* Validate and pad(if necessary) the TLVs */ tlv_ok_status = wmitlv_check_and_pad_event_tlvs(wmi_handle->scn_handle, data, len, id, &wmi_cmd_struct_ptr); if (tlv_ok_status != 0) { pr_err("%s: Error: id=0x%d, wmitlv_check_and_pad_tlvs ret=%d\n", __func__, id, tlv_ok_status); goto end; } #ifdef FEATURE_WLAN_D0WOW if (wmi_get_d0wow_flag(wmi_handle)) pr_debug("%s: WMI event ID is 0x%x\n", __func__, id); #endif if (id >= WMI_EVT_GRP_START_ID(WMI_GRP_START)) { u_int32_t idx = 0; idx = wmi_unified_get_event_handler_ix(wmi_handle, id) ; if (idx == -1) { pr_err("%s : event handler is not registered: event id 0x%x\n", __func__, id); goto end; } #ifdef WMI_INTERFACE_EVENT_LOGGING adf_os_spin_lock_bh(&wmi_handle->wmi_record_lock); /* Exclude 4 bytes of TLV header */ WMI_EVENT_RECORD(id, ((u_int8_t *)data + 4)); adf_os_spin_unlock_bh(&wmi_handle->wmi_record_lock); #endif /* Call the WMI registered event handler */ wmi_handle->event_handler[idx](wmi_handle->scn_handle, wmi_cmd_struct_ptr, len); goto end; } switch (id) { default: pr_info("%s: Unhandled WMI event %d\n", __func__, id); break; case WMI_SERVICE_READY_EVENTID: pr_info("%s: WMI UNIFIED SERVICE READY event\n", __func__); wma_rx_service_ready_event(wmi_handle->scn_handle, wmi_cmd_struct_ptr); break; case WMI_READY_EVENTID: pr_info("%s: WMI UNIFIED READY event\n", __func__); wma_rx_ready_event(wmi_handle->scn_handle, wmi_cmd_struct_ptr); break; } end: wmitlv_free_allocated_event_tlvs(id, &wmi_cmd_struct_ptr); adf_nbuf_free(evt_buf); }
A_STATUS htt_h2t_rx_ring_cfg_msg_hl(struct htt_pdev_t *pdev) { struct htt_htc_pkt *pkt; adf_nbuf_t msg; u_int32_t *msg_word; pkt = htt_htc_pkt_alloc(pdev); if (!pkt) { return A_ERROR; /* failure */ } /* show that this is not a tx frame download (not required, but helpful) */ pkt->msdu_id = HTT_TX_COMPL_INV_MSDU_ID; pkt->pdev_ctxt = NULL; /* not used during send-done callback */ msg = adf_nbuf_alloc( pdev->osdev, HTT_MSG_BUF_SIZE(HTT_RX_RING_CFG_BYTES(1)), /* reserve room for the HTC header */ HTC_HEADER_LEN + HTC_HDR_ALIGNMENT_PADDING, 4, TRUE); if (!msg) { htt_htc_pkt_free(pdev, pkt); return A_ERROR; /* failure */ } /* * Set the length of the message. * The contribution from the HTC_HDR_ALIGNMENT_PADDING is added * separately during the below call to adf_nbuf_push_head. * The contribution from the HTC header is added separately inside HTC. */ adf_nbuf_put_tail(msg, HTT_RX_RING_CFG_BYTES(1)); /* fill in the message contents */ msg_word = (u_int32_t *) adf_nbuf_data(msg); /* rewind beyond alignment pad to get to the HTC header reserved area */ adf_nbuf_push_head(msg, HTC_HDR_ALIGNMENT_PADDING); *msg_word = 0; HTT_H2T_MSG_TYPE_SET(*msg_word, HTT_H2T_MSG_TYPE_RX_RING_CFG); HTT_RX_RING_CFG_NUM_RINGS_SET(*msg_word, 1); msg_word++; *msg_word = 0; HTT_RX_RING_CFG_IDX_SHADOW_REG_PADDR_SET( *msg_word, pdev->rx_ring.alloc_idx.paddr); msg_word++; *msg_word = 0; HTT_RX_RING_CFG_BASE_PADDR_SET(*msg_word, pdev->rx_ring.base_paddr); msg_word++; *msg_word = 0; HTT_RX_RING_CFG_LEN_SET(*msg_word, pdev->rx_ring.size); HTT_RX_RING_CFG_BUF_SZ_SET(*msg_word, HTT_RX_BUF_SIZE); /* FIX THIS: if the FW creates a complete translated rx descriptor, then the MAC DMA of the HW rx descriptor should be disabled. */ msg_word++; *msg_word = 0; HTT_RX_RING_CFG_ENABLED_802_11_HDR_SET(*msg_word, 0); HTT_RX_RING_CFG_ENABLED_MSDU_PAYLD_SET(*msg_word, 1); HTT_RX_RING_CFG_ENABLED_PPDU_START_SET(*msg_word, 0); HTT_RX_RING_CFG_ENABLED_PPDU_END_SET(*msg_word, 0); HTT_RX_RING_CFG_ENABLED_MPDU_START_SET(*msg_word, 0); HTT_RX_RING_CFG_ENABLED_MPDU_END_SET(*msg_word, 0); HTT_RX_RING_CFG_ENABLED_MSDU_START_SET(*msg_word, 0); HTT_RX_RING_CFG_ENABLED_MSDU_END_SET(*msg_word, 0); HTT_RX_RING_CFG_ENABLED_RX_ATTN_SET(*msg_word, 0); HTT_RX_RING_CFG_ENABLED_FRAG_INFO_SET(*msg_word, 0); /* always present? */ HTT_RX_RING_CFG_ENABLED_UCAST_SET(*msg_word, 1); HTT_RX_RING_CFG_ENABLED_MCAST_SET(*msg_word, 1); /* Must change to dynamic enable at run time * rather than at compile time */ HTT_RX_RING_CFG_ENABLED_CTRL_SET(*msg_word, 0); HTT_RX_RING_CFG_ENABLED_MGMT_SET(*msg_word, 0); HTT_RX_RING_CFG_ENABLED_NULL_SET(*msg_word, 0); HTT_RX_RING_CFG_ENABLED_PHY_SET(*msg_word, 0); msg_word++; *msg_word = 0; HTT_RX_RING_CFG_OFFSET_802_11_HDR_SET(*msg_word, 0); HTT_RX_RING_CFG_OFFSET_MSDU_PAYLD_SET(*msg_word, 0); msg_word++; *msg_word = 0; HTT_RX_RING_CFG_OFFSET_PPDU_START_SET(*msg_word, 0); HTT_RX_RING_CFG_OFFSET_PPDU_END_SET(*msg_word, 0); msg_word++; *msg_word = 0; HTT_RX_RING_CFG_OFFSET_MPDU_START_SET(*msg_word, 0); HTT_RX_RING_CFG_OFFSET_MPDU_END_SET(*msg_word, 0); msg_word++; *msg_word = 0; HTT_RX_RING_CFG_OFFSET_MSDU_START_SET(*msg_word, 0); HTT_RX_RING_CFG_OFFSET_MSDU_END_SET(*msg_word, 0); msg_word++; *msg_word = 0; HTT_RX_RING_CFG_OFFSET_RX_ATTN_SET(*msg_word, 0); HTT_RX_RING_CFG_OFFSET_FRAG_INFO_SET(*msg_word, 0); SET_HTC_PACKET_INFO_TX( &pkt->htc_pkt, htt_h2t_send_complete_free_netbuf, adf_nbuf_data(msg), adf_nbuf_len(msg), pdev->htc_endpoint, 1); /* tag - not relevant here */ SET_HTC_PACKET_NET_BUF_CONTEXT(&pkt->htc_pkt, msg); #ifdef ATH_11AC_TXCOMPACT if (HTCSendPkt(pdev->htc_pdev, &pkt->htc_pkt) == A_OK) { htt_htc_misc_pkt_list_add(pdev, pkt); } #else HTCSendPkt(pdev->htc_pdev, &pkt->htc_pkt); #endif if (!pdev->cfg.default_tx_comp_req) { ol_tx_target_credit_update(pdev->txrx_pdev, -1); } return A_OK; }
A_STATUS HTCSendPkt(HTC_HANDLE hHTC, adf_nbuf_t hdr_buf, adf_nbuf_t buf, HTC_ENDPOINT_ID Ep) { HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(hHTC); A_STATUS status = A_OK; HTC_ENDPOINT *pEndpoint; #ifndef ATH_HTC_TX_SCHED do { if (Ep >= ENDPOINT_MAX) { adf_os_print("Ep %u is invalid!\n", Ep); if (hdr_buf) { adf_nbuf_free(hdr_buf); } if (buf) { adf_nbuf_free(buf); } status = A_EPROTO; break; } pEndpoint = &target->EndPoint[Ep]; #if 0 LOCK_HTC_TX(target); /* record number of buffers in corresponding endpoint */ if ((pAggrNumRec = HTC_AGGRNUMREC_DEQUEUE(&target->FreeAggrNumRecQueue)) == NULL) { adf_os_print("%s no more free aggr record\n", __FUNCTION__); status = A_NO_RESOURCE; UNLOCK_HTC_TX(target); break; } pAggrNumRec->AggrNum = num; pAggrNumRec->bufArray = bufArray; /* buffers were supplied to be queued */ HTC_AGGRNUMREC_ENQUEUE(&pEndpoint->AggrNumRecQueue, pAggrNumRec); UNLOCK_HTC_TX(target); #endif status = HTCTrySend(target, pEndpoint, hdr_buf, buf); // adf_os_print("return value of HTCTrySend: %u\n", status); } while(FALSE); #else a_uint16_t payloadLen; a_uint8_t SendFlags = 0; pEndpoint = &target->EndPoint[Ep]; if ( HIFGetFreeQueueNumber(target->hif_dev, pEndpoint->UL_PipeID) == 0 ) return -1 ; if(hdr_buf != NULL) payloadLen = (a_uint16_t) (adf_nbuf_len(hdr_buf) + adf_nbuf_len(buf)); else payloadLen = (a_uint16_t) adf_nbuf_len(buf) ; #ifdef HTC_HOST_CREDIT_DIST /* check if credits are enough for sending this packet */ #ifdef WMI_RETRY if((Ep != 1 ) && (Ep != 2)) #endif { status = HTCCheckCredits(target, HTC_HDR_LENGTH + payloadLen, pEndpoint, &SendFlags); if (A_FAILED(status)) { //adf_os_print("credits are not enough for sending the message!\n"); return status; } } #endif status = HTCIssueSend(target, hdr_buf, buf, SendFlags, payloadLen, Ep); if (A_FAILED(status)) { HTCReclaimCredits(target, HTC_HDR_LENGTH + payloadLen, pEndpoint); return -1 ; } #endif return status; }
int htt_h2t_ipa_uc_rsc_cfg_msg(struct htt_pdev_t *pdev) { struct htt_htc_pkt *pkt; adf_nbuf_t msg; u_int32_t *msg_word; pkt = htt_htc_pkt_alloc(pdev); if (!pkt) { return A_NO_MEMORY; } /* show that this is not a tx frame download (not required, but helpful) */ pkt->msdu_id = HTT_TX_COMPL_INV_MSDU_ID; pkt->pdev_ctxt = NULL; /* not used during send-done callback */ msg = adf_nbuf_alloc( pdev->osdev, HTT_MSG_BUF_SIZE(HTT_WDI_IPA_CFG_SZ), /* reserve room for HTC header */ HTC_HEADER_LEN + HTC_HDR_ALIGNMENT_PADDING, 4, FALSE); if (!msg) { htt_htc_pkt_free(pdev, pkt); return A_NO_MEMORY; } /* set the length of the message */ adf_nbuf_put_tail(msg, HTT_WDI_IPA_CFG_SZ); /* fill in the message contents */ msg_word = (u_int32_t *) adf_nbuf_data(msg); /* rewind beyond alignment pad to get to the HTC header reserved area */ adf_nbuf_push_head(msg, HTC_HDR_ALIGNMENT_PADDING); *msg_word = 0; HTT_WDI_IPA_CFG_TX_PKT_POOL_SIZE_SET(*msg_word, pdev->ipa_uc_tx_rsc.alloc_tx_buf_cnt); HTT_H2T_MSG_TYPE_SET(*msg_word, HTT_H2T_MSG_TYPE_WDI_IPA_CFG); msg_word++; *msg_word = 0; HTT_WDI_IPA_CFG_TX_COMP_RING_BASE_ADDR_SET(*msg_word, (unsigned int)pdev->ipa_uc_tx_rsc.tx_comp_base.paddr); msg_word++; *msg_word = 0; HTT_WDI_IPA_CFG_TX_COMP_RING_SIZE_SET(*msg_word, (unsigned int)ol_cfg_ipa_uc_tx_max_buf_cnt(pdev->ctrl_pdev)); msg_word++; *msg_word = 0; HTT_WDI_IPA_CFG_TX_COMP_WR_IDX_ADDR_SET(*msg_word, (unsigned int)pdev->ipa_uc_tx_rsc.tx_comp_idx_paddr); msg_word++; *msg_word = 0; HTT_WDI_IPA_CFG_TX_CE_WR_IDX_ADDR_SET(*msg_word, (unsigned int)pdev->ipa_uc_tx_rsc.tx_ce_idx.paddr); msg_word++; *msg_word = 0; HTT_WDI_IPA_CFG_RX_IND_RING_BASE_ADDR_SET(*msg_word, (unsigned int)pdev->ipa_uc_rx_rsc.rx_ind_ring_base.paddr); msg_word++; *msg_word = 0; HTT_WDI_IPA_CFG_RX_IND_RING_SIZE_SET(*msg_word, (unsigned int)ol_cfg_ipa_uc_rx_ind_ring_size(pdev->ctrl_pdev)); msg_word++; *msg_word = 0; HTT_WDI_IPA_CFG_RX_IND_RD_IDX_ADDR_SET(*msg_word, (unsigned int)pdev->ipa_uc_rx_rsc.rx_ipa_prc_done_idx.paddr); msg_word++; *msg_word = 0; HTT_WDI_IPA_CFG_RX_IND_WR_IDX_ADDR_SET(*msg_word, (unsigned int)pdev->ipa_uc_rx_rsc.rx_rdy_idx_paddr); SET_HTC_PACKET_INFO_TX( &pkt->htc_pkt, htt_h2t_send_complete_free_netbuf, adf_nbuf_data(msg), adf_nbuf_len(msg), pdev->htc_endpoint, HTC_TX_PACKET_TAG_RUNTIME_PUT); SET_HTC_PACKET_NET_BUF_CONTEXT(&pkt->htc_pkt, msg); #ifdef ATH_11AC_TXCOMPACT if (HTCSendPkt(pdev->htc_pdev, &pkt->htc_pkt) == A_OK) htt_htc_misc_pkt_list_add(pdev, pkt); #else HTCSendPkt(pdev->htc_pdev, &pkt->htc_pkt); #endif return A_OK; }
/* * Temporarily added to support older WMI events. We should move all events to unified * when the target is ready to support it. */ void wmi_control_rx(void *ctx, HTC_PACKET *htc_packet) { struct wmi_unified *wmi_handle = (struct wmi_unified *)ctx; wmi_buf_t evt_buf; u_int32_t len; void *wmi_cmd_struct_ptr = NULL; u_int32_t idx = 0; int tlv_ok_status = 0; #if defined(WMI_INTERFACE_EVENT_LOGGING) || !defined(QCA_CONFIG_SMP) u_int32_t id; u_int8_t *data; #endif evt_buf = (wmi_buf_t) htc_packet->pPktContext; id = WMI_GET_FIELD(adf_nbuf_data(evt_buf), WMI_CMD_HDR, COMMANDID); /* TX_PAUSE EVENT should be handled with tasklet context */ if ((WMI_TX_PAUSE_EVENTID == id) || (WMI_WOW_WAKEUP_HOST_EVENTID == id)) { if (adf_nbuf_pull_head(evt_buf, sizeof(WMI_CMD_HDR)) == NULL) return; data = adf_nbuf_data(evt_buf); len = adf_nbuf_len(evt_buf); tlv_ok_status = wmitlv_check_and_pad_event_tlvs( wmi_handle->scn_handle, data, len, id, &wmi_cmd_struct_ptr); if (tlv_ok_status != 0) { if (tlv_ok_status == 1) { wmi_cmd_struct_ptr = data; } else { return; } } idx = wmi_unified_get_event_handler_ix(wmi_handle, id); if (idx == -1) { wmitlv_free_allocated_event_tlvs(id, &wmi_cmd_struct_ptr); adf_nbuf_free(evt_buf); return; } wmi_handle->event_handler[idx](wmi_handle->scn_handle, wmi_cmd_struct_ptr, len); wmitlv_free_allocated_event_tlvs(id, &wmi_cmd_struct_ptr); adf_nbuf_free(evt_buf); return; } #ifdef WMI_INTERFACE_EVENT_LOGGING id = WMI_GET_FIELD(adf_nbuf_data(evt_buf), WMI_CMD_HDR, COMMANDID); data = adf_nbuf_data(evt_buf); adf_os_spin_lock_bh(&wmi_handle->wmi_record_lock); /* Exclude 4 bytes of TLV header */ WMI_RX_EVENT_RECORD(id, ((u_int8_t *)data + 4)); adf_os_spin_unlock_bh(&wmi_handle->wmi_record_lock); #endif adf_os_spin_lock_bh(&wmi_handle->eventq_lock); adf_nbuf_queue_add(&wmi_handle->event_queue, evt_buf); adf_os_spin_unlock_bh(&wmi_handle->eventq_lock); schedule_work(&wmi_handle->rx_event_work); }
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); pEndpoint = &target->EndPoint[htc_ep_id]; 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; break; } /* * 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 =%d\n", netlen, payloadLen + HTC_HDR_LENGTH)); DebugDumpBytes((A_UINT8 *)HtcHdr,sizeof(HTC_FRAME_HDR),"BAD RX packet length"); status = A_ERROR; 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, ("HTCProcessRecvHeader, 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; /* 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; break; } LOCK_HTC_RX(target); target->CtrlResponseLength = min((int)netlen,HTC_MAX_CONTROL_MESSAGE_LENGTH); A_MEMCPY(target->CtrlResponseBuffer,netdata,target->CtrlResponseLength); UNLOCK_HTC_RX(target); adf_os_mutex_release(target->osdev, &target->CtrlResponseValid); break; case HTC_MSG_SEND_SUSPEND_COMPLETE: target->HTCInitInfo.TargetSendSuspendComplete(target->HTCInitInfo.pContext); 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; /* TODO : this is a hack because the driver layer will set the actual length * of the skb again which will just double the length */ //A_NETBUF_TRIM(netbuf,netlen); adf_nbuf_trim_tail(netbuf, netlen); 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; }
A_STATUS htt_h2t_rx_ring_cfg_msg_ll(struct htt_pdev_t *pdev) { struct htt_htc_pkt *pkt; adf_nbuf_t msg; u_int32_t *msg_word; int enable_ctrl_data, enable_mgmt_data, enable_null_data, enable_phy_data, enable_hdr, enable_ppdu_start, enable_ppdu_end; pkt = htt_htc_pkt_alloc(pdev); if (!pkt) { return A_ERROR; /* failure */ } /* show that this is not a tx frame download (not required, but helpful) */ pkt->msdu_id = HTT_TX_COMPL_INV_MSDU_ID; pkt->pdev_ctxt = NULL; /* not used during send-done callback */ msg = adf_nbuf_alloc( pdev->osdev, HTT_MSG_BUF_SIZE(HTT_RX_RING_CFG_BYTES(1)), /* reserve room for the HTC header */ HTC_HEADER_LEN + HTC_HDR_ALIGNMENT_PADDING, 4, TRUE); if (!msg) { htt_htc_pkt_free(pdev, pkt); return A_ERROR; /* failure */ } /* * Set the length of the message. * The contribution from the HTC_HDR_ALIGNMENT_PADDING is added * separately during the below call to adf_nbuf_push_head. * The contribution from the HTC header is added separately inside HTC. */ adf_nbuf_put_tail(msg, HTT_RX_RING_CFG_BYTES(1)); /* fill in the message contents */ msg_word = (u_int32_t *) adf_nbuf_data(msg); /* rewind beyond alignment pad to get to the HTC header reserved area */ adf_nbuf_push_head(msg, HTC_HDR_ALIGNMENT_PADDING); *msg_word = 0; HTT_H2T_MSG_TYPE_SET(*msg_word, HTT_H2T_MSG_TYPE_RX_RING_CFG); HTT_RX_RING_CFG_NUM_RINGS_SET(*msg_word, 1); msg_word++; *msg_word = 0; HTT_RX_RING_CFG_IDX_SHADOW_REG_PADDR_SET( *msg_word, pdev->rx_ring.alloc_idx.paddr); msg_word++; *msg_word = 0; HTT_RX_RING_CFG_BASE_PADDR_SET(*msg_word, pdev->rx_ring.base_paddr); msg_word++; *msg_word = 0; HTT_RX_RING_CFG_LEN_SET(*msg_word, pdev->rx_ring.size); HTT_RX_RING_CFG_BUF_SZ_SET(*msg_word, HTT_RX_BUF_SIZE); /* FIX THIS: if the FW creates a complete translated rx descriptor, then the MAC DMA of the HW rx descriptor should be disabled. */ msg_word++; *msg_word = 0; #ifndef REMOVE_PKT_LOG if (ol_cfg_is_packet_log_enabled(pdev->ctrl_pdev)) { enable_ctrl_data = 1; enable_mgmt_data = 1; enable_null_data = 1; enable_phy_data = 1; enable_hdr = 1; enable_ppdu_start= 1; enable_ppdu_end = 1; /* Disable ASPM when pkt log is enabled */ adf_os_print("Pkt log is enabled\n"); htt_htc_disable_aspm(); } else { adf_os_print("Pkt log is disabled\n"); enable_ctrl_data = 0; enable_mgmt_data = 0; enable_null_data = 0; enable_phy_data = 0; enable_hdr = 0; enable_ppdu_start= 0; enable_ppdu_end = 0; } #else enable_ctrl_data = 0; enable_mgmt_data = 0; enable_null_data = 0; enable_phy_data = 0; enable_hdr = 0; enable_ppdu_start= 0; enable_ppdu_end = 0; #endif HTT_RX_RING_CFG_ENABLED_802_11_HDR_SET(*msg_word, enable_hdr); HTT_RX_RING_CFG_ENABLED_MSDU_PAYLD_SET(*msg_word, 1); HTT_RX_RING_CFG_ENABLED_PPDU_START_SET(*msg_word, enable_ppdu_start); HTT_RX_RING_CFG_ENABLED_PPDU_END_SET(*msg_word, enable_ppdu_end); HTT_RX_RING_CFG_ENABLED_MPDU_START_SET(*msg_word, 1); HTT_RX_RING_CFG_ENABLED_MPDU_END_SET(*msg_word, 1); HTT_RX_RING_CFG_ENABLED_MSDU_START_SET(*msg_word, 1); HTT_RX_RING_CFG_ENABLED_MSDU_END_SET(*msg_word, 1); HTT_RX_RING_CFG_ENABLED_RX_ATTN_SET(*msg_word, 1); HTT_RX_RING_CFG_ENABLED_FRAG_INFO_SET(*msg_word, 1); /* always present? */ HTT_RX_RING_CFG_ENABLED_UCAST_SET(*msg_word, 1); HTT_RX_RING_CFG_ENABLED_MCAST_SET(*msg_word, 1); /* Must change to dynamic enable at run time * rather than at compile time */ HTT_RX_RING_CFG_ENABLED_CTRL_SET(*msg_word, enable_ctrl_data); HTT_RX_RING_CFG_ENABLED_MGMT_SET(*msg_word, enable_mgmt_data); HTT_RX_RING_CFG_ENABLED_NULL_SET(*msg_word, enable_null_data); HTT_RX_RING_CFG_ENABLED_PHY_SET(*msg_word, enable_phy_data); HTT_RX_RING_CFG_IDX_INIT_VAL_SET(*msg_word, *pdev->rx_ring.alloc_idx.vaddr); msg_word++; *msg_word = 0; HTT_RX_RING_CFG_OFFSET_802_11_HDR_SET(*msg_word, RX_STD_DESC_HDR_STATUS_OFFSET_DWORD); HTT_RX_RING_CFG_OFFSET_MSDU_PAYLD_SET(*msg_word, HTT_RX_STD_DESC_RESERVATION_DWORD); msg_word++; *msg_word = 0; HTT_RX_RING_CFG_OFFSET_PPDU_START_SET(*msg_word, RX_STD_DESC_PPDU_START_OFFSET_DWORD); HTT_RX_RING_CFG_OFFSET_PPDU_END_SET(*msg_word, RX_STD_DESC_PPDU_END_OFFSET_DWORD); msg_word++; *msg_word = 0; HTT_RX_RING_CFG_OFFSET_MPDU_START_SET(*msg_word, RX_STD_DESC_MPDU_START_OFFSET_DWORD); HTT_RX_RING_CFG_OFFSET_MPDU_END_SET(*msg_word, RX_STD_DESC_MPDU_END_OFFSET_DWORD); msg_word++; *msg_word = 0; HTT_RX_RING_CFG_OFFSET_MSDU_START_SET(*msg_word, RX_STD_DESC_MSDU_START_OFFSET_DWORD); HTT_RX_RING_CFG_OFFSET_MSDU_END_SET(*msg_word, RX_STD_DESC_MSDU_END_OFFSET_DWORD); msg_word++; *msg_word = 0; HTT_RX_RING_CFG_OFFSET_RX_ATTN_SET(*msg_word, RX_STD_DESC_ATTN_OFFSET_DWORD); HTT_RX_RING_CFG_OFFSET_FRAG_INFO_SET(*msg_word, RX_STD_DESC_FRAG_INFO_OFFSET_DWORD); SET_HTC_PACKET_INFO_TX( &pkt->htc_pkt, htt_h2t_send_complete_free_netbuf, adf_nbuf_data(msg), adf_nbuf_len(msg), pdev->htc_endpoint, HTC_TX_PACKET_TAG_RUNTIME_PUT); SET_HTC_PACKET_NET_BUF_CONTEXT(&pkt->htc_pkt, msg); #ifdef ATH_11AC_TXCOMPACT if (HTCSendPkt(pdev->htc_pdev, &pkt->htc_pkt) == A_OK) htt_htc_misc_pkt_list_add(pdev, pkt); #else HTCSendPkt(pdev->htc_pdev, &pkt->htc_pkt); #endif return A_OK; }
int htt_h2t_dbg_stats_get( struct htt_pdev_t *pdev, u_int32_t stats_type_upload_mask, u_int32_t stats_type_reset_mask, u_int8_t cfg_stat_type, u_int32_t cfg_val, u_int64_t cookie) { struct htt_htc_pkt *pkt; adf_nbuf_t msg; u_int32_t *msg_word; uint16_t htc_tag = 1; pkt = htt_htc_pkt_alloc(pdev); if (!pkt) { return -1; /* failure */ } if (stats_type_upload_mask >= 1 << HTT_DBG_NUM_STATS || stats_type_reset_mask >= 1 << HTT_DBG_NUM_STATS) { /* FIX THIS - add more details? */ adf_os_print("%#x %#x stats not supported\n", stats_type_upload_mask, stats_type_reset_mask); return -1; /* failure */ } if (stats_type_reset_mask) htc_tag = HTC_TX_PACKET_TAG_RUNTIME_PUT; /* show that this is not a tx frame download (not required, but helpful) */ pkt->msdu_id = HTT_TX_COMPL_INV_MSDU_ID; pkt->pdev_ctxt = NULL; /* not used during send-done callback */ msg = adf_nbuf_alloc( pdev->osdev, HTT_MSG_BUF_SIZE(HTT_H2T_STATS_REQ_MSG_SZ), /* reserve room for HTC header */ HTC_HEADER_LEN + HTC_HDR_ALIGNMENT_PADDING, 4, FALSE); if (!msg) { htt_htc_pkt_free(pdev, pkt); return -1; /* failure */ } /* set the length of the message */ adf_nbuf_put_tail(msg, HTT_H2T_STATS_REQ_MSG_SZ); /* fill in the message contents */ msg_word = (u_int32_t *) adf_nbuf_data(msg); /* rewind beyond alignment pad to get to the HTC header reserved area */ adf_nbuf_push_head(msg, HTC_HDR_ALIGNMENT_PADDING); *msg_word = 0; HTT_H2T_MSG_TYPE_SET(*msg_word, HTT_H2T_MSG_TYPE_STATS_REQ); HTT_H2T_STATS_REQ_UPLOAD_TYPES_SET(*msg_word, stats_type_upload_mask); msg_word++; *msg_word = 0; HTT_H2T_STATS_REQ_RESET_TYPES_SET(*msg_word, stats_type_reset_mask); msg_word++; *msg_word = 0; HTT_H2T_STATS_REQ_CFG_VAL_SET(*msg_word, cfg_val); HTT_H2T_STATS_REQ_CFG_STAT_TYPE_SET(*msg_word, cfg_stat_type); /* cookie LSBs */ msg_word++; *msg_word = cookie & 0xffffffff; /* cookie MSBs */ msg_word++; *msg_word = cookie >> 32; SET_HTC_PACKET_INFO_TX( &pkt->htc_pkt, htt_h2t_send_complete_free_netbuf, adf_nbuf_data(msg), adf_nbuf_len(msg), pdev->htc_endpoint, htc_tag); SET_HTC_PACKET_NET_BUF_CONTEXT(&pkt->htc_pkt, msg); #ifdef ATH_11AC_TXCOMPACT if (HTCSendPkt(pdev->htc_pdev, &pkt->htc_pkt) == A_OK) { htt_htc_misc_pkt_list_add(pdev, pkt); } #else HTCSendPkt(pdev->htc_pdev, &pkt->htc_pkt); #endif if ((pdev->cfg.is_high_latency) && (!pdev->cfg.default_tx_comp_req)) { ol_tx_target_credit_update(pdev->txrx_pdev, -1); } return 0; }
LOCAL void _HTC_SendMsg(htc_handle_t htcHandle, HTC_ENDPOINT_ID EndpointID, adf_nbuf_t pBuffers) { HTC_FRAME_HDR *pHTCHdr; int totsz; HTC_CONTEXT *pHTC = (HTC_CONTEXT *)htcHandle; HTC_BUF_CONTEXT *ctx; ctx = (HTC_BUF_CONTEXT *)adf_nbuf_get_priv(pBuffers); /* init total size (this does not include the space we will put in for the HTC header) */ totsz = adf_nbuf_len(pBuffers); /* the first buffer stores the header */ /* back up buffer by a header size when we pass it down, by agreed upon convention the caller * points the buffer to it's payload and leaves head room for the HTC header * Note: in HTCSendDoneHandler(), we undo this so that the caller get's it's buffer * back untainted */ pHTCHdr = (HTC_FRAME_HDR *)adf_nbuf_push_head(pBuffers, HTC_HDR_LENGTH); /* flag that this is the header buffer that was modified */ ctx->htc_flags |= HTC_FLAGS_BUF_HDR; /* mark where this buffer came from */ ctx->end_point = EndpointID; /* the header start is ALWAYS aligned since we DMA it directly */ /* set some fields, the rest of them will be filled below when we check for * trailer space */ pHTCHdr->Flags = 0; pHTCHdr->EndpointID = EndpointID; /* check opportunistically if we can return any reports via a trailer */ do { int room,i,totalReportBytes; A_UINT32 creditsPendingMap, compareMask; HTC_CREDIT_REPORT *pCreditRpt; HTC_RECORD_HDR *pRecHdr; int pipeMaxLen; A_UINT32 roomForPipeMaxLen; /* figure out how much room the last buffer can spare */ pipeMaxLen = HIF_get_max_msg_len(pHTC->hifHandle, pHTC->Endpoints[EndpointID].DownLinkPipeID); roomForPipeMaxLen = pipeMaxLen - adf_nbuf_headroom(pBuffers) - adf_nbuf_len(pBuffers); if ( roomForPipeMaxLen < 0 ) { roomForPipeMaxLen = 0; } room = adf_os_min( adf_nbuf_tailroom(pBuffers), roomForPipeMaxLen); if (room < (int)(sizeof(HTC_CREDIT_REPORT) + sizeof(HTC_RECORD_HDR))) { /* no room for any reports */ break; } /* note, a record header only has 8 bit fields, so this is safe. * we need an uncached pointer here too */ totalReportBytes = 0; /* get a copy */ creditsPendingMap = pHTC->EpCreditPendingMap; /* test pending map to see if we can send a report , if any * credits are available, we might as well send them on the * unused space in the buffer */ if (creditsPendingMap) { pRecHdr = (HTC_RECORD_HDR *)adf_nbuf_put_tail(pBuffers, sizeof(HTC_RECORD_HDR)); /* set the ID, the length will be updated with the number of credit reports we * can fit (see below) */ pRecHdr->RecordID = HTC_RECORD_CREDITS; pRecHdr->Length = 0; /* the credit report follows the record header */ totalReportBytes += sizeof(HTC_RECORD_HDR); room -= sizeof(HTC_RECORD_HDR); /* walkthrough pending credits map and build the records */ for (i = 0; (creditsPendingMap != 0) && (room >= (int)sizeof(HTC_CREDIT_REPORT)); i++) { compareMask = (1 << i); if (compareMask & creditsPendingMap) { pCreditRpt = (HTC_CREDIT_REPORT *)adf_nbuf_put_tail(pBuffers, sizeof(HTC_CREDIT_REPORT)); /* clear pending mask, we are going to return all these credits */ creditsPendingMap &= ~(compareMask); /* add this record */ pCreditRpt->EndpointID = i; pCreditRpt->Credits = (A_UINT8)pHTC->Endpoints[i].CreditsToReturn; /* remove pending credits, we always send deltas */ pHTC->Endpoints[i].CreditsToReturn = 0; /* adjust new threshold for this endpoint if needed */ CHECK_AND_ADJUST_CREDIT_THRESHOLD(&pHTC->Endpoints[i]); /* update this record length */ pRecHdr->Length += sizeof(HTC_CREDIT_REPORT); room -= sizeof(HTC_CREDIT_REPORT); totalReportBytes += sizeof(HTC_CREDIT_REPORT); if ( room < sizeof(HTC_CREDIT_REPORT) ) { break; } } } /* update new pending credits map */ pHTC->EpCreditPendingMap = creditsPendingMap; } if (totalReportBytes <= 0) { break; } /* must fit into a byte, this should never actually happen since * the maximum possible number of endpoints is 32. * The trailer can have at most 1 credit record with up to 32 reports in the record. * The trailer can have at most 1 lookahead record with only 1 lookahead report in the record. */ /* set header option bytes */ pHTCHdr->ControlBytes[0] = totalReportBytes; /* HTC frame contains a trailer */ pHTCHdr->Flags |= HTC_FLAGS_RECV_TRAILER; /* increment total size by the reports we added */ totsz += totalReportBytes; /* adjust the last buffer we used for adding on the trailer */ } while (FALSE); if (totsz == 0) { } /* set length for message (this includes any reports that were added above) */ pHTCHdr->PayloadLen = adf_os_htons(totsz); HIF_send_buffer(pHTC->hifHandle, pHTC->Endpoints[EndpointID].DownLinkPipeID, pBuffers); }
A_STATUS htt_h2t_ver_req_msg(struct htt_pdev_t *pdev) { struct htt_htc_pkt *pkt; adf_nbuf_t msg; u_int32_t *msg_word; u_int32_t msg_size; u_int32_t max_tx_group; pkt = htt_htc_pkt_alloc(pdev); if (!pkt) { return A_ERROR; /* failure */ } max_tx_group = OL_TX_GET_MAX_GROUPS(pdev->txrx_pdev); if (max_tx_group) { msg_size = HTT_VER_REQ_BYTES + sizeof(struct htt_option_tlv_mac_tx_queue_groups_t); } else { msg_size = HTT_VER_REQ_BYTES; } /* show that this is not a tx frame download (not required, but helpful) */ pkt->msdu_id = HTT_TX_COMPL_INV_MSDU_ID; pkt->pdev_ctxt = NULL; /* not used during send-done callback */ msg = adf_nbuf_alloc( pdev->osdev, HTT_MSG_BUF_SIZE(msg_size), /* reserve room for the HTC header */ HTC_HEADER_LEN + HTC_HDR_ALIGNMENT_PADDING, 4, TRUE); if (!msg) { htt_htc_pkt_free(pdev, pkt); return A_ERROR; /* failure */ } /* * Set the length of the message. * The contribution from the HTC_HDR_ALIGNMENT_PADDING is added * separately during the below call to adf_nbuf_push_head. * The contribution from the HTC header is added separately inside HTC. */ adf_nbuf_put_tail(msg, msg_size); /* fill in the message contents */ msg_word = (u_int32_t *) adf_nbuf_data(msg); /* rewind beyond alignment pad to get to the HTC header reserved area */ adf_nbuf_push_head(msg, HTC_HDR_ALIGNMENT_PADDING); *msg_word = 0; HTT_H2T_MSG_TYPE_SET(*msg_word, HTT_H2T_MSG_TYPE_VERSION_REQ); if (max_tx_group) { *(msg_word + 1) = 0; /* Fill Group Info */ HTT_OPTION_TLV_TAG_SET(*(msg_word+1), HTT_OPTION_TLV_TAG_MAX_TX_QUEUE_GROUPS); HTT_OPTION_TLV_LENGTH_SET(*(msg_word+1), (sizeof(struct htt_option_tlv_mac_tx_queue_groups_t)/ sizeof(u_int32_t))); HTT_OPTION_TLV_VALUE0_SET(*(msg_word+1), max_tx_group); } SET_HTC_PACKET_INFO_TX( &pkt->htc_pkt, htt_h2t_send_complete_free_netbuf, adf_nbuf_data(msg), adf_nbuf_len(msg), pdev->htc_endpoint, 1); /* tag - not relevant here */ SET_HTC_PACKET_NET_BUF_CONTEXT(&pkt->htc_pkt, msg); #ifdef ATH_11AC_TXCOMPACT if (HTCSendPkt(pdev->htc_pdev, &pkt->htc_pkt) == A_OK) { htt_htc_misc_pkt_list_add(pdev, pkt); } #else HTCSendPkt(pdev->htc_pdev, &pkt->htc_pkt); #endif if ((pdev->cfg.is_high_latency) && (!pdev->cfg.default_tx_comp_req)) { ol_tx_target_credit_update(pdev->txrx_pdev, -1); } return A_OK; }