xref: /freebsd/sys/dev/rtwn/rtl8812a/r12a_rx.c (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
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
66 void
67 r12a_ratectl_tx_complete(struct rtwn_softc *sc, uint8_t *buf, int len)
68 {
69 	struct ieee80211_ratectl_tx_status txs;
70 	struct r12a_c2h_tx_rpt *rpt;
71 	struct ieee80211_node *ni;
72 	int ntries;
73 
74 	/* Skip Rx descriptor / report id / sequence fields. */
75 	buf += sizeof(struct r92c_rx_stat) + 2;
76 	len -= sizeof(struct r92c_rx_stat) + 2;
77 
78 	rpt = (struct r12a_c2h_tx_rpt *)buf;
79 	if (len != sizeof(*rpt)) {
80 		device_printf(sc->sc_dev,
81 		    "%s: wrong report size (%d, must be %zu)\n",
82 		    __func__, len, sizeof(*rpt));
83 		return;
84 	}
85 
86 	RTWN_DPRINTF(sc, RTWN_DEBUG_INTR,
87 	    "%s: ccx report dump: 0: %02X, id: %02X, 2: %02X, queue time: "
88 	    "low %02X, high %02X, final ridx: %02X, rsvd: %04X\n",
89 	    __func__, rpt->txrptb0, rpt->macid, rpt->txrptb2,
90 	    rpt->queue_time_low, rpt->queue_time_high, rpt->final_rate,
91 	    rpt->reserved);
92 
93 	if (rpt->macid > sc->macid_limit) {
94 		device_printf(sc->sc_dev,
95 		    "macid %u is too big; increase MACID_MAX limit\n",
96 		    rpt->macid);
97 		return;
98 	}
99 
100 	ntries = MS(rpt->txrptb2, R12A_TXRPTB2_RETRY_CNT);
101 
102 	ni = sc->node_list[rpt->macid];
103 	if (ni != NULL) {
104 		RTWN_DPRINTF(sc, RTWN_DEBUG_INTR, "%s: frame for macid %u was"
105 		    "%s sent (%d retries)\n", __func__, rpt->macid,
106 		    (rpt->txrptb0 & (R12A_TXRPTB0_RETRY_OVER |
107 		    R12A_TXRPTB0_LIFE_EXPIRE)) ? " not" : "", ntries);
108 
109 		txs.flags = IEEE80211_RATECTL_STATUS_LONG_RETRY |
110 			    IEEE80211_RATECTL_STATUS_FINAL_RATE;
111 		txs.long_retries = ntries;
112 		if (rpt->final_rate > RTWN_RIDX_OFDM54) {	/* MCS */
113 			txs.final_rate =
114 			    rpt->final_rate - RTWN_RIDX_HT_MCS_SHIFT;
115 			txs.final_rate |= IEEE80211_RATE_MCS;
116 		} else
117 			txs.final_rate = ridx2rate[rpt->final_rate];
118 		if (rpt->txrptb0 & R12A_TXRPTB0_RETRY_OVER)
119 			txs.status = IEEE80211_RATECTL_TX_FAIL_LONG;
120 		else if (rpt->txrptb0 & R12A_TXRPTB0_LIFE_EXPIRE)
121 			txs.status = IEEE80211_RATECTL_TX_FAIL_EXPIRED;
122 		else
123 			txs.status = IEEE80211_RATECTL_TX_SUCCESS;
124 		ieee80211_ratectl_tx_complete(ni, &txs);
125 	} else {
126 		RTWN_DPRINTF(sc, RTWN_DEBUG_INTR,
127 		    "%s: macid %u, ni is NULL\n", __func__, rpt->macid);
128 	}
129 }
130 
131 void
132 r12a_handle_c2h_report(struct rtwn_softc *sc, uint8_t *buf, int len)
133 {
134 	struct r12a_softc *rs = sc->sc_priv;
135 
136 	/* Skip Rx descriptor. */
137 	buf += sizeof(struct r92c_rx_stat);
138 	len -= sizeof(struct r92c_rx_stat);
139 
140 	if (len < 2) {
141 		device_printf(sc->sc_dev, "C2H report too short (len %d)\n",
142 		    len);
143 		return;
144 	}
145 	len -= 2;
146 
147 	switch (buf[0]) {	/* command id */
148 	case R12A_C2H_TX_REPORT:
149 		/* NOTREACHED */
150 		KASSERT(0, ("use handle_tx_report() instead of %s\n",
151 		    __func__));
152 		break;
153 	case R12A_C2H_IQK_FINISHED:
154 		RTWN_DPRINTF(sc, RTWN_DEBUG_CALIB,
155 		    "FW IQ calibration finished\n");
156 		rs->rs_flags &= ~R12A_IQK_RUNNING;
157 		break;
158 	default:
159 		device_printf(sc->sc_dev,
160 		    "%s: C2H report %u was not handled\n",
161 		    __func__, buf[0]);
162 	}
163 }
164 #else
165 void
166 r12a_ratectl_tx_complete(struct rtwn_softc *sc, uint8_t *buf, int len)
167 {
168 	/* Should not happen. */
169 	device_printf(sc->sc_dev, "%s: called\n", __func__);
170 }
171 
172 void
173 r12a_handle_c2h_report(struct rtwn_softc *sc, uint8_t *buf, int len)
174 {
175 	/* Should not happen. */
176 	device_printf(sc->sc_dev, "%s: called\n", __func__);
177 }
178 #endif
179 
180 int
181 r12a_check_frame_checksum(struct rtwn_softc *sc, struct mbuf *m)
182 {
183 	struct r12a_softc *rs = sc->sc_priv;
184 	struct r92c_rx_stat *stat;
185 	uint32_t rxdw1;
186 
187 	stat = mtod(m, struct r92c_rx_stat *);
188 	rxdw1 = le32toh(stat->rxdw1);
189 	if (rxdw1 & R12A_RXDW1_CKSUM) {
190 		RTWN_DPRINTF(sc, RTWN_DEBUG_RECV,
191 		    "%s: %s/%s checksum is %s\n", __func__,
192 		    (rxdw1 & R12A_RXDW1_UDP) ? "UDP" : "TCP",
193 		    (rxdw1 & R12A_RXDW1_IPV6) ? "IPv6" : "IP",
194 		    (rxdw1 & R12A_RXDW1_CKSUM_ERR) ? "invalid" : "valid");
195 
196 		if (rxdw1 & R12A_RXDW1_CKSUM_ERR)
197 			return (-1);
198 
199 		if ((rxdw1 & R12A_RXDW1_IPV6) ?
200 		    (rs->rs_flags & R12A_RXCKSUM6_EN) :
201 		    (rs->rs_flags & R12A_RXCKSUM_EN)) {
202 			m->m_pkthdr.csum_flags = CSUM_IP_CHECKED |
203 			    CSUM_IP_VALID | CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
204 			m->m_pkthdr.csum_data = 0xffff;
205 		}
206 	}
207 
208 	return (0);
209 }
210 
211 uint8_t
212 r12a_rx_radiotap_flags(const void *buf)
213 {
214 	const struct r92c_rx_stat *stat = buf;
215 	uint8_t flags, rate;
216 
217 	if (!(stat->rxdw4 & htole32(R12A_RXDW4_SPLCP)))
218 		return (0);
219 	rate = MS(le32toh(stat->rxdw3), R12A_RXDW3_RATE);
220 	if (RTWN_RATE_IS_CCK(rate))
221 		flags = IEEE80211_RADIOTAP_F_SHORTPRE;
222 	else
223 		flags = IEEE80211_RADIOTAP_F_SHORTGI;
224 	return (flags);
225 }
226 
227 void
228 r12a_get_rx_stats(struct rtwn_softc *sc, struct ieee80211_rx_stats *rxs,
229     const void *desc, const void *physt_ptr)
230 {
231 	const struct r92c_rx_stat *stat = desc;
232 	const struct r12a_rx_phystat *physt = physt_ptr;
233 	uint32_t rxdw0, rxdw1, rxdw3, rxdw4;
234 	uint8_t rate;
235 
236 	rxdw0 = le32toh(stat->rxdw0);
237 	rxdw1 = le32toh(stat->rxdw1);
238 	rxdw3 = le32toh(stat->rxdw3);
239 	rxdw4 = le32toh(stat->rxdw4);
240 	rate = MS(rxdw3, R12A_RXDW3_RATE);
241 
242 	/* TODO: STBC */
243 	if (rxdw4 & R12A_RXDW4_LDPC)
244 		rxs->c_pktflags |= IEEE80211_RX_F_LDPC;
245 	if (rxdw1 & R12A_RXDW1_AMPDU) {
246 		if (rxdw0 & R92C_RXDW0_PHYST)
247 			rxs->c_pktflags |= IEEE80211_RX_F_AMPDU;
248 		else
249 			rxs->c_pktflags |= IEEE80211_RX_F_AMPDU_MORE;
250 	}
251 
252 	if ((rxdw4 & R12A_RXDW4_SPLCP) && rate >= RTWN_RIDX_HT_MCS(0))
253 		rxs->c_pktflags |= IEEE80211_RX_F_SHORTGI;
254 
255 	switch (MS(rxdw4, R12A_RXDW4_BW)) {
256 	case R12A_RXDW4_BW20:
257 		rxs->c_width = IEEE80211_RX_FW_20MHZ;
258 		break;
259 	case R12A_RXDW4_BW40:
260 		rxs->c_width = IEEE80211_RX_FW_40MHZ;
261 		break;
262 	case R12A_RXDW4_BW80:
263 		rxs->c_width = IEEE80211_RX_FW_80MHZ;
264 		break;
265 	default:
266 		break;
267 	}
268 
269 	if (RTWN_RATE_IS_CCK(rate))
270 		rxs->c_phytype = IEEE80211_RX_FP_11B;
271 	else {
272 		int is5ghz;
273 
274 		/* XXX magic */
275 		/* XXX check with RTL8812AU */
276 		is5ghz = (physt->cfosho[2] != 0x01);
277 
278 		if (rate < RTWN_RIDX_HT_MCS(0)) {
279 			if (is5ghz)
280 				rxs->c_phytype = IEEE80211_RX_FP_11A;
281 			else
282 				rxs->c_phytype = IEEE80211_RX_FP_11G;
283 		} else {
284 			if (is5ghz)
285 				rxs->c_phytype = IEEE80211_RX_FP_11NA;
286 			else
287 				rxs->c_phytype = IEEE80211_RX_FP_11NG;
288 		}
289 	}
290 
291 	/* Map HW rate index to 802.11 rate. */
292 	if (rate < RTWN_RIDX_HT_MCS(0)) {
293 		rxs->c_rate = ridx2rate[rate];
294 		if (RTWN_RATE_IS_CCK(rate))
295 			rxs->c_pktflags |= IEEE80211_RX_F_CCK;
296 		else
297 			rxs->c_pktflags |= IEEE80211_RX_F_OFDM;
298 	} else {	/* MCS0~15. */
299 		/* TODO: VHT rates */
300 		rxs->c_rate =
301 		    IEEE80211_RATE_MCS | (rate - RTWN_RIDX_HT_MCS_SHIFT);
302 		rxs->c_pktflags |= IEEE80211_RX_F_HT;
303 	}
304 
305 	/*
306 	 * XXX always zero for RTL8821AU
307 	 * (vendor driver does not check this field)
308 	 */
309 #if 0
310 	rxs->r_flags |= IEEE80211_R_IEEE | IEEE80211_R_FREQ;
311 	rxs->r_flags |= IEEE80211_R_BAND;
312 	rxs->c_ieee = MS(le16toh(physt->phyw1), R12A_PHYW1_CHAN);
313 	rxs->c_freq = ieee80211_ieee2mhz(rxs->c_ieee,
314 	    (rxs->c_ieee < 36) ? IEEE80211_CHAN_2GHZ : IEEE80211_CHAN_5GHZ);
315 	rxs->c_band = (rxs->c_ieee < 36) ? IEEE80211_CHAN_2GHZ : IEEE80211_CHAN_5GHZ;
316 #endif
317 }
318