diff --git a/dp/wifi3.0/dp_rx.h b/dp/wifi3.0/dp_rx.h index ad5bc55574..04daa4efd3 100644 --- a/dp/wifi3.0/dp_rx.h +++ b/dp/wifi3.0/dp_rx.h @@ -647,6 +647,9 @@ QDF_STATUS dp_rx_buffers_replenish(struct dp_soc *dp_soc, uint32_t mac_id, * @bm_action: put to idle_list or release to msdu_list * Return: QDF_STATUS */ +QDF_STATUS +dp_rx_link_desc_return(struct dp_soc *soc, void *ring_desc, uint8_t bm_action); + QDF_STATUS dp_rx_link_desc_buf_return(struct dp_soc *soc, struct dp_srng *dp_rxdma_srng, void *buf_addr_info, uint8_t bm_action); diff --git a/dp/wifi3.0/dp_rx_defrag.c b/dp/wifi3.0/dp_rx_defrag.c index a575fcf161..7c23107636 100644 --- a/dp/wifi3.0/dp_rx_defrag.c +++ b/dp/wifi3.0/dp_rx_defrag.c @@ -77,14 +77,13 @@ static void dp_rx_defrag_frames_free(qdf_nbuf_t frames) */ static void dp_rx_clear_saved_desc_info(struct dp_peer *peer, unsigned tid) { - hal_rx_clear_mpdu_desc_info( - &peer->rx_tid[tid].transcap_rx_mpdu_desc_info); + if (peer->rx_tid[tid].dst_ring_desc) + qdf_mem_free(peer->rx_tid[tid].dst_ring_desc); - hal_rx_clear_msdu_link_ptr( - &peer->rx_tid[tid].transcap_msdu_link_ptr[0], - HAL_RX_MAX_SAVED_RING_DESC); + peer->rx_tid[tid].dst_ring_desc = NULL; } +#ifdef DEFRAG_TIMEOUT /* * dp_rx_defrag_waitlist_add(): Update per-PDEV defrag wait list * @peer: Pointer to the peer data structure @@ -142,6 +141,7 @@ static void dp_rx_defrag_waitlist_remove(struct dp_peer *peer, unsigned tid) qdf_assert(0); } } +#endif /* * dp_rx_defrag_fraglist_insert(): Create a per-sequence fragment list @@ -220,7 +220,7 @@ static void dp_rx_defrag_fraglist_insert(struct dp_peer *peer, unsigned tid, next = qdf_nbuf_next(*head_addr); rx_desc_info = qdf_nbuf_data(*tail_addr); - last_morefrag = hal_rx_get_rx_more_frag_bit(rx_desc_info); + last_morefrag = dp_rx_frag_get_more_frag_bit(rx_desc_info); /* TODO: optimize the loop */ if (!last_morefrag) { @@ -617,40 +617,57 @@ static QDF_STATUS dp_rx_defrag_tkip_demic(const uint8_t *key, } /* - * dp_rx_defrag_decap_recombine(): Recombine the fragments - * @peer: Pointer to the peer - * @frag_list: list of fragments - * @tid: Transmit identifier - * @hdrsize: Header size + * dp_rx_frag_pull_hdr(): Pulls the RXTLV & the 802.11 headers + * @nbuf: buffer pointer * - * Recombine fragments + * Pull the RXTLV & the 802.11 headers * - * Returns: QDF_STATUS + * Returns: None */ -static QDF_STATUS dp_rx_defrag_decap_recombine(struct dp_peer *peer, - qdf_nbuf_t head_msdu, unsigned tid, uint16_t hdrsize) +static void dp_rx_frag_pull_hdr(qdf_nbuf_t nbuf) { - qdf_nbuf_t msdu = head_msdu; - uint8_t i; - uint8_t num_ring_desc_saved = peer->rx_tid[tid].curr_ring_desc_idx; - uint8_t num_msdus; + uint16_t hdrsize = dp_rx_defrag_hdrsize(nbuf); - /* Stitch fragments together */ - for (i = 0; (i < num_ring_desc_saved) && msdu; i++) { + qdf_nbuf_pull_head(nbuf, + RX_PKT_TLVS_LEN + hdrsize); - struct hal_rx_msdu_link_ptr_info *msdu_link_ptr_info = - &peer->rx_tid[tid].transcap_msdu_link_ptr[i]; + QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_INFO, + "%s: final pktlen %d .11len %d\n", + __func__, + (uint32_t)qdf_nbuf_len(nbuf), hdrsize); +} - struct hal_rx_mpdu_desc_info *mpdu_desc_info = - &peer->rx_tid[tid].transcap_rx_mpdu_desc_info; - - num_msdus = hal_rx_chain_msdu_links(msdu, msdu_link_ptr_info, - mpdu_desc_info); +/* + * dp_rx_construct_fraglist(): Construct a nbuf fraglist + * @peer: Pointer to the peer + * @head: Pointer to list of fragments + * + * Construct a nbuf fraglist + * + * Returns: None + */ +static void +dp_rx_construct_fraglist(struct dp_peer *peer, qdf_nbuf_t head) +{ + qdf_nbuf_t msdu = qdf_nbuf_next(head); + qdf_nbuf_t rx_nbuf = msdu; + uint32_t len = 0; + while (msdu) { + dp_rx_frag_pull_hdr(msdu); + len += qdf_nbuf_len(msdu); msdu = qdf_nbuf_next(msdu); } - return QDF_STATUS_SUCCESS; + qdf_nbuf_append_ext_list(head, rx_nbuf, len); + qdf_nbuf_set_next(head, NULL); + + QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_INFO, + "%s: head len %d ext len %d data len %d \n", + __func__, + (uint32_t)qdf_nbuf_len(head), + (uint32_t)qdf_nbuf_len(rx_nbuf), + (uint32_t)(head->data_len)); } /** @@ -676,179 +693,243 @@ static void dp_rx_defrag_err(uint8_t vdev_id, uint8_t *peer_mac_addr, /* TODO: Who needs to know about the TKIP MIC error */ } -/* - * dp_rx_defrag_qos_decap(): Remove QOS header from the frame - * @nbuf: Pointer to the frame buffer - * @hdrlen: Length of the header information - * - * Recombine fragments - * - * Returns: None - */ -static void dp_rx_defrag_qos_decap(qdf_nbuf_t nbuf, uint16_t hdrlen) -{ - struct ieee80211_frame *wh; - uint16_t qoslen; - int pkt_tlv_size = sizeof(struct rx_pkt_tlvs); /* pkt TLV hdr size */ - uint16_t fc = 0; - - uint8_t *rx_tlv_hdr = qdf_nbuf_data(nbuf); - - /* Get the frame control field if it is valid */ - if (hal_rx_get_mpdu_frame_control_valid(rx_tlv_hdr)) - fc = hal_rx_get_frame_ctrl_field(rx_tlv_hdr); - - wh = (struct ieee80211_frame *)(qdf_nbuf_data(nbuf) + pkt_tlv_size); - - if (DP_RX_DEFRAG_IEEE80211_QOS_HAS_SEQ(fc & 0xff)) { - qoslen = sizeof(struct ieee80211_qoscntl); - - /* Qos frame with Order bit set indicates a HTC frame */ - if (((fc & 0xff00) >> 8) & IEEE80211_FC1_ORDER) - qoslen += sizeof(struct ieee80211_htc); - - /* remove QoS field from header */ - hdrlen -= qoslen; - qdf_mem_move((uint8_t *)wh + qoslen, wh, hdrlen); - - wh = (struct ieee80211_frame *)qdf_nbuf_pull_head(nbuf, - pkt_tlv_size + - qoslen); - /* clear QoS bit */ - if (wh) - wh->i_fc[0] &= ~IEEE80211_FC0_SUBTYPE_QOS; - } -} /* * dp_rx_defrag_nwifi_to_8023(): Transcap 802.11 to 802.3 - * @msdu: Pointer to the fragment buffer + * @nbuf: Pointer to the fragment buffer * * Transcap the fragment from 802.11 to 802.3 * * Returns: None */ -static void dp_rx_defrag_nwifi_to_8023(qdf_nbuf_t msdu) +static void dp_rx_defrag_nwifi_to_8023(qdf_nbuf_t nbuf) { - struct ieee80211_frame wh; uint32_t hdrsize; - struct llc_snap_hdr_t llchdr; + struct llc_snap_hdr_t *llchdr; struct ethernet_hdr_t *eth_hdr; - int rx_desc_len = sizeof(struct rx_pkt_tlvs); - struct ieee80211_frame *wh_ptr; + uint8_t ether_type[2]; + uint16_t fc; + union dp_align_mac_addr mac_addr; + uint8_t *rx_desc_info = qdf_mem_malloc(RX_PKT_TLVS_LEN); - wh_ptr = (struct ieee80211_frame *)(qdf_nbuf_data(msdu) + - rx_desc_len); - qdf_mem_copy(&wh, wh_ptr, sizeof(wh)); - hdrsize = sizeof(struct ieee80211_frame); - qdf_mem_copy(&llchdr, ((uint8_t *) (qdf_nbuf_data(msdu) + - rx_desc_len)) + hdrsize, - sizeof(struct llc_snap_hdr_t)); + if (rx_desc_info == NULL) { + QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR, + "%s: Memory alloc failed ! \n", __func__); + QDF_ASSERT(0); + return; + } - /* - * Now move the data pointer to the beginning of the mac header : - * new-header = old-hdr + (wifihdrsize + llchdrsize - ethhdrsize) - */ - qdf_nbuf_pull_head(msdu, (rx_desc_len + hdrsize + - sizeof(struct llc_snap_hdr_t) - - sizeof(struct ethernet_hdr_t))); - eth_hdr = (struct ethernet_hdr_t *)(qdf_nbuf_data(msdu)); + hdrsize = dp_rx_defrag_hdrsize(nbuf); + + qdf_mem_copy(rx_desc_info, qdf_nbuf_data(nbuf), RX_PKT_TLVS_LEN); + + llchdr = (struct llc_snap_hdr_t *)(qdf_nbuf_data(nbuf) + + RX_PKT_TLVS_LEN + hdrsize); + qdf_mem_copy(ether_type, llchdr->ethertype, 2); + + qdf_nbuf_pull_head(nbuf, (RX_PKT_TLVS_LEN + hdrsize + + sizeof(struct llc_snap_hdr_t) - + sizeof(struct ethernet_hdr_t))); + + eth_hdr = (struct ethernet_hdr_t *)(qdf_nbuf_data(nbuf)); + + if (hal_rx_get_mpdu_frame_control_valid(rx_desc_info)) + fc = hal_rx_get_frame_ctrl_field(rx_desc_info); + + switch (((fc & 0xff00) >> 8) & IEEE80211_FC1_DIR_MASK) { + + QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_INFO, + "%s: frame control type: 0x%x", __func__, fc); - switch (wh.i_fc[1] & IEEE80211_FC1_DIR_MASK) { case IEEE80211_FC1_DIR_NODS: - qdf_mem_copy(eth_hdr->dest_addr, wh.i_addr1, + hal_rx_mpdu_get_addr1(rx_desc_info, + &mac_addr.raw[0]); + qdf_mem_copy(eth_hdr->dest_addr, &mac_addr.raw[0], IEEE80211_ADDR_LEN); - qdf_mem_copy(eth_hdr->src_addr, wh.i_addr2, + hal_rx_mpdu_get_addr2(rx_desc_info, + &mac_addr.raw[0]); + qdf_mem_copy(eth_hdr->src_addr, &mac_addr.raw[0], IEEE80211_ADDR_LEN); break; case IEEE80211_FC1_DIR_TODS: - qdf_mem_copy(eth_hdr->dest_addr, wh.i_addr3, + hal_rx_mpdu_get_addr3(rx_desc_info, + &mac_addr.raw[0]); + qdf_mem_copy(eth_hdr->dest_addr, &mac_addr.raw[0], IEEE80211_ADDR_LEN); - qdf_mem_copy(eth_hdr->src_addr, wh.i_addr2, + hal_rx_mpdu_get_addr2(rx_desc_info, + &mac_addr.raw[0]); + qdf_mem_copy(eth_hdr->src_addr, &mac_addr.raw[0], IEEE80211_ADDR_LEN); break; case IEEE80211_FC1_DIR_FROMDS: - qdf_mem_copy(eth_hdr->dest_addr, wh.i_addr1, + hal_rx_mpdu_get_addr1(rx_desc_info, + &mac_addr.raw[0]); + qdf_mem_copy(eth_hdr->dest_addr, &mac_addr.raw[0], IEEE80211_ADDR_LEN); - qdf_mem_copy(eth_hdr->src_addr, wh.i_addr3, + hal_rx_mpdu_get_addr3(rx_desc_info, + &mac_addr.raw[0]); + qdf_mem_copy(eth_hdr->src_addr, &mac_addr.raw[0], IEEE80211_ADDR_LEN); break; + case IEEE80211_FC1_DIR_DSTODS: break; + + default: + QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR, + "%s: Unknown frame control type: 0x%x", __func__, fc); } - /* TODO: Is it requried to copy rx_pkt_tlvs - * to the start of data buffer? - */ - qdf_mem_copy(eth_hdr->ethertype, llchdr.ethertype, - sizeof(llchdr.ethertype)); + qdf_mem_copy(eth_hdr->ethertype, ether_type, + sizeof(ether_type)); + + qdf_nbuf_push_head(nbuf, RX_PKT_TLVS_LEN); + qdf_mem_copy(qdf_nbuf_data(nbuf), rx_desc_info, RX_PKT_TLVS_LEN); + qdf_mem_free(rx_desc_info); } /* * dp_rx_defrag_reo_reinject(): Reinject the fragment chain back into REO * @peer: Pointer to the peer * @tid: Transmit Identifier + * @head: Buffer to be reinjected back * * Reinject the fragment chain back into REO * * Returns: QDF_STATUS */ -static QDF_STATUS dp_rx_defrag_reo_reinject(struct dp_peer *peer, - unsigned tid) + static QDF_STATUS dp_rx_defrag_reo_reinject(struct dp_peer *peer, + unsigned tid, qdf_nbuf_t head) { struct dp_pdev *pdev = peer->vdev->pdev; struct dp_soc *soc = pdev->soc; - QDF_STATUS status = QDF_STATUS_E_FAILURE; - void *ring_desc; - enum hal_reo_error_status error; - struct hal_rx_mpdu_desc_info *saved_mpdu_desc_info; + struct hal_buf_info buf_info; + void *link_desc_va; + void *msdu0, *msdu_desc_info; + void *ent_ring_desc, *ent_mpdu_desc_info, *ent_qdesc_addr; + void *dst_mpdu_desc_info, *dst_qdesc_addr; + qdf_dma_addr_t paddr; + uint32_t nbuf_len, seq_no; + uint32_t *mpdu_wrd; + + void *dst_ring_desc = + peer->rx_tid[tid].dst_ring_desc; void *hal_srng = soc->reo_reinject_ring.hal_srng; - struct hal_rx_msdu_link_ptr_info *saved_msdu_link_ptr; + hal_rx_reo_buf_paddr_get(dst_ring_desc, &buf_info); + + link_desc_va = dp_rx_cookie_2_link_desc_va(soc, &buf_info); + + qdf_assert(link_desc_va); + + msdu0 = (uint8_t *)link_desc_va + + RX_MSDU_LINK_8_RX_MSDU_DETAILS_MSDU_0_OFFSET; + + nbuf_len = qdf_nbuf_len(head) - RX_PKT_TLVS_LEN; + + HAL_RX_UNIFORM_HDR_SET(link_desc_va, OWNER, UNI_DESC_OWNER_SW); + HAL_RX_UNIFORM_HDR_SET(link_desc_va, BUFFER_TYPE, + UNI_DESC_BUF_TYPE_RX_MSDU_LINK); + + /* msdu reconfig */ + msdu_desc_info = (uint8_t *)msdu0 + + RX_MSDU_DETAILS_2_RX_MSDU_DESC_INFO_RX_MSDU_DESC_INFO_DETAILS_OFFSET; + + qdf_mem_zero(msdu_desc_info, sizeof(struct rx_msdu_desc_info)); + + HAL_RX_MSDU_DESC_INFO_SET(msdu_desc_info, + FIRST_MSDU_IN_MPDU_FLAG, 1); + HAL_RX_MSDU_DESC_INFO_SET(msdu_desc_info, + LAST_MSDU_IN_MPDU_FLAG, 1); + HAL_RX_MSDU_DESC_INFO_SET(msdu_desc_info, + MSDU_CONTINUATION, 0x0); + HAL_RX_MSDU_DESC_INFO_SET(msdu_desc_info, + REO_DESTINATION_INDICATION, 1); + HAL_RX_MSDU_DESC_INFO_SET(msdu_desc_info, + MSDU_LENGTH, nbuf_len); + HAL_RX_MSDU_DESC_INFO_SET(msdu_desc_info, + SA_IS_VALID, 1); + HAL_RX_MSDU_DESC_INFO_SET(msdu_desc_info, + DA_IS_VALID, 1); + + /* change RX TLV's */ + hal_rx_msdu_start_msdu_len_set( + qdf_nbuf_data(head), nbuf_len); + + /* Lets fill entrance ring now !!! */ if (qdf_unlikely(hal_srng_access_start(soc->hal_soc, hal_srng))) { - - QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, - "HAL RING Access For WBM Release SRNG Failed: %pK", - hal_srng); - goto done; - } - - ring_desc = hal_srng_src_get_next(soc->hal_soc, hal_srng); - - qdf_assert(ring_desc); - - error = HAL_RX_ERROR_STATUS_GET(ring_desc); - - if (qdf_unlikely(error == HAL_REO_ERROR_DETECTED)) { QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR, - "HAL RING 0x%pK:error %d", hal_srng, error); + "HAL RING Access For REO entrance SRNG Failed: %pK", + hal_srng); - /* Don't know how to deal with this condition -- assert */ - qdf_assert(0); - goto done; + return QDF_STATUS_E_FAILURE; } - saved_mpdu_desc_info = - &peer->rx_tid[tid].transcap_rx_mpdu_desc_info; + ent_ring_desc = hal_srng_src_get_next(soc->hal_soc, hal_srng); - /* first msdu link pointer */ - saved_msdu_link_ptr = - &peer->rx_tid[tid].transcap_msdu_link_ptr[0]; + qdf_assert(ent_ring_desc); - hal_rx_defrag_update_src_ring_desc(ring_desc, - saved_mpdu_desc_info, saved_msdu_link_ptr); + paddr = (uint64_t)buf_info.paddr; + /* buf addr */ + hal_rxdma_buff_addr_info_set(ent_ring_desc, paddr, + buf_info.sw_cookie, + HAL_RX_BUF_RBM_WBM_IDLE_DESC_LIST); + /* mpdu desc info */ + ent_mpdu_desc_info = (uint8_t *)ent_ring_desc + + RX_MPDU_DETAILS_2_RX_MPDU_DESC_INFO_RX_MPDU_DESC_INFO_DETAILS_OFFSET; + + dst_mpdu_desc_info = (uint8_t *)dst_ring_desc + + REO_DESTINATION_RING_2_RX_MPDU_DESC_INFO_RX_MPDU_DESC_INFO_DETAILS_OFFSET; + + qdf_mem_copy(ent_mpdu_desc_info, dst_mpdu_desc_info, + sizeof(struct rx_mpdu_desc_info)); + qdf_mem_zero(ent_mpdu_desc_info, sizeof(uint32_t)); + + mpdu_wrd = (uint32_t *)dst_mpdu_desc_info; + seq_no = HAL_RX_MPDU_SEQUENCE_NUMBER_GET(mpdu_wrd); + + HAL_RX_MPDU_DESC_INFO_SET(ent_mpdu_desc_info, + MSDU_COUNT, 0x1); + HAL_RX_MPDU_DESC_INFO_SET(ent_mpdu_desc_info, + MPDU_SEQUENCE_NUMBER, seq_no); + + /* unset frag bit */ + HAL_RX_MPDU_DESC_INFO_SET(ent_mpdu_desc_info, + FRAGMENT_FLAG, 0x0); + + /* set sa/da valid bits */ + HAL_RX_MPDU_DESC_INFO_SET(ent_mpdu_desc_info, + SA_IS_VALID, 0x1); + HAL_RX_MPDU_DESC_INFO_SET(ent_mpdu_desc_info, + DA_IS_VALID, 0x1); + HAL_RX_MPDU_DESC_INFO_SET(ent_mpdu_desc_info, + RAW_MPDU, 0x0); + + /* qdesc addr */ + ent_qdesc_addr = (uint8_t *)ent_ring_desc + + REO_ENTRANCE_RING_4_RX_REO_QUEUE_DESC_ADDR_31_0_OFFSET; + + dst_qdesc_addr = (uint8_t *)dst_ring_desc + + REO_DESTINATION_RING_6_RX_REO_QUEUE_DESC_ADDR_31_0_OFFSET; + + qdf_mem_copy(ent_qdesc_addr, dst_qdesc_addr, 8); + + /* dst ind */ + HAL_RX_FLD_SET(ent_ring_desc, REO_ENTRANCE_RING_5, + REO_DESTINATION_INDICATION, 0x1); - status = QDF_STATUS_SUCCESS; -done: hal_srng_access_end(soc->hal_soc, hal_srng); - return status; + + QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_INFO, + "%s: reinjection done !\n", __func__); + return QDF_STATUS_SUCCESS; } /* * dp_rx_defrag(): Defragment the fragment chain * @peer: Pointer to the peer * @tid: Transmit Identifier - * @frag_list: Pointer to head list + * @frag_list_head: Pointer to head list * @frag_list_tail: Pointer to tail list * * Defragment the fragment chain @@ -856,22 +937,29 @@ done: * Returns: QDF_STATUS */ static QDF_STATUS dp_rx_defrag(struct dp_peer *peer, unsigned tid, - qdf_nbuf_t frag_list, qdf_nbuf_t frag_list_tail) + qdf_nbuf_t frag_list_head, qdf_nbuf_t frag_list_tail) { - qdf_nbuf_t tmp_next; - qdf_nbuf_t cur = frag_list, msdu; - + qdf_nbuf_t tmp_next, prev; + qdf_nbuf_t cur = frag_list_head, msdu; uint32_t index, tkip_demic = 0; uint16_t hdr_space; - QDF_STATUS status; uint8_t key[DEFRAG_IEEE80211_KEY_LEN]; struct dp_vdev *vdev = peer->vdev; - cur = frag_list; hdr_space = dp_rx_defrag_hdrsize(cur); index = hal_rx_msdu_is_wlan_mcast(cur) ? dp_sec_mcast : dp_sec_ucast; + /* Remove FCS from all fragments */ + while (cur) { + tmp_next = qdf_nbuf_next(cur); + qdf_nbuf_set_next(cur, NULL); + qdf_nbuf_trim_tail(cur, DEFRAG_IEEE80211_FCS_LEN); + prev = cur; + qdf_nbuf_set_next(cur, tmp_next); + cur = tmp_next; + } + switch (peer->security[index].sec_type) { case htt_sec_type_tkip: tkip_demic = 1; @@ -882,7 +970,7 @@ static QDF_STATUS dp_rx_defrag(struct dp_peer *peer, unsigned tid, if (dp_rx_defrag_tkip_decap(cur, hdr_space)) { /* TKIP decap failed, discard frags */ - dp_rx_defrag_frames_free(frag_list); + dp_rx_defrag_frames_free(frag_list_head); QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, @@ -900,7 +988,7 @@ static QDF_STATUS dp_rx_defrag(struct dp_peer *peer, unsigned tid, if (dp_rx_defrag_ccmp_demic(cur, hdr_space)) { /* CCMP demic failed, discard frags */ - dp_rx_defrag_frames_free(frag_list); + dp_rx_defrag_frames_free(frag_list_head); QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, @@ -911,7 +999,7 @@ static QDF_STATUS dp_rx_defrag(struct dp_peer *peer, unsigned tid, if (dp_rx_defrag_ccmp_decap(cur, hdr_space)) { /* CCMP decap failed, discard frags */ - dp_rx_defrag_frames_free(frag_list); + dp_rx_defrag_frames_free(frag_list_head); QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, @@ -930,7 +1018,7 @@ static QDF_STATUS dp_rx_defrag(struct dp_peer *peer, unsigned tid, if (dp_rx_defrag_wep_decap(cur, hdr_space)) { /* WEP decap failed, discard frags */ - dp_rx_defrag_frames_free(frag_list); + dp_rx_defrag_frames_free(frag_list_head); QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, @@ -965,36 +1053,24 @@ static QDF_STATUS dp_rx_defrag(struct dp_peer *peer, unsigned tid, } } - dp_rx_defrag_qos_decap(cur, hdr_space); - /* Convert the header to 802.3 header */ - dp_rx_defrag_nwifi_to_8023(cur); + dp_rx_defrag_nwifi_to_8023(frag_list_head); + dp_rx_construct_fraglist(peer, frag_list_head); - status = dp_rx_defrag_decap_recombine(peer, cur, tid, hdr_space); - - if (QDF_IS_STATUS_ERROR(status)) { - QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, - "dp_rx_defrag_decap_recombine failed"); - - qdf_assert(0); - } - - return status; + return QDF_STATUS_SUCCESS; } /* * dp_rx_defrag_cleanup(): Clean up activities * @peer: Pointer to the peer * @tid: Transmit Identifier - * @seq: Sequence number * * Returns: None */ -static void dp_rx_defrag_cleanup(struct dp_peer *peer, unsigned tid, - uint16_t seq) +static void dp_rx_defrag_cleanup(struct dp_peer *peer, unsigned tid) { struct dp_rx_reorder_array_elem *rx_reorder_array_elem = - &peer->rx_tid[tid].array[seq]; + peer->rx_tid[tid].array; /* Free up nbufs */ dp_rx_defrag_frames_free(rx_reorder_array_elem->head); @@ -1007,50 +1083,35 @@ static void dp_rx_defrag_cleanup(struct dp_peer *peer, unsigned tid, peer->rx_tid[tid].defrag_timeout_ms = 0; peer->rx_tid[tid].curr_frag_num = 0; peer->rx_tid[tid].curr_seq_num = 0; - peer->rx_tid[tid].curr_ring_desc_idx = 0; } /* * dp_rx_defrag_save_info_from_ring_desc(): Save info from REO ring descriptor - * @ring_desc: Pointer to the ring descriptor + * @ring_desc: Pointer to the dst ring descriptor * @peer: Pointer to the peer * @tid: Transmit Identifier - * @mpdu_desc_info: MPDU descriptor info * * Returns: None */ -static void dp_rx_defrag_save_info_from_ring_desc(void *ring_desc, - struct dp_peer *peer, unsigned tid, - struct hal_rx_mpdu_desc_info *mpdu_desc_info) +static QDF_STATUS dp_rx_defrag_save_info_from_ring_desc(void *ring_desc, + struct dp_peer *peer, unsigned tid) { - struct dp_pdev *pdev = peer->vdev->pdev; - void *msdu_link_desc_va = NULL; - uint8_t idx = peer->rx_tid[tid].curr_ring_desc_idx; - uint8_t rbm; + void *dst_ring_desc = qdf_mem_malloc( + sizeof(struct reo_destination_ring)); - struct hal_rx_msdu_link_ptr_info *msdu_link_ptr_info = - &peer->rx_tid[tid].transcap_msdu_link_ptr[++idx]; - struct hal_rx_mpdu_desc_info *tmp_mpdu_desc_info = - &peer->rx_tid[tid].transcap_rx_mpdu_desc_info; - struct hal_buf_info hbi; - - rbm = hal_rx_ret_buf_manager_get(ring_desc); - if (qdf_unlikely(rbm != HAL_RX_BUF_RBM_SW3_BM)) { - QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, - "Invalid RBM while chaining frag MSDUs"); - return; + if (dst_ring_desc == NULL) { + QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR, + "%s: Memory alloc failed !\n", __func__); + QDF_ASSERT(0); + return QDF_STATUS_E_NOMEM; } - hal_rx_reo_buf_paddr_get(ring_desc, &hbi); + qdf_mem_copy(dst_ring_desc, ring_desc, + sizeof(struct reo_destination_ring)); - msdu_link_desc_va = - dp_rx_cookie_2_link_desc_va(pdev->soc, &hbi); + peer->rx_tid[tid].dst_ring_desc = dst_ring_desc; - hal_rx_defrag_save_info_from_ring_desc(msdu_link_desc_va, - msdu_link_ptr_info, &hbi); - - qdf_mem_copy(tmp_mpdu_desc_info, mpdu_desc_info, - sizeof(*tmp_mpdu_desc_info)); + return QDF_STATUS_SUCCESS; } /* @@ -1058,10 +1119,10 @@ static void dp_rx_defrag_save_info_from_ring_desc(void *ring_desc, * @soc: Pointer to the SOC data structure * @ring_desc: Pointer to the ring descriptor * @mpdu_desc_info: MPDU descriptor info - * @msdu_info: Pointer to MSDU descriptor info * @tid: Traffic Identifier * @rx_desc: Pointer to rx descriptor - * + * @rx_bfs: Number of bfs consumed + * * Returns: QDF_STATUS */ static QDF_STATUS dp_rx_defrag_store_fragment(struct dp_soc *soc, @@ -1069,23 +1130,20 @@ static QDF_STATUS dp_rx_defrag_store_fragment(struct dp_soc *soc, union dp_rx_desc_list_elem_t **head, union dp_rx_desc_list_elem_t **tail, struct hal_rx_mpdu_desc_info *mpdu_desc_info, - struct hal_rx_msdu_desc_info *msdu_info, - unsigned tid, struct dp_rx_desc *rx_desc) + unsigned tid, struct dp_rx_desc *rx_desc, + uint32_t *rx_bfs) { - uint8_t idx; struct dp_rx_reorder_array_elem *rx_reorder_array_elem; struct dp_pdev *pdev; struct dp_peer *peer; uint16_t peer_id; - uint16_t rxseq, seq; uint8_t fragno, more_frag, all_frag_present = 0; - uint16_t seq_num = mpdu_desc_info->mpdu_seq; + uint16_t rxseq = mpdu_desc_info->mpdu_seq; QDF_STATUS status; struct dp_rx_tid *rx_tid; uint8_t mpdu_sequence_control_valid; uint8_t mpdu_frame_control_valid; qdf_nbuf_t frag = rx_desc->nbuf; - uint8_t *rx_desc_info; /* Check if the packet is from a valid peer */ peer_id = DP_PEER_METADATA_PEER_ID_GET( @@ -1109,13 +1167,10 @@ static QDF_STATUS dp_rx_defrag_store_fragment(struct dp_soc *soc, pdev = peer->vdev->pdev; rx_tid = &peer->rx_tid[tid]; - seq = seq_num & (peer->rx_tid[tid].ba_win_size - 1); - qdf_assert(seq == 0); - rx_reorder_array_elem = &peer->rx_tid[tid].array[seq]; + rx_reorder_array_elem = peer->rx_tid[tid].array; - rx_desc_info = qdf_nbuf_data(frag); mpdu_sequence_control_valid = - hal_rx_get_mpdu_sequence_control_valid(rx_desc_info); + hal_rx_get_mpdu_sequence_control_valid(rx_desc->rx_buf_start); /* Invalid MPDU sequence control field, MPDU is of no use */ if (!mpdu_sequence_control_valid) { @@ -1129,7 +1184,7 @@ static QDF_STATUS dp_rx_defrag_store_fragment(struct dp_soc *soc, } mpdu_frame_control_valid = - hal_rx_get_mpdu_frame_control_valid(rx_desc_info); + hal_rx_get_mpdu_frame_control_valid(rx_desc->rx_buf_start); /* Invalid frame control field */ if (!mpdu_frame_control_valid) { @@ -1143,13 +1198,12 @@ static QDF_STATUS dp_rx_defrag_store_fragment(struct dp_soc *soc, } /* Current mpdu sequence */ - rxseq = hal_rx_get_rx_sequence(rx_desc_info); - more_frag = hal_rx_get_rx_more_frag_bit(rx_desc_info); + more_frag = dp_rx_frag_get_more_frag_bit(rx_desc->rx_buf_start); /* HW does not populate the fragment number as of now * need to get from the 802.11 header */ - fragno = dp_rx_frag_get_mpdu_frag_number(rx_desc_info); + fragno = dp_rx_frag_get_mpdu_frag_number(rx_desc->rx_buf_start); /* * !more_frag: no more fragments to be delivered @@ -1173,7 +1227,6 @@ static QDF_STATUS dp_rx_defrag_store_fragment(struct dp_soc *soc, /* Check if the fragment is for the same sequence or a different one */ if (rx_reorder_array_elem->head) { - if (rxseq != rx_tid->curr_seq_num) { /* Drop stored fragments if out of sequence @@ -1198,6 +1251,7 @@ static QDF_STATUS dp_rx_defrag_store_fragment(struct dp_soc *soc, } } else { /* Start of a new sequence */ + dp_rx_defrag_cleanup(peer, tid); rx_tid->curr_seq_num = rxseq; } @@ -1215,32 +1269,37 @@ static QDF_STATUS dp_rx_defrag_store_fragment(struct dp_soc *soc, * have to use the next MSDU link descriptor and chain them together * before reinjection */ - if (more_frag == 0 || fragno == HAL_RX_NUM_MSDU_DESC) { - /* - * Deep copy of MSDU link pointer and msdu descriptor structs - */ - idx = peer->rx_tid[tid].curr_ring_desc_idx; - if (idx < HAL_RX_MAX_SAVED_RING_DESC) { - dp_rx_defrag_save_info_from_ring_desc(ring_desc, - peer, tid, mpdu_desc_info); + if ((fragno == 0) && (rx_reorder_array_elem->head == frag)) { - peer->rx_tid[tid].curr_ring_desc_idx++; - } else { - QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, - "Max ring descr saved, dropping fragment"); - /* - * Free up saved fragments and ring descriptors if any - */ + status = dp_rx_defrag_save_info_from_ring_desc(ring_desc, + peer, tid); + + if (status != QDF_STATUS_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR, + "%s: Unable to store ring desc !\n", __func__); goto end; } + } else { + dp_rx_add_to_free_desc_list(head, tail, rx_desc); + *rx_bfs = 1; + + /* Return the non-head link desc */ + if (dp_rx_link_desc_return(soc, ring_desc, + HAL_BM_ACTION_PUT_IN_IDLE_LIST) != + QDF_STATUS_SUCCESS) + QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR, + "%s: Failed to return link desc\n", + __func__); + } +#ifdef DEFRAG_TIMEOUT /* TODO: handle fragment timeout gracefully */ if (pdev->soc->rx.flags.defrag_timeout_check) { dp_rx_defrag_waitlist_remove(peer, tid); goto end; } - +#endif /* Yet to receive more fragments for this sequence number */ if (!all_frag_present) { uint32_t now_ms = @@ -1249,8 +1308,7 @@ static QDF_STATUS dp_rx_defrag_store_fragment(struct dp_soc *soc, peer->rx_tid[tid].defrag_timeout_ms = now_ms + pdev->soc->rx.defrag.timeout_ms; - dp_rx_defrag_waitlist_add(peer, tid); - goto end; + return QDF_STATUS_SUCCESS; } QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO, @@ -1266,16 +1324,22 @@ static QDF_STATUS dp_rx_defrag_store_fragment(struct dp_soc *soc, } /* Re-inject the fragments back to REO for further processing */ - status = dp_rx_defrag_reo_reinject(peer, tid); - if (QDF_IS_STATUS_SUCCESS(status)) + status = dp_rx_defrag_reo_reinject(peer, tid, + rx_reorder_array_elem->head); + if (QDF_IS_STATUS_SUCCESS(status)) { + rx_reorder_array_elem->head = NULL; + rx_reorder_array_elem->tail = NULL; QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO, "Fragmented sequence successfully reinjected"); + } else QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, "Fragmented sequence reinjection failed"); + dp_rx_defrag_cleanup(peer, tid); + return QDF_STATUS_SUCCESS; + end: - dp_rx_defrag_cleanup(peer, tid, seq); return QDF_STATUS_E_DEFRAG_ERROR; } @@ -1308,8 +1372,9 @@ uint32_t dp_rx_frag_handle(struct dp_soc *soc, void *ring_desc, void *link_desc_va; struct hal_buf_info buf_info; struct hal_rx_msdu_list msdu_list; /* per MPDU list of MSDUs */ - uint32_t tid; - int idx; + qdf_nbuf_t msdu = NULL; + uint32_t tid, msdu_len; + int idx, rx_bfs = 0; QDF_STATUS status; qdf_assert(soc); @@ -1345,20 +1410,38 @@ uint32_t dp_rx_frag_handle(struct dp_soc *soc, void *ring_desc, qdf_assert(rx_desc); + msdu = rx_desc->nbuf; + + qdf_nbuf_unmap_single(soc->osdev, msdu, + QDF_DMA_BIDIRECTIONAL); + + rx_desc->rx_buf_start = qdf_nbuf_data(msdu); + + msdu_len = hal_rx_msdu_start_msdu_len_get( + rx_desc->rx_buf_start); + + qdf_nbuf_set_pktlen(msdu, (msdu_len + RX_PKT_TLVS_LEN)); + tid = hal_rx_mpdu_start_tid_get(rx_desc->rx_buf_start); /* Process fragment-by-fragment */ status = dp_rx_defrag_store_fragment(soc, ring_desc, head, tail, mpdu_desc_info, - &msdu_list.msdu_info[idx], tid, - rx_desc); - if (QDF_IS_STATUS_SUCCESS(status)) - rx_bufs_used++; - else + tid, rx_desc, &rx_bfs); + + if (QDF_IS_STATUS_SUCCESS(status)) { + if (rx_bfs) + rx_bufs_used++; + } else { QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, - "Rx Defragmentation error. mpdu_seq: 0x%x msdu_count: %d mpdu_flags: %d", - mpdu_desc_info->mpdu_seq, mpdu_desc_info->msdu_count, - mpdu_desc_info->mpdu_flags); + "Rx Defrag err seq#:0x%x msdu_count:%d flags:%d", + mpdu_desc_info->mpdu_seq, + mpdu_desc_info->msdu_count, + mpdu_desc_info->mpdu_flags); + + /* No point in processing rest of the fragments */ + break; + } } return rx_bufs_used; diff --git a/dp/wifi3.0/dp_rx_defrag.h b/dp/wifi3.0/dp_rx_defrag.h index 4e6b5ac769..fe8b13a9d7 100644 --- a/dp/wifi3.0/dp_rx_defrag.h +++ b/dp/wifi3.0/dp_rx_defrag.h @@ -39,6 +39,8 @@ (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_QOS)) == \ (IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_QOS)) +#define UNI_DESC_OWNER_SW 0x1 +#define UNI_DESC_BUF_TYPE_RX_MSDU_LINK 0x6 /** * struct dp_rx_defrag_cipher: structure to indicate cipher header * @ic_name: Name @@ -125,7 +127,16 @@ uint8_t dp_rx_frag_get_more_frag_bit(uint8_t *rx_desc_info) struct ieee80211_frame *mac_hdr; mac_hdr = dp_rx_frag_get_mac_hdr(rx_desc_info); - return mac_hdr->i_fc[1] & IEEE80211_FC1_MORE_FRAG; + return (mac_hdr->i_fc[1] & IEEE80211_FC1_MORE_FRAG) >> 2; +} + +static inline +uint8_t dp_rx_get_pkt_dir(uint8_t *rx_desc_info) +{ + struct ieee80211_frame *mac_hdr; + mac_hdr = dp_rx_frag_get_mac_hdr(rx_desc_info); + + return mac_hdr->i_fc[1] & IEEE80211_FC1_DIR_MASK; } #endif /* _DP_RX_DEFRAG_H */ diff --git a/dp/wifi3.0/dp_rx_err.c b/dp/wifi3.0/dp_rx_err.c index 997aabe8fc..1cdb35429d 100644 --- a/dp/wifi3.0/dp_rx_err.c +++ b/dp/wifi3.0/dp_rx_err.c @@ -56,7 +56,7 @@ static inline bool dp_rx_desc_check_magic(struct dp_rx_desc *rx_desc) * * Return: QDF_STATUS */ - static QDF_STATUS +QDF_STATUS dp_rx_link_desc_return(struct dp_soc *soc, void *ring_desc, uint8_t bm_action) { void *buf_addr_info = HAL_RX_REO_BUF_ADDR_INFO_GET(ring_desc); @@ -840,7 +840,10 @@ dp_rx_err_process(struct dp_soc *soc, void *hal_ring, uint32_t quota) link_desc_va = dp_rx_cookie_2_link_desc_va(soc, &hbi); hal_rx_msdu_list_get(link_desc_va, &msdu_list, &num_msdus); - if (qdf_unlikely(msdu_list.rbm[0] != HAL_RX_BUF_RBM_SW3_BM)) { + if (qdf_unlikely((msdu_list.rbm[0] != + HAL_RX_BUF_RBM_SW3_BM) && + (msdu_list.rbm[0] != + HAL_RX_BUF_RBM_WBM_IDLE_DESC_LIST))) { /* TODO */ /* Call appropriate handler */ DP_STATS_INC(soc, rx.err.invalid_rbm, 1); diff --git a/dp/wifi3.0/dp_types.h b/dp/wifi3.0/dp_types.h index 085450677e..42c1e510b8 100644 --- a/dp/wifi3.0/dp_types.h +++ b/dp/wifi3.0/dp_types.h @@ -433,12 +433,8 @@ struct dp_rx_tid { /* only used for defrag right now */ TAILQ_ENTRY(dp_rx_tid) defrag_waitlist_elem; - /* MSDU link pointers used for reinjection */ - struct hal_rx_msdu_link_ptr_info - transcap_msdu_link_ptr[HAL_RX_MAX_SAVED_RING_DESC]; - - struct hal_rx_mpdu_desc_info transcap_rx_mpdu_desc_info; - uint8_t curr_ring_desc_idx; + /* Store dst desc for reinjection */ + void *dst_ring_desc; /* Sequence and fragments that are being processed currently */ uint32_t curr_seq_num; diff --git a/dp/wifi3.0/hal_rx.h b/dp/wifi3.0/hal_rx.h index bc93ab4c59..28676079ac 100644 --- a/dp/wifi3.0/hal_rx.h +++ b/dp/wifi3.0/hal_rx.h @@ -414,8 +414,23 @@ RX_MSDU_DETAILS_2_RX_MSDU_DESC_INFO_RX_MSDU_DESC_INFO_DETAILS_OFFSET)) RX_MPDU_INFO_2_FRAME_ENCRYPTION_INFO_VALID_MASK, \ RX_MPDU_INFO_2_FRAME_ENCRYPTION_INFO_VALID_LSB)) +#define HAL_RX_FLD_SET(_ptr, _wrd, _field, _val) \ + (*(uint32_t *)(((uint8_t *)_ptr) + \ + _wrd ## _ ## _field ## _OFFSET) |= \ + ((_val << _wrd ## _ ## _field ## _LSB) & \ + _wrd ## _ ## _field ## _MASK)) +#define HAL_RX_UNIFORM_HDR_SET(_rx_msdu_link, _field, _val) \ + HAL_RX_FLD_SET(_rx_msdu_link, UNIFORM_DESCRIPTOR_HEADER_0, \ + _field, _val) +#define HAL_RX_MSDU_DESC_INFO_SET(_msdu_info_ptr, _field, _val) \ + HAL_RX_FLD_SET(_msdu_info_ptr, RX_MSDU_DESC_INFO_0, \ + _field, _val) + +#define HAL_RX_MPDU_DESC_INFO_SET(_mpdu_info_ptr, _field, _val) \ + HAL_RX_FLD_SET(_mpdu_info_ptr, RX_MPDU_DESC_INFO_0, \ + _field, _val) static inline void hal_rx_mpdu_desc_info_get(void *desc_addr, struct hal_rx_mpdu_desc_info *mpdu_desc_info) @@ -1028,6 +1043,28 @@ hal_rx_msdu_start_msdu_len_get(uint8_t *buf) return msdu_len; } + /** + * hal_rx_msdu_start_msdu_len_set(): API to set the MSDU length + * from rx_msdu_start TLV + * + * @buf: pointer to the start of RX PKT TLV headers + * @len: msdu length + * + * Return: none + */ +static inline void +hal_rx_msdu_start_msdu_len_set(uint8_t *buf, uint32_t len) +{ + struct rx_pkt_tlvs *pkt_tlvs = (struct rx_pkt_tlvs *)buf; + struct rx_msdu_start *msdu_start = + &pkt_tlvs->msdu_start_tlv.rx_msdu_start; + void *wrd1; + + wrd1 = (uint8_t *)msdu_start + RX_MSDU_START_1_MSDU_LENGTH_OFFSET; + *(uint32_t *)wrd1 &= (~RX_MSDU_START_1_MSDU_LENGTH_MASK); + *(uint32_t *)wrd1 |= len; +} + #define HAL_RX_MSDU_START_BW_GET(_rx_msdu_start) \ (_HAL_MS((*_OFFSET_TO_WORD_PTR((_rx_msdu_start),\ RX_MSDU_START_5_RECEIVE_BANDWIDTH_OFFSET)), \ @@ -1484,6 +1521,12 @@ hal_rx_mpdu_get_fr_ds(uint8_t *buf) RX_MPDU_INFO_2_MAC_ADDR_AD2_VALID_MASK, \ RX_MPDU_INFO_2_MAC_ADDR_AD2_VALID_LSB)) +#define HAL_RX_MPDU_MAC_ADDR_AD3_VALID_GET(_rx_mpdu_info) \ + (_HAL_MS((*_OFFSET_TO_WORD_PTR(_rx_mpdu_info, \ + RX_MPDU_INFO_2_MAC_ADDR_AD3_VALID_OFFSET)), \ + RX_MPDU_INFO_2_MAC_ADDR_AD3_VALID_MASK, \ + RX_MPDU_INFO_2_MAC_ADDR_AD3_VALID_LSB)) + #define HAL_RX_MPDU_AD1_31_0_GET(_rx_mpdu_info) \ (_HAL_MS((*_OFFSET_TO_WORD_PTR(_rx_mpdu_info, \ RX_MPDU_INFO_15_MAC_ADDR_AD1_31_0_OFFSET)), \ @@ -1508,6 +1551,18 @@ hal_rx_mpdu_get_fr_ds(uint8_t *buf) RX_MPDU_INFO_17_MAC_ADDR_AD2_47_16_MASK, \ RX_MPDU_INFO_17_MAC_ADDR_AD2_47_16_LSB)) +#define HAL_RX_MPDU_AD3_31_0_GET(_rx_mpdu_info) \ + (_HAL_MS((*_OFFSET_TO_WORD_PTR(_rx_mpdu_info, \ + RX_MPDU_INFO_18_MAC_ADDR_AD3_31_0_OFFSET)), \ + RX_MPDU_INFO_18_MAC_ADDR_AD3_31_0_MASK, \ + RX_MPDU_INFO_18_MAC_ADDR_AD3_31_0_LSB)) + +#define HAL_RX_MPDU_AD3_47_32_GET(_rx_mpdu_info) \ + (_HAL_MS((*_OFFSET_TO_WORD_PTR(_rx_mpdu_info, \ + RX_MPDU_INFO_19_MAC_ADDR_AD3_47_32_OFFSET)), \ + RX_MPDU_INFO_19_MAC_ADDR_AD3_47_32_MASK, \ + RX_MPDU_INFO_19_MAC_ADDR_AD3_47_32_LSB)) + /* * hal_rx_mpdu_get_addr1(): API to check get address1 of the mpdu * @@ -1577,6 +1632,41 @@ QDF_STATUS hal_rx_mpdu_get_addr2(uint8_t *buf, uint8_t *mac_addr) return QDF_STATUS_E_FAILURE; } +/* + * hal_rx_mpdu_get_addr3(): API to get address3 of the mpdu + * in the packet + * + * @buf: pointer to the start of RX PKT TLV header + * @mac_addr: pointer to mac address + * Return: sucess/failure + */ +static inline +QDF_STATUS hal_rx_mpdu_get_addr3(uint8_t *buf, uint8_t *mac_addr) +{ + struct __attribute__((__packed__)) hal_addr3 { + uint16_t ad3_15_0; + uint32_t ad3_47_16; + }; + + struct rx_pkt_tlvs *pkt_tlvs = (struct rx_pkt_tlvs *)buf; + struct rx_mpdu_start *mpdu_start = + &pkt_tlvs->mpdu_start_tlv.rx_mpdu_start; + + struct rx_mpdu_info *mpdu_info = &mpdu_start->rx_mpdu_info_details; + struct hal_addr3 *addr = (struct hal_addr3 *)mac_addr; + uint32_t mac_addr_ad3_valid; + + mac_addr_ad3_valid = HAL_RX_MPDU_MAC_ADDR_AD3_VALID_GET(mpdu_info); + + if (mac_addr_ad3_valid) { + addr->ad3_15_0 = HAL_RX_MPDU_AD3_31_0_GET(mpdu_info); + addr->ad3_47_16 = HAL_RX_MPDU_AD3_47_32_GET(mpdu_info); + return QDF_STATUS_SUCCESS; + } + + return QDF_STATUS_E_FAILURE; +} + #define HAL_RX_MSDU_END_DA_IDX_GET(_rx_msdu_end) \ (_HAL_MS((*_OFFSET_TO_WORD_PTR(_rx_msdu_end, \ RX_MSDU_END_13_DA_IDX_OFFSET)), \