From 5104601ba745fe4f26c60430659ab700f181121f Mon Sep 17 00:00:00 2001 From: jinweic chen Date: Wed, 11 Apr 2018 16:02:22 +0800 Subject: [PATCH] qcacld-3.0: fix non-linear data TX dma failed issue Currently non-linear, non-tso TX data is not handled correctly, only the non-tso, single linear data is supported. the frag paged data in skb is missed while packet length for HW access is entire packet length, HW DMA failed. temporarily to linearize skb so that non-linear data could be TX correctly. Change-Id: Ic0f2b7a0b021ca190c870551a66181f50ae72c65 CRs-Fixed: 2180318 --- core/hdd/inc/wlan_hdd_tx_rx.h | 19 +++++++++++++++++++ core/hdd/src/wlan_hdd_softap_tx_rx.c | 10 ++++++++++ core/hdd/src/wlan_hdd_tx_rx.c | 10 ++++++++++ 3 files changed, 39 insertions(+) diff --git a/core/hdd/inc/wlan_hdd_tx_rx.h b/core/hdd/inc/wlan_hdd_tx_rx.h index d69ec9450dec..9b5519a3ac03 100644 --- a/core/hdd/inc/wlan_hdd_tx_rx.h +++ b/core/hdd/inc/wlan_hdd_tx_rx.h @@ -224,4 +224,23 @@ hdd_skb_fill_gso_size(struct net_device *dev, struct sk_buff *skb) * Return: tx acked count */ uint32_t hdd_txrx_get_tx_ack_count(struct hdd_adapter *adapter); + +#ifdef CONFIG_HL_SUPPORT +static inline QDF_STATUS +hdd_skb_nontso_linearize(struct sk_buff *skb) +{ + return QDF_STATUS_SUCCESS; +} +#else +static inline QDF_STATUS +hdd_skb_nontso_linearize(struct sk_buff *skb) +{ + if (qdf_nbuf_is_nonlinear(skb) && qdf_nbuf_is_tso(skb) == false) { + if (qdf_unlikely(skb_linearize(skb))) + return QDF_STATUS_E_NOMEM; + } + return QDF_STATUS_SUCCESS; +} +#endif + #endif /* end #if !defined(WLAN_HDD_TX_RX_H) */ diff --git a/core/hdd/src/wlan_hdd_softap_tx_rx.c b/core/hdd/src/wlan_hdd_softap_tx_rx.c index 2496df84b67a..8d13e4f37226 100644 --- a/core/hdd/src/wlan_hdd_softap_tx_rx.c +++ b/core/hdd/src/wlan_hdd_softap_tx_rx.c @@ -597,6 +597,16 @@ static netdev_tx_t __hdd_softap_hard_start_xmit(struct sk_buff *skb, (uint8_t *)&skb->data[QDF_DP_TRACE_RECORD_SIZE], (qdf_nbuf_len(skb)-QDF_DP_TRACE_RECORD_SIZE), QDF_TX)); + /* check whether need to linearize skb, like non-linear udp data */ + if (hdd_skb_nontso_linearize(skb) != QDF_STATUS_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, + QDF_TRACE_LEVEL_INFO_HIGH, + "%s: skb %pK linearize failed. drop the pkt", + __func__, skb); + ++adapter->hdd_stats.tx_rx_stats.tx_dropped_ac[ac]; + goto drop_pkt_and_release_skb; + } + if (adapter->tx_fn(adapter->txrx_vdev, (qdf_nbuf_t) skb) != NULL) { QDF_TRACE(QDF_MODULE_ID_HDD_SAP_DATA, QDF_TRACE_LEVEL_INFO_HIGH, diff --git a/core/hdd/src/wlan_hdd_tx_rx.c b/core/hdd/src/wlan_hdd_tx_rx.c index 7ce4610c965f..9cb443980da0 100644 --- a/core/hdd/src/wlan_hdd_tx_rx.c +++ b/core/hdd/src/wlan_hdd_tx_rx.c @@ -1092,6 +1092,16 @@ static netdev_tx_t __hdd_hard_start_xmit(struct sk_buff *skb, goto drop_pkt_and_release_skb; } + /* check whether need to linearize skb, like non-linear udp data */ + if (hdd_skb_nontso_linearize(skb) != QDF_STATUS_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, + QDF_TRACE_LEVEL_INFO_HIGH, + "%s: skb %pK linearize failed. drop the pkt", + __func__, skb); + ++adapter->hdd_stats.tx_rx_stats.tx_dropped_ac[ac]; + goto drop_pkt_and_release_skb; + } + /* * If a transmit function is not registered, drop packet */