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 #include "opt_wlan.h" 23 24 #include <sys/param.h> 25 #include <sys/lock.h> 26 #include <sys/mutex.h> 27 #include <sys/mbuf.h> 28 #include <sys/kernel.h> 29 #include <sys/socket.h> 30 #include <sys/systm.h> 31 #include <sys/malloc.h> 32 #include <sys/queue.h> 33 #include <sys/taskqueue.h> 34 #include <sys/bus.h> 35 #include <sys/endian.h> 36 #include <sys/linker.h> 37 38 #include <net/if.h> 39 #include <net/ethernet.h> 40 #include <net/if_media.h> 41 42 #include <net80211/ieee80211_var.h> 43 #include <net80211/ieee80211_radiotap.h> 44 45 #include <dev/rtwn/if_rtwnreg.h> 46 #include <dev/rtwn/if_rtwnvar.h> 47 48 #include <dev/rtwn/if_rtwn_ridx.h> 49 #include <dev/rtwn/if_rtwn_tx.h> 50 51 #include <dev/rtwn/rtl8192c/r92c.h> 52 #include <dev/rtwn/rtl8192c/r92c_var.h> 53 #include <dev/rtwn/rtl8192c/r92c_tx_desc.h> 54 55 static int 56 r92c_tx_get_sco(struct rtwn_softc *sc, struct ieee80211_channel *c) 57 { 58 if (IEEE80211_IS_CHAN_HT40U(c)) 59 return (R92C_TXDW4_SCO_SCA); 60 else 61 return (R92C_TXDW4_SCO_SCB); 62 } 63 64 static void 65 r92c_tx_set_ht40(struct rtwn_softc *sc, void *buf, struct ieee80211_node *ni) 66 { 67 struct r92c_tx_desc *txd = (struct r92c_tx_desc *)buf; 68 69 if (ieee80211_ht_check_tx_ht40(ni)) { 70 int extc_offset; 71 72 extc_offset = r92c_tx_get_sco(sc, ni->ni_chan); 73 txd->txdw4 |= htole32(R92C_TXDW4_DATA_BW40); 74 txd->txdw4 |= htole32(SM(R92C_TXDW4_DATA_SCO, extc_offset)); 75 } 76 } 77 78 static void 79 r92c_tx_protection(struct rtwn_softc *sc, struct r92c_tx_desc *txd, 80 enum ieee80211_protmode mode, uint8_t ridx) 81 { 82 struct ieee80211com *ic = &sc->sc_ic; 83 uint8_t rate; 84 85 switch (mode) { 86 case IEEE80211_PROT_CTSONLY: 87 txd->txdw4 |= htole32(R92C_TXDW4_CTS2SELF); 88 break; 89 case IEEE80211_PROT_RTSCTS: 90 txd->txdw4 |= htole32(R92C_TXDW4_RTSEN); 91 break; 92 default: 93 break; 94 } 95 96 if (mode == IEEE80211_PROT_CTSONLY || 97 mode == IEEE80211_PROT_RTSCTS) { 98 if (RTWN_RATE_IS_HT(ridx)) 99 rate = rtwn_ctl_mcsrate(ic->ic_rt, ridx); 100 else 101 rate = ieee80211_ctl_rate(ic->ic_rt, ridx2rate[ridx]); 102 ridx = rate2ridx(IEEE80211_RV(rate)); 103 104 txd->txdw4 |= htole32(SM(R92C_TXDW4_RTSRATE, ridx)); 105 /* RTS rate fallback limit (max). */ 106 txd->txdw5 |= htole32(SM(R92C_TXDW5_RTSRATE_FB_LMT, 0xf)); 107 108 if (RTWN_RATE_IS_CCK(ridx) && ridx != RTWN_RIDX_CCK1 && 109 (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) 110 txd->txdw4 |= htole32(R92C_TXDW4_RTS_SHORT); 111 } 112 } 113 114 static void 115 r92c_tx_raid(struct rtwn_softc *sc, struct r92c_tx_desc *txd, 116 struct ieee80211_node *ni, int ismcast) 117 { 118 struct ieee80211com *ic = &sc->sc_ic; 119 struct ieee80211vap *vap = ni->ni_vap; 120 struct ieee80211_channel *chan; 121 enum ieee80211_phymode mode; 122 uint8_t raid; 123 124 chan = (ni->ni_chan != IEEE80211_CHAN_ANYC) ? 125 ni->ni_chan : ic->ic_curchan; 126 mode = ieee80211_chan2mode(chan); 127 128 /* NB: group addressed frames are done at 11bg rates for now */ 129 if (ismcast || !(ni->ni_flags & IEEE80211_NODE_HT)) { 130 switch (mode) { 131 case IEEE80211_MODE_11B: 132 case IEEE80211_MODE_11G: 133 break; 134 case IEEE80211_MODE_11NG: 135 mode = IEEE80211_MODE_11G; 136 break; 137 default: 138 device_printf(sc->sc_dev, "unknown mode(1) %d!\n", 139 ic->ic_curmode); 140 return; 141 } 142 } 143 144 switch (mode) { 145 case IEEE80211_MODE_11B: 146 raid = R92C_RAID_11B; 147 break; 148 case IEEE80211_MODE_11G: 149 if (vap->iv_flags & IEEE80211_F_PUREG) 150 raid = R92C_RAID_11G; 151 else 152 raid = R92C_RAID_11BG; 153 break; 154 case IEEE80211_MODE_11NG: 155 if (vap->iv_flags_ht & IEEE80211_FHT_PUREN) 156 raid = R92C_RAID_11N; 157 else 158 raid = R92C_RAID_11BGN; 159 break; 160 default: 161 device_printf(sc->sc_dev, "unknown mode(2) %d!\n", mode); 162 return; 163 } 164 165 txd->txdw1 |= htole32(SM(R92C_TXDW1_RAID, raid)); 166 } 167 168 /* XXX move to device-independent layer */ 169 static void 170 r92c_tx_set_sgi(struct rtwn_softc *sc, void *buf, struct ieee80211_node *ni) 171 { 172 struct r92c_tx_desc *txd = (struct r92c_tx_desc *)buf; 173 174 /* 175 * Only enable short-GI if we're transmitting in that 176 * width to that node. 177 * 178 * Specifically, do not enable shortgi for 20MHz if 179 * we're attempting to transmit at 40MHz. 180 */ 181 if (ieee80211_ht_check_tx_ht40(ni)) { 182 if (ieee80211_ht_check_tx_shortgi_40(ni)) 183 txd->txdw5 |= htole32(R92C_TXDW5_SGI); 184 } else if (ieee80211_ht_check_tx_ht(ni)) { 185 if (ieee80211_ht_check_tx_shortgi_20(ni)) 186 txd->txdw5 |= htole32(R92C_TXDW5_SGI); 187 } 188 } 189 190 void 191 r92c_tx_enable_ampdu(void *buf, int enable) 192 { 193 struct r92c_tx_desc *txd = (struct r92c_tx_desc *)buf; 194 195 if (enable) 196 txd->txdw1 |= htole32(R92C_TXDW1_AGGEN); 197 else 198 txd->txdw1 |= htole32(R92C_TXDW1_AGGBK); 199 } 200 201 void 202 r92c_tx_setup_hwseq(void *buf) 203 { 204 struct r92c_tx_desc *txd = (struct r92c_tx_desc *)buf; 205 206 txd->txdw4 |= htole32(R92C_TXDW4_HWSEQ_EN); 207 } 208 209 void 210 r92c_tx_setup_macid(void *buf, int id) 211 { 212 struct r92c_tx_desc *txd = (struct r92c_tx_desc *)buf; 213 214 txd->txdw1 |= htole32(SM(R92C_TXDW1_MACID, id)); 215 } 216 217 static int 218 r92c_calculate_tx_agg_window(struct rtwn_softc *sc, 219 const struct ieee80211_node *ni, int tid) 220 { 221 const struct ieee80211_tx_ampdu *tap; 222 int wnd; 223 224 tap = &ni->ni_tx_ampdu[tid]; 225 226 /* 227 * BAW is (MAX_AGG * 2) + 1, hence the /2 here. 228 * Ensure we don't send 0 or more than 64. 229 */ 230 wnd = tap->txa_wnd / 2; 231 if (wnd == 0) 232 wnd = 1; 233 else if (wnd > 0x1f) 234 wnd = 0x1f; 235 236 return (wnd); 237 } 238 239 /* 240 * Check whether to enable the per-packet TX CCX report. 241 * 242 * For chipsets that do the RPT2 reports, enabling the TX 243 * CCX report results in the packet not being counted in 244 * the RPT2 counts. 245 */ 246 static bool 247 r92c_check_enable_ccx_report(struct rtwn_softc *sc, int macid) 248 { 249 if (sc->sc_ratectl != RTWN_RATECTL_NET80211) 250 return false; 251 252 #ifndef RTWN_WITHOUT_UCODE 253 if ((sc->macid_rpt2_max_num != 0) && 254 (macid < sc->macid_rpt2_max_num)) 255 return false; 256 #endif 257 return true; 258 } 259 260 void 261 r92c_fill_tx_desc(struct rtwn_softc *sc, struct ieee80211_node *ni, 262 struct mbuf *m, void *buf, uint8_t ridx, bool force_rate, int maxretry) 263 { 264 #ifndef RTWN_WITHOUT_UCODE 265 struct r92c_softc *rs = sc->sc_priv; 266 #endif 267 struct ieee80211com *ic = &sc->sc_ic; 268 struct ieee80211vap *vap = ni->ni_vap; 269 struct rtwn_vap *uvp = RTWN_VAP(vap); 270 struct ieee80211_frame *wh; 271 struct r92c_tx_desc *txd; 272 enum ieee80211_protmode prot; 273 uint8_t type, tid, qos, qsel; 274 int hasqos, ismcast, macid; 275 276 wh = mtod(m, struct ieee80211_frame *); 277 type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; 278 hasqos = IEEE80211_QOS_HAS_SEQ(wh); 279 ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1); 280 281 /* Select TX ring for this frame. */ 282 if (hasqos) { 283 qos = ((const struct ieee80211_qosframe *)wh)->i_qos[0]; 284 tid = qos & IEEE80211_QOS_TID; 285 } else { 286 qos = 0; 287 tid = 0; 288 } 289 290 /* Fill Tx descriptor. */ 291 txd = (struct r92c_tx_desc *)buf; 292 txd->flags0 |= R92C_FLAGS0_LSG | R92C_FLAGS0_FSG; 293 if (ismcast) 294 txd->flags0 |= R92C_FLAGS0_BMCAST; 295 296 if (IEEE80211_IS_QOSDATA(wh)) 297 txd->txdw4 |= htole32(R92C_TXDW4_QOS); 298 299 if (!ismcast) { 300 struct rtwn_node *un = RTWN_NODE(ni); 301 macid = un->id; 302 303 /* Unicast frame, check if an ACK is expected. */ 304 if (!qos || (qos & IEEE80211_QOS_ACKPOLICY) != 305 IEEE80211_QOS_ACKPOLICY_NOACK) { 306 txd->txdw5 |= htole32(R92C_TXDW5_RTY_LMT_ENA); 307 txd->txdw5 |= htole32(SM(R92C_TXDW5_RTY_LMT, 308 maxretry)); 309 } 310 311 if (type == IEEE80211_FC0_TYPE_DATA) { 312 qsel = tid % RTWN_MAX_TID; 313 314 rtwn_r92c_tx_enable_ampdu(sc, buf, 315 (m->m_flags & M_AMPDU_MPDU) != 0); 316 if (m->m_flags & M_AMPDU_MPDU) { 317 txd->txdw2 |= htole32(SM(R92C_TXDW2_AMPDU_DEN, 318 ieee80211_ht_get_node_ampdu_density(ni))); 319 txd->txdw6 |= htole32(SM(R92C_TXDW6_MAX_AGG, 320 r92c_calculate_tx_agg_window(sc, ni, tid))); 321 } 322 if (r92c_check_enable_ccx_report(sc, macid)) { 323 txd->txdw2 |= htole32(R92C_TXDW2_CCX_RPT); 324 sc->sc_tx_n_active++; 325 #ifndef RTWN_WITHOUT_UCODE 326 rs->rs_c2h_pending++; 327 #endif 328 } 329 330 if (RTWN_RATE_IS_CCK(ridx) && ridx != RTWN_RIDX_CCK1 && 331 (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) 332 txd->txdw4 |= htole32(R92C_TXDW4_DATA_SHPRE); 333 334 prot = IEEE80211_PROT_NONE; 335 if (RTWN_RATE_IS_HT(ridx)) { 336 r92c_tx_set_ht40(sc, txd, ni); 337 r92c_tx_set_sgi(sc, txd, ni); 338 prot = ic->ic_htprotmode; 339 } else if (ic->ic_flags & IEEE80211_F_USEPROT) 340 prot = ic->ic_protmode; 341 342 /* XXX fix last comparison for A-MSDU (in net80211) */ 343 /* XXX A-MPDU? */ 344 if (m->m_pkthdr.len + IEEE80211_CRC_LEN > 345 vap->iv_rtsthreshold && 346 vap->iv_rtsthreshold != IEEE80211_RTS_MAX) 347 prot = IEEE80211_PROT_RTSCTS; 348 349 /* NB: checks for ht40 / short bits (set above). */ 350 if (prot != IEEE80211_PROT_NONE) 351 r92c_tx_protection(sc, txd, prot, ridx); 352 } else /* IEEE80211_FC0_TYPE_MGT */ 353 qsel = R92C_TXDW1_QSEL_MGNT; 354 } else { 355 macid = RTWN_MACID_BC; 356 qsel = R92C_TXDW1_QSEL_MGNT; 357 } 358 359 txd->txdw1 |= htole32(SM(R92C_TXDW1_QSEL, qsel)); 360 361 rtwn_r92c_tx_setup_macid(sc, txd, macid); 362 txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE, ridx)); 363 /* Data rate fallback limit (max). */ 364 txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE_FB_LMT, 0x1f)); 365 txd->txdw4 |= htole32(SM(R92C_TXDW4_PORT_ID, uvp->id)); 366 r92c_tx_raid(sc, txd, ni, ismcast); 367 368 /* Force this rate if needed. */ 369 if (sc->sc_ratectl != RTWN_RATECTL_FW) 370 txd->txdw4 |= htole32(R92C_TXDW4_DRVRATE); 371 372 if (!hasqos) { 373 /* Use HW sequence numbering for non-QoS frames. */ 374 rtwn_r92c_tx_setup_hwseq(sc, txd); 375 } else { 376 uint16_t seqno; 377 378 if (m->m_flags & M_AMPDU_MPDU) { 379 seqno = ni->ni_txseqs[tid] % IEEE80211_SEQ_RANGE; 380 ni->ni_txseqs[tid]++; 381 } else 382 seqno = M_SEQNO_GET(m) % IEEE80211_SEQ_RANGE; 383 384 /* Set sequence number. */ 385 txd->txdseq = htole16(seqno); 386 } 387 } 388 389 void 390 r92c_fill_tx_desc_raw(struct rtwn_softc *sc, struct ieee80211_node *ni, 391 struct mbuf *m, void *buf, const struct ieee80211_bpf_params *params) 392 { 393 struct ieee80211vap *vap = ni->ni_vap; 394 struct rtwn_vap *uvp = RTWN_VAP(vap); 395 struct ieee80211_frame *wh; 396 struct r92c_tx_desc *txd; 397 uint8_t ridx; 398 int ismcast; 399 400 /* XXX TODO: 11n checks, matching r92c_fill_tx_desc() */ 401 402 wh = mtod(m, struct ieee80211_frame *); 403 ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1); 404 ridx = rate2ridx(params->ibp_rate0); 405 406 /* Fill Tx descriptor. */ 407 txd = (struct r92c_tx_desc *)buf; 408 txd->flags0 |= R92C_FLAGS0_LSG | R92C_FLAGS0_FSG; 409 if (ismcast) 410 txd->flags0 |= R92C_FLAGS0_BMCAST; 411 412 if ((params->ibp_flags & IEEE80211_BPF_NOACK) == 0) { 413 txd->txdw5 |= htole32(R92C_TXDW5_RTY_LMT_ENA); 414 txd->txdw5 |= htole32(SM(R92C_TXDW5_RTY_LMT, 415 params->ibp_try0)); 416 } 417 if (params->ibp_flags & IEEE80211_BPF_RTS) 418 r92c_tx_protection(sc, txd, IEEE80211_PROT_RTSCTS, ridx); 419 if (params->ibp_flags & IEEE80211_BPF_CTS) 420 r92c_tx_protection(sc, txd, IEEE80211_PROT_CTSONLY, ridx); 421 422 rtwn_r92c_tx_setup_macid(sc, txd, RTWN_MACID_BC); 423 txd->txdw1 |= htole32(SM(R92C_TXDW1_QSEL, R92C_TXDW1_QSEL_MGNT)); 424 425 /* Set TX rate index. */ 426 txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE, ridx)); 427 txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE_FB_LMT, 0x1f)); 428 txd->txdw4 |= htole32(SM(R92C_TXDW4_PORT_ID, uvp->id)); 429 txd->txdw4 |= htole32(R92C_TXDW4_DRVRATE); 430 r92c_tx_raid(sc, txd, ni, ismcast); 431 432 if (!IEEE80211_QOS_HAS_SEQ(wh)) { 433 /* Use HW sequence numbering for non-QoS frames. */ 434 rtwn_r92c_tx_setup_hwseq(sc, txd); 435 } else { 436 /* Set sequence number. */ 437 txd->txdseq |= htole16(M_SEQNO_GET(m) % IEEE80211_SEQ_RANGE); 438 } 439 } 440 441 void 442 r92c_fill_tx_desc_null(struct rtwn_softc *sc, void *buf, int is11b, 443 int qos, int id) 444 { 445 struct r92c_tx_desc *txd = (struct r92c_tx_desc *)buf; 446 447 txd->flags0 = R92C_FLAGS0_FSG | R92C_FLAGS0_LSG | R92C_FLAGS0_OWN; 448 txd->txdw1 = htole32( 449 SM(R92C_TXDW1_QSEL, R92C_TXDW1_QSEL_MGNT)); 450 451 txd->txdw4 = htole32(R92C_TXDW4_DRVRATE); 452 txd->txdw4 |= htole32(SM(R92C_TXDW4_PORT_ID, id)); 453 if (is11b) { 454 txd->txdw5 = htole32(SM(R92C_TXDW5_DATARATE, 455 RTWN_RIDX_CCK1)); 456 } else { 457 txd->txdw5 = htole32(SM(R92C_TXDW5_DATARATE, 458 RTWN_RIDX_OFDM6)); 459 } 460 461 if (!qos) { 462 rtwn_r92c_tx_setup_hwseq(sc, txd); 463 } 464 } 465 466 uint8_t 467 r92c_tx_radiotap_flags(const void *buf) 468 { 469 const struct r92c_tx_desc *txd = buf; 470 uint8_t flags; 471 472 flags = 0; 473 if (txd->txdw4 & htole32(R92C_TXDW4_DATA_SHPRE)) 474 flags |= IEEE80211_RADIOTAP_F_SHORTPRE; 475 if (txd->txdw5 & htole32(R92C_TXDW5_SGI)) 476 flags |= IEEE80211_RADIOTAP_F_SHORTGI; 477 return (flags); 478 } 479