qcacmn: fix STA + SAP IPA de-frag issue
Currently wlan host will re-inject defrag data with RBM 6 to REO, this data buffer will go to REO-->REO2SW4-->IPA-->FW2RXDMA, fix below issue introduced by this RX buffer path. a. FW assert due to FW2RXDMA DMA address not 4 bytes aligned. b. host skb double allocation due to qdf_nbuf_linearize() for frag skb. c. Invalid RBM 6 for fragment RX due to RX buffer resue. Change-Id: I36d831fc14b6b9aa0cea32682823de348f7eecd3 CRs-Fixed: 2591453
This commit is contained in:
@@ -1801,6 +1801,69 @@ bool dp_ipa_is_mdm_platform(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* dp_ipa_frag_nbuf_linearize - linearize nbuf for IPA
|
||||
* @soc: soc
|
||||
* @nbuf: source skb
|
||||
*
|
||||
* Return: new nbuf if success and otherwise NULL
|
||||
*/
|
||||
static qdf_nbuf_t dp_ipa_frag_nbuf_linearize(struct dp_soc *soc,
|
||||
qdf_nbuf_t nbuf)
|
||||
{
|
||||
uint8_t *src_nbuf_data;
|
||||
uint8_t *dst_nbuf_data;
|
||||
qdf_nbuf_t dst_nbuf;
|
||||
qdf_nbuf_t temp_nbuf = nbuf;
|
||||
uint32_t nbuf_len = qdf_nbuf_len(nbuf);
|
||||
bool is_nbuf_head = true;
|
||||
uint32_t copy_len = 0;
|
||||
|
||||
dst_nbuf = qdf_nbuf_alloc(soc->osdev, RX_BUFFER_SIZE,
|
||||
RX_BUFFER_RESERVATION, RX_BUFFER_ALIGNMENT,
|
||||
FALSE);
|
||||
|
||||
if (!dst_nbuf) {
|
||||
dp_err_rl("nbuf allocate fail");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((nbuf_len + L3_HEADER_PADDING) > RX_BUFFER_SIZE) {
|
||||
qdf_nbuf_free(dst_nbuf);
|
||||
dp_err_rl("nbuf is jumbo data");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* prepeare to copy all data into new skb */
|
||||
dst_nbuf_data = qdf_nbuf_data(dst_nbuf);
|
||||
while (temp_nbuf) {
|
||||
src_nbuf_data = qdf_nbuf_data(temp_nbuf);
|
||||
/* first head nbuf */
|
||||
if (is_nbuf_head) {
|
||||
qdf_mem_copy(dst_nbuf_data, src_nbuf_data,
|
||||
RX_PKT_TLVS_LEN);
|
||||
/* leave extra 2 bytes L3_HEADER_PADDING */
|
||||
dst_nbuf_data += (RX_PKT_TLVS_LEN + L3_HEADER_PADDING);
|
||||
src_nbuf_data += RX_PKT_TLVS_LEN;
|
||||
copy_len = qdf_nbuf_headlen(temp_nbuf) -
|
||||
RX_PKT_TLVS_LEN;
|
||||
temp_nbuf = qdf_nbuf_get_ext_list(temp_nbuf);
|
||||
is_nbuf_head = false;
|
||||
} else {
|
||||
copy_len = qdf_nbuf_len(temp_nbuf);
|
||||
temp_nbuf = qdf_nbuf_queue_next(temp_nbuf);
|
||||
}
|
||||
qdf_mem_copy(dst_nbuf_data, src_nbuf_data, copy_len);
|
||||
dst_nbuf_data += copy_len;
|
||||
}
|
||||
|
||||
qdf_nbuf_set_len(dst_nbuf, nbuf_len);
|
||||
/* copy is done, free original nbuf */
|
||||
qdf_nbuf_free(nbuf);
|
||||
|
||||
return dst_nbuf;
|
||||
}
|
||||
|
||||
/**
|
||||
* dp_ipa_handle_rx_reo_reinject - Handle RX REO reinject skb buffer
|
||||
* @soc: soc
|
||||
@@ -1810,7 +1873,6 @@ bool dp_ipa_is_mdm_platform(void)
|
||||
*/
|
||||
qdf_nbuf_t dp_ipa_handle_rx_reo_reinject(struct dp_soc *soc, qdf_nbuf_t nbuf)
|
||||
{
|
||||
uint8_t *rx_pkt_tlvs;
|
||||
|
||||
if (!wlan_cfg_is_ipa_enabled(soc->wlan_cfg_ctx))
|
||||
return nbuf;
|
||||
@@ -1819,33 +1881,11 @@ qdf_nbuf_t dp_ipa_handle_rx_reo_reinject(struct dp_soc *soc, qdf_nbuf_t nbuf)
|
||||
if (!qdf_atomic_read(&soc->ipa_pipes_enabled))
|
||||
return nbuf;
|
||||
|
||||
/* Linearize the skb since IPA assumes linear buffer */
|
||||
if (qdf_likely(qdf_nbuf_is_frag(nbuf))) {
|
||||
if (qdf_nbuf_linearize(nbuf)) {
|
||||
dp_err_rl("nbuf linearize failed");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
if (!qdf_nbuf_is_frag(nbuf))
|
||||
return nbuf;
|
||||
|
||||
rx_pkt_tlvs = qdf_mem_malloc(RX_PKT_TLVS_LEN);
|
||||
if (!rx_pkt_tlvs) {
|
||||
dp_err_rl("rx_pkt_tlvs alloc failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
qdf_mem_copy(rx_pkt_tlvs, qdf_nbuf_data(nbuf), RX_PKT_TLVS_LEN);
|
||||
|
||||
/* Pad L3_HEADER_PADDING before ethhdr and after rx_pkt_tlvs */
|
||||
qdf_nbuf_push_head(nbuf, L3_HEADER_PADDING);
|
||||
|
||||
qdf_mem_copy(qdf_nbuf_data(nbuf), rx_pkt_tlvs, RX_PKT_TLVS_LEN);
|
||||
|
||||
/* L3_HEADDING_PADDING is not accounted for real skb length */
|
||||
qdf_nbuf_set_len(nbuf, qdf_nbuf_len(nbuf) - L3_HEADER_PADDING);
|
||||
|
||||
qdf_mem_free(rx_pkt_tlvs);
|
||||
|
||||
return nbuf;
|
||||
/* linearize skb for IPA */
|
||||
return dp_ipa_frag_nbuf_linearize(soc, nbuf);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@@ -1026,13 +1026,23 @@ static QDF_STATUS dp_rx_defrag_reo_reinject(struct dp_peer *peer,
|
||||
peer->rx_tid[tid].dst_ring_desc;
|
||||
hal_ring_handle_t hal_srng = soc->reo_reinject_ring.hal_srng;
|
||||
struct dp_rx_desc *rx_desc = peer->rx_tid[tid].head_frag_desc;
|
||||
struct dp_rx_reorder_array_elem *rx_reorder_array_elem =
|
||||
peer->rx_tid[tid].array;
|
||||
qdf_nbuf_t nbuf_head;
|
||||
|
||||
head = dp_ipa_handle_rx_reo_reinject(soc, head);
|
||||
if (qdf_unlikely(!head)) {
|
||||
nbuf_head = dp_ipa_handle_rx_reo_reinject(soc, head);
|
||||
if (qdf_unlikely(!nbuf_head)) {
|
||||
dp_err_rl("IPA RX REO reinject failed");
|
||||
return QDF_STATUS_E_FAILURE;
|
||||
}
|
||||
|
||||
/* update new allocated skb in case IPA is enabled */
|
||||
if (nbuf_head != head) {
|
||||
head = nbuf_head;
|
||||
rx_desc->nbuf = head;
|
||||
rx_reorder_array_elem->head = head;
|
||||
}
|
||||
|
||||
ent_ring_desc = hal_srng_src_get_next(soc->hal_soc, hal_srng);
|
||||
if (!ent_ring_desc) {
|
||||
QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
|
||||
|
@@ -1244,7 +1244,8 @@ dp_rx_err_process(struct dp_intr *int_ctx, struct dp_soc *soc,
|
||||
|
||||
if (qdf_unlikely((msdu_list.rbm[0] != DP_WBM2SW_RBM) &&
|
||||
(msdu_list.rbm[0] !=
|
||||
HAL_RX_BUF_RBM_WBM_IDLE_DESC_LIST))) {
|
||||
HAL_RX_BUF_RBM_WBM_IDLE_DESC_LIST) &&
|
||||
(msdu_list.rbm[0] != DP_DEFRAG_RBM))) {
|
||||
/* TODO */
|
||||
/* Call appropriate handler */
|
||||
if (!wlan_cfg_get_dp_soc_nss_cfg(soc->wlan_cfg_ctx)) {
|
||||
|
Reference in New Issue
Block a user