xref: /freebsd/sys/dev/rtwn/rtl8812a/r12a_rx.c (revision 5dae51da3da0cc94d17bd67b308fad304ebec7e0)
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 
66 #ifndef RTWN_WITHOUT_UCODE
67 void
68 r12a_ratectl_tx_complete(struct rtwn_softc *sc, uint8_t *buf, int len)
69 {
70 #if __FreeBSD_version >= 1200012
71 	struct ieee80211_ratectl_tx_status txs;
72 #endif
73 	struct r12a_c2h_tx_rpt *rpt;
74 	struct ieee80211_node *ni;
75 	int ntries;
76 
77 	/* Skip Rx descriptor / report id / sequence fields. */
78 	buf += sizeof(struct r92c_rx_stat) + 2;
79 	len -= sizeof(struct r92c_rx_stat) + 2;
80 
81 	rpt = (struct r12a_c2h_tx_rpt *)buf;
82 	if (len != sizeof(*rpt)) {
83 		device_printf(sc->sc_dev,
84 		    "%s: wrong report size (%d, must be %zu)\n",
85 		    __func__, len, sizeof(*rpt));
86 		return;
87 	}
88 
89 	RTWN_DPRINTF(sc, RTWN_DEBUG_INTR,
90 	    "%s: ccx report dump: 0: %02X, id: %02X, 2: %02X, queue time: "
91 	    "low %02X, high %02X, final ridx: %02X, rsvd: %04X\n",
92 	    __func__, rpt->txrptb0, rpt->macid, rpt->txrptb2,
93 	    rpt->queue_time_low, rpt->queue_time_high, rpt->final_rate,
94 	    rpt->reserved);
95 
96 	if (rpt->macid > sc->macid_limit) {
97 		device_printf(sc->sc_dev,
98 		    "macid %u is too big; increase MACID_MAX limit\n",
99 		    rpt->macid);
100 		return;
101 	}
102 
103 	ntries = MS(rpt->txrptb2, R12A_TXRPTB2_RETRY_CNT);
104 
105 	ni = sc->node_list[rpt->macid];
106 	if (ni != NULL) {
107 		RTWN_DPRINTF(sc, RTWN_DEBUG_INTR, "%s: frame for macid %u was"
108 		    "%s sent (%d retries)\n", __func__, rpt->macid,
109 		    (rpt->txrptb0 & (R12A_TXRPTB0_RETRY_OVER |
110 		    R12A_TXRPTB0_LIFE_EXPIRE)) ? " not" : "", ntries);
111 
112 #if __FreeBSD_version >= 1200012
113 		txs.flags = IEEE80211_RATECTL_STATUS_LONG_RETRY |
114 			    IEEE80211_RATECTL_STATUS_FINAL_RATE;
115 		txs.long_retries = ntries;
116 		if (rpt->final_rate > RTWN_RIDX_OFDM54) {	/* MCS */
117 			txs.final_rate =
118 			    (rpt->final_rate - 12) | 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 
144 void
145 r12a_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
178 void
179 r12a_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 
185 void
186 r12a_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 
193 int
194 r12a_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 
224 uint8_t
225 r12a_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), R92C_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