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 58 static int 59 r92c_tx_get_sco(struct rtwn_softc *sc, struct ieee80211_channel *c) 60 { 61 if (IEEE80211_IS_CHAN_HT40U(c)) 62 return (R92C_TXDW4_SCO_SCA); 63 else 64 return (R92C_TXDW4_SCO_SCB); 65 } 66 67 static void 68 r92c_tx_set_ht40(struct rtwn_softc *sc, void *buf, struct ieee80211_node *ni) 69 { 70 struct r92c_tx_desc *txd = (struct r92c_tx_desc *)buf; 71 72 if (ni->ni_chan != IEEE80211_CHAN_ANYC && 73 IEEE80211_IS_CHAN_HT40(ni->ni_chan)) { 74 int extc_offset; 75 76 extc_offset = r92c_tx_get_sco(sc, ni->ni_chan); 77 txd->txdw4 |= htole32(R92C_TXDW4_DATA_BW40); 78 txd->txdw4 |= htole32(SM(R92C_TXDW4_DATA_SCO, extc_offset)); 79 } 80 } 81 82 static void 83 r92c_tx_protection(struct rtwn_softc *sc, struct r92c_tx_desc *txd, 84 enum ieee80211_protmode mode, uint8_t ridx) 85 { 86 struct ieee80211com *ic = &sc->sc_ic; 87 uint8_t rate; 88 89 switch (mode) { 90 case IEEE80211_PROT_CTSONLY: 91 txd->txdw4 |= htole32(R92C_TXDW4_CTS2SELF); 92 break; 93 case IEEE80211_PROT_RTSCTS: 94 txd->txdw4 |= htole32(R92C_TXDW4_RTSEN); 95 break; 96 default: 97 break; 98 } 99 100 if (mode == IEEE80211_PROT_CTSONLY || 101 mode == IEEE80211_PROT_RTSCTS) { 102 if (ridx >= RTWN_RIDX_HT_MCS(0)) 103 rate = rtwn_ctl_mcsrate(ic->ic_rt, ridx); 104 else 105 rate = ieee80211_ctl_rate(ic->ic_rt, ridx2rate[ridx]); 106 ridx = rate2ridx(IEEE80211_RV(rate)); 107 108 txd->txdw4 |= htole32(SM(R92C_TXDW4_RTSRATE, ridx)); 109 /* RTS rate fallback limit (max). */ 110 txd->txdw5 |= htole32(SM(R92C_TXDW5_RTSRATE_FB_LMT, 0xf)); 111 112 if (RTWN_RATE_IS_CCK(ridx) && ridx != RTWN_RIDX_CCK1 && 113 (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) 114 txd->txdw4 |= htole32(R92C_TXDW4_RTS_SHORT); 115 } 116 } 117 118 static void 119 r92c_tx_raid(struct rtwn_softc *sc, struct r92c_tx_desc *txd, 120 struct ieee80211_node *ni, int ismcast) 121 { 122 struct ieee80211com *ic = &sc->sc_ic; 123 struct ieee80211vap *vap = ni->ni_vap; 124 struct ieee80211_channel *chan; 125 enum ieee80211_phymode mode; 126 uint8_t raid; 127 128 chan = (ni->ni_chan != IEEE80211_CHAN_ANYC) ? 129 ni->ni_chan : ic->ic_curchan; 130 mode = ieee80211_chan2mode(chan); 131 132 /* NB: group addressed frames are done at 11bg rates for now */ 133 if (ismcast || !(ni->ni_flags & IEEE80211_NODE_HT)) { 134 switch (mode) { 135 case IEEE80211_MODE_11B: 136 case IEEE80211_MODE_11G: 137 break; 138 case IEEE80211_MODE_11NG: 139 mode = IEEE80211_MODE_11G; 140 break; 141 default: 142 device_printf(sc->sc_dev, "unknown mode(1) %d!\n", 143 ic->ic_curmode); 144 return; 145 } 146 } 147 148 switch (mode) { 149 case IEEE80211_MODE_11B: 150 raid = R92C_RAID_11B; 151 break; 152 case IEEE80211_MODE_11G: 153 if (vap->iv_flags & IEEE80211_F_PUREG) 154 raid = R92C_RAID_11G; 155 else 156 raid = R92C_RAID_11BG; 157 break; 158 case IEEE80211_MODE_11NG: 159 if (vap->iv_flags_ht & IEEE80211_FHT_PUREN) 160 raid = R92C_RAID_11N; 161 else 162 raid = R92C_RAID_11BGN; 163 break; 164 default: 165 device_printf(sc->sc_dev, "unknown mode(2) %d!\n", mode); 166 return; 167 } 168 169 txd->txdw1 |= htole32(SM(R92C_TXDW1_RAID, raid)); 170 } 171 172 /* XXX move to device-independent layer */ 173 static void 174 r92c_tx_set_sgi(struct rtwn_softc *sc, void *buf, struct ieee80211_node *ni) 175 { 176 struct r92c_tx_desc *txd = (struct r92c_tx_desc *)buf; 177 struct ieee80211vap *vap = ni->ni_vap; 178 179 if ((vap->iv_flags_ht & IEEE80211_FHT_SHORTGI20) && /* HT20 */ 180 (ni->ni_htcap & IEEE80211_HTCAP_SHORTGI20)) 181 txd->txdw5 |= htole32(R92C_TXDW5_SGI); 182 else if (ni->ni_chan != IEEE80211_CHAN_ANYC && /* HT40 */ 183 IEEE80211_IS_CHAN_HT40(ni->ni_chan) && 184 (ni->ni_htcap & IEEE80211_HTCAP_SHORTGI40) && 185 (vap->iv_flags_ht & IEEE80211_FHT_SHORTGI40)) 186 txd->txdw5 |= htole32(R92C_TXDW5_SGI); 187 } 188 189 void 190 r92c_tx_enable_ampdu(void *buf, int enable) 191 { 192 struct r92c_tx_desc *txd = (struct r92c_tx_desc *)buf; 193 194 if (enable) 195 txd->txdw1 |= htole32(R92C_TXDW1_AGGEN); 196 else 197 txd->txdw1 |= htole32(R92C_TXDW1_AGGBK); 198 } 199 200 void 201 r92c_tx_setup_hwseq(void *buf) 202 { 203 struct r92c_tx_desc *txd = (struct r92c_tx_desc *)buf; 204 205 txd->txdw4 |= htole32(R92C_TXDW4_HWSEQ_EN); 206 } 207 208 void 209 r92c_tx_setup_macid(void *buf, int id) 210 { 211 struct r92c_tx_desc *txd = (struct r92c_tx_desc *)buf; 212 213 txd->txdw1 |= htole32(SM(R92C_TXDW1_MACID, id)); 214 215 /* XXX does not belong here */ 216 /* XXX temporary (I hope) */ 217 /* Force CCK1 for RTS / CTS frames (driver bug) */ 218 txd->txdw4 &= ~htole32(SM(R92C_TXDW4_RTSRATE, R92C_TXDW4_RTSRATE_M)); 219 txd->txdw4 &= ~htole32(R92C_TXDW4_RTS_SHORT); 220 } 221 222 void 223 r92c_fill_tx_desc(struct rtwn_softc *sc, struct ieee80211_node *ni, 224 struct mbuf *m, void *buf, uint8_t ridx, int maxretry) 225 { 226 #ifndef RTWN_WITHOUT_UCODE 227 struct r92c_softc *rs = sc->sc_priv; 228 #endif 229 struct ieee80211com *ic = &sc->sc_ic; 230 struct ieee80211vap *vap = ni->ni_vap; 231 struct rtwn_vap *uvp = RTWN_VAP(vap); 232 struct ieee80211_frame *wh; 233 struct r92c_tx_desc *txd; 234 enum ieee80211_protmode prot; 235 uint8_t type, tid, qos, qsel; 236 int hasqos, ismcast, macid; 237 238 wh = mtod(m, struct ieee80211_frame *); 239 type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; 240 hasqos = IEEE80211_QOS_HAS_SEQ(wh); 241 ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1); 242 243 /* Select TX ring for this frame. */ 244 if (hasqos) { 245 qos = ((const struct ieee80211_qosframe *)wh)->i_qos[0]; 246 tid = qos & IEEE80211_QOS_TID; 247 } else { 248 qos = 0; 249 tid = 0; 250 } 251 252 /* Fill Tx descriptor. */ 253 txd = (struct r92c_tx_desc *)buf; 254 txd->flags0 |= R92C_FLAGS0_LSG | R92C_FLAGS0_FSG; 255 if (ismcast) 256 txd->flags0 |= R92C_FLAGS0_BMCAST; 257 258 if (!ismcast) { 259 /* Unicast frame, check if an ACK is expected. */ 260 if (!qos || (qos & IEEE80211_QOS_ACKPOLICY) != 261 IEEE80211_QOS_ACKPOLICY_NOACK) { 262 txd->txdw5 |= htole32(R92C_TXDW5_RTY_LMT_ENA); 263 txd->txdw5 |= htole32(SM(R92C_TXDW5_RTY_LMT, 264 maxretry)); 265 } 266 267 struct rtwn_node *un = RTWN_NODE(ni); 268 macid = un->id; 269 270 if (type == IEEE80211_FC0_TYPE_DATA) { 271 qsel = tid % RTWN_MAX_TID; 272 273 rtwn_r92c_tx_enable_ampdu(sc, buf, 274 (m->m_flags & M_AMPDU_MPDU) != 0); 275 if (m->m_flags & M_AMPDU_MPDU) { 276 txd->txdw2 |= htole32(SM(R92C_TXDW2_AMPDU_DEN, 277 vap->iv_ampdu_density)); 278 txd->txdw6 |= htole32(SM(R92C_TXDW6_MAX_AGG, 279 0x1f)); /* XXX */ 280 } 281 if (sc->sc_ratectl == RTWN_RATECTL_NET80211) { 282 txd->txdw2 |= htole32(R92C_TXDW2_CCX_RPT); 283 sc->sc_tx_n_active++; 284 #ifndef RTWN_WITHOUT_UCODE 285 rs->rs_c2h_pending++; 286 #endif 287 } 288 289 if (RTWN_RATE_IS_CCK(ridx) && ridx != RTWN_RIDX_CCK1 && 290 (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) 291 txd->txdw4 |= htole32(R92C_TXDW4_DATA_SHPRE); 292 293 prot = IEEE80211_PROT_NONE; 294 if (ridx >= RTWN_RIDX_HT_MCS(0)) { 295 r92c_tx_set_ht40(sc, txd, ni); 296 r92c_tx_set_sgi(sc, txd, ni); 297 prot = ic->ic_htprotmode; 298 } else if (ic->ic_flags & IEEE80211_F_USEPROT) 299 prot = ic->ic_protmode; 300 301 /* XXX fix last comparison for A-MSDU (in net80211) */ 302 /* XXX A-MPDU? */ 303 if (m->m_pkthdr.len + IEEE80211_CRC_LEN > 304 vap->iv_rtsthreshold && 305 vap->iv_rtsthreshold != IEEE80211_RTS_MAX) 306 prot = IEEE80211_PROT_RTSCTS; 307 308 /* NB: checks for ht40 / short bits (set above). */ 309 if (prot != IEEE80211_PROT_NONE) 310 r92c_tx_protection(sc, txd, prot, ridx); 311 } else /* IEEE80211_FC0_TYPE_MGT */ 312 qsel = R92C_TXDW1_QSEL_MGNT; 313 } else { 314 macid = RTWN_MACID_BC; 315 qsel = R92C_TXDW1_QSEL_MGNT; 316 } 317 318 txd->txdw1 |= htole32(SM(R92C_TXDW1_QSEL, qsel)); 319 320 rtwn_r92c_tx_setup_macid(sc, txd, macid); 321 txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE, ridx)); 322 /* Data rate fallback limit (max). */ 323 txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE_FB_LMT, 0x1f)); 324 txd->txdw4 |= htole32(SM(R92C_TXDW4_PORT_ID, uvp->id)); 325 r92c_tx_raid(sc, txd, ni, ismcast); 326 327 /* Force this rate if needed. */ 328 if (sc->sc_ratectl != RTWN_RATECTL_FW) 329 txd->txdw4 |= htole32(R92C_TXDW4_DRVRATE); 330 331 if (!hasqos) { 332 /* Use HW sequence numbering for non-QoS frames. */ 333 rtwn_r92c_tx_setup_hwseq(sc, txd); 334 txd->txdw4 |= htole32(SM(R92C_TXDW4_SEQ_SEL, uvp->id)); 335 } else { 336 uint16_t seqno; 337 338 if (m->m_flags & M_AMPDU_MPDU) { 339 seqno = ni->ni_txseqs[tid]; 340 ni->ni_txseqs[tid]++; 341 } else 342 seqno = M_SEQNO_GET(m) % IEEE80211_SEQ_RANGE; 343 344 /* Set sequence number. */ 345 txd->txdseq = htole16(seqno); 346 } 347 } 348 349 void 350 r92c_fill_tx_desc_raw(struct rtwn_softc *sc, struct ieee80211_node *ni, 351 struct mbuf *m, void *buf, const struct ieee80211_bpf_params *params) 352 { 353 struct ieee80211vap *vap = ni->ni_vap; 354 struct rtwn_vap *uvp = RTWN_VAP(vap); 355 struct ieee80211_frame *wh; 356 struct r92c_tx_desc *txd; 357 uint8_t ridx; 358 int ismcast; 359 360 /* XXX TODO: 11n checks, matching r92c_fill_tx_desc() */ 361 362 wh = mtod(m, struct ieee80211_frame *); 363 ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1); 364 ridx = rate2ridx(params->ibp_rate0); 365 366 /* Fill Tx descriptor. */ 367 txd = (struct r92c_tx_desc *)buf; 368 txd->flags0 |= R92C_FLAGS0_LSG | R92C_FLAGS0_FSG; 369 if (ismcast) 370 txd->flags0 |= R92C_FLAGS0_BMCAST; 371 372 if ((params->ibp_flags & IEEE80211_BPF_NOACK) == 0) { 373 txd->txdw5 |= htole32(R92C_TXDW5_RTY_LMT_ENA); 374 txd->txdw5 |= htole32(SM(R92C_TXDW5_RTY_LMT, 375 params->ibp_try0)); 376 } 377 if (params->ibp_flags & IEEE80211_BPF_RTS) 378 r92c_tx_protection(sc, txd, IEEE80211_PROT_RTSCTS, ridx); 379 if (params->ibp_flags & IEEE80211_BPF_CTS) 380 r92c_tx_protection(sc, txd, IEEE80211_PROT_CTSONLY, ridx); 381 382 rtwn_r92c_tx_setup_macid(sc, txd, RTWN_MACID_BC); 383 txd->txdw1 |= htole32(SM(R92C_TXDW1_QSEL, R92C_TXDW1_QSEL_MGNT)); 384 385 /* Set TX rate index. */ 386 txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE, ridx)); 387 txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE_FB_LMT, 0x1f)); 388 txd->txdw4 |= htole32(SM(R92C_TXDW4_PORT_ID, uvp->id)); 389 txd->txdw4 |= htole32(R92C_TXDW4_DRVRATE); 390 r92c_tx_raid(sc, txd, ni, ismcast); 391 392 if (!IEEE80211_QOS_HAS_SEQ(wh)) { 393 /* Use HW sequence numbering for non-QoS frames. */ 394 rtwn_r92c_tx_setup_hwseq(sc, txd); 395 txd->txdw4 |= htole32(SM(R92C_TXDW4_SEQ_SEL, uvp->id)); 396 } else { 397 /* Set sequence number. */ 398 txd->txdseq |= htole16(M_SEQNO_GET(m) % IEEE80211_SEQ_RANGE); 399 } 400 } 401 402 void 403 r92c_fill_tx_desc_null(struct rtwn_softc *sc, void *buf, int is11b, 404 int qos, int id) 405 { 406 struct r92c_tx_desc *txd = (struct r92c_tx_desc *)buf; 407 408 txd->flags0 = R92C_FLAGS0_FSG | R92C_FLAGS0_LSG | R92C_FLAGS0_OWN; 409 txd->txdw1 = htole32( 410 SM(R92C_TXDW1_QSEL, R92C_TXDW1_QSEL_MGNT)); 411 412 txd->txdw4 = htole32(R92C_TXDW4_DRVRATE); 413 txd->txdw4 |= htole32(SM(R92C_TXDW4_PORT_ID, id)); 414 if (is11b) { 415 txd->txdw5 = htole32(SM(R92C_TXDW5_DATARATE, 416 RTWN_RIDX_CCK1)); 417 } else { 418 txd->txdw5 = htole32(SM(R92C_TXDW5_DATARATE, 419 RTWN_RIDX_OFDM6)); 420 } 421 422 if (!qos) { 423 rtwn_r92c_tx_setup_hwseq(sc, txd); 424 txd->txdw4 |= htole32(SM(R92C_TXDW4_SEQ_SEL, id)); 425 } 426 } 427 428 uint8_t 429 r92c_tx_radiotap_flags(const void *buf) 430 { 431 const struct r92c_tx_desc *txd = buf; 432 uint8_t flags; 433 434 flags = 0; 435 if (txd->txdw4 & htole32(R92C_TXDW4_DATA_SHPRE)) 436 flags |= IEEE80211_RADIOTAP_F_SHORTPRE; 437 if (txd->txdw5 & htole32(R92C_TXDW5_SGI)) 438 flags |= IEEE80211_RADIOTAP_F_SHORTGI; 439 return (flags); 440 } 441