diff --git a/dp/inc/cdp_txrx_misc.h b/dp/inc/cdp_txrx_misc.h index e161d7b252..88d198c871 100644 --- a/dp/inc/cdp_txrx_misc.h +++ b/dp/inc/cdp_txrx_misc.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2016-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. 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 @@ -960,4 +960,38 @@ cdp_get_tx_rings_grp_bitmap(ol_txrx_soc_handle soc) return 0; } + +#ifdef WLAN_FEATURE_PEER_TXQ_FLUSH_CONF +/** + * cdp_set_peer_txq_flush_config() - Set the peer txq flush configuration + * @soc: Opaque handle to the DP soc object + * @vdev_id: VDEV identifier + * @mac: MAC address of the peer + * @ac: access category mask + * @tid: TID mask + * @policy: Flush policy + * + * Return: 0 on success, errno on failure + */ +static inline int +cdp_set_peer_txq_flush_config(ol_txrx_soc_handle soc, uint8_t vdev_id, + uint8_t *mac, uint8_t ac, uint32_t tid, + enum cdp_peer_txq_flush_policy policy) +{ + if (!soc || !soc->ops || !soc->ops->misc_ops || !mac) { + dp_cdp_debug("Invalid parameters"); + return 0; + } + + if (soc->ops->misc_ops->set_peer_txq_flush_config) { + return soc->ops->misc_ops->set_peer_txq_flush_config(soc, + vdev_id, + mac, ac, + tid, + policy); + } + + return 0; +} +#endif /* WLAN_FEATURE_PEER_TXQ_FLUSH_CONF */ #endif /* _CDP_TXRX_MISC_H_ */ diff --git a/dp/inc/cdp_txrx_ops.h b/dp/inc/cdp_txrx_ops.h index 88f951f323..818ccfd20f 100644 --- a/dp/inc/cdp_txrx_ops.h +++ b/dp/inc/cdp_txrx_ops.h @@ -119,6 +119,23 @@ enum vdev_ll_conn_actions { CDP_VDEV_LL_CONN_DEL }; +/** + * enum cdp_peer_txq_flush_policy: Values for peer TX TID queues flush policy + * @CDP_PEER_TXQ_FLUSH_POLICY_NONE: No flush policy configured + * @CDP_PEER_TXQ_FLUSH_POLICY_IMMEDIATE: Flush peer TX TID queue(s) immediately + * @CDP_PEER_TXQ_FLUSH_POLICY_TWT_SP_END: Flush peer TX TID queue(s) at SP end + * + * This is used to map the 'flush_policy' in WMI_PEER_FLUSH_POLICY_CMDID + */ +enum cdp_peer_txq_flush_policy { + CDP_PEER_TXQ_FLUSH_POLICY_NONE = 0, + CDP_PEER_TXQ_FLUSH_POLICY_IMMEDIATE = 1, + CDP_PEER_TXQ_FLUSH_POLICY_TWT_SP_END = 2, + + /* keep last */ + CDP_PEER_TXQ_FLUSH_POLICY_INVALID, +}; + /** * struct cdp_mlo_ops - MLO ops for multichip * @mlo_soc_setup: setup DP mlo for SOC @@ -1474,6 +1491,8 @@ struct ol_if_ops { * @set_swlm_enable: Enable or Disable Software Latency Manager. * @is_swlm_enabled: Check if Software latency manager is enabled or not. * @display_txrx_hw_info: Dump the DP rings info + * @set_tx_flush_pending: Configures the ac/tid to be flushed and policy + * to flush. * * Function pointers for miscellaneous soc/pdev/vdev related operations. */ @@ -1566,6 +1585,12 @@ struct cdp_misc_ops { uint8_t (*is_swlm_enabled)(struct cdp_soc_t *soc_hdl); void (*display_txrx_hw_info)(struct cdp_soc_t *soc_hdl); uint32_t (*get_tx_rings_grp_bitmap)(struct cdp_soc_t *soc_hdl); +#ifdef WLAN_FEATURE_PEER_TXQ_FLUSH_CONF + int (*set_peer_txq_flush_config)(struct cdp_soc_t *soc_hdl, + uint8_t vdev_id, uint8_t *addr, + uint8_t ac, uint32_t tid, + enum cdp_peer_txq_flush_policy policy); +#endif }; /** diff --git a/dp/wifi3.0/dp_main.c b/dp/wifi3.0/dp_main.c index fc721000f8..025f36bb2d 100644 --- a/dp/wifi3.0/dp_main.c +++ b/dp/wifi3.0/dp_main.c @@ -92,6 +92,9 @@ cdp_dump_flow_pool_info(struct cdp_soc_t *soc) #ifdef CONFIG_SAWF_DEF_QUEUES #include "dp_sawf.h" #endif +#ifdef WLAN_FEATURE_PEER_TXQ_FLUSH_CONF +#include +#endif #ifdef WLAN_FEATURE_STATS_EXT #define INIT_RX_HW_STATS_LOCK(_soc) \ @@ -13405,6 +13408,35 @@ static void dp_mark_first_wakeup_packet(struct cdp_soc_t *soc_hdl, } #endif +#ifdef WLAN_FEATURE_PEER_TXQ_FLUSH_CONF +/** + * dp_set_peer_txq_flush_config() - Set the peer txq flush configuration + * @soc_hdl: Opaque handle to the DP soc object + * @vdev_id: VDEV identifier + * @mac: MAC address of the peer + * @ac: access category mask + * @tid: TID mask + * @policy: Flush policy + * + * Return: 0 on success, errno on failure + */ +static int dp_set_peer_txq_flush_config(struct cdp_soc_t *soc_hdl, + uint8_t vdev_id, uint8_t *mac, + uint8_t ac, uint32_t tid, + enum cdp_peer_txq_flush_policy policy) +{ + struct dp_soc *soc; + + if (!soc_hdl) { + dp_err("soc is null"); + return -EINVAL; + } + soc = cdp_soc_t_to_dp_soc(soc_hdl); + return target_if_peer_txq_flush_config(soc->ctrl_psoc, vdev_id, + mac, ac, tid, policy); +} +#endif + #ifdef DP_PEER_EXTENDED_API static struct cdp_misc_ops dp_ops_misc = { #ifdef FEATURE_WLAN_TDLS @@ -13438,6 +13470,9 @@ static struct cdp_misc_ops dp_ops_misc = { #ifdef WLAN_FEATURE_MARK_FIRST_WAKEUP_PACKET .mark_first_wakeup_packet = dp_mark_first_wakeup_packet, #endif +#ifdef WLAN_FEATURE_PEER_TXQ_FLUSH_CONF + .set_peer_txq_flush_config = dp_set_peer_txq_flush_config, +#endif }; #endif diff --git a/target_if/dp/inc/target_if_dp.h b/target_if/dp/inc/target_if_dp.h index 6ccfb4a671..bd7328eed3 100644 --- a/target_if/dp/inc/target_if_dp.h +++ b/target_if/dp/inc/target_if_dp.h @@ -213,4 +213,30 @@ target_if_update_wds_entry(struct cdp_ctrl_objmgr_psoc *soc, uint8_t vdev_id, return QDF_STATUS_SUCCESS; } #endif /* FEATURE_MCL_REPEATER */ -#endif + +#ifdef WLAN_FEATURE_PEER_TXQ_FLUSH_CONF +/** + * target_if_peer_txq_flush_config() - Send flush command for pending frames + * @psoc: psoc handle pointer + * @vdev_id: VDEV id + * @mac: MAC addr of peer for which the tx queue flush is intended + * @ac: AC mask for identifying the tx queues to be flushed + * @tid: TID mask for identifying the tx queues to be flushed + * @policy: Defines the flush policy + * + * Return: 0 for success or error code + */ +int target_if_peer_txq_flush_config(struct cdp_ctrl_objmgr_psoc *psoc, + uint8_t vdev_id, uint8_t *mac, + uint8_t ac, uint32_t tid, uint32_t policy); +#else +static inline int +target_if_peer_txq_flush_config(struct cdp_ctrl_objmgr_psoc *psoc, + uint8_t vdev_id, uint8_t *mac, + uint8_t ac, uint32_t tid, + enum cdp_peer_txq_flush_policy policy) +{ + return 0; +} +#endif /* WLAN_FEATURE_PEER_TXQ_FLUSH_CONF */ +#endif /* _WLAN_TARGET_IF_DP_H_ */ diff --git a/target_if/dp/src/target_if_dp.c b/target_if/dp/src/target_if_dp.c index 2df228c68b..efc6b2ea9b 100644 --- a/target_if/dp/src/target_if_dp.c +++ b/target_if/dp/src/target_if_dp.c @@ -24,6 +24,10 @@ #include #include "target_if_dp.h" #include +#ifdef WLAN_FEATURE_PEER_TXQ_FLUSH_CONF +#include +#include +#endif uint32_t target_if_get_active_mac_phy_number(struct wlan_objmgr_psoc *psoc) { @@ -452,3 +456,169 @@ target_if_update_wds_entry(struct cdp_ctrl_objmgr_psoc *soc, uint8_t vdev_id, return status; } #endif + +#ifdef WLAN_FEATURE_PEER_TXQ_FLUSH_CONF +/** + * map_flush_policy() - Map DP layer flush policy values to target i/f layer + * @policy: The DP layer flush policy value + * + * Return: Peer flush policy + */ +static enum peer_txq_flush_policy +map_flush_policy(enum cdp_peer_txq_flush_policy policy) +{ + switch (policy) { + case CDP_PEER_TXQ_FLUSH_POLICY_NONE: + return PEER_TXQ_FLUSH_POLICY_NONE; + case CDP_PEER_TXQ_FLUSH_POLICY_TWT_SP_END: + return PEER_TXQ_FLUSH_POLICY_TWT_SP_END; + default: + return PEER_TXQ_FLUSH_POLICY_INVALID; + } +} + +/** + * send_peer_txq_flush_conf() - Send flush config for peers TID queues + * @psoc: Opaque handle for posc object manager object + * @mac: MAC addr of peer for which the tx queue flush is intended + * @vdev_id: VDEV identifier + * @tid: TID mask for identifying the tx queues to be flushed + * @policy: The peer tid queue flush policy + * + * Return: 0 for success or error code + */ +static int send_peer_txq_flush_conf(struct cdp_ctrl_objmgr_psoc *psoc, + uint8_t *mac, uint8_t vdev_id, + uint32_t tid, + enum cdp_peer_txq_flush_policy policy) +{ + struct wlan_objmgr_psoc *obj_soc; + struct wmi_unified *wmi_handle; + enum peer_txq_flush_policy flush_policy; + struct peer_txq_flush_config_params param = {0}; + QDF_STATUS status; + + obj_soc = (struct wlan_objmgr_psoc *)psoc; + wmi_handle = GET_WMI_HDL_FROM_PSOC(obj_soc); + if (!wmi_handle) { + target_if_err("Invalid wmi handle"); + return -EINVAL; + } + + flush_policy = map_flush_policy(policy); + if (flush_policy >= PEER_TXQ_FLUSH_POLICY_INVALID) { + target_if_err("Invalid flush policy : %d", policy); + return -EINVAL; + } + + param.vdev_id = vdev_id; + param.tid_mask = tid; + param.policy = flush_policy; + qdf_mem_copy(param.peer, mac, QDF_MAC_ADDR_SIZE); + + status = wmi_unified_peer_txq_flush_config_send(wmi_handle, ¶m); + return qdf_status_to_os_return(status); +} + +/** + * send_peer_txq_flush_tids() - Send flush command peers TID queues + * @psoc: Opaque handle for psoc object manager object + * @mac: MAC addr of peer for which the tx queue flush is intended + * @vdev_id: VDEV identifier + * @tid: TID mask for identifying the tx queues to be flushed + * + * Return: 0 for success or error code + */ +static int send_peer_txq_flush_tids(struct cdp_ctrl_objmgr_psoc *psoc, + uint8_t *mac, uint8_t vdev_id, + uint32_t tid) +{ + struct wlan_objmgr_psoc *obj_soc; + struct wmi_unified *wmi_handle; + struct peer_flush_params param; + QDF_STATUS status; + + if (!psoc || !mac) { + target_if_err("Invalid params"); + return -EINVAL; + } + + obj_soc = (struct wlan_objmgr_psoc *)psoc; + wmi_handle = GET_WMI_HDL_FROM_PSOC(obj_soc); + if (!wmi_handle) { + target_if_err("Invalid wmi handle"); + return -EINVAL; + } + + param.vdev_id = vdev_id; + param.peer_tid_bitmap = tid; + qdf_mem_copy(param.peer_mac, mac, QDF_MAC_ADDR_SIZE); + + status = wmi_unified_peer_flush_tids_send(wmi_handle, mac, ¶m); + return qdf_status_to_os_return(status); +} + +int target_if_peer_txq_flush_config(struct cdp_ctrl_objmgr_psoc *psoc, + uint8_t vdev_id, uint8_t *addr, + uint8_t ac, uint32_t tid, + enum cdp_peer_txq_flush_policy policy) +{ + static uint8_t ac_to_tid[4][2] = { {0, 3}, {1, 2}, {4, 5}, {6, 7} }; + struct wlan_objmgr_psoc *obj_soc; + struct wlan_objmgr_peer *peer; + int i, rc; + + if (!psoc || !addr) { + target_if_err("Invalid params"); + return -EINVAL; + } + + if (!tid && !ac) { + target_if_err("no ac/tid mask setting"); + return -EINVAL; + } + + if (tid && policy == CDP_PEER_TXQ_FLUSH_POLICY_INVALID) { + target_if_err("Invalid flush policy"); + return -EINVAL; + } + obj_soc = (struct wlan_objmgr_psoc *)psoc; + + peer = wlan_objmgr_get_peer_by_mac(obj_soc, addr, WLAN_DP_ID); + if (!peer) { + target_if_err("Peer not found in the list"); + return -EINVAL; + } + /* If tid mask is provided and policy is immediate use legacy WMI. + * If tid mask is provided and policy is other than immediate use + * the new WMI command for flush config. + * If tid mask is not provided and ac mask is provided, convert to tid, + * use the legacy WMI cmd for flushing the queues immediately. + */ + if (tid) { + if (policy == CDP_PEER_TXQ_FLUSH_POLICY_IMMEDIATE) { + rc = send_peer_txq_flush_tids(psoc, addr, vdev_id, tid); + wlan_objmgr_peer_release_ref(peer, WLAN_DP_ID); + return rc; + } + rc = send_peer_txq_flush_conf(psoc, addr, vdev_id, tid, policy); + wlan_objmgr_peer_release_ref(peer, WLAN_DP_ID); + return rc; + } + + if (ac) { + tid = 0; + for (i = 0; i < 4; ++i) { + if (((ac & 0x0f) >> i) & 0x01) { + tid |= (1 << ac_to_tid[i][0]) | + (1 << ac_to_tid[i][1]); + } + } + rc = send_peer_txq_flush_tids(psoc, addr, vdev_id, tid); + wlan_objmgr_peer_release_ref(peer, WLAN_DP_ID); + return rc; + } + /* should not hit this line */ + return 0; +} +#endif diff --git a/wmi/inc/wmi_unified_api.h b/wmi/inc/wmi_unified_api.h index a2774575e1..b0c5d5418b 100644 --- a/wmi/inc/wmi_unified_api.h +++ b/wmi/inc/wmi_unified_api.h @@ -934,6 +934,18 @@ QDF_STATUS wmi_unified_peer_flush_tids_send(wmi_unified_t wmi_handle, uint8_t peer_addr[QDF_MAC_ADDR_SIZE], struct peer_flush_params *param); +#ifdef WLAN_FEATURE_PEER_TXQ_FLUSH_CONF +/** + * wmi_unified_peer_txq_flush_config_send() - peer txq flush policy config in fw + * @wmi_handle: wmi handle + * @pr: peer txq flush config parameters + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS +wmi_unified_peer_txq_flush_config_send(wmi_unified_t wmi_handle, + struct peer_txq_flush_config_params *pr); +#endif /** * wmi_unified_peer_delete_all_send() - send PEER delete all command to fw diff --git a/wmi/inc/wmi_unified_param.h b/wmi/inc/wmi_unified_param.h index dffcab1cbe..aba0d50b97 100644 --- a/wmi/inc/wmi_unified_param.h +++ b/wmi/inc/wmi_unified_param.h @@ -3696,6 +3696,34 @@ enum wmi_ratemask_type { WMI_RATEMASK_TYPE_HE = 3, }; +/** + * enum peer_txq_flush_policy - Peer flush policy values + * @PEER_TXQ_FLUSH_POLICY_NONE: No policy configured for peer TID queues + * @PEER_TXQ_FLUSH_POLICY_TWT_SP_END: flush peer TID queues after SP end + * + * This is mapped to 'flush_policy' in WMI_PEER_FLUSH_POLICY_CMDID + */ +enum peer_txq_flush_policy { + PEER_TXQ_FLUSH_POLICY_NONE = 0, + PEER_TXQ_FLUSH_POLICY_TWT_SP_END = 1, + /*keep last */ + PEER_TXQ_FLUSH_POLICY_INVALID, +}; + +/** + * struct peer_txq_flush_config_params: Peer TXQ flush configuration parameters + * @vdev_id: vdev id + * @peer: Peer mac address + * @tid_mask: TID queues of the peer being configured + * @policy: Policy to be applied + */ +struct peer_txq_flush_config_params { + uint8_t vdev_id; + uint8_t peer[QDF_MAC_ADDR_SIZE]; + uint32_t tid_mask; + enum peer_txq_flush_policy policy; +}; + /** * enum gpio_pull_type - GPIO PULL TYPE * @WMI_HOST_GPIO_PULL_NONE: set gpio pull type to none diff --git a/wmi/inc/wmi_unified_priv.h b/wmi/inc/wmi_unified_priv.h index 9edcc43172..fd1e1e4dfb 100644 --- a/wmi/inc/wmi_unified_priv.h +++ b/wmi/inc/wmi_unified_priv.h @@ -3017,6 +3017,11 @@ QDF_STATUS (*extract_pdev_telemetry_stats)( wmi_unified_t wmi_handle, void *evt_buf, struct wmi_host_pdev_telemetry_stats *pdev_stats); +#ifdef WLAN_FEATURE_PEER_TXQ_FLUSH_CONF +QDF_STATUS +(*send_peer_txq_flush_config_cmd)(wmi_unified_t wmi_handle, + struct peer_txq_flush_config_params *param); +#endif }; /* Forward declartion for psoc*/ diff --git a/wmi/src/wmi_unified_api.c b/wmi/src/wmi_unified_api.c index 43195a2cb8..355278c30e 100644 --- a/wmi/src/wmi_unified_api.c +++ b/wmi/src/wmi_unified_api.c @@ -160,6 +160,20 @@ wmi_unified_peer_flush_tids_send(wmi_unified_t wmi_handle, return QDF_STATUS_E_FAILURE; } +#ifdef WLAN_FEATURE_PEER_TXQ_FLUSH_CONF +QDF_STATUS +wmi_unified_peer_txq_flush_config_send(wmi_unified_t wmi_handle, + struct peer_txq_flush_config_params *pr) +{ + struct wmi_ops *ops = wmi_handle->ops; + + if (ops->send_peer_txq_flush_config_cmd) + return ops->send_peer_txq_flush_config_cmd(wmi_handle, pr); + + return QDF_STATUS_E_FAILURE; +} +#endif + QDF_STATUS wmi_unified_peer_delete_send(wmi_unified_t wmi_handle, uint8_t peer_addr[QDF_MAC_ADDR_SIZE], struct peer_delete_cmd_params *param) diff --git a/wmi/src/wmi_unified_tlv.c b/wmi/src/wmi_unified_tlv.c index c1e36755ce..2b173e98e0 100644 --- a/wmi/src/wmi_unified_tlv.c +++ b/wmi/src/wmi_unified_tlv.c @@ -1284,6 +1284,74 @@ static QDF_STATUS send_peer_flush_tids_cmd_tlv(wmi_unified_t wmi, return 0; } +#ifdef WLAN_FEATURE_PEER_TXQ_FLUSH_CONF +/** + * map_to_wmi_flush_policy() - Map flush policy to firmware defined values + * @policy: The target i/f flush policy value + * + * Return: WMI layer flush policy + */ +static wmi_peer_flush_policy +map_to_wmi_flush_policy(enum peer_txq_flush_policy policy) +{ + switch (policy) { + case PEER_TXQ_FLUSH_POLICY_NONE: + return WMI_NO_FLUSH; + case PEER_TXQ_FLUSH_POLICY_TWT_SP_END: + return WMI_TWT_FLUSH; + default: + return WMI_MAX_FLUSH_POLICY; + } +} + +/** + * send_peer_txq_flush_config_cmd_tlv() - Send peer TID queue flush config + * @wmi: wmi handle + * @para: Peer txq flush configuration + * + * Return: QDF status + */ +static QDF_STATUS +send_peer_txq_flush_config_cmd_tlv(wmi_unified_t wmi, + struct peer_txq_flush_config_params *param) +{ + wmi_peer_flush_policy_cmd_fixed_param *cmd; + wmi_buf_t buf; + int32_t len = sizeof(*cmd); + + buf = wmi_buf_alloc(wmi, len); + if (!buf) + return QDF_STATUS_E_NOMEM; + + cmd = (wmi_peer_flush_policy_cmd_fixed_param *)wmi_buf_data(buf); + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_peer_flush_policy_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_peer_flush_policy_cmd_fixed_param)); + + WMI_CHAR_ARRAY_TO_MAC_ADDR(param->peer, &cmd->peer_macaddr); + cmd->peer_tid_bitmap = param->tid_mask; + cmd->vdev_id = param->vdev_id; + cmd->flush_policy = map_to_wmi_flush_policy(param->policy); + if (cmd->flush_policy == WMI_MAX_FLUSH_POLICY) { + wmi_buf_free(buf); + wmi_err("Invalid policy"); + return QDF_STATUS_E_INVAL; + } + wmi_debug("peer_addr " QDF_MAC_ADDR_FMT "vdev %d tid %x policy %d", + QDF_MAC_ADDR_REF(param->peer), param->vdev_id, + param->tid_mask, param->policy); + wmi_mtrace(WMI_PEER_FLUSH_POLICY_CMDID, cmd->vdev_id, 0); + if (wmi_unified_cmd_send(wmi, buf, len, WMI_PEER_FLUSH_POLICY_CMDID)) { + wmi_err("Failed to send flush policy command"); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} +#endif /** * send_peer_delete_cmd_tlv() - send PEER delete command to fw * @wmi: wmi handle @@ -18387,6 +18455,9 @@ struct wmi_ops tlv_ops = { extract_pktlog_decode_info_event_tlv, .extract_pdev_telemetry_stats = extract_pdev_telemetry_stats_tlv, .extract_mgmt_rx_ext_params = extract_mgmt_rx_ext_params_tlv, +#ifdef WLAN_FEATURE_PEER_TXQ_FLUSH_CONF + .send_peer_txq_flush_config_cmd = send_peer_txq_flush_config_cmd_tlv, +#endif }; #ifdef WLAN_FEATURE_11BE_MLO