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 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 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 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 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 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 if (rxdw1 & R12A_RXDW1_CKSUM_ERR) 194 return (-1); 195 196 if ((rxdw1 & R12A_RXDW1_IPV6) ? 197 (rs->rs_flags & R12A_RXCKSUM6_EN) : 198 (rs->rs_flags & R12A_RXCKSUM_EN)) { 199 m->m_pkthdr.csum_flags = CSUM_IP_CHECKED | 200 CSUM_IP_VALID | CSUM_DATA_VALID | CSUM_PSEUDO_HDR; 201 m->m_pkthdr.csum_data = 0xffff; 202 } 203 } 204 205 return (0); 206 } 207 208 uint8_t 209 r12a_rx_radiotap_flags(const void *buf) 210 { 211 const struct r92c_rx_stat *stat = buf; 212 uint8_t flags, rate; 213 214 if (!(stat->rxdw4 & htole32(R12A_RXDW4_SPLCP))) 215 return (0); 216 rate = MS(le32toh(stat->rxdw3), R12A_RXDW3_RATE); 217 if (RTWN_RATE_IS_CCK(rate)) 218 flags = IEEE80211_RADIOTAP_F_SHORTPRE; 219 else 220 flags = IEEE80211_RADIOTAP_F_SHORTGI; 221 return (flags); 222 } 223 224 void 225 r12a_get_rx_stats(struct rtwn_softc *sc, struct ieee80211_rx_stats *rxs, 226 const void *desc, const void *physt_ptr) 227 { 228 const struct r92c_rx_stat *stat = desc; 229 const struct r12a_rx_phystat *physt = physt_ptr; 230 uint32_t rxdw0, rxdw1, rxdw3, rxdw4; 231 uint8_t rate; 232 233 rxdw0 = le32toh(stat->rxdw0); 234 rxdw1 = le32toh(stat->rxdw1); 235 rxdw3 = le32toh(stat->rxdw3); 236 rxdw4 = le32toh(stat->rxdw4); 237 rate = MS(rxdw3, R12A_RXDW3_RATE); 238 239 /* TODO: STBC */ 240 if (rxdw4 & R12A_RXDW4_LDPC) 241 rxs->c_pktflags |= IEEE80211_RX_F_LDPC; 242 if (rxdw1 & R12A_RXDW1_AMPDU) { 243 if (rxdw0 & R92C_RXDW0_PHYST) 244 rxs->c_pktflags |= IEEE80211_RX_F_AMPDU; 245 else 246 rxs->c_pktflags |= IEEE80211_RX_F_AMPDU_MORE; 247 } 248 249 if ((rxdw4 & R12A_RXDW4_SPLCP) && 250 (RTWN_RATE_IS_HT(rate) || RTWN_RATE_IS_VHT(rate))) 251 rxs->c_pktflags |= IEEE80211_RX_F_SHORTGI; 252 253 switch (MS(rxdw4, R12A_RXDW4_BW)) { 254 case R12A_RXDW4_BW20: 255 rxs->c_width = IEEE80211_RX_FW_20MHZ; 256 break; 257 case R12A_RXDW4_BW40: 258 rxs->c_width = IEEE80211_RX_FW_40MHZ; 259 break; 260 case R12A_RXDW4_BW80: 261 rxs->c_width = IEEE80211_RX_FW_80MHZ; 262 break; 263 default: 264 break; 265 } 266 267 if (RTWN_RATE_IS_CCK(rate)) 268 rxs->c_phytype = IEEE80211_RX_FP_11B; 269 else { 270 int is5ghz; 271 272 /* XXX magic */ 273 /* XXX check with RTL8812AU */ 274 is5ghz = (physt->cfosho[2] != 0x01); 275 276 if (RTWN_RATE_IS_CCK(rate) || RTWN_RATE_IS_OFDM(rate)) { 277 if (is5ghz) 278 rxs->c_phytype = IEEE80211_RX_FP_11A; 279 else 280 rxs->c_phytype = IEEE80211_RX_FP_11G; 281 } else if (RTWN_RATE_IS_HT(rate)) { 282 if (is5ghz) 283 rxs->c_phytype = IEEE80211_RX_FP_11NA; 284 else 285 rxs->c_phytype = IEEE80211_RX_FP_11NG; 286 } else if (RTWN_RATE_IS_VHT(rate)) { 287 /* TODO: there's no FP_VHT_5GHZ yet */ 288 rxs->c_phytype = IEEE80211_RX_FP_11NA; 289 } 290 } 291 292 /* Map HW rate index to 802.11 rate. */ 293 if (RTWN_RATE_IS_CCK(rate) || RTWN_RATE_IS_OFDM(rate)) { 294 rxs->c_rate = ridx2rate[rate]; 295 if (RTWN_RATE_IS_CCK(rate)) 296 rxs->c_pktflags |= IEEE80211_RX_F_CCK; 297 else 298 rxs->c_pktflags |= IEEE80211_RX_F_OFDM; 299 } else if (RTWN_RATE_IS_HT(rate)) { /* MCS0~15. */ 300 rxs->c_rate = 301 IEEE80211_RATE_MCS | RTWN_RIDX_TO_MCS(rate); 302 rxs->c_pktflags |= IEEE80211_RX_F_HT; 303 } else if (RTWN_RATE_IS_VHT(rate)) { 304 /* XXX: need to revisit VHT rate representation */ 305 rxs->c_vhtnss = (rate - RTWN_RIDX_VHT_MCS_SHIFT) / 10; 306 rxs->c_rate = (rate - RTWN_RIDX_VHT_MCS_SHIFT) % 10; 307 rxs->c_pktflags |= IEEE80211_RX_F_VHT; 308 } 309 310 /* 311 * XXX always zero for RTL8821AU 312 * (vendor driver does not check this field) 313 */ 314 #if 0 315 rxs->r_flags |= IEEE80211_R_IEEE | IEEE80211_R_FREQ; 316 rxs->r_flags |= IEEE80211_R_BAND; 317 rxs->c_ieee = MS(le16toh(physt->phyw1), R12A_PHYW1_CHAN); 318 rxs->c_freq = ieee80211_ieee2mhz(rxs->c_ieee, 319 (rxs->c_ieee < 36) ? IEEE80211_CHAN_2GHZ : IEEE80211_CHAN_5GHZ); 320 rxs->c_band = (rxs->c_ieee < 36) ? IEEE80211_CHAN_2GHZ : IEEE80211_CHAN_5GHZ; 321 #endif 322 } 323