|
|
@@ -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)
|
|
|
|
static void dp_rx_clear_saved_desc_info(struct dp_peer *peer, unsigned tid)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
hal_rx_clear_mpdu_desc_info(
|
|
|
|
if (peer->rx_tid[tid].dst_ring_desc)
|
|
|
|
&peer->rx_tid[tid].transcap_rx_mpdu_desc_info);
|
|
|
|
qdf_mem_free(peer->rx_tid[tid].dst_ring_desc);
|
|
|
|
|
|
|
|
|
|
|
|
hal_rx_clear_msdu_link_ptr(
|
|
|
|
peer->rx_tid[tid].dst_ring_desc = NULL;
|
|
|
|
&peer->rx_tid[tid].transcap_msdu_link_ptr[0],
|
|
|
|
|
|
|
|
HAL_RX_MAX_SAVED_RING_DESC);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef DEFRAG_TIMEOUT
|
|
|
|
/*
|
|
|
|
/*
|
|
|
|
* dp_rx_defrag_waitlist_add(): Update per-PDEV defrag wait list
|
|
|
|
* dp_rx_defrag_waitlist_add(): Update per-PDEV defrag wait list
|
|
|
|
* @peer: Pointer to the peer data structure
|
|
|
|
* @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);
|
|
|
|
qdf_assert(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
/*
|
|
|
|
* dp_rx_defrag_fraglist_insert(): Create a per-sequence fragment list
|
|
|
|
* 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);
|
|
|
|
next = qdf_nbuf_next(*head_addr);
|
|
|
|
|
|
|
|
|
|
|
|
rx_desc_info = qdf_nbuf_data(*tail_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 */
|
|
|
|
/* TODO: optimize the loop */
|
|
|
|
if (!last_morefrag) {
|
|
|
|
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
|
|
|
|
* dp_rx_frag_pull_hdr(): Pulls the RXTLV & the 802.11 headers
|
|
|
|
* @peer: Pointer to the peer
|
|
|
|
* @nbuf: buffer pointer
|
|
|
|
* @frag_list: list of fragments
|
|
|
|
|
|
|
|
* @tid: Transmit identifier
|
|
|
|
|
|
|
|
* @hdrsize: Header size
|
|
|
|
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* 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,
|
|
|
|
static void dp_rx_frag_pull_hdr(qdf_nbuf_t nbuf)
|
|
|
|
qdf_nbuf_t head_msdu, unsigned tid, uint16_t hdrsize)
|
|
|
|
|
|
|
|
{
|
|
|
|
{
|
|
|
|
qdf_nbuf_t msdu = head_msdu;
|
|
|
|
uint16_t hdrsize = dp_rx_defrag_hdrsize(nbuf);
|
|
|
|
uint8_t i;
|
|
|
|
|
|
|
|
uint8_t num_ring_desc_saved = peer->rx_tid[tid].curr_ring_desc_idx;
|
|
|
|
|
|
|
|
uint8_t num_msdus;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Stitch fragments together */
|
|
|
|
qdf_nbuf_pull_head(nbuf,
|
|
|
|
for (i = 0; (i < num_ring_desc_saved) && msdu; i++) {
|
|
|
|
RX_PKT_TLVS_LEN + hdrsize);
|
|
|
|
|
|
|
|
|
|
|
|
struct hal_rx_msdu_link_ptr_info *msdu_link_ptr_info =
|
|
|
|
QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_INFO,
|
|
|
|
&peer->rx_tid[tid].transcap_msdu_link_ptr[i];
|
|
|
|
"%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;
|
|
|
|
* dp_rx_construct_fraglist(): Construct a nbuf fraglist
|
|
|
|
|
|
|
|
* @peer: Pointer to the peer
|
|
|
|
num_msdus = hal_rx_chain_msdu_links(msdu, msdu_link_ptr_info,
|
|
|
|
* @head: Pointer to list of fragments
|
|
|
|
mpdu_desc_info);
|
|
|
|
*
|
|
|
|
|
|
|
|
* 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);
|
|
|
|
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 */
|
|
|
|
/* 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
|
|
|
|
* 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
|
|
|
|
* Transcap the fragment from 802.11 to 802.3
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* Returns: None
|
|
|
|
* 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;
|
|
|
|
uint32_t hdrsize;
|
|
|
|
struct llc_snap_hdr_t llchdr;
|
|
|
|
struct llc_snap_hdr_t *llchdr;
|
|
|
|
struct ethernet_hdr_t *eth_hdr;
|
|
|
|
struct ethernet_hdr_t *eth_hdr;
|
|
|
|
int rx_desc_len = sizeof(struct rx_pkt_tlvs);
|
|
|
|
uint8_t ether_type[2];
|
|
|
|
struct ieee80211_frame *wh_ptr;
|
|
|
|
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) +
|
|
|
|
if (rx_desc_info == NULL) {
|
|
|
|
rx_desc_len);
|
|
|
|
QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
|
|
|
|
qdf_mem_copy(&wh, wh_ptr, sizeof(wh));
|
|
|
|
"%s: Memory alloc failed ! \n", __func__);
|
|
|
|
hdrsize = sizeof(struct ieee80211_frame);
|
|
|
|
QDF_ASSERT(0);
|
|
|
|
qdf_mem_copy(&llchdr, ((uint8_t *) (qdf_nbuf_data(msdu) +
|
|
|
|
return;
|
|
|
|
rx_desc_len)) + hdrsize,
|
|
|
|
}
|
|
|
|
sizeof(struct llc_snap_hdr_t));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
hdrsize = dp_rx_defrag_hdrsize(nbuf);
|
|
|
|
* Now move the data pointer to the beginning of the mac header :
|
|
|
|
|
|
|
|
* new-header = old-hdr + (wifihdrsize + llchdrsize - ethhdrsize)
|
|
|
|
qdf_mem_copy(rx_desc_info, qdf_nbuf_data(nbuf), RX_PKT_TLVS_LEN);
|
|
|
|
*/
|
|
|
|
|
|
|
|
qdf_nbuf_pull_head(msdu, (rx_desc_len + hdrsize +
|
|
|
|
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 llc_snap_hdr_t) -
|
|
|
|
sizeof(struct ethernet_hdr_t)));
|
|
|
|
sizeof(struct ethernet_hdr_t)));
|
|
|
|
eth_hdr = (struct ethernet_hdr_t *)(qdf_nbuf_data(msdu));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
switch (wh.i_fc[1] & IEEE80211_FC1_DIR_MASK) {
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
|
|
case IEEE80211_FC1_DIR_NODS:
|
|
|
|
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);
|
|
|
|
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);
|
|
|
|
IEEE80211_ADDR_LEN);
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
case IEEE80211_FC1_DIR_TODS:
|
|
|
|
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);
|
|
|
|
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);
|
|
|
|
IEEE80211_ADDR_LEN);
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
case IEEE80211_FC1_DIR_FROMDS:
|
|
|
|
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);
|
|
|
|
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);
|
|
|
|
IEEE80211_ADDR_LEN);
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case IEEE80211_FC1_DIR_DSTODS:
|
|
|
|
case IEEE80211_FC1_DIR_DSTODS:
|
|
|
|
break;
|
|
|
|
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
|
|
|
|
qdf_mem_copy(eth_hdr->ethertype, ether_type,
|
|
|
|
* to the start of data buffer?
|
|
|
|
sizeof(ether_type));
|
|
|
|
*/
|
|
|
|
|
|
|
|
qdf_mem_copy(eth_hdr->ethertype, llchdr.ethertype,
|
|
|
|
qdf_nbuf_push_head(nbuf, RX_PKT_TLVS_LEN);
|
|
|
|
sizeof(llchdr.ethertype));
|
|
|
|
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
|
|
|
|
* dp_rx_defrag_reo_reinject(): Reinject the fragment chain back into REO
|
|
|
|
* @peer: Pointer to the peer
|
|
|
|
* @peer: Pointer to the peer
|
|
|
|
* @tid: Transmit Identifier
|
|
|
|
* @tid: Transmit Identifier
|
|
|
|
|
|
|
|
* @head: Buffer to be reinjected back
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* Reinject the fragment chain back into REO
|
|
|
|
* Reinject the fragment chain back into REO
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* Returns: QDF_STATUS
|
|
|
|
* Returns: QDF_STATUS
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
static QDF_STATUS dp_rx_defrag_reo_reinject(struct dp_peer *peer,
|
|
|
|
static QDF_STATUS dp_rx_defrag_reo_reinject(struct dp_peer *peer,
|
|
|
|
unsigned tid)
|
|
|
|
unsigned tid, qdf_nbuf_t head)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
struct dp_pdev *pdev = peer->vdev->pdev;
|
|
|
|
struct dp_pdev *pdev = peer->vdev->pdev;
|
|
|
|
struct dp_soc *soc = pdev->soc;
|
|
|
|
struct dp_soc *soc = pdev->soc;
|
|
|
|
QDF_STATUS status = QDF_STATUS_E_FAILURE;
|
|
|
|
struct hal_buf_info buf_info;
|
|
|
|
void *ring_desc;
|
|
|
|
void *link_desc_va;
|
|
|
|
enum hal_reo_error_status error;
|
|
|
|
void *msdu0, *msdu_desc_info;
|
|
|
|
struct hal_rx_mpdu_desc_info *saved_mpdu_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;
|
|
|
|
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))) {
|
|
|
|
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,
|
|
|
|
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 */
|
|
|
|
return QDF_STATUS_E_FAILURE;
|
|
|
|
qdf_assert(0);
|
|
|
|
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
saved_mpdu_desc_info =
|
|
|
|
ent_ring_desc = hal_srng_src_get_next(soc->hal_soc, hal_srng);
|
|
|
|
&peer->rx_tid[tid].transcap_rx_mpdu_desc_info;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* first msdu link pointer */
|
|
|
|
qdf_assert(ent_ring_desc);
|
|
|
|
saved_msdu_link_ptr =
|
|
|
|
|
|
|
|
&peer->rx_tid[tid].transcap_msdu_link_ptr[0];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
hal_rx_defrag_update_src_ring_desc(ring_desc,
|
|
|
|
paddr = (uint64_t)buf_info.paddr;
|
|
|
|
saved_mpdu_desc_info, saved_msdu_link_ptr);
|
|
|
|
/* 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);
|
|
|
|
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
|
|
|
|
* dp_rx_defrag(): Defragment the fragment chain
|
|
|
|
* @peer: Pointer to the peer
|
|
|
|
* @peer: Pointer to the peer
|
|
|
|
* @tid: Transmit Identifier
|
|
|
|
* @tid: Transmit Identifier
|
|
|
|
* @frag_list: Pointer to head list
|
|
|
|
* @frag_list_head: Pointer to head list
|
|
|
|
* @frag_list_tail: Pointer to tail list
|
|
|
|
* @frag_list_tail: Pointer to tail list
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* Defragment the fragment chain
|
|
|
|
* Defragment the fragment chain
|
|
|
@@ -856,22 +937,29 @@ done:
|
|
|
|
* Returns: QDF_STATUS
|
|
|
|
* Returns: QDF_STATUS
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
static QDF_STATUS dp_rx_defrag(struct dp_peer *peer, unsigned tid,
|
|
|
|
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 tmp_next, prev;
|
|
|
|
qdf_nbuf_t cur = frag_list, msdu;
|
|
|
|
qdf_nbuf_t cur = frag_list_head, msdu;
|
|
|
|
|
|
|
|
|
|
|
|
uint32_t index, tkip_demic = 0;
|
|
|
|
uint32_t index, tkip_demic = 0;
|
|
|
|
uint16_t hdr_space;
|
|
|
|
uint16_t hdr_space;
|
|
|
|
QDF_STATUS status;
|
|
|
|
|
|
|
|
uint8_t key[DEFRAG_IEEE80211_KEY_LEN];
|
|
|
|
uint8_t key[DEFRAG_IEEE80211_KEY_LEN];
|
|
|
|
struct dp_vdev *vdev = peer->vdev;
|
|
|
|
struct dp_vdev *vdev = peer->vdev;
|
|
|
|
|
|
|
|
|
|
|
|
cur = frag_list;
|
|
|
|
|
|
|
|
hdr_space = dp_rx_defrag_hdrsize(cur);
|
|
|
|
hdr_space = dp_rx_defrag_hdrsize(cur);
|
|
|
|
index = hal_rx_msdu_is_wlan_mcast(cur) ?
|
|
|
|
index = hal_rx_msdu_is_wlan_mcast(cur) ?
|
|
|
|
dp_sec_mcast : dp_sec_ucast;
|
|
|
|
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) {
|
|
|
|
switch (peer->security[index].sec_type) {
|
|
|
|
case htt_sec_type_tkip:
|
|
|
|
case htt_sec_type_tkip:
|
|
|
|
tkip_demic = 1;
|
|
|
|
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)) {
|
|
|
|
if (dp_rx_defrag_tkip_decap(cur, hdr_space)) {
|
|
|
|
|
|
|
|
|
|
|
|
/* TKIP decap failed, discard frags */
|
|
|
|
/* 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(QDF_MODULE_ID_TXRX,
|
|
|
|
QDF_TRACE_LEVEL_ERROR,
|
|
|
|
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)) {
|
|
|
|
if (dp_rx_defrag_ccmp_demic(cur, hdr_space)) {
|
|
|
|
|
|
|
|
|
|
|
|
/* CCMP demic failed, discard frags */
|
|
|
|
/* 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(QDF_MODULE_ID_TXRX,
|
|
|
|
QDF_TRACE_LEVEL_ERROR,
|
|
|
|
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)) {
|
|
|
|
if (dp_rx_defrag_ccmp_decap(cur, hdr_space)) {
|
|
|
|
|
|
|
|
|
|
|
|
/* CCMP decap failed, discard frags */
|
|
|
|
/* 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(QDF_MODULE_ID_TXRX,
|
|
|
|
QDF_TRACE_LEVEL_ERROR,
|
|
|
|
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)) {
|
|
|
|
if (dp_rx_defrag_wep_decap(cur, hdr_space)) {
|
|
|
|
|
|
|
|
|
|
|
|
/* WEP decap failed, discard frags */
|
|
|
|
/* 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(QDF_MODULE_ID_TXRX,
|
|
|
|
QDF_TRACE_LEVEL_ERROR,
|
|
|
|
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 */
|
|
|
|
/* 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);
|
|
|
|
return QDF_STATUS_SUCCESS;
|
|
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
/*
|
|
|
|
* dp_rx_defrag_cleanup(): Clean up activities
|
|
|
|
* dp_rx_defrag_cleanup(): Clean up activities
|
|
|
|
* @peer: Pointer to the peer
|
|
|
|
* @peer: Pointer to the peer
|
|
|
|
* @tid: Transmit Identifier
|
|
|
|
* @tid: Transmit Identifier
|
|
|
|
* @seq: Sequence number
|
|
|
|
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* Returns: None
|
|
|
|
* Returns: None
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
static void dp_rx_defrag_cleanup(struct dp_peer *peer, unsigned tid,
|
|
|
|
static void dp_rx_defrag_cleanup(struct dp_peer *peer, unsigned tid)
|
|
|
|
uint16_t seq)
|
|
|
|
|
|
|
|
{
|
|
|
|
{
|
|
|
|
struct dp_rx_reorder_array_elem *rx_reorder_array_elem =
|
|
|
|
struct dp_rx_reorder_array_elem *rx_reorder_array_elem =
|
|
|
|
&peer->rx_tid[tid].array[seq];
|
|
|
|
peer->rx_tid[tid].array;
|
|
|
|
|
|
|
|
|
|
|
|
/* Free up nbufs */
|
|
|
|
/* Free up nbufs */
|
|
|
|
dp_rx_defrag_frames_free(rx_reorder_array_elem->head);
|
|
|
|
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].defrag_timeout_ms = 0;
|
|
|
|
peer->rx_tid[tid].curr_frag_num = 0;
|
|
|
|
peer->rx_tid[tid].curr_frag_num = 0;
|
|
|
|
peer->rx_tid[tid].curr_seq_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
|
|
|
|
* 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
|
|
|
|
* @peer: Pointer to the peer
|
|
|
|
* @tid: Transmit Identifier
|
|
|
|
* @tid: Transmit Identifier
|
|
|
|
* @mpdu_desc_info: MPDU descriptor info
|
|
|
|
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* Returns: None
|
|
|
|
* Returns: None
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
static void dp_rx_defrag_save_info_from_ring_desc(void *ring_desc,
|
|
|
|
static QDF_STATUS dp_rx_defrag_save_info_from_ring_desc(void *ring_desc,
|
|
|
|
struct dp_peer *peer, unsigned tid,
|
|
|
|
struct dp_peer *peer, unsigned tid)
|
|
|
|
struct hal_rx_mpdu_desc_info *mpdu_desc_info)
|
|
|
|
|
|
|
|
{
|
|
|
|
{
|
|
|
|
struct dp_pdev *pdev = peer->vdev->pdev;
|
|
|
|
void *dst_ring_desc = qdf_mem_malloc(
|
|
|
|
void *msdu_link_desc_va = NULL;
|
|
|
|
sizeof(struct reo_destination_ring));
|
|
|
|
uint8_t idx = peer->rx_tid[tid].curr_ring_desc_idx;
|
|
|
|
|
|
|
|
uint8_t rbm;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct hal_rx_msdu_link_ptr_info *msdu_link_ptr_info =
|
|
|
|
if (dst_ring_desc == NULL) {
|
|
|
|
&peer->rx_tid[tid].transcap_msdu_link_ptr[++idx];
|
|
|
|
QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
|
|
|
|
struct hal_rx_mpdu_desc_info *tmp_mpdu_desc_info =
|
|
|
|
"%s: Memory alloc failed !\n", __func__);
|
|
|
|
&peer->rx_tid[tid].transcap_rx_mpdu_desc_info;
|
|
|
|
QDF_ASSERT(0);
|
|
|
|
struct hal_buf_info hbi;
|
|
|
|
return QDF_STATUS_E_NOMEM;
|
|
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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 =
|
|
|
|
peer->rx_tid[tid].dst_ring_desc = dst_ring_desc;
|
|
|
|
dp_rx_cookie_2_link_desc_va(pdev->soc, &hbi);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
hal_rx_defrag_save_info_from_ring_desc(msdu_link_desc_va,
|
|
|
|
return QDF_STATUS_SUCCESS;
|
|
|
|
msdu_link_ptr_info, &hbi);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
qdf_mem_copy(tmp_mpdu_desc_info, mpdu_desc_info,
|
|
|
|
|
|
|
|
sizeof(*tmp_mpdu_desc_info));
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
/*
|
|
|
@@ -1058,9 +1119,9 @@ static void dp_rx_defrag_save_info_from_ring_desc(void *ring_desc,
|
|
|
|
* @soc: Pointer to the SOC data structure
|
|
|
|
* @soc: Pointer to the SOC data structure
|
|
|
|
* @ring_desc: Pointer to the ring descriptor
|
|
|
|
* @ring_desc: Pointer to the ring descriptor
|
|
|
|
* @mpdu_desc_info: MPDU descriptor info
|
|
|
|
* @mpdu_desc_info: MPDU descriptor info
|
|
|
|
* @msdu_info: Pointer to MSDU descriptor info
|
|
|
|
|
|
|
|
* @tid: Traffic Identifier
|
|
|
|
* @tid: Traffic Identifier
|
|
|
|
* @rx_desc: Pointer to rx descriptor
|
|
|
|
* @rx_desc: Pointer to rx descriptor
|
|
|
|
|
|
|
|
* @rx_bfs: Number of bfs consumed
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* Returns: QDF_STATUS
|
|
|
|
* Returns: QDF_STATUS
|
|
|
|
*/
|
|
|
|
*/
|
|
|
@@ -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 **head,
|
|
|
|
union dp_rx_desc_list_elem_t **tail,
|
|
|
|
union dp_rx_desc_list_elem_t **tail,
|
|
|
|
struct hal_rx_mpdu_desc_info *mpdu_desc_info,
|
|
|
|
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_rx_reorder_array_elem *rx_reorder_array_elem;
|
|
|
|
struct dp_pdev *pdev;
|
|
|
|
struct dp_pdev *pdev;
|
|
|
|
struct dp_peer *peer;
|
|
|
|
struct dp_peer *peer;
|
|
|
|
uint16_t peer_id;
|
|
|
|
uint16_t peer_id;
|
|
|
|
uint16_t rxseq, seq;
|
|
|
|
|
|
|
|
uint8_t fragno, more_frag, all_frag_present = 0;
|
|
|
|
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;
|
|
|
|
QDF_STATUS status;
|
|
|
|
struct dp_rx_tid *rx_tid;
|
|
|
|
struct dp_rx_tid *rx_tid;
|
|
|
|
uint8_t mpdu_sequence_control_valid;
|
|
|
|
uint8_t mpdu_sequence_control_valid;
|
|
|
|
uint8_t mpdu_frame_control_valid;
|
|
|
|
uint8_t mpdu_frame_control_valid;
|
|
|
|
qdf_nbuf_t frag = rx_desc->nbuf;
|
|
|
|
qdf_nbuf_t frag = rx_desc->nbuf;
|
|
|
|
uint8_t *rx_desc_info;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Check if the packet is from a valid peer */
|
|
|
|
/* Check if the packet is from a valid peer */
|
|
|
|
peer_id = DP_PEER_METADATA_PEER_ID_GET(
|
|
|
|
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;
|
|
|
|
pdev = peer->vdev->pdev;
|
|
|
|
rx_tid = &peer->rx_tid[tid];
|
|
|
|
rx_tid = &peer->rx_tid[tid];
|
|
|
|
|
|
|
|
|
|
|
|
seq = seq_num & (peer->rx_tid[tid].ba_win_size - 1);
|
|
|
|
rx_reorder_array_elem = peer->rx_tid[tid].array;
|
|
|
|
qdf_assert(seq == 0);
|
|
|
|
|
|
|
|
rx_reorder_array_elem = &peer->rx_tid[tid].array[seq];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
rx_desc_info = qdf_nbuf_data(frag);
|
|
|
|
|
|
|
|
mpdu_sequence_control_valid =
|
|
|
|
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 */
|
|
|
|
/* Invalid MPDU sequence control field, MPDU is of no use */
|
|
|
|
if (!mpdu_sequence_control_valid) {
|
|
|
|
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 =
|
|
|
|
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 */
|
|
|
|
/* Invalid frame control field */
|
|
|
|
if (!mpdu_frame_control_valid) {
|
|
|
|
if (!mpdu_frame_control_valid) {
|
|
|
@@ -1143,13 +1198,12 @@ static QDF_STATUS dp_rx_defrag_store_fragment(struct dp_soc *soc,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Current mpdu sequence */
|
|
|
|
/* Current mpdu sequence */
|
|
|
|
rxseq = hal_rx_get_rx_sequence(rx_desc_info);
|
|
|
|
more_frag = dp_rx_frag_get_more_frag_bit(rx_desc->rx_buf_start);
|
|
|
|
more_frag = hal_rx_get_rx_more_frag_bit(rx_desc_info);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* HW does not populate the fragment number as of now
|
|
|
|
/* HW does not populate the fragment number as of now
|
|
|
|
* need to get from the 802.11 header
|
|
|
|
* 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
|
|
|
|
* !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 */
|
|
|
|
/* Check if the fragment is for the same sequence or a different one */
|
|
|
|
if (rx_reorder_array_elem->head) {
|
|
|
|
if (rx_reorder_array_elem->head) {
|
|
|
|
|
|
|
|
|
|
|
|
if (rxseq != rx_tid->curr_seq_num) {
|
|
|
|
if (rxseq != rx_tid->curr_seq_num) {
|
|
|
|
|
|
|
|
|
|
|
|
/* Drop stored fragments if out of sequence
|
|
|
|
/* Drop stored fragments if out of sequence
|
|
|
@@ -1198,6 +1251,7 @@ static QDF_STATUS dp_rx_defrag_store_fragment(struct dp_soc *soc,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
/* Start of a new sequence */
|
|
|
|
/* Start of a new sequence */
|
|
|
|
|
|
|
|
dp_rx_defrag_cleanup(peer, tid);
|
|
|
|
rx_tid->curr_seq_num = rxseq;
|
|
|
|
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
|
|
|
|
* have to use the next MSDU link descriptor and chain them together
|
|
|
|
* before reinjection
|
|
|
|
* before reinjection
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
if (more_frag == 0 || fragno == HAL_RX_NUM_MSDU_DESC) {
|
|
|
|
if ((fragno == 0) && (rx_reorder_array_elem->head == frag)) {
|
|
|
|
/*
|
|
|
|
|
|
|
|
* 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);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
peer->rx_tid[tid].curr_ring_desc_idx++;
|
|
|
|
status = dp_rx_defrag_save_info_from_ring_desc(ring_desc,
|
|
|
|
} else {
|
|
|
|
peer, tid);
|
|
|
|
QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
|
|
|
|
|
|
|
|
"Max ring descr saved, dropping fragment");
|
|
|
|
if (status != QDF_STATUS_SUCCESS) {
|
|
|
|
/*
|
|
|
|
QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
|
|
|
|
* Free up saved fragments and ring descriptors if any
|
|
|
|
"%s: Unable to store ring desc !\n", __func__);
|
|
|
|
*/
|
|
|
|
|
|
|
|
goto end;
|
|
|
|
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 */
|
|
|
|
/* TODO: handle fragment timeout gracefully */
|
|
|
|
if (pdev->soc->rx.flags.defrag_timeout_check) {
|
|
|
|
if (pdev->soc->rx.flags.defrag_timeout_check) {
|
|
|
|
dp_rx_defrag_waitlist_remove(peer, tid);
|
|
|
|
dp_rx_defrag_waitlist_remove(peer, tid);
|
|
|
|
goto end;
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
/* Yet to receive more fragments for this sequence number */
|
|
|
|
/* Yet to receive more fragments for this sequence number */
|
|
|
|
if (!all_frag_present) {
|
|
|
|
if (!all_frag_present) {
|
|
|
|
uint32_t now_ms =
|
|
|
|
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 =
|
|
|
|
peer->rx_tid[tid].defrag_timeout_ms =
|
|
|
|
now_ms + pdev->soc->rx.defrag.timeout_ms;
|
|
|
|
now_ms + pdev->soc->rx.defrag.timeout_ms;
|
|
|
|
|
|
|
|
|
|
|
|
dp_rx_defrag_waitlist_add(peer, tid);
|
|
|
|
return QDF_STATUS_SUCCESS;
|
|
|
|
goto end;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO,
|
|
|
|
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 */
|
|
|
|
/* Re-inject the fragments back to REO for further processing */
|
|
|
|
status = dp_rx_defrag_reo_reinject(peer, tid);
|
|
|
|
status = dp_rx_defrag_reo_reinject(peer, tid,
|
|
|
|
if (QDF_IS_STATUS_SUCCESS(status))
|
|
|
|
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,
|
|
|
|
QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO,
|
|
|
|
"Fragmented sequence successfully reinjected");
|
|
|
|
"Fragmented sequence successfully reinjected");
|
|
|
|
|
|
|
|
}
|
|
|
|
else
|
|
|
|
else
|
|
|
|
QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
|
|
|
|
QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
|
|
|
|
"Fragmented sequence reinjection failed");
|
|
|
|
"Fragmented sequence reinjection failed");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
dp_rx_defrag_cleanup(peer, tid);
|
|
|
|
|
|
|
|
return QDF_STATUS_SUCCESS;
|
|
|
|
|
|
|
|
|
|
|
|
end:
|
|
|
|
end:
|
|
|
|
dp_rx_defrag_cleanup(peer, tid, seq);
|
|
|
|
|
|
|
|
return QDF_STATUS_E_DEFRAG_ERROR;
|
|
|
|
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;
|
|
|
|
void *link_desc_va;
|
|
|
|
struct hal_buf_info buf_info;
|
|
|
|
struct hal_buf_info buf_info;
|
|
|
|
struct hal_rx_msdu_list msdu_list; /* per MPDU list of MSDUs */
|
|
|
|
struct hal_rx_msdu_list msdu_list; /* per MPDU list of MSDUs */
|
|
|
|
uint32_t tid;
|
|
|
|
qdf_nbuf_t msdu = NULL;
|
|
|
|
int idx;
|
|
|
|
uint32_t tid, msdu_len;
|
|
|
|
|
|
|
|
int idx, rx_bfs = 0;
|
|
|
|
QDF_STATUS status;
|
|
|
|
QDF_STATUS status;
|
|
|
|
|
|
|
|
|
|
|
|
qdf_assert(soc);
|
|
|
|
qdf_assert(soc);
|
|
|
@@ -1345,20 +1410,38 @@ uint32_t dp_rx_frag_handle(struct dp_soc *soc, void *ring_desc,
|
|
|
|
|
|
|
|
|
|
|
|
qdf_assert(rx_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);
|
|
|
|
tid = hal_rx_mpdu_start_tid_get(rx_desc->rx_buf_start);
|
|
|
|
|
|
|
|
|
|
|
|
/* Process fragment-by-fragment */
|
|
|
|
/* Process fragment-by-fragment */
|
|
|
|
status = dp_rx_defrag_store_fragment(soc, ring_desc,
|
|
|
|
status = dp_rx_defrag_store_fragment(soc, ring_desc,
|
|
|
|
head, tail, mpdu_desc_info,
|
|
|
|
head, tail, mpdu_desc_info,
|
|
|
|
&msdu_list.msdu_info[idx], tid,
|
|
|
|
tid, rx_desc, &rx_bfs);
|
|
|
|
rx_desc);
|
|
|
|
|
|
|
|
if (QDF_IS_STATUS_SUCCESS(status))
|
|
|
|
if (QDF_IS_STATUS_SUCCESS(status)) {
|
|
|
|
|
|
|
|
if (rx_bfs)
|
|
|
|
rx_bufs_used++;
|
|
|
|
rx_bufs_used++;
|
|
|
|
else
|
|
|
|
} else {
|
|
|
|
QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
|
|
|
|
QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
|
|
|
|
"Rx Defragmentation error. mpdu_seq: 0x%x msdu_count: %d mpdu_flags: %d",
|
|
|
|
"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_seq,
|
|
|
|
|
|
|
|
mpdu_desc_info->msdu_count,
|
|
|
|
mpdu_desc_info->mpdu_flags);
|
|
|
|
mpdu_desc_info->mpdu_flags);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* No point in processing rest of the fragments */
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return rx_bufs_used;
|
|
|
|
return rx_bufs_used;
|
|
|
|