diff --git a/dp/inc/cdp_txrx_cmn_struct.h b/dp/inc/cdp_txrx_cmn_struct.h index 358dbd0fce..eac535290e 100644 --- a/dp/inc/cdp_txrx_cmn_struct.h +++ b/dp/inc/cdp_txrx_cmn_struct.h @@ -295,7 +295,7 @@ typedef void (*ol_txrx_mgmt_tx_cb)(void *ctxt, qdf_nbuf_t tx_mgmt_frm, int had_error); /** - * ol_rxrx_data_tx_cb - Function registered with the data path + * ol_txrx_data_tx_cb - Function registered with the data path * that is called when tx frames marked as "no free" are * done being transmitted */ diff --git a/dp/wifi3.0/dp_main.c b/dp/wifi3.0/dp_main.c index f0e5086b3e..14e5396804 100644 --- a/dp/wifi3.0/dp_main.c +++ b/dp/wifi3.0/dp_main.c @@ -5119,6 +5119,23 @@ static inline void dp_peer_delete_ast_entries(struct dp_soc *soc, } #endif +/* + * dp_txrx_data_tx_cb_set(): set the callback for non standard tx + * @vdev_handle - datapath vdev handle + * @callback - callback function + * @ctxt: callback context + * + */ +static void +dp_txrx_data_tx_cb_set(struct cdp_vdev *vdev_handle, + ol_txrx_data_tx_cb callback, void *ctxt) +{ + struct dp_vdev *vdev = (struct dp_vdev *)vdev_handle; + + vdev->tx_non_std_data_callback.func = callback; + vdev->tx_non_std_data_callback.ctxt = ctxt; +} + #ifdef CONFIG_WIN static void dp_peer_teardown_wifi3(struct cdp_vdev *vdev_hdl, void *peer_hdl) { @@ -5170,6 +5187,7 @@ static struct cdp_cmn_ops dp_ops_cmn = { .txrx_intr_detach = dp_soc_interrupt_detach, .set_pn_check = dp_set_pn_check_wifi3, /* TODO: Add other functions */ + .txrx_data_tx_cb_set = dp_txrx_data_tx_cb_set }; static struct cdp_ctrl_ops dp_ops_ctrl = { @@ -5309,6 +5327,7 @@ static QDF_STATUS dp_bus_resume(struct cdp_pdev *opaque_pdev) #ifndef CONFIG_WIN static struct cdp_misc_ops dp_ops_misc = { + .tx_non_std = dp_tx_non_std, .get_opmode = dp_get_opmode, #ifdef FEATURE_RUNTIME_PM .runtime_suspend = dp_runtime_suspend, diff --git a/dp/wifi3.0/dp_tx.c b/dp/wifi3.0/dp_tx.c index 04d8ff4047..e7111cc056 100644 --- a/dp/wifi3.0/dp_tx.c +++ b/dp/wifi3.0/dp_tx.c @@ -986,6 +986,46 @@ static void dp_tx_classify_tid(struct dp_vdev *vdev, qdf_nbuf_t nbuf, return; } +#ifdef CONVERGED_TDLS_ENABLE +/** + * dp_tx_update_tdls_flags() - Update descriptor flags for TDLS frame + * @tx_desc: TX descriptor + * + * Return: None + */ +static void dp_tx_update_tdls_flags(struct dp_tx_desc_s *tx_desc) +{ + if (tx_desc->vdev) { + if (tx_desc->vdev->is_tdls_frame) + tx_desc->flags |= DP_TX_DESC_FLAG_TDLS_FRAME; + tx_desc->vdev->is_tdls_frame = false; + } +} + +/** + * dp_non_std_tx_comp_free_buff() - Free the non std tx packet buffer + * @tx_desc: TX descriptor + * @vdev: datapath vdev handle + * + * Return: None + */ +static void dp_non_std_tx_comp_free_buff(struct dp_tx_desc_s *tx_desc, + struct dp_vdev *vdev) +{ + struct hal_tx_completion_status ts = {0}; + qdf_nbuf_t nbuf = tx_desc->nbuf; + + hal_tx_comp_get_status(&tx_desc->comp, &ts); + if (vdev->tx_non_std_data_callback.func) { + qdf_nbuf_set_next(tx_desc->nbuf, NULL); + vdev->tx_non_std_data_callback.func( + vdev->tx_non_std_data_callback.ctxt, + nbuf, ts.status); + return; + } +} +#endif + /** * dp_tx_send_msdu_single() - Setup descriptor and enqueue single MSDU to TCL * @vdev: DP vdev handle @@ -1018,6 +1058,8 @@ static qdf_nbuf_t dp_tx_send_msdu_single(struct dp_vdev *vdev, qdf_nbuf_t nbuf, return nbuf; } + dp_tx_update_tdls_flags(tx_desc); + if (qdf_unlikely(hal_srng_access_start(soc->hal_soc, hal_srng))) { QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, "%s %d : HAL RING Access Failed -- %pK\n", @@ -1702,6 +1744,10 @@ static inline void dp_tx_comp_free_buf(struct dp_soc *soc, struct dp_vdev *vdev = desc->vdev; qdf_nbuf_t nbuf = desc->nbuf; + /* If it is TDLS mgmt, don't unmap or free the frame */ + if (desc->flags & DP_TX_DESC_FLAG_TDLS_FRAME) + return dp_non_std_tx_comp_free_buff(desc, vdev); + /* 0 : MSDU buffer, 1 : MLE */ if (desc->msdu_ext_desc) { /* TSO free */ @@ -2226,6 +2272,26 @@ uint32_t dp_tx_comp_handler(struct dp_soc *soc, void *hal_srng, uint32_t quota) return num_processed; } +/** + * dp_tx_non_std() - Allow the control-path SW to send data frames + * + * @data_vdev - which vdev should transmit the tx data frames + * @tx_spec - what non-standard handling to apply to the tx data frames + * @msdu_list - NULL-terminated list of tx MSDUs + * + * Return: NULL on success, + * nbuf when it fails to send + */ +qdf_nbuf_t dp_tx_non_std(struct cdp_vdev *vdev_handle, + enum ol_tx_spec tx_spec, qdf_nbuf_t msdu_list) +{ + struct dp_vdev *vdev = (struct dp_vdev *) vdev_handle; + + if (tx_spec & OL_TX_SPEC_NO_FREE) + vdev->is_tdls_frame = true; + return dp_tx_send(vdev_handle, msdu_list); +} + /** * dp_tx_vdev_attach() - attach vdev to dp tx * @vdev: virtual device instance diff --git a/dp/wifi3.0/dp_tx.h b/dp/wifi3.0/dp_tx.h index fae65be80a..2fae13bd5a 100644 --- a/dp/wifi3.0/dp_tx.h +++ b/dp/wifi3.0/dp_tx.h @@ -30,9 +30,10 @@ #define DP_TX_DESC_FLAG_FRAG 0x4 #define DP_TX_DESC_FLAG_RAW 0x8 #define DP_TX_DESC_FLAG_MESH 0x10 -#define DP_TX_DESC_FLAG_QUEUED_TX 0x20 -#define DP_TX_DESC_FLAG_COMPLETED_TX 0x40 +#define DP_TX_DESC_FLAG_QUEUED_TX 0x20 +#define DP_TX_DESC_FLAG_COMPLETED_TX 0x40 #define DP_TX_DESC_FLAG_ME 0x80 +#define DP_TX_DESC_FLAG_TDLS_FRAME 0x100 #define DP_TX_FREE_SINGLE_BUF(soc, buf) \ do { \ @@ -143,11 +144,30 @@ QDF_STATUS dp_tx_pdev_attach(struct dp_pdev *pdev); qdf_nbuf_t dp_tx_send(void *data_vdev, qdf_nbuf_t nbuf); +qdf_nbuf_t dp_tx_non_std(struct cdp_vdev *vdev_handle, + enum ol_tx_spec tx_spec, qdf_nbuf_t msdu_list); + uint32_t dp_tx_comp_handler(struct dp_soc *soc, void *hal_srng, uint32_t quota); int32_t dp_tx_prepare_send_me(struct dp_vdev *vdev, qdf_nbuf_t nbuf); +#ifndef CONVERGED_TDLS_ENABLE + +static inline void dp_tx_update_tdls_flags(struct dp_tx_desc_s *tx_desc) +{ + return; +} + +static inline void dp_non_std_tx_comp_free_buff(struct dp_tx_desc_s *tx_desc, + struct dp_vdev *vdev) +{ + return; +} + +#endif + + #ifdef FEATURE_WDS void dp_tx_mec_handler(struct dp_vdev *vdev, uint8_t *status); diff --git a/dp/wifi3.0/dp_types.h b/dp/wifi3.0/dp_types.h index d57abd86ee..70e221ac68 100644 --- a/dp/wifi3.0/dp_types.h +++ b/dp/wifi3.0/dp_types.h @@ -247,7 +247,7 @@ struct dp_tx_desc_s { struct dp_vdev *vdev; struct dp_pdev *pdev; uint8_t pool_id; - uint8_t flags; + uint16_t flags; struct hal_tx_desc_comp_s comp; uint16_t tx_encap_type; uint8_t frm_type; @@ -1102,6 +1102,13 @@ struct dp_vdev { void *context; } delete; + /* tx data delivery notification callback function */ + struct { + ol_txrx_data_tx_cb func; + void *ctxt; + } tx_non_std_data_callback; + + /* safe mode control to bypass the encrypt and decipher process*/ uint32_t safemode; @@ -1113,6 +1120,8 @@ struct dp_vdev { #endif /* TDLS Link status */ bool tdls_link_connected; + bool is_tdls_frame; + /* VDEV operating mode */ enum wlan_op_mode opmode; diff --git a/umac/tdls/core/src/wlan_tdls_cmds_process.c b/umac/tdls/core/src/wlan_tdls_cmds_process.c index 5b66567618..3b9f1ad339 100644 --- a/umac/tdls/core/src/wlan_tdls_cmds_process.c +++ b/umac/tdls/core/src/wlan_tdls_cmds_process.c @@ -1133,6 +1133,10 @@ QDF_STATUS tdls_process_del_peer(struct tdls_oper_request *req) struct wlan_serialization_command cmd = {0,}; enum wlan_serialization_status ser_cmd_status; struct wlan_objmgr_vdev *vdev; + struct tdls_vdev_priv_obj *vdev_obj; + struct tdls_soc_priv_obj *soc_obj; + uint8_t *mac; + struct tdls_peer *peer; QDF_STATUS status = QDF_STATUS_SUCCESS; if (!req || !req->vdev) { @@ -1140,7 +1144,35 @@ QDF_STATUS tdls_process_del_peer(struct tdls_oper_request *req) status = QDF_STATUS_E_INVAL; goto error; } + vdev = req->vdev; + + /* vdev reference cnt is acquired in ucfg_tdls_oper */ + vdev_obj = wlan_vdev_get_tdls_vdev_obj(vdev); + soc_obj = wlan_vdev_get_tdls_soc_obj(vdev); + + if (!vdev_obj || !soc_obj) { + tdls_err("tdls vdev_obj: %p soc_obj: %p", vdev_obj, soc_obj); + status = QDF_STATUS_E_NULL_VALUE; + goto error; + } + + mac = req->peer_addr; + peer = tdls_find_peer(vdev_obj, mac); + if (!peer) { + tdls_err(QDF_MAC_ADDRESS_STR + " not found, ignore NL80211_TDLS_ENABLE_LINK", + QDF_MAC_ADDR_ARRAY(mac)); + status = QDF_STATUS_E_INVAL; + goto error; + } + + if (soc_obj->tdls_dp_vdev_update) + soc_obj->tdls_dp_vdev_update(&soc_obj->soc, + peer->sta_id, + soc_obj->tdls_update_dp_vdev_flags, + false); + cmd.cmd_type = WLAN_SER_CMD_TDLS_DEL_PEER; cmd.cmd_id = 0; cmd.cmd_cb = (wlan_serialization_cmd_callback) @@ -1904,8 +1936,7 @@ QDF_STATUS tdls_process_remove_force_peer(struct tdls_oper_request *req) soc_obj->tdls_dp_vdev_update(&soc_obj->soc, peer->sta_id, soc_obj->tdls_update_dp_vdev_flags, - ((peer->link_status == - TDLS_LINK_CONNECTED) ? true : false)); + false); if (soc_obj->tdls_event_cb) { qdf_mem_copy(ind.peer_mac, macaddr, QDF_MAC_ADDR_SIZE); diff --git a/umac/tdls/core/src/wlan_tdls_ct.c b/umac/tdls/core/src/wlan_tdls_ct.c index a07f6dc418..2b676114c8 100644 --- a/umac/tdls/core/src/wlan_tdls_ct.c +++ b/umac/tdls/core/src/wlan_tdls_ct.c @@ -532,8 +532,7 @@ void tdls_indicate_teardown(struct tdls_vdev_priv_obj *tdls_vdev, tdls_soc->tdls_dp_vdev_update(&tdls_soc->soc, curr_peer->sta_id, tdls_soc->tdls_update_dp_vdev_flags, - ((curr_peer->link_status == - TDLS_LINK_CONNECTED) ? true : false)); + false); indication.reason = reason; indication.vdev = tdls_vdev->vdev; diff --git a/umac/tdls/dispatcher/src/wlan_tdls_ucfg_api.c b/umac/tdls/dispatcher/src/wlan_tdls_ucfg_api.c index 5b41921a02..c5bf80475e 100644 --- a/umac/tdls/dispatcher/src/wlan_tdls_ucfg_api.c +++ b/umac/tdls/dispatcher/src/wlan_tdls_ucfg_api.c @@ -218,6 +218,7 @@ QDF_STATUS ucfg_tdls_update_config(struct wlan_objmgr_psoc *psoc, soc_obj->tdls_update_peer_state = req->tdls_update_peer_state; soc_obj->tdls_del_all_peers = req->tdls_del_all_peers; soc_obj->tdls_update_dp_vdev_flags = req->tdls_update_dp_vdev_flags; + soc_obj->tdls_dp_vdev_update = req->tdls_dp_vdev_update; tdls_pm_call_backs.tdls_notify_increment_session = tdls_notify_increment_session;