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