diff --git a/sys/dev/rtwn/if_rtwn_tx.c b/sys/dev/rtwn/if_rtwn_tx.c index bf45d14f7edc..c59d1de1dea8 100644 --- a/sys/dev/rtwn/if_rtwn_tx.c +++ b/sys/dev/rtwn/if_rtwn_tx.c @@ -1,342 +1,346 @@ /* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ /*- * Copyright (c) 2010 Damien Bergamini * Copyright (c) 2014 Kevin Lo * Copyright (c) 2015-2016 Andriy Voskoboinyk * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include "opt_wlan.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef IEEE80211_SUPPORT_SUPERG #include #endif #include #include #include #include #include #include void rtwn_drain_mbufq(struct rtwn_softc *sc) { struct mbuf *m; struct ieee80211_node *ni; RTWN_ASSERT_LOCKED(sc); while ((m = mbufq_dequeue(&sc->sc_snd)) != NULL) { ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; m->m_pkthdr.rcvif = NULL; ieee80211_free_node(ni); m_freem(m); } } #ifdef IEEE80211_SUPPORT_SUPERG void rtwn_ff_flush_all(struct rtwn_softc *sc, union sec_param *data) { struct ieee80211com *ic = &sc->sc_ic; RTWN_UNLOCK(sc); ieee80211_ff_flush_all(ic); RTWN_LOCK(sc); } #endif static uint8_t rtwn_get_cipher(u_int ic_cipher) { uint8_t cipher; switch (ic_cipher) { case IEEE80211_CIPHER_NONE: cipher = RTWN_TXDW1_CIPHER_NONE; break; case IEEE80211_CIPHER_WEP: case IEEE80211_CIPHER_TKIP: cipher = RTWN_TXDW1_CIPHER_RC4; break; case IEEE80211_CIPHER_AES_CCM: cipher = RTWN_TXDW1_CIPHER_AES; break; default: KASSERT(0, ("%s: unknown cipher %d\n", __func__, ic_cipher)); return (RTWN_TXDW1_CIPHER_SM4); } return (cipher); } static int rtwn_tx_data(struct rtwn_softc *sc, struct ieee80211_node *ni, struct mbuf *m) { const struct ieee80211_txparam *tp = ni->ni_txparms; struct ieee80211com *ic = &sc->sc_ic; struct ieee80211vap *vap = ni->ni_vap; struct ieee80211_key *k = NULL; struct ieee80211_frame *wh; struct rtwn_tx_desc_common *txd; struct rtwn_tx_buf buf; uint8_t rate, ridx, type; + bool force_rate = false; u_int cipher; int ismcast; RTWN_ASSERT_LOCKED(sc); wh = mtod(m, struct ieee80211_frame *); type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1); /* Choose a TX rate index. */ if (type == IEEE80211_FC0_TYPE_MGT || type == IEEE80211_FC0_TYPE_CTL || - (m->m_flags & M_EAPOL) != 0) + (m->m_flags & M_EAPOL) != 0) { rate = tp->mgmtrate; - else if (ismcast) + force_rate = true; + } else if (ismcast) { + force_rate = true; rate = tp->mcastrate; - else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) + } else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) { + force_rate = true; rate = tp->ucastrate; - else { + } else { if (sc->sc_ratectl == RTWN_RATECTL_NET80211) { /* XXX pass pktlen */ (void) ieee80211_ratectl_rate(ni, NULL, 0); rate = ni->ni_txrate; } else { if (ni->ni_flags & IEEE80211_NODE_HT) rate = IEEE80211_RATE_MCS | 0x4; /* MCS4 */ else if (ic->ic_curmode != IEEE80211_MODE_11B) rate = ridx2rate[RTWN_RIDX_OFDM36]; else rate = ridx2rate[RTWN_RIDX_CCK55]; } } ridx = rate2ridx(rate); cipher = IEEE80211_CIPHER_NONE; if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { k = ieee80211_crypto_encap(ni, m); if (k == NULL) { device_printf(sc->sc_dev, "ieee80211_crypto_encap returns NULL.\n"); return (ENOBUFS); } if (!(k->wk_flags & IEEE80211_KEY_SWCRYPT)) cipher = k->wk_cipher->ic_cipher; /* in case packet header moved, reset pointer */ wh = mtod(m, struct ieee80211_frame *); } /* Fill Tx descriptor. */ txd = (struct rtwn_tx_desc_common *)&buf; memset(txd, 0, sc->txdesc_len); txd->txdw1 = htole32(SM(RTWN_TXDW1_CIPHER, rtwn_get_cipher(cipher))); - rtwn_fill_tx_desc(sc, ni, m, txd, ridx, tp->maxretry); + rtwn_fill_tx_desc(sc, ni, m, txd, ridx, force_rate, tp->maxretry); if (ieee80211_radiotap_active_vap(vap)) { struct rtwn_tx_radiotap_header *tap = &sc->sc_txtap; tap->wt_flags = rtwn_tx_radiotap_flags(sc, txd); if (k != NULL) tap->wt_flags |= IEEE80211_RADIOTAP_F_WEP; ieee80211_radiotap_tx(vap, m); } return (rtwn_tx_start(sc, ni, m, (uint8_t *)txd, type, 0)); } static int rtwn_tx_raw(struct rtwn_softc *sc, struct ieee80211_node *ni, struct mbuf *m, const struct ieee80211_bpf_params *params) { struct ieee80211vap *vap = ni->ni_vap; struct ieee80211_key *k = NULL; struct ieee80211_frame *wh; struct rtwn_tx_desc_common *txd; struct rtwn_tx_buf buf; uint8_t type; u_int cipher; /* Encrypt the frame if need be. */ cipher = IEEE80211_CIPHER_NONE; if (params->ibp_flags & IEEE80211_BPF_CRYPTO) { /* Retrieve key for TX. */ k = ieee80211_crypto_encap(ni, m); if (k == NULL) { device_printf(sc->sc_dev, "ieee80211_crypto_encap returns NULL.\n"); return (ENOBUFS); } if (!(k->wk_flags & IEEE80211_KEY_SWCRYPT)) cipher = k->wk_cipher->ic_cipher; } wh = mtod(m, struct ieee80211_frame *); type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; /* Fill Tx descriptor. */ txd = (struct rtwn_tx_desc_common *)&buf; memset(txd, 0, sc->txdesc_len); txd->txdw1 = htole32(SM(RTWN_TXDW1_CIPHER, rtwn_get_cipher(cipher))); rtwn_fill_tx_desc_raw(sc, ni, m, txd, params); if (ieee80211_radiotap_active_vap(vap)) { struct rtwn_tx_radiotap_header *tap = &sc->sc_txtap; tap->wt_flags = rtwn_tx_radiotap_flags(sc, txd); if (k != NULL) tap->wt_flags |= IEEE80211_RADIOTAP_F_WEP; ieee80211_radiotap_tx(vap, m); } return (rtwn_tx_start(sc, ni, m, (uint8_t *)txd, type, 0)); } int rtwn_transmit(struct ieee80211com *ic, struct mbuf *m) { struct rtwn_softc *sc = ic->ic_softc; int error; RTWN_LOCK(sc); if ((sc->sc_flags & RTWN_RUNNING) == 0) { RTWN_UNLOCK(sc); return (ENXIO); } error = mbufq_enqueue(&sc->sc_snd, m); if (error) { RTWN_UNLOCK(sc); return (error); } rtwn_start(sc); RTWN_UNLOCK(sc); return (0); } void rtwn_start(struct rtwn_softc *sc) { struct ieee80211_node *ni; struct mbuf *m; RTWN_ASSERT_LOCKED(sc); /* Ensure no work is scheduled during reset/teardown */ if ((sc->sc_flags & RTWN_RUNNING) == 0) return; while ((m = mbufq_dequeue(&sc->sc_snd)) != NULL) { if (sc->qfullmsk != 0) { mbufq_prepend(&sc->sc_snd, m); break; } ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; m->m_pkthdr.rcvif = NULL; RTWN_DPRINTF(sc, RTWN_DEBUG_XMIT, "%s: called; m %p, ni %p\n", __func__, m, ni); if (rtwn_tx_data(sc, ni, m) != 0) { if_inc_counter(ni->ni_vap->iv_ifp, IFCOUNTER_OERRORS, 1); m_freem(m); #ifdef D4054 ieee80211_tx_watchdog_refresh(ni->ni_ic, -1, 0); #endif ieee80211_free_node(ni); break; } } } int rtwn_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, const struct ieee80211_bpf_params *params) { struct ieee80211com *ic = ni->ni_ic; struct rtwn_softc *sc = ic->ic_softc; int error; RTWN_DPRINTF(sc, RTWN_DEBUG_XMIT, "%s: called; m %p, ni %p\n", __func__, m, ni); /* prevent management frames from being sent if we're not ready */ RTWN_LOCK(sc); if (!(sc->sc_flags & RTWN_RUNNING)) { error = ENETDOWN; goto end; } if (sc->qfullmsk != 0) { error = ENOBUFS; goto end; } if (params == NULL) { /* * Legacy path; interpret frame contents to decide * precisely how to send the frame. */ error = rtwn_tx_data(sc, ni, m); } else { /* * Caller supplied explicit parameters to use in * sending the frame. */ error = rtwn_tx_raw(sc, ni, m, params); } end: if (error != 0) { if (m->m_flags & M_TXCB) ieee80211_process_callback(ni, m, 1); m_freem(m); } RTWN_UNLOCK(sc); return (error); } diff --git a/sys/dev/rtwn/if_rtwnvar.h b/sys/dev/rtwn/if_rtwnvar.h index 3913526f8c3c..fa4b6d0a5df7 100644 --- a/sys/dev/rtwn/if_rtwnvar.h +++ b/sys/dev/rtwn/if_rtwnvar.h @@ -1,647 +1,647 @@ /*- * Copyright (c) 2010 Damien Bergamini * Copyright (c) 2015-2016 Andriy Voskoboinyk * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $ */ #ifndef IF_RTWNVAR_H #define IF_RTWNVAR_H #include "opt_rtwn.h" #define RTWN_TX_DESC_SIZE 64 #define RTWN_BCN_MAX_SIZE 512 #define RTWN_CAM_ENTRY_LIMIT 64 #define RTWN_MACID_BC 1 /* Broadcast. */ #define RTWN_MACID_UNDEFINED 0x7fff #define RTWN_MACID_VALID 0x8000 #define RTWN_MACID_LIMIT 128 #define RTWN_TX_TIMEOUT 1000 /* ms */ #define RTWN_MAX_EPOUT 4 #define RTWN_PORT_COUNT 2 #define RTWN_LED_LINK 0 #define RTWN_LED_DATA 1 struct rtwn_rx_radiotap_header { struct ieee80211_radiotap_header wr_ihdr; uint64_t wr_tsft; uint8_t wr_flags; uint8_t wr_rate; uint16_t wr_chan_freq; uint16_t wr_chan_flags; int8_t wr_dbm_antsignal; int8_t wr_dbm_antnoise; } __packed __aligned(8); #define RTWN_RX_RADIOTAP_PRESENT \ (1 << IEEE80211_RADIOTAP_TSFT | \ 1 << IEEE80211_RADIOTAP_FLAGS | \ 1 << IEEE80211_RADIOTAP_RATE | \ 1 << IEEE80211_RADIOTAP_CHANNEL | \ 1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL | \ 1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) struct rtwn_tx_radiotap_header { struct ieee80211_radiotap_header wt_ihdr; uint8_t wt_flags; uint8_t wt_pad; uint16_t wt_chan_freq; uint16_t wt_chan_flags; } __packed; #define RTWN_TX_RADIOTAP_PRESENT \ (1 << IEEE80211_RADIOTAP_FLAGS | \ 1 << IEEE80211_RADIOTAP_CHANNEL) struct rtwn_tx_buf { uint8_t txd[RTWN_TX_DESC_SIZE]; } __attribute__((aligned(4))); #define RTWN_PHY_STATUS_SIZE 32 struct rtwn_tx_phystat { uint32_t phydw[RTWN_PHY_STATUS_SIZE / sizeof(uint32_t)]; }; struct rtwn_softc; union sec_param { struct ieee80211_key key; int macid; }; #define CMD_FUNC_PROTO void (*func)(struct rtwn_softc *, \ union sec_param *) struct rtwn_cmdq { union sec_param data; CMD_FUNC_PROTO; }; #define RTWN_CMDQ_SIZE 16 struct rtwn_node { struct ieee80211_node ni; /* must be the first */ int id; struct rtwn_tx_phystat last_physt; int avg_pwdb; }; #define RTWN_NODE(ni) ((struct rtwn_node *)(ni)) struct rtwn_vap { struct ieee80211vap vap; int id; #define RTWN_VAP_ID_INVALID -1 int curr_mode; struct rtwn_tx_buf bcn_desc; struct mbuf *bcn_mbuf; struct timeout_task tx_beacon_csa; struct callout tsf_sync_adhoc; struct task tsf_sync_adhoc_task; const struct ieee80211_key *keys[IEEE80211_WEP_NKID]; int (*newstate)(struct ieee80211vap *, enum ieee80211_state, int); void (*recv_mgmt)(struct ieee80211_node *, struct mbuf *, int, const struct ieee80211_rx_stats *, int, int); }; #define RTWN_VAP(vap) ((struct rtwn_vap *)(vap)) /* * Rx data types. */ enum { RTWN_RX_DATA, RTWN_RX_TX_REPORT, /* Per-packet */ RTWN_RX_TX_REPORT2, /* Per-MACID summary */ RTWN_RX_OTHER }; /* * Firmware reset reasons. */ enum { RTWN_FW_RESET_DOWNLOAD, RTWN_FW_RESET_CHECKSUM, RTWN_FW_RESET_SHUTDOWN }; /* * Rate control algorithm selection. */ enum { RTWN_RATECTL_NONE, RTWN_RATECTL_NET80211, RTWN_RATECTL_FW, RTWN_RATECTL_MAX }; /* * Control h/w crypto usage. */ enum { RTWN_CRYPTO_SW, RTWN_CRYPTO_PAIR, RTWN_CRYPTO_FULL, RTWN_CRYPTO_MAX, }; struct rtwn_softc { struct ieee80211com sc_ic; struct mbufq sc_snd; device_t sc_dev; int sc_ht40; int sc_ena_tsf64; uint32_t sc_debug; int sc_hwcrypto; int sc_ratectl_sysctl; int sc_ratectl; uint32_t sc_reg_addr; uint8_t sc_detached; uint8_t sc_flags; /* Device flags */ #define RTWN_FLAG_CCK_HIPWR 0x01 #define RTWN_FLAG_EXT_HDR 0x02 #define RTWN_FLAG_CAM_FIXED 0x04 /* Driver state */ #define RTWN_STARTED 0x08 #define RTWN_RUNNING 0x10 #define RTWN_FW_LOADED 0x20 #define RTWN_TEMP_MEASURED 0x40 #define RTWN_RCR_LOCKED 0x80 #define RTWN_CHIP_HAS_BCNQ1(_sc) \ ((_sc)->bcn_status_reg[0] != (_sc)->bcn_status_reg[1]) void *sc_priv; const char *name; int sc_ant; struct rtwn_tx_phystat last_physt; uint8_t thcal_temp; int cur_bcnq_id; int nvaps; int ap_vaps; int bcn_vaps; int mon_vaps; int vaps_running; int monvaps_running; uint16_t next_rom_addr; uint8_t keys_bmap[howmany(RTWN_CAM_ENTRY_LIMIT, NBBY)]; struct rtwn_vap *vaps[RTWN_PORT_COUNT]; struct ieee80211_node *node_list[RTWN_MACID_LIMIT]; struct mtx nt_mtx; struct callout sc_calib_to; struct callout sc_pwrmode_init; #ifndef D4054 struct callout sc_watchdog_to; int sc_tx_timer; #endif struct mtx sc_mtx; struct rtwn_cmdq cmdq[RTWN_CMDQ_SIZE]; struct mtx cmdq_mtx; struct task cmdq_task; uint8_t cmdq_first; uint8_t cmdq_last; struct wmeParams cap_wmeParams[WME_NUM_AC]; struct rtwn_rx_radiotap_header sc_rxtap; struct rtwn_tx_radiotap_header sc_txtap; int ntxchains; int nrxchains; int ledlink; uint8_t thermal_meter; int sc_tx_n_active; uint8_t qfullmsk; /* Firmware-specific */ const char *fwname; uint16_t fwver; uint16_t fwsig; int fwcur; void (*sc_node_free)(struct ieee80211_node *); void (*sc_scan_curchan)(struct ieee80211_scan_state *, unsigned long); /* Interface-specific. */ int (*sc_write_1)(struct rtwn_softc *, uint16_t, uint8_t); int (*sc_write_2)(struct rtwn_softc *, uint16_t, uint16_t); int (*sc_write_4)(struct rtwn_softc *, uint16_t, uint32_t); uint8_t (*sc_read_1)(struct rtwn_softc *, uint16_t); uint16_t (*sc_read_2)(struct rtwn_softc *, uint16_t); uint32_t (*sc_read_4)(struct rtwn_softc *, uint16_t); /* XXX eliminate */ void (*sc_delay)(struct rtwn_softc *, int); int (*sc_tx_start)(struct rtwn_softc *, struct ieee80211_node *, struct mbuf *, uint8_t *, uint8_t, int); void (*sc_start_xfers)(struct rtwn_softc *); void (*sc_reset_lists)(struct rtwn_softc *, struct ieee80211vap *); void (*sc_abort_xfers)(struct rtwn_softc *); int (*sc_fw_write_block)(struct rtwn_softc *, const uint8_t *, uint16_t, int); uint16_t (*sc_get_qmap)(struct rtwn_softc *); void (*sc_set_desc_addr)(struct rtwn_softc *); void (*sc_drop_incorrect_tx)(struct rtwn_softc *); void (*sc_beacon_update_begin)(struct rtwn_softc *, struct ieee80211vap *); void (*sc_beacon_update_end)(struct rtwn_softc *, struct ieee80211vap *); void (*sc_beacon_unload)(struct rtwn_softc *, int); /* XXX drop checks for PCIe? */ int bcn_check_interval; /* Device-specific. */ uint32_t (*sc_rf_read)(struct rtwn_softc *, int, uint8_t); void (*sc_rf_write)(struct rtwn_softc *, int, uint8_t, uint32_t); int (*sc_check_condition)(struct rtwn_softc *, const uint8_t[]); void (*sc_efuse_postread)(struct rtwn_softc *); void (*sc_parse_rom)(struct rtwn_softc *, uint8_t *); void (*sc_set_led)(struct rtwn_softc *, int, int); int (*sc_power_on)(struct rtwn_softc *); void (*sc_power_off)(struct rtwn_softc *); #ifndef RTWN_WITHOUT_UCODE void (*sc_fw_reset)(struct rtwn_softc *, int); void (*sc_fw_download_enable)(struct rtwn_softc *, int); #endif int (*sc_llt_init)(struct rtwn_softc *); int (*sc_set_page_size)(struct rtwn_softc *); void (*sc_lc_calib)(struct rtwn_softc *); void (*sc_iq_calib)(struct rtwn_softc *); void (*sc_read_chipid_vendor)(struct rtwn_softc *, uint32_t); void (*sc_adj_devcaps)(struct rtwn_softc *); void (*sc_vap_preattach)(struct rtwn_softc *, struct ieee80211vap *); void (*sc_postattach)(struct rtwn_softc *); void (*sc_detach_private)(struct rtwn_softc *); void (*sc_fill_tx_desc)(struct rtwn_softc *, struct ieee80211_node *, struct mbuf *, - void *, uint8_t, int); + void *, uint8_t, bool, int); void (*sc_fill_tx_desc_raw)(struct rtwn_softc *, struct ieee80211_node *, struct mbuf *, void *, const struct ieee80211_bpf_params *); void (*sc_fill_tx_desc_null)(struct rtwn_softc *, void *, int, int, int); void (*sc_dump_tx_desc)(struct rtwn_softc *, const void *); uint8_t (*sc_tx_radiotap_flags)(const void *); uint8_t (*sc_rx_radiotap_flags)(const void *); void (*sc_beacon_init)(struct rtwn_softc *, void *, int); void (*sc_beacon_enable)(struct rtwn_softc *, int, int); void (*sc_sta_beacon_enable)(struct rtwn_softc *, int, bool); void (*sc_beacon_set_rate)(void *, int); void (*sc_beacon_select)(struct rtwn_softc *, int); void (*sc_set_chan)(struct rtwn_softc *, struct ieee80211_channel *); void (*sc_set_media_status)(struct rtwn_softc *, int); #ifndef RTWN_WITHOUT_UCODE int (*sc_set_rsvd_page)(struct rtwn_softc *, int, int, int); int (*sc_set_pwrmode)(struct rtwn_softc *, struct ieee80211vap *, int); void (*sc_set_rssi)(struct rtwn_softc *); #endif void (*sc_get_rx_stats)(struct rtwn_softc *, struct ieee80211_rx_stats *, const void *, const void *); int8_t (*sc_get_rssi_cck)(struct rtwn_softc *, void *); int8_t (*sc_get_rssi_ofdm)(struct rtwn_softc *, void *); int (*sc_classify_intr)(struct rtwn_softc *, void *, int); void (*sc_handle_tx_report)(struct rtwn_softc *, uint8_t *, int); void (*sc_handle_tx_report2)(struct rtwn_softc *, uint8_t *, int); void (*sc_handle_c2h_report)(struct rtwn_softc *, uint8_t *, int); int (*sc_check_frame)(struct rtwn_softc *, struct mbuf *); void (*sc_temp_measure)(struct rtwn_softc *); uint8_t (*sc_temp_read)(struct rtwn_softc *); void (*sc_init_tx_agg)(struct rtwn_softc *); void (*sc_init_rx_agg)(struct rtwn_softc *); void (*sc_init_intr)(struct rtwn_softc *); void (*sc_init_ampdu)(struct rtwn_softc *); void (*sc_init_edca)(struct rtwn_softc *); void (*sc_init_bb)(struct rtwn_softc *); void (*sc_init_rf)(struct rtwn_softc *); void (*sc_init_antsel)(struct rtwn_softc *); void (*sc_post_init)(struct rtwn_softc *); int (*sc_init_bcnq1_boundary)(struct rtwn_softc *); int (*sc_set_tx_power)(struct rtwn_softc *, struct ieee80211vap *); const uint8_t *chan_list_5ghz[3]; int chan_num_5ghz[3]; const struct rtwn_mac_prog *mac_prog; int mac_size; const struct rtwn_bb_prog *bb_prog; int bb_size; const struct rtwn_agc_prog *agc_prog; int agc_size; const struct rtwn_rf_prog *rf_prog; int page_count; int pktbuf_count; int ackto; int npubqpages; int nhqpages; int nnqpages; int nlqpages; int page_size; int txdesc_len; int efuse_maxlen; int efuse_maplen; uint16_t rx_dma_size; int macid_limit; int macid_rpt2_max_num; int cam_entry_limit; int fwsize_limit; int temp_delta; uint16_t bcn_status_reg[RTWN_PORT_COUNT]; uint32_t rcr; /* Rx filter */ }; MALLOC_DECLARE(M_RTWN_PRIV); #define RTWN_LOCK(sc) mtx_lock(&(sc)->sc_mtx) #define RTWN_UNLOCK(sc) mtx_unlock(&(sc)->sc_mtx) #define RTWN_ASSERT_LOCKED(sc) mtx_assert(&(sc)->sc_mtx, MA_OWNED) #define RTWN_CMDQ_LOCK_INIT(sc) \ mtx_init(&(sc)->cmdq_mtx, "cmdq lock", NULL, MTX_DEF) #define RTWN_CMDQ_LOCK(sc) mtx_lock(&(sc)->cmdq_mtx) #define RTWN_CMDQ_UNLOCK(sc) mtx_unlock(&(sc)->cmdq_mtx) #define RTWN_CMDQ_LOCK_INITIALIZED(sc) mtx_initialized(&(sc)->cmdq_mtx) #define RTWN_CMDQ_LOCK_DESTROY(sc) mtx_destroy(&(sc)->cmdq_mtx) #define RTWN_NT_LOCK_INIT(sc) \ mtx_init(&(sc)->nt_mtx, "node table lock", NULL, MTX_DEF) #define RTWN_NT_LOCK(sc) mtx_lock(&(sc)->nt_mtx) #define RTWN_NT_UNLOCK(sc) mtx_unlock(&(sc)->nt_mtx) #define RTWN_NT_LOCK_INITIALIZED(sc) mtx_initialized(&(sc)->nt_mtx) #define RTWN_NT_LOCK_DESTROY(sc) mtx_destroy(&(sc)->nt_mtx) void rtwn_sysctlattach(struct rtwn_softc *); int rtwn_attach(struct rtwn_softc *); void rtwn_detach(struct rtwn_softc *); void rtwn_resume(struct rtwn_softc *); void rtwn_suspend(struct rtwn_softc *); /* Interface-specific. */ #define rtwn_write_1(_sc, _addr, _val) \ (((_sc)->sc_write_1)((_sc), (_addr), (_val))) #define rtwn_write_2(_sc, _addr, _val) \ (((_sc)->sc_write_2)((_sc), (_addr), (_val))) #define rtwn_write_4(_sc, _addr, _val) \ (((_sc)->sc_write_4)((_sc), (_addr), (_val))) #define rtwn_read_1(_sc, _addr) \ (((_sc)->sc_read_1)((_sc), (_addr))) #define rtwn_read_2(_sc, _addr) \ (((_sc)->sc_read_2)((_sc), (_addr))) #define rtwn_read_4(_sc, _addr) \ (((_sc)->sc_read_4)((_sc), (_addr))) #define rtwn_delay(_sc, _usec) \ (((_sc)->sc_delay)((_sc), (_usec))) #define rtwn_tx_start(_sc, _ni, _m, _desc, _type, _id) \ (((_sc)->sc_tx_start)((_sc), (_ni), (_m), (_desc), (_type), (_id))) #define rtwn_start_xfers(_sc) \ (((_sc)->sc_start_xfers)((_sc))) #define rtwn_reset_lists(_sc, _vap) \ (((_sc)->sc_reset_lists)((_sc), (_vap))) #define rtwn_abort_xfers(_sc) \ (((_sc)->sc_abort_xfers)((_sc))) #define rtwn_fw_write_block(_sc, _buf, _reg, _len) \ (((_sc)->sc_fw_write_block)((_sc), (_buf), (_reg), (_len))) #define rtwn_get_qmap(_sc) \ (((_sc)->sc_get_qmap)((_sc))) #define rtwn_set_desc_addr(_sc) \ (((_sc)->sc_set_desc_addr)((_sc))) #define rtwn_drop_incorrect_tx(_sc) \ (((_sc)->sc_drop_incorrect_tx)((_sc))) #define rtwn_beacon_update_begin(_sc, _vap) \ (((_sc)->sc_beacon_update_begin)((_sc), (_vap))) #define rtwn_beacon_update_end(_sc, _vap) \ (((_sc)->sc_beacon_update_end)((_sc), (_vap))) #define rtwn_beacon_unload(_sc, _id) \ (((_sc)->sc_beacon_unload)((_sc), (_id))) /* Aliases. */ #define rtwn_bb_write rtwn_write_4 #define rtwn_bb_read rtwn_read_4 #define rtwn_bb_setbits rtwn_setbits_4 /* Device-specific. */ #define rtwn_rf_read(_sc, _chain, _addr) \ (((_sc)->sc_rf_read)((_sc), (_chain), (_addr))) #define rtwn_rf_write(_sc, _chain, _addr, _val) \ (((_sc)->sc_rf_write)((_sc), (_chain), (_addr), (_val))) #define rtwn_check_condition(_sc, _cond) \ (((_sc)->sc_check_condition)((_sc), (_cond))) #define rtwn_efuse_postread(_sc) \ (((_sc)->sc_efuse_postread)((_sc))) #define rtwn_parse_rom(_sc, _rom) \ (((_sc)->sc_parse_rom)((_sc), (_rom))) #define rtwn_set_led(_sc, _led, _on) \ (((_sc)->sc_set_led)((_sc), (_led), (_on))) #define rtwn_get_rx_stats(_sc, _rxs, _desc, _physt) \ (((_sc)->sc_get_rx_stats((_sc), (_rxs), (_desc), (_physt)))) #define rtwn_get_rssi_cck(_sc, _physt) \ (((_sc)->sc_get_rssi_cck)((_sc), (_physt))) #define rtwn_get_rssi_ofdm(_sc, _physt) \ (((_sc)->sc_get_rssi_ofdm)((_sc), (_physt))) #define rtwn_power_on(_sc) \ (((_sc)->sc_power_on)((_sc))) #define rtwn_power_off(_sc) \ (((_sc)->sc_power_off)((_sc))) #ifndef RTWN_WITHOUT_UCODE #define rtwn_fw_reset(_sc, _reason) \ (((_sc)->sc_fw_reset)((_sc), (_reason))) #define rtwn_fw_download_enable(_sc, _enable) \ (((_sc)->sc_fw_download_enable)((_sc), (_enable))) #endif #define rtwn_llt_init(_sc) \ (((_sc)->sc_llt_init)((_sc))) #define rtwn_set_page_size(_sc) \ (((_sc)->sc_set_page_size)((_sc))) #define rtwn_lc_calib(_sc) \ (((_sc)->sc_lc_calib)((_sc))) #define rtwn_iq_calib(_sc) \ (((_sc)->sc_iq_calib)((_sc))) #define rtwn_read_chipid_vendor(_sc, _reg) \ (((_sc)->sc_read_chipid_vendor)((_sc), (_reg))) #define rtwn_adj_devcaps(_sc) \ (((_sc)->sc_adj_devcaps)((_sc))) #define rtwn_vap_preattach(_sc, _vap) \ (((_sc)->sc_vap_preattach)((_sc), (_vap))) #define rtwn_postattach(_sc) \ (((_sc)->sc_postattach)((_sc))) #define rtwn_detach_private(_sc) \ (((_sc)->sc_detach_private)((_sc))) #define rtwn_fill_tx_desc(_sc, _ni, _m, \ - _buf, _ridx, _maxretry) \ + _buf, _ridx, _force, _maxretry) \ (((_sc)->sc_fill_tx_desc)((_sc), (_ni), \ - (_m), (_buf), (_ridx), (_maxretry))) + (_m), (_buf), (_ridx), (_force), (_maxretry))) #define rtwn_fill_tx_desc_raw(_sc, _ni, _m, \ _buf, _params) \ (((_sc)->sc_fill_tx_desc_raw)((_sc), (_ni), \ (_m), (_buf), (_params))) #define rtwn_fill_tx_desc_null(_sc, _buf, _11b, _qos, _id) \ (((_sc)->sc_fill_tx_desc_null)((_sc), \ (_buf), (_11b), (_qos), (_id))) #define rtwn_dump_tx_desc(_sc, _desc) \ (((_sc)->sc_dump_tx_desc)((_sc), (_desc))) #define rtwn_tx_radiotap_flags(_sc, _buf) \ (((_sc)->sc_tx_radiotap_flags)((_buf))) #define rtwn_rx_radiotap_flags(_sc, _buf) \ (((_sc)->sc_rx_radiotap_flags)((_buf))) #define rtwn_set_chan(_sc, _c) \ (((_sc)->sc_set_chan)((_sc), (_c))) #ifndef RTWN_WITHOUT_UCODE #define rtwn_set_rsvd_page(_sc, _resp, _null, _qos_null) \ (((_sc)->sc_set_rsvd_page)((_sc), \ (_resp), (_null), (_qos_null))) #define rtwn_set_pwrmode(_sc, _vap, _off) \ (((_sc)->sc_set_pwrmode)((_sc), (_vap), (_off))) #define rtwn_set_rssi(_sc) \ (((_sc)->sc_set_rssi)((_sc))) #endif #define rtwn_classify_intr(_sc, _buf, _len) \ (((_sc)->sc_classify_intr)((_sc), (_buf), (_len))) #define rtwn_handle_tx_report(_sc, _buf, _len) \ (((_sc)->sc_handle_tx_report)((_sc), (_buf), (_len))) #define rtwn_handle_tx_report2(_sc, _buf, _len) \ (((_sc)->sc_handle_tx_report2)((_sc), (_buf), (_len))) #define rtwn_handle_c2h_report(_sc, _buf, _len) \ (((_sc)->sc_handle_c2h_report)((_sc), (_buf), (_len))) #define rtwn_check_frame(_sc, _m) \ (((_sc)->sc_check_frame)((_sc), (_m))) #define rtwn_beacon_init(_sc, _buf, _id) \ (((_sc)->sc_beacon_init)((_sc), (_buf), (_id))) #define rtwn_beacon_enable(_sc, _id, _enable) \ (((_sc)->sc_beacon_enable)((_sc), (_id), (_enable))) #define rtwn_sta_beacon_enable(_sc, _id, _enable) \ (((_sc)->sc_sta_beacon_enable)((_sc), (_id), (_enable))) #define rtwn_beacon_set_rate(_sc, _buf, _is5ghz) \ (((_sc)->sc_beacon_set_rate)((_buf), (_is5ghz))) #define rtwn_beacon_select(_sc, _id) \ (((_sc)->sc_beacon_select)((_sc), (_id))) #define rtwn_temp_measure(_sc) \ (((_sc)->sc_temp_measure)((_sc))) #define rtwn_temp_read(_sc) \ (((_sc)->sc_temp_read)((_sc))) #define rtwn_init_tx_agg(_sc) \ (((_sc)->sc_init_tx_agg)((_sc))) #define rtwn_init_rx_agg(_sc) \ (((_sc)->sc_init_rx_agg)((_sc))) #define rtwn_init_intr(_sc) \ (((_sc)->sc_init_intr)((_sc))) #define rtwn_init_ampdu(_sc) \ (((_sc)->sc_init_ampdu)((_sc))) #define rtwn_init_edca(_sc) \ (((_sc)->sc_init_edca)((_sc))) #define rtwn_init_bb(_sc) \ (((_sc)->sc_init_bb)((_sc))) #define rtwn_init_rf(_sc) \ (((_sc)->sc_init_rf)((_sc))) #define rtwn_init_antsel(_sc) \ (((_sc)->sc_init_antsel)((_sc))) #define rtwn_post_init(_sc) \ (((_sc)->sc_post_init)((_sc))) #define rtwn_init_bcnq1_boundary(_sc) \ (((_sc)->sc_init_bcnq1_boundary)((_sc))) #define rtwn_set_tx_power(_sc, _vap) \ (((_sc)->sc_set_tx_power)((_sc), (_vap))) /* * Methods to access subfields in registers. */ static __inline int rtwn_setbits_1(struct rtwn_softc *sc, uint16_t addr, uint8_t clr, uint8_t set) { return (rtwn_write_1(sc, addr, (rtwn_read_1(sc, addr) & ~clr) | set)); } static __inline int rtwn_setbits_1_shift(struct rtwn_softc *sc, uint16_t addr, uint32_t clr, uint32_t set, int shift) { return (rtwn_setbits_1(sc, addr + shift, clr >> shift * NBBY, set >> shift * NBBY)); } static __inline int rtwn_setbits_2(struct rtwn_softc *sc, uint16_t addr, uint16_t clr, uint16_t set) { return (rtwn_write_2(sc, addr, (rtwn_read_2(sc, addr) & ~clr) | set)); } static __inline int rtwn_setbits_4(struct rtwn_softc *sc, uint16_t addr, uint32_t clr, uint32_t set) { return (rtwn_write_4(sc, addr, (rtwn_read_4(sc, addr) & ~clr) | set)); } static __inline void rtwn_rf_setbits(struct rtwn_softc *sc, int chain, uint8_t addr, uint32_t clr, uint32_t set) { rtwn_rf_write(sc, chain, addr, (rtwn_rf_read(sc, chain, addr) & ~clr) | set); } #endif /* IF_RTWNVAR_H */ diff --git a/sys/dev/rtwn/rtl8192c/r92c.h b/sys/dev/rtwn/rtl8192c/r92c.h index a7091be66f64..cab7393caf39 100644 --- a/sys/dev/rtwn/rtl8192c/r92c.h +++ b/sys/dev/rtwn/rtl8192c/r92c.h @@ -1,126 +1,126 @@ /*- * Copyright (c) 2010 Damien Bergamini * Copyright (c) 2015-2016 Andriy Voskoboinyk * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $ */ #ifndef RTL8192C_H #define RTL8192C_H #include /* * Global definitions. */ #define R92C_TXPKTBUF_COUNT 256 #define R92C_TX_PAGE_SIZE 128 #define R92C_RX_DMA_BUFFER_SIZE 0x2800 #define R92C_MAX_FW_SIZE 0x4000 #define R92C_MACID_MAX 31 #define R92C_CAM_ENTRY_COUNT 32 #define R92C_CALIB_THRESHOLD 2 /* * Function declarations. */ /* r92c_attach.c */ void r92c_detach_private(struct rtwn_softc *); void r92c_read_chipid_vendor(struct rtwn_softc *, uint32_t); /* r92c_beacon.c */ void r92c_beacon_init(struct rtwn_softc *, void *, int); void r92c_beacon_enable(struct rtwn_softc *, int, int); void r92c_sta_beacon_enable(struct rtwn_softc *, int, bool); /* r92c_calib.c */ void r92c_iq_calib(struct rtwn_softc *); void r92c_lc_calib(struct rtwn_softc *); void r92c_temp_measure(struct rtwn_softc *); uint8_t r92c_temp_read(struct rtwn_softc *); /* r92c_chan.c */ void r92c_dump_txpower(struct rtwn_softc *, int, uint8_t[RTWN_RIDX_COUNT]); void r92c_get_txpower(struct rtwn_softc *, int, struct ieee80211_channel *, uint8_t[RTWN_RIDX_COUNT]); void r92c_write_txpower(struct rtwn_softc *, int, uint8_t power[RTWN_RIDX_COUNT]); int r92c_set_tx_power(struct rtwn_softc *, struct ieee80211vap *); void r92c_set_bw20(struct rtwn_softc *, uint8_t); void r92c_set_chan(struct rtwn_softc *, struct ieee80211_channel *); void r92c_set_gain(struct rtwn_softc *, uint8_t); void r92c_scan_start(struct ieee80211com *); void r92c_scan_end(struct ieee80211com *); /* r92c_fw.c */ #ifndef RTWN_WITHOUT_UCODE void r92c_fw_reset(struct rtwn_softc *, int); void r92c_fw_download_enable(struct rtwn_softc *, int); #endif void r92c_joinbss_rpt(struct rtwn_softc *, int); #ifndef RTWN_WITHOUT_UCODE int r92c_set_rsvd_page(struct rtwn_softc *, int, int, int); int r92c_set_pwrmode(struct rtwn_softc *, struct ieee80211vap *, int); void r92c_set_rssi(struct rtwn_softc *); void r92c_handle_c2h_report(void *); #endif /* r92c_init.c */ int r92c_check_condition(struct rtwn_softc *, const uint8_t[]); int r92c_llt_init(struct rtwn_softc *); int r92c_set_page_size(struct rtwn_softc *); void r92c_init_bb_common(struct rtwn_softc *); int r92c_init_rf_chain(struct rtwn_softc *, const struct rtwn_rf_prog *, int); void r92c_init_rf(struct rtwn_softc *); void r92c_init_edca(struct rtwn_softc *); void r92c_init_ampdu(struct rtwn_softc *); void r92c_init_antsel(struct rtwn_softc *); void r92c_pa_bias_init(struct rtwn_softc *); /* r92c_llt.c */ int r92c_llt_write(struct rtwn_softc *, uint32_t, uint32_t); /* r92c_rf.c */ uint32_t r92c_rf_read(struct rtwn_softc *, int, uint8_t); void r92c_rf_write(struct rtwn_softc *, int, uint8_t, uint32_t); /* r92c_rom.c */ void r92c_efuse_postread(struct rtwn_softc *); void r92c_parse_rom(struct rtwn_softc *, uint8_t *); /* r92c_rx.c */ int r92c_classify_intr(struct rtwn_softc *, void *, int); int8_t r92c_get_rssi_cck(struct rtwn_softc *, void *); int8_t r92c_get_rssi_ofdm(struct rtwn_softc *, void *); uint8_t r92c_rx_radiotap_flags(const void *); void r92c_get_rx_stats(struct rtwn_softc *, struct ieee80211_rx_stats *, const void *, const void *); /* r92c_tx.c */ void r92c_tx_enable_ampdu(void *, int); void r92c_tx_setup_hwseq(void *); void r92c_tx_setup_macid(void *, int); void r92c_fill_tx_desc(struct rtwn_softc *, struct ieee80211_node *, - struct mbuf *, void *, uint8_t, int); + struct mbuf *, void *, uint8_t, bool, int); void r92c_fill_tx_desc_raw(struct rtwn_softc *, struct ieee80211_node *, struct mbuf *, void *, const struct ieee80211_bpf_params *); void r92c_fill_tx_desc_null(struct rtwn_softc *, void *, int, int, int); uint8_t r92c_tx_radiotap_flags(const void *); #endif /* RTL8192C_H */ diff --git a/sys/dev/rtwn/rtl8192c/r92c_tx.c b/sys/dev/rtwn/rtl8192c/r92c_tx.c index 07a6a184e924..d5cbc3ad9db9 100644 --- a/sys/dev/rtwn/rtl8192c/r92c_tx.c +++ b/sys/dev/rtwn/rtl8192c/r92c_tx.c @@ -1,478 +1,478 @@ /* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ /*- * Copyright (c) 2010 Damien Bergamini * Copyright (c) 2014 Kevin Lo * Copyright (c) 2015-2016 Andriy Voskoboinyk * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include "opt_wlan.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static int r92c_tx_get_sco(struct rtwn_softc *sc, struct ieee80211_channel *c) { if (IEEE80211_IS_CHAN_HT40U(c)) return (R92C_TXDW4_SCO_SCA); else return (R92C_TXDW4_SCO_SCB); } static void r92c_tx_set_ht40(struct rtwn_softc *sc, void *buf, struct ieee80211_node *ni) { struct r92c_tx_desc *txd = (struct r92c_tx_desc *)buf; if (ieee80211_ht_check_tx_ht40(ni)) { int extc_offset; extc_offset = r92c_tx_get_sco(sc, ni->ni_chan); txd->txdw4 |= htole32(R92C_TXDW4_DATA_BW40); txd->txdw4 |= htole32(SM(R92C_TXDW4_DATA_SCO, extc_offset)); } } static void r92c_tx_protection(struct rtwn_softc *sc, struct r92c_tx_desc *txd, enum ieee80211_protmode mode, uint8_t ridx) { struct ieee80211com *ic = &sc->sc_ic; uint8_t rate; switch (mode) { case IEEE80211_PROT_CTSONLY: txd->txdw4 |= htole32(R92C_TXDW4_CTS2SELF); break; case IEEE80211_PROT_RTSCTS: txd->txdw4 |= htole32(R92C_TXDW4_RTSEN); break; default: break; } if (mode == IEEE80211_PROT_CTSONLY || mode == IEEE80211_PROT_RTSCTS) { if (RTWN_RATE_IS_HT(ridx)) rate = rtwn_ctl_mcsrate(ic->ic_rt, ridx); else rate = ieee80211_ctl_rate(ic->ic_rt, ridx2rate[ridx]); ridx = rate2ridx(IEEE80211_RV(rate)); txd->txdw4 |= htole32(SM(R92C_TXDW4_RTSRATE, ridx)); /* RTS rate fallback limit (max). */ txd->txdw5 |= htole32(SM(R92C_TXDW5_RTSRATE_FB_LMT, 0xf)); if (RTWN_RATE_IS_CCK(ridx) && ridx != RTWN_RIDX_CCK1 && (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) txd->txdw4 |= htole32(R92C_TXDW4_RTS_SHORT); } } static void r92c_tx_raid(struct rtwn_softc *sc, struct r92c_tx_desc *txd, struct ieee80211_node *ni, int ismcast) { struct ieee80211com *ic = &sc->sc_ic; struct ieee80211vap *vap = ni->ni_vap; struct ieee80211_channel *chan; enum ieee80211_phymode mode; uint8_t raid; chan = (ni->ni_chan != IEEE80211_CHAN_ANYC) ? ni->ni_chan : ic->ic_curchan; mode = ieee80211_chan2mode(chan); /* NB: group addressed frames are done at 11bg rates for now */ if (ismcast || !(ni->ni_flags & IEEE80211_NODE_HT)) { switch (mode) { case IEEE80211_MODE_11B: case IEEE80211_MODE_11G: break; case IEEE80211_MODE_11NG: mode = IEEE80211_MODE_11G; break; default: device_printf(sc->sc_dev, "unknown mode(1) %d!\n", ic->ic_curmode); return; } } switch (mode) { case IEEE80211_MODE_11B: raid = R92C_RAID_11B; break; case IEEE80211_MODE_11G: if (vap->iv_flags & IEEE80211_F_PUREG) raid = R92C_RAID_11G; else raid = R92C_RAID_11BG; break; case IEEE80211_MODE_11NG: if (vap->iv_flags_ht & IEEE80211_FHT_PUREN) raid = R92C_RAID_11N; else raid = R92C_RAID_11BGN; break; default: device_printf(sc->sc_dev, "unknown mode(2) %d!\n", mode); return; } txd->txdw1 |= htole32(SM(R92C_TXDW1_RAID, raid)); } /* XXX move to device-independent layer */ static void r92c_tx_set_sgi(struct rtwn_softc *sc, void *buf, struct ieee80211_node *ni) { struct r92c_tx_desc *txd = (struct r92c_tx_desc *)buf; /* * Only enable short-GI if we're transmitting in that * width to that node. * * Specifically, do not enable shortgi for 20MHz if * we're attempting to transmit at 40MHz. */ if (ieee80211_ht_check_tx_ht40(ni)) { if (ieee80211_ht_check_tx_shortgi_40(ni)) txd->txdw5 |= htole32(R92C_TXDW5_SGI); } else if (ieee80211_ht_check_tx_ht(ni)) { if (ieee80211_ht_check_tx_shortgi_20(ni)) txd->txdw5 |= htole32(R92C_TXDW5_SGI); } } void r92c_tx_enable_ampdu(void *buf, int enable) { struct r92c_tx_desc *txd = (struct r92c_tx_desc *)buf; if (enable) txd->txdw1 |= htole32(R92C_TXDW1_AGGEN); else txd->txdw1 |= htole32(R92C_TXDW1_AGGBK); } void r92c_tx_setup_hwseq(void *buf) { struct r92c_tx_desc *txd = (struct r92c_tx_desc *)buf; txd->txdw4 |= htole32(R92C_TXDW4_HWSEQ_EN); } void r92c_tx_setup_macid(void *buf, int id) { struct r92c_tx_desc *txd = (struct r92c_tx_desc *)buf; txd->txdw1 |= htole32(SM(R92C_TXDW1_MACID, id)); } static int r92c_calculate_tx_agg_window(struct rtwn_softc *sc, const struct ieee80211_node *ni, int tid) { const struct ieee80211_tx_ampdu *tap; int wnd; tap = &ni->ni_tx_ampdu[tid]; /* * BAW is (MAX_AGG * 2) + 1, hence the /2 here. * Ensure we don't send 0 or more than 64. */ wnd = tap->txa_wnd / 2; if (wnd == 0) wnd = 1; else if (wnd > 0x1f) wnd = 0x1f; return (wnd); } /* * Check whether to enable the per-packet TX CCX report. * * For chipsets that do the RPT2 reports, enabling the TX * CCX report results in the packet not being counted in * the RPT2 counts. */ static bool r92c_check_enable_ccx_report(struct rtwn_softc *sc, int macid) { if (sc->sc_ratectl != RTWN_RATECTL_NET80211) return false; #ifndef RTWN_WITHOUT_UCODE if ((sc->macid_rpt2_max_num != 0) && (macid < sc->macid_rpt2_max_num)) return false; #endif return true; } void r92c_fill_tx_desc(struct rtwn_softc *sc, struct ieee80211_node *ni, - struct mbuf *m, void *buf, uint8_t ridx, int maxretry) + struct mbuf *m, void *buf, uint8_t ridx, bool force_rate, int maxretry) { #ifndef RTWN_WITHOUT_UCODE struct r92c_softc *rs = sc->sc_priv; #endif struct ieee80211com *ic = &sc->sc_ic; struct ieee80211vap *vap = ni->ni_vap; struct rtwn_vap *uvp = RTWN_VAP(vap); struct ieee80211_frame *wh; struct r92c_tx_desc *txd; enum ieee80211_protmode prot; uint8_t type, tid, qos, qsel; int hasqos, ismcast, macid; wh = mtod(m, struct ieee80211_frame *); type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; hasqos = IEEE80211_QOS_HAS_SEQ(wh); ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1); /* Select TX ring for this frame. */ if (hasqos) { qos = ((const struct ieee80211_qosframe *)wh)->i_qos[0]; tid = qos & IEEE80211_QOS_TID; } else { qos = 0; tid = 0; } /* Fill Tx descriptor. */ txd = (struct r92c_tx_desc *)buf; txd->flags0 |= R92C_FLAGS0_LSG | R92C_FLAGS0_FSG; if (ismcast) txd->flags0 |= R92C_FLAGS0_BMCAST; if (IEEE80211_IS_QOSDATA(wh)) txd->txdw4 |= htole32(R92C_TXDW4_QOS); if (!ismcast) { struct rtwn_node *un = RTWN_NODE(ni); macid = un->id; /* Unicast frame, check if an ACK is expected. */ if (!qos || (qos & IEEE80211_QOS_ACKPOLICY) != IEEE80211_QOS_ACKPOLICY_NOACK) { txd->txdw5 |= htole32(R92C_TXDW5_RTY_LMT_ENA); txd->txdw5 |= htole32(SM(R92C_TXDW5_RTY_LMT, maxretry)); } if (type == IEEE80211_FC0_TYPE_DATA) { qsel = tid % RTWN_MAX_TID; rtwn_r92c_tx_enable_ampdu(sc, buf, (m->m_flags & M_AMPDU_MPDU) != 0); if (m->m_flags & M_AMPDU_MPDU) { txd->txdw2 |= htole32(SM(R92C_TXDW2_AMPDU_DEN, ieee80211_ht_get_node_ampdu_density(ni))); txd->txdw6 |= htole32(SM(R92C_TXDW6_MAX_AGG, r92c_calculate_tx_agg_window(sc, ni, tid))); } if (r92c_check_enable_ccx_report(sc, macid)) { txd->txdw2 |= htole32(R92C_TXDW2_CCX_RPT); sc->sc_tx_n_active++; #ifndef RTWN_WITHOUT_UCODE rs->rs_c2h_pending++; #endif } if (RTWN_RATE_IS_CCK(ridx) && ridx != RTWN_RIDX_CCK1 && (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) txd->txdw4 |= htole32(R92C_TXDW4_DATA_SHPRE); prot = IEEE80211_PROT_NONE; if (RTWN_RATE_IS_HT(ridx)) { r92c_tx_set_ht40(sc, txd, ni); r92c_tx_set_sgi(sc, txd, ni); prot = ic->ic_htprotmode; } else if (ic->ic_flags & IEEE80211_F_USEPROT) prot = ic->ic_protmode; /* XXX fix last comparison for A-MSDU (in net80211) */ /* XXX A-MPDU? */ if (m->m_pkthdr.len + IEEE80211_CRC_LEN > vap->iv_rtsthreshold && vap->iv_rtsthreshold != IEEE80211_RTS_MAX) prot = IEEE80211_PROT_RTSCTS; /* NB: checks for ht40 / short bits (set above). */ if (prot != IEEE80211_PROT_NONE) r92c_tx_protection(sc, txd, prot, ridx); } else /* IEEE80211_FC0_TYPE_MGT */ qsel = R92C_TXDW1_QSEL_MGNT; } else { macid = RTWN_MACID_BC; qsel = R92C_TXDW1_QSEL_MGNT; } txd->txdw1 |= htole32(SM(R92C_TXDW1_QSEL, qsel)); rtwn_r92c_tx_setup_macid(sc, txd, macid); txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE, ridx)); /* Data rate fallback limit (max). */ txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE_FB_LMT, 0x1f)); txd->txdw4 |= htole32(SM(R92C_TXDW4_PORT_ID, uvp->id)); r92c_tx_raid(sc, txd, ni, ismcast); /* Force this rate if needed. */ if (sc->sc_ratectl != RTWN_RATECTL_FW) txd->txdw4 |= htole32(R92C_TXDW4_DRVRATE); if (!hasqos) { /* Use HW sequence numbering for non-QoS frames. */ rtwn_r92c_tx_setup_hwseq(sc, txd); } else { uint16_t seqno; if (m->m_flags & M_AMPDU_MPDU) { seqno = ni->ni_txseqs[tid] % IEEE80211_SEQ_RANGE; ni->ni_txseqs[tid]++; } else seqno = M_SEQNO_GET(m) % IEEE80211_SEQ_RANGE; /* Set sequence number. */ txd->txdseq = htole16(seqno); } } 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) { struct ieee80211vap *vap = ni->ni_vap; struct rtwn_vap *uvp = RTWN_VAP(vap); struct ieee80211_frame *wh; struct r92c_tx_desc *txd; uint8_t ridx; int ismcast; /* XXX TODO: 11n checks, matching r92c_fill_tx_desc() */ wh = mtod(m, struct ieee80211_frame *); ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1); ridx = rate2ridx(params->ibp_rate0); /* Fill Tx descriptor. */ txd = (struct r92c_tx_desc *)buf; txd->flags0 |= R92C_FLAGS0_LSG | R92C_FLAGS0_FSG; if (ismcast) txd->flags0 |= R92C_FLAGS0_BMCAST; if ((params->ibp_flags & IEEE80211_BPF_NOACK) == 0) { txd->txdw5 |= htole32(R92C_TXDW5_RTY_LMT_ENA); txd->txdw5 |= htole32(SM(R92C_TXDW5_RTY_LMT, params->ibp_try0)); } if (params->ibp_flags & IEEE80211_BPF_RTS) r92c_tx_protection(sc, txd, IEEE80211_PROT_RTSCTS, ridx); if (params->ibp_flags & IEEE80211_BPF_CTS) r92c_tx_protection(sc, txd, IEEE80211_PROT_CTSONLY, ridx); rtwn_r92c_tx_setup_macid(sc, txd, RTWN_MACID_BC); txd->txdw1 |= htole32(SM(R92C_TXDW1_QSEL, R92C_TXDW1_QSEL_MGNT)); /* Set TX rate index. */ txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE, ridx)); txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE_FB_LMT, 0x1f)); txd->txdw4 |= htole32(SM(R92C_TXDW4_PORT_ID, uvp->id)); txd->txdw4 |= htole32(R92C_TXDW4_DRVRATE); r92c_tx_raid(sc, txd, ni, ismcast); if (!IEEE80211_QOS_HAS_SEQ(wh)) { /* Use HW sequence numbering for non-QoS frames. */ rtwn_r92c_tx_setup_hwseq(sc, txd); } else { /* Set sequence number. */ txd->txdseq |= htole16(M_SEQNO_GET(m) % IEEE80211_SEQ_RANGE); } } void r92c_fill_tx_desc_null(struct rtwn_softc *sc, void *buf, int is11b, int qos, int id) { struct r92c_tx_desc *txd = (struct r92c_tx_desc *)buf; txd->flags0 = R92C_FLAGS0_FSG | R92C_FLAGS0_LSG | R92C_FLAGS0_OWN; txd->txdw1 = htole32( SM(R92C_TXDW1_QSEL, R92C_TXDW1_QSEL_MGNT)); txd->txdw4 = htole32(R92C_TXDW4_DRVRATE); txd->txdw4 |= htole32(SM(R92C_TXDW4_PORT_ID, id)); if (is11b) { txd->txdw5 = htole32(SM(R92C_TXDW5_DATARATE, RTWN_RIDX_CCK1)); } else { txd->txdw5 = htole32(SM(R92C_TXDW5_DATARATE, RTWN_RIDX_OFDM6)); } if (!qos) { rtwn_r92c_tx_setup_hwseq(sc, txd); } } uint8_t r92c_tx_radiotap_flags(const void *buf) { const struct r92c_tx_desc *txd = buf; uint8_t flags; flags = 0; if (txd->txdw4 & htole32(R92C_TXDW4_DATA_SHPRE)) flags |= IEEE80211_RADIOTAP_F_SHORTPRE; if (txd->txdw5 & htole32(R92C_TXDW5_SGI)) flags |= IEEE80211_RADIOTAP_F_SHORTGI; return (flags); } diff --git a/sys/dev/rtwn/rtl8812a/r12a.h b/sys/dev/rtwn/rtl8812a/r12a.h index 8bf1464b9525..e5c5c7cd6a80 100644 --- a/sys/dev/rtwn/rtl8812a/r12a.h +++ b/sys/dev/rtwn/rtl8812a/r12a.h @@ -1,140 +1,140 @@ /*- * Copyright (c) 2016 Andriy Voskoboinyk * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef RTL8812A_H #define RTL8812A_H /* * Global definitions. */ #define R12A_PUBQ_NPAGES 219 #define R12A_TXPKTBUF_COUNT 255 #define R12A_TX_PAGE_COUNT 248 #define R12A_TX_PAGE_SIZE 512 #define R12A_RX_DMA_BUFFER_SIZE 0x3e80 #define R12A_MAX_FW_SIZE 0x8000 #define R12A_MACID_MAX 127 #define R12A_CAM_ENTRY_COUNT 64 #define R12A_INTR_MSG_LEN 60 static const uint8_t r12a_chan_5ghz_0[] = { 36, 40, 44, 48, 52, 56, 60, 64 }; static const uint8_t r12a_chan_5ghz_1[] = { 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144 }; static const uint8_t r12a_chan_5ghz_2[] = { 149, 153, 157, 161, 165, 169, 173, 177 }; /* * Function declarations. */ /* r12a_attach.c */ void r12a_vap_preattach(struct rtwn_softc *, struct ieee80211vap *); void r12a_detach_private(struct rtwn_softc *); /* r12a_beacon.c */ void r12a_beacon_init(struct rtwn_softc *, void *, int); void r12a_beacon_set_rate(void *, int); void r12a_sta_beacon_enable(struct rtwn_softc *, int, bool); /* r12a_calib.c */ void r12a_save_bb_afe_vals(struct rtwn_softc *, uint32_t[], const uint16_t[], int); void r12a_restore_bb_afe_vals(struct rtwn_softc *, uint32_t[], const uint16_t[], int); void r12a_save_rf_vals(struct rtwn_softc *, uint32_t[], const uint8_t[], int); void r12a_restore_rf_vals(struct rtwn_softc *, uint32_t[], const uint8_t[], int); void r12a_lc_calib(struct rtwn_softc *); #ifndef RTWN_WITHOUT_UCODE int r12a_iq_calib_fw_supported(struct rtwn_softc *); #endif void r12a_iq_calib_sw(struct rtwn_softc *); void r12a_iq_calib(struct rtwn_softc *); /* r12a_caps.c */ int r12a_ioctl_net(struct ieee80211com *, u_long, void *); /* r12a_chan.c */ void r12a_fix_spur(struct rtwn_softc *, struct ieee80211_channel *); void r12a_set_chan(struct rtwn_softc *, struct ieee80211_channel *); void r12a_set_band_2ghz(struct rtwn_softc *, uint32_t); void r12a_set_band_5ghz(struct rtwn_softc *, uint32_t); /* r12a_fw.c */ #ifndef RTWN_WITHOUT_UCODE void r12a_fw_reset(struct rtwn_softc *, int); void r12a_fw_download_enable(struct rtwn_softc *, int); void r12a_set_media_status(struct rtwn_softc *, int); int r12a_set_pwrmode(struct rtwn_softc *, struct ieee80211vap *, int); void r12a_iq_calib_fw(struct rtwn_softc *); #endif /* r12a_init.c */ int r12a_check_condition(struct rtwn_softc *, const uint8_t[]); int r12a_set_page_size(struct rtwn_softc *); void r12a_init_edca(struct rtwn_softc *); void r12a_init_bb(struct rtwn_softc *); void r12a_init_rf(struct rtwn_softc *); void r12a_crystalcap_write(struct rtwn_softc *); int r12a_power_on(struct rtwn_softc *); void r12a_power_off(struct rtwn_softc *); void r12a_init_intr(struct rtwn_softc *); void r12a_init_antsel(struct rtwn_softc *); /* r12a_led.c */ void r12a_set_led(struct rtwn_softc *, int, int); /* r12a_rf.c */ uint32_t r12a_rf_read(struct rtwn_softc *, int, uint8_t); uint32_t r12a_c_cut_rf_read(struct rtwn_softc *, int, uint8_t); void r12a_rf_write(struct rtwn_softc *, int, uint8_t, uint32_t); /* r12a_rom.c */ void r12a_parse_rom_common(struct rtwn_softc *, uint8_t *); void r12a_parse_rom(struct rtwn_softc *, uint8_t *); /* r12a_rx.c */ void r12a_ratectl_tx_complete(struct rtwn_softc *, uint8_t *, int); void r12a_handle_c2h_report(struct rtwn_softc *, uint8_t *, int); int r12a_check_frame_checksum(struct rtwn_softc *, struct mbuf *); uint8_t r12a_rx_radiotap_flags(const void *); void r12a_get_rx_stats(struct rtwn_softc *, struct ieee80211_rx_stats *, const void *, const void *); /* r12a_tx.c */ void r12a_fill_tx_desc(struct rtwn_softc *, struct ieee80211_node *, - struct mbuf *, void *, uint8_t, int); + struct mbuf *, void *, uint8_t, bool, int); void r12a_fill_tx_desc_raw(struct rtwn_softc *, struct ieee80211_node *, struct mbuf *, void *, const struct ieee80211_bpf_params *); void r12a_fill_tx_desc_null(struct rtwn_softc *, void *, int, int, int); uint8_t r12a_tx_radiotap_flags(const void *); #endif /* RTL8812A_H */ diff --git a/sys/dev/rtwn/rtl8812a/r12a_tx.c b/sys/dev/rtwn/rtl8812a/r12a_tx.c index 822416a09618..cc686668e4a2 100644 --- a/sys/dev/rtwn/rtl8812a/r12a_tx.c +++ b/sys/dev/rtwn/rtl8812a/r12a_tx.c @@ -1,480 +1,480 @@ /*- * Copyright (c) 2016 Andriy Voskoboinyk * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include "opt_wlan.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static int r12a_get_primary_channel(struct rtwn_softc *sc, struct ieee80211_channel *c) { /* XXX VHT80; VHT40 */ if (IEEE80211_IS_CHAN_HT40U(c)) return (R12A_TXDW5_PRIM_CHAN_20_80_2); else return (R12A_TXDW5_PRIM_CHAN_20_80_3); } static void r12a_tx_set_ht40(struct rtwn_softc *sc, void *buf, struct ieee80211_node *ni) { struct r12a_tx_desc *txd = (struct r12a_tx_desc *)buf; /* XXX VHT80; VHT40; VHT20 */ if (ieee80211_ht_check_tx_ht40(ni)) { int prim_chan; prim_chan = r12a_get_primary_channel(sc, ni->ni_chan); txd->txdw5 |= htole32(SM(R12A_TXDW5_DATA_BW, R12A_TXDW5_DATA_BW40)); txd->txdw5 |= htole32(SM(R12A_TXDW5_DATA_PRIM_CHAN, prim_chan)); } } static void r12a_tx_protection(struct rtwn_softc *sc, struct r12a_tx_desc *txd, enum ieee80211_protmode mode, uint8_t ridx) { struct ieee80211com *ic = &sc->sc_ic; uint8_t rate; switch (mode) { case IEEE80211_PROT_CTSONLY: txd->txdw3 |= htole32(R12A_TXDW3_CTS2SELF); break; case IEEE80211_PROT_RTSCTS: txd->txdw3 |= htole32(R12A_TXDW3_RTSEN); break; default: break; } if (mode == IEEE80211_PROT_CTSONLY || mode == IEEE80211_PROT_RTSCTS) { /* TODO: VHT */ if (RTWN_RATE_IS_HT(ridx)) rate = rtwn_ctl_mcsrate(ic->ic_rt, ridx); else rate = ieee80211_ctl_rate(ic->ic_rt, ridx2rate[ridx]); ridx = rate2ridx(IEEE80211_RV(rate)); txd->txdw4 |= htole32(SM(R12A_TXDW4_RTSRATE, ridx)); /* RTS rate fallback limit (max). */ txd->txdw4 |= htole32(SM(R12A_TXDW4_RTSRATE_FB_LMT, 0xf)); if (RTWN_RATE_IS_CCK(ridx) && ridx != RTWN_RIDX_CCK1 && (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) txd->txdw5 |= htole32(R12A_TXDW5_RTS_SHORT); } } static void r12a_tx_raid(struct rtwn_softc *sc, struct r12a_tx_desc *txd, struct ieee80211_node *ni, int ismcast) { struct ieee80211com *ic = &sc->sc_ic; struct ieee80211vap *vap = ni->ni_vap; struct ieee80211_channel *chan; enum ieee80211_phymode mode; uint8_t raid; chan = (ni->ni_chan != IEEE80211_CHAN_ANYC) ? ni->ni_chan : ic->ic_curchan; mode = ieee80211_chan2mode(chan); /* NB: group addressed frames are done at 11bg rates for now */ if (ismcast || !(ni->ni_flags & IEEE80211_NODE_HT)) { switch (mode) { case IEEE80211_MODE_11A: case IEEE80211_MODE_11B: case IEEE80211_MODE_11G: break; case IEEE80211_MODE_11NA: mode = IEEE80211_MODE_11A; break; case IEEE80211_MODE_11NG: mode = IEEE80211_MODE_11G; break; case IEEE80211_MODE_VHT_5GHZ: mode = IEEE80211_MODE_VHT_5GHZ; break; default: device_printf(sc->sc_dev, "unknown mode(1) %d!\n", ic->ic_curmode); return; } } switch (mode) { case IEEE80211_MODE_11A: raid = R12A_RAID_11G; break; case IEEE80211_MODE_11B: raid = R12A_RAID_11B; break; case IEEE80211_MODE_11G: if (vap->iv_flags & IEEE80211_F_PUREG) raid = R12A_RAID_11G; else raid = R12A_RAID_11BG; break; case IEEE80211_MODE_11NA: if (sc->ntxchains == 1) raid = R12A_RAID_11GN_1; else raid = R12A_RAID_11GN_2; break; case IEEE80211_MODE_11NG: if (sc->ntxchains == 1) { if (IEEE80211_IS_CHAN_HT40(chan)) raid = R12A_RAID_11BGN_1_40; else raid = R12A_RAID_11BGN_1; } else { if (IEEE80211_IS_CHAN_HT40(chan)) raid = R12A_RAID_11BGN_2_40; else raid = R12A_RAID_11BGN_2; } break; case IEEE80211_MODE_VHT_5GHZ: if (sc->ntxchains == 1) raid = R12A_RAID_11AC_1; else raid = R12A_RAID_11AC_2; break; default: device_printf(sc->sc_dev, "unknown mode(2) %d!\n", mode); return; } txd->txdw1 |= htole32(SM(R12A_TXDW1_RAID, raid)); } static void r12a_tx_set_sgi(struct rtwn_softc *sc, void *buf, struct ieee80211_node *ni) { struct r12a_tx_desc *txd = (struct r12a_tx_desc *)buf; /* TODO: VHT 20/40/80 checks */ /* * Only enable short-GI if we're transmitting in that * width to that node. * * Specifically, do not enable shortgi for 20MHz if * we're attempting to transmit at 40MHz. */ if (ieee80211_ht_check_tx_ht40(ni)) { if (ieee80211_ht_check_tx_shortgi_40(ni)) txd->txdw5 |= htole32(R12A_TXDW5_DATA_SHORT); } else if (ieee80211_ht_check_tx_ht(ni)) { if (ieee80211_ht_check_tx_shortgi_20(ni)) txd->txdw5 |= htole32(R12A_TXDW5_DATA_SHORT); } } static void r12a_tx_set_ldpc(struct rtwn_softc *sc, struct r12a_tx_desc *txd, struct ieee80211_node *ni) { struct ieee80211vap *vap = ni->ni_vap; if ((vap->iv_flags_ht & IEEE80211_FHT_LDPC_TX) && (ni->ni_htcap & IEEE80211_HTCAP_LDPC)) txd->txdw5 |= htole32(R12A_TXDW5_DATA_LDPC); } static int r12a_calculate_tx_agg_window(struct rtwn_softc *sc, const struct ieee80211_node *ni, int tid) { const struct ieee80211_tx_ampdu *tap; int wnd; tap = &ni->ni_tx_ampdu[tid]; /* * BAW is (MAX_AGG * 2) + 1, hence the /2 here. * Ensure we don't send 0 or more than 64. */ wnd = tap->txa_wnd / 2; if (wnd == 0) wnd = 1; else if (wnd > 0x1f) wnd = 0x1f; return (wnd); } void r12a_fill_tx_desc(struct rtwn_softc *sc, struct ieee80211_node *ni, - struct mbuf *m, void *buf, uint8_t ridx, int maxretry) + struct mbuf *m, void *buf, uint8_t ridx, bool force_rate, int maxretry) { struct ieee80211com *ic = &sc->sc_ic; struct ieee80211vap *vap = ni->ni_vap; struct rtwn_vap *uvp = RTWN_VAP(vap); struct ieee80211_frame *wh; struct r12a_tx_desc *txd; enum ieee80211_protmode prot; uint8_t type, tid, qos, qsel; int hasqos, ismcast, macid; wh = mtod(m, struct ieee80211_frame *); type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; hasqos = IEEE80211_QOS_HAS_SEQ(wh); ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1); /* Select TX ring for this frame. */ if (hasqos) { qos = ((const struct ieee80211_qosframe *)wh)->i_qos[0]; tid = qos & IEEE80211_QOS_TID; } else { qos = 0; tid = 0; } /* Fill Tx descriptor. */ txd = (struct r12a_tx_desc *)buf; txd->flags0 |= R12A_FLAGS0_LSG | R12A_FLAGS0_FSG; if (ismcast) txd->flags0 |= R12A_FLAGS0_BMCAST; if (!ismcast) { /* Unicast frame, check if an ACK is expected. */ if (!qos || (qos & IEEE80211_QOS_ACKPOLICY) != IEEE80211_QOS_ACKPOLICY_NOACK) { txd->txdw4 = htole32(R12A_TXDW4_RETRY_LMT_ENA); txd->txdw4 |= htole32(SM(R12A_TXDW4_RETRY_LMT, maxretry)); } struct rtwn_node *un = RTWN_NODE(ni); macid = un->id; if (type == IEEE80211_FC0_TYPE_DATA) { qsel = tid % RTWN_MAX_TID; if (m->m_flags & M_AMPDU_MPDU) { txd->txdw2 |= htole32(R12A_TXDW2_AGGEN); txd->txdw2 |= htole32(SM(R12A_TXDW2_AMPDU_DEN, ieee80211_ht_get_node_ampdu_density(ni))); txd->txdw3 |= htole32(SM(R12A_TXDW3_MAX_AGG, r12a_calculate_tx_agg_window(sc, ni, tid))); } else txd->txdw2 |= htole32(R12A_TXDW2_AGGBK); if (sc->sc_ratectl == RTWN_RATECTL_NET80211) { txd->txdw2 |= htole32(R12A_TXDW2_SPE_RPT); sc->sc_tx_n_active++; } if (RTWN_RATE_IS_CCK(ridx) && ridx != RTWN_RIDX_CCK1 && (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) txd->txdw5 |= htole32(R12A_TXDW5_DATA_SHORT); prot = IEEE80211_PROT_NONE; /* TODO: VHT */ if (RTWN_RATE_IS_HT(ridx)) { r12a_tx_set_ht40(sc, txd, ni); r12a_tx_set_sgi(sc, txd, ni); r12a_tx_set_ldpc(sc, txd, ni); prot = ic->ic_htprotmode; } else if (ic->ic_flags & IEEE80211_F_USEPROT) prot = ic->ic_protmode; /* XXX fix last comparison for A-MSDU (in net80211) */ /* XXX A-MPDU? */ if (m->m_pkthdr.len + IEEE80211_CRC_LEN > vap->iv_rtsthreshold && vap->iv_rtsthreshold != IEEE80211_RTS_MAX) prot = IEEE80211_PROT_RTSCTS; if (prot != IEEE80211_PROT_NONE) r12a_tx_protection(sc, txd, prot, ridx); } else /* IEEE80211_FC0_TYPE_MGT */ qsel = R12A_TXDW1_QSEL_MGNT; } else { macid = RTWN_MACID_BC; qsel = R12A_TXDW1_QSEL_MGNT; } txd->txdw1 |= htole32(SM(R12A_TXDW1_QSEL, qsel)); txd->txdw1 |= htole32(SM(R12A_TXDW1_MACID, macid)); txd->txdw4 |= htole32(SM(R12A_TXDW4_DATARATE, ridx)); /* Data rate fallback limit (max). */ txd->txdw4 |= htole32(SM(R12A_TXDW4_DATARATE_FB_LMT, 0x1f)); /* XXX recheck for non-21au */ txd->txdw6 |= htole32(SM(R21A_TXDW6_MBSSID, uvp->id)); r12a_tx_raid(sc, txd, ni, ismcast); /* Force this rate if needed. */ if (sc->sc_ratectl != RTWN_RATECTL_FW) txd->txdw3 |= htole32(R12A_TXDW3_DRVRATE); if (!hasqos) { /* Use HW sequence numbering for non-QoS frames. */ txd->txdw8 |= htole32(R12A_TXDW8_HWSEQ_EN); txd->txdw3 |= htole32(SM(R12A_TXDW3_SEQ_SEL, uvp->id)); } else { uint16_t seqno; if (m->m_flags & M_AMPDU_MPDU) { seqno = ni->ni_txseqs[tid]; ni->ni_txseqs[tid]++; } else seqno = M_SEQNO_GET(m) % IEEE80211_SEQ_RANGE; /* Set sequence number. */ txd->txdw9 |= htole32(SM(R12A_TXDW9_SEQ, seqno)); } } void r12a_fill_tx_desc_raw(struct rtwn_softc *sc, struct ieee80211_node *ni, struct mbuf *m, void *buf, const struct ieee80211_bpf_params *params) { struct ieee80211vap *vap = ni->ni_vap; struct rtwn_vap *uvp = RTWN_VAP(vap); struct ieee80211_frame *wh; struct r12a_tx_desc *txd; uint8_t ridx; int ismcast; /* XXX TODO: 11n checks, matching rtwn_fill_tx_desc() */ wh = mtod(m, struct ieee80211_frame *); ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1); ridx = rate2ridx(params->ibp_rate0); /* Fill Tx descriptor. */ txd = (struct r12a_tx_desc *)buf; txd->flags0 |= R12A_FLAGS0_LSG | R12A_FLAGS0_FSG; if (ismcast) txd->flags0 |= R12A_FLAGS0_BMCAST; if ((params->ibp_flags & IEEE80211_BPF_NOACK) == 0) { txd->txdw4 = htole32(R12A_TXDW4_RETRY_LMT_ENA); txd->txdw4 |= htole32(SM(R12A_TXDW4_RETRY_LMT, params->ibp_try0)); } if (params->ibp_flags & IEEE80211_BPF_RTS) r12a_tx_protection(sc, txd, IEEE80211_PROT_RTSCTS, ridx); if (params->ibp_flags & IEEE80211_BPF_CTS) r12a_tx_protection(sc, txd, IEEE80211_PROT_CTSONLY, ridx); txd->txdw1 |= htole32(SM(R12A_TXDW1_MACID, RTWN_MACID_BC)); txd->txdw1 |= htole32(SM(R12A_TXDW1_QSEL, R12A_TXDW1_QSEL_MGNT)); /* Set TX rate index. */ txd->txdw4 |= htole32(SM(R12A_TXDW4_DATARATE, ridx)); txd->txdw4 |= htole32(SM(R12A_TXDW4_DATARATE_FB_LMT, 0x1f)); txd->txdw6 |= htole32(SM(R21A_TXDW6_MBSSID, uvp->id)); txd->txdw3 |= htole32(R12A_TXDW3_DRVRATE); r12a_tx_raid(sc, txd, ni, ismcast); if (!IEEE80211_QOS_HAS_SEQ(wh)) { /* Use HW sequence numbering for non-QoS frames. */ txd->txdw8 |= htole32(R12A_TXDW8_HWSEQ_EN); txd->txdw3 |= htole32(SM(R12A_TXDW3_SEQ_SEL, uvp->id)); } else { /* Set sequence number. */ txd->txdw9 |= htole32(SM(R12A_TXDW9_SEQ, M_SEQNO_GET(m) % IEEE80211_SEQ_RANGE)); } } void r12a_fill_tx_desc_null(struct rtwn_softc *sc, void *buf, int is11b, int qos, int id) { struct r12a_tx_desc *txd = (struct r12a_tx_desc *)buf; txd->flags0 = R12A_FLAGS0_FSG | R12A_FLAGS0_LSG | R12A_FLAGS0_OWN; txd->txdw1 = htole32( SM(R12A_TXDW1_QSEL, R12A_TXDW1_QSEL_MGNT)); txd->txdw3 = htole32(R12A_TXDW3_DRVRATE); txd->txdw6 = htole32(SM(R21A_TXDW6_MBSSID, id)); if (is11b) { txd->txdw4 = htole32(SM(R12A_TXDW4_DATARATE, RTWN_RIDX_CCK1)); } else { txd->txdw4 = htole32(SM(R12A_TXDW4_DATARATE, RTWN_RIDX_OFDM6)); } if (!qos) { txd->txdw8 = htole32(R12A_TXDW8_HWSEQ_EN); txd->txdw3 |= htole32(SM(R12A_TXDW3_SEQ_SEL, id)); } } uint8_t r12a_tx_radiotap_flags(const void *buf) { const struct r12a_tx_desc *txd = buf; uint8_t flags, rate; if (!(txd->txdw5 & htole32(R12A_TXDW5_DATA_SHORT))) return (0); rate = MS(le32toh(txd->txdw4), R12A_TXDW4_DATARATE); if (RTWN_RATE_IS_CCK(rate)) flags = IEEE80211_RADIOTAP_F_SHORTPRE; else flags = IEEE80211_RADIOTAP_F_SHORTGI; return (flags); }