1/*-
2 * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD$");
29
30#include "opt_wlan.h"
31
32#include <sys/param.h>
33#include <sys/lock.h>
34#include <sys/mutex.h>
35#include <sys/mbuf.h>
36#include <sys/kernel.h>
37#include <sys/socket.h>
38#include <sys/systm.h>
39#include <sys/malloc.h>
40#include <sys/queue.h>
41#include <sys/taskqueue.h>
42#include <sys/bus.h>
43#include <sys/endian.h>
44#include <sys/linker.h>
45
46#include <net/if.h>
47#include <net/ethernet.h>
48#include <net/if_media.h>
49
50#include <net80211/ieee80211_var.h>
51#include <net80211/ieee80211_radiotap.h>
52#include <net80211/ieee80211_ratectl.h>
53
54#include <dev/rtwn/if_rtwnreg.h>
55#include <dev/rtwn/if_rtwnvar.h>
56
57#include <dev/rtwn/if_rtwn_debug.h>
58#include <dev/rtwn/if_rtwn_ridx.h>
59
60#include <dev/rtwn/rtl8812a/r12a.h>
61#include <dev/rtwn/rtl8812a/r12a_var.h>
62#include <dev/rtwn/rtl8812a/r12a_fw_cmd.h>
63#include <dev/rtwn/rtl8812a/r12a_rx_desc.h>
64
65#ifndef RTWN_WITHOUT_UCODE
66void
67r12a_ratectl_tx_complete(struct rtwn_softc *sc, uint8_t *buf, int len)
68{
69#if __FreeBSD_version >= 1200012
70	struct ieee80211_ratectl_tx_status txs;
71#endif
72	struct r12a_c2h_tx_rpt *rpt;
73	struct ieee80211_node *ni;
74	int ntries;
75
76	/* Skip Rx descriptor / report id / sequence fields. */
77	buf += sizeof(struct r92c_rx_stat) + 2;
78	len -= sizeof(struct r92c_rx_stat) + 2;
79
80	rpt = (struct r12a_c2h_tx_rpt *)buf;
81	if (len != sizeof(*rpt)) {
82		device_printf(sc->sc_dev,
83		    "%s: wrong report size (%d, must be %zu)\n",
84		    __func__, len, sizeof(*rpt));
85		return;
86	}
87
88	RTWN_DPRINTF(sc, RTWN_DEBUG_INTR,
89	    "%s: ccx report dump: 0: %02X, id: %02X, 2: %02X, queue time: "
90	    "low %02X, high %02X, final ridx: %02X, rsvd: %04X\n",
91	    __func__, rpt->txrptb0, rpt->macid, rpt->txrptb2,
92	    rpt->queue_time_low, rpt->queue_time_high, rpt->final_rate,
93	    rpt->reserved);
94
95	if (rpt->macid > sc->macid_limit) {
96		device_printf(sc->sc_dev,
97		    "macid %u is too big; increase MACID_MAX limit\n",
98		    rpt->macid);
99		return;
100	}
101
102	ntries = MS(rpt->txrptb2, R12A_TXRPTB2_RETRY_CNT);
103
104	ni = sc->node_list[rpt->macid];
105	if (ni != NULL) {
106		RTWN_DPRINTF(sc, RTWN_DEBUG_INTR, "%s: frame for macid %u was"
107		    "%s sent (%d retries)\n", __func__, rpt->macid,
108		    (rpt->txrptb0 & (R12A_TXRPTB0_RETRY_OVER |
109		    R12A_TXRPTB0_LIFE_EXPIRE)) ? " not" : "", ntries);
110
111#if __FreeBSD_version >= 1200012
112		txs.flags = IEEE80211_RATECTL_STATUS_LONG_RETRY |
113			    IEEE80211_RATECTL_STATUS_FINAL_RATE;
114		txs.long_retries = ntries;
115		if (rpt->final_rate > RTWN_RIDX_OFDM54) {	/* MCS */
116			txs.final_rate =
117			    rpt->final_rate - RTWN_RIDX_HT_MCS_SHIFT;
118			txs.final_rate |= IEEE80211_RATE_MCS;
119		} else
120			txs.final_rate = ridx2rate[rpt->final_rate];
121		if (rpt->txrptb0 & R12A_TXRPTB0_RETRY_OVER)
122			txs.status = IEEE80211_RATECTL_TX_FAIL_LONG;
123		else if (rpt->txrptb0 & R12A_TXRPTB0_LIFE_EXPIRE)
124			txs.status = IEEE80211_RATECTL_TX_FAIL_EXPIRED;
125		else
126			txs.status = IEEE80211_RATECTL_TX_SUCCESS;
127		ieee80211_ratectl_tx_complete(ni, &txs);
128#else
129		struct ieee80211vap *vap = ni->ni_vap;
130		if (rpt->txrptb0 & R12A_TXRPTB0_RETRY_OVER) {
131			ieee80211_ratectl_tx_complete(vap, ni,
132			    IEEE80211_RATECTL_TX_FAILURE, &ntries, NULL);
133		} else {
134			ieee80211_ratectl_tx_complete(vap, ni,
135			    IEEE80211_RATECTL_TX_SUCCESS, &ntries, NULL);
136		}
137#endif
138	} else {
139		RTWN_DPRINTF(sc, RTWN_DEBUG_INTR,
140		    "%s: macid %u, ni is NULL\n", __func__, rpt->macid);
141	}
142}
143
144void
145r12a_handle_c2h_report(struct rtwn_softc *sc, uint8_t *buf, int len)
146{
147	struct r12a_softc *rs = sc->sc_priv;
148
149	/* Skip Rx descriptor. */
150	buf += sizeof(struct r92c_rx_stat);
151	len -= sizeof(struct r92c_rx_stat);
152
153	if (len < 2) {
154		device_printf(sc->sc_dev, "C2H report too short (len %d)\n",
155		    len);
156		return;
157	}
158	len -= 2;
159
160	switch (buf[0]) {	/* command id */
161	case R12A_C2H_TX_REPORT:
162		/* NOTREACHED */
163		KASSERT(0, ("use handle_tx_report() instead of %s\n",
164		    __func__));
165		break;
166	case R12A_C2H_IQK_FINISHED:
167		RTWN_DPRINTF(sc, RTWN_DEBUG_CALIB,
168		    "FW IQ calibration finished\n");
169		rs->rs_flags &= ~R12A_IQK_RUNNING;
170		break;
171	default:
172		device_printf(sc->sc_dev,
173		    "%s: C2H report %u was not handled\n",
174		    __func__, buf[0]);
175	}
176}
177#else
178void
179r12a_ratectl_tx_complete(struct rtwn_softc *sc, uint8_t *buf, int len)
180{
181	/* Should not happen. */
182	device_printf(sc->sc_dev, "%s: called\n", __func__);
183}
184
185void
186r12a_handle_c2h_report(struct rtwn_softc *sc, uint8_t *buf, int len)
187{
188	/* Should not happen. */
189	device_printf(sc->sc_dev, "%s: called\n", __func__);
190}
191#endif
192
193int
194r12a_check_frame_checksum(struct rtwn_softc *sc, struct mbuf *m)
195{
196	struct r12a_softc *rs = sc->sc_priv;
197	struct r92c_rx_stat *stat;
198	uint32_t rxdw1;
199
200	stat = mtod(m, struct r92c_rx_stat *);
201	rxdw1 = le32toh(stat->rxdw1);
202	if (rxdw1 & R12A_RXDW1_CKSUM) {
203		RTWN_DPRINTF(sc, RTWN_DEBUG_RECV,
204		    "%s: %s/%s checksum is %s\n", __func__,
205		    (rxdw1 & R12A_RXDW1_UDP) ? "UDP" : "TCP",
206		    (rxdw1 & R12A_RXDW1_IPV6) ? "IPv6" : "IP",
207		    (rxdw1 & R12A_RXDW1_CKSUM_ERR) ? "invalid" : "valid");
208
209		if (rxdw1 & R12A_RXDW1_CKSUM_ERR)
210			return (-1);
211
212		if ((rxdw1 & R12A_RXDW1_IPV6) ?
213		    (rs->rs_flags & R12A_RXCKSUM6_EN) :
214		    (rs->rs_flags & R12A_RXCKSUM_EN)) {
215			m->m_pkthdr.csum_flags = CSUM_IP_CHECKED |
216			    CSUM_IP_VALID | CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
217			m->m_pkthdr.csum_data = 0xffff;
218		}
219	}
220
221	return (0);
222}
223
224uint8_t
225r12a_rx_radiotap_flags(const void *buf)
226{
227	const struct r92c_rx_stat *stat = buf;
228	uint8_t flags, rate;
229
230	if (!(stat->rxdw4 & htole32(R12A_RXDW4_SPLCP)))
231		return (0);
232	rate = MS(le32toh(stat->rxdw3), R12A_RXDW3_RATE);
233	if (RTWN_RATE_IS_CCK(rate))
234		flags = IEEE80211_RADIOTAP_F_SHORTPRE;
235	else
236		flags = IEEE80211_RADIOTAP_F_SHORTGI;
237	return (flags);
238}
239
240void
241r12a_get_rx_stats(struct rtwn_softc *sc, struct ieee80211_rx_stats *rxs,
242    const void *desc, const void *physt_ptr)
243{
244	const struct r92c_rx_stat *stat = desc;
245	const struct r12a_rx_phystat *physt = physt_ptr;
246	uint32_t rxdw0, rxdw1, rxdw3, rxdw4;
247	uint8_t rate;
248
249	rxdw0 = le32toh(stat->rxdw0);
250	rxdw1 = le32toh(stat->rxdw1);
251	rxdw3 = le32toh(stat->rxdw3);
252	rxdw4 = le32toh(stat->rxdw4);
253	rate = MS(rxdw3, R12A_RXDW3_RATE);
254
255	/* TODO: STBC */
256	if (rxdw4 & R12A_RXDW4_LDPC)
257		rxs->c_pktflags |= IEEE80211_RX_F_LDPC;
258	if (rxdw1 & R12A_RXDW1_AMPDU) {
259		if (rxdw0 & R92C_RXDW0_PHYST)
260			rxs->c_pktflags |= IEEE80211_RX_F_AMPDU;
261		else
262			rxs->c_pktflags |= IEEE80211_RX_F_AMPDU_MORE;
263	}
264
265	if ((rxdw4 & R12A_RXDW4_SPLCP) && rate >= RTWN_RIDX_HT_MCS(0))
266		rxs->c_pktflags |= IEEE80211_RX_F_SHORTGI;
267
268	switch (MS(rxdw4, R12A_RXDW4_BW)) {
269	case R12A_RXDW4_BW20:
270		rxs->c_width = IEEE80211_RX_FW_20MHZ;
271		break;
272	case R12A_RXDW4_BW40:
273		rxs->c_width = IEEE80211_RX_FW_40MHZ;
274		break;
275	case R12A_RXDW4_BW80:
276		rxs->c_width = IEEE80211_RX_FW_80MHZ;
277		break;
278	default:
279		break;
280	}
281
282	if (RTWN_RATE_IS_CCK(rate))
283		rxs->c_phytype = IEEE80211_RX_FP_11B;
284	else {
285		int is5ghz;
286
287		/* XXX magic */
288		/* XXX check with RTL8812AU */
289		is5ghz = (physt->cfosho[2] != 0x01);
290
291		if (rate < RTWN_RIDX_HT_MCS(0)) {
292			if (is5ghz)
293				rxs->c_phytype = IEEE80211_RX_FP_11A;
294			else
295				rxs->c_phytype = IEEE80211_RX_FP_11G;
296		} else {
297			if (is5ghz)
298				rxs->c_phytype = IEEE80211_RX_FP_11NA;
299			else
300				rxs->c_phytype = IEEE80211_RX_FP_11NG;
301		}
302	}
303
304	/* Map HW rate index to 802.11 rate. */
305	if (rate < RTWN_RIDX_HT_MCS(0)) {
306		rxs->c_rate = ridx2rate[rate];
307		if (RTWN_RATE_IS_CCK(rate))
308			rxs->c_pktflags |= IEEE80211_RX_F_CCK;
309		else
310			rxs->c_pktflags |= IEEE80211_RX_F_OFDM;
311	} else {	/* MCS0~15. */
312		/* TODO: VHT rates */
313		rxs->c_rate =
314		    IEEE80211_RATE_MCS | (rate - RTWN_RIDX_HT_MCS_SHIFT);
315		rxs->c_pktflags |= IEEE80211_RX_F_HT;
316	}
317
318	/*
319	 * XXX always zero for RTL8821AU
320	 * (vendor driver does not check this field)
321	 */
322#if 0
323	rxs->r_flags |= IEEE80211_R_IEEE | IEEE80211_R_FREQ;
324	rxs->r_flags |= IEEE80211_R_BAND;
325	rxs->c_ieee = MS(le16toh(physt->phyw1), R12A_PHYW1_CHAN);
326	rxs->c_freq = ieee80211_ieee2mhz(rxs->c_ieee,
327	    (rxs->c_ieee < 36) ? IEEE80211_CHAN_2GHZ : IEEE80211_CHAN_5GHZ);
328	rxs->c_band = (rxs->c_ieee < 36) ? IEEE80211_CHAN_2GHZ : IEEE80211_CHAN_5GHZ;
329#endif
330}
331