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