1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Implementation of the host-to-chip commands (aka request/confirmation) of the
4 * hardware API.
5 *
6 * Copyright (c) 2017-2020, Silicon Laboratories, Inc.
7 * Copyright (c) 2010, ST-Ericsson
8 */
9#include <linux/etherdevice.h>
10
11#include "hif_tx.h"
12#include "wfx.h"
13#include "bh.h"
14#include "hwio.h"
15#include "debug.h"
16#include "sta.h"
17
18void wfx_init_hif_cmd(struct wfx_hif_cmd *hif_cmd)
19{
20	init_completion(&hif_cmd->ready);
21	init_completion(&hif_cmd->done);
22	mutex_init(&hif_cmd->lock);
23}
24
25static void wfx_fill_header(struct wfx_hif_msg *hif, int if_id, unsigned int cmd, size_t size)
26{
27	if (if_id == -1)
28		if_id = 2;
29
30	WARN(cmd > 0x3f, "invalid hardware command %#.2x", cmd);
31	WARN(size > 0xFFF, "requested buffer is too large: %zu bytes", size);
32	WARN(if_id > 0x3, "invalid interface ID %d", if_id);
33
34	hif->len = cpu_to_le16(size + 4);
35	hif->id = cmd;
36	hif->interface = if_id;
37}
38
39static void *wfx_alloc_hif(size_t body_len, struct wfx_hif_msg **hif)
40{
41	*hif = kzalloc(sizeof(struct wfx_hif_msg) + body_len, GFP_KERNEL);
42	if (*hif)
43		return (*hif)->body;
44	else
45		return NULL;
46}
47
48int wfx_cmd_send(struct wfx_dev *wdev, struct wfx_hif_msg *request,
49		 void *reply, size_t reply_len, bool no_reply)
50{
51	const char *mib_name = "";
52	const char *mib_sep = "";
53	int cmd = request->id;
54	int vif = request->interface;
55	int ret;
56
57	/* Do not wait for any reply if chip is frozen */
58	if (wdev->chip_frozen)
59		return -ETIMEDOUT;
60
61	mutex_lock(&wdev->hif_cmd.lock);
62	WARN(wdev->hif_cmd.buf_send, "data locking error");
63
64	/* Note: call to complete() below has an implicit memory barrier that hopefully protect
65	 * buf_send
66	 */
67	wdev->hif_cmd.buf_send = request;
68	wdev->hif_cmd.buf_recv = reply;
69	wdev->hif_cmd.len_recv = reply_len;
70	complete(&wdev->hif_cmd.ready);
71
72	wfx_bh_request_tx(wdev);
73
74	if (no_reply) {
75		/* Chip won't reply. Ensure the wq has send the buffer before to continue. */
76		flush_workqueue(wdev->bh_wq);
77		ret = 0;
78		goto end;
79	}
80
81	if (wdev->poll_irq)
82		wfx_bh_poll_irq(wdev);
83
84	ret = wait_for_completion_timeout(&wdev->hif_cmd.done, 1 * HZ);
85	if (!ret) {
86		dev_err(wdev->dev, "chip is abnormally long to answer\n");
87		reinit_completion(&wdev->hif_cmd.ready);
88		ret = wait_for_completion_timeout(&wdev->hif_cmd.done, 3 * HZ);
89	}
90	if (!ret) {
91		dev_err(wdev->dev, "chip did not answer\n");
92		wfx_pending_dump_old_frames(wdev, 3000);
93		wdev->chip_frozen = true;
94		reinit_completion(&wdev->hif_cmd.done);
95		ret = -ETIMEDOUT;
96	} else {
97		ret = wdev->hif_cmd.ret;
98	}
99
100end:
101	wdev->hif_cmd.buf_send = NULL;
102	mutex_unlock(&wdev->hif_cmd.lock);
103
104	if (ret &&
105	    (cmd == HIF_REQ_ID_READ_MIB || cmd == HIF_REQ_ID_WRITE_MIB)) {
106		mib_name = wfx_get_mib_name(((u16 *)request)[2]);
107		mib_sep = "/";
108	}
109	if (ret < 0)
110		dev_err(wdev->dev, "hardware request %s%s%s (%#.2x) on vif %d returned error %d\n",
111			wfx_get_hif_name(cmd), mib_sep, mib_name, cmd, vif, ret);
112	if (ret > 0)
113		dev_warn(wdev->dev, "hardware request %s%s%s (%#.2x) on vif %d returned status %d\n",
114			 wfx_get_hif_name(cmd), mib_sep, mib_name, cmd, vif, ret);
115
116	return ret;
117}
118
119/* This function is special. After HIF_REQ_ID_SHUT_DOWN, chip won't reply to any request anymore.
120 * Obviously, only call this function during device unregister.
121 */
122int wfx_hif_shutdown(struct wfx_dev *wdev)
123{
124	int ret;
125	struct wfx_hif_msg *hif;
126
127	wfx_alloc_hif(0, &hif);
128	if (!hif)
129		return -ENOMEM;
130	wfx_fill_header(hif, -1, HIF_REQ_ID_SHUT_DOWN, 0);
131	ret = wfx_cmd_send(wdev, hif, NULL, 0, true);
132	if (wdev->pdata.gpio_wakeup)
133		gpiod_set_value(wdev->pdata.gpio_wakeup, 0);
134	else
135		wfx_control_reg_write(wdev, 0);
136	kfree(hif);
137	return ret;
138}
139
140int wfx_hif_configuration(struct wfx_dev *wdev, const u8 *conf, size_t len)
141{
142	int ret;
143	size_t buf_len = sizeof(struct wfx_hif_req_configuration) + len;
144	struct wfx_hif_msg *hif;
145	struct wfx_hif_req_configuration *body = wfx_alloc_hif(buf_len, &hif);
146
147	if (!hif)
148		return -ENOMEM;
149	body->length = cpu_to_le16(len);
150	memcpy(body->pds_data, conf, len);
151	wfx_fill_header(hif, -1, HIF_REQ_ID_CONFIGURATION, buf_len);
152	ret = wfx_cmd_send(wdev, hif, NULL, 0, false);
153	kfree(hif);
154	return ret;
155}
156
157int wfx_hif_reset(struct wfx_vif *wvif, bool reset_stat)
158{
159	int ret;
160	struct wfx_hif_msg *hif;
161	struct wfx_hif_req_reset *body = wfx_alloc_hif(sizeof(*body), &hif);
162
163	if (!hif)
164		return -ENOMEM;
165	body->reset_stat = reset_stat;
166	wfx_fill_header(hif, wvif->id, HIF_REQ_ID_RESET, sizeof(*body));
167	ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false);
168	kfree(hif);
169	return ret;
170}
171
172int wfx_hif_read_mib(struct wfx_dev *wdev, int vif_id, u16 mib_id, void *val, size_t val_len)
173{
174	int ret;
175	struct wfx_hif_msg *hif;
176	int buf_len = sizeof(struct wfx_hif_cnf_read_mib) + val_len;
177	struct wfx_hif_req_read_mib *body = wfx_alloc_hif(sizeof(*body), &hif);
178	struct wfx_hif_cnf_read_mib *reply = kmalloc(buf_len, GFP_KERNEL);
179
180	if (!body || !reply) {
181		ret = -ENOMEM;
182		goto out;
183	}
184	body->mib_id = cpu_to_le16(mib_id);
185	wfx_fill_header(hif, vif_id, HIF_REQ_ID_READ_MIB, sizeof(*body));
186	ret = wfx_cmd_send(wdev, hif, reply, buf_len, false);
187
188	if (!ret && mib_id != le16_to_cpu(reply->mib_id)) {
189		dev_warn(wdev->dev, "%s: confirmation mismatch request\n", __func__);
190		ret = -EIO;
191	}
192	if (ret == -ENOMEM)
193		dev_err(wdev->dev, "buffer is too small to receive %s (%zu < %d)\n",
194			wfx_get_mib_name(mib_id), val_len, le16_to_cpu(reply->length));
195	if (!ret)
196		memcpy(val, &reply->mib_data, le16_to_cpu(reply->length));
197	else
198		memset(val, 0xFF, val_len);
199out:
200	kfree(hif);
201	kfree(reply);
202	return ret;
203}
204
205int wfx_hif_write_mib(struct wfx_dev *wdev, int vif_id, u16 mib_id, void *val, size_t val_len)
206{
207	int ret;
208	struct wfx_hif_msg *hif;
209	int buf_len = sizeof(struct wfx_hif_req_write_mib) + val_len;
210	struct wfx_hif_req_write_mib *body = wfx_alloc_hif(buf_len, &hif);
211
212	if (!hif)
213		return -ENOMEM;
214	body->mib_id = cpu_to_le16(mib_id);
215	body->length = cpu_to_le16(val_len);
216	memcpy(&body->mib_data, val, val_len);
217	wfx_fill_header(hif, vif_id, HIF_REQ_ID_WRITE_MIB, buf_len);
218	ret = wfx_cmd_send(wdev, hif, NULL, 0, false);
219	kfree(hif);
220	return ret;
221}
222
223int wfx_hif_scan(struct wfx_vif *wvif, struct cfg80211_scan_request *req,
224		 int chan_start_idx, int chan_num)
225{
226	int ret, i;
227	struct wfx_hif_msg *hif;
228	size_t buf_len = sizeof(struct wfx_hif_req_start_scan_alt) + chan_num * sizeof(u8);
229	struct wfx_hif_req_start_scan_alt *body = wfx_alloc_hif(buf_len, &hif);
230
231	WARN(chan_num > HIF_API_MAX_NB_CHANNELS, "invalid params");
232	WARN(req->n_ssids > HIF_API_MAX_NB_SSIDS, "invalid params");
233
234	if (!hif)
235		return -ENOMEM;
236	for (i = 0; i < req->n_ssids; i++) {
237		memcpy(body->ssid_def[i].ssid, req->ssids[i].ssid, IEEE80211_MAX_SSID_LEN);
238		body->ssid_def[i].ssid_length = cpu_to_le32(req->ssids[i].ssid_len);
239	}
240	body->num_of_ssids = HIF_API_MAX_NB_SSIDS;
241	body->maintain_current_bss = 1;
242	body->disallow_ps = 1;
243	body->tx_power_level = cpu_to_le32(req->channels[chan_start_idx]->max_power);
244	body->num_of_channels = chan_num;
245	for (i = 0; i < chan_num; i++)
246		body->channel_list[i] = req->channels[i + chan_start_idx]->hw_value;
247	if (req->no_cck)
248		body->max_transmit_rate = API_RATE_INDEX_G_6MBPS;
249	else
250		body->max_transmit_rate = API_RATE_INDEX_B_1MBPS;
251	if (req->channels[chan_start_idx]->flags & IEEE80211_CHAN_NO_IR) {
252		body->min_channel_time = cpu_to_le32(50);
253		body->max_channel_time = cpu_to_le32(150);
254	} else {
255		body->min_channel_time = cpu_to_le32(10);
256		body->max_channel_time = cpu_to_le32(50);
257		body->num_of_probe_requests = 2;
258		body->probe_delay = 100;
259	}
260
261	wfx_fill_header(hif, wvif->id, HIF_REQ_ID_START_SCAN, buf_len);
262	ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false);
263	kfree(hif);
264	return ret;
265}
266
267int wfx_hif_stop_scan(struct wfx_vif *wvif)
268{
269	int ret;
270	struct wfx_hif_msg *hif;
271	/* body associated to HIF_REQ_ID_STOP_SCAN is empty */
272	wfx_alloc_hif(0, &hif);
273
274	if (!hif)
275		return -ENOMEM;
276	wfx_fill_header(hif, wvif->id, HIF_REQ_ID_STOP_SCAN, 0);
277	ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false);
278	kfree(hif);
279	return ret;
280}
281
282int wfx_hif_join(struct wfx_vif *wvif, const struct ieee80211_bss_conf *conf,
283		 struct ieee80211_channel *channel, const u8 *ssid, int ssid_len)
284{
285	struct ieee80211_vif *vif = container_of(conf, struct ieee80211_vif,
286						 bss_conf);
287	int ret;
288	struct wfx_hif_msg *hif;
289	struct wfx_hif_req_join *body = wfx_alloc_hif(sizeof(*body), &hif);
290
291	WARN_ON(!conf->beacon_int);
292	WARN_ON(!conf->basic_rates);
293	WARN_ON(sizeof(body->ssid) < ssid_len);
294	WARN(!vif->cfg.ibss_joined && !ssid_len, "joining an unknown BSS");
295	if (!hif)
296		return -ENOMEM;
297	body->infrastructure_bss_mode = !vif->cfg.ibss_joined;
298	body->short_preamble = conf->use_short_preamble;
299	body->probe_for_join = !(channel->flags & IEEE80211_CHAN_NO_IR);
300	body->channel_number = channel->hw_value;
301	body->beacon_interval = cpu_to_le32(conf->beacon_int);
302	body->basic_rate_set = cpu_to_le32(wfx_rate_mask_to_hw(wvif->wdev, conf->basic_rates));
303	memcpy(body->bssid, conf->bssid, sizeof(body->bssid));
304	if (ssid) {
305		body->ssid_length = cpu_to_le32(ssid_len);
306		memcpy(body->ssid, ssid, ssid_len);
307	}
308	wfx_fill_header(hif, wvif->id, HIF_REQ_ID_JOIN, sizeof(*body));
309	ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false);
310	kfree(hif);
311	return ret;
312}
313
314int wfx_hif_set_bss_params(struct wfx_vif *wvif, int aid, int beacon_lost_count)
315{
316	int ret;
317	struct wfx_hif_msg *hif;
318	struct wfx_hif_req_set_bss_params *body = wfx_alloc_hif(sizeof(*body), &hif);
319
320	if (!hif)
321		return -ENOMEM;
322	body->aid = cpu_to_le16(aid);
323	body->beacon_lost_count = beacon_lost_count;
324	wfx_fill_header(hif, wvif->id, HIF_REQ_ID_SET_BSS_PARAMS, sizeof(*body));
325	ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false);
326	kfree(hif);
327	return ret;
328}
329
330int wfx_hif_add_key(struct wfx_dev *wdev, const struct wfx_hif_req_add_key *arg)
331{
332	int ret;
333	struct wfx_hif_msg *hif;
334	/* FIXME: only send necessary bits */
335	struct wfx_hif_req_add_key *body = wfx_alloc_hif(sizeof(*body), &hif);
336
337	if (!hif)
338		return -ENOMEM;
339	/* FIXME: swap bytes as necessary in body */
340	memcpy(body, arg, sizeof(*body));
341	if (wfx_api_older_than(wdev, 1, 5))
342		/* Legacy firmwares expect that add_key to be sent on right interface. */
343		wfx_fill_header(hif, arg->int_id, HIF_REQ_ID_ADD_KEY, sizeof(*body));
344	else
345		wfx_fill_header(hif, -1, HIF_REQ_ID_ADD_KEY, sizeof(*body));
346	ret = wfx_cmd_send(wdev, hif, NULL, 0, false);
347	kfree(hif);
348	return ret;
349}
350
351int wfx_hif_remove_key(struct wfx_dev *wdev, int idx)
352{
353	int ret;
354	struct wfx_hif_msg *hif;
355	struct wfx_hif_req_remove_key *body = wfx_alloc_hif(sizeof(*body), &hif);
356
357	if (!hif)
358		return -ENOMEM;
359	body->entry_index = idx;
360	wfx_fill_header(hif, -1, HIF_REQ_ID_REMOVE_KEY, sizeof(*body));
361	ret = wfx_cmd_send(wdev, hif, NULL, 0, false);
362	kfree(hif);
363	return ret;
364}
365
366int wfx_hif_set_edca_queue_params(struct wfx_vif *wvif, u16 queue,
367				  const struct ieee80211_tx_queue_params *arg)
368{
369	int ret;
370	struct wfx_hif_msg *hif;
371	struct wfx_hif_req_edca_queue_params *body = wfx_alloc_hif(sizeof(*body), &hif);
372
373	if (!body)
374		return -ENOMEM;
375
376	WARN_ON(arg->aifs > 255);
377	if (!hif)
378		return -ENOMEM;
379	body->aifsn = arg->aifs;
380	body->cw_min = cpu_to_le16(arg->cw_min);
381	body->cw_max = cpu_to_le16(arg->cw_max);
382	body->tx_op_limit = cpu_to_le16(arg->txop * USEC_PER_TXOP);
383	body->queue_id = 3 - queue;
384	/* API 2.0 has changed queue IDs values */
385	if (wfx_api_older_than(wvif->wdev, 2, 0) && queue == IEEE80211_AC_BE)
386		body->queue_id = HIF_QUEUE_ID_BACKGROUND;
387	if (wfx_api_older_than(wvif->wdev, 2, 0) && queue == IEEE80211_AC_BK)
388		body->queue_id = HIF_QUEUE_ID_BESTEFFORT;
389	wfx_fill_header(hif, wvif->id, HIF_REQ_ID_EDCA_QUEUE_PARAMS, sizeof(*body));
390	ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false);
391	kfree(hif);
392	return ret;
393}
394
395int wfx_hif_set_pm(struct wfx_vif *wvif, bool ps, int dynamic_ps_timeout)
396{
397	int ret;
398	struct wfx_hif_msg *hif;
399	struct wfx_hif_req_set_pm_mode *body = wfx_alloc_hif(sizeof(*body), &hif);
400
401	if (!body)
402		return -ENOMEM;
403
404	if (!hif)
405		return -ENOMEM;
406	if (ps) {
407		body->enter_psm = 1;
408		/* Firmware does not support more than 128ms */
409		body->fast_psm_idle_period = min(dynamic_ps_timeout * 2, 255);
410		if (body->fast_psm_idle_period)
411			body->fast_psm = 1;
412	}
413	wfx_fill_header(hif, wvif->id, HIF_REQ_ID_SET_PM_MODE, sizeof(*body));
414	ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false);
415	kfree(hif);
416	return ret;
417}
418
419int wfx_hif_start(struct wfx_vif *wvif, const struct ieee80211_bss_conf *conf,
420		  const struct ieee80211_channel *channel)
421{
422        struct ieee80211_vif *vif = container_of(conf, struct ieee80211_vif,
423						 bss_conf);
424	int ret;
425	struct wfx_hif_msg *hif;
426	struct wfx_hif_req_start *body = wfx_alloc_hif(sizeof(*body), &hif);
427
428	WARN_ON(!conf->beacon_int);
429	if (!hif)
430		return -ENOMEM;
431	body->dtim_period = conf->dtim_period;
432	body->short_preamble = conf->use_short_preamble;
433	body->channel_number = channel->hw_value;
434	body->beacon_interval = cpu_to_le32(conf->beacon_int);
435	body->basic_rate_set = cpu_to_le32(wfx_rate_mask_to_hw(wvif->wdev, conf->basic_rates));
436	body->ssid_length = vif->cfg.ssid_len;
437	memcpy(body->ssid, vif->cfg.ssid, vif->cfg.ssid_len);
438	wfx_fill_header(hif, wvif->id, HIF_REQ_ID_START, sizeof(*body));
439	ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false);
440	kfree(hif);
441	return ret;
442}
443
444int wfx_hif_beacon_transmit(struct wfx_vif *wvif, bool enable)
445{
446	int ret;
447	struct wfx_hif_msg *hif;
448	struct wfx_hif_req_beacon_transmit *body = wfx_alloc_hif(sizeof(*body), &hif);
449
450	if (!hif)
451		return -ENOMEM;
452	body->enable_beaconing = enable ? 1 : 0;
453	wfx_fill_header(hif, wvif->id, HIF_REQ_ID_BEACON_TRANSMIT, sizeof(*body));
454	ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false);
455	kfree(hif);
456	return ret;
457}
458
459int wfx_hif_map_link(struct wfx_vif *wvif, bool unmap, u8 *mac_addr, int sta_id, bool mfp)
460{
461	int ret;
462	struct wfx_hif_msg *hif;
463	struct wfx_hif_req_map_link *body = wfx_alloc_hif(sizeof(*body), &hif);
464
465	if (!hif)
466		return -ENOMEM;
467	if (mac_addr)
468		ether_addr_copy(body->mac_addr, mac_addr);
469	body->mfpc = mfp ? 1 : 0;
470	body->unmap = unmap ? 1 : 0;
471	body->peer_sta_id = sta_id;
472	wfx_fill_header(hif, wvif->id, HIF_REQ_ID_MAP_LINK, sizeof(*body));
473	ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false);
474	kfree(hif);
475	return ret;
476}
477
478int wfx_hif_update_ie_beacon(struct wfx_vif *wvif, const u8 *ies, size_t ies_len)
479{
480	int ret;
481	struct wfx_hif_msg *hif;
482	int buf_len = sizeof(struct wfx_hif_req_update_ie) + ies_len;
483	struct wfx_hif_req_update_ie *body = wfx_alloc_hif(buf_len, &hif);
484
485	if (!hif)
486		return -ENOMEM;
487	body->beacon = 1;
488	body->num_ies = cpu_to_le16(1);
489	memcpy(body->ie, ies, ies_len);
490	wfx_fill_header(hif, wvif->id, HIF_REQ_ID_UPDATE_IE, buf_len);
491	ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false);
492	kfree(hif);
493	return ret;
494}
495