1/*	$OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $	*/
2
3/*-
4 * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
5 * Copyright (c) 2014 Kevin Lo <kevlo@FreeBSD.org>
6 * Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org>
7 *
8 * Permission to use, copy, modify, and distribute this software for any
9 * purpose with or without fee is hereby granted, provided that the above
10 * copyright notice and this permission notice appear in all copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 */
20
21#include <sys/cdefs.h>
22__FBSDID("$FreeBSD$");
23
24#include "opt_wlan.h"
25
26#include <sys/param.h>
27#include <sys/lock.h>
28#include <sys/mutex.h>
29#include <sys/mbuf.h>
30#include <sys/kernel.h>
31#include <sys/socket.h>
32#include <sys/systm.h>
33#include <sys/malloc.h>
34#include <sys/queue.h>
35#include <sys/taskqueue.h>
36#include <sys/bus.h>
37#include <sys/endian.h>
38#include <sys/linker.h>
39
40#include <net/if.h>
41#include <net/ethernet.h>
42#include <net/if_media.h>
43
44#include <net80211/ieee80211_var.h>
45#include <net80211/ieee80211_radiotap.h>
46#include <net80211/ieee80211_ratectl.h>
47
48#include <dev/rtwn/if_rtwnreg.h>
49#include <dev/rtwn/if_rtwnvar.h>
50
51#include <dev/rtwn/if_rtwn_debug.h>
52#include <dev/rtwn/if_rtwn_ridx.h>
53#include <dev/rtwn/if_rtwn_rx.h>
54#include <dev/rtwn/if_rtwn_task.h>
55#include <dev/rtwn/if_rtwn_tx.h>
56
57#include <dev/rtwn/rtl8192c/r92c.h>
58#include <dev/rtwn/rtl8192c/r92c_reg.h>
59#include <dev/rtwn/rtl8192c/r92c_var.h>
60#include <dev/rtwn/rtl8192c/r92c_fw_cmd.h>
61#include <dev/rtwn/rtl8192c/r92c_tx_desc.h>
62
63#ifndef RTWN_WITHOUT_UCODE
64static int
65r92c_fw_cmd(struct rtwn_softc *sc, uint8_t id, const void *buf, int len)
66{
67	struct r92c_fw_cmd cmd;
68	int ntries, error;
69
70	KASSERT(len <= sizeof(cmd.msg),
71	    ("%s: firmware command too long (%d > %zu)\n",
72	    __func__, len, sizeof(cmd.msg)));
73
74	if (!(sc->sc_flags & RTWN_FW_LOADED)) {
75		RTWN_DPRINTF(sc, RTWN_DEBUG_FIRMWARE, "%s: firmware "
76		    "was not loaded; command (id %u) will be discarded\n",
77		    __func__, id);
78		return (0);
79	}
80
81	/* Wait for current FW box to be empty. */
82	for (ntries = 0; ntries < 100; ntries++) {
83		if (!(rtwn_read_1(sc, R92C_HMETFR) & (1 << sc->fwcur)))
84			break;
85		rtwn_delay(sc, 2000);
86	}
87	if (ntries == 100) {
88		device_printf(sc->sc_dev,
89		    "could not send firmware command\n");
90		return (ETIMEDOUT);
91	}
92	memset(&cmd, 0, sizeof(cmd));
93	cmd.id = id;
94	if (len > 3) {
95		/* Ext command: [id : byte2 : byte3 : byte4 : byte0 : byte1] */
96		cmd.id |= R92C_CMD_FLAG_EXT;
97		memcpy(cmd.msg, (const uint8_t *)buf + 2, len - 2);
98		memcpy(cmd.msg + 3, buf, 2);
99	} else
100		memcpy(cmd.msg, buf, len);
101
102	/* Write the first word last since that will trigger the FW. */
103	if (len > 3) {
104		error = rtwn_write_2(sc, R92C_HMEBOX_EXT(sc->fwcur),
105		    *(uint16_t *)((uint8_t *)&cmd + 4));
106		if (error != 0)
107			return (error);
108	}
109	error = rtwn_write_4(sc, R92C_HMEBOX(sc->fwcur),
110	    *(uint32_t *)&cmd);
111	if (error != 0)
112		return (error);
113
114	sc->fwcur = (sc->fwcur + 1) % R92C_H2C_NBOX;
115
116	return (0);
117}
118
119void
120r92c_fw_reset(struct rtwn_softc *sc, int reason)
121{
122	int ntries;
123
124	if (reason == RTWN_FW_RESET_CHECKSUM)
125		return;
126
127	/* Tell 8051 to reset itself. */
128	rtwn_write_1(sc, R92C_HMETFR + 3, 0x20);
129
130	/* Wait until 8051 resets by itself. */
131	for (ntries = 0; ntries < 100; ntries++) {
132		if ((rtwn_read_2(sc, R92C_SYS_FUNC_EN) &
133		    R92C_SYS_FUNC_EN_CPUEN) == 0)
134			return;
135		rtwn_delay(sc, 50);
136	}
137	/* Force 8051 reset. */
138	rtwn_setbits_1_shift(sc, R92C_SYS_FUNC_EN,
139	    R92C_SYS_FUNC_EN_CPUEN, 0, 1);
140}
141
142void
143r92c_fw_download_enable(struct rtwn_softc *sc, int enable)
144{
145	if (enable) {
146		/* 8051 enable. */
147		rtwn_setbits_1_shift(sc, R92C_SYS_FUNC_EN, 0,
148		    R92C_SYS_FUNC_EN_CPUEN, 1);
149		/* MCU firmware download enable. */
150		rtwn_setbits_1(sc, R92C_MCUFWDL, 0, R92C_MCUFWDL_EN);
151		/* 8051 reset. */
152		rtwn_setbits_1_shift(sc, R92C_MCUFWDL, R92C_MCUFWDL_ROM_DLEN,
153		    0, 2);
154	} else {
155		/* MCU download disable. */
156		rtwn_setbits_1(sc, R92C_MCUFWDL, R92C_MCUFWDL_EN, 0);
157		/* Reserved for f/w extension. */
158		rtwn_write_1(sc, R92C_MCUFWDL + 1, 0);
159	}
160}
161#endif
162
163/*
164 * Initialize firmware rate adaptation.
165 */
166#ifndef RTWN_WITHOUT_UCODE
167static int
168r92c_send_ra_cmd(struct rtwn_softc *sc, int macid, uint32_t rates,
169    int maxrate)
170{
171	struct r92c_fw_cmd_macid_cfg cmd;
172	uint8_t mode;
173	int error = 0;
174
175	/* XXX should be called directly from iv_newstate() for MACID_BC */
176	/* XXX joinbss, not send_ra_cmd() */
177#ifdef RTWN_TODO
178	/* NB: group addressed frames are done at 11bg rates for now */
179	if (ic->ic_curmode == IEEE80211_MODE_11B)
180		mode = R92C_RAID_11B;
181	else
182		mode = R92C_RAID_11BG;
183	/* XXX misleading 'mode' value here for unicast frames */
184	RTWN_DPRINTF(sc, RTWN_DEBUG_RA,
185	    "%s: mode 0x%x, rates 0x%08x, basicrates 0x%08x\n", __func__,
186	    mode, rates, basicrates);
187
188	/* Set rates mask for group addressed frames. */
189	cmd.macid = RTWN_MACID_BC | R92C_CMD_MACID_VALID;
190	cmd.mask = htole32(mode << 28 | basicrates);
191	error = rtwn_fw_cmd(sc, R92C_CMD_MACID_CONFIG, &cmd, sizeof(cmd));
192	if (error != 0) {
193		device_printf(sc->sc_dev,
194		    "could not set RA mask for broadcast station\n");
195		return (error);
196	}
197#endif
198
199	/* Set rates mask for unicast frames. */
200	if (maxrate >= RTWN_RIDX_HT_MCS(0))
201		mode = R92C_RAID_11GN;
202	else if (maxrate >= RTWN_RIDX_OFDM6)
203		mode = R92C_RAID_11BG;
204	else
205		mode = R92C_RAID_11B;
206	cmd.macid = macid | R92C_CMD_MACID_VALID;
207	cmd.mask = htole32(mode << 28 | rates);
208	error = r92c_fw_cmd(sc, R92C_CMD_MACID_CONFIG, &cmd, sizeof(cmd));
209	if (error != 0) {
210		device_printf(sc->sc_dev,
211		    "%s: could not set RA mask for %d station\n",
212		    __func__, macid);
213		return (error);
214	}
215
216	return (0);
217}
218#endif
219
220static void
221r92c_init_ra(struct rtwn_softc *sc, int macid)
222{
223	struct ieee80211_htrateset *rs_ht;
224	struct ieee80211_node *ni;
225	uint32_t rates;
226	int maxrate;
227
228	RTWN_NT_LOCK(sc);
229	if (sc->node_list[macid] == NULL) {
230		RTWN_DPRINTF(sc, RTWN_DEBUG_RA, "%s: macid %d, ni is NULL\n",
231		    __func__, macid);
232		RTWN_NT_UNLOCK(sc);
233		return;
234	}
235
236	ni = ieee80211_ref_node(sc->node_list[macid]);
237	if (ni->ni_flags & IEEE80211_NODE_HT)
238		rs_ht = &ni->ni_htrates;
239	else
240		rs_ht = NULL;
241	/* XXX MACID_BC */
242	rtwn_get_rates(sc, &ni->ni_rates, rs_ht, &rates, &maxrate, 0);
243	RTWN_NT_UNLOCK(sc);
244
245#ifndef RTWN_WITHOUT_UCODE
246	if (sc->sc_ratectl == RTWN_RATECTL_FW) {
247		r92c_send_ra_cmd(sc, macid, rates, maxrate);
248	}
249#endif
250
251	rtwn_write_1(sc, R92C_INIDATA_RATE_SEL(macid), maxrate);
252
253	ieee80211_free_node(ni);
254}
255
256void
257r92c_joinbss_rpt(struct rtwn_softc *sc, int macid)
258{
259#ifndef RTWN_WITHOUT_UCODE
260	struct r92c_softc *rs = sc->sc_priv;
261	struct ieee80211vap *vap;
262	struct r92c_fw_cmd_joinbss_rpt cmd;
263
264	if (sc->vaps[0] == NULL)	/* XXX fix */
265		goto end;
266
267	vap = &sc->vaps[0]->vap;
268	if ((vap->iv_state == IEEE80211_S_RUN) ^
269	    !(rs->rs_flags & R92C_FLAG_ASSOCIATED))
270		goto end;
271
272	if (rs->rs_flags & R92C_FLAG_ASSOCIATED) {
273		cmd.mstatus = R92C_MSTATUS_DISASSOC;
274		rs->rs_flags &= ~R92C_FLAG_ASSOCIATED;
275	} else {
276		cmd.mstatus = R92C_MSTATUS_ASSOC;
277		rs->rs_flags |= R92C_FLAG_ASSOCIATED;
278	}
279
280	if (r92c_fw_cmd(sc, R92C_CMD_JOINBSS_RPT, &cmd, sizeof(cmd)) != 0) {
281		device_printf(sc->sc_dev, "%s: cannot change media status!\n",
282		    __func__);
283	}
284
285end:
286#endif
287
288	/* TODO: init rates for RTWN_MACID_BC. */
289	if (macid & RTWN_MACID_VALID)
290		r92c_init_ra(sc, macid & ~RTWN_MACID_VALID);
291}
292
293#ifndef RTWN_WITHOUT_UCODE
294int
295r92c_set_rsvd_page(struct rtwn_softc *sc, int probe_resp, int null,
296    int qos_null)
297{
298	struct r92c_fw_cmd_rsvdpage rsvd;
299
300	rsvd.probe_resp = probe_resp;
301	rsvd.ps_poll = 0;
302	rsvd.null_data = null;
303
304	return (r92c_fw_cmd(sc, R92C_CMD_RSVD_PAGE, &rsvd, sizeof(rsvd)));
305}
306
307int
308r92c_set_pwrmode(struct rtwn_softc *sc, struct ieee80211vap *vap,
309    int off)
310{
311	struct r92c_fw_cmd_pwrmode mode;
312	int error;
313
314	/* XXX dm_RF_saving */
315
316	if (off && vap->iv_state == IEEE80211_S_RUN &&
317	    (vap->iv_flags & IEEE80211_F_PMGTON))
318		mode.mode = R92C_PWRMODE_MIN;
319	else
320		mode.mode = R92C_PWRMODE_CAM;
321	mode.smart_ps = R92C_PWRMODE_SMARTPS_NULLDATA;
322	mode.bcn_pass = 1;	/* XXX */
323	error = r92c_fw_cmd(sc, R92C_CMD_SET_PWRMODE, &mode, sizeof(mode));
324	if (error != 0) {
325		device_printf(sc->sc_dev,
326		    "%s: CMD_SET_PWRMODE was not sent, error %d\n",
327		    __func__, error);
328	}
329
330	return (error);
331}
332
333void
334r92c_set_rssi(struct rtwn_softc *sc)
335{
336	struct ieee80211_node *ni;
337	struct rtwn_node *rn;
338	struct r92c_fw_cmd_rssi cmd;
339	int i;
340
341	cmd.reserved = 0;
342
343	RTWN_NT_LOCK(sc);
344	for (i = 0; i < sc->macid_limit; i++) {
345		/* XXX optimize? */
346		ni = sc->node_list[i];
347		if (ni == NULL)
348			continue;
349
350		rn = RTWN_NODE(ni);
351		cmd.macid = i;
352		cmd.pwdb = rn->avg_pwdb;
353		RTWN_DPRINTF(sc, RTWN_DEBUG_RSSI,
354		    "%s: sending RSSI command (macid %d, rssi %d)\n",
355		    __func__, i, rn->avg_pwdb);
356
357		RTWN_NT_UNLOCK(sc);
358		r92c_fw_cmd(sc, R92C_CMD_RSSI_SETTING, &cmd, sizeof(cmd));
359		RTWN_NT_LOCK(sc);
360	}
361	RTWN_NT_UNLOCK(sc);
362}
363
364static void
365r92c_ratectl_tx_complete(struct rtwn_softc *sc, uint8_t *buf, int len)
366{
367#if __FreeBSD_version >= 1200012
368	struct ieee80211_ratectl_tx_status txs;
369#endif
370	struct r92c_c2h_tx_rpt *rpt;
371	struct ieee80211_node *ni;
372	uint8_t macid;
373	int ntries;
374
375	if (sc->sc_ratectl != RTWN_RATECTL_NET80211) {
376		/* shouldn't happen */
377		device_printf(sc->sc_dev, "%s called while ratectl = %d!\n",
378		    __func__, sc->sc_ratectl);
379		return;
380	}
381
382	rpt = (struct r92c_c2h_tx_rpt *)buf;
383	if (len != sizeof(*rpt)) {
384		device_printf(sc->sc_dev,
385		    "%s: wrong report size (%d, must be %zu)\n",
386		    __func__, len, sizeof(*rpt));
387		return;
388	}
389
390	RTWN_DPRINTF(sc, RTWN_DEBUG_INTR,
391	    "%s: ccx report dump: 0: %02X, 1: %02X, queue time: "
392	    "low %02X, high %02X, 4: %02X, 5: %02X, 6: %02X, 7: %02X\n",
393	    __func__, rpt->rptb0, rpt->rptb1, rpt->queue_time_low,
394	    rpt->queue_time_high, rpt->rptb4, rpt->rptb5, rpt->rptb6,
395	    rpt->rptb7);
396
397	macid = MS(rpt->rptb5, R92C_RPTB5_MACID);
398	if (macid > sc->macid_limit) {
399		device_printf(sc->sc_dev,
400		    "macid %u is too big; increase MACID_MAX limit\n",
401		    macid);
402		return;
403	}
404
405	ntries = MS(rpt->rptb0, R92C_RPTB0_RETRY_CNT);
406
407	RTWN_NT_LOCK(sc);
408	ni = sc->node_list[macid];
409	if (ni != NULL) {
410		RTWN_DPRINTF(sc, RTWN_DEBUG_INTR, "%s: frame for macid %u was"
411		    "%s sent (%d retries)\n", __func__, macid,
412		    (rpt->rptb7 & R92C_RPTB7_PKT_OK) ? "" : " not",
413		    ntries);
414
415#if __FreeBSD_version >= 1200012
416		txs.flags = IEEE80211_RATECTL_STATUS_LONG_RETRY;
417		txs.long_retries = ntries;
418		if (rpt->rptb7 & R92C_RPTB7_PKT_OK)
419			txs.status = IEEE80211_RATECTL_TX_SUCCESS;
420		else if (rpt->rptb6 & R92C_RPTB6_RETRY_OVER)
421			txs.status = IEEE80211_RATECTL_TX_FAIL_LONG; /* XXX */
422		else if (rpt->rptb6 & R92C_RPTB6_LIFE_EXPIRE)
423			txs.status = IEEE80211_RATECTL_TX_FAIL_EXPIRED;
424		else
425			txs.status = IEEE80211_RATECTL_TX_FAIL_UNSPECIFIED;
426		ieee80211_ratectl_tx_complete(ni, &txs);
427#else
428		struct ieee80211vap *vap = ni->ni_vap;
429		if (rpt->rptb7 & R92C_RPTB7_PKT_OK) {
430			ieee80211_ratectl_tx_complete(vap, ni,
431			    IEEE80211_RATECTL_TX_SUCCESS, &ntries, NULL);
432		} else {
433			ieee80211_ratectl_tx_complete(vap, ni,
434			    IEEE80211_RATECTL_TX_FAILURE, &ntries, NULL);
435		}
436#endif
437	} else {
438		RTWN_DPRINTF(sc, RTWN_DEBUG_INTR, "%s: macid %u, ni is NULL\n",
439		    __func__, macid);
440	}
441	RTWN_NT_UNLOCK(sc);
442
443#ifdef IEEE80211_SUPPORT_SUPERG
444	if (sc->sc_tx_n_active > 0 && --sc->sc_tx_n_active <= 1)
445		rtwn_cmd_sleepable(sc, NULL, 0, rtwn_ff_flush_all);
446#endif
447}
448
449static void
450r92c_handle_c2h_task(struct rtwn_softc *sc, union sec_param *data)
451{
452	const uint16_t off = R92C_C2H_EVT_MSG + sizeof(struct r92c_c2h_evt);
453	struct r92c_softc *rs = sc->sc_priv;
454	uint16_t buf[R92C_C2H_MSG_MAX_LEN / 2 + 1];
455	uint8_t id, len, status;
456	int i;
457
458	/* Do not reschedule the task if device is not running. */
459	if (!(sc->sc_flags & RTWN_RUNNING))
460		return;
461
462	/* Read current status. */
463	status = rtwn_read_1(sc, R92C_C2H_EVT_CLEAR);
464	if (status == R92C_C2H_EVT_HOST_CLOSE)
465		goto end;	/* nothing to do */
466	else if (status == R92C_C2H_EVT_FW_CLOSE) {
467		len = rtwn_read_1(sc, R92C_C2H_EVT_MSG);
468		id = MS(len, R92C_C2H_EVTB0_ID);
469		len = MS(len, R92C_C2H_EVTB0_LEN);
470
471		memset(buf, 0, sizeof(buf));
472		/* Try to optimize event reads. */
473		for (i = 0; i < len; i += 2)
474			buf[i / 2] = rtwn_read_2(sc, off + i);
475		KASSERT(i < sizeof(buf), ("%s: buffer overrun (%d >= %zu)!",
476		    __func__, i, sizeof(buf)));
477
478		switch (id) {
479		case R92C_C2H_EVT_TX_REPORT:
480			r92c_ratectl_tx_complete(sc, (uint8_t *)buf, len);
481			break;
482		default:
483			device_printf(sc->sc_dev,
484			    "%s: C2H report %u (len %u) was not handled\n",
485			    __func__, id, len);
486			break;
487		}
488	}
489
490	/* Prepare for next event. */
491	rtwn_write_1(sc, R92C_C2H_EVT_CLEAR, R92C_C2H_EVT_HOST_CLOSE);
492
493end:
494	/* Adjust timeout for next call. */
495	if (rs->rs_c2h_pending != 0) {
496		rs->rs_c2h_pending = 0;
497		rs->rs_c2h_paused = 0;
498	} else
499		rs->rs_c2h_paused++;
500
501	if (rs->rs_c2h_paused > R92C_TX_PAUSED_THRESHOLD)
502		rs->rs_c2h_timeout = hz;
503	else
504		rs->rs_c2h_timeout = MAX(hz / 100, 1);
505
506	/* Reschedule the task. */
507	callout_reset(&rs->rs_c2h_report, rs->rs_c2h_timeout,
508	    r92c_handle_c2h_report, sc);
509}
510
511void
512r92c_handle_c2h_report(void *arg)
513{
514	struct rtwn_softc *sc = arg;
515
516	rtwn_cmd_sleepable(sc, NULL, 0, r92c_handle_c2h_task);
517}
518
519#endif	/* RTWN_WITHOUT_UCODE */
520