1 /*
2 * Copyright (c) 2012-2020 The Linux Foundation. All rights reserved.
3 * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
4 *
5 * Permission to use, copy, modify, and/or distribute this software for
6 * any purpose with or without fee is hereby granted, provided that the
7 * above copyright notice and this permission notice appear in all
8 * copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
18 */
19
20 /**
21 * DOC: wlan_hdd_active_tos.c
22 *
23 * WLAN active tos functions
24 *
25 */
26
27 #include "osif_sync.h"
28 #include <wlan_hdd_includes.h>
29 #include <linux/netdevice.h>
30 #include <linux/skbuff.h>
31 #include <linux/etherdevice.h>
32 #include <linux/if_ether.h>
33 #include <wlan_hdd_active_tos.h>
34 #include "wlan_policy_mgr_ucfg.h"
35 #include "wlan_scan_ucfg_api.h"
36
37 #define HDD_AC_BK_BIT 1
38 #define HDD_AC_BE_BIT 2
39 #define HDD_AC_VI_BIT 4
40 #define HDD_AC_VO_BIT 8
41
42 #define HDD_MAX_OFF_CHAN_TIME_FOR_VO 20
43 #define HDD_MAX_OFF_CHAN_TIME_FOR_VI 20
44 #define HDD_MAX_OFF_CHAN_TIME_FOR_BE 40
45 #define HDD_MAX_OFF_CHAN_TIME_FOR_BK 40
46
47 #define HDD_MAX_OFF_CHAN_ENTRIES 2
48
49 #define HDD_AC_BIT_INDX 0
50 #define HDD_DWELL_TIME_INDX 1
51
52 static int limit_off_chan_tbl[QCA_WLAN_AC_ALL][HDD_MAX_OFF_CHAN_ENTRIES] = {
53 { HDD_AC_BK_BIT, HDD_MAX_OFF_CHAN_TIME_FOR_BK },
54 { HDD_AC_BE_BIT, HDD_MAX_OFF_CHAN_TIME_FOR_BE },
55 { HDD_AC_VI_BIT, HDD_MAX_OFF_CHAN_TIME_FOR_VI },
56 { HDD_AC_VO_BIT, HDD_MAX_OFF_CHAN_TIME_FOR_VO },
57 };
58
59 const struct nla_policy
60 wlan_hdd_set_limit_off_channel_param_policy
61 [QCA_WLAN_VENDOR_ATTR_ACTIVE_TOS_MAX + 1] = {
62 [QCA_WLAN_VENDOR_ATTR_ACTIVE_TOS] = {.type = NLA_U8 },
63 [QCA_WLAN_VENDOR_ATTR_ACTIVE_TOS_START] = {.type = NLA_U8 },
64 };
65
66 /**
67 * hdd_set_limit_off_chan_for_tos() - set limit off-channel command parameters
68 * @adapter: HDD adapter
69 * @tos: type of service
70 * @is_tos_active: status of the traffic
71 *
72 * Return: 0 on success and non zero value on failure
73 */
74
75 static int
hdd_set_limit_off_chan_for_tos(struct hdd_adapter * adapter,enum qca_wlan_ac_type tos,bool is_tos_active)76 hdd_set_limit_off_chan_for_tos(struct hdd_adapter *adapter,
77 enum qca_wlan_ac_type tos,
78 bool is_tos_active)
79 {
80 int ac_bit;
81 struct hdd_context *hdd_ctx;
82 uint32_t max_off_chan_time = 0;
83 QDF_STATUS status;
84 int ret;
85 uint8_t def_sys_pref = 0;
86 uint32_t rest_conc_time;
87
88 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
89 ret = wlan_hdd_validate_context(hdd_ctx);
90
91 if (ret < 0)
92 return ret;
93 ucfg_policy_mgr_get_sys_pref(hdd_ctx->psoc,
94 &def_sys_pref);
95
96 ac_bit = limit_off_chan_tbl[tos][HDD_AC_BIT_INDX];
97
98 if (is_tos_active)
99 adapter->active_ac |= ac_bit;
100 else
101 adapter->active_ac &= ~ac_bit;
102
103 if (adapter->active_ac) {
104 if (adapter->active_ac & HDD_AC_VO_BIT) {
105 max_off_chan_time =
106 limit_off_chan_tbl[QCA_WLAN_AC_VO][HDD_DWELL_TIME_INDX];
107 policy_mgr_set_cur_conc_system_pref(hdd_ctx->psoc,
108 PM_LATENCY);
109 } else if (adapter->active_ac & HDD_AC_VI_BIT) {
110 max_off_chan_time =
111 limit_off_chan_tbl[QCA_WLAN_AC_VI][HDD_DWELL_TIME_INDX];
112 policy_mgr_set_cur_conc_system_pref(hdd_ctx->psoc,
113 PM_LATENCY);
114 } else {
115 /*ignore this command if only BE/BK is active */
116 is_tos_active = false;
117 policy_mgr_set_cur_conc_system_pref(hdd_ctx->psoc,
118 def_sys_pref);
119 }
120 } else {
121 /* No active tos */
122 policy_mgr_set_cur_conc_system_pref(hdd_ctx->psoc,
123 def_sys_pref);
124 }
125
126 ucfg_scan_cfg_get_conc_max_resttime(hdd_ctx->psoc, &rest_conc_time);
127 status = sme_send_limit_off_channel_params(hdd_ctx->mac_handle,
128 adapter->deflink->vdev_id,
129 is_tos_active,
130 max_off_chan_time,
131 rest_conc_time,
132 true);
133 if (!QDF_IS_STATUS_SUCCESS(status)) {
134 hdd_err("failed to set limit off chan params");
135 ret = -EINVAL;
136 }
137
138 return ret;
139 }
140
141 /**
142 * __wlan_hdd_cfg80211_set_limit_offchan_param() - set limit off-channel cmd
143 * parameters
144 * @wiphy: pointer to wireless wiphy structure.
145 * @wdev: pointer to wireless_dev structure.
146 * @data: pointer to limit off-channel command parameters.
147 * @data_len: the length in byte of limit off-channel command parameters.
148 *
149 * This is called when application wants to limit the off channel time due to
150 * active voip traffic.
151 *
152 * Return: An error code or 0 on success.
153 */
154 static int
__wlan_hdd_cfg80211_set_limit_offchan_param(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)155 __wlan_hdd_cfg80211_set_limit_offchan_param(struct wiphy *wiphy,
156 struct wireless_dev *wdev,
157 const void *data,
158 int data_len)
159 {
160 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_ACTIVE_TOS_MAX + 1];
161 struct net_device *dev = wdev->netdev;
162 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
163 struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
164 int ret = 0;
165 uint8_t tos;
166 uint8_t tos_status;
167
168 hdd_enter();
169
170 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
171 hdd_err("Command not allowed in FTM mode");
172 return -EPERM;
173 }
174
175 ret = wlan_hdd_validate_context(hdd_ctx);
176 if (ret < 0)
177 return ret;
178
179 if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_ACTIVE_TOS_MAX,
180 data, data_len,
181 wlan_hdd_set_limit_off_channel_param_policy)) {
182 hdd_err("Invalid ATTR");
183 return -EINVAL;
184 }
185
186 if (!tb[QCA_WLAN_VENDOR_ATTR_ACTIVE_TOS]) {
187 hdd_err("attr tos failed");
188 goto fail;
189 }
190
191 tos = nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACTIVE_TOS]);
192 if (tos >= QCA_WLAN_AC_ALL) {
193 hdd_err("tos value %d exceeded Max value %d",
194 tos, QCA_WLAN_AC_ALL);
195 goto fail;
196 }
197 hdd_debug("tos %d", tos);
198
199 if (!tb[QCA_WLAN_VENDOR_ATTR_ACTIVE_TOS_START]) {
200 hdd_err("attr tos active failed");
201 goto fail;
202 }
203 tos_status = nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACTIVE_TOS_START]);
204
205 hdd_debug("tos status %d", tos_status);
206 ret = hdd_set_limit_off_chan_for_tos(adapter, tos, tos_status);
207
208 fail:
209 return ret;
210 }
211
wlan_hdd_cfg80211_set_limit_offchan_param(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)212 int wlan_hdd_cfg80211_set_limit_offchan_param(struct wiphy *wiphy,
213 struct wireless_dev *wdev,
214 const void *data, int data_len)
215
216 {
217 struct osif_vdev_sync *vdev_sync;
218 int errno;
219
220 errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync);
221 if (errno)
222 return errno;
223
224 errno = __wlan_hdd_cfg80211_set_limit_offchan_param(wiphy, wdev, data,
225 data_len);
226
227 osif_vdev_sync_op_stop(vdev_sync);
228
229 return errno;
230 }
231
232