|
@@ -1134,27 +1134,64 @@ void dp_rx_fill_gro_info(struct dp_soc *soc, uint8_t *rx_tlv,
|
|
* @soc: DP soc handle
|
|
* @soc: DP soc handle
|
|
* @nbuf: pointer to msdu.
|
|
* @nbuf: pointer to msdu.
|
|
* @mpdu_len: mpdu length
|
|
* @mpdu_len: mpdu length
|
|
|
|
+ * @l3_pad_len: L3 padding length by HW
|
|
*
|
|
*
|
|
* Return: returns true if nbuf is last msdu of mpdu else retuns false.
|
|
* Return: returns true if nbuf is last msdu of mpdu else retuns false.
|
|
*/
|
|
*/
|
|
static inline bool dp_rx_adjust_nbuf_len(struct dp_soc *soc,
|
|
static inline bool dp_rx_adjust_nbuf_len(struct dp_soc *soc,
|
|
- qdf_nbuf_t nbuf, uint16_t *mpdu_len)
|
|
|
|
|
|
+ qdf_nbuf_t nbuf,
|
|
|
|
+ uint16_t *mpdu_len,
|
|
|
|
+ uint32_t l3_pad_len)
|
|
{
|
|
{
|
|
bool last_nbuf;
|
|
bool last_nbuf;
|
|
|
|
+ uint32_t pkt_hdr_size;
|
|
|
|
|
|
- if (*mpdu_len > (RX_DATA_BUFFER_SIZE - soc->rx_pkt_tlv_size)) {
|
|
|
|
|
|
+ pkt_hdr_size = soc->rx_pkt_tlv_size + l3_pad_len;
|
|
|
|
+
|
|
|
|
+ if ((*mpdu_len + pkt_hdr_size) > RX_DATA_BUFFER_SIZE) {
|
|
qdf_nbuf_set_pktlen(nbuf, RX_DATA_BUFFER_SIZE);
|
|
qdf_nbuf_set_pktlen(nbuf, RX_DATA_BUFFER_SIZE);
|
|
last_nbuf = false;
|
|
last_nbuf = false;
|
|
|
|
+ *mpdu_len -= (RX_DATA_BUFFER_SIZE - pkt_hdr_size);
|
|
} else {
|
|
} else {
|
|
- qdf_nbuf_set_pktlen(nbuf, (*mpdu_len + soc->rx_pkt_tlv_size));
|
|
|
|
|
|
+ qdf_nbuf_set_pktlen(nbuf, (*mpdu_len + pkt_hdr_size));
|
|
last_nbuf = true;
|
|
last_nbuf = true;
|
|
|
|
+ *mpdu_len = 0;
|
|
}
|
|
}
|
|
|
|
|
|
- *mpdu_len -= (RX_DATA_BUFFER_SIZE - soc->rx_pkt_tlv_size);
|
|
|
|
-
|
|
|
|
return last_nbuf;
|
|
return last_nbuf;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * dp_get_l3_hdr_pad_len() - get L3 header padding length.
|
|
|
|
+ *
|
|
|
|
+ * @soc: DP soc handle
|
|
|
|
+ * @nbuf: pointer to msdu.
|
|
|
|
+ *
|
|
|
|
+ * Return: returns padding length in bytes.
|
|
|
|
+ */
|
|
|
|
+static inline uint32_t dp_get_l3_hdr_pad_len(struct dp_soc *soc,
|
|
|
|
+ qdf_nbuf_t nbuf)
|
|
|
|
+{
|
|
|
|
+ uint32_t l3_hdr_pad = 0;
|
|
|
|
+ uint8_t *rx_tlv_hdr;
|
|
|
|
+ struct hal_rx_msdu_metadata msdu_metadata;
|
|
|
|
+
|
|
|
|
+ while (nbuf) {
|
|
|
|
+ if (!qdf_nbuf_is_rx_chfrag_cont(nbuf)) {
|
|
|
|
+ /* scattered msdu end with continuation is 0 */
|
|
|
|
+ rx_tlv_hdr = qdf_nbuf_data(nbuf);
|
|
|
|
+ hal_rx_msdu_metadata_get(soc->hal_soc,
|
|
|
|
+ rx_tlv_hdr,
|
|
|
|
+ &msdu_metadata);
|
|
|
|
+ l3_hdr_pad = msdu_metadata.l3_hdr_pad;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ nbuf = nbuf->next;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return l3_hdr_pad;
|
|
|
|
+}
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* dp_rx_sg_create() - create a frag_list for MSDUs which are spread across
|
|
* dp_rx_sg_create() - create a frag_list for MSDUs which are spread across
|
|
* multiple nbufs.
|
|
* multiple nbufs.
|
|
@@ -1172,6 +1209,7 @@ qdf_nbuf_t dp_rx_sg_create(struct dp_soc *soc, qdf_nbuf_t nbuf)
|
|
uint16_t frag_list_len = 0;
|
|
uint16_t frag_list_len = 0;
|
|
uint16_t mpdu_len;
|
|
uint16_t mpdu_len;
|
|
bool last_nbuf;
|
|
bool last_nbuf;
|
|
|
|
+ uint32_t l3_hdr_pad_offset = 0;
|
|
|
|
|
|
/*
|
|
/*
|
|
* Use msdu len got from REO entry descriptor instead since
|
|
* Use msdu len got from REO entry descriptor instead since
|
|
@@ -1179,6 +1217,7 @@ qdf_nbuf_t dp_rx_sg_create(struct dp_soc *soc, qdf_nbuf_t nbuf)
|
|
* from REO descriptor is right for non-raw RX scatter msdu.
|
|
* from REO descriptor is right for non-raw RX scatter msdu.
|
|
*/
|
|
*/
|
|
mpdu_len = QDF_NBUF_CB_RX_PKT_LEN(nbuf);
|
|
mpdu_len = QDF_NBUF_CB_RX_PKT_LEN(nbuf);
|
|
|
|
+
|
|
/*
|
|
/*
|
|
* this is a case where the complete msdu fits in one single nbuf.
|
|
* this is a case where the complete msdu fits in one single nbuf.
|
|
* in this case HW sets both start and end bit and we only need to
|
|
* in this case HW sets both start and end bit and we only need to
|
|
@@ -1191,6 +1230,7 @@ qdf_nbuf_t dp_rx_sg_create(struct dp_soc *soc, qdf_nbuf_t nbuf)
|
|
return nbuf;
|
|
return nbuf;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ l3_hdr_pad_offset = dp_get_l3_hdr_pad_len(soc, nbuf);
|
|
/*
|
|
/*
|
|
* This is a case where we have multiple msdus (A-MSDU) spread across
|
|
* This is a case where we have multiple msdus (A-MSDU) spread across
|
|
* multiple nbufs. here we create a fraglist out of these nbufs.
|
|
* multiple nbufs. here we create a fraglist out of these nbufs.
|
|
@@ -1210,17 +1250,23 @@ qdf_nbuf_t dp_rx_sg_create(struct dp_soc *soc, qdf_nbuf_t nbuf)
|
|
* nbufs will form the frag_list of the parent nbuf.
|
|
* nbufs will form the frag_list of the parent nbuf.
|
|
*/
|
|
*/
|
|
qdf_nbuf_set_rx_chfrag_start(parent, 1);
|
|
qdf_nbuf_set_rx_chfrag_start(parent, 1);
|
|
- last_nbuf = dp_rx_adjust_nbuf_len(soc, parent, &mpdu_len);
|
|
|
|
|
|
+ /*
|
|
|
|
+ * L3 header padding is only needed for the 1st buffer
|
|
|
|
+ * in a scattered msdu
|
|
|
|
+ */
|
|
|
|
+ last_nbuf = dp_rx_adjust_nbuf_len(soc, parent, &mpdu_len,
|
|
|
|
+ l3_hdr_pad_offset);
|
|
|
|
|
|
/*
|
|
/*
|
|
- * HW issue: MSDU cont bit is set but reported MPDU length can fit
|
|
|
|
|
|
+ * MSDU cont bit is set but reported MPDU length can fit
|
|
* in to single buffer
|
|
* in to single buffer
|
|
*
|
|
*
|
|
* Increment error stats and avoid SG list creation
|
|
* Increment error stats and avoid SG list creation
|
|
*/
|
|
*/
|
|
if (last_nbuf) {
|
|
if (last_nbuf) {
|
|
DP_STATS_INC(soc, rx.err.msdu_continuation_err, 1);
|
|
DP_STATS_INC(soc, rx.err.msdu_continuation_err, 1);
|
|
- qdf_nbuf_pull_head(parent, soc->rx_pkt_tlv_size);
|
|
|
|
|
|
+ qdf_nbuf_pull_head(parent,
|
|
|
|
+ soc->rx_pkt_tlv_size + l3_hdr_pad_offset);
|
|
return parent;
|
|
return parent;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1230,8 +1276,9 @@ qdf_nbuf_t dp_rx_sg_create(struct dp_soc *soc, qdf_nbuf_t nbuf)
|
|
* till we hit the last_nbuf of the list.
|
|
* till we hit the last_nbuf of the list.
|
|
*/
|
|
*/
|
|
do {
|
|
do {
|
|
- last_nbuf = dp_rx_adjust_nbuf_len(soc, nbuf, &mpdu_len);
|
|
|
|
- qdf_nbuf_pull_head(nbuf, soc->rx_pkt_tlv_size);
|
|
|
|
|
|
+ last_nbuf = dp_rx_adjust_nbuf_len(soc, nbuf, &mpdu_len, 0);
|
|
|
|
+ qdf_nbuf_pull_head(nbuf,
|
|
|
|
+ soc->rx_pkt_tlv_size);
|
|
frag_list_len += qdf_nbuf_len(nbuf);
|
|
frag_list_len += qdf_nbuf_len(nbuf);
|
|
|
|
|
|
if (last_nbuf) {
|
|
if (last_nbuf) {
|
|
@@ -1247,7 +1294,8 @@ qdf_nbuf_t dp_rx_sg_create(struct dp_soc *soc, qdf_nbuf_t nbuf)
|
|
qdf_nbuf_append_ext_list(parent, frag_list, frag_list_len);
|
|
qdf_nbuf_append_ext_list(parent, frag_list, frag_list_len);
|
|
parent->next = next;
|
|
parent->next = next;
|
|
|
|
|
|
- qdf_nbuf_pull_head(parent, soc->rx_pkt_tlv_size);
|
|
|
|
|
|
+ qdf_nbuf_pull_head(parent,
|
|
|
|
+ soc->rx_pkt_tlv_size + l3_hdr_pad_offset);
|
|
return parent;
|
|
return parent;
|
|
}
|
|
}
|
|
|
|
|