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 #include "opt_wlan.h"
29
30 #include <sys/param.h>
31 #include <sys/lock.h>
32 #include <sys/mutex.h>
33 #include <sys/mbuf.h>
34 #include <sys/kernel.h>
35 #include <sys/socket.h>
36 #include <sys/systm.h>
37 #include <sys/malloc.h>
38 #include <sys/queue.h>
39 #include <sys/taskqueue.h>
40 #include <sys/bus.h>
41 #include <sys/endian.h>
42 #include <sys/linker.h>
43
44 #include <net/if.h>
45 #include <net/ethernet.h>
46 #include <net/if_media.h>
47
48 #include <net80211/ieee80211_var.h>
49 #include <net80211/ieee80211_radiotap.h>
50 #include <net80211/ieee80211_ratectl.h>
51
52 #include <dev/rtwn/if_rtwnreg.h>
53 #include <dev/rtwn/if_rtwnvar.h>
54
55 #include <dev/rtwn/if_rtwn_debug.h>
56 #include <dev/rtwn/if_rtwn_ridx.h>
57
58 #include <dev/rtwn/rtl8812a/r12a.h>
59 #include <dev/rtwn/rtl8812a/r12a_var.h>
60 #include <dev/rtwn/rtl8812a/r12a_fw_cmd.h>
61 #include <dev/rtwn/rtl8812a/r12a_rx_desc.h>
62
63 #ifndef RTWN_WITHOUT_UCODE
64 void
r12a_ratectl_tx_complete(struct rtwn_softc * sc,uint8_t * buf,int len)65 r12a_ratectl_tx_complete(struct rtwn_softc *sc, uint8_t *buf, int len)
66 {
67 struct ieee80211_ratectl_tx_status txs;
68 struct r12a_c2h_tx_rpt *rpt;
69 struct ieee80211_node *ni;
70 int ntries;
71
72 /* Skip Rx descriptor / report id / sequence fields. */
73 buf += sizeof(struct r92c_rx_stat) + 2;
74 len -= sizeof(struct r92c_rx_stat) + 2;
75
76 rpt = (struct r12a_c2h_tx_rpt *)buf;
77 if (len != sizeof(*rpt)) {
78 device_printf(sc->sc_dev,
79 "%s: wrong report size (%d, must be %zu)\n",
80 __func__, len, sizeof(*rpt));
81 return;
82 }
83
84 RTWN_DPRINTF(sc, RTWN_DEBUG_INTR,
85 "%s: ccx report dump: 0: %02X, id: %02X, 2: %02X, queue time: "
86 "low %02X, high %02X, final ridx: %02X, rsvd: %04X\n",
87 __func__, rpt->txrptb0, rpt->macid, rpt->txrptb2,
88 rpt->queue_time_low, rpt->queue_time_high, rpt->final_rate,
89 rpt->reserved);
90
91 if (rpt->macid > sc->macid_limit) {
92 device_printf(sc->sc_dev,
93 "macid %u is too big; increase MACID_MAX limit\n",
94 rpt->macid);
95 return;
96 }
97
98 ntries = MS(rpt->txrptb2, R12A_TXRPTB2_RETRY_CNT);
99
100 ni = sc->node_list[rpt->macid];
101 if (ni != NULL) {
102 RTWN_DPRINTF(sc, RTWN_DEBUG_INTR, "%s: frame for macid %u was"
103 "%s sent (%d retries)\n", __func__, rpt->macid,
104 (rpt->txrptb0 & (R12A_TXRPTB0_RETRY_OVER |
105 R12A_TXRPTB0_LIFE_EXPIRE)) ? " not" : "", ntries);
106
107 txs.flags = IEEE80211_RATECTL_STATUS_LONG_RETRY |
108 IEEE80211_RATECTL_STATUS_FINAL_RATE;
109 txs.long_retries = ntries;
110 if (RTWN_RATE_IS_HT(rpt->final_rate)) { /* MCS */
111 txs.final_rate = RTWN_RIDX_TO_MCS(rpt->final_rate);
112 txs.final_rate |= IEEE80211_RATE_MCS;
113 } else
114 txs.final_rate = ridx2rate[rpt->final_rate];
115 if (rpt->txrptb0 & R12A_TXRPTB0_RETRY_OVER)
116 txs.status = IEEE80211_RATECTL_TX_FAIL_LONG;
117 else if (rpt->txrptb0 & R12A_TXRPTB0_LIFE_EXPIRE)
118 txs.status = IEEE80211_RATECTL_TX_FAIL_EXPIRED;
119 else
120 txs.status = IEEE80211_RATECTL_TX_SUCCESS;
121 ieee80211_ratectl_tx_complete(ni, &txs);
122 } else {
123 RTWN_DPRINTF(sc, RTWN_DEBUG_INTR,
124 "%s: macid %u, ni is NULL\n", __func__, rpt->macid);
125 }
126 }
127
128 void
r12a_handle_c2h_report(struct rtwn_softc * sc,uint8_t * buf,int len)129 r12a_handle_c2h_report(struct rtwn_softc *sc, uint8_t *buf, int len)
130 {
131 struct r12a_softc *rs = sc->sc_priv;
132
133 /* Skip Rx descriptor. */
134 buf += sizeof(struct r92c_rx_stat);
135 len -= sizeof(struct r92c_rx_stat);
136
137 if (len < 2) {
138 device_printf(sc->sc_dev, "C2H report too short (len %d)\n",
139 len);
140 return;
141 }
142 len -= 2;
143
144 switch (buf[0]) { /* command id */
145 case R12A_C2H_TX_REPORT:
146 /* NOTREACHED */
147 KASSERT(0, ("use handle_tx_report() instead of %s\n",
148 __func__));
149 break;
150 case R12A_C2H_IQK_FINISHED:
151 RTWN_DPRINTF(sc, RTWN_DEBUG_CALIB,
152 "FW IQ calibration finished\n");
153 rs->rs_flags &= ~R12A_IQK_RUNNING;
154 break;
155 default:
156 device_printf(sc->sc_dev,
157 "%s: C2H report %u was not handled\n",
158 __func__, buf[0]);
159 }
160 }
161 #else
162 void
r12a_ratectl_tx_complete(struct rtwn_softc * sc,uint8_t * buf,int len)163 r12a_ratectl_tx_complete(struct rtwn_softc *sc, uint8_t *buf, int len)
164 {
165 /* Should not happen. */
166 device_printf(sc->sc_dev, "%s: called\n", __func__);
167 }
168
169 void
r12a_handle_c2h_report(struct rtwn_softc * sc,uint8_t * buf,int len)170 r12a_handle_c2h_report(struct rtwn_softc *sc, uint8_t *buf, int len)
171 {
172 /* Should not happen. */
173 device_printf(sc->sc_dev, "%s: called\n", __func__);
174 }
175 #endif
176
177 int
r12a_check_frame_checksum(struct rtwn_softc * sc,struct mbuf * m)178 r12a_check_frame_checksum(struct rtwn_softc *sc, struct mbuf *m)
179 {
180 struct r12a_softc *rs = sc->sc_priv;
181 struct r92c_rx_stat *stat;
182 uint32_t rxdw1;
183
184 stat = mtod(m, struct r92c_rx_stat *);
185 rxdw1 = le32toh(stat->rxdw1);
186 if (rxdw1 & R12A_RXDW1_CKSUM) {
187 RTWN_DPRINTF(sc, RTWN_DEBUG_RECV,
188 "%s: %s/%s checksum is %s\n", __func__,
189 (rxdw1 & R12A_RXDW1_UDP) ? "UDP" : "TCP",
190 (rxdw1 & R12A_RXDW1_IPV6) ? "IPv6" : "IP",
191 (rxdw1 & R12A_RXDW1_CKSUM_ERR) ? "invalid" : "valid");
192
193 /*
194 * There seems to be a problem with UDP checksum processing
195 * with the checksum value = 0 (ie, no checksum.)
196 * So, don't treat it as a permament failure; just let
197 * the IP stack take a crack at validating frames.
198 *
199 * See kern/285837 for more details.
200 */
201 if (rxdw1 & R12A_RXDW1_CKSUM_ERR)
202 return (0);
203
204 if ((rxdw1 & R12A_RXDW1_IPV6) ?
205 (rs->rs_flags & R12A_RXCKSUM6_EN) :
206 (rs->rs_flags & R12A_RXCKSUM_EN)) {
207 m->m_pkthdr.csum_flags = CSUM_IP_CHECKED |
208 CSUM_IP_VALID | CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
209 m->m_pkthdr.csum_data = 0xffff;
210 }
211 }
212
213 return (0);
214 }
215
216 uint8_t
r12a_rx_radiotap_flags(const void * buf)217 r12a_rx_radiotap_flags(const void *buf)
218 {
219 const struct r92c_rx_stat *stat = buf;
220 uint8_t flags, rate;
221
222 if (!(stat->rxdw4 & htole32(R12A_RXDW4_SPLCP)))
223 return (0);
224 rate = MS(le32toh(stat->rxdw3), R12A_RXDW3_RATE);
225 if (RTWN_RATE_IS_CCK(rate))
226 flags = IEEE80211_RADIOTAP_F_SHORTPRE;
227 else
228 flags = IEEE80211_RADIOTAP_F_SHORTGI;
229 return (flags);
230 }
231
232 void
r12a_get_rx_stats(struct rtwn_softc * sc,struct ieee80211_rx_stats * rxs,const void * desc,const void * physt_ptr)233 r12a_get_rx_stats(struct rtwn_softc *sc, struct ieee80211_rx_stats *rxs,
234 const void *desc, const void *physt_ptr)
235 {
236 const struct r92c_rx_stat *stat = desc;
237 const struct r12a_rx_phystat *physt = physt_ptr;
238 uint32_t rxdw0, rxdw1, rxdw3, rxdw4;
239 uint8_t rate;
240
241 rxdw0 = le32toh(stat->rxdw0);
242 rxdw1 = le32toh(stat->rxdw1);
243 rxdw3 = le32toh(stat->rxdw3);
244 rxdw4 = le32toh(stat->rxdw4);
245 rate = MS(rxdw3, R12A_RXDW3_RATE);
246
247 /* TODO: STBC */
248 if (rxdw4 & R12A_RXDW4_LDPC)
249 rxs->c_pktflags |= IEEE80211_RX_F_LDPC;
250 if (rxdw1 & R12A_RXDW1_AMPDU) {
251 if (rxdw0 & R92C_RXDW0_PHYST)
252 rxs->c_pktflags |= IEEE80211_RX_F_AMPDU;
253 else
254 rxs->c_pktflags |= IEEE80211_RX_F_AMPDU_MORE;
255 }
256
257 if ((rxdw4 & R12A_RXDW4_SPLCP) &&
258 (RTWN_RATE_IS_HT(rate) || RTWN_RATE_IS_VHT(rate)))
259 rxs->c_pktflags |= IEEE80211_RX_F_SHORTGI;
260
261 switch (MS(rxdw4, R12A_RXDW4_BW)) {
262 case R12A_RXDW4_BW20:
263 rxs->c_width = IEEE80211_RX_FW_20MHZ;
264 break;
265 case R12A_RXDW4_BW40:
266 rxs->c_width = IEEE80211_RX_FW_40MHZ;
267 break;
268 case R12A_RXDW4_BW80:
269 rxs->c_width = IEEE80211_RX_FW_80MHZ;
270 break;
271 default:
272 break;
273 }
274
275 if (RTWN_RATE_IS_CCK(rate))
276 rxs->c_phytype = IEEE80211_RX_FP_11B;
277 else {
278 int is5ghz;
279
280 /* XXX magic */
281 /* XXX check with RTL8812AU */
282 is5ghz = (physt->cfosho[2] != 0x01);
283
284 if (RTWN_RATE_IS_CCK(rate) || RTWN_RATE_IS_OFDM(rate)) {
285 if (is5ghz)
286 rxs->c_phytype = IEEE80211_RX_FP_11A;
287 else
288 rxs->c_phytype = IEEE80211_RX_FP_11G;
289 } else if (RTWN_RATE_IS_HT(rate)) {
290 if (is5ghz)
291 rxs->c_phytype = IEEE80211_RX_FP_11NA;
292 else
293 rxs->c_phytype = IEEE80211_RX_FP_11NG;
294 } else if (RTWN_RATE_IS_VHT(rate)) {
295 /* TODO: there's no FP_VHT_5GHZ yet */
296 rxs->c_phytype = IEEE80211_RX_FP_11NA;
297 }
298 }
299
300 /* Map HW rate index to 802.11 rate. */
301 if (RTWN_RATE_IS_CCK(rate) || RTWN_RATE_IS_OFDM(rate)) {
302 rxs->c_rate = ridx2rate[rate];
303 if (RTWN_RATE_IS_CCK(rate))
304 rxs->c_pktflags |= IEEE80211_RX_F_CCK;
305 else
306 rxs->c_pktflags |= IEEE80211_RX_F_OFDM;
307 } else if (RTWN_RATE_IS_HT(rate)) { /* MCS0~15. */
308 rxs->c_rate =
309 IEEE80211_RATE_MCS | RTWN_RIDX_TO_MCS(rate);
310 rxs->c_pktflags |= IEEE80211_RX_F_HT;
311 } else if (RTWN_RATE_IS_VHT(rate)) {
312 /* XXX: need to revisit VHT rate representation */
313 rxs->c_vhtnss = (rate - RTWN_RIDX_VHT_MCS_SHIFT) / 10;
314 rxs->c_rate = (rate - RTWN_RIDX_VHT_MCS_SHIFT) % 10;
315 rxs->c_pktflags |= IEEE80211_RX_F_VHT;
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