From 1c9562691142e02d08c40bf796d36751b4c9cfe3 Mon Sep 17 00:00:00 2001 From: Manjunathappa Prakash Date: Wed, 13 Apr 2016 23:39:04 -0700 Subject: [PATCH] qcacld-3.0: add fastpath Rx support With dedicated CE for Rx HTT messages, skip processing in HTC layer. Do special handling in HIF-CE and HTT layer, this optimization results in 3-4% CPU utilization gain. Change-Id: I400148a0e24ac62dd09e2a95d5f35d94d83fe2df CRs-Fixed: 987182 --- core/dp/htt/htt.c | 4 + core/dp/htt/htt_internal.h | 2 + core/dp/htt/htt_t2h.c | 245 ++++++++++++++++++++++++++++++++++- core/hdd/src/wlan_hdd_main.c | 2 + 4 files changed, 250 insertions(+), 3 deletions(-) diff --git a/core/dp/htt/htt.c b/core/dp/htt/htt.c index 840692b82dce..ed114ac44caa 100644 --- a/core/dp/htt/htt.c +++ b/core/dp/htt/htt.c @@ -397,6 +397,10 @@ int htt_htc_attach(struct htt_pdev_t *pdev) HTC_SERVICE_CONNECT_RESP response; A_STATUS status; + if (QDF_STATUS_SUCCESS != + hif_ce_fastpath_cb_register(htt_t2h_msg_handler_fast, pdev)) + qdf_print("failed to register fastpath callback\n"); + qdf_mem_set(&connect, sizeof(connect), 0); qdf_mem_set(&response, sizeof(response), 0); diff --git a/core/dp/htt/htt_internal.h b/core/dp/htt/htt_internal.h index 8b371ae5f58e..9e4628b86b3d 100644 --- a/core/dp/htt/htt_internal.h +++ b/core/dp/htt/htt_internal.h @@ -431,6 +431,8 @@ void htt_rx_detach(struct htt_pdev_t *pdev); int htt_htc_attach(struct htt_pdev_t *pdev); void htt_t2h_msg_handler(void *context, HTC_PACKET *pkt); +int htt_t2h_msg_handler_fast(void *htt_pdev, qdf_nbuf_t *cmpl_msdus, + uint32_t num_cmpls); void htt_h2t_send_complete(void *context, HTC_PACKET *pkt); diff --git a/core/dp/htt/htt_t2h.c b/core/dp/htt/htt_t2h.c index 3da86ec398d8..3efa3f76cf80 100644 --- a/core/dp/htt/htt_t2h.c +++ b/core/dp/htt/htt_t2h.c @@ -44,6 +44,7 @@ #include #include /* htt_tx_status */ +#include #include /* HTT_TX_SCHED, etc. */ #include #include @@ -132,7 +133,8 @@ static void htt_rx_frag_set_last_msdu(struct htt_pdev_t *pdev, qdf_nbuf_t msg) } /* Target to host Msg/event handler for low priority messages*/ -void htt_t2h_lp_msg_handler(void *context, qdf_nbuf_t htt_t2h_msg) +void htt_t2h_lp_msg_handler(void *context, qdf_nbuf_t htt_t2h_msg, bool + free_msg_buf) { struct htt_pdev_t *pdev = (struct htt_pdev_t *)context; uint32_t *msg_word; @@ -473,7 +475,8 @@ void htt_t2h_lp_msg_handler(void *context, qdf_nbuf_t htt_t2h_msg) break; }; /* Free the indication buffer */ - qdf_nbuf_free(htt_t2h_msg); + if (free_msg_buf) + qdf_nbuf_free(htt_t2h_msg); } /* Generic Target to host Msg/event handler for low priority messages @@ -680,7 +683,7 @@ void htt_t2h_msg_handler(void *context, HTC_PACKET *pkt) } default: - htt_t2h_lp_msg_handler(context, htt_t2h_msg); + htt_t2h_lp_msg_handler(context, htt_t2h_msg, true); return; }; @@ -689,6 +692,242 @@ void htt_t2h_msg_handler(void *context, HTC_PACKET *pkt) qdf_nbuf_free(htt_t2h_msg); } +#ifdef WLAN_FEATURE_FASTPATH +#define HTT_T2H_MSG_BUF_REINIT(_buf, dev) \ + do { \ + QDF_NBUF_CB_PADDR(_buf) -= (HTC_HEADER_LEN + \ + HTC_HDR_ALIGNMENT_PADDING); \ + qdf_nbuf_init_fast((_buf)); \ + OS_SYNC_SINGLE_FOR_DEVICE(dev, (QDF_NBUF_CB_PADDR(_buf)), \ + (skb_end_pointer(_buf) - \ + (_buf)->data) , \ + PCI_DMA_FROMDEVICE); \ + } while (0) + +/** + * htt_t2h_msg_handler_fast() - Fastpath specific message handler + * @context: HTT context + * @cmpl_msdus: netbuf completions + * @num_cmpls: number of completions to be handled + * + * Return: Number of completions handled + */ +int +htt_t2h_msg_handler_fast(void *context, qdf_nbuf_t *cmpl_msdus, + uint32_t num_cmpls) +{ + struct htt_pdev_t *pdev = (struct htt_pdev_t *)context; + qdf_nbuf_t htt_t2h_msg; + uint32_t *msg_word; + uint32_t i; + enum htt_t2h_msg_type msg_type; + uint32_t msg_len; + uint32_t num_htt_tx_cmpls = 0; + + for (i = 0; i < num_cmpls; i++) { + htt_t2h_msg = cmpl_msdus[i]; + msg_len = qdf_nbuf_len(htt_t2h_msg); + + /* + * Move the data pointer to point to HTT header + * past the HTC header + HTC header alignment padding + */ + qdf_nbuf_pull_head(htt_t2h_msg, HTC_HEADER_LEN + + HTC_HDR_ALIGNMENT_PADDING); + + /* confirm alignment */ + HTT_ASSERT3((((unsigned long) qdf_nbuf_data(htt_t2h_msg)) & 0x3) + == 0); + + msg_word = (u_int32_t *) qdf_nbuf_data(htt_t2h_msg); + msg_type = HTT_T2H_MSG_TYPE_GET(*msg_word); + + switch (msg_type) { + case HTT_T2H_MSG_TYPE_RX_IND: + { + unsigned int num_mpdu_ranges; + unsigned int num_msdu_bytes; + u_int16_t peer_id; + u_int8_t tid; + + peer_id = HTT_RX_IND_PEER_ID_GET(*msg_word); + tid = HTT_RX_IND_EXT_TID_GET(*msg_word); + + num_msdu_bytes = + HTT_RX_IND_FW_RX_DESC_BYTES_GET( + *(msg_word + 2 + + HTT_RX_PPDU_DESC_SIZE32)); + /* + * 1 word for the message header, + * HTT_RX_PPDU_DESC_SIZE32 words for the FW + * rx PPDU desc. + * 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 = + (HTT_RX_IND_HDR_BYTES + num_msdu_bytes + 3) >> + 2; + num_mpdu_ranges = + HTT_RX_IND_NUM_MPDU_RANGES_GET(*(msg_word + + 1)); + pdev->rx_ind_msdu_byte_idx = 0; + ol_rx_indication_handler(pdev->txrx_pdev, htt_t2h_msg, + peer_id, tid, num_mpdu_ranges); + break; + } + case HTT_T2H_MSG_TYPE_TX_COMPL_IND: + { + int num_msdus; + enum htt_tx_status status; + + /* status - no enum translation needed */ + status = HTT_TX_COMPL_IND_STATUS_GET(*msg_word); + num_msdus = HTT_TX_COMPL_IND_NUM_GET(*msg_word); + if (num_msdus & 0x1) { + struct htt_tx_compl_ind_base *compl = + (void *)msg_word; + + /* + * Host CPU endianness can be different + * from FW CPU. This can result in even + * and odd MSDU IDs being switched. If + * this happens, copy the switched final + * odd MSDU ID from location + * payload[size], to location + * payload[size-1],where the message + * handler function expects to find it + */ + if (compl->payload[num_msdus] != + HTT_TX_COMPL_INV_MSDU_ID) { + compl->payload[num_msdus - 1] = + compl->payload[num_msdus]; + } + } + ol_tx_completion_handler(pdev->txrx_pdev, num_msdus, + status, msg_word + 1); + + num_htt_tx_cmpls += SLOTS_PER_TX; + break; + } + case HTT_T2H_MSG_TYPE_RX_PN_IND: + { + u_int16_t peer_id; + u_int8_t tid, pn_ie_cnt, *pn_ie = NULL; + int seq_num_start, seq_num_end; + + /*First dword */ + peer_id = HTT_RX_PN_IND_PEER_ID_GET(*msg_word); + tid = HTT_RX_PN_IND_EXT_TID_GET(*msg_word); + + msg_word++; + /*Second dword */ + seq_num_start = + HTT_RX_PN_IND_SEQ_NUM_START_GET(*msg_word); + seq_num_end = + HTT_RX_PN_IND_SEQ_NUM_END_GET(*msg_word); + pn_ie_cnt = + HTT_RX_PN_IND_PN_IE_CNT_GET(*msg_word); + + msg_word++; + /*Third dword*/ + if (pn_ie_cnt) + pn_ie = (u_int8_t *)msg_word; + + ol_rx_pn_ind_handler(pdev->txrx_pdev, peer_id, tid, + seq_num_start, seq_num_end, pn_ie_cnt, pn_ie); + + break; + } + case HTT_T2H_MSG_TYPE_TX_INSPECT_IND: + { + int num_msdus; + + num_msdus = HTT_TX_COMPL_IND_NUM_GET(*msg_word); + if (num_msdus & 0x1) { + struct htt_tx_compl_ind_base *compl = + (void *)msg_word; + + /* + * Host CPU endianness can be different + * from FW CPU. This * can result in + * even and odd MSDU IDs being switched. + * If this happens, copy the switched + * final odd MSDU ID from location + * payload[size], to location + * payload[size-1], where the message + * handler function expects to find it + */ + if (compl->payload[num_msdus] != + HTT_TX_COMPL_INV_MSDU_ID) { + compl->payload[num_msdus - 1] = + compl->payload[num_msdus]; + } + } + ol_tx_inspect_handler(pdev->txrx_pdev, + num_msdus, msg_word + 1); + num_htt_tx_cmpls += SLOTS_PER_TX; + break; + } + case HTT_T2H_MSG_TYPE_RX_IN_ORD_PADDR_IND: + { + u_int16_t peer_id; + u_int8_t tid; + u_int8_t offload_ind, frag_ind; + + if (qdf_unlikely( + !pdev->cfg.is_full_reorder_offload)) { + qdf_print("HTT_T2H_MSG_TYPE_RX_IN_ORD_PADDR_IND not supported when full reorder offload is disabled\n"); + break; + } + + if (qdf_unlikely( + pdev->txrx_pdev->cfg.is_high_latency)) { + qdf_print("HTT_T2H_MSG_TYPE_RX_IN_ORD_PADDR_IND not supported on high latency\n"); + break; + } + + peer_id = HTT_RX_IN_ORD_PADDR_IND_PEER_ID_GET( + *msg_word); + tid = HTT_RX_IN_ORD_PADDR_IND_EXT_TID_GET( + *msg_word); + offload_ind = + HTT_RX_IN_ORD_PADDR_IND_OFFLOAD_GET( + *msg_word); + frag_ind = HTT_RX_IN_ORD_PADDR_IND_FRAG_GET( + *msg_word); + + if (qdf_unlikely(frag_ind)) { + ol_rx_frag_indication_handler( + pdev->txrx_pdev, htt_t2h_msg, peer_id, + tid); + break; + } + + ol_rx_in_order_indication_handler( + pdev->txrx_pdev, htt_t2h_msg, + peer_id, tid, offload_ind); + break; + } + default: + htt_t2h_lp_msg_handler(context, htt_t2h_msg, false); + break; + }; + + /* Re-initialize the indication buffer */ + HTT_T2H_MSG_BUF_REINIT(htt_t2h_msg, pdev->osdev->dev); + qdf_nbuf_set_pktlen(htt_t2h_msg, 0); + } + return num_htt_tx_cmpls; +} +#else +int htt_t2h_msg_handler_fast(void *context, qdf_nbuf_t *cmpl_msdus, + uint32_t num_cmpls) +{ + return 0; +} +#endif /* WLAN_FEATURE_FASTPATH */ + /*--- target->host HTT message Info Element access methods ------------------*/ /*--- tx completion message ---*/ diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index ae1e9d00109c..60270235ffdc 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/core/hdd/src/wlan_hdd_main.c @@ -5609,6 +5609,8 @@ int hdd_wlan_startup(struct device *dev, void *hif_sc) if (IS_ERR(hdd_ctx)) return PTR_ERR(hdd_ctx); + hif_update_fastpath_recv_bufs_cnt(hif_sc); + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { ret = hdd_enable_ftm(hdd_ctx);