1 /* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ 2 3 /*- 4 * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr> 5 * Copyright (c) 2014 Kevin Lo <kevlo@FreeBSD.org> 6 * Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org> 7 * 8 * Permission to use, copy, modify, and distribute this software for any 9 * purpose with or without fee is hereby granted, provided that the above 10 * copyright notice and this permission notice appear in all copies. 11 * 12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19 */ 20 21 #include <sys/cdefs.h> 22 __FBSDID("$FreeBSD$"); 23 24 #include "opt_wlan.h" 25 26 #include <sys/param.h> 27 #include <sys/lock.h> 28 #include <sys/mutex.h> 29 #include <sys/mbuf.h> 30 #include <sys/kernel.h> 31 #include <sys/socket.h> 32 #include <sys/systm.h> 33 #include <sys/malloc.h> 34 #include <sys/queue.h> 35 #include <sys/taskqueue.h> 36 #include <sys/bus.h> 37 #include <sys/endian.h> 38 #include <sys/linker.h> 39 40 #include <net/if.h> 41 #include <net/ethernet.h> 42 #include <net/if_media.h> 43 44 #include <net80211/ieee80211_var.h> 45 #include <net80211/ieee80211_radiotap.h> 46 47 #include <dev/rtwn/if_rtwnreg.h> 48 #include <dev/rtwn/if_rtwnvar.h> 49 50 #include <dev/rtwn/if_rtwn_ridx.h> 51 #include <dev/rtwn/if_rtwn_tx.h> 52 53 #include <dev/rtwn/rtl8192c/r92c.h> 54 #include <dev/rtwn/rtl8192c/r92c_var.h> 55 #include <dev/rtwn/rtl8192c/r92c_tx_desc.h> 56 57 static int 58 r92c_tx_get_sco(struct rtwn_softc *sc, struct ieee80211_channel *c) 59 { 60 if (IEEE80211_IS_CHAN_HT40U(c)) 61 return (R92C_TXDW4_SCO_SCA); 62 else 63 return (R92C_TXDW4_SCO_SCB); 64 } 65 66 static void 67 r92c_tx_set_ht40(struct rtwn_softc *sc, void *buf, struct ieee80211_node *ni) 68 { 69 struct r92c_tx_desc *txd = (struct r92c_tx_desc *)buf; 70 71 if (ni->ni_chan != IEEE80211_CHAN_ANYC && 72 IEEE80211_IS_CHAN_HT40(ni->ni_chan)) { 73 int extc_offset; 74 75 extc_offset = r92c_tx_get_sco(sc, ni->ni_chan); 76 txd->txdw4 |= htole32(R92C_TXDW4_DATA_BW40); 77 txd->txdw4 |= htole32(SM(R92C_TXDW4_DATA_SCO, extc_offset)); 78 } 79 } 80 81 static void 82 r92c_tx_protection(struct rtwn_softc *sc, struct r92c_tx_desc *txd, 83 enum ieee80211_protmode mode, uint8_t ridx) 84 { 85 struct ieee80211com *ic = &sc->sc_ic; 86 uint8_t rate; 87 88 switch (mode) { 89 case IEEE80211_PROT_CTSONLY: 90 txd->txdw4 |= htole32(R92C_TXDW4_CTS2SELF); 91 break; 92 case IEEE80211_PROT_RTSCTS: 93 txd->txdw4 |= htole32(R92C_TXDW4_RTSEN); 94 break; 95 default: 96 break; 97 } 98 99 if (mode == IEEE80211_PROT_CTSONLY || 100 mode == IEEE80211_PROT_RTSCTS) { 101 if (ridx >= RTWN_RIDX_HT_MCS(0)) 102 rate = rtwn_ctl_mcsrate(ic->ic_rt, ridx); 103 else 104 rate = ieee80211_ctl_rate(ic->ic_rt, ridx2rate[ridx]); 105 ridx = rate2ridx(IEEE80211_RV(rate)); 106 107 txd->txdw4 |= htole32(SM(R92C_TXDW4_RTSRATE, ridx)); 108 /* RTS rate fallback limit (max). */ 109 txd->txdw5 |= htole32(SM(R92C_TXDW5_RTSRATE_FB_LMT, 0xf)); 110 111 if (RTWN_RATE_IS_CCK(ridx) && ridx != RTWN_RIDX_CCK1 && 112 (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) 113 txd->txdw4 |= htole32(R92C_TXDW4_RTS_SHORT); 114 } 115 } 116 117 static void 118 r92c_tx_raid(struct rtwn_softc *sc, struct r92c_tx_desc *txd, 119 struct ieee80211_node *ni, int ismcast) 120 { 121 struct ieee80211com *ic = &sc->sc_ic; 122 struct ieee80211vap *vap = ni->ni_vap; 123 struct ieee80211_channel *chan; 124 enum ieee80211_phymode mode; 125 uint8_t raid; 126 127 chan = (ni->ni_chan != IEEE80211_CHAN_ANYC) ? 128 ni->ni_chan : ic->ic_curchan; 129 mode = ieee80211_chan2mode(chan); 130 131 /* NB: group addressed frames are done at 11bg rates for now */ 132 if (ismcast || !(ni->ni_flags & IEEE80211_NODE_HT)) { 133 switch (mode) { 134 case IEEE80211_MODE_11B: 135 case IEEE80211_MODE_11G: 136 break; 137 case IEEE80211_MODE_11NG: 138 mode = IEEE80211_MODE_11G; 139 break; 140 default: 141 device_printf(sc->sc_dev, "unknown mode(1) %d!\n", 142 ic->ic_curmode); 143 return; 144 } 145 } 146 147 switch (mode) { 148 case IEEE80211_MODE_11B: 149 raid = R92C_RAID_11B; 150 break; 151 case IEEE80211_MODE_11G: 152 if (vap->iv_flags & IEEE80211_F_PUREG) 153 raid = R92C_RAID_11G; 154 else 155 raid = R92C_RAID_11BG; 156 break; 157 case IEEE80211_MODE_11NG: 158 if (vap->iv_flags_ht & IEEE80211_FHT_PUREN) 159 raid = R92C_RAID_11N; 160 else 161 raid = R92C_RAID_11BGN; 162 break; 163 default: 164 device_printf(sc->sc_dev, "unknown mode(2) %d!\n", mode); 165 return; 166 } 167 168 txd->txdw1 |= htole32(SM(R92C_TXDW1_RAID, raid)); 169 } 170 171 /* XXX move to device-independent layer */ 172 static void 173 r92c_tx_set_sgi(struct rtwn_softc *sc, void *buf, struct ieee80211_node *ni) 174 { 175 struct r92c_tx_desc *txd = (struct r92c_tx_desc *)buf; 176 struct ieee80211vap *vap = ni->ni_vap; 177 178 if ((vap->iv_flags_ht & IEEE80211_FHT_SHORTGI20) && /* HT20 */ 179 (ni->ni_htcap & IEEE80211_HTCAP_SHORTGI20)) 180 txd->txdw5 |= htole32(R92C_TXDW5_SGI); 181 else if (ni->ni_chan != IEEE80211_CHAN_ANYC && /* HT40 */ 182 IEEE80211_IS_CHAN_HT40(ni->ni_chan) && 183 (ni->ni_htcap & IEEE80211_HTCAP_SHORTGI40) && 184 (vap->iv_flags_ht & IEEE80211_FHT_SHORTGI40)) 185 txd->txdw5 |= htole32(R92C_TXDW5_SGI); 186 } 187 188 void 189 r92c_tx_enable_ampdu(void *buf, int enable) 190 { 191 struct r92c_tx_desc *txd = (struct r92c_tx_desc *)buf; 192 193 if (enable) 194 txd->txdw1 |= htole32(R92C_TXDW1_AGGEN); 195 else 196 txd->txdw1 |= htole32(R92C_TXDW1_AGGBK); 197 } 198 199 void 200 r92c_tx_setup_hwseq(void *buf) 201 { 202 struct r92c_tx_desc *txd = (struct r92c_tx_desc *)buf; 203 204 txd->txdw4 |= htole32(R92C_TXDW4_HWSEQ_EN); 205 } 206 207 void 208 r92c_tx_setup_macid(void *buf, int id) 209 { 210 struct r92c_tx_desc *txd = (struct r92c_tx_desc *)buf; 211 212 txd->txdw1 |= htole32(SM(R92C_TXDW1_MACID, id)); 213 214 /* XXX does not belong here */ 215 /* XXX temporary (I hope) */ 216 /* Force CCK1 for RTS / CTS frames (driver bug) */ 217 txd->txdw4 &= ~htole32(SM(R92C_TXDW4_RTSRATE, R92C_TXDW4_RTSRATE_M)); 218 txd->txdw4 &= ~htole32(R92C_TXDW4_RTS_SHORT); 219 } 220 221 void 222 r92c_fill_tx_desc(struct rtwn_softc *sc, struct ieee80211_node *ni, 223 struct mbuf *m, void *buf, uint8_t ridx, int maxretry) 224 { 225 #ifndef RTWN_WITHOUT_UCODE 226 struct r92c_softc *rs = sc->sc_priv; 227 #endif 228 struct ieee80211com *ic = &sc->sc_ic; 229 struct ieee80211vap *vap = ni->ni_vap; 230 struct rtwn_vap *uvp = RTWN_VAP(vap); 231 struct ieee80211_frame *wh; 232 struct r92c_tx_desc *txd; 233 enum ieee80211_protmode prot; 234 uint8_t type, tid, qos, qsel; 235 int hasqos, ismcast, macid; 236 237 wh = mtod(m, struct ieee80211_frame *); 238 type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; 239 hasqos = IEEE80211_QOS_HAS_SEQ(wh); 240 ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1); 241 242 /* Select TX ring for this frame. */ 243 if (hasqos) { 244 qos = ((const struct ieee80211_qosframe *)wh)->i_qos[0]; 245 tid = qos & IEEE80211_QOS_TID; 246 } else { 247 qos = 0; 248 tid = 0; 249 } 250 251 /* Fill Tx descriptor. */ 252 txd = (struct r92c_tx_desc *)buf; 253 txd->flags0 |= R92C_FLAGS0_LSG | R92C_FLAGS0_FSG; 254 if (ismcast) 255 txd->flags0 |= R92C_FLAGS0_BMCAST; 256 257 if (!ismcast) { 258 /* Unicast frame, check if an ACK is expected. */ 259 if (!qos || (qos & IEEE80211_QOS_ACKPOLICY) != 260 IEEE80211_QOS_ACKPOLICY_NOACK) { 261 txd->txdw5 |= htole32(R92C_TXDW5_RTY_LMT_ENA); 262 txd->txdw5 |= htole32(SM(R92C_TXDW5_RTY_LMT, 263 maxretry)); 264 } 265 266 struct rtwn_node *un = RTWN_NODE(ni); 267 macid = un->id; 268 269 if (type == IEEE80211_FC0_TYPE_DATA) { 270 qsel = tid % RTWN_MAX_TID; 271 272 rtwn_r92c_tx_enable_ampdu(sc, buf, 273 (m->m_flags & M_AMPDU_MPDU) != 0); 274 if (m->m_flags & M_AMPDU_MPDU) { 275 txd->txdw2 |= htole32(SM(R92C_TXDW2_AMPDU_DEN, 276 vap->iv_ampdu_density)); 277 txd->txdw6 |= htole32(SM(R92C_TXDW6_MAX_AGG, 278 0x1f)); /* XXX */ 279 } 280 if (sc->sc_ratectl == RTWN_RATECTL_NET80211) { 281 txd->txdw2 |= htole32(R92C_TXDW2_CCX_RPT); 282 sc->sc_tx_n_active++; 283 #ifndef RTWN_WITHOUT_UCODE 284 rs->rs_c2h_pending++; 285 #endif 286 } 287 288 if (RTWN_RATE_IS_CCK(ridx) && ridx != RTWN_RIDX_CCK1 && 289 (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) 290 txd->txdw4 |= htole32(R92C_TXDW4_DATA_SHPRE); 291 292 prot = IEEE80211_PROT_NONE; 293 if (ridx >= RTWN_RIDX_HT_MCS(0)) { 294 r92c_tx_set_ht40(sc, txd, ni); 295 r92c_tx_set_sgi(sc, txd, ni); 296 prot = ic->ic_htprotmode; 297 } else if (ic->ic_flags & IEEE80211_F_USEPROT) 298 prot = ic->ic_protmode; 299 300 /* XXX fix last comparison for A-MSDU (in net80211) */ 301 /* XXX A-MPDU? */ 302 if (m->m_pkthdr.len + IEEE80211_CRC_LEN > 303 vap->iv_rtsthreshold && 304 vap->iv_rtsthreshold != IEEE80211_RTS_MAX) 305 prot = IEEE80211_PROT_RTSCTS; 306 307 /* NB: checks for ht40 / short bits (set above). */ 308 if (prot != IEEE80211_PROT_NONE) 309 r92c_tx_protection(sc, txd, prot, ridx); 310 } else /* IEEE80211_FC0_TYPE_MGT */ 311 qsel = R92C_TXDW1_QSEL_MGNT; 312 } else { 313 macid = RTWN_MACID_BC; 314 qsel = R92C_TXDW1_QSEL_MGNT; 315 } 316 317 txd->txdw1 |= htole32(SM(R92C_TXDW1_QSEL, qsel)); 318 319 rtwn_r92c_tx_setup_macid(sc, txd, macid); 320 txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE, ridx)); 321 /* Data rate fallback limit (max). */ 322 txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE_FB_LMT, 0x1f)); 323 txd->txdw4 |= htole32(SM(R92C_TXDW4_PORT_ID, uvp->id)); 324 r92c_tx_raid(sc, txd, ni, ismcast); 325 326 /* Force this rate if needed. */ 327 if (sc->sc_ratectl != RTWN_RATECTL_FW) 328 txd->txdw4 |= htole32(R92C_TXDW4_DRVRATE); 329 330 if (!hasqos) { 331 /* Use HW sequence numbering for non-QoS frames. */ 332 rtwn_r92c_tx_setup_hwseq(sc, txd); 333 txd->txdw4 |= htole32(SM(R92C_TXDW4_SEQ_SEL, uvp->id)); 334 } else { 335 uint16_t seqno; 336 337 if (m->m_flags & M_AMPDU_MPDU) { 338 seqno = ni->ni_txseqs[tid] % IEEE80211_SEQ_RANGE; 339 ni->ni_txseqs[tid]++; 340 } else 341 seqno = M_SEQNO_GET(m) % IEEE80211_SEQ_RANGE; 342 343 /* Set sequence number. */ 344 txd->txdseq = htole16(seqno); 345 } 346 } 347 348 void 349 r92c_fill_tx_desc_raw(struct rtwn_softc *sc, struct ieee80211_node *ni, 350 struct mbuf *m, void *buf, const struct ieee80211_bpf_params *params) 351 { 352 struct ieee80211vap *vap = ni->ni_vap; 353 struct rtwn_vap *uvp = RTWN_VAP(vap); 354 struct ieee80211_frame *wh; 355 struct r92c_tx_desc *txd; 356 uint8_t ridx; 357 int ismcast; 358 359 /* XXX TODO: 11n checks, matching r92c_fill_tx_desc() */ 360 361 wh = mtod(m, struct ieee80211_frame *); 362 ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1); 363 ridx = rate2ridx(params->ibp_rate0); 364 365 /* Fill Tx descriptor. */ 366 txd = (struct r92c_tx_desc *)buf; 367 txd->flags0 |= R92C_FLAGS0_LSG | R92C_FLAGS0_FSG; 368 if (ismcast) 369 txd->flags0 |= R92C_FLAGS0_BMCAST; 370 371 if ((params->ibp_flags & IEEE80211_BPF_NOACK) == 0) { 372 txd->txdw5 |= htole32(R92C_TXDW5_RTY_LMT_ENA); 373 txd->txdw5 |= htole32(SM(R92C_TXDW5_RTY_LMT, 374 params->ibp_try0)); 375 } 376 if (params->ibp_flags & IEEE80211_BPF_RTS) 377 r92c_tx_protection(sc, txd, IEEE80211_PROT_RTSCTS, ridx); 378 if (params->ibp_flags & IEEE80211_BPF_CTS) 379 r92c_tx_protection(sc, txd, IEEE80211_PROT_CTSONLY, ridx); 380 381 rtwn_r92c_tx_setup_macid(sc, txd, RTWN_MACID_BC); 382 txd->txdw1 |= htole32(SM(R92C_TXDW1_QSEL, R92C_TXDW1_QSEL_MGNT)); 383 384 /* Set TX rate index. */ 385 txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE, ridx)); 386 txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE_FB_LMT, 0x1f)); 387 txd->txdw4 |= htole32(SM(R92C_TXDW4_PORT_ID, uvp->id)); 388 txd->txdw4 |= htole32(R92C_TXDW4_DRVRATE); 389 r92c_tx_raid(sc, txd, ni, ismcast); 390 391 if (!IEEE80211_QOS_HAS_SEQ(wh)) { 392 /* Use HW sequence numbering for non-QoS frames. */ 393 rtwn_r92c_tx_setup_hwseq(sc, txd); 394 txd->txdw4 |= htole32(SM(R92C_TXDW4_SEQ_SEL, uvp->id)); 395 } else { 396 /* Set sequence number. */ 397 txd->txdseq |= htole16(M_SEQNO_GET(m) % IEEE80211_SEQ_RANGE); 398 } 399 } 400 401 void 402 r92c_fill_tx_desc_null(struct rtwn_softc *sc, void *buf, int is11b, 403 int qos, int id) 404 { 405 struct r92c_tx_desc *txd = (struct r92c_tx_desc *)buf; 406 407 txd->flags0 = R92C_FLAGS0_FSG | R92C_FLAGS0_LSG | R92C_FLAGS0_OWN; 408 txd->txdw1 = htole32( 409 SM(R92C_TXDW1_QSEL, R92C_TXDW1_QSEL_MGNT)); 410 411 txd->txdw4 = htole32(R92C_TXDW4_DRVRATE); 412 txd->txdw4 |= htole32(SM(R92C_TXDW4_PORT_ID, id)); 413 if (is11b) { 414 txd->txdw5 = htole32(SM(R92C_TXDW5_DATARATE, 415 RTWN_RIDX_CCK1)); 416 } else { 417 txd->txdw5 = htole32(SM(R92C_TXDW5_DATARATE, 418 RTWN_RIDX_OFDM6)); 419 } 420 421 if (!qos) { 422 rtwn_r92c_tx_setup_hwseq(sc, txd); 423 txd->txdw4 |= htole32(SM(R92C_TXDW4_SEQ_SEL, id)); 424 } 425 } 426 427 uint8_t 428 r92c_tx_radiotap_flags(const void *buf) 429 { 430 const struct r92c_tx_desc *txd = buf; 431 uint8_t flags; 432 433 flags = 0; 434 if (txd->txdw4 & htole32(R92C_TXDW4_DATA_SHPRE)) 435 flags |= IEEE80211_RADIOTAP_F_SHORTPRE; 436 if (txd->txdw5 & htole32(R92C_TXDW5_SGI)) 437 flags |= IEEE80211_RADIOTAP_F_SHORTGI; 438 return (flags); 439 } 440