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
r92c_tx_get_sco(struct rtwn_softc * sc,struct ieee80211_channel * c)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
r92c_tx_set_ht40(struct rtwn_softc * sc,void * buf,struct ieee80211_node * ni)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
r92c_tx_protection(struct rtwn_softc * sc,struct r92c_tx_desc * txd,enum ieee80211_protmode mode,uint8_t ridx,bool force_rate)79 r92c_tx_protection(struct rtwn_softc *sc, struct r92c_tx_desc *txd,
80 enum ieee80211_protmode mode, uint8_t ridx, bool force_rate)
81 {
82 struct ieee80211com *ic = &sc->sc_ic;
83 uint8_t rate;
84 bool use_fw_ratectl;
85
86 use_fw_ratectl =
87 (sc->sc_ratectl == RTWN_RATECTL_FW && !force_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 (use_fw_ratectl) {
103 /*
104 * If we're not forcing the driver rate then this
105 * field actually doesn't matter; what matters is
106 * the RRSR and INIRTS configuration.
107 */
108 ridx = RTWN_RIDX_OFDM24;
109 } else if (RTWN_RATE_IS_HT(ridx)) {
110 rate = rtwn_ctl_mcsrate(ic->ic_rt, ridx);
111 ridx = rate2ridx(IEEE80211_RV(rate));
112 } else {
113 rate = ieee80211_ctl_rate(ic->ic_rt, ridx2rate[ridx]);
114 ridx = rate2ridx(IEEE80211_RV(rate));
115 }
116
117 txd->txdw4 |= htole32(SM(R92C_TXDW4_RTSRATE, ridx));
118 /* RTS rate fallback limit (max). */
119 txd->txdw5 |= htole32(SM(R92C_TXDW5_RTSRATE_FB_LMT, 0xf));
120
121 if (!use_fw_ratectl && RTWN_RATE_IS_CCK(ridx) &&
122 ridx != RTWN_RIDX_CCK1 &&
123 (ic->ic_flags & IEEE80211_F_SHPREAMBLE))
124 txd->txdw4 |= htole32(R92C_TXDW4_RTS_SHORT);
125 }
126 }
127
128 static void
r92c_tx_raid(struct rtwn_softc * sc,struct r92c_tx_desc * txd,struct ieee80211_node * ni,int ismcast)129 r92c_tx_raid(struct rtwn_softc *sc, struct r92c_tx_desc *txd,
130 struct ieee80211_node *ni, int ismcast)
131 {
132 struct ieee80211com *ic = &sc->sc_ic;
133 struct ieee80211vap *vap = ni->ni_vap;
134 struct ieee80211_channel *chan;
135 enum ieee80211_phymode mode;
136 uint8_t raid;
137
138 chan = (ni->ni_chan != IEEE80211_CHAN_ANYC) ?
139 ni->ni_chan : ic->ic_curchan;
140 mode = ieee80211_chan2mode(chan);
141
142 /* NB: group addressed frames are done at 11bg rates for now */
143 if (ismcast || !(ni->ni_flags & IEEE80211_NODE_HT)) {
144 switch (mode) {
145 case IEEE80211_MODE_11B:
146 case IEEE80211_MODE_11G:
147 break;
148 case IEEE80211_MODE_11NG:
149 mode = IEEE80211_MODE_11G;
150 break;
151 default:
152 device_printf(sc->sc_dev, "unknown mode(1) %d!\n",
153 ic->ic_curmode);
154 return;
155 }
156 }
157
158 switch (mode) {
159 case IEEE80211_MODE_11B:
160 raid = R92C_RAID_11B;
161 break;
162 case IEEE80211_MODE_11G:
163 if (vap->iv_flags & IEEE80211_F_PUREG)
164 raid = R92C_RAID_11G;
165 else
166 raid = R92C_RAID_11BG;
167 break;
168 case IEEE80211_MODE_11NG:
169 if (vap->iv_flags_ht & IEEE80211_FHT_PUREN)
170 raid = R92C_RAID_11N;
171 else
172 raid = R92C_RAID_11BGN;
173 break;
174 default:
175 device_printf(sc->sc_dev, "unknown mode(2) %d!\n", mode);
176 return;
177 }
178
179 txd->txdw1 |= htole32(SM(R92C_TXDW1_RAID, raid));
180 }
181
182 /* XXX move to device-independent layer */
183 static void
r92c_tx_set_sgi(struct rtwn_softc * sc,void * buf,struct ieee80211_node * ni)184 r92c_tx_set_sgi(struct rtwn_softc *sc, void *buf, struct ieee80211_node *ni)
185 {
186 struct r92c_tx_desc *txd = (struct r92c_tx_desc *)buf;
187
188 /*
189 * Only enable short-GI if we're transmitting in that
190 * width to that node.
191 *
192 * Specifically, do not enable shortgi for 20MHz if
193 * we're attempting to transmit at 40MHz.
194 */
195 if (ieee80211_ht_check_tx_ht40(ni)) {
196 if (ieee80211_ht_check_tx_shortgi_40(ni))
197 txd->txdw5 |= htole32(R92C_TXDW5_SGI);
198 } else if (ieee80211_ht_check_tx_ht(ni)) {
199 if (ieee80211_ht_check_tx_shortgi_20(ni))
200 txd->txdw5 |= htole32(R92C_TXDW5_SGI);
201 }
202 }
203
204 void
r92c_tx_enable_ampdu(void * buf,int enable)205 r92c_tx_enable_ampdu(void *buf, int enable)
206 {
207 struct r92c_tx_desc *txd = (struct r92c_tx_desc *)buf;
208
209 if (enable)
210 txd->txdw1 |= htole32(R92C_TXDW1_AGGEN);
211 else
212 txd->txdw1 |= htole32(R92C_TXDW1_AGGBK);
213 }
214
215 void
r92c_tx_setup_hwseq(void * buf)216 r92c_tx_setup_hwseq(void *buf)
217 {
218 struct r92c_tx_desc *txd = (struct r92c_tx_desc *)buf;
219
220 txd->txdw4 |= htole32(R92C_TXDW4_HWSEQ_EN);
221 }
222
223 void
r92c_tx_setup_macid(void * buf,int id)224 r92c_tx_setup_macid(void *buf, int id)
225 {
226 struct r92c_tx_desc *txd = (struct r92c_tx_desc *)buf;
227
228 txd->txdw1 |= htole32(SM(R92C_TXDW1_MACID, id));
229 }
230
231 static int
r92c_calculate_tx_agg_window(struct rtwn_softc * sc,const struct ieee80211_node * ni,int tid)232 r92c_calculate_tx_agg_window(struct rtwn_softc *sc,
233 const struct ieee80211_node *ni, int tid)
234 {
235 const struct ieee80211_tx_ampdu *tap;
236 int wnd;
237
238 tap = &ni->ni_tx_ampdu[tid];
239
240 /*
241 * BAW is (MAX_AGG * 2) + 1, hence the /2 here.
242 * Ensure we don't send 0 or more than 64.
243 */
244 wnd = tap->txa_wnd / 2;
245 if (wnd == 0)
246 wnd = 1;
247 else if (wnd > 0x1f)
248 wnd = 0x1f;
249
250 return (wnd);
251 }
252
253 /*
254 * Check whether to enable the per-packet TX CCX report.
255 *
256 * For chipsets that do the RPT2 reports, enabling the TX
257 * CCX report results in the packet not being counted in
258 * the RPT2 counts.
259 */
260 static bool
r92c_check_enable_ccx_report(struct rtwn_softc * sc,int macid)261 r92c_check_enable_ccx_report(struct rtwn_softc *sc, int macid)
262 {
263 if (sc->sc_ratectl != RTWN_RATECTL_NET80211)
264 return false;
265
266 #ifndef RTWN_WITHOUT_UCODE
267 if ((sc->macid_rpt2_max_num != 0) &&
268 (macid < sc->macid_rpt2_max_num))
269 return false;
270 #endif
271 return true;
272 }
273
274 static void
r92c_fill_tx_desc_datarate(struct rtwn_softc * sc,struct r92c_tx_desc * txd,uint8_t ridx,bool force_rate)275 r92c_fill_tx_desc_datarate(struct rtwn_softc *sc, struct r92c_tx_desc *txd,
276 uint8_t ridx, bool force_rate)
277 {
278
279 /* Force this rate if needed. */
280 if (sc->sc_ratectl == RTWN_RATECTL_FW && !force_rate) {
281 txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE, 0));
282 } else {
283 txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE, ridx));
284 txd->txdw4 |= htole32(R92C_TXDW4_DRVRATE);
285 }
286
287 /* Data rate fallback limit (max). */
288 txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE_FB_LMT, 0x1f));
289 }
290
291 static void
r92c_fill_tx_desc_shpreamble(struct rtwn_softc * sc,struct r92c_tx_desc * txd,uint8_t ridx,bool force_rate)292 r92c_fill_tx_desc_shpreamble(struct rtwn_softc *sc, struct r92c_tx_desc *txd,
293 uint8_t ridx, bool force_rate)
294 {
295 const struct ieee80211com *ic = &sc->sc_ic;
296
297 if (RTWN_RATE_IS_CCK(ridx) && ridx != RTWN_RIDX_CCK1 &&
298 (ic->ic_flags & IEEE80211_F_SHPREAMBLE))
299 txd->txdw4 |= htole32(R92C_TXDW4_DATA_SHPRE);
300 }
301
302 static enum ieee80211_protmode
r92c_tx_get_protmode(struct rtwn_softc * sc,const struct ieee80211vap * vap,const struct ieee80211_node * ni,const struct mbuf * m,uint8_t ridx,bool force_rate)303 r92c_tx_get_protmode(struct rtwn_softc *sc, const struct ieee80211vap *vap,
304 const struct ieee80211_node *ni, const struct mbuf *m,
305 uint8_t ridx, bool force_rate)
306 {
307 const struct ieee80211com *ic = &sc->sc_ic;
308 enum ieee80211_protmode prot;
309
310 prot = IEEE80211_PROT_NONE;
311
312 /*
313 * If doing firmware rate control, base it the configured channel.
314 * This ensures that for HT operation the RTS/CTS or CTS-to-self
315 * configuration is obeyed.
316 */
317 if (sc->sc_ratectl == RTWN_RATECTL_FW && !force_rate) {
318 struct ieee80211_channel *chan;
319 enum ieee80211_phymode mode;
320
321 chan = (ni->ni_chan != IEEE80211_CHAN_ANYC) ?
322 ni->ni_chan : ic->ic_curchan;
323 mode = ieee80211_chan2mode(chan);
324 if (mode == IEEE80211_MODE_11NG)
325 prot = ic->ic_htprotmode;
326 else if (ic->ic_flags & IEEE80211_F_USEPROT)
327 prot = ic->ic_protmode;
328 } else {
329 if (RTWN_RATE_IS_HT(ridx))
330 prot = ic->ic_htprotmode;
331 else if (ic->ic_flags & IEEE80211_F_USEPROT)
332 prot = ic->ic_protmode;
333 }
334
335 /* XXX fix last comparison for A-MSDU (in net80211) */
336 /* XXX A-MPDU? */
337 if (m->m_pkthdr.len + IEEE80211_CRC_LEN >
338 vap->iv_rtsthreshold &&
339 vap->iv_rtsthreshold != IEEE80211_RTS_MAX)
340 prot = IEEE80211_PROT_RTSCTS;
341
342 return (prot);
343 }
344
345 void
r92c_fill_tx_desc(struct rtwn_softc * sc,struct ieee80211_node * ni,struct mbuf * m,void * buf,uint8_t ridx,bool force_rate,int maxretry)346 r92c_fill_tx_desc(struct rtwn_softc *sc, struct ieee80211_node *ni,
347 struct mbuf *m, void *buf, uint8_t ridx, bool force_rate, int maxretry)
348 {
349 #ifndef RTWN_WITHOUT_UCODE
350 struct r92c_softc *rs = sc->sc_priv;
351 #endif
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 enum ieee80211_protmode prot;
357 uint8_t type, tid, qos, qsel;
358 int hasqos, ismcast, macid;
359
360 wh = mtod(m, struct ieee80211_frame *);
361 type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
362 hasqos = IEEE80211_QOS_HAS_SEQ(wh);
363 ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1);
364
365 /* Select TX ring for this frame. */
366 if (hasqos) {
367 qos = ((const struct ieee80211_qosframe *)wh)->i_qos[0];
368 tid = qos & IEEE80211_QOS_TID;
369 } else {
370 qos = 0;
371 tid = 0;
372 }
373
374 /* Fill Tx descriptor. */
375 txd = (struct r92c_tx_desc *)buf;
376 txd->flags0 |= R92C_FLAGS0_LSG | R92C_FLAGS0_FSG;
377 if (ismcast)
378 txd->flags0 |= R92C_FLAGS0_BMCAST;
379
380 if (IEEE80211_IS_QOSDATA(wh))
381 txd->txdw4 |= htole32(R92C_TXDW4_QOS);
382
383 if (!ismcast) {
384 struct rtwn_node *un = RTWN_NODE(ni);
385 macid = un->id;
386
387 /* Unicast frame, check if an ACK is expected. */
388 if (!qos || (qos & IEEE80211_QOS_ACKPOLICY) !=
389 IEEE80211_QOS_ACKPOLICY_NOACK) {
390 txd->txdw5 |= htole32(R92C_TXDW5_RTY_LMT_ENA);
391 txd->txdw5 |= htole32(SM(R92C_TXDW5_RTY_LMT,
392 maxretry));
393 }
394
395 if (type == IEEE80211_FC0_TYPE_DATA) {
396 qsel = tid % RTWN_MAX_TID;
397
398 rtwn_r92c_tx_enable_ampdu(sc, buf,
399 (m->m_flags & M_AMPDU_MPDU) != 0);
400 if (m->m_flags & M_AMPDU_MPDU) {
401 txd->txdw2 |= htole32(SM(R92C_TXDW2_AMPDU_DEN,
402 ieee80211_ht_get_node_ampdu_density(ni)));
403 txd->txdw6 |= htole32(SM(R92C_TXDW6_MAX_AGG,
404 r92c_calculate_tx_agg_window(sc, ni, tid)));
405 }
406 if (r92c_check_enable_ccx_report(sc, macid)) {
407 txd->txdw2 |= htole32(R92C_TXDW2_CCX_RPT);
408 sc->sc_tx_n_active++;
409 #ifndef RTWN_WITHOUT_UCODE
410 rs->rs_c2h_pending++;
411 #endif
412 }
413
414 r92c_fill_tx_desc_shpreamble(sc, txd, ridx, force_rate);
415
416 prot = r92c_tx_get_protmode(sc, vap, ni, m, ridx,
417 force_rate);
418
419 /*
420 * Note: Firmware rate control will enable short-GI
421 * based on the configured rate mask, however HT40
422 * may not be enabled.
423 */
424 if (sc->sc_ratectl != RTWN_RATECTL_FW &&
425 RTWN_RATE_IS_HT(ridx)) {
426 r92c_tx_set_ht40(sc, txd, ni);
427 r92c_tx_set_sgi(sc, txd, ni);
428 }
429
430 /* NB: checks for ht40 / short bits (set above). */
431 r92c_tx_protection(sc, txd, prot, ridx, force_rate);
432 } else /* IEEE80211_FC0_TYPE_MGT */
433 qsel = R92C_TXDW1_QSEL_MGNT;
434 } else {
435 macid = RTWN_MACID_BC;
436 qsel = R92C_TXDW1_QSEL_MGNT;
437 }
438
439 txd->txdw1 |= htole32(SM(R92C_TXDW1_QSEL, qsel));
440
441 rtwn_r92c_tx_setup_macid(sc, txd, macid);
442
443 /* Fill in data rate, data retry */
444 r92c_fill_tx_desc_datarate(sc, txd, ridx, force_rate);
445
446 txd->txdw4 |= htole32(SM(R92C_TXDW4_PORT_ID, uvp->id));
447 r92c_tx_raid(sc, txd, ni, ismcast);
448
449 if (!hasqos) {
450 /* Use HW sequence numbering for non-QoS frames. */
451 rtwn_r92c_tx_setup_hwseq(sc, txd);
452 } else {
453 uint16_t seqno;
454
455 if (m->m_flags & M_AMPDU_MPDU) {
456 seqno = ni->ni_txseqs[tid] % IEEE80211_SEQ_RANGE;
457 ni->ni_txseqs[tid]++;
458 } else
459 seqno = M_SEQNO_GET(m) % IEEE80211_SEQ_RANGE;
460
461 /* Set sequence number. */
462 txd->txdseq = htole16(seqno);
463 }
464 }
465
466 void
r92c_fill_tx_desc_raw(struct rtwn_softc * sc,struct ieee80211_node * ni,struct mbuf * m,void * buf,const struct ieee80211_bpf_params * params)467 r92c_fill_tx_desc_raw(struct rtwn_softc *sc, struct ieee80211_node *ni,
468 struct mbuf *m, void *buf, const struct ieee80211_bpf_params *params)
469 {
470 struct ieee80211vap *vap = ni->ni_vap;
471 struct rtwn_vap *uvp = RTWN_VAP(vap);
472 struct ieee80211_frame *wh;
473 struct r92c_tx_desc *txd;
474 uint8_t ridx;
475 int ismcast;
476
477 /* XXX TODO: 11n checks, matching r92c_fill_tx_desc() */
478
479 wh = mtod(m, struct ieee80211_frame *);
480 ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1);
481 ridx = rate2ridx(params->ibp_rate0);
482
483 /* Fill Tx descriptor. */
484 txd = (struct r92c_tx_desc *)buf;
485 txd->flags0 |= R92C_FLAGS0_LSG | R92C_FLAGS0_FSG;
486 if (ismcast)
487 txd->flags0 |= R92C_FLAGS0_BMCAST;
488
489 if ((params->ibp_flags & IEEE80211_BPF_NOACK) == 0) {
490 txd->txdw5 |= htole32(R92C_TXDW5_RTY_LMT_ENA);
491 txd->txdw5 |= htole32(SM(R92C_TXDW5_RTY_LMT,
492 params->ibp_try0));
493 }
494 if (params->ibp_flags & IEEE80211_BPF_RTS)
495 r92c_tx_protection(sc, txd, IEEE80211_PROT_RTSCTS, ridx,
496 true);
497 if (params->ibp_flags & IEEE80211_BPF_CTS)
498 r92c_tx_protection(sc, txd, IEEE80211_PROT_CTSONLY, ridx,
499 true);
500
501 rtwn_r92c_tx_setup_macid(sc, txd, RTWN_MACID_BC);
502 txd->txdw1 |= htole32(SM(R92C_TXDW1_QSEL, R92C_TXDW1_QSEL_MGNT));
503
504 /* Set TX rate index. */
505 r92c_fill_tx_desc_datarate(sc, txd, ridx, true); /* force rate */
506 txd->txdw4 |= htole32(SM(R92C_TXDW4_PORT_ID, uvp->id));
507 r92c_tx_raid(sc, txd, ni, ismcast);
508
509 if (!IEEE80211_QOS_HAS_SEQ(wh)) {
510 /* Use HW sequence numbering for non-QoS frames. */
511 rtwn_r92c_tx_setup_hwseq(sc, txd);
512 } else {
513 /* Set sequence number. */
514 txd->txdseq |= htole16(M_SEQNO_GET(m) % IEEE80211_SEQ_RANGE);
515 }
516 }
517
518 void
r92c_fill_tx_desc_null(struct rtwn_softc * sc,void * buf,int is11b,int qos,int id)519 r92c_fill_tx_desc_null(struct rtwn_softc *sc, void *buf, int is11b,
520 int qos, int id)
521 {
522 struct r92c_tx_desc *txd = (struct r92c_tx_desc *)buf;
523
524 txd->flags0 = R92C_FLAGS0_FSG | R92C_FLAGS0_LSG | R92C_FLAGS0_OWN;
525 txd->txdw1 = htole32(
526 SM(R92C_TXDW1_QSEL, R92C_TXDW1_QSEL_MGNT));
527
528 txd->txdw4 = htole32(R92C_TXDW4_DRVRATE);
529 txd->txdw4 |= htole32(SM(R92C_TXDW4_PORT_ID, id));
530 if (is11b) {
531 txd->txdw5 = htole32(SM(R92C_TXDW5_DATARATE,
532 RTWN_RIDX_CCK1));
533 } else {
534 txd->txdw5 = htole32(SM(R92C_TXDW5_DATARATE,
535 RTWN_RIDX_OFDM6));
536 }
537
538 if (!qos) {
539 rtwn_r92c_tx_setup_hwseq(sc, txd);
540 }
541 }
542
543 uint8_t
r92c_tx_radiotap_flags(const void * buf)544 r92c_tx_radiotap_flags(const void *buf)
545 {
546 const struct r92c_tx_desc *txd = buf;
547 uint8_t flags;
548
549 flags = 0;
550 if (txd->txdw4 & htole32(R92C_TXDW4_DATA_SHPRE))
551 flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
552 if (txd->txdw5 & htole32(R92C_TXDW5_SGI))
553 flags |= IEEE80211_RADIOTAP_F_SHORTGI;
554 return (flags);
555 }
556