xref: /wlan-driver/qcacld-3.0/os_if/twt/src/osif_twt_ext_req.c (revision 5113495b16420b49004c444715d2daae2066e7dc)
1*5113495bSYour Name /*
2*5113495bSYour Name  * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
3*5113495bSYour Name  *
4*5113495bSYour Name  * Permission to use, copy, modify, and/or distribute this software for any
5*5113495bSYour Name  * purpose with or without fee is hereby granted, provided that the above
6*5113495bSYour Name  * copyright notice and this permission notice appear in all copies.
7*5113495bSYour Name  *
8*5113495bSYour Name  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9*5113495bSYour Name  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10*5113495bSYour Name  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11*5113495bSYour Name  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12*5113495bSYour Name  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13*5113495bSYour Name  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14*5113495bSYour Name  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15*5113495bSYour Name  */
16*5113495bSYour Name 
17*5113495bSYour Name /**
18*5113495bSYour Name  *  DOC: osif_twt_ext_req.c
19*5113495bSYour Name  *  This file contains twt component's osif API implementation
20*5113495bSYour Name  */
21*5113495bSYour Name #include <wlan_objmgr_vdev_obj.h>
22*5113495bSYour Name #include <wlan_twt_ucfg_api.h>
23*5113495bSYour Name #include <wlan_twt_ucfg_ext_api.h>
24*5113495bSYour Name #include <wlan_twt_ucfg_ext_cfg.h>
25*5113495bSYour Name #include <osif_twt_req.h>
26*5113495bSYour Name #include <osif_twt_ext_req.h>
27*5113495bSYour Name #include <wlan_policy_mgr_api.h>
28*5113495bSYour Name #include <wlan_cm_api.h>
29*5113495bSYour Name #include <wlan_cfg80211.h>
30*5113495bSYour Name #include <wlan_cm_roam_api.h>
31*5113495bSYour Name #include <osif_twt_internal.h>
32*5113495bSYour Name #include <wlan_osif_request_manager.h>
33*5113495bSYour Name #include <wlan_osif_priv.h>
34*5113495bSYour Name #include "wlan_cp_stats_mc_ucfg_api.h"
35*5113495bSYour Name #include "wlan_mlme_ucfg_api.h"
36*5113495bSYour Name #include "wlan_cp_stats_ucfg_api.h"
37*5113495bSYour Name #include "osif_vdev_sync.h"
38*5113495bSYour Name 
39*5113495bSYour Name #define TWT_ACK_COMPLETE_TIMEOUT 1000
40*5113495bSYour Name 
41*5113495bSYour Name #define TWT_FLOW_TYPE_ANNOUNCED 0
42*5113495bSYour Name #define TWT_FLOW_TYPE_UNANNOUNCED 1
43*5113495bSYour Name 
44*5113495bSYour Name #define TWT_SETUP_WAKE_INTVL_MANTISSA_MAX       0xFFFF
45*5113495bSYour Name #define TWT_SETUP_WAKE_DURATION_MAX             0xFFFF
46*5113495bSYour Name #define TWT_SETUP_WAKE_INTVL_EXP_MAX            31
47*5113495bSYour Name #define TWT_MAX_NEXT_TWT_SIZE                   3
48*5113495bSYour Name #define TWT_DEL_DIALOG_REQ_MAX_RETRY            10
49*5113495bSYour Name #define TWT_TEARDOWN_IN_PS_DISABLE_WAIT_TIME    500
50*5113495bSYour Name 
51*5113495bSYour Name static const struct nla_policy
52*5113495bSYour Name qca_wlan_vendor_twt_add_dialog_policy[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX + 1] = {
53*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_EXP] = {.type = NLA_U8 },
54*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST] = {.type = NLA_FLAG },
55*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_REQ_TYPE] = {.type = NLA_U8 },
56*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TRIGGER] = {.type = NLA_FLAG },
57*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID] = {.type = NLA_U8 },
58*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_TYPE] = {.type = NLA_U8 },
59*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_PROTECTION] = {.type = NLA_FLAG },
60*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_TIME] = {.type = NLA_U32 },
61*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_DURATION] = {.type = NLA_U32 },
62*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_MANTISSA] = {.type = NLA_U32 },
63*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MIN_WAKE_DURATION] = {.type = NLA_U32 },
64*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX_WAKE_DURATION] = {.type = NLA_U32 },
65*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MIN_WAKE_INTVL] = {.type = NLA_U32 },
66*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX_WAKE_INTVL] = {.type = NLA_U32 },
67*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL2_MANTISSA] = {.type = NLA_U32 },
68*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAC_ADDR] = VENDOR_NLA_POLICY_MAC_ADDR,
69*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST_ID] = {.type = NLA_U8 },
70*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST_RECOMMENDATION] = {
71*5113495bSYour Name 							.type = NLA_U8 },
72*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST_PERSISTENCE] = {.type = NLA_U8 },
73*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_TIME_TSF] = {.type = NLA_U64 },
74*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_ANNOUNCE_TIMEOUT] = {.type = NLA_U32 },
75*5113495bSYour Name };
76*5113495bSYour Name 
77*5113495bSYour Name static const struct nla_policy
78*5113495bSYour Name qca_wlan_vendor_twt_resume_dialog_policy[QCA_WLAN_VENDOR_ATTR_TWT_RESUME_MAX + 1] = {
79*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_TWT_RESUME_FLOW_ID] = {.type = NLA_U8 },
80*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_TWT_RESUME_NEXT_TWT] = {.type = NLA_U8 },
81*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_TWT_RESUME_NEXT_TWT_SIZE] = {.type = NLA_U32 },
82*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_TWT_RESUME_NEXT2_TWT] = {.type = NLA_U32 },
83*5113495bSYour Name };
84*5113495bSYour Name 
85*5113495bSYour Name static const struct nla_policy
86*5113495bSYour Name qca_wlan_vendor_twt_nudge_dialog_policy[QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_MAX + 1] = {
87*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_FLOW_ID] = {.type = NLA_U8 },
88*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_WAKE_TIME] = {.type = NLA_U32 },
89*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_NEXT_TWT_SIZE] = {.type = NLA_U32 },
90*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_MAC_ADDR] = VENDOR_NLA_POLICY_MAC_ADDR,
91*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_SP_START_OFFSET] = {.type = NLA_S32},
92*5113495bSYour Name };
93*5113495bSYour Name 
94*5113495bSYour Name static const struct nla_policy
95*5113495bSYour Name qca_wlan_vendor_twt_set_param_policy[QCA_WLAN_VENDOR_ATTR_TWT_SET_PARAM_MAX + 1] = {
96*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_TWT_SET_PARAM_AP_AC_VALUE] = {.type = NLA_U8 },
97*5113495bSYour Name };
98*5113495bSYour Name 
99*5113495bSYour Name static const struct nla_policy
100*5113495bSYour Name qca_wlan_vendor_twt_stats_dialog_policy[QCA_WLAN_VENDOR_ATTR_TWT_STATS_MAX + 1] = {
101*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_TWT_STATS_FLOW_ID] = {.type = NLA_U8 },
102*5113495bSYour Name };
103*5113495bSYour Name 
osif_is_twt_command_allowed(struct wlan_objmgr_vdev * vdev,uint8_t vdev_id,struct wlan_objmgr_psoc * psoc)104*5113495bSYour Name static int osif_is_twt_command_allowed(struct wlan_objmgr_vdev *vdev,
105*5113495bSYour Name 				       uint8_t vdev_id,
106*5113495bSYour Name 				       struct wlan_objmgr_psoc *psoc)
107*5113495bSYour Name {
108*5113495bSYour Name 	enum QDF_OPMODE mode = wlan_vdev_mlme_get_opmode(vdev);
109*5113495bSYour Name 
110*5113495bSYour Name 	if (mode != QDF_STA_MODE &&
111*5113495bSYour Name 	    mode != QDF_P2P_CLIENT_MODE)
112*5113495bSYour Name 		return -EOPNOTSUPP;
113*5113495bSYour Name 
114*5113495bSYour Name 	if (!wlan_cm_is_vdev_connected(vdev)) {
115*5113495bSYour Name 		osif_err_rl("Not associated!, vdev %d mode %d", vdev_id, mode);
116*5113495bSYour Name 		return -EAGAIN;
117*5113495bSYour Name 	}
118*5113495bSYour Name 
119*5113495bSYour Name 	if (wlan_cm_host_roam_in_progress(psoc, vdev_id))
120*5113495bSYour Name 		return -EBUSY;
121*5113495bSYour Name 
122*5113495bSYour Name 	if (wlan_get_vdev_status(vdev)) {
123*5113495bSYour Name 		osif_err_rl("Scan in progress");
124*5113495bSYour Name 		return -EBUSY;
125*5113495bSYour Name 	}
126*5113495bSYour Name 
127*5113495bSYour Name 	return 0;
128*5113495bSYour Name }
129*5113495bSYour Name 
osif_twt_setup_conc_allowed(struct wlan_objmgr_psoc * psoc,uint8_t vdev_id)130*5113495bSYour Name static bool osif_twt_setup_conc_allowed(struct wlan_objmgr_psoc *psoc,
131*5113495bSYour Name 					uint8_t vdev_id)
132*5113495bSYour Name {
133*5113495bSYour Name 	return policy_mgr_current_concurrency_is_mcc(psoc) ||
134*5113495bSYour Name 	       policy_mgr_is_scc_with_this_vdev_id(psoc, vdev_id);
135*5113495bSYour Name }
136*5113495bSYour Name 
137*5113495bSYour Name /**
138*5113495bSYour Name  * osif_twt_setup_req_type_to_cmd() - Converts twt setup request type to twt cmd
139*5113495bSYour Name  * @req_type: twt setup request type
140*5113495bSYour Name  * @twt_cmd: pointer to store twt command
141*5113495bSYour Name  *
142*5113495bSYour Name  * Return: QDF_STATUS_SUCCESS on success, else other qdf error values
143*5113495bSYour Name  */
144*5113495bSYour Name static QDF_STATUS
osif_twt_setup_req_type_to_cmd(u8 req_type,enum HOST_TWT_COMMAND * twt_cmd)145*5113495bSYour Name osif_twt_setup_req_type_to_cmd(u8 req_type, enum HOST_TWT_COMMAND *twt_cmd)
146*5113495bSYour Name {
147*5113495bSYour Name 	if (req_type == QCA_WLAN_VENDOR_TWT_SETUP_REQUEST) {
148*5113495bSYour Name 		*twt_cmd = HOST_TWT_COMMAND_REQUEST_TWT;
149*5113495bSYour Name 	} else if (req_type == QCA_WLAN_VENDOR_TWT_SETUP_SUGGEST) {
150*5113495bSYour Name 		*twt_cmd = HOST_TWT_COMMAND_SUGGEST_TWT;
151*5113495bSYour Name 	} else if (req_type == QCA_WLAN_VENDOR_TWT_SETUP_DEMAND) {
152*5113495bSYour Name 		*twt_cmd = HOST_TWT_COMMAND_DEMAND_TWT;
153*5113495bSYour Name 	} else {
154*5113495bSYour Name 		osif_err_rl("Invalid TWT_SETUP_REQ_TYPE %d", req_type);
155*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
156*5113495bSYour Name 	}
157*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
158*5113495bSYour Name }
159*5113495bSYour Name 
160*5113495bSYour Name /**
161*5113495bSYour Name  * osif_twt_parse_add_dialog_attrs() - Get TWT add dialog parameter
162*5113495bSYour Name  * values from QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS
163*5113495bSYour Name  * @tb: nl attributes
164*5113495bSYour Name  * @params: wmi twt add dialog parameters
165*5113495bSYour Name  *
166*5113495bSYour Name  * Handles QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX
167*5113495bSYour Name  *
168*5113495bSYour Name  * Return: 0 or -EINVAL.
169*5113495bSYour Name  */
170*5113495bSYour Name static int
osif_twt_parse_add_dialog_attrs(struct nlattr ** tb,struct twt_add_dialog_param * params)171*5113495bSYour Name osif_twt_parse_add_dialog_attrs(struct nlattr **tb,
172*5113495bSYour Name 				struct twt_add_dialog_param *params)
173*5113495bSYour Name {
174*5113495bSYour Name 	uint32_t wake_intvl_exp, result;
175*5113495bSYour Name 	int cmd_id;
176*5113495bSYour Name 	QDF_STATUS qdf_status;
177*5113495bSYour Name 
178*5113495bSYour Name 	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID;
179*5113495bSYour Name 	if (tb[cmd_id]) {
180*5113495bSYour Name 		params->dialog_id = nla_get_u8(tb[cmd_id]);
181*5113495bSYour Name 		if (params->dialog_id > TWT_MAX_DIALOG_ID) {
182*5113495bSYour Name 			osif_err_rl("Flow id (%u) invalid", params->dialog_id);
183*5113495bSYour Name 			return -EINVAL;
184*5113495bSYour Name 		}
185*5113495bSYour Name 	} else {
186*5113495bSYour Name 		params->dialog_id = 0;
187*5113495bSYour Name 		osif_debug("TWT_SETUP_FLOW_ID not specified. set to zero");
188*5113495bSYour Name 	}
189*5113495bSYour Name 
190*5113495bSYour Name 	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_EXP;
191*5113495bSYour Name 	if (!tb[cmd_id]) {
192*5113495bSYour Name 		osif_err_rl("TWT_SETUP_WAKE_INTVL_EXP is must");
193*5113495bSYour Name 		return -EINVAL;
194*5113495bSYour Name 	}
195*5113495bSYour Name 	wake_intvl_exp = nla_get_u8(tb[cmd_id]);
196*5113495bSYour Name 	if (wake_intvl_exp > TWT_SETUP_WAKE_INTVL_EXP_MAX) {
197*5113495bSYour Name 		osif_err_rl("Invalid wake_intvl_exp %u > %u",
198*5113495bSYour Name 			   wake_intvl_exp,
199*5113495bSYour Name 			   TWT_SETUP_WAKE_INTVL_EXP_MAX);
200*5113495bSYour Name 		return -EINVAL;
201*5113495bSYour Name 	}
202*5113495bSYour Name 
203*5113495bSYour Name 	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST;
204*5113495bSYour Name 	params->flag_bcast = nla_get_flag(tb[cmd_id]);
205*5113495bSYour Name 
206*5113495bSYour Name 	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST_ID;
207*5113495bSYour Name 	if (tb[cmd_id]) {
208*5113495bSYour Name 		params->dialog_id = nla_get_u8(tb[cmd_id]);
209*5113495bSYour Name 		osif_debug("TWT_SETUP_BCAST_ID %d", params->dialog_id);
210*5113495bSYour Name 	}
211*5113495bSYour Name 
212*5113495bSYour Name 	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST_RECOMMENDATION;
213*5113495bSYour Name 	if (tb[cmd_id]) {
214*5113495bSYour Name 		params->b_twt_recommendation = nla_get_u8(tb[cmd_id]);
215*5113495bSYour Name 		osif_debug("TWT_SETUP_BCAST_RECOMM %d",
216*5113495bSYour Name 			  params->b_twt_recommendation);
217*5113495bSYour Name 	}
218*5113495bSYour Name 
219*5113495bSYour Name 	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST_PERSISTENCE;
220*5113495bSYour Name 	if (tb[cmd_id]) {
221*5113495bSYour Name 		params->b_twt_persistence = nla_get_u8(tb[cmd_id]);
222*5113495bSYour Name 		osif_debug("TWT_SETUP_BCAST_PERSIS %d",
223*5113495bSYour Name 			  params->b_twt_persistence);
224*5113495bSYour Name 	}
225*5113495bSYour Name 
226*5113495bSYour Name 	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_REQ_TYPE;
227*5113495bSYour Name 	if (!tb[cmd_id]) {
228*5113495bSYour Name 		osif_err_rl("TWT_SETUP_REQ_TYPE is must");
229*5113495bSYour Name 		return -EINVAL;
230*5113495bSYour Name 	}
231*5113495bSYour Name 	qdf_status = osif_twt_setup_req_type_to_cmd(nla_get_u8(tb[cmd_id]),
232*5113495bSYour Name 						   &params->twt_cmd);
233*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(qdf_status))
234*5113495bSYour Name 		return qdf_status_to_os_return(qdf_status);
235*5113495bSYour Name 
236*5113495bSYour Name 	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TRIGGER;
237*5113495bSYour Name 	params->flag_trigger = nla_get_flag(tb[cmd_id]);
238*5113495bSYour Name 
239*5113495bSYour Name 	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_TYPE;
240*5113495bSYour Name 	if (!tb[cmd_id]) {
241*5113495bSYour Name 		osif_err_rl("TWT_SETUP_FLOW_TYPE is must");
242*5113495bSYour Name 		return -EINVAL;
243*5113495bSYour Name 	}
244*5113495bSYour Name 	params->flag_flow_type = nla_get_u8(tb[cmd_id]);
245*5113495bSYour Name 	if (params->flag_flow_type != TWT_FLOW_TYPE_ANNOUNCED &&
246*5113495bSYour Name 	    params->flag_flow_type != TWT_FLOW_TYPE_UNANNOUNCED)
247*5113495bSYour Name 		return -EINVAL;
248*5113495bSYour Name 
249*5113495bSYour Name 	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_PROTECTION;
250*5113495bSYour Name 	params->flag_protection = nla_get_flag(tb[cmd_id]);
251*5113495bSYour Name 
252*5113495bSYour Name 	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_TIME;
253*5113495bSYour Name 	if (tb[cmd_id])
254*5113495bSYour Name 		params->sp_offset_us = nla_get_u32(tb[cmd_id]);
255*5113495bSYour Name 
256*5113495bSYour Name 	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_DURATION;
257*5113495bSYour Name 	if (!tb[cmd_id]) {
258*5113495bSYour Name 		osif_err_rl("TWT_SETUP_WAKE_DURATION is must");
259*5113495bSYour Name 		return -EINVAL;
260*5113495bSYour Name 	}
261*5113495bSYour Name 	params->wake_dura_us = TWT_WAKE_DURATION_MULTIPLICATION_FACTOR *
262*5113495bSYour Name 			       nla_get_u32(tb[cmd_id]);
263*5113495bSYour Name 	if (params->wake_dura_us > TWT_SETUP_WAKE_DURATION_MAX) {
264*5113495bSYour Name 		osif_err_rl("Invalid wake_dura_us %u",
265*5113495bSYour Name 			   params->wake_dura_us);
266*5113495bSYour Name 		return -EINVAL;
267*5113495bSYour Name 	}
268*5113495bSYour Name 
269*5113495bSYour Name 	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MIN_WAKE_DURATION;
270*5113495bSYour Name 	if (tb[cmd_id])
271*5113495bSYour Name 		params->min_wake_dura_us = nla_get_u32(tb[cmd_id]);
272*5113495bSYour Name 
273*5113495bSYour Name 	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX_WAKE_DURATION;
274*5113495bSYour Name 	if (tb[cmd_id])
275*5113495bSYour Name 		params->max_wake_dura_us = nla_get_u32(tb[cmd_id]);
276*5113495bSYour Name 
277*5113495bSYour Name 	if (params->min_wake_dura_us > params->max_wake_dura_us) {
278*5113495bSYour Name 		osif_err_rl("Invalid wake duration range min:%d max:%d. Reset to zero",
279*5113495bSYour Name 			   params->min_wake_dura_us, params->max_wake_dura_us);
280*5113495bSYour Name 		params->min_wake_dura_us = 0;
281*5113495bSYour Name 		params->max_wake_dura_us = 0;
282*5113495bSYour Name 	}
283*5113495bSYour Name 
284*5113495bSYour Name 	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_MANTISSA;
285*5113495bSYour Name 	if (!tb[cmd_id]) {
286*5113495bSYour Name 		osif_err_rl("SETUP_WAKE_INTVL_MANTISSA is must");
287*5113495bSYour Name 		return -EINVAL;
288*5113495bSYour Name 	}
289*5113495bSYour Name 	params->wake_intvl_mantis = nla_get_u32(tb[cmd_id]);
290*5113495bSYour Name 
291*5113495bSYour Name 	/*
292*5113495bSYour Name 	 * If mantissa in microsecond is present then take precedence over
293*5113495bSYour Name 	 * mantissa in TU. And send mantissa in microsecond to firmware.
294*5113495bSYour Name 	 */
295*5113495bSYour Name 	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL2_MANTISSA;
296*5113495bSYour Name 	if (tb[cmd_id])
297*5113495bSYour Name 		params->wake_intvl_mantis = nla_get_u32(tb[cmd_id]);
298*5113495bSYour Name 
299*5113495bSYour Name 	if (params->wake_intvl_mantis >
300*5113495bSYour Name 	    TWT_SETUP_WAKE_INTVL_MANTISSA_MAX) {
301*5113495bSYour Name 		osif_err_rl("Invalid wake_intvl_mantis %u",
302*5113495bSYour Name 			   params->wake_intvl_mantis);
303*5113495bSYour Name 		return -EINVAL;
304*5113495bSYour Name 	}
305*5113495bSYour Name 
306*5113495bSYour Name 	if (wake_intvl_exp && params->wake_intvl_mantis) {
307*5113495bSYour Name 		result = 2 << (wake_intvl_exp - 1);
308*5113495bSYour Name 		if (result >
309*5113495bSYour Name 		    (UINT_MAX / params->wake_intvl_mantis)) {
310*5113495bSYour Name 			osif_err_rl("Invalid exp %d mantissa %d",
311*5113495bSYour Name 				   wake_intvl_exp,
312*5113495bSYour Name 				   params->wake_intvl_mantis);
313*5113495bSYour Name 			return -EINVAL;
314*5113495bSYour Name 		}
315*5113495bSYour Name 		params->wake_intvl_us =
316*5113495bSYour Name 			params->wake_intvl_mantis * result;
317*5113495bSYour Name 	} else {
318*5113495bSYour Name 		params->wake_intvl_us = params->wake_intvl_mantis;
319*5113495bSYour Name 	}
320*5113495bSYour Name 
321*5113495bSYour Name 	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MIN_WAKE_INTVL;
322*5113495bSYour Name 	if (tb[cmd_id])
323*5113495bSYour Name 		params->min_wake_intvl_us = nla_get_u32(tb[cmd_id]);
324*5113495bSYour Name 
325*5113495bSYour Name 	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX_WAKE_INTVL;
326*5113495bSYour Name 	if (tb[cmd_id])
327*5113495bSYour Name 		params->max_wake_intvl_us = nla_get_u32(tb[cmd_id]);
328*5113495bSYour Name 
329*5113495bSYour Name 	if (params->min_wake_intvl_us > params->max_wake_intvl_us) {
330*5113495bSYour Name 		osif_err_rl("Invalid wake intvl range min:%d max:%d. Reset to zero",
331*5113495bSYour Name 			   params->min_wake_intvl_us,
332*5113495bSYour Name 			   params->max_wake_intvl_us);
333*5113495bSYour Name 		params->min_wake_dura_us = 0;
334*5113495bSYour Name 		params->max_wake_dura_us = 0;
335*5113495bSYour Name 	}
336*5113495bSYour Name 
337*5113495bSYour Name 	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_TIME_TSF;
338*5113495bSYour Name 	if (tb[cmd_id])
339*5113495bSYour Name 		params->wake_time_tsf = nla_get_u64(tb[cmd_id]);
340*5113495bSYour Name 	else
341*5113495bSYour Name 		params->wake_time_tsf = 0;
342*5113495bSYour Name 
343*5113495bSYour Name 	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_ANNOUNCE_TIMEOUT;
344*5113495bSYour Name 	if (tb[cmd_id])
345*5113495bSYour Name 		params->announce_timeout_us = nla_get_u32(tb[cmd_id]);
346*5113495bSYour Name 	else
347*5113495bSYour Name 		params->announce_timeout_us = 0;
348*5113495bSYour Name 
349*5113495bSYour Name 	osif_debug("twt: dialog_id %d, vdev %d, wake intvl_us %d, min %d, max %d, mantis %d",
350*5113495bSYour Name 		  params->dialog_id, params->vdev_id, params->wake_intvl_us,
351*5113495bSYour Name 		  params->min_wake_intvl_us, params->max_wake_intvl_us,
352*5113495bSYour Name 		  params->wake_intvl_mantis);
353*5113495bSYour Name 
354*5113495bSYour Name 	osif_debug("twt: wake dura %d, min %d, max %d, sp_offset %d, cmd %d",
355*5113495bSYour Name 		  params->wake_dura_us, params->min_wake_dura_us,
356*5113495bSYour Name 		  params->max_wake_dura_us, params->sp_offset_us,
357*5113495bSYour Name 		  params->twt_cmd);
358*5113495bSYour Name 	osif_debug("twt: bcast %d, trigger %d, flow_type %d, prot %d wake_tsf 0x%llx",
359*5113495bSYour Name 		  params->flag_bcast, params->flag_trigger,
360*5113495bSYour Name 		  params->flag_flow_type,
361*5113495bSYour Name 		  params->flag_protection,
362*5113495bSYour Name 		  params->wake_time_tsf);
363*5113495bSYour Name 	osif_debug("twt: peer mac_addr "
364*5113495bSYour Name 		  QDF_MAC_ADDR_FMT,
365*5113495bSYour Name 		  QDF_MAC_ADDR_REF(params->peer_macaddr.bytes));
366*5113495bSYour Name 	osif_debug("twt: announce timeout(in us) %u",
367*5113495bSYour Name 		   params->announce_timeout_us);
368*5113495bSYour Name 	return 0;
369*5113495bSYour Name }
370*5113495bSYour Name 
371*5113495bSYour Name /**
372*5113495bSYour Name  * osif_twt_parse_del_dialog_attrs() - Parse TWT del dialog parameters
373*5113495bSYour Name  * values from QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS
374*5113495bSYour Name  * @tb: nl attributes
375*5113495bSYour Name  * @params: twt del dialog parameters
376*5113495bSYour Name  *
377*5113495bSYour Name  * Handles QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX
378*5113495bSYour Name  *
379*5113495bSYour Name  * Return: 0 or -EINVAL.
380*5113495bSYour Name  */
381*5113495bSYour Name static int
osif_twt_parse_del_dialog_attrs(struct nlattr ** tb,struct twt_del_dialog_param * params)382*5113495bSYour Name osif_twt_parse_del_dialog_attrs(struct nlattr **tb,
383*5113495bSYour Name 				struct twt_del_dialog_param *params)
384*5113495bSYour Name {
385*5113495bSYour Name 	int cmd_id;
386*5113495bSYour Name 
387*5113495bSYour Name 	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID;
388*5113495bSYour Name 	if (tb[cmd_id]) {
389*5113495bSYour Name 		params->dialog_id = nla_get_u8(tb[cmd_id]);
390*5113495bSYour Name 	} else {
391*5113495bSYour Name 		params->dialog_id = 0;
392*5113495bSYour Name 		osif_debug("TWT_TERMINATE_FLOW_ID not specified. set to zero");
393*5113495bSYour Name 	}
394*5113495bSYour Name 
395*5113495bSYour Name 	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST_ID;
396*5113495bSYour Name 	if (tb[cmd_id]) {
397*5113495bSYour Name 		params->dialog_id = nla_get_u8(tb[cmd_id]);
398*5113495bSYour Name 		osif_debug("TWT_SETUP_BCAST_ID %d", params->dialog_id);
399*5113495bSYour Name 	}
400*5113495bSYour Name 
401*5113495bSYour Name 	osif_debug("twt: dialog_id %d vdev %d peer mac_addr "QDF_MAC_ADDR_FMT,
402*5113495bSYour Name 		   params->dialog_id, params->vdev_id,
403*5113495bSYour Name 		   QDF_MAC_ADDR_REF(params->peer_macaddr.bytes));
404*5113495bSYour Name 
405*5113495bSYour Name 	return 0;
406*5113495bSYour Name }
407*5113495bSYour Name 
osif_fill_peer_macaddr(struct wlan_objmgr_vdev * vdev,uint8_t * mac_addr)408*5113495bSYour Name int osif_fill_peer_macaddr(struct wlan_objmgr_vdev *vdev, uint8_t *mac_addr)
409*5113495bSYour Name {
410*5113495bSYour Name 	struct wlan_objmgr_peer *peer;
411*5113495bSYour Name 
412*5113495bSYour Name 	peer = wlan_objmgr_vdev_try_get_bsspeer(vdev, WLAN_TWT_ID);
413*5113495bSYour Name 	if (!peer) {
414*5113495bSYour Name 		osif_err("peer is null");
415*5113495bSYour Name 		return -EAGAIN;
416*5113495bSYour Name 	}
417*5113495bSYour Name 	wlan_peer_obj_lock(peer);
418*5113495bSYour Name 	qdf_mem_copy(mac_addr, wlan_peer_get_macaddr(peer), QDF_MAC_ADDR_SIZE);
419*5113495bSYour Name 	wlan_peer_obj_unlock(peer);
420*5113495bSYour Name 
421*5113495bSYour Name 	wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID);
422*5113495bSYour Name 	return 0;
423*5113495bSYour Name }
424*5113495bSYour Name 
425*5113495bSYour Name /**
426*5113495bSYour Name  * osif_twt_ack_wait_response: TWT wait for ack event if it's supported
427*5113495bSYour Name  * @psoc: psoc context
428*5113495bSYour Name  * @request: OSIF request cookie
429*5113495bSYour Name  * @twt_cmd: TWT command for which ack event come
430*5113495bSYour Name  *
431*5113495bSYour Name  * Return: QDF_STATUS
432*5113495bSYour Name  */
433*5113495bSYour Name static QDF_STATUS
osif_twt_ack_wait_response(struct wlan_objmgr_psoc * psoc,struct osif_request * request,int twt_cmd)434*5113495bSYour Name osif_twt_ack_wait_response(struct wlan_objmgr_psoc *psoc,
435*5113495bSYour Name 			   struct osif_request *request, int twt_cmd)
436*5113495bSYour Name {
437*5113495bSYour Name 	struct twt_ack_context *ack_priv;
438*5113495bSYour Name 	int ret = 0;
439*5113495bSYour Name 	bool twt_ack_cap;
440*5113495bSYour Name 
441*5113495bSYour Name 	ucfg_twt_get_twt_ack_supported(psoc, &twt_ack_cap);
442*5113495bSYour Name 
443*5113495bSYour Name 	if (!twt_ack_cap) {
444*5113495bSYour Name 		osif_err("TWT ack is not supported. No need to wait");
445*5113495bSYour Name 		return QDF_STATUS_SUCCESS;
446*5113495bSYour Name 	}
447*5113495bSYour Name 
448*5113495bSYour Name 	ack_priv = osif_request_priv(request);
449*5113495bSYour Name 	ack_priv->twt_cmd_ack = twt_cmd;
450*5113495bSYour Name 
451*5113495bSYour Name 	ret = osif_request_wait_for_response(request);
452*5113495bSYour Name 	if (ret) {
453*5113495bSYour Name 		osif_err("TWT ack response timed out");
454*5113495bSYour Name 		return QDF_STATUS_E_TIMEOUT;
455*5113495bSYour Name 	}
456*5113495bSYour Name 
457*5113495bSYour Name 	osif_debug("TWT ack info: vdev_id %d dialog_id %d twt_cmd %d status %d peer_macaddr "
458*5113495bSYour Name 			  QDF_MAC_ADDR_FMT, ack_priv->vdev_id, ack_priv->dialog_id,
459*5113495bSYour Name 			  ack_priv->twt_cmd_ack, ack_priv->status,
460*5113495bSYour Name 			  QDF_MAC_ADDR_REF(ack_priv->peer_macaddr.bytes));
461*5113495bSYour Name 
462*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
463*5113495bSYour Name }
464*5113495bSYour Name 
465*5113495bSYour Name static void
osif_send_twt_delete_cmd(struct wlan_objmgr_vdev * vdev,struct qdf_mac_addr * peer_mac,uint8_t dialog_id,bool is_ps_disabled)466*5113495bSYour Name osif_send_twt_delete_cmd(struct wlan_objmgr_vdev *vdev,
467*5113495bSYour Name 			 struct qdf_mac_addr *peer_mac, uint8_t dialog_id,
468*5113495bSYour Name 			 bool is_ps_disabled)
469*5113495bSYour Name {
470*5113495bSYour Name 	uint32_t twt_next_action = HOST_TWT_SEND_DELETE_CMD;
471*5113495bSYour Name 
472*5113495bSYour Name 	ucfg_twt_set_work_params(vdev, peer_mac, dialog_id, is_ps_disabled,
473*5113495bSYour Name 				 twt_next_action);
474*5113495bSYour Name 	qdf_sched_work(0, &vdev->twt_work);
475*5113495bSYour Name }
476*5113495bSYour Name 
477*5113495bSYour Name static int
osif_send_twt_setup_req(struct wlan_objmgr_vdev * vdev,struct wlan_objmgr_psoc * psoc,struct twt_add_dialog_param * twt_params)478*5113495bSYour Name osif_send_twt_setup_req(struct wlan_objmgr_vdev *vdev,
479*5113495bSYour Name 			struct wlan_objmgr_psoc *psoc,
480*5113495bSYour Name 			struct twt_add_dialog_param *twt_params)
481*5113495bSYour Name {
482*5113495bSYour Name 	QDF_STATUS status;
483*5113495bSYour Name 	int twt_cmd, ret = 0;
484*5113495bSYour Name 	struct osif_request *request;
485*5113495bSYour Name 	struct twt_ack_context *ack_priv;
486*5113495bSYour Name 	void *context;
487*5113495bSYour Name 	static const struct osif_request_params params = {
488*5113495bSYour Name 				.priv_size = sizeof(*ack_priv),
489*5113495bSYour Name 				.timeout_ms = TWT_ACK_COMPLETE_TIMEOUT,
490*5113495bSYour Name 	};
491*5113495bSYour Name 
492*5113495bSYour Name 	request = osif_request_alloc(&params);
493*5113495bSYour Name 	if (!request) {
494*5113495bSYour Name 		osif_err("Request allocation failure");
495*5113495bSYour Name 		return -ENOMEM;
496*5113495bSYour Name 	}
497*5113495bSYour Name 
498*5113495bSYour Name 	context = osif_request_cookie(request);
499*5113495bSYour Name 
500*5113495bSYour Name 	status = ucfg_twt_setup_req(psoc, twt_params, context);
501*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
502*5113495bSYour Name 		ret = qdf_status_to_os_return(status);
503*5113495bSYour Name 		osif_err("Failed to send add dialog command");
504*5113495bSYour Name 		goto cleanup;
505*5113495bSYour Name 	}
506*5113495bSYour Name 
507*5113495bSYour Name 	twt_cmd = HOST_TWT_ADD_DIALOG_CMDID;
508*5113495bSYour Name 	status = osif_twt_ack_wait_response(psoc, request, twt_cmd);
509*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
510*5113495bSYour Name 		/*
511*5113495bSYour Name 		 * If the TWT ack event comes after the timeout or
512*5113495bSYour Name 		 * if the event is not received from the firmware, then
513*5113495bSYour Name 		 * initialize the context (reset the active command),
514*5113495bSYour Name 		 * otherwise future commands shall be blocked.
515*5113495bSYour Name 		 */
516*5113495bSYour Name 		ucfg_twt_init_context(psoc, &twt_params->peer_macaddr,
517*5113495bSYour Name 				      twt_params->dialog_id);
518*5113495bSYour Name 		ret = qdf_status_to_os_return(status);
519*5113495bSYour Name 		goto cleanup;
520*5113495bSYour Name 	}
521*5113495bSYour Name 
522*5113495bSYour Name 	ack_priv = osif_request_priv(request);
523*5113495bSYour Name 	if (ack_priv->status) {
524*5113495bSYour Name 		osif_err("Received TWT ack error: %d. Reset twt command",
525*5113495bSYour Name 			 ack_priv->status);
526*5113495bSYour Name 
527*5113495bSYour Name 		if (ucfg_twt_is_setup_done(psoc,
528*5113495bSYour Name 					   &twt_params->peer_macaddr,
529*5113495bSYour Name 					   twt_params->dialog_id)) {
530*5113495bSYour Name 			/* If TWT setup is already done then this is
531*5113495bSYour Name 			 * renegotiation failure scenario.
532*5113495bSYour Name 			 * Terminate TWT session on renegotiation failure.
533*5113495bSYour Name 			 */
534*5113495bSYour Name 			osif_debug("setup_done set, renego failure");
535*5113495bSYour Name 			osif_send_twt_delete_cmd(vdev,
536*5113495bSYour Name 						 &twt_params->peer_macaddr,
537*5113495bSYour Name 						 twt_params->dialog_id, false);
538*5113495bSYour Name 		} else {
539*5113495bSYour Name 			ucfg_twt_init_context(psoc, &twt_params->peer_macaddr,
540*5113495bSYour Name 					      twt_params->dialog_id);
541*5113495bSYour Name 		}
542*5113495bSYour Name 
543*5113495bSYour Name 		switch (ack_priv->status) {
544*5113495bSYour Name 		case HOST_ADD_TWT_STATUS_INVALID_PARAM:
545*5113495bSYour Name 		case HOST_ADD_TWT_STATUS_UNKNOWN_ERROR:
546*5113495bSYour Name 		case HOST_ADD_TWT_STATUS_USED_DIALOG_ID:
547*5113495bSYour Name 			ret = -EINVAL;
548*5113495bSYour Name 			break;
549*5113495bSYour Name 		case HOST_ADD_TWT_STATUS_ROAM_IN_PROGRESS:
550*5113495bSYour Name 		case HOST_ADD_TWT_STATUS_CHAN_SW_IN_PROGRESS:
551*5113495bSYour Name 		case HOST_ADD_TWT_STATUS_SCAN_IN_PROGRESS:
552*5113495bSYour Name 		case HOST_ADD_TWT_STATUS_LINK_SWITCH_IN_PROGRESS:
553*5113495bSYour Name 		case HOST_ADD_TWT_STATUS_UNSUPPORTED_MODE_MLMR:
554*5113495bSYour Name 			ret = -EBUSY;
555*5113495bSYour Name 			break;
556*5113495bSYour Name 		case HOST_ADD_TWT_STATUS_TWT_NOT_ENABLED:
557*5113495bSYour Name 			ret = -EOPNOTSUPP;
558*5113495bSYour Name 			break;
559*5113495bSYour Name 		case HOST_ADD_TWT_STATUS_NOT_READY:
560*5113495bSYour Name 			ret = -EAGAIN;
561*5113495bSYour Name 			break;
562*5113495bSYour Name 		case HOST_ADD_TWT_STATUS_NO_RESOURCE:
563*5113495bSYour Name 			ret = -ENOMEM;
564*5113495bSYour Name 			break;
565*5113495bSYour Name 		default:
566*5113495bSYour Name 			ret = -EINVAL;
567*5113495bSYour Name 			break;
568*5113495bSYour Name 		}
569*5113495bSYour Name 	}
570*5113495bSYour Name 
571*5113495bSYour Name cleanup:
572*5113495bSYour Name 	osif_request_put(request);
573*5113495bSYour Name 	return ret;
574*5113495bSYour Name }
575*5113495bSYour Name 
576*5113495bSYour Name /**
577*5113495bSYour Name  * osif_send_twt_pause_req() - Send TWT pause dialog command to target
578*5113495bSYour Name  * @vdev: vdev
579*5113495bSYour Name  * @psoc: psoc
580*5113495bSYour Name  * @twt_params: Pointer to pause dialog cmd params structure
581*5113495bSYour Name  *
582*5113495bSYour Name  * Return: 0 on success, negative value on failure
583*5113495bSYour Name  */
584*5113495bSYour Name static int
osif_send_twt_pause_req(struct wlan_objmgr_vdev * vdev,struct wlan_objmgr_psoc * psoc,struct twt_pause_dialog_cmd_param * twt_params)585*5113495bSYour Name osif_send_twt_pause_req(struct wlan_objmgr_vdev *vdev,
586*5113495bSYour Name 			struct wlan_objmgr_psoc *psoc,
587*5113495bSYour Name 			struct twt_pause_dialog_cmd_param *twt_params)
588*5113495bSYour Name {
589*5113495bSYour Name 	QDF_STATUS status;
590*5113495bSYour Name 	int ret = 0, twt_cmd;
591*5113495bSYour Name 	struct osif_request *request;
592*5113495bSYour Name 	struct twt_ack_context *ack_priv;
593*5113495bSYour Name 	void *context;
594*5113495bSYour Name 	static const struct osif_request_params params = {
595*5113495bSYour Name 				.priv_size = sizeof(*ack_priv),
596*5113495bSYour Name 				.timeout_ms = TWT_ACK_COMPLETE_TIMEOUT,
597*5113495bSYour Name 	};
598*5113495bSYour Name 
599*5113495bSYour Name 	request = osif_request_alloc(&params);
600*5113495bSYour Name 	if (!request) {
601*5113495bSYour Name 		osif_err("Request allocation failure");
602*5113495bSYour Name 		return -ENOMEM;
603*5113495bSYour Name 	}
604*5113495bSYour Name 
605*5113495bSYour Name 	context = osif_request_cookie(request);
606*5113495bSYour Name 
607*5113495bSYour Name 	status = ucfg_twt_pause_req(psoc, twt_params, context);
608*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
609*5113495bSYour Name 		osif_err("Failed to send pause dialog command");
610*5113495bSYour Name 		ret = qdf_status_to_os_return(status);
611*5113495bSYour Name 		goto cleanup;
612*5113495bSYour Name 	}
613*5113495bSYour Name 
614*5113495bSYour Name 	twt_cmd = HOST_TWT_PAUSE_DIALOG_CMDID;
615*5113495bSYour Name 	status = osif_twt_ack_wait_response(psoc, request, twt_cmd);
616*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
617*5113495bSYour Name 		ret = qdf_status_to_os_return(status);
618*5113495bSYour Name 		goto cleanup;
619*5113495bSYour Name 	}
620*5113495bSYour Name 
621*5113495bSYour Name 	ack_priv = osif_request_priv(request);
622*5113495bSYour Name 	if (ack_priv->status != HOST_TWT_PAUSE_STATUS_OK) {
623*5113495bSYour Name 		osif_err("Received TWT ack error:%d. Reset twt command",
624*5113495bSYour Name 			 ack_priv->status);
625*5113495bSYour Name 
626*5113495bSYour Name 		switch (ack_priv->status) {
627*5113495bSYour Name 		case HOST_TWT_PAUSE_STATUS_INVALID_PARAM:
628*5113495bSYour Name 		case HOST_TWT_PAUSE_STATUS_ALREADY_PAUSED:
629*5113495bSYour Name 		case HOST_TWT_PAUSE_STATUS_UNKNOWN_ERROR:
630*5113495bSYour Name 			ret = -EINVAL;
631*5113495bSYour Name 			break;
632*5113495bSYour Name 		case HOST_TWT_PAUSE_STATUS_DIALOG_ID_NOT_EXIST:
633*5113495bSYour Name 			ret = -EAGAIN;
634*5113495bSYour Name 			break;
635*5113495bSYour Name 		case HOST_TWT_PAUSE_STATUS_DIALOG_ID_BUSY:
636*5113495bSYour Name 			ret = -EINPROGRESS;
637*5113495bSYour Name 			break;
638*5113495bSYour Name 		case HOST_TWT_PAUSE_STATUS_NO_RESOURCE:
639*5113495bSYour Name 			ret = -ENOMEM;
640*5113495bSYour Name 			break;
641*5113495bSYour Name 		case HOST_TWT_PAUSE_STATUS_CHAN_SW_IN_PROGRESS:
642*5113495bSYour Name 		case HOST_TWT_PAUSE_STATUS_ROAM_IN_PROGRESS:
643*5113495bSYour Name 		case HOST_TWT_PAUSE_STATUS_SCAN_IN_PROGRESS:
644*5113495bSYour Name 			ret = -EBUSY;
645*5113495bSYour Name 			break;
646*5113495bSYour Name 		default:
647*5113495bSYour Name 			ret = -EAGAIN;
648*5113495bSYour Name 			break;
649*5113495bSYour Name 		}
650*5113495bSYour Name 	}
651*5113495bSYour Name 
652*5113495bSYour Name cleanup:
653*5113495bSYour Name 	osif_request_put(request);
654*5113495bSYour Name 	return ret;
655*5113495bSYour Name }
656*5113495bSYour Name 
657*5113495bSYour Name static int
osif_send_sta_twt_teardown_req(struct wlan_objmgr_vdev * vdev,struct wlan_objmgr_psoc * psoc,struct twt_del_dialog_param * twt_params)658*5113495bSYour Name osif_send_sta_twt_teardown_req(struct wlan_objmgr_vdev *vdev,
659*5113495bSYour Name 			       struct wlan_objmgr_psoc *psoc,
660*5113495bSYour Name 			       struct twt_del_dialog_param *twt_params)
661*5113495bSYour Name {
662*5113495bSYour Name 	QDF_STATUS status;
663*5113495bSYour Name 	int twt_cmd, ret = 0;
664*5113495bSYour Name 	struct osif_request *request;
665*5113495bSYour Name 	struct twt_ack_context *ack_priv;
666*5113495bSYour Name 	void *context;
667*5113495bSYour Name 	static const struct osif_request_params params = {
668*5113495bSYour Name 				.priv_size = sizeof(*ack_priv),
669*5113495bSYour Name 				.timeout_ms = TWT_ACK_COMPLETE_TIMEOUT,
670*5113495bSYour Name 	};
671*5113495bSYour Name 
672*5113495bSYour Name 	request = osif_request_alloc(&params);
673*5113495bSYour Name 	if (!request) {
674*5113495bSYour Name 		osif_err("Request allocation failure");
675*5113495bSYour Name 		return -ENOMEM;
676*5113495bSYour Name 	}
677*5113495bSYour Name 
678*5113495bSYour Name 	context = osif_request_cookie(request);
679*5113495bSYour Name 
680*5113495bSYour Name 	status = ucfg_twt_teardown_req(psoc, twt_params, context);
681*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
682*5113495bSYour Name 		ret = qdf_status_to_os_return(status);
683*5113495bSYour Name 		osif_err("Failed to send del dialog command");
684*5113495bSYour Name 		goto cleanup;
685*5113495bSYour Name 	}
686*5113495bSYour Name 
687*5113495bSYour Name 	twt_cmd = HOST_TWT_DEL_DIALOG_CMDID;
688*5113495bSYour Name 
689*5113495bSYour Name 	status = osif_twt_ack_wait_response(psoc, request, twt_cmd);
690*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
691*5113495bSYour Name 		ucfg_twt_reset_active_command(psoc, &twt_params->peer_macaddr,
692*5113495bSYour Name 					      twt_params->dialog_id);
693*5113495bSYour Name 		ret = qdf_status_to_os_return(status);
694*5113495bSYour Name 		goto cleanup;
695*5113495bSYour Name 	}
696*5113495bSYour Name 
697*5113495bSYour Name 	ack_priv = osif_request_priv(request);
698*5113495bSYour Name 	if (ack_priv->status != HOST_TWT_DEL_STATUS_OK) {
699*5113495bSYour Name 		osif_err("Received TWT ack error:%d. Reset twt command",
700*5113495bSYour Name 			  ack_priv->status);
701*5113495bSYour Name 
702*5113495bSYour Name 		switch (ack_priv->status) {
703*5113495bSYour Name 		case HOST_TWT_DEL_STATUS_INVALID_PARAM:
704*5113495bSYour Name 		case HOST_TWT_DEL_STATUS_UNKNOWN_ERROR:
705*5113495bSYour Name 			ret = -EINVAL;
706*5113495bSYour Name 			break;
707*5113495bSYour Name 		case HOST_TWT_DEL_STATUS_DIALOG_ID_NOT_EXIST:
708*5113495bSYour Name 			ret = -EAGAIN;
709*5113495bSYour Name 			break;
710*5113495bSYour Name 		case HOST_TWT_DEL_STATUS_DIALOG_ID_BUSY:
711*5113495bSYour Name 			ret = -EINPROGRESS;
712*5113495bSYour Name 			break;
713*5113495bSYour Name 		case HOST_TWT_DEL_STATUS_NO_RESOURCE:
714*5113495bSYour Name 			ret = -ENOMEM;
715*5113495bSYour Name 			break;
716*5113495bSYour Name 		case HOST_TWT_DEL_STATUS_ROAMING:
717*5113495bSYour Name 		case HOST_TWT_DEL_STATUS_CHAN_SW_IN_PROGRESS:
718*5113495bSYour Name 		case HOST_TWT_DEL_STATUS_SCAN_IN_PROGRESS:
719*5113495bSYour Name 			ret = -EBUSY;
720*5113495bSYour Name 			break;
721*5113495bSYour Name 		case HOST_TWT_DEL_STATUS_CONCURRENCY:
722*5113495bSYour Name 			ret = -EAGAIN;
723*5113495bSYour Name 			break;
724*5113495bSYour Name 		default:
725*5113495bSYour Name 			ret = -EAGAIN;
726*5113495bSYour Name 			break;
727*5113495bSYour Name 		}
728*5113495bSYour Name 	}
729*5113495bSYour Name 
730*5113495bSYour Name cleanup:
731*5113495bSYour Name 	osif_request_put(request);
732*5113495bSYour Name 	return ret;
733*5113495bSYour Name }
734*5113495bSYour Name 
735*5113495bSYour Name /**
736*5113495bSYour Name  * osif_send_twt_resume_req() - Send TWT resume dialog command to target
737*5113495bSYour Name  * @vdev: vdev
738*5113495bSYour Name  * @psoc: psoc
739*5113495bSYour Name  * @twt_params: Pointer to resume dialog cmd params structure
740*5113495bSYour Name  *
741*5113495bSYour Name  * Return: 0 on success, negative value on failure
742*5113495bSYour Name  */
743*5113495bSYour Name static int
osif_send_twt_resume_req(struct wlan_objmgr_vdev * vdev,struct wlan_objmgr_psoc * psoc,struct twt_resume_dialog_cmd_param * twt_params)744*5113495bSYour Name osif_send_twt_resume_req(struct wlan_objmgr_vdev *vdev,
745*5113495bSYour Name 			struct wlan_objmgr_psoc *psoc,
746*5113495bSYour Name 			struct twt_resume_dialog_cmd_param *twt_params)
747*5113495bSYour Name {
748*5113495bSYour Name 	QDF_STATUS status;
749*5113495bSYour Name 	int ret = 0, twt_cmd;
750*5113495bSYour Name 	struct osif_request *request;
751*5113495bSYour Name 	struct twt_ack_context *ack_priv;
752*5113495bSYour Name 	void *context;
753*5113495bSYour Name 	static const struct osif_request_params params = {
754*5113495bSYour Name 				.priv_size = sizeof(*ack_priv),
755*5113495bSYour Name 				.timeout_ms = TWT_ACK_COMPLETE_TIMEOUT,
756*5113495bSYour Name 	};
757*5113495bSYour Name 
758*5113495bSYour Name 	request = osif_request_alloc(&params);
759*5113495bSYour Name 	if (!request) {
760*5113495bSYour Name 		osif_err("Request allocation failure");
761*5113495bSYour Name 		return -ENOMEM;
762*5113495bSYour Name 	}
763*5113495bSYour Name 
764*5113495bSYour Name 	context = osif_request_cookie(request);
765*5113495bSYour Name 
766*5113495bSYour Name 	status = ucfg_twt_resume_req(psoc, twt_params, context);
767*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
768*5113495bSYour Name 		osif_err("Failed to send resume dialog command");
769*5113495bSYour Name 		ret = qdf_status_to_os_return(status);
770*5113495bSYour Name 		goto cleanup;
771*5113495bSYour Name 	}
772*5113495bSYour Name 
773*5113495bSYour Name 	twt_cmd = HOST_TWT_RESUME_DIALOG_CMDID;
774*5113495bSYour Name 	status = osif_twt_ack_wait_response(psoc, request, twt_cmd);
775*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
776*5113495bSYour Name 		ret = qdf_status_to_os_return(status);
777*5113495bSYour Name 		goto cleanup;
778*5113495bSYour Name 	}
779*5113495bSYour Name 
780*5113495bSYour Name 	ack_priv = osif_request_priv(request);
781*5113495bSYour Name 	if (ack_priv->status != HOST_TWT_RESUME_STATUS_OK) {
782*5113495bSYour Name 		osif_err("Received TWT ack error:%d. Reset twt command",
783*5113495bSYour Name 			 ack_priv->status);
784*5113495bSYour Name 
785*5113495bSYour Name 		switch (ack_priv->status) {
786*5113495bSYour Name 		case HOST_TWT_RESUME_STATUS_INVALID_PARAM:
787*5113495bSYour Name 		case HOST_TWT_RESUME_STATUS_UNKNOWN_ERROR:
788*5113495bSYour Name 			ret = -EINVAL;
789*5113495bSYour Name 			break;
790*5113495bSYour Name 		case HOST_TWT_RESUME_STATUS_DIALOG_ID_NOT_EXIST:
791*5113495bSYour Name 		case HOST_TWT_RESUME_STATUS_NOT_PAUSED:
792*5113495bSYour Name 			ret = -EAGAIN;
793*5113495bSYour Name 			break;
794*5113495bSYour Name 		case HOST_TWT_RESUME_STATUS_DIALOG_ID_BUSY:
795*5113495bSYour Name 			ret = -EINPROGRESS;
796*5113495bSYour Name 			break;
797*5113495bSYour Name 		case HOST_TWT_RESUME_STATUS_NO_RESOURCE:
798*5113495bSYour Name 			ret = -ENOMEM;
799*5113495bSYour Name 			break;
800*5113495bSYour Name 		case HOST_TWT_RESUME_STATUS_CHAN_SW_IN_PROGRESS:
801*5113495bSYour Name 		case HOST_TWT_RESUME_STATUS_ROAM_IN_PROGRESS:
802*5113495bSYour Name 		case HOST_TWT_RESUME_STATUS_SCAN_IN_PROGRESS:
803*5113495bSYour Name 			ret = -EBUSY;
804*5113495bSYour Name 			break;
805*5113495bSYour Name 		default:
806*5113495bSYour Name 			ret = -EINVAL;
807*5113495bSYour Name 			break;
808*5113495bSYour Name 		}
809*5113495bSYour Name 	}
810*5113495bSYour Name 
811*5113495bSYour Name cleanup:
812*5113495bSYour Name 	osif_request_put(request);
813*5113495bSYour Name 	return ret;
814*5113495bSYour Name }
815*5113495bSYour Name 
816*5113495bSYour Name /**
817*5113495bSYour Name  * osif_send_twt_nudge_req() - Send TWT nudge dialog command to target
818*5113495bSYour Name  * @vdev: vdev
819*5113495bSYour Name  * @psoc: psoc
820*5113495bSYour Name  * @twt_params: Pointer to nudge dialog cmd params structure
821*5113495bSYour Name  *
822*5113495bSYour Name  * Return: 0 on success, negative value on failure
823*5113495bSYour Name  */
824*5113495bSYour Name static int
osif_send_twt_nudge_req(struct wlan_objmgr_vdev * vdev,struct wlan_objmgr_psoc * psoc,struct twt_nudge_dialog_cmd_param * twt_params)825*5113495bSYour Name osif_send_twt_nudge_req(struct wlan_objmgr_vdev *vdev,
826*5113495bSYour Name 			struct wlan_objmgr_psoc *psoc,
827*5113495bSYour Name 			struct twt_nudge_dialog_cmd_param *twt_params)
828*5113495bSYour Name {
829*5113495bSYour Name 	QDF_STATUS status;
830*5113495bSYour Name 	int ret = 0, twt_cmd;
831*5113495bSYour Name 	struct osif_request *request;
832*5113495bSYour Name 	struct twt_ack_context *ack_priv;
833*5113495bSYour Name 	void *context;
834*5113495bSYour Name 	static const struct osif_request_params params = {
835*5113495bSYour Name 				.priv_size = sizeof(*ack_priv),
836*5113495bSYour Name 				.timeout_ms = TWT_ACK_COMPLETE_TIMEOUT,
837*5113495bSYour Name 	};
838*5113495bSYour Name 
839*5113495bSYour Name 	request = osif_request_alloc(&params);
840*5113495bSYour Name 	if (!request) {
841*5113495bSYour Name 		osif_err("Request allocation failure");
842*5113495bSYour Name 		return -ENOMEM;
843*5113495bSYour Name 	}
844*5113495bSYour Name 
845*5113495bSYour Name 	context = osif_request_cookie(request);
846*5113495bSYour Name 
847*5113495bSYour Name 	status = ucfg_twt_nudge_req(psoc, twt_params, context);
848*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
849*5113495bSYour Name 		osif_err("Failed to send nudge dialog command");
850*5113495bSYour Name 		ret = qdf_status_to_os_return(status);
851*5113495bSYour Name 		goto cleanup;
852*5113495bSYour Name 	}
853*5113495bSYour Name 
854*5113495bSYour Name 	twt_cmd = HOST_TWT_NUDGE_DIALOG_CMDID;
855*5113495bSYour Name 
856*5113495bSYour Name 	status = osif_twt_ack_wait_response(psoc, request, twt_cmd);
857*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
858*5113495bSYour Name 		ret = qdf_status_to_os_return(status);
859*5113495bSYour Name 		goto cleanup;
860*5113495bSYour Name 	}
861*5113495bSYour Name 
862*5113495bSYour Name 	ack_priv = osif_request_priv(request);
863*5113495bSYour Name 	if (ack_priv->status != HOST_TWT_NUDGE_STATUS_OK) {
864*5113495bSYour Name 		osif_err("Received TWT ack error:%d. Reset twt command",
865*5113495bSYour Name 			 ack_priv->status);
866*5113495bSYour Name 
867*5113495bSYour Name 		switch (ack_priv->status) {
868*5113495bSYour Name 		case HOST_TWT_NUDGE_STATUS_INVALID_PARAM:
869*5113495bSYour Name 		case HOST_TWT_NUDGE_STATUS_UNKNOWN_ERROR:
870*5113495bSYour Name 			ret = -EINVAL;
871*5113495bSYour Name 			break;
872*5113495bSYour Name 		case HOST_TWT_NUDGE_STATUS_DIALOG_ID_NOT_EXIST:
873*5113495bSYour Name 			ret = -EAGAIN;
874*5113495bSYour Name 			break;
875*5113495bSYour Name 		case HOST_TWT_NUDGE_STATUS_DIALOG_ID_BUSY:
876*5113495bSYour Name 			ret = -EINPROGRESS;
877*5113495bSYour Name 			break;
878*5113495bSYour Name 		case HOST_TWT_NUDGE_STATUS_NO_RESOURCE:
879*5113495bSYour Name 			ret = -ENOMEM;
880*5113495bSYour Name 			break;
881*5113495bSYour Name 		case HOST_TWT_NUDGE_STATUS_CHAN_SW_IN_PROGRESS:
882*5113495bSYour Name 		case HOST_TWT_NUDGE_STATUS_ROAM_IN_PROGRESS:
883*5113495bSYour Name 		case HOST_TWT_NUDGE_STATUS_SCAN_IN_PROGRESS:
884*5113495bSYour Name 			ret = -EBUSY;
885*5113495bSYour Name 			break;
886*5113495bSYour Name 		default:
887*5113495bSYour Name 			ret = -EINVAL;
888*5113495bSYour Name 			break;
889*5113495bSYour Name 		}
890*5113495bSYour Name 	}
891*5113495bSYour Name 
892*5113495bSYour Name cleanup:
893*5113495bSYour Name 	osif_request_put(request);
894*5113495bSYour Name 	return ret;
895*5113495bSYour Name }
896*5113495bSYour Name 
osif_twt_send_requestor_enable_cmd(struct wlan_objmgr_psoc * psoc,uint8_t pdev_id)897*5113495bSYour Name int osif_twt_send_requestor_enable_cmd(struct wlan_objmgr_psoc *psoc,
898*5113495bSYour Name 				       uint8_t pdev_id)
899*5113495bSYour Name {
900*5113495bSYour Name 	struct twt_enable_param req = {0};
901*5113495bSYour Name 
902*5113495bSYour Name 	req.pdev_id = pdev_id;
903*5113495bSYour Name 	req.ext_conf_present = true;
904*5113495bSYour Name 
905*5113495bSYour Name 	return osif_twt_requestor_enable(psoc, &req);
906*5113495bSYour Name }
907*5113495bSYour Name 
osif_twt_send_responder_enable_cmd(struct wlan_objmgr_psoc * psoc,uint8_t pdev_id)908*5113495bSYour Name int osif_twt_send_responder_enable_cmd(struct wlan_objmgr_psoc *psoc,
909*5113495bSYour Name 				       uint8_t pdev_id)
910*5113495bSYour Name {
911*5113495bSYour Name 	struct twt_enable_param req = {0};
912*5113495bSYour Name 
913*5113495bSYour Name 	req.pdev_id = pdev_id;
914*5113495bSYour Name 	req.ext_conf_present = true;
915*5113495bSYour Name 
916*5113495bSYour Name 	return osif_twt_responder_enable(psoc, &req);
917*5113495bSYour Name }
918*5113495bSYour Name 
osif_twt_send_requestor_disable_cmd(struct wlan_objmgr_psoc * psoc,uint8_t pdev_id,uint32_t reason)919*5113495bSYour Name int osif_twt_send_requestor_disable_cmd(struct wlan_objmgr_psoc *psoc,
920*5113495bSYour Name 					uint8_t pdev_id, uint32_t reason)
921*5113495bSYour Name {
922*5113495bSYour Name 	struct twt_disable_param req = {0};
923*5113495bSYour Name 
924*5113495bSYour Name 	req.pdev_id = pdev_id;
925*5113495bSYour Name 	req.ext_conf_present = true;
926*5113495bSYour Name 	req.dis_reason_code = reason;
927*5113495bSYour Name 
928*5113495bSYour Name 	return osif_twt_requestor_disable(psoc, &req);
929*5113495bSYour Name }
930*5113495bSYour Name 
osif_twt_send_responder_disable_cmd(struct wlan_objmgr_psoc * psoc,uint8_t pdev_id,uint32_t reason)931*5113495bSYour Name int osif_twt_send_responder_disable_cmd(struct wlan_objmgr_psoc *psoc,
932*5113495bSYour Name 					uint8_t pdev_id, uint32_t reason)
933*5113495bSYour Name {
934*5113495bSYour Name 	struct twt_disable_param req = {0};
935*5113495bSYour Name 
936*5113495bSYour Name 	req.pdev_id = pdev_id;
937*5113495bSYour Name 	req.ext_conf_present = true;
938*5113495bSYour Name 	req.dis_reason_code = reason;
939*5113495bSYour Name 
940*5113495bSYour Name 	return osif_twt_responder_disable(psoc, &req);
941*5113495bSYour Name }
942*5113495bSYour Name 
osif_twt_teardown_in_ps_disable(struct wlan_objmgr_psoc * psoc,struct qdf_mac_addr * mac_addr,uint8_t vdev_id)943*5113495bSYour Name void osif_twt_teardown_in_ps_disable(struct wlan_objmgr_psoc *psoc,
944*5113495bSYour Name 				     struct qdf_mac_addr *mac_addr,
945*5113495bSYour Name 				     uint8_t vdev_id)
946*5113495bSYour Name {
947*5113495bSYour Name 	struct twt_del_dialog_param params = {0};
948*5113495bSYour Name 	int ret;
949*5113495bSYour Name 	struct wlan_objmgr_vdev *vdev;
950*5113495bSYour Name 
951*5113495bSYour Name 	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, WLAN_TWT_ID);
952*5113495bSYour Name 	if (!vdev) {
953*5113495bSYour Name 		osif_err("vdev is NULL");
954*5113495bSYour Name 		return;
955*5113495bSYour Name 	}
956*5113495bSYour Name 
957*5113495bSYour Name 	params.dialog_id = TWT_ALL_SESSIONS_DIALOG_ID;
958*5113495bSYour Name 	params.vdev_id = vdev_id;
959*5113495bSYour Name 	qdf_copy_macaddr(&params.peer_macaddr, mac_addr);
960*5113495bSYour Name 
961*5113495bSYour Name 	if (ucfg_twt_is_setup_done(psoc, mac_addr, params.dialog_id)) {
962*5113495bSYour Name 		osif_debug("vdev%d: Terminate existing TWT session %d due to ps disable",
963*5113495bSYour Name 			  params.vdev_id, params.dialog_id);
964*5113495bSYour Name 		ret = osif_send_sta_twt_teardown_req(vdev, psoc, &params);
965*5113495bSYour Name 		if (ret) {
966*5113495bSYour Name 			osif_debug("TWT teardown is failed on vdev: %d",
967*5113495bSYour Name 				   vdev_id);
968*5113495bSYour Name 			osif_send_twt_delete_cmd(vdev, mac_addr,
969*5113495bSYour Name 						 params.dialog_id, true);
970*5113495bSYour Name 		}
971*5113495bSYour Name 	}
972*5113495bSYour Name 	wlan_objmgr_vdev_release_ref(vdev, WLAN_TWT_ID);
973*5113495bSYour Name }
974*5113495bSYour Name 
osif_twt_get_capabilities(struct wlan_objmgr_vdev * vdev)975*5113495bSYour Name int osif_twt_get_capabilities(struct wlan_objmgr_vdev *vdev)
976*5113495bSYour Name {
977*5113495bSYour Name 	struct wlan_objmgr_psoc *psoc;
978*5113495bSYour Name 	enum QDF_OPMODE mode;
979*5113495bSYour Name 	QDF_STATUS status;
980*5113495bSYour Name 	uint8_t vdev_id;
981*5113495bSYour Name 
982*5113495bSYour Name 	psoc = wlan_vdev_get_psoc(vdev);
983*5113495bSYour Name 	if (!psoc)
984*5113495bSYour Name 		return -EINVAL;
985*5113495bSYour Name 
986*5113495bSYour Name 	vdev_id = wlan_vdev_get_id(vdev);
987*5113495bSYour Name 	mode = wlan_vdev_mlme_get_opmode(vdev);
988*5113495bSYour Name 	if (mode != QDF_STA_MODE && mode != QDF_P2P_CLIENT_MODE)
989*5113495bSYour Name 		return -EOPNOTSUPP;
990*5113495bSYour Name 
991*5113495bSYour Name 	if (!wlan_cm_is_vdev_connected(vdev)) {
992*5113495bSYour Name 		osif_err_rl("Not associated!, vdev %d mode %d", vdev_id, mode);
993*5113495bSYour Name 		return -EAGAIN;
994*5113495bSYour Name 	}
995*5113495bSYour Name 
996*5113495bSYour Name 	if (wlan_cm_host_roam_in_progress(psoc, vdev_id))
997*5113495bSYour Name 		return -EBUSY;
998*5113495bSYour Name 
999*5113495bSYour Name 	status = osif_twt_send_get_capabilities_response(psoc, vdev);
1000*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status))
1001*5113495bSYour Name 		osif_err_rl("TWT: Get capabilities failed");
1002*5113495bSYour Name 
1003*5113495bSYour Name 	return qdf_status_to_os_return(status);
1004*5113495bSYour Name }
1005*5113495bSYour Name 
osif_twt_setup_req(struct wlan_objmgr_vdev * vdev,struct nlattr * twt_param_attr)1006*5113495bSYour Name int osif_twt_setup_req(struct wlan_objmgr_vdev *vdev,
1007*5113495bSYour Name 		       struct nlattr *twt_param_attr)
1008*5113495bSYour Name {
1009*5113495bSYour Name 	struct nlattr *tb2[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX + 1];
1010*5113495bSYour Name 	struct wlan_objmgr_psoc *psoc;
1011*5113495bSYour Name 	int ret = 0;
1012*5113495bSYour Name 	uint8_t vdev_id, pdev_id;
1013*5113495bSYour Name 	struct twt_add_dialog_param params = {0};
1014*5113495bSYour Name 	uint32_t congestion_timeout = 0, reason;
1015*5113495bSYour Name 	uint8_t peer_cap;
1016*5113495bSYour Name 	QDF_STATUS qdf_status;
1017*5113495bSYour Name 
1018*5113495bSYour Name 	psoc = wlan_vdev_get_psoc(vdev);
1019*5113495bSYour Name 	if (!psoc) {
1020*5113495bSYour Name 		osif_err("NULL psoc");
1021*5113495bSYour Name 		return -EINVAL;
1022*5113495bSYour Name 	}
1023*5113495bSYour Name 
1024*5113495bSYour Name 	vdev_id = wlan_vdev_get_id(vdev);
1025*5113495bSYour Name 
1026*5113495bSYour Name 	ret = wlan_cfg80211_nla_parse_nested(tb2,
1027*5113495bSYour Name 					 QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX,
1028*5113495bSYour Name 					 twt_param_attr,
1029*5113495bSYour Name 					 qca_wlan_vendor_twt_add_dialog_policy);
1030*5113495bSYour Name 	if (ret)
1031*5113495bSYour Name 		return ret;
1032*5113495bSYour Name 
1033*5113495bSYour Name 	ret = osif_fill_peer_macaddr(vdev, params.peer_macaddr.bytes);
1034*5113495bSYour Name 	if (ret)
1035*5113495bSYour Name 		return ret;
1036*5113495bSYour Name 
1037*5113495bSYour Name 	params.vdev_id = vdev_id;
1038*5113495bSYour Name 	pdev_id = wlan_get_pdev_id_from_vdev_id(psoc, vdev_id, WLAN_TWT_ID);
1039*5113495bSYour Name 
1040*5113495bSYour Name 	ret = osif_twt_parse_add_dialog_attrs(tb2, &params);
1041*5113495bSYour Name 	if (ret)
1042*5113495bSYour Name 		return ret;
1043*5113495bSYour Name 
1044*5113495bSYour Name 	qdf_status = ucfg_twt_get_peer_capabilities(psoc, &params.peer_macaddr,
1045*5113495bSYour Name 						    &peer_cap);
1046*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(qdf_status))
1047*5113495bSYour Name 		return -EINVAL;
1048*5113495bSYour Name 
1049*5113495bSYour Name 	if (params.flag_bcast && !(peer_cap & WLAN_TWT_CAPA_BROADCAST)) {
1050*5113495bSYour Name 		osif_err_rl("TWT setup reject: TWT Broadcast not supported");
1051*5113495bSYour Name 		return -EOPNOTSUPP;
1052*5113495bSYour Name 	}
1053*5113495bSYour Name 
1054*5113495bSYour Name 	if (!params.flag_bcast && !(peer_cap & WLAN_TWT_CAPA_RESPONDER)) {
1055*5113495bSYour Name 		osif_err_rl("TWT setup reject: TWT responder not supported");
1056*5113495bSYour Name 		return -EOPNOTSUPP;
1057*5113495bSYour Name 	}
1058*5113495bSYour Name 
1059*5113495bSYour Name 	ret = osif_is_twt_command_allowed(vdev, vdev_id, psoc);
1060*5113495bSYour Name 	if (ret)
1061*5113495bSYour Name 		return ret;
1062*5113495bSYour Name 
1063*5113495bSYour Name 	if (osif_twt_setup_conc_allowed(psoc, vdev_id)) {
1064*5113495bSYour Name 		osif_err_rl("TWT setup reject: SCC or MCC concurrency exists");
1065*5113495bSYour Name 		return -EAGAIN;
1066*5113495bSYour Name 	}
1067*5113495bSYour Name 
1068*5113495bSYour Name 	ucfg_twt_cfg_get_congestion_timeout(psoc, &congestion_timeout);
1069*5113495bSYour Name 
1070*5113495bSYour Name 	if (congestion_timeout) {
1071*5113495bSYour Name 		reason = HOST_TWT_DISABLE_REASON_CHANGE_CONGESTION_TIMEOUT;
1072*5113495bSYour Name 		ret = osif_twt_send_requestor_disable_cmd(psoc, pdev_id,
1073*5113495bSYour Name 							  reason);
1074*5113495bSYour Name 		if (ret) {
1075*5113495bSYour Name 			osif_err("Failed to disable TWT");
1076*5113495bSYour Name 			return ret;
1077*5113495bSYour Name 		}
1078*5113495bSYour Name 	}
1079*5113495bSYour Name 
1080*5113495bSYour Name 	ucfg_twt_cfg_set_congestion_timeout(psoc, 0);
1081*5113495bSYour Name 
1082*5113495bSYour Name 	ret = osif_twt_send_requestor_enable_cmd(psoc, pdev_id);
1083*5113495bSYour Name 	if (ret) {
1084*5113495bSYour Name 		osif_err("Failed to Enable TWT");
1085*5113495bSYour Name 		return ret;
1086*5113495bSYour Name 	}
1087*5113495bSYour Name 
1088*5113495bSYour Name 	return osif_send_twt_setup_req(vdev, psoc, &params);
1089*5113495bSYour Name }
1090*5113495bSYour Name 
1091*5113495bSYour Name /**
1092*5113495bSYour Name  * osif_twt_handle_renego_failure() - Upon re-nego failure send TWT teardown
1093*5113495bSYour Name  * @psoc: Pointer to psoc object
1094*5113495bSYour Name  * @event: Pointer to Add dialog complete event structure
1095*5113495bSYour Name  *
1096*5113495bSYour Name  * Upon re-negotiation failure, this function constructs TWT teardown
1097*5113495bSYour Name  * message to the target.
1098*5113495bSYour Name  *
1099*5113495bSYour Name  * Return: None
1100*5113495bSYour Name  */
1101*5113495bSYour Name void
osif_twt_handle_renego_failure(struct wlan_objmgr_psoc * psoc,struct twt_add_dialog_complete_event * event)1102*5113495bSYour Name osif_twt_handle_renego_failure(struct wlan_objmgr_psoc *psoc,
1103*5113495bSYour Name 		       struct twt_add_dialog_complete_event *event)
1104*5113495bSYour Name {
1105*5113495bSYour Name 	uint8_t pdev_id;
1106*5113495bSYour Name 	struct wlan_objmgr_pdev *pdev;
1107*5113495bSYour Name 	struct wlan_objmgr_vdev *vdev;
1108*5113495bSYour Name 	uint32_t vdev_id;
1109*5113495bSYour Name 
1110*5113495bSYour Name 	if (!event)
1111*5113495bSYour Name 		return;
1112*5113495bSYour Name 
1113*5113495bSYour Name 	vdev_id = event->params.vdev_id;
1114*5113495bSYour Name 	pdev_id = wlan_get_pdev_id_from_vdev_id(psoc, vdev_id,
1115*5113495bSYour Name 						WLAN_TWT_ID);
1116*5113495bSYour Name 	if (pdev_id == WLAN_INVALID_PDEV_ID) {
1117*5113495bSYour Name 		osif_err("Invalid pdev id");
1118*5113495bSYour Name 		return;
1119*5113495bSYour Name 	}
1120*5113495bSYour Name 
1121*5113495bSYour Name 	pdev = wlan_objmgr_get_pdev_by_id(psoc, pdev_id, WLAN_TWT_ID);
1122*5113495bSYour Name 	if (!pdev) {
1123*5113495bSYour Name 		osif_err("Invalid pdev");
1124*5113495bSYour Name 		return;
1125*5113495bSYour Name 	}
1126*5113495bSYour Name 
1127*5113495bSYour Name 	vdev = wlan_objmgr_get_vdev_by_id_from_pdev(pdev, vdev_id,
1128*5113495bSYour Name 						    WLAN_TWT_ID);
1129*5113495bSYour Name 	if (!vdev) {
1130*5113495bSYour Name 		osif_err("vdev object is NULL");
1131*5113495bSYour Name 		goto end;
1132*5113495bSYour Name 	}
1133*5113495bSYour Name 
1134*5113495bSYour Name 	osif_send_twt_delete_cmd(vdev, &event->params.peer_macaddr,
1135*5113495bSYour Name 				 event->params.dialog_id, false);
1136*5113495bSYour Name 
1137*5113495bSYour Name 	wlan_objmgr_vdev_release_ref(vdev, WLAN_TWT_ID);
1138*5113495bSYour Name 
1139*5113495bSYour Name end:
1140*5113495bSYour Name 	wlan_objmgr_pdev_release_ref(pdev, WLAN_TWT_ID);
1141*5113495bSYour Name }
1142*5113495bSYour Name 
osif_twt_sap_teardown_req(struct wlan_objmgr_vdev * vdev,struct nlattr * twt_param_attr)1143*5113495bSYour Name int osif_twt_sap_teardown_req(struct wlan_objmgr_vdev *vdev,
1144*5113495bSYour Name 			      struct nlattr *twt_param_attr)
1145*5113495bSYour Name {
1146*5113495bSYour Name 	struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX + 1];
1147*5113495bSYour Name 	struct wlan_objmgr_psoc *psoc;
1148*5113495bSYour Name 	int id, id1, ret = 0;
1149*5113495bSYour Name 	uint8_t vdev_id;
1150*5113495bSYour Name 	struct twt_del_dialog_param params = {0};
1151*5113495bSYour Name 	QDF_STATUS status;
1152*5113495bSYour Name 
1153*5113495bSYour Name 	psoc = wlan_vdev_get_psoc(vdev);
1154*5113495bSYour Name 	if (!psoc) {
1155*5113495bSYour Name 		osif_err("NULL psoc");
1156*5113495bSYour Name 		return -EINVAL;
1157*5113495bSYour Name 	}
1158*5113495bSYour Name 
1159*5113495bSYour Name 	vdev_id = wlan_vdev_get_id(vdev);
1160*5113495bSYour Name 	params.vdev_id = vdev_id;
1161*5113495bSYour Name 
1162*5113495bSYour Name 	ret = wlan_cfg80211_nla_parse_nested(tb,
1163*5113495bSYour Name 					 QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX,
1164*5113495bSYour Name 					 twt_param_attr,
1165*5113495bSYour Name 					 qca_wlan_vendor_twt_add_dialog_policy);
1166*5113495bSYour Name 	if (ret)
1167*5113495bSYour Name 		return ret;
1168*5113495bSYour Name 
1169*5113495bSYour Name 	id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID;
1170*5113495bSYour Name 	id1 = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAC_ADDR;
1171*5113495bSYour Name 	if (tb[id] && tb[id1]) {
1172*5113495bSYour Name 		params.dialog_id = nla_get_u8(tb[id]);
1173*5113495bSYour Name 		nla_memcpy(params.peer_macaddr.bytes, tb[id1],
1174*5113495bSYour Name 			   QDF_MAC_ADDR_SIZE);
1175*5113495bSYour Name 	} else if (!tb[id] && !tb[id1]) {
1176*5113495bSYour Name 		struct qdf_mac_addr bcast_addr = QDF_MAC_ADDR_BCAST_INIT;
1177*5113495bSYour Name 
1178*5113495bSYour Name 		params.dialog_id = TWT_ALL_SESSIONS_DIALOG_ID;
1179*5113495bSYour Name 		qdf_copy_macaddr(&params.peer_macaddr, &bcast_addr);
1180*5113495bSYour Name 	} else {
1181*5113495bSYour Name 		osif_err_rl("get_params dialog_id or mac_addr is missing");
1182*5113495bSYour Name 		return -EINVAL;
1183*5113495bSYour Name 	}
1184*5113495bSYour Name 
1185*5113495bSYour Name 	if (!params.dialog_id)
1186*5113495bSYour Name 		params.dialog_id = TWT_ALL_SESSIONS_DIALOG_ID;
1187*5113495bSYour Name 
1188*5113495bSYour Name 	if (params.dialog_id != TWT_ALL_SESSIONS_DIALOG_ID &&
1189*5113495bSYour Name 	    qdf_is_macaddr_broadcast(&params.peer_macaddr)) {
1190*5113495bSYour Name 		osif_err("Bcast MAC valid with dlg_id:%d but here dlg_id is:%d",
1191*5113495bSYour Name 			TWT_ALL_SESSIONS_DIALOG_ID, params.dialog_id);
1192*5113495bSYour Name 		return -EINVAL;
1193*5113495bSYour Name 	}
1194*5113495bSYour Name 
1195*5113495bSYour Name 	osif_debug("vdev_id %d dialog_id %d peer mac_addr "
1196*5113495bSYour Name 		  QDF_MAC_ADDR_FMT, params.vdev_id, params.dialog_id,
1197*5113495bSYour Name 		  QDF_MAC_ADDR_REF(params.peer_macaddr.bytes));
1198*5113495bSYour Name 
1199*5113495bSYour Name 	status = ucfg_twt_teardown_req(psoc, &params, NULL);
1200*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
1201*5113495bSYour Name 		osif_err("Failed to send del dialog command");
1202*5113495bSYour Name 		ret = qdf_status_to_os_return(status);
1203*5113495bSYour Name 	}
1204*5113495bSYour Name 
1205*5113495bSYour Name 	return ret;
1206*5113495bSYour Name }
1207*5113495bSYour Name 
osif_twt_sta_teardown_req(struct wlan_objmgr_vdev * vdev,struct nlattr * twt_param_attr)1208*5113495bSYour Name int osif_twt_sta_teardown_req(struct wlan_objmgr_vdev *vdev,
1209*5113495bSYour Name 			      struct nlattr *twt_param_attr)
1210*5113495bSYour Name {
1211*5113495bSYour Name 	struct nlattr *tb2[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX + 1];
1212*5113495bSYour Name 	struct wlan_objmgr_psoc *psoc;
1213*5113495bSYour Name 	int ret = 0;
1214*5113495bSYour Name 	uint8_t vdev_id, pdev_id;
1215*5113495bSYour Name 	struct twt_del_dialog_param params = {0};
1216*5113495bSYour Name 
1217*5113495bSYour Name 	psoc = wlan_vdev_get_psoc(vdev);
1218*5113495bSYour Name 	if (!psoc) {
1219*5113495bSYour Name 		osif_err("NULL psoc");
1220*5113495bSYour Name 		return -EINVAL;
1221*5113495bSYour Name 	}
1222*5113495bSYour Name 
1223*5113495bSYour Name 	vdev_id = wlan_vdev_get_id(vdev);
1224*5113495bSYour Name 
1225*5113495bSYour Name 	if (!wlan_cm_is_vdev_connected(vdev)) {
1226*5113495bSYour Name 		osif_err_rl("Not associated!, vdev %d", vdev_id);
1227*5113495bSYour Name 		/*
1228*5113495bSYour Name 		 * Return success, since STA is not associated and there is
1229*5113495bSYour Name 		 * no TWT session.
1230*5113495bSYour Name 		 */
1231*5113495bSYour Name 		return 0;
1232*5113495bSYour Name 	}
1233*5113495bSYour Name 
1234*5113495bSYour Name 	if (wlan_cm_host_roam_in_progress(psoc, vdev_id))
1235*5113495bSYour Name 		return -EBUSY;
1236*5113495bSYour Name 
1237*5113495bSYour Name 	if (wlan_get_vdev_status(vdev)) {
1238*5113495bSYour Name 		osif_err_rl("Scan in progress");
1239*5113495bSYour Name 		return -EBUSY;
1240*5113495bSYour Name 	}
1241*5113495bSYour Name 
1242*5113495bSYour Name 	ret = wlan_cfg80211_nla_parse_nested(tb2,
1243*5113495bSYour Name 					 QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX,
1244*5113495bSYour Name 					 twt_param_attr,
1245*5113495bSYour Name 					 qca_wlan_vendor_twt_add_dialog_policy);
1246*5113495bSYour Name 	if (ret)
1247*5113495bSYour Name 		return ret;
1248*5113495bSYour Name 
1249*5113495bSYour Name 	ret = osif_fill_peer_macaddr(vdev, params.peer_macaddr.bytes);
1250*5113495bSYour Name 	if (ret)
1251*5113495bSYour Name 		return ret;
1252*5113495bSYour Name 
1253*5113495bSYour Name 	params.vdev_id = vdev_id;
1254*5113495bSYour Name 	pdev_id = wlan_get_pdev_id_from_vdev_id(psoc, vdev_id, WLAN_TWT_ID);
1255*5113495bSYour Name 
1256*5113495bSYour Name 	ret = osif_twt_parse_del_dialog_attrs(tb2, &params);
1257*5113495bSYour Name 	if (ret)
1258*5113495bSYour Name 		return ret;
1259*5113495bSYour Name 
1260*5113495bSYour Name 	return osif_send_sta_twt_teardown_req(vdev, psoc, &params);
1261*5113495bSYour Name }
1262*5113495bSYour Name 
1263*5113495bSYour Name static void
osif_twt_concurrency_update_on_scc(struct wlan_objmgr_pdev * pdev,void * object,void * arg)1264*5113495bSYour Name osif_twt_concurrency_update_on_scc(struct wlan_objmgr_pdev *pdev,
1265*5113495bSYour Name 				   void *object, void *arg)
1266*5113495bSYour Name {
1267*5113495bSYour Name 	struct wlan_objmgr_vdev *vdev = object;
1268*5113495bSYour Name 	struct twt_conc_context *twt_arg = arg;
1269*5113495bSYour Name 	QDF_STATUS status;
1270*5113495bSYour Name 	uint8_t pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev);
1271*5113495bSYour Name 	uint32_t reason;
1272*5113495bSYour Name 
1273*5113495bSYour Name 	if (vdev->vdev_mlme.vdev_opmode == QDF_SAP_MODE &&
1274*5113495bSYour Name 	    vdev->vdev_mlme.mlme_state == WLAN_VDEV_S_UP) {
1275*5113495bSYour Name 		osif_debug("Concurrency exist on SAP vdev");
1276*5113495bSYour Name 		reason = HOST_TWT_DISABLE_REASON_CONCURRENCY_SCC;
1277*5113495bSYour Name 		status = osif_twt_send_responder_disable_cmd(twt_arg->psoc,
1278*5113495bSYour Name 							     pdev_id, reason);
1279*5113495bSYour Name 		if (QDF_IS_STATUS_ERROR(status)) {
1280*5113495bSYour Name 			osif_err("TWT responder disable cmd to fw failed");
1281*5113495bSYour Name 			return;
1282*5113495bSYour Name 		}
1283*5113495bSYour Name 		ucfg_twt_update_beacon_template();
1284*5113495bSYour Name 	}
1285*5113495bSYour Name 
1286*5113495bSYour Name 	if (vdev->vdev_mlme.vdev_opmode == QDF_STA_MODE &&
1287*5113495bSYour Name 	    vdev->vdev_mlme.mlme_state == WLAN_VDEV_S_UP) {
1288*5113495bSYour Name 		osif_debug("Concurrency exist on STA vdev");
1289*5113495bSYour Name 		reason = HOST_TWT_DISABLE_REASON_CONCURRENCY_SCC;
1290*5113495bSYour Name 		status = osif_twt_send_requestor_disable_cmd(twt_arg->psoc,
1291*5113495bSYour Name 							     pdev_id, reason);
1292*5113495bSYour Name 		if (QDF_IS_STATUS_ERROR(status)) {
1293*5113495bSYour Name 			osif_err("TWT requestor disable cmd to fw failed");
1294*5113495bSYour Name 			return;
1295*5113495bSYour Name 		}
1296*5113495bSYour Name 	}
1297*5113495bSYour Name }
1298*5113495bSYour Name 
1299*5113495bSYour Name static void
osif_twt_concurrency_update_on_mcc(struct wlan_objmgr_pdev * pdev,void * object,void * arg)1300*5113495bSYour Name osif_twt_concurrency_update_on_mcc(struct wlan_objmgr_pdev *pdev,
1301*5113495bSYour Name 				   void *object, void *arg)
1302*5113495bSYour Name {
1303*5113495bSYour Name 	struct wlan_objmgr_vdev *vdev = object;
1304*5113495bSYour Name 	struct twt_conc_context *twt_arg = arg;
1305*5113495bSYour Name 	QDF_STATUS status;
1306*5113495bSYour Name 	uint8_t pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev);
1307*5113495bSYour Name 	uint32_t reason;
1308*5113495bSYour Name 	uint8_t vdev_id;
1309*5113495bSYour Name 	struct wlan_objmgr_psoc *psoc;
1310*5113495bSYour Name 
1311*5113495bSYour Name 	vdev_id = wlan_vdev_get_id(vdev);
1312*5113495bSYour Name 	psoc = wlan_pdev_get_psoc(pdev);
1313*5113495bSYour Name 
1314*5113495bSYour Name 	if (vdev->vdev_mlme.vdev_opmode == QDF_SAP_MODE &&
1315*5113495bSYour Name 	    vdev->vdev_mlme.mlme_state == WLAN_VDEV_S_UP) {
1316*5113495bSYour Name 		if (policy_mgr_is_vdev_ll_lt_sap(psoc, vdev_id))
1317*5113495bSYour Name 			return;
1318*5113495bSYour Name 
1319*5113495bSYour Name 		osif_debug("Concurrency exist on SAP vdev");
1320*5113495bSYour Name 		reason = HOST_TWT_DISABLE_REASON_CONCURRENCY_MCC;
1321*5113495bSYour Name 		status = osif_twt_send_responder_disable_cmd(twt_arg->psoc,
1322*5113495bSYour Name 							     pdev_id, reason);
1323*5113495bSYour Name 		if (QDF_IS_STATUS_ERROR(status)) {
1324*5113495bSYour Name 			osif_err("TWT responder disable cmd to fw failed");
1325*5113495bSYour Name 			return;
1326*5113495bSYour Name 		}
1327*5113495bSYour Name 		ucfg_twt_update_beacon_template();
1328*5113495bSYour Name 	}
1329*5113495bSYour Name 
1330*5113495bSYour Name 	if (vdev->vdev_mlme.vdev_opmode == QDF_STA_MODE &&
1331*5113495bSYour Name 	    vdev->vdev_mlme.mlme_state == WLAN_VDEV_S_UP) {
1332*5113495bSYour Name 		osif_debug("Concurrency exist on STA vdev");
1333*5113495bSYour Name 		reason = HOST_TWT_DISABLE_REASON_CONCURRENCY_MCC;
1334*5113495bSYour Name 		status = osif_twt_send_requestor_disable_cmd(twt_arg->psoc,
1335*5113495bSYour Name 							     pdev_id, reason);
1336*5113495bSYour Name 		if (QDF_IS_STATUS_ERROR(status)) {
1337*5113495bSYour Name 			osif_err("TWT requestor disable cmd to fw failed");
1338*5113495bSYour Name 			return;
1339*5113495bSYour Name 		}
1340*5113495bSYour Name 	}
1341*5113495bSYour Name }
1342*5113495bSYour Name 
1343*5113495bSYour Name static void
osif_twt_concurrency_update_on_dbs(struct wlan_objmgr_pdev * pdev,void * object,void * arg)1344*5113495bSYour Name osif_twt_concurrency_update_on_dbs(struct wlan_objmgr_pdev *pdev,
1345*5113495bSYour Name 				   void *object, void *arg)
1346*5113495bSYour Name {
1347*5113495bSYour Name 	struct wlan_objmgr_vdev *vdev = object;
1348*5113495bSYour Name 	struct twt_conc_context *twt_arg = arg;
1349*5113495bSYour Name 	QDF_STATUS status;
1350*5113495bSYour Name 	uint8_t pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev);
1351*5113495bSYour Name 
1352*5113495bSYour Name 	if (vdev->vdev_mlme.vdev_opmode == QDF_SAP_MODE &&
1353*5113495bSYour Name 	    vdev->vdev_mlme.mlme_state == WLAN_VDEV_S_UP) {
1354*5113495bSYour Name 		osif_debug("SAP vdev exist");
1355*5113495bSYour Name 		status = osif_twt_send_responder_enable_cmd(twt_arg->psoc,
1356*5113495bSYour Name 							    pdev_id);
1357*5113495bSYour Name 		if (QDF_IS_STATUS_ERROR(status)) {
1358*5113495bSYour Name 			osif_err("TWT responder enable cmd to firmware failed");
1359*5113495bSYour Name 			return;
1360*5113495bSYour Name 		}
1361*5113495bSYour Name 		ucfg_twt_update_beacon_template();
1362*5113495bSYour Name 	}
1363*5113495bSYour Name 
1364*5113495bSYour Name 	if (vdev->vdev_mlme.vdev_opmode == QDF_STA_MODE &&
1365*5113495bSYour Name 	    vdev->vdev_mlme.mlme_state == WLAN_VDEV_S_UP) {
1366*5113495bSYour Name 		osif_debug("STA vdev exist");
1367*5113495bSYour Name 		status = osif_twt_send_requestor_enable_cmd(twt_arg->psoc,
1368*5113495bSYour Name 							    pdev_id);
1369*5113495bSYour Name 		if (QDF_IS_STATUS_ERROR(status)) {
1370*5113495bSYour Name 			osif_err("TWT requestor enable cmd to firmware failed");
1371*5113495bSYour Name 			return;
1372*5113495bSYour Name 		}
1373*5113495bSYour Name 	}
1374*5113495bSYour Name }
1375*5113495bSYour Name 
osif_twt_concurrency_update_handler(struct wlan_objmgr_psoc * psoc,struct wlan_objmgr_pdev * pdev)1376*5113495bSYour Name void osif_twt_concurrency_update_handler(struct wlan_objmgr_psoc *psoc,
1377*5113495bSYour Name 					 struct wlan_objmgr_pdev *pdev)
1378*5113495bSYour Name {
1379*5113495bSYour Name 	uint32_t num_connections, sap_count, sta_count;
1380*5113495bSYour Name 	QDF_STATUS status;
1381*5113495bSYour Name 	struct twt_conc_context twt_arg;
1382*5113495bSYour Name 	uint8_t pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev);
1383*5113495bSYour Name 
1384*5113495bSYour Name 	num_connections = policy_mgr_get_connection_count(psoc);
1385*5113495bSYour Name 	sta_count = policy_mgr_mode_specific_connection_count(psoc,
1386*5113495bSYour Name 							      PM_STA_MODE,
1387*5113495bSYour Name 							      NULL);
1388*5113495bSYour Name 	sap_count = policy_mgr_get_sap_mode_count(psoc, NULL);
1389*5113495bSYour Name 
1390*5113495bSYour Name 	twt_arg.psoc = psoc;
1391*5113495bSYour Name 
1392*5113495bSYour Name 	osif_debug("Total connection %d, sta_count %d, sap_count %d",
1393*5113495bSYour Name 		  num_connections, sta_count, sap_count);
1394*5113495bSYour Name 	switch (num_connections) {
1395*5113495bSYour Name 	case 1:
1396*5113495bSYour Name 		if (sta_count == 1) {
1397*5113495bSYour Name 			osif_twt_send_requestor_enable_cmd(psoc, pdev_id);
1398*5113495bSYour Name 		} else if (sap_count == 1) {
1399*5113495bSYour Name 			osif_twt_send_responder_enable_cmd(psoc, pdev_id);
1400*5113495bSYour Name 			ucfg_twt_update_beacon_template();
1401*5113495bSYour Name 		}
1402*5113495bSYour Name 		break;
1403*5113495bSYour Name 	case 2:
1404*5113495bSYour Name 		if (policy_mgr_current_concurrency_is_scc(psoc)) {
1405*5113495bSYour Name 			status = wlan_objmgr_pdev_iterate_obj_list(
1406*5113495bSYour Name 					pdev,
1407*5113495bSYour Name 					WLAN_VDEV_OP,
1408*5113495bSYour Name 					osif_twt_concurrency_update_on_scc,
1409*5113495bSYour Name 					&twt_arg, 0,
1410*5113495bSYour Name 					WLAN_TWT_ID);
1411*5113495bSYour Name 			if (QDF_IS_STATUS_ERROR(status)) {
1412*5113495bSYour Name 				osif_err("2port conc: SAP/STA not in SCC");
1413*5113495bSYour Name 				return;
1414*5113495bSYour Name 			}
1415*5113495bSYour Name 		} else if (policy_mgr_current_concurrency_is_mcc(psoc)) {
1416*5113495bSYour Name 			status = wlan_objmgr_pdev_iterate_obj_list(
1417*5113495bSYour Name 					pdev,
1418*5113495bSYour Name 					WLAN_VDEV_OP,
1419*5113495bSYour Name 					osif_twt_concurrency_update_on_mcc,
1420*5113495bSYour Name 					&twt_arg, 0,
1421*5113495bSYour Name 					WLAN_TWT_ID);
1422*5113495bSYour Name 			if (QDF_IS_STATUS_ERROR(status)) {
1423*5113495bSYour Name 				osif_err("2port conc: SAP/STA not in MCC");
1424*5113495bSYour Name 				return;
1425*5113495bSYour Name 			}
1426*5113495bSYour Name 		} else if (policy_mgr_is_current_hwmode_dbs(psoc)) {
1427*5113495bSYour Name 			status = wlan_objmgr_pdev_iterate_obj_list(
1428*5113495bSYour Name 					pdev,
1429*5113495bSYour Name 					WLAN_VDEV_OP,
1430*5113495bSYour Name 					osif_twt_concurrency_update_on_dbs,
1431*5113495bSYour Name 					&twt_arg, 0,
1432*5113495bSYour Name 					WLAN_TWT_ID);
1433*5113495bSYour Name 			if (QDF_IS_STATUS_ERROR(status)) {
1434*5113495bSYour Name 				osif_err("SAP not in DBS case");
1435*5113495bSYour Name 				return;
1436*5113495bSYour Name 			}
1437*5113495bSYour Name 		}
1438*5113495bSYour Name 		break;
1439*5113495bSYour Name 	case 3:
1440*5113495bSYour Name 		if (policy_mgr_current_concurrency_is_scc(psoc)) {
1441*5113495bSYour Name 			status = wlan_objmgr_pdev_iterate_obj_list(
1442*5113495bSYour Name 					pdev,
1443*5113495bSYour Name 					WLAN_VDEV_OP,
1444*5113495bSYour Name 					osif_twt_concurrency_update_on_scc,
1445*5113495bSYour Name 					&twt_arg, 0,
1446*5113495bSYour Name 					WLAN_TWT_ID);
1447*5113495bSYour Name 			if (QDF_IS_STATUS_ERROR(status)) {
1448*5113495bSYour Name 				osif_err("3port conc: SAP/STA not in SCC");
1449*5113495bSYour Name 				return;
1450*5113495bSYour Name 			}
1451*5113495bSYour Name 		} else if (policy_mgr_current_concurrency_is_mcc(psoc)) {
1452*5113495bSYour Name 			status = wlan_objmgr_pdev_iterate_obj_list(
1453*5113495bSYour Name 					pdev,
1454*5113495bSYour Name 					WLAN_VDEV_OP,
1455*5113495bSYour Name 					osif_twt_concurrency_update_on_mcc,
1456*5113495bSYour Name 					&twt_arg, 0,
1457*5113495bSYour Name 					WLAN_TWT_ID);
1458*5113495bSYour Name 			if (QDF_IS_STATUS_ERROR(status)) {
1459*5113495bSYour Name 				osif_err("3port conc: SAP/STA not in MCC");
1460*5113495bSYour Name 				return;
1461*5113495bSYour Name 			}
1462*5113495bSYour Name 		}
1463*5113495bSYour Name 		break;
1464*5113495bSYour Name 	default:
1465*5113495bSYour Name 		osif_debug("Unexpected number of connections: %d",
1466*5113495bSYour Name 			   num_connections);
1467*5113495bSYour Name 		break;
1468*5113495bSYour Name 	}
1469*5113495bSYour Name }
1470*5113495bSYour Name 
osif_twt_pause_req(struct wlan_objmgr_vdev * vdev,struct nlattr * twt_param_attr)1471*5113495bSYour Name int osif_twt_pause_req(struct wlan_objmgr_vdev *vdev,
1472*5113495bSYour Name 		       struct nlattr *twt_param_attr)
1473*5113495bSYour Name {
1474*5113495bSYour Name 	struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX + 1];
1475*5113495bSYour Name 	struct wlan_objmgr_psoc *psoc;
1476*5113495bSYour Name 	int ret = 0, id;
1477*5113495bSYour Name 	uint32_t vdev_id;
1478*5113495bSYour Name 	struct  twt_pause_dialog_cmd_param params = {0};
1479*5113495bSYour Name 
1480*5113495bSYour Name 	psoc = wlan_vdev_get_psoc(vdev);
1481*5113495bSYour Name 	if (!psoc) {
1482*5113495bSYour Name 		osif_err("NULL psoc");
1483*5113495bSYour Name 		return -EINVAL;
1484*5113495bSYour Name 	}
1485*5113495bSYour Name 
1486*5113495bSYour Name 	vdev_id = wlan_vdev_get_id(vdev);
1487*5113495bSYour Name 	ret = osif_is_twt_command_allowed(vdev, vdev_id, psoc);
1488*5113495bSYour Name 	if (ret)
1489*5113495bSYour Name 		return ret;
1490*5113495bSYour Name 
1491*5113495bSYour Name 	ret = osif_fill_peer_macaddr(vdev, params.peer_macaddr.bytes);
1492*5113495bSYour Name 	if (ret)
1493*5113495bSYour Name 		return ret;
1494*5113495bSYour Name 
1495*5113495bSYour Name 	if (twt_param_attr) {
1496*5113495bSYour Name 		ret = wlan_cfg80211_nla_parse_nested(tb,
1497*5113495bSYour Name 					QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX,
1498*5113495bSYour Name 					twt_param_attr,
1499*5113495bSYour Name 					qca_wlan_vendor_twt_add_dialog_policy);
1500*5113495bSYour Name 		if (ret)
1501*5113495bSYour Name 			return ret;
1502*5113495bSYour Name 
1503*5113495bSYour Name 		id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID;
1504*5113495bSYour Name 		if (tb[id])
1505*5113495bSYour Name 			params.dialog_id = nla_get_u8(tb[id]);
1506*5113495bSYour Name 		else
1507*5113495bSYour Name 			osif_debug("TWT: FLOW_ID not specified. set to zero");
1508*5113495bSYour Name 	} else {
1509*5113495bSYour Name 		osif_debug("TWT param not present. flow id set to zero");
1510*5113495bSYour Name 	}
1511*5113495bSYour Name 
1512*5113495bSYour Name 	osif_debug("twt_pause: vdev_id %d dialog_id %d peer mac_addr "
1513*5113495bSYour Name 		  QDF_MAC_ADDR_FMT, vdev_id, params.dialog_id,
1514*5113495bSYour Name 		  QDF_MAC_ADDR_REF(params.peer_macaddr.bytes));
1515*5113495bSYour Name 
1516*5113495bSYour Name 	return osif_send_twt_pause_req(vdev, psoc, &params);
1517*5113495bSYour Name }
1518*5113495bSYour Name 
osif_twt_resume_req(struct wlan_objmgr_vdev * vdev,struct nlattr * twt_param_attr)1519*5113495bSYour Name int osif_twt_resume_req(struct wlan_objmgr_vdev *vdev,
1520*5113495bSYour Name 		       struct nlattr *twt_param_attr)
1521*5113495bSYour Name {
1522*5113495bSYour Name 	struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX + 1];
1523*5113495bSYour Name 	struct wlan_objmgr_psoc *psoc;
1524*5113495bSYour Name 	int ret = 0;
1525*5113495bSYour Name 	uint32_t vdev_id;
1526*5113495bSYour Name 	int id, id2;
1527*5113495bSYour Name 	struct  twt_resume_dialog_cmd_param params = {0};
1528*5113495bSYour Name 
1529*5113495bSYour Name 	psoc = wlan_vdev_get_psoc(vdev);
1530*5113495bSYour Name 	if (!psoc) {
1531*5113495bSYour Name 		osif_err("NULL psoc");
1532*5113495bSYour Name 		return -EINVAL;
1533*5113495bSYour Name 	}
1534*5113495bSYour Name 
1535*5113495bSYour Name 	vdev_id = wlan_vdev_get_id(vdev);
1536*5113495bSYour Name 
1537*5113495bSYour Name 	ret = osif_is_twt_command_allowed(vdev, vdev_id, psoc);
1538*5113495bSYour Name 	if (ret)
1539*5113495bSYour Name 		return ret;
1540*5113495bSYour Name 
1541*5113495bSYour Name 	ret = osif_fill_peer_macaddr(vdev, params.peer_macaddr.bytes);
1542*5113495bSYour Name 	if (ret)
1543*5113495bSYour Name 		return ret;
1544*5113495bSYour Name 
1545*5113495bSYour Name 	ret = wlan_cfg80211_nla_parse_nested(tb,
1546*5113495bSYour Name 				QCA_WLAN_VENDOR_ATTR_TWT_RESUME_MAX,
1547*5113495bSYour Name 				twt_param_attr,
1548*5113495bSYour Name 				qca_wlan_vendor_twt_resume_dialog_policy);
1549*5113495bSYour Name 	if (ret)
1550*5113495bSYour Name 		return ret;
1551*5113495bSYour Name 
1552*5113495bSYour Name 	id = QCA_WLAN_VENDOR_ATTR_TWT_RESUME_FLOW_ID;
1553*5113495bSYour Name 	if (tb[id])
1554*5113495bSYour Name 		params.dialog_id = nla_get_u8(tb[id]);
1555*5113495bSYour Name 	else
1556*5113495bSYour Name 		osif_debug("TWT_RESUME_FLOW_ID not specified. set to zero");
1557*5113495bSYour Name 
1558*5113495bSYour Name 	id = QCA_WLAN_VENDOR_ATTR_TWT_RESUME_NEXT_TWT;
1559*5113495bSYour Name 	id2 = QCA_WLAN_VENDOR_ATTR_TWT_RESUME_NEXT2_TWT;
1560*5113495bSYour Name 	if (tb[id2])
1561*5113495bSYour Name 		params.sp_offset_us = nla_get_u32(tb[id2]);
1562*5113495bSYour Name 	else if (tb[id])
1563*5113495bSYour Name 		params.sp_offset_us = nla_get_u8(tb[id]);
1564*5113495bSYour Name 	else
1565*5113495bSYour Name 		params.sp_offset_us = 0;
1566*5113495bSYour Name 
1567*5113495bSYour Name 	id = QCA_WLAN_VENDOR_ATTR_TWT_RESUME_NEXT_TWT_SIZE;
1568*5113495bSYour Name 	if (tb[id]) {
1569*5113495bSYour Name 		params.next_twt_size = nla_get_u32(tb[id]);
1570*5113495bSYour Name 	} else {
1571*5113495bSYour Name 		osif_err_rl("TWT_RESUME NEXT_TWT_SIZE is must");
1572*5113495bSYour Name 		return -EINVAL;
1573*5113495bSYour Name 	}
1574*5113495bSYour Name 	if (params.next_twt_size > TWT_MAX_NEXT_TWT_SIZE)
1575*5113495bSYour Name 		return -EINVAL;
1576*5113495bSYour Name 
1577*5113495bSYour Name 	osif_debug("twt_resume: vdev_id %d dialog_id %d peer mac_addr "
1578*5113495bSYour Name 		   QDF_MAC_ADDR_FMT, vdev_id, params.dialog_id,
1579*5113495bSYour Name 		   QDF_MAC_ADDR_REF(params.peer_macaddr.bytes));
1580*5113495bSYour Name 
1581*5113495bSYour Name 	return osif_send_twt_resume_req(vdev, psoc, &params);
1582*5113495bSYour Name }
1583*5113495bSYour Name 
osif_twt_nudge_req(struct wlan_objmgr_vdev * vdev,struct nlattr * twt_param_attr)1584*5113495bSYour Name int osif_twt_nudge_req(struct wlan_objmgr_vdev *vdev,
1585*5113495bSYour Name 		       struct nlattr *twt_param_attr)
1586*5113495bSYour Name {
1587*5113495bSYour Name 	struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX + 1];
1588*5113495bSYour Name 	struct wlan_objmgr_psoc *psoc;
1589*5113495bSYour Name 	int ret = 0, id;
1590*5113495bSYour Name 	uint32_t vdev_id;
1591*5113495bSYour Name 	struct  twt_nudge_dialog_cmd_param params = {0};
1592*5113495bSYour Name 	QDF_STATUS status;
1593*5113495bSYour Name 
1594*5113495bSYour Name 	psoc = wlan_vdev_get_psoc(vdev);
1595*5113495bSYour Name 	if (!psoc) {
1596*5113495bSYour Name 		osif_err("NULL psoc");
1597*5113495bSYour Name 		return -EINVAL;
1598*5113495bSYour Name 	}
1599*5113495bSYour Name 
1600*5113495bSYour Name 	vdev_id = wlan_vdev_get_id(vdev);
1601*5113495bSYour Name 	ret = osif_is_twt_command_allowed(vdev, vdev_id, psoc);
1602*5113495bSYour Name 	if (ret)
1603*5113495bSYour Name 		return ret;
1604*5113495bSYour Name 
1605*5113495bSYour Name 	ret = wlan_cfg80211_nla_parse_nested(tb,
1606*5113495bSYour Name 				QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_MAX,
1607*5113495bSYour Name 				twt_param_attr,
1608*5113495bSYour Name 				qca_wlan_vendor_twt_nudge_dialog_policy);
1609*5113495bSYour Name 	if (ret)
1610*5113495bSYour Name 		return ret;
1611*5113495bSYour Name 
1612*5113495bSYour Name 	id = QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_MAC_ADDR;
1613*5113495bSYour Name 	if (tb[id]) {
1614*5113495bSYour Name 		nla_memcpy(params.peer_macaddr.bytes, tb[id],
1615*5113495bSYour Name 			   QDF_MAC_ADDR_SIZE);
1616*5113495bSYour Name 	} else {
1617*5113495bSYour Name 		ret = osif_fill_peer_macaddr(vdev, params.peer_macaddr.bytes);
1618*5113495bSYour Name 		if (ret)
1619*5113495bSYour Name 			return ret;
1620*5113495bSYour Name 	}
1621*5113495bSYour Name 
1622*5113495bSYour Name 	id = QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_FLOW_ID;
1623*5113495bSYour Name 	if (!tb[id]) {
1624*5113495bSYour Name 		osif_debug("TWT: FLOW_ID not specified");
1625*5113495bSYour Name 		return -EINVAL;
1626*5113495bSYour Name 	}
1627*5113495bSYour Name 	params.dialog_id = nla_get_u8(tb[id]);
1628*5113495bSYour Name 
1629*5113495bSYour Name 	id = QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_WAKE_TIME;
1630*5113495bSYour Name 	if (!tb[id]) {
1631*5113495bSYour Name 		osif_debug("TWT: NEXT_TWT_SIZE not specified");
1632*5113495bSYour Name 		return -EINVAL;
1633*5113495bSYour Name 	}
1634*5113495bSYour Name 
1635*5113495bSYour Name 	params.suspend_duration = nla_get_u32(tb[id]);
1636*5113495bSYour Name 
1637*5113495bSYour Name 	id = QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_NEXT_TWT_SIZE;
1638*5113495bSYour Name 	if (!tb[id]) {
1639*5113495bSYour Name 		osif_debug("TWT: NEXT_TWT_SIZE not specified");
1640*5113495bSYour Name 		return -EINVAL;
1641*5113495bSYour Name 	}
1642*5113495bSYour Name 	params.next_twt_size = nla_get_u32(tb[id]);
1643*5113495bSYour Name 
1644*5113495bSYour Name 	id = QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_SP_START_OFFSET;
1645*5113495bSYour Name 	if (tb[id]) {
1646*5113495bSYour Name 		uint8_t peer_cap = 0;
1647*5113495bSYour Name 
1648*5113495bSYour Name 		status = ucfg_twt_get_peer_capabilities(psoc,
1649*5113495bSYour Name 							&params.peer_macaddr,
1650*5113495bSYour Name 							&peer_cap);
1651*5113495bSYour Name 		if (QDF_IS_STATUS_SUCCESS(status) &&
1652*5113495bSYour Name 		    (peer_cap & WLAN_TWT_CAPA_FLEXIBLE)) {
1653*5113495bSYour Name 			params.sp_start_offset = nla_get_s32(tb[id]);
1654*5113495bSYour Name 		}
1655*5113495bSYour Name 	}
1656*5113495bSYour Name 
1657*5113495bSYour Name 	osif_debug("twt_nudge: vdev_id %d dialog_id %d ", params.vdev_id,
1658*5113495bSYour Name 		   params.dialog_id);
1659*5113495bSYour Name 	osif_debug("twt_nudge: suspend_duration %d next_twt_size %d",
1660*5113495bSYour Name 		   params.suspend_duration, params.next_twt_size);
1661*5113495bSYour Name 	osif_debug("peer mac_addr " QDF_MAC_ADDR_FMT,
1662*5113495bSYour Name 		   QDF_MAC_ADDR_REF(params.peer_macaddr.bytes));
1663*5113495bSYour Name 	osif_debug("twt_nudge: sp_start_offset %d", params.sp_start_offset);
1664*5113495bSYour Name 
1665*5113495bSYour Name 	return osif_send_twt_nudge_req(vdev, psoc, &params);
1666*5113495bSYour Name }
1667*5113495bSYour Name 
1668*5113495bSYour Name static uint32_t
osif_twt_get_params_resp_len(struct twt_session_stats_info * params)1669*5113495bSYour Name osif_twt_get_params_resp_len(struct twt_session_stats_info *params)
1670*5113495bSYour Name {
1671*5113495bSYour Name 	uint32_t len = nla_total_size(0);
1672*5113495bSYour Name 
1673*5113495bSYour Name 	/* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAC_ADDR */
1674*5113495bSYour Name 	len += nla_total_size(QDF_MAC_ADDR_SIZE);
1675*5113495bSYour Name 
1676*5113495bSYour Name 	/* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID */
1677*5113495bSYour Name 	len += nla_total_size(sizeof(u8));
1678*5113495bSYour Name 
1679*5113495bSYour Name 	/* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST */
1680*5113495bSYour Name 	len += nla_total_size(sizeof(u8));
1681*5113495bSYour Name 
1682*5113495bSYour Name 	/* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TRIGGER */
1683*5113495bSYour Name 	len += nla_total_size(sizeof(u8));
1684*5113495bSYour Name 
1685*5113495bSYour Name 	/* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_ANNOUNCE */
1686*5113495bSYour Name 	len += nla_total_size(sizeof(u8));
1687*5113495bSYour Name 
1688*5113495bSYour Name 	/* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_PROTECTION */
1689*5113495bSYour Name 	len += nla_total_size(sizeof(u8));
1690*5113495bSYour Name 
1691*5113495bSYour Name 	/* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TWT_INFO_ENABLED */
1692*5113495bSYour Name 	len += nla_total_size(sizeof(u8));
1693*5113495bSYour Name 
1694*5113495bSYour Name 	/* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_DURATION */
1695*5113495bSYour Name 	len += nla_total_size(sizeof(u32));
1696*5113495bSYour Name 
1697*5113495bSYour Name 	/* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_MANTISSA */
1698*5113495bSYour Name 	len += nla_total_size(sizeof(u32));
1699*5113495bSYour Name 
1700*5113495bSYour Name 	/*QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_EXP*/
1701*5113495bSYour Name 	len += nla_total_size(sizeof(u8));
1702*5113495bSYour Name 
1703*5113495bSYour Name 	/* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_TIME_TSF */
1704*5113495bSYour Name 	len += nla_total_size(sizeof(u64));
1705*5113495bSYour Name 
1706*5113495bSYour Name 	/* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_STATE */
1707*5113495bSYour Name 	len += nla_total_size(sizeof(u32));
1708*5113495bSYour Name 
1709*5113495bSYour Name 	/* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_TYPE */
1710*5113495bSYour Name 	len += nla_total_size(sizeof(u8));
1711*5113495bSYour Name 
1712*5113495bSYour Name 	/* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL2_MANTISSA */
1713*5113495bSYour Name 	len += nla_total_size(sizeof(u32));
1714*5113495bSYour Name 
1715*5113495bSYour Name 	/* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_RESPONDER_PM_MODE */
1716*5113495bSYour Name 	if (params->pm_responder_bit_valid)
1717*5113495bSYour Name 		len += nla_total_size(sizeof(u8));
1718*5113495bSYour Name 
1719*5113495bSYour Name 	return len;
1720*5113495bSYour Name }
1721*5113495bSYour Name 
1722*5113495bSYour Name static enum qca_wlan_twt_setup_state
osif_get_converted_twt_state(enum wlan_twt_session_state state)1723*5113495bSYour Name osif_get_converted_twt_state(enum wlan_twt_session_state state)
1724*5113495bSYour Name {
1725*5113495bSYour Name 	switch (state) {
1726*5113495bSYour Name 	case WLAN_TWT_SETUP_STATE_NOT_ESTABLISHED:
1727*5113495bSYour Name 		return QCA_WLAN_TWT_SETUP_STATE_NOT_ESTABLISHED;
1728*5113495bSYour Name 	case WLAN_TWT_SETUP_STATE_ACTIVE:
1729*5113495bSYour Name 		return QCA_WLAN_TWT_SETUP_STATE_ACTIVE;
1730*5113495bSYour Name 	case WLAN_TWT_SETUP_STATE_SUSPEND:
1731*5113495bSYour Name 		return QCA_WLAN_TWT_SETUP_STATE_SUSPEND;
1732*5113495bSYour Name 	default:
1733*5113495bSYour Name 		return QCA_WLAN_TWT_SETUP_STATE_NOT_ESTABLISHED;
1734*5113495bSYour Name 	}
1735*5113495bSYour Name }
1736*5113495bSYour Name 
1737*5113495bSYour Name static QDF_STATUS
osif_twt_pack_get_params_resp_nlmsg(struct wlan_objmgr_psoc * psoc,struct sk_buff * reply_skb,struct twt_session_stats_info * params,int num_twt_session)1738*5113495bSYour Name osif_twt_pack_get_params_resp_nlmsg(struct wlan_objmgr_psoc *psoc,
1739*5113495bSYour Name 				    struct sk_buff *reply_skb,
1740*5113495bSYour Name 				    struct twt_session_stats_info *params,
1741*5113495bSYour Name 				    int num_twt_session)
1742*5113495bSYour Name {
1743*5113495bSYour Name 	struct nlattr *config_attr, *nla_params;
1744*5113495bSYour Name 	enum wlan_twt_session_state state;
1745*5113495bSYour Name 	enum qca_wlan_twt_setup_state converted_state;
1746*5113495bSYour Name 	uint64_t tsf_val;
1747*5113495bSYour Name 	uint32_t wake_duration;
1748*5113495bSYour Name 	uint32_t wake_intvl_mantis_us, wake_intvl_mantis_tu;
1749*5113495bSYour Name 	int i, attr;
1750*5113495bSYour Name 
1751*5113495bSYour Name 	config_attr = nla_nest_start(reply_skb,
1752*5113495bSYour Name 				     QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS);
1753*5113495bSYour Name 	if (!config_attr) {
1754*5113495bSYour Name 		osif_err("TWT: get_params nla_nest_start error");
1755*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
1756*5113495bSYour Name 	}
1757*5113495bSYour Name 
1758*5113495bSYour Name 	for (i = 0; i < num_twt_session; i++) {
1759*5113495bSYour Name 		if (params[i].event_type != HOST_TWT_SESSION_SETUP &&
1760*5113495bSYour Name 		    params[i].event_type != HOST_TWT_SESSION_UPDATE)
1761*5113495bSYour Name 			continue;
1762*5113495bSYour Name 
1763*5113495bSYour Name 		nla_params = nla_nest_start(reply_skb, i);
1764*5113495bSYour Name 		if (!nla_params) {
1765*5113495bSYour Name 			osif_err("TWT: get_params nla_nest_start error");
1766*5113495bSYour Name 			return QDF_STATUS_E_INVAL;
1767*5113495bSYour Name 		}
1768*5113495bSYour Name 
1769*5113495bSYour Name 		attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAC_ADDR;
1770*5113495bSYour Name 		if (nla_put(reply_skb, attr, QDF_MAC_ADDR_SIZE,
1771*5113495bSYour Name 			    params[i].peer_mac.bytes)) {
1772*5113495bSYour Name 			osif_err("TWT: get_params failed to put mac_addr");
1773*5113495bSYour Name 			return QDF_STATUS_E_INVAL;
1774*5113495bSYour Name 		}
1775*5113495bSYour Name 
1776*5113495bSYour Name 		osif_debug("TWT: get_params peer mac_addr " QDF_MAC_ADDR_FMT,
1777*5113495bSYour Name 			   QDF_MAC_ADDR_REF(params[i].peer_mac.bytes));
1778*5113495bSYour Name 		attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID;
1779*5113495bSYour Name 		if (nla_put_u8(reply_skb, attr, params[i].dialog_id)) {
1780*5113495bSYour Name 			osif_err("TWT: get_params failed to put dialog_id");
1781*5113495bSYour Name 			return QDF_STATUS_E_INVAL;
1782*5113495bSYour Name 		}
1783*5113495bSYour Name 
1784*5113495bSYour Name 		if (params[i].bcast) {
1785*5113495bSYour Name 			attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST;
1786*5113495bSYour Name 			if (nla_put_flag(reply_skb, attr)) {
1787*5113495bSYour Name 				osif_err("TWT: get_params fail to put bcast");
1788*5113495bSYour Name 				return QDF_STATUS_E_INVAL;
1789*5113495bSYour Name 			}
1790*5113495bSYour Name 		}
1791*5113495bSYour Name 
1792*5113495bSYour Name 		if (params[i].trig) {
1793*5113495bSYour Name 			attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TRIGGER;
1794*5113495bSYour Name 			if (nla_put_flag(reply_skb, attr)) {
1795*5113495bSYour Name 				osif_err("TWT: get_params fail to put Trigger");
1796*5113495bSYour Name 				return QDF_STATUS_E_INVAL;
1797*5113495bSYour Name 			}
1798*5113495bSYour Name 		}
1799*5113495bSYour Name 
1800*5113495bSYour Name 		if (params[i].announ) {
1801*5113495bSYour Name 			attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_TYPE;
1802*5113495bSYour Name 			if (nla_put_flag(reply_skb, attr)) {
1803*5113495bSYour Name 				osif_err("TWT: get_params fail to put Announce");
1804*5113495bSYour Name 				return QDF_STATUS_E_INVAL;
1805*5113495bSYour Name 			}
1806*5113495bSYour Name 		}
1807*5113495bSYour Name 
1808*5113495bSYour Name 		if (params[i].protection) {
1809*5113495bSYour Name 			attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_PROTECTION;
1810*5113495bSYour Name 			if (nla_put_flag(reply_skb, attr)) {
1811*5113495bSYour Name 				osif_err("TWT: get_params fail to put Protect");
1812*5113495bSYour Name 				return QDF_STATUS_E_INVAL;
1813*5113495bSYour Name 			}
1814*5113495bSYour Name 		}
1815*5113495bSYour Name 
1816*5113495bSYour Name 		if (params[i].pm_responder_bit_valid) {
1817*5113495bSYour Name 			attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_RESPONDER_PM_MODE;
1818*5113495bSYour Name 			if (nla_put_u8(reply_skb, attr,
1819*5113495bSYour Name 				       params[i].pm_responder_bit)) {
1820*5113495bSYour Name 				osif_err("TWT: fail to put pm responder mode");
1821*5113495bSYour Name 				return QDF_STATUS_E_INVAL;
1822*5113495bSYour Name 			}
1823*5113495bSYour Name 		}
1824*5113495bSYour Name 
1825*5113495bSYour Name 		if (!params[i].info_frame_disabled) {
1826*5113495bSYour Name 			attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TWT_INFO_ENABLED;
1827*5113495bSYour Name 			if (nla_put_flag(reply_skb, attr)) {
1828*5113495bSYour Name 				osif_err("TWT: get_params put Info Enable fail");
1829*5113495bSYour Name 				return QDF_STATUS_E_INVAL;
1830*5113495bSYour Name 			}
1831*5113495bSYour Name 		}
1832*5113495bSYour Name 
1833*5113495bSYour Name 		attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_DURATION;
1834*5113495bSYour Name 		wake_duration = (params[i].wake_dura_us /
1835*5113495bSYour Name 				TWT_WAKE_DURATION_MULTIPLICATION_FACTOR);
1836*5113495bSYour Name 		if (nla_put_u32(reply_skb, attr, wake_duration)) {
1837*5113495bSYour Name 			osif_err("TWT: get_params failed to put Wake duration");
1838*5113495bSYour Name 			return QDF_STATUS_E_INVAL;
1839*5113495bSYour Name 		}
1840*5113495bSYour Name 
1841*5113495bSYour Name 		wake_intvl_mantis_us = params[i].wake_intvl_us;
1842*5113495bSYour Name 		attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL2_MANTISSA;
1843*5113495bSYour Name 		if (nla_put_u32(reply_skb, attr, wake_intvl_mantis_us)) {
1844*5113495bSYour Name 			osif_err("TWT: get_params failed to put Wake Interval in us");
1845*5113495bSYour Name 			return QDF_STATUS_E_INVAL;
1846*5113495bSYour Name 		}
1847*5113495bSYour Name 
1848*5113495bSYour Name 		wake_intvl_mantis_tu = params[i].wake_intvl_us /
1849*5113495bSYour Name 					TWT_WAKE_INTVL_MULTIPLICATION_FACTOR;
1850*5113495bSYour Name 		attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_MANTISSA;
1851*5113495bSYour Name 		if (nla_put_u32(reply_skb, attr, wake_intvl_mantis_tu)) {
1852*5113495bSYour Name 			osif_err("TWT: get_params failed to put Wake Interval");
1853*5113495bSYour Name 			return QDF_STATUS_E_INVAL;
1854*5113495bSYour Name 		}
1855*5113495bSYour Name 
1856*5113495bSYour Name 		osif_debug("TWT: Send mantissa_us:%d, mantissa_tu:%d to userspace",
1857*5113495bSYour Name 			   wake_intvl_mantis_us, wake_intvl_mantis_tu);
1858*5113495bSYour Name 		attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_EXP;
1859*5113495bSYour Name 		if (nla_put_u8(reply_skb, attr, 0)) {
1860*5113495bSYour Name 			osif_err("TWT: get_params put Wake Interval Exp failed");
1861*5113495bSYour Name 			return QDF_STATUS_E_INVAL;
1862*5113495bSYour Name 		}
1863*5113495bSYour Name 
1864*5113495bSYour Name 		tsf_val = ((uint64_t)params[i].sp_tsf_us_hi << 32) |
1865*5113495bSYour Name 			   params[i].sp_tsf_us_lo;
1866*5113495bSYour Name 		osif_debug("TWT: get_params dialog_id %d TSF = 0x%llx",
1867*5113495bSYour Name 			   params[i].dialog_id, tsf_val);
1868*5113495bSYour Name 		attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_TIME_TSF;
1869*5113495bSYour Name 		if (wlan_cfg80211_nla_put_u64(reply_skb, attr, tsf_val)) {
1870*5113495bSYour Name 			osif_err("TWT: get_params failed to put TSF Value");
1871*5113495bSYour Name 			return QDF_STATUS_E_INVAL;
1872*5113495bSYour Name 		}
1873*5113495bSYour Name 		attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_STATE;
1874*5113495bSYour Name 		state = ucfg_twt_get_session_state(psoc,
1875*5113495bSYour Name 				   &params[i].peer_mac,
1876*5113495bSYour Name 				   params[i].dialog_id);
1877*5113495bSYour Name 		converted_state = osif_get_converted_twt_state(state);
1878*5113495bSYour Name 		if (nla_put_u32(reply_skb, attr, converted_state)) {
1879*5113495bSYour Name 			osif_err("TWT: get_params failed to put TWT state");
1880*5113495bSYour Name 			return QDF_STATUS_E_INVAL;
1881*5113495bSYour Name 		}
1882*5113495bSYour Name 
1883*5113495bSYour Name 		nla_nest_end(reply_skb, nla_params);
1884*5113495bSYour Name 	}
1885*5113495bSYour Name 	nla_nest_end(reply_skb, config_attr);
1886*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
1887*5113495bSYour Name }
1888*5113495bSYour Name 
1889*5113495bSYour Name static QDF_STATUS
osif_twt_send_get_params_resp(struct wlan_objmgr_vdev * vdev,struct twt_session_stats_info * params,int num_twt_session)1890*5113495bSYour Name osif_twt_send_get_params_resp(struct wlan_objmgr_vdev *vdev,
1891*5113495bSYour Name 			      struct twt_session_stats_info *params,
1892*5113495bSYour Name 			      int num_twt_session)
1893*5113495bSYour Name {
1894*5113495bSYour Name 	struct wlan_objmgr_psoc *psoc;
1895*5113495bSYour Name 	struct vdev_osif_priv *osif_priv;
1896*5113495bSYour Name 	struct sk_buff *reply_skb;
1897*5113495bSYour Name 	uint32_t skb_len = NLMSG_HDRLEN, i;
1898*5113495bSYour Name 	QDF_STATUS qdf_status;
1899*5113495bSYour Name 	struct wireless_dev *wdev;
1900*5113495bSYour Name 
1901*5113495bSYour Name 	psoc = wlan_vdev_get_psoc(vdev);
1902*5113495bSYour Name 	if (!psoc)
1903*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
1904*5113495bSYour Name 
1905*5113495bSYour Name 	osif_priv = wlan_vdev_get_ospriv(vdev);
1906*5113495bSYour Name 	if (!osif_priv) {
1907*5113495bSYour Name 		osif_err("osif_priv is null");
1908*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
1909*5113495bSYour Name 	}
1910*5113495bSYour Name 
1911*5113495bSYour Name 	wdev = osif_priv->wdev;
1912*5113495bSYour Name 	if (!wdev) {
1913*5113495bSYour Name 		osif_err("wireless dev is null");
1914*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
1915*5113495bSYour Name 	}
1916*5113495bSYour Name 	/* Length of attribute QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS */
1917*5113495bSYour Name 	skb_len += NLA_HDRLEN;
1918*5113495bSYour Name 
1919*5113495bSYour Name 	/* Length of twt session parameters */
1920*5113495bSYour Name 	for (i = 0; i < num_twt_session; i++) {
1921*5113495bSYour Name 		if (params[i].event_type == HOST_TWT_SESSION_SETUP ||
1922*5113495bSYour Name 		    params[i].event_type == HOST_TWT_SESSION_UPDATE)
1923*5113495bSYour Name 			skb_len += osif_twt_get_params_resp_len(params + i);
1924*5113495bSYour Name 	}
1925*5113495bSYour Name 
1926*5113495bSYour Name 	reply_skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(wdev->wiphy,
1927*5113495bSYour Name 							     skb_len);
1928*5113495bSYour Name 	if (!reply_skb) {
1929*5113495bSYour Name 		osif_err("TWT: get_params alloc reply skb failed");
1930*5113495bSYour Name 		return QDF_STATUS_E_NOMEM;
1931*5113495bSYour Name 	}
1932*5113495bSYour Name 
1933*5113495bSYour Name 	qdf_status = osif_twt_pack_get_params_resp_nlmsg(psoc, reply_skb,
1934*5113495bSYour Name 							 params,
1935*5113495bSYour Name 							 num_twt_session);
1936*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(qdf_status))
1937*5113495bSYour Name 		goto fail;
1938*5113495bSYour Name 
1939*5113495bSYour Name 	if (wlan_cfg80211_vendor_cmd_reply(reply_skb))
1940*5113495bSYour Name 		qdf_status = QDF_STATUS_E_INVAL;
1941*5113495bSYour Name 
1942*5113495bSYour Name 	return qdf_status;
1943*5113495bSYour Name fail:
1944*5113495bSYour Name 	wlan_cfg80211_vendor_free_skb(reply_skb);
1945*5113495bSYour Name 	return qdf_status;
1946*5113495bSYour Name }
1947*5113495bSYour Name 
1948*5113495bSYour Name static QDF_STATUS
osif_twt_get_peer_session_params(struct wlan_objmgr_vdev * vdev,struct twt_session_stats_info * params)1949*5113495bSYour Name osif_twt_get_peer_session_params(struct wlan_objmgr_vdev *vdev,
1950*5113495bSYour Name 				 struct twt_session_stats_info *params)
1951*5113495bSYour Name {
1952*5113495bSYour Name 	struct wlan_objmgr_psoc *psoc;
1953*5113495bSYour Name 	int num_twt_session = 0;
1954*5113495bSYour Name 	QDF_STATUS qdf_status = QDF_STATUS_E_INVAL;
1955*5113495bSYour Name 
1956*5113495bSYour Name 	psoc = wlan_vdev_get_psoc(vdev);
1957*5113495bSYour Name 
1958*5113495bSYour Name 	if (!psoc)
1959*5113495bSYour Name 		return qdf_status;
1960*5113495bSYour Name 
1961*5113495bSYour Name 	num_twt_session = ucfg_cp_stats_twt_get_peer_session_params(psoc,
1962*5113495bSYour Name 								    params);
1963*5113495bSYour Name 
1964*5113495bSYour Name 	if (num_twt_session)
1965*5113495bSYour Name 		qdf_status = osif_twt_send_get_params_resp(vdev, params,
1966*5113495bSYour Name 							   num_twt_session);
1967*5113495bSYour Name 
1968*5113495bSYour Name 	return qdf_status;
1969*5113495bSYour Name }
1970*5113495bSYour Name 
1971*5113495bSYour Name static QDF_STATUS
osif_send_inactive_session_reply(struct wlan_objmgr_vdev * vdev,struct twt_session_stats_info * params)1972*5113495bSYour Name osif_send_inactive_session_reply(struct wlan_objmgr_vdev *vdev,
1973*5113495bSYour Name 				 struct twt_session_stats_info *params)
1974*5113495bSYour Name {
1975*5113495bSYour Name 	QDF_STATUS qdf_status;
1976*5113495bSYour Name 	int num_twt_session = 0;
1977*5113495bSYour Name 
1978*5113495bSYour Name 	params[num_twt_session].event_type = HOST_TWT_SESSION_UPDATE;
1979*5113495bSYour Name 	num_twt_session++;
1980*5113495bSYour Name 
1981*5113495bSYour Name 	qdf_status = osif_twt_send_get_params_resp(vdev, params,
1982*5113495bSYour Name 						   num_twt_session);
1983*5113495bSYour Name 
1984*5113495bSYour Name 	return qdf_status;
1985*5113495bSYour Name }
1986*5113495bSYour Name 
1987*5113495bSYour Name static int
osif_twt_sap_get_session_params(struct wlan_objmgr_vdev * vdev,struct nlattr * twt_param_attr)1988*5113495bSYour Name osif_twt_sap_get_session_params(struct wlan_objmgr_vdev *vdev,
1989*5113495bSYour Name 				struct nlattr *twt_param_attr)
1990*5113495bSYour Name {
1991*5113495bSYour Name 	struct wlan_objmgr_psoc *psoc;
1992*5113495bSYour Name 	struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX + 1];
1993*5113495bSYour Name 	uint16_t num_peer;
1994*5113495bSYour Name 	struct twt_session_stats_info *params;
1995*5113495bSYour Name 	int ret, id, id1;
1996*5113495bSYour Name 	QDF_STATUS qdf_status = QDF_STATUS_E_INVAL;
1997*5113495bSYour Name 	uint8_t vdev_id;
1998*5113495bSYour Name 
1999*5113495bSYour Name 	ret = wlan_cfg80211_nla_parse_nested(
2000*5113495bSYour Name 			tb, QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX,
2001*5113495bSYour Name 			twt_param_attr,
2002*5113495bSYour Name 			qca_wlan_vendor_twt_add_dialog_policy);
2003*5113495bSYour Name 
2004*5113495bSYour Name 	if (ret)
2005*5113495bSYour Name 		return ret;
2006*5113495bSYour Name 
2007*5113495bSYour Name 	psoc = wlan_vdev_get_psoc(vdev);
2008*5113495bSYour Name 	if (!psoc)
2009*5113495bSYour Name 		return -EINVAL;
2010*5113495bSYour Name 
2011*5113495bSYour Name 	num_peer = wlan_vdev_get_peer_count(vdev);
2012*5113495bSYour Name 	params = qdf_mem_malloc(TWT_PEER_MAX_SESSIONS * num_peer *
2013*5113495bSYour Name 				sizeof(*params));
2014*5113495bSYour Name 
2015*5113495bSYour Name 	if (!params)
2016*5113495bSYour Name 		return -ENOMEM;
2017*5113495bSYour Name 
2018*5113495bSYour Name 	vdev_id = wlan_vdev_get_id(vdev);
2019*5113495bSYour Name 	params[0].vdev_id = vdev_id;
2020*5113495bSYour Name 	id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID;
2021*5113495bSYour Name 	id1 = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAC_ADDR;
2022*5113495bSYour Name 
2023*5113495bSYour Name 	if (!tb[id] || !tb[id1]) {
2024*5113495bSYour Name 		osif_err_rl("TWT: get_params dialog_id or mac_addr is missing");
2025*5113495bSYour Name 		goto done;
2026*5113495bSYour Name 	}
2027*5113495bSYour Name 
2028*5113495bSYour Name 	params[0].dialog_id = nla_get_u8(tb[id]);
2029*5113495bSYour Name 	nla_memcpy(params[0].peer_mac.bytes, tb[id1], QDF_MAC_ADDR_SIZE);
2030*5113495bSYour Name 
2031*5113495bSYour Name 	if (qdf_is_macaddr_broadcast(&params[0].peer_mac) &&
2032*5113495bSYour Name 	    params[0].dialog_id != TWT_ALL_SESSIONS_DIALOG_ID) {
2033*5113495bSYour Name 		osif_err_rl("Bcast MAC valid with dlg_id:%d but here dlg_id is:%d",
2034*5113495bSYour Name 			TWT_ALL_SESSIONS_DIALOG_ID, params[0].dialog_id);
2035*5113495bSYour Name 		goto done;
2036*5113495bSYour Name 	}
2037*5113495bSYour Name 
2038*5113495bSYour Name 	if (!params[0].dialog_id)
2039*5113495bSYour Name 		params[0].dialog_id = TWT_ALL_SESSIONS_DIALOG_ID;
2040*5113495bSYour Name 
2041*5113495bSYour Name 	osif_debug("TWT: get_params dialog_id %d and mac_addr "QDF_MAC_ADDR_FMT,
2042*5113495bSYour Name 		   params[0].dialog_id,
2043*5113495bSYour Name 		   QDF_MAC_ADDR_REF(params[0].peer_mac.bytes));
2044*5113495bSYour Name 	qdf_status = osif_twt_get_peer_session_params(vdev, params);
2045*5113495bSYour Name 
2046*5113495bSYour Name done:
2047*5113495bSYour Name 	qdf_mem_free(params);
2048*5113495bSYour Name 	return qdf_status_to_os_return(qdf_status);
2049*5113495bSYour Name }
2050*5113495bSYour Name 
2051*5113495bSYour Name static int
osif_twt_sta_get_session_params(struct wlan_objmgr_vdev * vdev,struct nlattr * twt_param_attr)2052*5113495bSYour Name osif_twt_sta_get_session_params(struct wlan_objmgr_vdev *vdev,
2053*5113495bSYour Name 				struct nlattr *twt_param_attr)
2054*5113495bSYour Name {
2055*5113495bSYour Name 	struct wlan_objmgr_psoc *psoc;
2056*5113495bSYour Name 	struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX + 1];
2057*5113495bSYour Name 	struct twt_session_stats_info
2058*5113495bSYour Name 		params[TWT_PSOC_MAX_SESSIONS] = { {0} };
2059*5113495bSYour Name 	int ret, id;
2060*5113495bSYour Name 	QDF_STATUS qdf_status;
2061*5113495bSYour Name 	struct qdf_mac_addr bcast_addr = QDF_MAC_ADDR_BCAST_INIT;
2062*5113495bSYour Name 	struct qdf_mac_addr peer_mac;
2063*5113495bSYour Name 	uint8_t vdev_id;
2064*5113495bSYour Name 
2065*5113495bSYour Name 	ret = wlan_cfg80211_nla_parse_nested(tb,
2066*5113495bSYour Name 					 QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX,
2067*5113495bSYour Name 					 twt_param_attr,
2068*5113495bSYour Name 					 qca_wlan_vendor_twt_add_dialog_policy);
2069*5113495bSYour Name 	if (ret)
2070*5113495bSYour Name 		return ret;
2071*5113495bSYour Name 
2072*5113495bSYour Name 	psoc = wlan_vdev_get_psoc(vdev);
2073*5113495bSYour Name 	if (!psoc)
2074*5113495bSYour Name 		return -EINVAL;
2075*5113495bSYour Name 
2076*5113495bSYour Name 	vdev_id = wlan_vdev_get_id(vdev);
2077*5113495bSYour Name 	params[0].vdev_id = vdev_id;
2078*5113495bSYour Name 
2079*5113495bSYour Name 	/*
2080*5113495bSYour Name 	 * Currently twt_get_params nl cmd is sending only dialog_id(STA), fill
2081*5113495bSYour Name 	 * mac_addr of STA in params and call osif_twt_get_peer_session_params.
2082*5113495bSYour Name 	 * When twt_get_params passes mac_addr and dialog_id of STA/SAP, update
2083*5113495bSYour Name 	 * both mac_addr and dialog_id in params before calling
2084*5113495bSYour Name 	 * osif_twt_get_peer_session_params. dialog_id if not received,
2085*5113495bSYour Name 	 * dialog_id of value 0 will be used as default.
2086*5113495bSYour Name 	 */
2087*5113495bSYour Name 
2088*5113495bSYour Name 	id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID;
2089*5113495bSYour Name 	if (tb[id])
2090*5113495bSYour Name 		params[0].dialog_id = (uint32_t)nla_get_u8(tb[id]);
2091*5113495bSYour Name 	else
2092*5113495bSYour Name 		params[0].dialog_id = 0;
2093*5113495bSYour Name 
2094*5113495bSYour Name 	if (osif_fill_peer_macaddr(vdev, peer_mac.bytes))
2095*5113495bSYour Name 		return -EINVAL;
2096*5113495bSYour Name 
2097*5113495bSYour Name 	if (params[0].dialog_id <= TWT_MAX_DIALOG_ID) {
2098*5113495bSYour Name 		qdf_copy_macaddr(&params[0].peer_mac, &peer_mac);
2099*5113495bSYour Name 		osif_debug("TWT: get_params peer mac_addr " QDF_MAC_ADDR_FMT,
2100*5113495bSYour Name 			   QDF_MAC_ADDR_REF(params[0].peer_mac.bytes));
2101*5113495bSYour Name 	} else {
2102*5113495bSYour Name 		qdf_copy_macaddr(&params[0].peer_mac, &bcast_addr);
2103*5113495bSYour Name 	}
2104*5113495bSYour Name 
2105*5113495bSYour Name 	if (!ucfg_twt_is_setup_done(psoc, &peer_mac,
2106*5113495bSYour Name 				    params[0].dialog_id)) {
2107*5113495bSYour Name 		osif_debug("vdev%d: TWT session %d setup incomplete", vdev_id,
2108*5113495bSYour Name 			   params[0].dialog_id);
2109*5113495bSYour Name 		qdf_status = osif_send_inactive_session_reply(vdev, params);
2110*5113495bSYour Name 		return qdf_status_to_os_return(qdf_status);
2111*5113495bSYour Name 	}
2112*5113495bSYour Name 
2113*5113495bSYour Name 	osif_debug("TWT: get_params dialog_id %d and mac_addr "QDF_MAC_ADDR_FMT,
2114*5113495bSYour Name 		   params[0].dialog_id,
2115*5113495bSYour Name 		   QDF_MAC_ADDR_REF(params[0].peer_mac.bytes));
2116*5113495bSYour Name 
2117*5113495bSYour Name 	qdf_status = osif_twt_get_peer_session_params(vdev, params);
2118*5113495bSYour Name 
2119*5113495bSYour Name 	return qdf_status_to_os_return(qdf_status);
2120*5113495bSYour Name }
2121*5113495bSYour Name 
osif_twt_get_session_req(struct wlan_objmgr_vdev * vdev,struct nlattr * twt_param_attr)2122*5113495bSYour Name int osif_twt_get_session_req(struct wlan_objmgr_vdev *vdev,
2123*5113495bSYour Name 			     struct nlattr *twt_param_attr)
2124*5113495bSYour Name {
2125*5113495bSYour Name 	enum QDF_OPMODE device_mode;
2126*5113495bSYour Name 
2127*5113495bSYour Name 	device_mode = wlan_vdev_mlme_get_opmode(vdev);
2128*5113495bSYour Name 
2129*5113495bSYour Name 	switch (device_mode) {
2130*5113495bSYour Name 	case QDF_STA_MODE:
2131*5113495bSYour Name 		return osif_twt_sta_get_session_params(vdev, twt_param_attr);
2132*5113495bSYour Name 	case QDF_SAP_MODE:
2133*5113495bSYour Name 		return osif_twt_sap_get_session_params(vdev, twt_param_attr);
2134*5113495bSYour Name 	default:
2135*5113495bSYour Name 		osif_err_rl("TWT get session params is not supported on %s",
2136*5113495bSYour Name 			    qdf_opmode_str(device_mode));
2137*5113495bSYour Name 	}
2138*5113495bSYour Name 
2139*5113495bSYour Name 	return -EOPNOTSUPP;
2140*5113495bSYour Name }
2141*5113495bSYour Name 
2142*5113495bSYour Name /**
2143*5113495bSYour Name  * osif_twt_request_session_traffic_stats() - Obtains twt session traffic
2144*5113495bSYour Name  * statistics and sends response to the user space
2145*5113495bSYour Name  * @vdev: vdev
2146*5113495bSYour Name  * @dialog_id: dialog id of the twt session
2147*5113495bSYour Name  * @peer_mac: Mac address of the peer
2148*5113495bSYour Name  *
2149*5113495bSYour Name  * Return: QDF_STATUS_SUCCESS on success, else other qdf error values
2150*5113495bSYour Name  */
2151*5113495bSYour Name static QDF_STATUS
osif_twt_request_session_traffic_stats(struct wlan_objmgr_vdev * vdev,uint32_t dialog_id,uint8_t * peer_mac)2152*5113495bSYour Name osif_twt_request_session_traffic_stats(struct wlan_objmgr_vdev *vdev,
2153*5113495bSYour Name 				       uint32_t dialog_id, uint8_t *peer_mac)
2154*5113495bSYour Name {
2155*5113495bSYour Name 	int errno;
2156*5113495bSYour Name 	QDF_STATUS status = QDF_STATUS_E_INVAL;
2157*5113495bSYour Name 	struct infra_cp_stats_event *event;
2158*5113495bSYour Name 
2159*5113495bSYour Name 	if (!peer_mac)
2160*5113495bSYour Name 		return status;
2161*5113495bSYour Name 	event = wlan_cfg80211_mc_twt_get_infra_cp_stats(vdev, dialog_id,
2162*5113495bSYour Name 							peer_mac, &errno);
2163*5113495bSYour Name 
2164*5113495bSYour Name 	if (!event)
2165*5113495bSYour Name 		return errno;
2166*5113495bSYour Name 
2167*5113495bSYour Name 	status = osif_twt_get_stats_response(vdev, event->twt_infra_cp_stats,
2168*5113495bSYour Name 					     event->num_twt_infra_cp_stats);
2169*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status))
2170*5113495bSYour Name 		osif_err("TWT: Get_traffic_stats failed status: %d", status);
2171*5113495bSYour Name 
2172*5113495bSYour Name 	qdf_mem_free(event->twt_infra_cp_stats);
2173*5113495bSYour Name 	qdf_mem_free(event);
2174*5113495bSYour Name 
2175*5113495bSYour Name 	return status;
2176*5113495bSYour Name }
2177*5113495bSYour Name 
osif_twt_get_session_traffic_stats(struct wlan_objmgr_vdev * vdev,struct nlattr * twt_param_attr)2178*5113495bSYour Name int osif_twt_get_session_traffic_stats(struct wlan_objmgr_vdev *vdev,
2179*5113495bSYour Name 				       struct nlattr *twt_param_attr)
2180*5113495bSYour Name {
2181*5113495bSYour Name 	struct wlan_objmgr_psoc *psoc;
2182*5113495bSYour Name 	struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TWT_STATS_MAX + 1];
2183*5113495bSYour Name 	int ret, id;
2184*5113495bSYour Name 	QDF_STATUS qdf_status;
2185*5113495bSYour Name 	uint32_t dialog_id;
2186*5113495bSYour Name 	bool is_stats_tgt_cap_enabled;
2187*5113495bSYour Name 	struct qdf_mac_addr peer_mac;
2188*5113495bSYour Name 
2189*5113495bSYour Name 	psoc = wlan_vdev_get_psoc(vdev);
2190*5113495bSYour Name 	if (!psoc)
2191*5113495bSYour Name 		return -EINVAL;
2192*5113495bSYour Name 
2193*5113495bSYour Name 	ret = wlan_cfg80211_nla_parse_nested(tb,
2194*5113495bSYour Name 					     QCA_WLAN_VENDOR_ATTR_TWT_STATS_MAX,
2195*5113495bSYour Name 					     twt_param_attr,
2196*5113495bSYour Name 					     qca_wlan_vendor_twt_stats_dialog_policy);
2197*5113495bSYour Name 
2198*5113495bSYour Name 	if (ret)
2199*5113495bSYour Name 		return ret;
2200*5113495bSYour Name 
2201*5113495bSYour Name 	ucfg_twt_get_twt_stats_enabled(psoc, &is_stats_tgt_cap_enabled);
2202*5113495bSYour Name 	if (!is_stats_tgt_cap_enabled) {
2203*5113495bSYour Name 		osif_debug("TWT Stats not supported by target");
2204*5113495bSYour Name 		return -EOPNOTSUPP;
2205*5113495bSYour Name 	}
2206*5113495bSYour Name 
2207*5113495bSYour Name 	if (osif_fill_peer_macaddr(vdev, peer_mac.bytes))
2208*5113495bSYour Name 		return -EINVAL;
2209*5113495bSYour Name 
2210*5113495bSYour Name 	if (ucfg_twt_is_command_in_progress(psoc, &peer_mac,
2211*5113495bSYour Name 					    TWT_ALL_SESSIONS_DIALOG_ID,
2212*5113495bSYour Name 					    WLAN_TWT_STATISTICS,
2213*5113495bSYour Name 					    NULL) ||
2214*5113495bSYour Name 	    ucfg_twt_is_command_in_progress(psoc, &peer_mac,
2215*5113495bSYour Name 					    TWT_ALL_SESSIONS_DIALOG_ID,
2216*5113495bSYour Name 					    WLAN_TWT_CLEAR_STATISTICS,
2217*5113495bSYour Name 					    NULL)) {
2218*5113495bSYour Name 		osif_warn("Already TWT statistics or clear statistics exists");
2219*5113495bSYour Name 		return -EALREADY;
2220*5113495bSYour Name 	}
2221*5113495bSYour Name 
2222*5113495bSYour Name 	id = QCA_WLAN_VENDOR_ATTR_TWT_STATS_FLOW_ID;
2223*5113495bSYour Name 	if (tb[id])
2224*5113495bSYour Name 		dialog_id = (uint32_t)nla_get_u8(tb[id]);
2225*5113495bSYour Name 	else
2226*5113495bSYour Name 		dialog_id = 0;
2227*5113495bSYour Name 
2228*5113495bSYour Name 	osif_debug("get_stats dialog_id %d", dialog_id);
2229*5113495bSYour Name 	osif_debug("get_stats peer mac_addr " QDF_MAC_ADDR_FMT,
2230*5113495bSYour Name 		   QDF_MAC_ADDR_REF(peer_mac.bytes));
2231*5113495bSYour Name 
2232*5113495bSYour Name 	if (!ucfg_twt_is_setup_done(psoc, &peer_mac, dialog_id)) {
2233*5113495bSYour Name 		osif_debug("TWT session %d setup incomplete", dialog_id);
2234*5113495bSYour Name 		return -EAGAIN;
2235*5113495bSYour Name 	}
2236*5113495bSYour Name 
2237*5113495bSYour Name 	ucfg_twt_set_command_in_progress(psoc, &peer_mac, dialog_id,
2238*5113495bSYour Name 					 WLAN_TWT_STATISTICS);
2239*5113495bSYour Name 
2240*5113495bSYour Name 	qdf_status = osif_twt_request_session_traffic_stats(vdev, dialog_id,
2241*5113495bSYour Name 							    peer_mac.bytes);
2242*5113495bSYour Name 	ucfg_twt_set_command_in_progress(psoc, &peer_mac,
2243*5113495bSYour Name 					 dialog_id, WLAN_TWT_NONE);
2244*5113495bSYour Name 
2245*5113495bSYour Name 	return qdf_status_to_os_return(qdf_status);
2246*5113495bSYour Name }
2247*5113495bSYour Name 
osif_twt_clear_session_traffic_stats(struct wlan_objmgr_vdev * vdev,struct nlattr * twt_param_attr)2248*5113495bSYour Name int osif_twt_clear_session_traffic_stats(struct wlan_objmgr_vdev *vdev,
2249*5113495bSYour Name 					 struct nlattr *twt_param_attr)
2250*5113495bSYour Name {
2251*5113495bSYour Name 	struct wlan_objmgr_psoc *psoc;
2252*5113495bSYour Name 	struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TWT_STATS_MAX + 1];
2253*5113495bSYour Name 	int ret, id;
2254*5113495bSYour Name 	uint32_t dialog_id;
2255*5113495bSYour Name 	bool is_stats_tgt_cap_enabled;
2256*5113495bSYour Name 	QDF_STATUS status;
2257*5113495bSYour Name 	struct qdf_mac_addr peer_mac;
2258*5113495bSYour Name 
2259*5113495bSYour Name 	psoc = wlan_vdev_get_psoc(vdev);
2260*5113495bSYour Name 	if (!psoc)
2261*5113495bSYour Name 		return -EINVAL;
2262*5113495bSYour Name 
2263*5113495bSYour Name 	ret = wlan_cfg80211_nla_parse_nested(tb,
2264*5113495bSYour Name 				QCA_WLAN_VENDOR_ATTR_TWT_STATS_MAX,
2265*5113495bSYour Name 				twt_param_attr,
2266*5113495bSYour Name 				qca_wlan_vendor_twt_stats_dialog_policy);
2267*5113495bSYour Name 
2268*5113495bSYour Name 	if (ret)
2269*5113495bSYour Name 		return ret;
2270*5113495bSYour Name 
2271*5113495bSYour Name 	ucfg_twt_get_twt_stats_enabled(psoc, &is_stats_tgt_cap_enabled);
2272*5113495bSYour Name 	if (!is_stats_tgt_cap_enabled) {
2273*5113495bSYour Name 		osif_debug("TWT Stats not supported by target");
2274*5113495bSYour Name 		return -EOPNOTSUPP;
2275*5113495bSYour Name 	}
2276*5113495bSYour Name 
2277*5113495bSYour Name 	id = QCA_WLAN_VENDOR_ATTR_TWT_STATS_FLOW_ID;
2278*5113495bSYour Name 	if (!tb[id]) {
2279*5113495bSYour Name 		osif_err_rl("TWT Clear stats - dialog id param is must");
2280*5113495bSYour Name 		return -EINVAL;
2281*5113495bSYour Name 	}
2282*5113495bSYour Name 
2283*5113495bSYour Name 	if (osif_fill_peer_macaddr(vdev, peer_mac.bytes))
2284*5113495bSYour Name 		return -EINVAL;
2285*5113495bSYour Name 
2286*5113495bSYour Name 	dialog_id = (uint32_t)nla_get_u8(tb[id]);
2287*5113495bSYour Name 	osif_debug("dialog_id %d peer mac_addr "QDF_MAC_ADDR_FMT,
2288*5113495bSYour Name 		   dialog_id, QDF_MAC_ADDR_REF(peer_mac.bytes));
2289*5113495bSYour Name 
2290*5113495bSYour Name 	status = ucfg_twt_check_all_twt_support(psoc, dialog_id);
2291*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
2292*5113495bSYour Name 		osif_debug("All TWT sessions not supported by target");
2293*5113495bSYour Name 		return -EOPNOTSUPP;
2294*5113495bSYour Name 	}
2295*5113495bSYour Name 
2296*5113495bSYour Name 	if (ucfg_twt_is_command_in_progress(psoc, &peer_mac,
2297*5113495bSYour Name 					    TWT_ALL_SESSIONS_DIALOG_ID,
2298*5113495bSYour Name 					    WLAN_TWT_STATISTICS, NULL) ||
2299*5113495bSYour Name 	    ucfg_twt_is_command_in_progress(psoc, &peer_mac,
2300*5113495bSYour Name 					    TWT_ALL_SESSIONS_DIALOG_ID,
2301*5113495bSYour Name 					    WLAN_TWT_CLEAR_STATISTICS,
2302*5113495bSYour Name 					    NULL)) {
2303*5113495bSYour Name 		osif_warn("Already TWT statistics or clear statistics exists");
2304*5113495bSYour Name 		return -EALREADY;
2305*5113495bSYour Name 	}
2306*5113495bSYour Name 
2307*5113495bSYour Name 	if (!ucfg_twt_is_setup_done(psoc, &peer_mac, dialog_id)) {
2308*5113495bSYour Name 		osif_debug("TWT session %d setup incomplete", dialog_id);
2309*5113495bSYour Name 		return -EAGAIN;
2310*5113495bSYour Name 	}
2311*5113495bSYour Name 
2312*5113495bSYour Name 	ret = wlan_cfg80211_mc_twt_clear_infra_cp_stats(vdev, dialog_id,
2313*5113495bSYour Name 							peer_mac.bytes);
2314*5113495bSYour Name 
2315*5113495bSYour Name 	return ret;
2316*5113495bSYour Name }
2317*5113495bSYour Name 
2318*5113495bSYour Name /**
2319*5113495bSYour Name  * osif_twt_convert_ac_value() - map ac setting to the value to be used in FW.
2320*5113495bSYour Name  * @ac_value: ac value to be mapped.
2321*5113495bSYour Name  *
2322*5113495bSYour Name  * Return: enum twt_traffic_ac
2323*5113495bSYour Name  */
2324*5113495bSYour Name static inline
osif_twt_convert_ac_value(enum qca_wlan_ac_type ac_value)2325*5113495bSYour Name enum twt_traffic_ac osif_twt_convert_ac_value(enum qca_wlan_ac_type ac_value)
2326*5113495bSYour Name {
2327*5113495bSYour Name 	switch (ac_value) {
2328*5113495bSYour Name 	case QCA_WLAN_AC_BE:
2329*5113495bSYour Name 		return TWT_AC_BE;
2330*5113495bSYour Name 	case QCA_WLAN_AC_BK:
2331*5113495bSYour Name 		return TWT_AC_BK;
2332*5113495bSYour Name 	case QCA_WLAN_AC_VI:
2333*5113495bSYour Name 		return TWT_AC_VI;
2334*5113495bSYour Name 	case QCA_WLAN_AC_VO:
2335*5113495bSYour Name 		return TWT_AC_VO;
2336*5113495bSYour Name 	case QCA_WLAN_AC_ALL:
2337*5113495bSYour Name 		return TWT_AC_MAX;
2338*5113495bSYour Name 	}
2339*5113495bSYour Name 	osif_err("invalid enum: %u", ac_value);
2340*5113495bSYour Name 	return TWT_AC_MAX;
2341*5113495bSYour Name }
2342*5113495bSYour Name 
2343*5113495bSYour Name /**
2344*5113495bSYour Name  * osif_twt_add_ac_config() - pdev TWT param send
2345*5113495bSYour Name  * @vdev: Pointer to vdev object
2346*5113495bSYour Name  * @twt_ac: TWT access category
2347*5113495bSYour Name  *
2348*5113495bSYour Name  * Return: QDF Status
2349*5113495bSYour Name  */
osif_twt_add_ac_config(struct wlan_objmgr_vdev * vdev,enum qca_wlan_ac_type twt_ac)2350*5113495bSYour Name static int osif_twt_add_ac_config(struct wlan_objmgr_vdev *vdev,
2351*5113495bSYour Name 				  enum qca_wlan_ac_type twt_ac)
2352*5113495bSYour Name {
2353*5113495bSYour Name 	bool is_responder_en;
2354*5113495bSYour Name 	int ret = 0;
2355*5113495bSYour Name 	struct wlan_objmgr_psoc *psoc;
2356*5113495bSYour Name 	enum QDF_OPMODE device_mode;
2357*5113495bSYour Name 
2358*5113495bSYour Name 	psoc = wlan_vdev_get_psoc(vdev);
2359*5113495bSYour Name 	if (!psoc)
2360*5113495bSYour Name 		return -EINVAL;
2361*5113495bSYour Name 
2362*5113495bSYour Name 	device_mode = wlan_vdev_mlme_get_opmode(vdev);
2363*5113495bSYour Name 
2364*5113495bSYour Name 	if (twt_ac < QCA_WLAN_AC_BE || twt_ac > QCA_WLAN_AC_VO) {
2365*5113495bSYour Name 		osif_err_rl("Invalid AC parameter. Value: %d", twt_ac);
2366*5113495bSYour Name 		return -EINVAL;
2367*5113495bSYour Name 	}
2368*5113495bSYour Name 
2369*5113495bSYour Name 	ucfg_twt_cfg_get_responder(psoc, &is_responder_en);
2370*5113495bSYour Name 
2371*5113495bSYour Name 	if (device_mode == QDF_SAP_MODE && is_responder_en) {
2372*5113495bSYour Name 		ret = ucfg_twt_ac_pdev_param_send(psoc,
2373*5113495bSYour Name 						  osif_twt_convert_ac_value(twt_ac));
2374*5113495bSYour Name 	} else {
2375*5113495bSYour Name 		osif_err_rl("Undesired device mode. Mode: %d and responder: %d",
2376*5113495bSYour Name 			    device_mode, is_responder_en);
2377*5113495bSYour Name 		return -EINVAL;
2378*5113495bSYour Name 	}
2379*5113495bSYour Name 
2380*5113495bSYour Name 	return ret;
2381*5113495bSYour Name }
2382*5113495bSYour Name 
osif_twt_set_param(struct wlan_objmgr_vdev * vdev,struct nlattr * twt_param_attr)2383*5113495bSYour Name int osif_twt_set_param(struct wlan_objmgr_vdev *vdev,
2384*5113495bSYour Name 		       struct nlattr *twt_param_attr)
2385*5113495bSYour Name {
2386*5113495bSYour Name 	struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TWT_SET_PARAM_MAX + 1];
2387*5113495bSYour Name 	int ret;
2388*5113495bSYour Name 	int cmd_id;
2389*5113495bSYour Name 	enum qca_wlan_ac_type twt_ac;
2390*5113495bSYour Name 
2391*5113495bSYour Name 	ret = wlan_cfg80211_nla_parse_nested
2392*5113495bSYour Name 					(tb,
2393*5113495bSYour Name 					 QCA_WLAN_VENDOR_ATTR_TWT_SET_PARAM_MAX,
2394*5113495bSYour Name 					 twt_param_attr,
2395*5113495bSYour Name 					 qca_wlan_vendor_twt_set_param_policy);
2396*5113495bSYour Name 	if (ret)
2397*5113495bSYour Name 		return ret;
2398*5113495bSYour Name 
2399*5113495bSYour Name 	cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SET_PARAM_AP_AC_VALUE;
2400*5113495bSYour Name 
2401*5113495bSYour Name 	if (tb[cmd_id]) {
2402*5113495bSYour Name 		twt_ac = nla_get_u8(tb[cmd_id]);
2403*5113495bSYour Name 		osif_debug("TWT_AC_CONFIG_VALUE: %d", twt_ac);
2404*5113495bSYour Name 		ret = osif_twt_add_ac_config(vdev, twt_ac);
2405*5113495bSYour Name 
2406*5113495bSYour Name 		if (ret) {
2407*5113495bSYour Name 			osif_err("Fail to set TWT AC parameter, errno %d",
2408*5113495bSYour Name 				 ret);
2409*5113495bSYour Name 			return ret;
2410*5113495bSYour Name 		}
2411*5113495bSYour Name 	}
2412*5113495bSYour Name 
2413*5113495bSYour Name 	return ret;
2414*5113495bSYour Name }
2415*5113495bSYour Name 
osif_twt_teardown_req_retry(struct wlan_objmgr_vdev * vdev,struct wlan_objmgr_psoc * psoc,struct twt_del_dialog_param params)2416*5113495bSYour Name static void osif_twt_teardown_req_retry(struct wlan_objmgr_vdev *vdev,
2417*5113495bSYour Name 					struct wlan_objmgr_psoc *psoc,
2418*5113495bSYour Name 					struct twt_del_dialog_param params)
2419*5113495bSYour Name {
2420*5113495bSYour Name 	int retries = 1;
2421*5113495bSYour Name 	int ret;
2422*5113495bSYour Name 
2423*5113495bSYour Name 	while (retries < TWT_DEL_DIALOG_REQ_MAX_RETRY) {
2424*5113495bSYour Name 		qdf_sleep(TWT_TEARDOWN_IN_PS_DISABLE_WAIT_TIME);
2425*5113495bSYour Name 		osif_debug("Implicitly TWT teardown req retry count:%d", retries);
2426*5113495bSYour Name 		ret = osif_send_sta_twt_teardown_req(vdev, psoc, &params);
2427*5113495bSYour Name 		if (ret != -EBUSY)
2428*5113495bSYour Name 			break;
2429*5113495bSYour Name 		retries++;
2430*5113495bSYour Name 	}
2431*5113495bSYour Name 
2432*5113495bSYour Name 	if (retries >= TWT_DEL_DIALOG_REQ_MAX_RETRY)
2433*5113495bSYour Name 		osif_debug("TWT Del Dialog req max retries reached");
2434*5113495bSYour Name }
2435*5113495bSYour Name 
__osif_twt_work_handler(struct wlan_objmgr_vdev * vdev)2436*5113495bSYour Name void __osif_twt_work_handler(struct wlan_objmgr_vdev *vdev)
2437*5113495bSYour Name {
2438*5113495bSYour Name 	struct twt_del_dialog_param params = {0};
2439*5113495bSYour Name 	struct twt_work_params twt_work_params = {0};
2440*5113495bSYour Name 	struct wlan_objmgr_psoc *psoc;
2441*5113495bSYour Name 	uint8_t vdev_id;
2442*5113495bSYour Name 	uint32_t next_action;
2443*5113495bSYour Name 	int ret;
2444*5113495bSYour Name 
2445*5113495bSYour Name 	psoc = wlan_vdev_get_psoc(vdev);
2446*5113495bSYour Name 	if (!psoc) {
2447*5113495bSYour Name 		osif_err("psoc is null");
2448*5113495bSYour Name 		return;
2449*5113495bSYour Name 	}
2450*5113495bSYour Name 
2451*5113495bSYour Name 	vdev_id = wlan_vdev_get_id(vdev);
2452*5113495bSYour Name 	ucfg_twt_get_work_params(vdev, &twt_work_params, &next_action);
2453*5113495bSYour Name 
2454*5113495bSYour Name 	if (next_action != HOST_TWT_SEND_DELETE_CMD) {
2455*5113495bSYour Name 		osif_debug("Do not send STA teardown req as TWT renegotiation or power save work is not scheduled");
2456*5113495bSYour Name 		return;
2457*5113495bSYour Name 	}
2458*5113495bSYour Name 
2459*5113495bSYour Name 	qdf_copy_macaddr(&params.peer_macaddr, &twt_work_params.peer_macaddr);
2460*5113495bSYour Name 	params.dialog_id = twt_work_params.dialog_id;
2461*5113495bSYour Name 	params.vdev_id = vdev_id;
2462*5113495bSYour Name 
2463*5113495bSYour Name 	ret = osif_send_sta_twt_teardown_req(vdev, psoc, &params);
2464*5113495bSYour Name 
2465*5113495bSYour Name 	/*
2466*5113495bSYour Name 	 * In case of FW returns ack_event with status as scan_in_progress or
2467*5113495bSYour Name 	 * Channel switch in progress and TWT teardown happens due to power
2468*5113495bSYour Name 	 * save disable then host will retry the TWT teardown cmd.
2469*5113495bSYour Name 	 */
2470*5113495bSYour Name 	if (ret == -EBUSY && twt_work_params.is_ps_disabled)
2471*5113495bSYour Name 		osif_twt_teardown_req_retry(vdev, psoc, params);
2472*5113495bSYour Name }
2473*5113495bSYour Name 
osif_twt_work_handler(void * data)2474*5113495bSYour Name void osif_twt_work_handler(void *data)
2475*5113495bSYour Name {
2476*5113495bSYour Name 	struct wlan_objmgr_vdev *vdev = (struct wlan_objmgr_vdev *)data;
2477*5113495bSYour Name 	struct net_device *net_dev;
2478*5113495bSYour Name 	struct osif_vdev_sync *vdev_sync;
2479*5113495bSYour Name 	struct vdev_osif_priv *priv;
2480*5113495bSYour Name 	int errno;
2481*5113495bSYour Name 
2482*5113495bSYour Name 	if (!vdev) {
2483*5113495bSYour Name 		osif_err("vdev is null");
2484*5113495bSYour Name 		return;
2485*5113495bSYour Name 	}
2486*5113495bSYour Name 
2487*5113495bSYour Name 	priv = wlan_vdev_get_ospriv(vdev);
2488*5113495bSYour Name 	if (!priv || !priv->wdev || !priv->wdev->netdev)
2489*5113495bSYour Name 		return;
2490*5113495bSYour Name 
2491*5113495bSYour Name 	net_dev = priv->wdev->netdev;
2492*5113495bSYour Name 	errno = osif_vdev_sync_op_start(net_dev, &vdev_sync);
2493*5113495bSYour Name 	if (errno)
2494*5113495bSYour Name 		return;
2495*5113495bSYour Name 
2496*5113495bSYour Name 	__osif_twt_work_handler(vdev);
2497*5113495bSYour Name 
2498*5113495bSYour Name 	osif_vdev_sync_op_stop(vdev_sync);
2499*5113495bSYour Name }
2500*5113495bSYour Name 
osif_twt_create_work(struct wlan_objmgr_vdev * vdev)2501*5113495bSYour Name QDF_STATUS osif_twt_create_work(struct wlan_objmgr_vdev *vdev)
2502*5113495bSYour Name {
2503*5113495bSYour Name 	qdf_create_work(0, &vdev->twt_work,
2504*5113495bSYour Name 			osif_twt_work_handler, vdev);
2505*5113495bSYour Name 
2506*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
2507*5113495bSYour Name }
2508*5113495bSYour Name 
osif_twt_destroy_work(struct wlan_objmgr_vdev * vdev)2509*5113495bSYour Name QDF_STATUS osif_twt_destroy_work(struct wlan_objmgr_vdev *vdev)
2510*5113495bSYour Name {
2511*5113495bSYour Name 	qdf_flush_work(&vdev->twt_work);
2512*5113495bSYour Name 	qdf_destroy_work(NULL, &vdev->twt_work);
2513*5113495bSYour Name 
2514*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
2515*5113495bSYour Name }
2516