1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * This file is part of wl1271
4  *
5  * Copyright (C) 2010 Nokia Corporation
6  *
7  * Contact: Luciano Coelho <luciano.coelho@nokia.com>
8  */
9 #include "testmode.h"
10 
11 #include <linux/pm_runtime.h>
12 #include <linux/slab.h>
13 #include <net/genetlink.h>
14 
15 #include "wlcore.h"
16 #include "debug.h"
17 #include "acx.h"
18 #include "io.h"
19 
20 #define WL1271_TM_MAX_DATA_LENGTH 1024
21 
22 enum wl1271_tm_commands {
23 	WL1271_TM_CMD_UNSPEC,
24 	WL1271_TM_CMD_TEST,
25 	WL1271_TM_CMD_INTERROGATE,
26 	WL1271_TM_CMD_CONFIGURE,
27 	WL1271_TM_CMD_NVS_PUSH,		/* Not in use. Keep to not break ABI */
28 	WL1271_TM_CMD_SET_PLT_MODE,
29 	WL1271_TM_CMD_RECOVER,		/* Not in use. Keep to not break ABI */
30 	WL1271_TM_CMD_GET_MAC,
31 
32 	__WL1271_TM_CMD_AFTER_LAST
33 };
34 #define WL1271_TM_CMD_MAX (__WL1271_TM_CMD_AFTER_LAST - 1)
35 
36 enum wl1271_tm_attrs {
37 	WL1271_TM_ATTR_UNSPEC,
38 	WL1271_TM_ATTR_CMD_ID,
39 	WL1271_TM_ATTR_ANSWER,
40 	WL1271_TM_ATTR_DATA,
41 	WL1271_TM_ATTR_IE_ID,
42 	WL1271_TM_ATTR_PLT_MODE,
43 
44 	__WL1271_TM_ATTR_AFTER_LAST
45 };
46 #define WL1271_TM_ATTR_MAX (__WL1271_TM_ATTR_AFTER_LAST - 1)
47 
48 static struct nla_policy wl1271_tm_policy[WL1271_TM_ATTR_MAX + 1] = {
49 	[WL1271_TM_ATTR_CMD_ID] =	{ .type = NLA_U32 },
50 	[WL1271_TM_ATTR_ANSWER] =	{ .type = NLA_U8 },
51 	[WL1271_TM_ATTR_DATA] =		{ .type = NLA_BINARY,
52 					  .len = WL1271_TM_MAX_DATA_LENGTH },
53 	[WL1271_TM_ATTR_IE_ID] =	{ .type = NLA_U32 },
54 	[WL1271_TM_ATTR_PLT_MODE] =	{ .type = NLA_U32 },
55 };
56 
57 
wl1271_tm_cmd_test(struct wl1271 * wl,struct nlattr * tb[])58 static int wl1271_tm_cmd_test(struct wl1271 *wl, struct nlattr *tb[])
59 {
60 	int buf_len, ret, len;
61 	struct sk_buff *skb;
62 	void *buf;
63 	u8 answer = 0;
64 
65 	wl1271_debug(DEBUG_TESTMODE, "testmode cmd test");
66 
67 	if (!tb[WL1271_TM_ATTR_DATA])
68 		return -EINVAL;
69 
70 	buf = nla_data(tb[WL1271_TM_ATTR_DATA]);
71 	buf_len = nla_len(tb[WL1271_TM_ATTR_DATA]);
72 
73 	if (tb[WL1271_TM_ATTR_ANSWER])
74 		answer = nla_get_u8(tb[WL1271_TM_ATTR_ANSWER]);
75 
76 	if (buf_len > sizeof(struct wl1271_command))
77 		return -EMSGSIZE;
78 
79 	mutex_lock(&wl->mutex);
80 
81 	if (unlikely(wl->state != WLCORE_STATE_ON)) {
82 		ret = -EINVAL;
83 		goto out;
84 	}
85 
86 	ret = pm_runtime_get_sync(wl->dev);
87 	if (ret < 0) {
88 		pm_runtime_put_noidle(wl->dev);
89 		goto out;
90 	}
91 
92 	ret = wl1271_cmd_test(wl, buf, buf_len, answer);
93 	if (ret < 0) {
94 		wl1271_warning("testmode cmd test failed: %d", ret);
95 		goto out_sleep;
96 	}
97 
98 	if (answer) {
99 		/* If we got bip calibration answer print radio status */
100 		struct wl1271_cmd_cal_p2g *params =
101 			(struct wl1271_cmd_cal_p2g *) buf;
102 
103 		s16 radio_status = (s16) le16_to_cpu(params->radio_status);
104 
105 		if (params->test.id == TEST_CMD_P2G_CAL &&
106 		    radio_status < 0)
107 			wl1271_warning("testmode cmd: radio status=%d",
108 					radio_status);
109 		else
110 			wl1271_info("testmode cmd: radio status=%d",
111 					radio_status);
112 
113 		len = nla_total_size(buf_len);
114 		skb = cfg80211_testmode_alloc_reply_skb(wl->hw->wiphy, len);
115 		if (!skb) {
116 			ret = -ENOMEM;
117 			goto out_sleep;
118 		}
119 
120 		if (nla_put(skb, WL1271_TM_ATTR_DATA, buf_len, buf)) {
121 			kfree_skb(skb);
122 			ret = -EMSGSIZE;
123 			goto out_sleep;
124 		}
125 
126 		ret = cfg80211_testmode_reply(skb);
127 		if (ret < 0)
128 			goto out_sleep;
129 	}
130 
131 out_sleep:
132 	pm_runtime_mark_last_busy(wl->dev);
133 	pm_runtime_put_autosuspend(wl->dev);
134 out:
135 	mutex_unlock(&wl->mutex);
136 
137 	return ret;
138 }
139 
wl1271_tm_cmd_interrogate(struct wl1271 * wl,struct nlattr * tb[])140 static int wl1271_tm_cmd_interrogate(struct wl1271 *wl, struct nlattr *tb[])
141 {
142 	int ret;
143 	struct wl1271_command *cmd;
144 	struct sk_buff *skb;
145 	u8 ie_id;
146 
147 	wl1271_debug(DEBUG_TESTMODE, "testmode cmd interrogate");
148 
149 	if (!tb[WL1271_TM_ATTR_IE_ID])
150 		return -EINVAL;
151 
152 	ie_id = nla_get_u8(tb[WL1271_TM_ATTR_IE_ID]);
153 
154 	mutex_lock(&wl->mutex);
155 
156 	if (unlikely(wl->state != WLCORE_STATE_ON)) {
157 		ret = -EINVAL;
158 		goto out;
159 	}
160 
161 	ret = pm_runtime_get_sync(wl->dev);
162 	if (ret < 0) {
163 		pm_runtime_put_noidle(wl->dev);
164 		goto out;
165 	}
166 
167 	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
168 	if (!cmd) {
169 		ret = -ENOMEM;
170 		goto out_sleep;
171 	}
172 
173 	ret = wl1271_cmd_interrogate(wl, ie_id, cmd,
174 				     sizeof(struct acx_header), sizeof(*cmd));
175 	if (ret < 0) {
176 		wl1271_warning("testmode cmd interrogate failed: %d", ret);
177 		goto out_free;
178 	}
179 
180 	skb = cfg80211_testmode_alloc_reply_skb(wl->hw->wiphy, sizeof(*cmd));
181 	if (!skb) {
182 		ret = -ENOMEM;
183 		goto out_free;
184 	}
185 
186 	if (nla_put(skb, WL1271_TM_ATTR_DATA, sizeof(*cmd), cmd)) {
187 		kfree_skb(skb);
188 		ret = -EMSGSIZE;
189 		goto out_free;
190 	}
191 
192 	ret = cfg80211_testmode_reply(skb);
193 	if (ret < 0)
194 		goto out_free;
195 
196 out_free:
197 	kfree(cmd);
198 out_sleep:
199 	pm_runtime_mark_last_busy(wl->dev);
200 	pm_runtime_put_autosuspend(wl->dev);
201 out:
202 	mutex_unlock(&wl->mutex);
203 
204 	return ret;
205 }
206 
wl1271_tm_cmd_configure(struct wl1271 * wl,struct nlattr * tb[])207 static int wl1271_tm_cmd_configure(struct wl1271 *wl, struct nlattr *tb[])
208 {
209 	int buf_len, ret;
210 	void *buf;
211 	u8 ie_id;
212 
213 	wl1271_debug(DEBUG_TESTMODE, "testmode cmd configure");
214 
215 	if (!tb[WL1271_TM_ATTR_DATA])
216 		return -EINVAL;
217 	if (!tb[WL1271_TM_ATTR_IE_ID])
218 		return -EINVAL;
219 
220 	ie_id = nla_get_u8(tb[WL1271_TM_ATTR_IE_ID]);
221 	buf = nla_data(tb[WL1271_TM_ATTR_DATA]);
222 	buf_len = nla_len(tb[WL1271_TM_ATTR_DATA]);
223 
224 	if (buf_len > sizeof(struct wl1271_command))
225 		return -EMSGSIZE;
226 
227 	mutex_lock(&wl->mutex);
228 	ret = wl1271_cmd_configure(wl, ie_id, buf, buf_len);
229 	mutex_unlock(&wl->mutex);
230 
231 	if (ret < 0) {
232 		wl1271_warning("testmode cmd configure failed: %d", ret);
233 		return ret;
234 	}
235 
236 	return 0;
237 }
238 
wl1271_tm_detect_fem(struct wl1271 * wl,struct nlattr * tb[])239 static int wl1271_tm_detect_fem(struct wl1271 *wl, struct nlattr *tb[])
240 {
241 	/* return FEM type */
242 	int ret, len;
243 	struct sk_buff *skb;
244 
245 	ret = wl1271_plt_start(wl, PLT_FEM_DETECT);
246 	if (ret < 0)
247 		goto out;
248 
249 	mutex_lock(&wl->mutex);
250 
251 	len = nla_total_size(sizeof(wl->fem_manuf));
252 	skb = cfg80211_testmode_alloc_reply_skb(wl->hw->wiphy, len);
253 	if (!skb) {
254 		ret = -ENOMEM;
255 		goto out_mutex;
256 	}
257 
258 	if (nla_put(skb, WL1271_TM_ATTR_DATA, sizeof(wl->fem_manuf),
259 					      &wl->fem_manuf)) {
260 		kfree_skb(skb);
261 		ret = -EMSGSIZE;
262 		goto out_mutex;
263 	}
264 
265 	ret = cfg80211_testmode_reply(skb);
266 
267 out_mutex:
268 	mutex_unlock(&wl->mutex);
269 
270 	/* We always stop plt after DETECT mode */
271 	wl1271_plt_stop(wl);
272 out:
273 	return ret;
274 }
275 
wl1271_tm_cmd_set_plt_mode(struct wl1271 * wl,struct nlattr * tb[])276 static int wl1271_tm_cmd_set_plt_mode(struct wl1271 *wl, struct nlattr *tb[])
277 {
278 	u32 val;
279 	int ret;
280 
281 	wl1271_debug(DEBUG_TESTMODE, "testmode cmd set plt mode");
282 
283 	if (!tb[WL1271_TM_ATTR_PLT_MODE])
284 		return -EINVAL;
285 
286 	val = nla_get_u32(tb[WL1271_TM_ATTR_PLT_MODE]);
287 
288 	switch (val) {
289 	case PLT_OFF:
290 		ret = wl1271_plt_stop(wl);
291 		break;
292 	case PLT_ON:
293 	case PLT_CHIP_AWAKE:
294 		ret = wl1271_plt_start(wl, val);
295 		break;
296 	case PLT_FEM_DETECT:
297 		ret = wl1271_tm_detect_fem(wl, tb);
298 		break;
299 	default:
300 		ret = -EINVAL;
301 		break;
302 	}
303 
304 	return ret;
305 }
306 
wl12xx_tm_cmd_get_mac(struct wl1271 * wl,struct nlattr * tb[])307 static int wl12xx_tm_cmd_get_mac(struct wl1271 *wl, struct nlattr *tb[])
308 {
309 	struct sk_buff *skb;
310 	u8 mac_addr[ETH_ALEN];
311 	int ret = 0;
312 
313 	mutex_lock(&wl->mutex);
314 
315 	if (!wl->plt) {
316 		ret = -EINVAL;
317 		goto out;
318 	}
319 
320 	if (wl->fuse_oui_addr == 0 && wl->fuse_nic_addr == 0) {
321 		ret = -EOPNOTSUPP;
322 		goto out;
323 	}
324 
325 	mac_addr[0] = (u8)(wl->fuse_oui_addr >> 16);
326 	mac_addr[1] = (u8)(wl->fuse_oui_addr >> 8);
327 	mac_addr[2] = (u8) wl->fuse_oui_addr;
328 	mac_addr[3] = (u8)(wl->fuse_nic_addr >> 16);
329 	mac_addr[4] = (u8)(wl->fuse_nic_addr >> 8);
330 	mac_addr[5] = (u8) wl->fuse_nic_addr;
331 
332 	skb = cfg80211_testmode_alloc_reply_skb(wl->hw->wiphy, ETH_ALEN);
333 	if (!skb) {
334 		ret = -ENOMEM;
335 		goto out;
336 	}
337 
338 	if (nla_put(skb, WL1271_TM_ATTR_DATA, ETH_ALEN, mac_addr)) {
339 		kfree_skb(skb);
340 		ret = -EMSGSIZE;
341 		goto out;
342 	}
343 
344 	ret = cfg80211_testmode_reply(skb);
345 	if (ret < 0)
346 		goto out;
347 
348 out:
349 	mutex_unlock(&wl->mutex);
350 	return ret;
351 }
352 
wl1271_tm_cmd(struct ieee80211_hw * hw,struct ieee80211_vif * vif,void * data,int len)353 int wl1271_tm_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
354 		  void *data, int len)
355 {
356 	struct wl1271 *wl = hw->priv;
357 	struct nlattr *tb[WL1271_TM_ATTR_MAX + 1];
358 	u32 nla_cmd;
359 	int err;
360 
361 	err = nla_parse_deprecated(tb, WL1271_TM_ATTR_MAX, data, len,
362 				   wl1271_tm_policy, NULL);
363 	if (err)
364 		return err;
365 
366 	if (!tb[WL1271_TM_ATTR_CMD_ID])
367 		return -EINVAL;
368 
369 	nla_cmd = nla_get_u32(tb[WL1271_TM_ATTR_CMD_ID]);
370 
371 	/* Only SET_PLT_MODE is allowed in case of mode PLT_CHIP_AWAKE */
372 	if (wl->plt_mode == PLT_CHIP_AWAKE &&
373 	    nla_cmd != WL1271_TM_CMD_SET_PLT_MODE)
374 		return -EOPNOTSUPP;
375 
376 	switch (nla_cmd) {
377 	case WL1271_TM_CMD_TEST:
378 		return wl1271_tm_cmd_test(wl, tb);
379 	case WL1271_TM_CMD_INTERROGATE:
380 		return wl1271_tm_cmd_interrogate(wl, tb);
381 	case WL1271_TM_CMD_CONFIGURE:
382 		return wl1271_tm_cmd_configure(wl, tb);
383 	case WL1271_TM_CMD_SET_PLT_MODE:
384 		return wl1271_tm_cmd_set_plt_mode(wl, tb);
385 	case WL1271_TM_CMD_GET_MAC:
386 		return wl12xx_tm_cmd_get_mac(wl, tb);
387 	default:
388 		return -EOPNOTSUPP;
389 	}
390 }
391