summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlok Kumar <alokkuma@codeaurora.org>2018-06-03 02:25:41 +0530
committernshrivas <nshrivas@codeaurora.org>2018-06-06 07:35:50 -0700
commitaa08e3143dc3ecd0fb26e65104da188ea361cbc9 (patch)
tree7cda38689e5eb7f733d111b00e6753dc0b255bce
parent43981a16968ac615bbd6677f75f08e5f216eab03 (diff)
qcacld-3.0: Add Tx compl callback to check if OTA is needed for TX desc
During hard_start_xmit, a flag in TX desc is marked as true or false based on, if OTA is needed during TX completion. Based on this flag, a callback gets called on TX completion before freeing this descriptor. Change-Id: I4e11b2c35b4747c7af35a387b404e3ccb1e8e8e4 CRs-Fixed: 2253557
-rw-r--r--core/dp/ol/inc/ol_txrx_osif_api.h6
-rw-r--r--core/dp/txrx/ol_rx_fwd.c4
-rw-r--r--core/dp/txrx/ol_tx.c47
-rw-r--r--core/dp/txrx/ol_tx.h9
-rw-r--r--core/dp/txrx/ol_tx_desc.c1
-rw-r--r--core/dp/txrx/ol_tx_send.c38
-rw-r--r--core/dp/txrx/ol_txrx.c1
-rw-r--r--core/dp/txrx/ol_txrx_types.h4
-rw-r--r--core/hdd/inc/wlan_hdd_softap_tx_rx.h16
-rw-r--r--core/hdd/src/wlan_hdd_softap_tx_rx.c89
-rw-r--r--core/hdd/src/wlan_hdd_tx_rx.c2
11 files changed, 180 insertions, 37 deletions
diff --git a/core/dp/ol/inc/ol_txrx_osif_api.h b/core/dp/ol/inc/ol_txrx_osif_api.h
index fff4da3d1bda..eea3d384d437 100644
--- a/core/dp/ol/inc/ol_txrx_osif_api.h
+++ b/core/dp/ol/inc/ol_txrx_osif_api.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2014-2017 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012, 2014-2018 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -69,7 +69,9 @@ qdf_nbuf_t ol_txrx_osif_tso_segment(ol_txrx_vdev_handle txrx_vdev,
int max_seg_payload_bytes,
qdf_nbuf_t jumbo_tcp_frame);
-qdf_nbuf_t ol_tx_data(ol_txrx_vdev_handle data_vdev, qdf_nbuf_t skb);
+qdf_nbuf_t ol_tx_data(ol_txrx_vdev_handle data_vdev,
+ qdf_nbuf_t skb,
+ bool notify_tx_comp);
void ol_rx_data_process(struct ol_txrx_peer_t *peer,
qdf_nbuf_t rx_buf_list);
diff --git a/core/dp/txrx/ol_rx_fwd.c b/core/dp/txrx/ol_rx_fwd.c
index f33db7424a81..ebc15b7206d9 100644
--- a/core/dp/txrx/ol_rx_fwd.c
+++ b/core/dp/txrx/ol_rx_fwd.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2014-2017 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011, 2014-2018 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -124,7 +124,7 @@ static inline void ol_rx_fwd_to_tx(struct ol_txrx_vdev_t *vdev, qdf_nbuf_t msdu)
qdf_mem_set(msdu->cb, sizeof(msdu->cb), 0);
/* update any cb field expected by OL_TX_SEND */
- msdu = OL_TX_SEND(vdev, msdu);
+ msdu = OL_TX_SEND(vdev, msdu, 0);
if (msdu) {
/*
diff --git a/core/dp/txrx/ol_tx.c b/core/dp/txrx/ol_tx.c
index e08ebab8e82b..201498853abf 100644
--- a/core/dp/txrx/ol_tx.c
+++ b/core/dp/txrx/ol_tx.c
@@ -239,10 +239,12 @@ static inline uint8_t ol_tx_prepare_tso(ol_txrx_vdev_handle vdev,
* ol_tx_data() - send data frame
* @vdev: virtual device handle
* @skb: skb
+ * @notify_tx_comp: whether OTA to be notified
*
* Return: skb/NULL for success
*/
-qdf_nbuf_t ol_tx_data(ol_txrx_vdev_handle vdev, qdf_nbuf_t skb)
+qdf_nbuf_t ol_tx_data(ol_txrx_vdev_handle vdev, qdf_nbuf_t skb,
+ bool notify_tx_comp)
{
struct ol_txrx_pdev_t *pdev;
qdf_nbuf_t ret;
@@ -268,7 +270,7 @@ qdf_nbuf_t ol_tx_data(ol_txrx_vdev_handle vdev, qdf_nbuf_t skb)
/* Terminate the (single-element) list of tx frames */
qdf_nbuf_set_next(skb, NULL);
- ret = OL_TX_SEND(vdev, skb);
+ ret = OL_TX_SEND(vdev, skb, notify_tx_comp);
if (ret) {
ol_txrx_dbg("%s: Failed to tx", __func__);
return ret;
@@ -312,7 +314,7 @@ qdf_nbuf_t ol_tx_send_ipa_data_frame(void *vdev,
*/
qdf_net_buf_debug_acquire_skb(skb, __FILE__, __LINE__);
- ret = OL_TX_SEND((struct ol_txrx_vdev_t *)vdev, skb);
+ ret = OL_TX_SEND((struct ol_txrx_vdev_t *)vdev, skb, 0);
if (ret) {
ol_txrx_dbg("%s: Failed to tx", __func__);
return ret;
@@ -375,7 +377,8 @@ static uint32_t ol_tx_tso_get_stats_idx(struct ol_txrx_pdev_t *pdev)
#endif
#if defined(FEATURE_TSO)
-qdf_nbuf_t ol_tx_ll(ol_txrx_vdev_handle vdev, qdf_nbuf_t msdu_list)
+qdf_nbuf_t ol_tx_ll(ol_txrx_vdev_handle vdev, qdf_nbuf_t msdu_list,
+ bool notify_tx_comp)
{
qdf_nbuf_t msdu = msdu_list;
struct ol_txrx_msdu_info_t msdu_info;
@@ -473,7 +476,8 @@ qdf_nbuf_t ol_tx_ll(ol_txrx_vdev_handle vdev, qdf_nbuf_t msdu_list)
}
#else /* TSO */
-qdf_nbuf_t ol_tx_ll(ol_txrx_vdev_handle vdev, qdf_nbuf_t msdu_list)
+qdf_nbuf_t ol_tx_ll(ol_txrx_vdev_handle vdev, qdf_nbuf_t msdu_list,
+ bool notify_tx_comp)
{
qdf_nbuf_t msdu = msdu_list;
struct ol_txrx_msdu_info_t msdu_info;
@@ -709,7 +713,8 @@ ol_tx_prepare_ll_fast(struct ol_txrx_pdev_t *pdev,
* Return: on success return NULL, pointer to nbuf when it fails to send.
*/
qdf_nbuf_t
-ol_tx_ll_fast(ol_txrx_vdev_handle vdev, qdf_nbuf_t msdu_list)
+ol_tx_ll_fast(ol_txrx_vdev_handle vdev, qdf_nbuf_t msdu_list,
+ bool notify_tx_comp)
{
qdf_nbuf_t msdu = msdu_list;
struct ol_txrx_pdev_t *pdev = vdev->pdev;
@@ -823,6 +828,10 @@ ol_tx_ll_fast(ol_txrx_vdev_handle vdev, qdf_nbuf_t msdu_list)
htt_tx_desc_display(tx_desc->htt_tx_desc);
+ if (!msdu_info.tso_info.is_tso)
+ tx_desc->notify_tx_comp =
+ notify_tx_comp;
+
/* mark the relevant tso_seg free-able */
if (msdu_info.tso_info.curr_seg) {
msdu_info.tso_info.curr_seg->
@@ -890,7 +899,8 @@ ol_tx_ll_fast(ol_txrx_vdev_handle vdev, qdf_nbuf_t msdu_list)
}
#else
qdf_nbuf_t
-ol_tx_ll_fast(ol_txrx_vdev_handle vdev, qdf_nbuf_t msdu_list)
+ol_tx_ll_fast(ol_txrx_vdev_handle vdev, qdf_nbuf_t msdu_list,
+ bool notify_tx_comp)
{
qdf_nbuf_t msdu = msdu_list;
struct ol_txrx_pdev_t *pdev = vdev->pdev;
@@ -955,6 +965,8 @@ ol_tx_ll_fast(ol_txrx_vdev_handle vdev, qdf_nbuf_t msdu_list)
pkt_download_len +=
sizeof(struct htt_tx_msdu_desc_ext_t);
+ tx_desc->notify_tx_comp = notify_tx_comp;
+
htt_tx_desc_display(tx_desc->htt_tx_desc);
/*
* The netbuf may get linked into a different list
@@ -991,23 +1003,25 @@ ol_tx_ll_fast(ol_txrx_vdev_handle vdev, qdf_nbuf_t msdu_list)
*
*/
qdf_nbuf_t
-ol_tx_ll_wrapper(ol_txrx_vdev_handle vdev, qdf_nbuf_t msdu_list)
+ol_tx_ll_wrapper(ol_txrx_vdev_handle vdev, qdf_nbuf_t msdu_list,
+ bool notify_tx_comp)
{
struct hif_opaque_softc *hif_device =
(struct hif_opaque_softc *)cds_get_context(QDF_MODULE_ID_HIF);
if (qdf_likely(hif_device && hif_is_fastpath_mode_enabled(hif_device)))
- msdu_list = ol_tx_ll_fast(vdev, msdu_list);
+ msdu_list = ol_tx_ll_fast(vdev, msdu_list, notify_tx_comp);
else
- msdu_list = ol_tx_ll(vdev, msdu_list);
+ msdu_list = ol_tx_ll(vdev, msdu_list, notify_tx_comp);
return msdu_list;
}
#else
qdf_nbuf_t
-ol_tx_ll_wrapper(ol_txrx_vdev_handle vdev, qdf_nbuf_t msdu_list)
+ol_tx_ll_wrapper(ol_txrx_vdev_handle vdev, qdf_nbuf_t msdu_list,
+ bool notify_tx_comp)
{
- return ol_tx_ll(vdev, msdu_list);
+ return ol_tx_ll(vdev, msdu_list, notify_tx_comp);
}
#endif /* WLAN_FEATURE_FASTPATH */
@@ -1057,7 +1071,7 @@ static void ol_tx_vdev_ll_pause_queue_send_base(struct ol_txrx_vdev_t *vdev)
qdf_nbuf_set_next(tx_msdu, NULL);
QDF_NBUF_UPDATE_TX_PKT_COUNT(tx_msdu,
QDF_NBUF_TX_PKT_TXRX_DEQUEUE);
- tx_msdu = ol_tx_ll_wrapper(vdev, tx_msdu);
+ tx_msdu = ol_tx_ll_wrapper(vdev, tx_msdu, 0);
/*
* It is unexpected that ol_tx_ll would reject the frame
* since we checked that there's room for it, though
@@ -1153,7 +1167,8 @@ qdf_nbuf_t ol_tx_ll_queue(ol_txrx_vdev_handle vdev, qdf_nbuf_t msdu_list)
(((struct ethernet_hdr_t *)
qdf_nbuf_data(msdu_list))->ethertype[1]);
if (ETHERTYPE_IS_EAPOL_WAPI(eth_type)) {
- msdu_list = ol_tx_ll_wrapper(vdev, msdu_list);
+ msdu_list =
+ ol_tx_ll_wrapper(vdev, msdu_list, 0);
return msdu_list;
}
}
@@ -1187,7 +1202,7 @@ qdf_nbuf_t ol_tx_ll_queue(ol_txrx_vdev_handle vdev, qdf_nbuf_t msdu_list)
* not paused, no throttle and no backlog -
* send the new frames
*/
- msdu_list = ol_tx_ll_wrapper(vdev, msdu_list);
+ msdu_list = ol_tx_ll_wrapper(vdev, msdu_list, 0);
}
}
return msdu_list;
@@ -1251,7 +1266,7 @@ void ol_tx_pdev_ll_pause_queue_send_all(struct ol_txrx_pdev_t *pdev)
vdev->ll_pause.txq.tail = NULL;
qdf_nbuf_set_next(tx_msdu, NULL);
- tx_msdu = ol_tx_ll_wrapper(vdev, tx_msdu);
+ tx_msdu = ol_tx_ll_wrapper(vdev, tx_msdu, 0);
/*
* It is unexpected that ol_tx_ll would reject
* the frame, since we checked that there's
diff --git a/core/dp/txrx/ol_tx.h b/core/dp/txrx/ol_tx.h
index 7eb71ea38eb2..35d56bb6dcb5 100644
--- a/core/dp/txrx/ol_tx.h
+++ b/core/dp/txrx/ol_tx.h
@@ -30,10 +30,13 @@
#include <ol_txrx_types.h> /* ol_tx_desc_t, ol_txrx_msdu_info_t */
-qdf_nbuf_t ol_tx_ll(ol_txrx_vdev_handle vdev, qdf_nbuf_t msdu_list);
-qdf_nbuf_t ol_tx_ll_wrapper(ol_txrx_vdev_handle vdev, qdf_nbuf_t msdu_list);
+qdf_nbuf_t ol_tx_ll(ol_txrx_vdev_handle vdev, qdf_nbuf_t msdu_list,
+ bool notify_tx_comp);
+qdf_nbuf_t ol_tx_ll_wrapper(ol_txrx_vdev_handle vdev, qdf_nbuf_t msdu_list,
+ bool notify_tx_comp);
#ifdef WLAN_FEATURE_FASTPATH
-qdf_nbuf_t ol_tx_ll_fast(ol_txrx_vdev_handle vdev, qdf_nbuf_t msdu_list);
+qdf_nbuf_t ol_tx_ll_fast(ol_txrx_vdev_handle vdev, qdf_nbuf_t msdu_list,
+ bool notify_tx_comp);
#endif
qdf_nbuf_t ol_tx_ll_queue(ol_txrx_vdev_handle vdev, qdf_nbuf_t msdu_list);
diff --git a/core/dp/txrx/ol_tx_desc.c b/core/dp/txrx/ol_tx_desc.c
index e8e150536ff0..0232296e745d 100644
--- a/core/dp/txrx/ol_tx_desc.c
+++ b/core/dp/txrx/ol_tx_desc.c
@@ -415,6 +415,7 @@ static void ol_tx_desc_free_common(struct ol_txrx_pdev_t *pdev,
/* clear the ref cnt */
qdf_atomic_init(&tx_desc->ref_cnt);
tx_desc->vdev_id = OL_TXRX_INVALID_VDEV_ID;
+ tx_desc->notify_tx_comp = 0;
}
#ifndef QCA_LL_TX_FLOW_CONTROL_V2
diff --git a/core/dp/txrx/ol_tx_send.c b/core/dp/txrx/ol_tx_send.c
index 9fcf10c9d9f0..71fcda87da90 100644
--- a/core/dp/txrx/ol_tx_send.c
+++ b/core/dp/txrx/ol_tx_send.c
@@ -575,6 +575,41 @@ void ol_tx_flow_pool_unlock(struct ol_tx_desc_t *tx_desc)
#endif
/**
+ * ol_tx_notify_completion() - Notify tx completion for this desc
+ * @tx_desc: tx desc
+ * @netbuf: buffer
+ *
+ * Return: none
+ */
+static void ol_tx_notify_completion(struct ol_tx_desc_t *tx_desc,
+ qdf_nbuf_t netbuf)
+{
+ void *osif_dev;
+ ol_txrx_completion_fp tx_compl_cbk = NULL;
+
+ qdf_assert(tx_desc);
+
+ ol_tx_flow_pool_lock(tx_desc);
+ /*
+ * In cases when vdev has gone down and tx completion
+ * are received, leads to NULL vdev access.
+ * So, check for NULL before dereferencing it.
+ */
+ if (!tx_desc->vdev ||
+ !tx_desc->vdev->osif_dev ||
+ !tx_desc->vdev->tx_comp ||
+ !tx_desc->notify_tx_comp) {
+ ol_tx_flow_pool_unlock(tx_desc);
+ return;
+ }
+ osif_dev = tx_desc->vdev->osif_dev;
+ tx_compl_cbk = tx_desc->vdev->tx_comp;
+ ol_tx_flow_pool_unlock(tx_desc);
+
+ tx_compl_cbk(netbuf, osif_dev);
+}
+
+/**
* ol_tx_update_connectivity_stats() - update connectivity stats
* @tx_desc: tx desc
* @netbuf: buffer
@@ -772,6 +807,9 @@ ol_tx_completion_handler(ol_txrx_pdev_handle pdev,
ol_tx_update_arp_stats(tx_desc, netbuf, status);
}
+ /* check tx completion notification */
+ ol_tx_notify_completion(tx_desc, netbuf);
+
/* track connectivity stats */
ol_tx_update_connectivity_stats(tx_desc, netbuf,
status);
diff --git a/core/dp/txrx/ol_txrx.c b/core/dp/txrx/ol_txrx.c
index 419fa98f16b7..049f548598c8 100644
--- a/core/dp/txrx/ol_txrx.c
+++ b/core/dp/txrx/ol_txrx.c
@@ -2469,6 +2469,7 @@ void ol_txrx_vdev_register(ol_txrx_vdev_handle vdev,
vdev->osif_dev = osif_vdev;
vdev->rx = txrx_ops->rx.rx;
vdev->stats_rx = txrx_ops->rx.stats_rx;
+ vdev->tx_comp = txrx_ops->tx.tx_comp;
txrx_ops->tx.tx = ol_tx_data;
}
diff --git a/core/dp/txrx/ol_txrx_types.h b/core/dp/txrx/ol_txrx_types.h
index 2d595b20b343..ea28aa3ba3da 100644
--- a/core/dp/txrx/ol_txrx_types.h
+++ b/core/dp/txrx/ol_txrx_types.h
@@ -203,6 +203,7 @@ struct ol_tx_desc_t {
#endif
void *tso_desc;
void *tso_num_desc;
+ bool notify_tx_comp;
};
typedef TAILQ_HEAD(some_struct_name, ol_tx_desc_t) ol_tx_desc_list;
@@ -1058,6 +1059,9 @@ struct ol_txrx_vdev_t {
ol_txrx_rx_fp rx; /* receive function used by this vdev */
ol_txrx_stats_rx_fp stats_rx; /* receive function used by this vdev */
+ /* completion function used by this vdev*/
+ ol_txrx_completion_fp tx_comp;
+
struct {
/*
* If the vdev object couldn't be deleted immediately because
diff --git a/core/hdd/inc/wlan_hdd_softap_tx_rx.h b/core/hdd/inc/wlan_hdd_softap_tx_rx.h
index 66a8e323d11e..7ea467131d3d 100644
--- a/core/hdd/inc/wlan_hdd_softap_tx_rx.h
+++ b/core/hdd/inc/wlan_hdd_softap_tx_rx.h
@@ -38,7 +38,7 @@ QDF_STATUS hdd_softap_init_tx_rx_sta(hdd_adapter_t *pAdapter,
struct qdf_mac_addr *pmacAddrSTA);
QDF_STATUS hdd_softap_deinit_tx_rx_sta(hdd_adapter_t *pAdapter,
uint8_t STAId);
-
+void hdd_softap_notify_tx_compl_cbk(struct sk_buff *skb, void *context);
QDF_STATUS hdd_softap_rx_packet_cbk(void *context, qdf_nbuf_t rxBufChain);
#ifdef IPA_OFFLOAD
QDF_STATUS hdd_softap_rx_mul_packet_cbk(void *cds_context,
@@ -92,15 +92,25 @@ QDF_STATUS hdd_post_dhcp_ind(hdd_adapter_t *adapter,
uint8_t sta_id, uint16_t type);
/**
+ * hdd_softap_notify_dhcp_ind() - Notify SAP for DHCP indication for tx desc
+ * @context: pointer to HDD context
+ * @netbuf: pointer to OS packet (sk_buff)
+ *
+ * Return: None
+ */
+void hdd_softap_notify_dhcp_ind(void *context,
+ struct sk_buff *netbuf);
+
+/**
* hdd_dhcp_indication() - Send DHCP START/STOP indication to FW
* @adapter: pointer to hdd adapter
* @sta_id: peer station ID
* @skb: pointer to OS packet (sk_buff)
* @dir: direction
*
- * Return: None
+ * Return: true if tx comp is to be notified for skb
*/
-void hdd_dhcp_indication(hdd_adapter_t *adapter,
+bool hdd_dhcp_indication(hdd_adapter_t *adapter,
uint8_t sta_id,
struct sk_buff *skb,
enum qdf_proto_dir dir);
diff --git a/core/hdd/src/wlan_hdd_softap_tx_rx.c b/core/hdd/src/wlan_hdd_softap_tx_rx.c
index 69cfb7d565b5..0eef1a708cad 100644
--- a/core/hdd/src/wlan_hdd_softap_tx_rx.c
+++ b/core/hdd/src/wlan_hdd_softap_tx_rx.c
@@ -285,6 +285,47 @@ QDF_STATUS hdd_post_dhcp_ind(hdd_adapter_t *adapter,
return status;
}
+void hdd_softap_notify_dhcp_ind(void *context, struct sk_buff *netbuf)
+{
+ hdd_ap_ctx_t *hdd_ap_ctx;
+ struct qdf_mac_addr *dest_mac_addr;
+ uint8_t sta_id;
+
+ hdd_adapter_t *adapter = context;
+
+ if (!adapter) {
+ hdd_err("NULL adapter");
+ return;
+ }
+
+ hdd_ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter);
+ if (!hdd_ap_ctx) {
+ hdd_err("HDD sap context is NULL");
+ return;
+ }
+
+ dest_mac_addr = (struct qdf_mac_addr *)netbuf->data;
+
+ if (QDF_NBUF_CB_GET_IS_BCAST(netbuf) ||
+ QDF_NBUF_CB_GET_IS_MCAST(netbuf)) {
+ /* The BC/MC station ID is assigned during BSS
+ * starting phase. SAP will return the station ID
+ * used for BC/MC traffic.
+ */
+ sta_id = hdd_ap_ctx->uBCStaId;
+ } else {
+ if (QDF_STATUS_SUCCESS !=
+ hdd_softap_get_sta_id(adapter,
+ dest_mac_addr, &sta_id)) {
+ QDF_TRACE(QDF_MODULE_ID_HDD_SAP_DATA,
+ QDF_TRACE_LEVEL_INFO_HIGH,
+ "%s: Failed to find right station", __func__);
+ return;
+ }
+ }
+ hdd_post_dhcp_ind(adapter, sta_id, WMA_DHCP_STOP_IND);
+}
+
/**
* hdd_dhcp_indication() - Send DHCP START/STOP indication to FW
* @adapter: pointer to hdd adapter
@@ -292,19 +333,22 @@ QDF_STATUS hdd_post_dhcp_ind(hdd_adapter_t *adapter,
* @skb: pointer to OS packet (sk_buff)
* @dir: direction
*
- * Return: None
+ * Return: true if tx completion to be notified for skb
*/
-void hdd_dhcp_indication(hdd_adapter_t *adapter,
- uint8_t sta_id,
- struct sk_buff *skb,
- enum qdf_proto_dir dir)
+bool hdd_dhcp_indication(hdd_adapter_t *adapter,
+ uint8_t sta_id,
+ struct sk_buff *skb,
+ enum qdf_proto_dir dir)
{
enum qdf_proto_subtype subtype = QDF_PROTO_INVALID;
hdd_station_info_t *hdd_sta_info;
+ bool notify_tx_comp = false;
+
hdd_debug("adapter=%p, sta_id=%d, dir=%d", adapter, sta_id, dir);
- if ((adapter->device_mode == QDF_SAP_MODE) &&
+ if (((adapter->device_mode == QDF_SAP_MODE) ||
+ (adapter->device_mode == QDF_P2P_GO_MODE)) &&
((dir == QDF_TX && QDF_NBUF_CB_PACKET_TYPE_DHCP ==
QDF_NBUF_CB_GET_PACKET_TYPE(skb)) ||
(dir == QDF_RX && qdf_nbuf_is_ipv4_dhcp_pkt(skb) == true))) {
@@ -346,8 +390,7 @@ void hdd_dhcp_indication(hdd_adapter_t *adapter,
hdd_sta_info->dhcp_phase = DHCP_PHASE_ACK;
if ((hdd_sta_info->dhcp_nego_status ==
DHCP_NEGO_IN_PROGRESS))
- hdd_post_dhcp_ind(adapter, sta_id,
- WMA_DHCP_STOP_IND);
+ notify_tx_comp = true;
hdd_sta_info->dhcp_nego_status = DHCP_NEGO_STOP;
break;
default:
@@ -358,6 +401,7 @@ void hdd_dhcp_indication(hdd_adapter_t *adapter,
hdd_sta_info->dhcp_phase,
hdd_sta_info->dhcp_nego_status);
}
+ return notify_tx_comp;
}
/**
@@ -382,6 +426,7 @@ static netdev_tx_t __hdd_softap_hard_start_xmit(struct sk_buff *skb,
struct qdf_mac_addr *pDestMacAddress;
uint8_t STAId;
uint32_t num_seg;
+ bool notify_tx_comp = false;
++pAdapter->hdd_stats.hddTxRxStats.txXmitCalled;
pAdapter->hdd_stats.hddTxRxStats.cont_txtimeout_cnt = 0;
@@ -523,7 +568,8 @@ static netdev_tx_t __hdd_softap_hard_start_xmit(struct sk_buff *skb,
pAdapter->aStaInfo[STAId].last_tx_rx_ts = qdf_system_ticks();
if (STAId != pHddApCtx->uBCStaId)
- hdd_dhcp_indication(pAdapter, STAId, skb, QDF_TX);
+ notify_tx_comp = hdd_dhcp_indication(pAdapter,
+ STAId, skb, QDF_TX);
hdd_event_eapol_log(skb, QDF_TX);
QDF_NBUF_CB_TX_PACKET_TRACK(skb) = QDF_NBUF_TX_PKT_DATA_TRACK;
@@ -544,7 +590,7 @@ static netdev_tx_t __hdd_softap_hard_start_xmit(struct sk_buff *skb,
}
if (pAdapter->tx_fn(ol_txrx_get_vdev_by_sta_id(STAId),
- (qdf_nbuf_t) skb) != NULL) {
+ (qdf_nbuf_t)skb, notify_tx_comp) != NULL) {
QDF_TRACE(QDF_MODULE_ID_HDD_SAP_DATA, QDF_TRACE_LEVEL_INFO_HIGH,
"%s: Failed to send packet to txrx for staid:%d",
__func__, STAId);
@@ -768,6 +814,28 @@ QDF_STATUS hdd_softap_deinit_tx_rx_sta(hdd_adapter_t *pAdapter, uint8_t STAId)
}
/**
+ * hdd_softap_notify_tx_compl_cbk() - callback to notify tx completion
+ * @skb: pointer to skb data
+ * @adapter: pointer to vdev apdapter
+ *
+ * Return: None
+ */
+void hdd_softap_notify_tx_compl_cbk(struct sk_buff *skb,
+ void *context)
+{
+ int errno;
+ hdd_adapter_t *adapter = NULL;
+
+ adapter = (hdd_adapter_t *)context;
+ errno = hdd_validate_adapter(adapter);
+ if (errno)
+ return;
+
+ if (QDF_NBUF_CB_PACKET_TYPE_DHCP == QDF_NBUF_CB_GET_PACKET_TYPE(skb))
+ hdd_softap_notify_dhcp_ind(context, skb);
+}
+
+/**
* hdd_softap_rx_packet_cbk() - Receive packet handler
* @context: pointer to HDD context
* @rxBuf: pointer to rx qdf_nbuf
@@ -987,6 +1055,7 @@ QDF_STATUS hdd_softap_register_sta(hdd_adapter_t *pAdapter,
/* Register the vdev transmit and receive functions */
qdf_mem_zero(&txrx_ops, sizeof(txrx_ops));
txrx_ops.rx.rx = hdd_softap_rx_packet_cbk;
+ txrx_ops.tx.tx_comp = hdd_softap_notify_tx_compl_cbk;
ol_txrx_vdev_register(
ol_txrx_get_vdev_from_vdev_id(pAdapter->sessionId),
pAdapter, &txrx_ops);
diff --git a/core/hdd/src/wlan_hdd_tx_rx.c b/core/hdd/src/wlan_hdd_tx_rx.c
index b07a7aaec412..89c5ac95997e 100644
--- a/core/hdd/src/wlan_hdd_tx_rx.c
+++ b/core/hdd/src/wlan_hdd_tx_rx.c
@@ -1071,7 +1071,7 @@ static netdev_tx_t __hdd_hard_start_xmit(struct sk_buff *skb,
}
if (pAdapter->tx_fn(ol_txrx_get_vdev_by_sta_id(STAId),
- (qdf_nbuf_t) skb) != NULL) {
+ (qdf_nbuf_t)skb, 0) != NULL) {
QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_INFO_HIGH,
"%s: Failed to send packet to txrx for staid: %d",
__func__, STAId);