blob: b1795b2079f52dd6bcf30dde10872c2a29b08971 [file] [log] [blame]
Googlerb48fa912023-03-17 12:40:29 +05301// SPDX-License-Identifier: ISC
2/*
3 * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
4 */
5
6#include <net/netlink.h>
7#include <net/mac80211.h>
8#include "core.h"
9#include "debug.h"
10
11static const struct nla_policy
12ath11k_vendor_set_wifi_config_policy[QCA_WLAN_VENDOR_ATTR_CONFIG_MAX + 1] = {
13 [QCA_WLAN_VENDOR_ATTR_CONFIG_GTX] = {.type = NLA_FLAG}
14};
15
16static const struct nla_policy
17ath11k_cfg80211_afc_event_policy[QCA_WLAN_VENDOR_ATTR_AFC_EVENT_MAX] = {
18 [QCA_WLAN_VENDOR_ATTR_AFC_EVENT_TYPE] = { .type = NLA_U8 },
19 [QCA_WLAN_VENDOR_ATTR_AFC_EVENT_DATA] =
20 { .type = NLA_BINARY,
21 .len = QCA_NL80211_AFC_REQ_RESP_BUF_MAX_SIZE },
22};
23
24static const struct nla_policy
25ath11k_cfg80211_afc_response_policy[QCA_WLAN_VENDOR_ATTR_AFC_RESPONSE_MAX] = {
26 [QCA_WLAN_VENDOR_ATTR_AFC_RESPONSE_DATA_TYPE] = { .type = NLA_U8 },
27 [QCA_WLAN_VENDOR_ATTR_AFC_RESPONSE_DATA] =
28 { .type = NLA_BINARY,
29 .len = QCA_NL80211_AFC_REQ_RESP_BUF_MAX_SIZE },
30};
31
32static int ath11k_vendor_set_wifi_config(struct wiphy *wihpy,
33 struct wireless_dev *wdev,
34 const void *data,
35 int data_len)
36{
37 struct ieee80211_vif *vif;
38 struct ath11k_vif *arvif;
39 struct ath11k *ar;
40 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_CONFIG_MAX + 1];
41 int ret = 0;
42
43 if (!wdev)
44 return -EINVAL;
45
46 vif = wdev_to_ieee80211_vif(wdev);
47 if (!vif)
48 return -EINVAL;
49
50 arvif = (struct ath11k_vif*)vif->drv_priv;
51 if (!arvif)
52 return -EINVAL;
53
54 ar = arvif->ar;
55
56 mutex_lock(&ar->conf_mutex);
57
58 ret = nla_parse(tb, QCA_WLAN_VENDOR_ATTR_CONFIG_MAX, data, data_len,
59 ath11k_vendor_set_wifi_config_policy, NULL);
60 if (ret) {
61 ath11k_warn(ar->ab, "invalid set wifi config policy attribute\n");
62 goto exit;
63 }
64
65 ar->ap_ps_enabled = nla_get_flag(tb[QCA_WLAN_VENDOR_ATTR_CONFIG_GTX]);
66 ret = ath11k_mac_ap_ps_recalc(ar);
67 if (ret) {
68 ath11k_warn(ar->ab, "failed to send ap ps ret %d\n", ret);
69 goto exit;
70 }
71
72exit:
73 mutex_unlock(&ar->conf_mutex);
74 return ret;
75}
76
77static void ath11k_afc_resp_ntoh_conv(struct ath11k_base *ab, u32 *data, int data_len)
78{
79 int iter = 0;
80
81 if (!data || !data_len) {
82 ath11k_warn(ab, "Invalid AFC response\n");
83 return;
84 }
85
86 for (iter = 0; iter < data_len; iter++) {
87 /* Skip endian conversion for description field
88 * in the AFC response as it is a char array.
89 */
90 if (iter < QCA_WLAN_AFC_RESP_DESC_FIELD_START_OCTET ||
91 iter > QCA_WLAN_AFC_RESP_DESC_FIELD_END_OCTET) {
92 data[iter] = ntohl(data[iter]);
93 }
94 }
95}
96
97static int ath11k_vendor_receive_afc_response(struct wiphy *wihpy,
98 struct wireless_dev *wdev,
99 const void *data,
100 int data_len)
101{
102 struct ieee80211_vif *vif;
103 struct ath11k_vif *arvif;
104 struct ath11k *ar;
105 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_AFC_RESPONSE_MAX + 1];
106 int afc_resp_len = 0, afc_resp_len_32 = 0;
107 u8 data_type = 0;
108 struct ath11k_afc_host_resp *afc_rsp = NULL;
109 int ret = 0;
110
111 if (!wdev)
112 return -EINVAL;
113
114 vif = wdev_to_ieee80211_vif(wdev);
115 if (!vif)
116 return -EINVAL;
117
118 arvif = (struct ath11k_vif *)vif->drv_priv;
119 if (!arvif)
120 return -EINVAL;
121
122 ar = arvif->ar;
123
124 ath11k_dbg(ar->ab, ATH11K_DBG_AFC, "Received AFC response event\n");
125
126 ret = nla_parse(tb, QCA_WLAN_VENDOR_ATTR_AFC_RESPONSE_MAX, data, data_len,
127 ath11k_cfg80211_afc_event_policy, NULL);
128 if (ret) {
129 ath11k_warn(ar->ab, "invalid set afc config policy attribute\n");
130 return ret;
131 }
132
133 if (!tb[QCA_WLAN_VENDOR_ATTR_AFC_RESPONSE_DATA_TYPE])
134 return -EINVAL;
135
136 data_type = nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_AFC_RESPONSE_DATA_TYPE]);
137
138 if (!tb[QCA_WLAN_VENDOR_ATTR_AFC_RESPONSE_DATA]) {
139 ath11k_warn(ar->ab, "AFC response data not found\n");
140 return -EINVAL;
141 }
142
143 afc_resp_len = nla_len(tb[QCA_WLAN_VENDOR_ATTR_AFC_RESPONSE_DATA]);
144
145 if (!afc_resp_len) {
146 ath11k_warn(ar->ab, "AFC response data is not present!\n");
147 return -EINVAL;
148 }
149
150 afc_rsp = kzalloc(afc_resp_len, GFP_KERNEL);
151 if (!afc_rsp)
152 return -ENOMEM;
153
154 nla_memcpy((void *)afc_rsp, tb[QCA_WLAN_VENDOR_ATTR_AFC_RESPONSE_DATA],
155 afc_resp_len);
156
157 switch (data_type) {
158 case QCA_WLAN_VENDOR_ATTR_AFC_JSON_RESP:
159 /* No processing required in Driver for JSON data */
160 break;
161
162 case QCA_WLAN_VENDOR_ATTR_AFC_BIN_RESP:
163 /* The AFC response received from the user space application
164 * is expected to be packed in network byte order(Big endian).
165 * Since q6 is little endian, Host needs to convert the afc
166 * response to little endian format.
167 *
168 * Note: This conversion of data to little endian format is only
169 * required for Binary type data. For raw JSON data,
170 * no conversion is required since it is text string.
171 *
172 * Since all the members of the AFC response structure are defined
173 * to be 32-bit words, convert the length appropriately for
174 * conversion to little endian format.
175 */
176 afc_resp_len_32 = (afc_resp_len / sizeof(uint32_t));
177 ath11k_afc_resp_ntoh_conv(ar->ab, (u32 *)afc_rsp, afc_resp_len_32);
178 ath11k_dbg_dump(ar->ab, ATH11K_DBG_AFC, NULL, "", afc_rsp, afc_resp_len);
179
180 break;
181
182 default:
183 ath11k_warn(ar->ab, "Invalid response format type %d\n", data_type);
184 ret = -EINVAL;
185 goto exit;
186 }
187
188 /* Copy the data buffer to AFC memory location */
189 ret = ath11k_copy_afc_response(ar, (char *)afc_rsp, afc_resp_len);
190 if (ret)
191 goto exit;
192
193 ath11k_dbg(ar->ab, ATH11K_DBG_AFC, "AFC response copied to AFC memory\n");
194
195 ret = ath11k_wmi_send_afc_resp_rx_ind(ar, data_type);
196 if (ret) {
197 ath11k_warn(ar->ab, "AFC Rx indication to FW failed: %d\n", ret);
198 goto exit;
199 }
200 ath11k_dbg(ar->ab, ATH11K_DBG_AFC, "AFC Resp RX indication sent to target\n");
201
202exit:
203 kfree(afc_rsp);
204 return ret;
205}
206
207static struct wiphy_vendor_command ath11k_vendor_commands[] = {
208 {
209 .info.vendor_id = QCA_NL80211_VENDOR_ID,
210 .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION,
211 .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
212 WIPHY_VENDOR_CMD_NEED_RUNNING,
213 .doit = ath11k_vendor_set_wifi_config,
214 .policy = ath11k_vendor_set_wifi_config_policy,
215 .maxattr = QCA_WLAN_VENDOR_ATTR_CONFIG_MAX
216 },
217 {
218 .info.vendor_id = QCA_NL80211_VENDOR_ID,
219 .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_AFC_RESPONSE,
220 .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
221 WIPHY_VENDOR_CMD_NEED_NETDEV |
222 WIPHY_VENDOR_CMD_NEED_RUNNING,
223 .doit = ath11k_vendor_receive_afc_response,
224 .policy = ath11k_cfg80211_afc_response_policy,
225 .maxattr = QCA_WLAN_VENDOR_ATTR_AFC_RESPONSE_MAX
226 },
227};
228
229int ath11k_send_power_update_complete(struct ath11k *ar)
230{
231 struct ath11k_base *ab = ar->ab;
232 struct ath11k_afc_req_fixed_params fixed_param = {0};
233 struct ath11k_afc_info *afc = &ar->afc;
234 struct sk_buff *nl_skb;
235 int ret = 0;
236
237 fixed_param.req_id = afc->request_id;
238 fixed_param.min_des_power = DEFAULT_MIN_POWER;
239 fixed_param.req_length = sizeof(struct ath11k_afc_req_fixed_params);
240 fixed_param.status_code = afc->afc_reg_info->fw_status_code;
241
242 nl_skb = cfg80211_vendor_event_alloc(ar->hw->wiphy, NULL,
243 nla_total_size(sizeof(u8) +
244 sizeof(struct ath11k_afc_req_fixed_params)),
245 QCA_NL80211_VENDOR_SUBCMD_AFC_EVENT_INDEX,
246 GFP_ATOMIC);
247 if (!nl_skb) {
248 ath11k_warn(ab, "failed to allocate skb for power update complete event\n");
249 return -ENOMEM;
250 }
251
252 ret = nla_put_u8(nl_skb, QCA_WLAN_VENDOR_ATTR_AFC_EVENT_TYPE,
253 QCA_WLAN_VENDOR_AFC_POWER_UPDATE_COMPLETE_EVENT);
254 if (ret) {
255 ath11k_warn(ar->ab, "failed to put afc event type for power cmd\n");
256 kfree_skb(nl_skb);
257 return -EFAULT;
258 }
259
260 ret = nla_put(nl_skb, QCA_WLAN_VENDOR_ATTR_AFC_EVENT_DATA,
261 sizeof(struct ath11k_afc_req_fixed_params), &fixed_param);
262
263 if (ret) {
264 ath11k_warn(ar->ab, "failed to put afc event data for power cmd\n");
265 kfree_skb(nl_skb);
266 return -EFAULT;
267 }
268
269 ath11k_dbg(ab, ATH11K_DBG_AFC,
270 "Sending power update complete for afc request id %llu status code %d\n",
271 fixed_param.req_id, fixed_param.status_code);
272 cfg80211_vendor_event(nl_skb, GFP_ATOMIC);
273 return 0;
274}
275
276int ath11k_send_afc_start(struct ath11k *ar, struct ath11k_afc_req_fixed_params *afc_data)
277{
278 struct sk_buff *nl_skb;
279 int ret = 0;
280
281 nl_skb = cfg80211_vendor_event_alloc(ar->hw->wiphy, NULL,
282 nla_total_size(sizeof(u8) +
283 sizeof(struct ath11k_afc_req_fixed_params)),
284 QCA_NL80211_VENDOR_SUBCMD_AFC_EVENT_INDEX,
285 GFP_ATOMIC);
286 if (!nl_skb) {
287 ath11k_warn(ar->ab, "failed to allocate skb for afc expiry event\n");
288 goto out;
289 }
290
291 ret = nla_put_u8(nl_skb, QCA_WLAN_VENDOR_ATTR_AFC_EVENT_TYPE,
292 QCA_WLAN_VENDOR_AFC_EXPIRY_EVENT);
293 if (ret) {
294 ath11k_warn(ar->ab, "failed to put afc event type\n");
295 kfree_skb(nl_skb);
296 goto out;
297 }
298
299 ret = nla_put(nl_skb, QCA_WLAN_VENDOR_ATTR_AFC_EVENT_DATA,
300 sizeof(struct ath11k_afc_req_fixed_params), afc_data);
301
302 if (ret) {
303 ath11k_warn(ar->ab, "failed to put afc event data\n");
304 kfree_skb(nl_skb);
305 goto out;
306 }
307
308 cfg80211_vendor_event(nl_skb, GFP_ATOMIC);
309 ath11k_dbg(ar->ab, ATH11K_DBG_AFC,
310 "Sending expiry event to higher layer of type %d\n",
311 QCA_WLAN_VENDOR_AFC_EXPIRY_EVENT);
312out:
313 return ret;
314}
315
316static const struct nl80211_vendor_cmd_info ath11k_vendor_events[] = {
317 [QCA_NL80211_VENDOR_SUBCMD_AFC_EVENT_INDEX] = {
318 .vendor_id = QCA_NL80211_VENDOR_ID,
319 .subcmd = QCA_NL80211_VENDOR_SUBCMD_AFC_EVENT
320 },
321};
322
323int ath11k_vendor_register(struct ath11k *ar)
324{
325 ar->hw->wiphy->vendor_commands = ath11k_vendor_commands;
326 ar->hw->wiphy->n_vendor_commands = ARRAY_SIZE(ath11k_vendor_commands);
327 ar->hw->wiphy->vendor_events = ath11k_vendor_events;
328 ar->hw->wiphy->n_vendor_events = ARRAY_SIZE(ath11k_vendor_events);
329
330 return 0;
331}