diff --git a/sys/dev/rtwn/if_rtwnvar.h b/sys/dev/rtwn/if_rtwnvar.h index 6a44b7b73902..f4c6d7ee64b4 100644 --- a/sys/dev/rtwn/if_rtwnvar.h +++ b/sys/dev/rtwn/if_rtwnvar.h @@ -1,633 +1,633 @@ /*- * 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 5000 /* ms */ +#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, 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; #if 1 int sc_ht40; #endif uint32_t sc_debug; int sc_hwcrypto; int sc_ratectl_sysctl; int sc_ratectl; 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 (*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_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_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 *); 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 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) \ (((_sc)->sc_fill_tx_desc)((_sc), (_ni), \ (_m), (_buf), (_ridx), (_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_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_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))) /* * 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/usb/rtwn_usb_attach.c b/sys/dev/rtwn/usb/rtwn_usb_attach.c index 71798ffc14f9..4958939a768a 100644 --- a/sys/dev/rtwn/usb/rtwn_usb_attach.c +++ b/sys/dev/rtwn/usb/rtwn_usb_attach.c @@ -1,485 +1,493 @@ /* $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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "usbdevs.h" #include #include #include #include #include #include #include #include static device_probe_t rtwn_usb_match; static device_attach_t rtwn_usb_attach; static device_detach_t rtwn_usb_detach; static device_suspend_t rtwn_usb_suspend; static device_resume_t rtwn_usb_resume; static int rtwn_usb_alloc_list(struct rtwn_softc *, struct rtwn_data[], int, int); static int rtwn_usb_alloc_rx_list(struct rtwn_softc *); static int rtwn_usb_alloc_tx_list(struct rtwn_softc *); static void rtwn_usb_free_list(struct rtwn_softc *, struct rtwn_data data[], int); static void rtwn_usb_free_rx_list(struct rtwn_softc *); static void rtwn_usb_free_tx_list(struct rtwn_softc *); static void rtwn_usb_reset_lists(struct rtwn_softc *, struct ieee80211vap *); static void rtwn_usb_reset_tx_list(struct rtwn_usb_softc *, rtwn_datahead *, struct ieee80211vap *); static void rtwn_usb_reset_rx_list(struct rtwn_usb_softc *); static void rtwn_usb_start_xfers(struct rtwn_softc *); static void rtwn_usb_abort_xfers(struct rtwn_softc *); static int rtwn_usb_fw_write_block(struct rtwn_softc *, const uint8_t *, uint16_t, int); static void rtwn_usb_drop_incorrect_tx(struct rtwn_softc *); static void rtwn_usb_attach_methods(struct rtwn_softc *); static void rtwn_usb_sysctlattach(struct rtwn_softc *); #define RTWN_CONFIG_INDEX 0 static int rtwn_usb_match(device_t self) { struct usb_attach_arg *uaa = device_get_ivars(self); if (uaa->usb_mode != USB_MODE_HOST) return (ENXIO); if (uaa->info.bConfigIndex != RTWN_CONFIG_INDEX) return (ENXIO); if (uaa->info.bIfaceIndex != RTWN_IFACE_INDEX) return (ENXIO); return (usbd_lookup_id_by_uaa(rtwn_devs, sizeof(rtwn_devs), uaa)); } static int rtwn_usb_alloc_list(struct rtwn_softc *sc, struct rtwn_data data[], int ndata, int maxsz) { int i, error; for (i = 0; i < ndata; i++) { struct rtwn_data *dp = &data[i]; dp->m = NULL; dp->buf = malloc(maxsz, M_USBDEV, M_NOWAIT); if (dp->buf == NULL) { device_printf(sc->sc_dev, "could not allocate buffer\n"); error = ENOMEM; goto fail; } dp->ni = NULL; } return (0); fail: rtwn_usb_free_list(sc, data, ndata); return (error); } static int rtwn_usb_alloc_rx_list(struct rtwn_softc *sc) { struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); int error, i; error = rtwn_usb_alloc_list(sc, uc->uc_rx, RTWN_USB_RX_LIST_COUNT, uc->uc_rx_buf_size * RTWN_USB_RXBUFSZ_UNIT); if (error != 0) return (error); STAILQ_INIT(&uc->uc_rx_active); STAILQ_INIT(&uc->uc_rx_inactive); for (i = 0; i < RTWN_USB_RX_LIST_COUNT; i++) STAILQ_INSERT_HEAD(&uc->uc_rx_inactive, &uc->uc_rx[i], next); return (0); } static int rtwn_usb_alloc_tx_list(struct rtwn_softc *sc) { struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); int error, i; error = rtwn_usb_alloc_list(sc, uc->uc_tx, RTWN_USB_TX_LIST_COUNT, RTWN_USB_TXBUFSZ); if (error != 0) return (error); - STAILQ_INIT(&uc->uc_tx_active); - STAILQ_INIT(&uc->uc_tx_inactive); - STAILQ_INIT(&uc->uc_tx_pending); + for (i = RTWN_BULK_TX_FIRST; i < RTWN_BULK_EP_COUNT; i++) { + STAILQ_INIT(&uc->uc_tx_active[i]); + STAILQ_INIT(&uc->uc_tx_pending[i]); + } + STAILQ_INIT(&uc->uc_tx_inactive); for (i = 0; i < RTWN_USB_TX_LIST_COUNT; i++) STAILQ_INSERT_HEAD(&uc->uc_tx_inactive, &uc->uc_tx[i], next); return (0); } static void rtwn_usb_free_list(struct rtwn_softc *sc, struct rtwn_data data[], int ndata) { int i; for (i = 0; i < ndata; i++) { struct rtwn_data *dp = &data[i]; if (dp->buf != NULL) { free(dp->buf, M_USBDEV); dp->buf = NULL; } if (dp->ni != NULL) { ieee80211_free_node(dp->ni); dp->ni = NULL; } if (dp->m != NULL) { m_freem(dp->m); dp->m = NULL; } } } static void rtwn_usb_free_rx_list(struct rtwn_softc *sc) { struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); rtwn_usb_free_list(sc, uc->uc_rx, RTWN_USB_RX_LIST_COUNT); uc->uc_rx_stat_len = 0; uc->uc_rx_off = 0; STAILQ_INIT(&uc->uc_rx_active); STAILQ_INIT(&uc->uc_rx_inactive); } static void rtwn_usb_free_tx_list(struct rtwn_softc *sc) { struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); + int i; rtwn_usb_free_list(sc, uc->uc_tx, RTWN_USB_TX_LIST_COUNT); - STAILQ_INIT(&uc->uc_tx_active); + for (i = RTWN_BULK_TX_FIRST; i < RTWN_BULK_EP_COUNT; i++) { + STAILQ_INIT(&uc->uc_tx_active[i]); + STAILQ_INIT(&uc->uc_tx_pending[i]); + } STAILQ_INIT(&uc->uc_tx_inactive); - STAILQ_INIT(&uc->uc_tx_pending); } static void rtwn_usb_reset_lists(struct rtwn_softc *sc, struct ieee80211vap *vap) { struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); + int i; RTWN_ASSERT_LOCKED(sc); - rtwn_usb_reset_tx_list(uc, &uc->uc_tx_active, vap); - rtwn_usb_reset_tx_list(uc, &uc->uc_tx_pending, vap); + for (i = RTWN_BULK_TX_FIRST; i < RTWN_BULK_EP_COUNT; i++) { + rtwn_usb_reset_tx_list(uc, &uc->uc_tx_active[i], vap); + rtwn_usb_reset_tx_list(uc, &uc->uc_tx_pending[i], vap); + } if (vap == NULL) { rtwn_usb_reset_rx_list(uc); sc->qfullmsk = 0; } } static void rtwn_usb_reset_tx_list(struct rtwn_usb_softc *uc, rtwn_datahead *head, struct ieee80211vap *vap) { struct rtwn_vap *uvp = RTWN_VAP(vap); struct rtwn_data *dp, *tmp; int id; id = (uvp != NULL ? uvp->id : RTWN_VAP_ID_INVALID); STAILQ_FOREACH_SAFE(dp, head, next, tmp) { if (vap == NULL || (dp->ni == NULL && (dp->id == id || id == RTWN_VAP_ID_INVALID)) || (dp->ni != NULL && dp->ni->ni_vap == vap)) { if (dp->ni != NULL) { ieee80211_free_node(dp->ni); dp->ni = NULL; } if (dp->m != NULL) { m_freem(dp->m); dp->m = NULL; } STAILQ_REMOVE(head, dp, rtwn_data, next); STAILQ_INSERT_TAIL(&uc->uc_tx_inactive, dp, next); } } } static void rtwn_usb_reset_rx_list(struct rtwn_usb_softc *uc) { int i; for (i = 0; i < RTWN_USB_RX_LIST_COUNT; i++) { struct rtwn_data *dp = &uc->uc_rx[i]; if (dp->m != NULL) { m_freem(dp->m); dp->m = NULL; } } uc->uc_rx_stat_len = 0; uc->uc_rx_off = 0; } static void rtwn_usb_start_xfers(struct rtwn_softc *sc) { struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); usbd_transfer_start(uc->uc_xfer[RTWN_BULK_RX]); } static void rtwn_usb_abort_xfers(struct rtwn_softc *sc) { struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); int i; RTWN_ASSERT_LOCKED(sc); /* abort any pending transfers */ RTWN_UNLOCK(sc); - for (i = 0; i < RTWN_N_TRANSFER; i++) + for (i = 0; i < RTWN_BULK_EP_COUNT; i++) usbd_transfer_drain(uc->uc_xfer[i]); RTWN_LOCK(sc); } static int rtwn_usb_fw_write_block(struct rtwn_softc *sc, const uint8_t *buf, uint16_t reg, int mlen) { int error; /* XXX fix this deconst */ error = rtwn_usb_write_region_1(sc, reg, __DECONST(uint8_t *, buf), mlen); return (error); } static void rtwn_usb_drop_incorrect_tx(struct rtwn_softc *sc) { rtwn_setbits_1_shift(sc, R92C_TXDMA_OFFSET_CHK, 0, R92C_TXDMA_OFFSET_DROP_DATA_EN, 1); } static void rtwn_usb_attach_methods(struct rtwn_softc *sc) { sc->sc_write_1 = rtwn_usb_write_1; sc->sc_write_2 = rtwn_usb_write_2; sc->sc_write_4 = rtwn_usb_write_4; sc->sc_read_1 = rtwn_usb_read_1; sc->sc_read_2 = rtwn_usb_read_2; sc->sc_read_4 = rtwn_usb_read_4; sc->sc_delay = rtwn_usb_delay; sc->sc_tx_start = rtwn_usb_tx_start; sc->sc_start_xfers = rtwn_usb_start_xfers; sc->sc_reset_lists = rtwn_usb_reset_lists; sc->sc_abort_xfers = rtwn_usb_abort_xfers; sc->sc_fw_write_block = rtwn_usb_fw_write_block; sc->sc_get_qmap = rtwn_usb_get_qmap; sc->sc_set_desc_addr = rtwn_nop_softc; sc->sc_drop_incorrect_tx = rtwn_usb_drop_incorrect_tx; sc->sc_beacon_update_begin = rtwn_nop_softc_vap; sc->sc_beacon_update_end = rtwn_nop_softc_vap; sc->sc_beacon_unload = rtwn_nop_softc_int; sc->bcn_check_interval = 100; } static void rtwn_usb_sysctlattach(struct rtwn_softc *sc) { struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev); struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev); char str[64]; int ret; ret = snprintf(str, sizeof(str), "Rx buffer size, 512-byte units [%d...%d]", RTWN_USB_RXBUFSZ_MIN, RTWN_USB_RXBUFSZ_MAX); KASSERT(ret > 0, ("ret (%d) <= 0!\n", ret)); (void) ret; uc->uc_rx_buf_size = RTWN_USB_RXBUFSZ_DEF; SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "rx_buf_size", CTLFLAG_RDTUN, &uc->uc_rx_buf_size, uc->uc_rx_buf_size, str); if (uc->uc_rx_buf_size < RTWN_USB_RXBUFSZ_MIN) uc->uc_rx_buf_size = RTWN_USB_RXBUFSZ_MIN; if (uc->uc_rx_buf_size > RTWN_USB_RXBUFSZ_MAX) uc->uc_rx_buf_size = RTWN_USB_RXBUFSZ_MAX; } static int rtwn_usb_attach(device_t self) { struct usb_attach_arg *uaa = device_get_ivars(self); struct rtwn_usb_softc *uc = device_get_softc(self); struct rtwn_softc *sc = &uc->uc_sc; struct ieee80211com *ic = &sc->sc_ic; int error; device_set_usb_desc(self); uc->uc_udev = uaa->device; sc->sc_dev = self; ic->ic_name = device_get_nameunit(self); /* Need to be initialized early. */ rtwn_sysctlattach(sc); rtwn_usb_sysctlattach(sc); mtx_init(&sc->sc_mtx, ic->ic_name, MTX_NETWORK_LOCK, MTX_DEF); rtwn_usb_attach_methods(sc); rtwn_usb_attach_private(uc, USB_GET_DRIVER_INFO(uaa)); error = rtwn_usb_setup_endpoints(uc); if (error != 0) goto detach; /* Allocate Tx/Rx buffers. */ error = rtwn_usb_alloc_rx_list(sc); if (error != 0) goto detach; error = rtwn_usb_alloc_tx_list(sc); if (error != 0) goto detach; /* Generic attach. */ error = rtwn_attach(sc); if (error != 0) goto detach; return (0); detach: rtwn_usb_detach(self); /* failure */ return (ENXIO); } static int rtwn_usb_detach(device_t self) { struct rtwn_usb_softc *uc = device_get_softc(self); struct rtwn_softc *sc = &uc->uc_sc; /* Generic detach. */ rtwn_detach(sc); /* Free Tx/Rx buffers. */ rtwn_usb_free_tx_list(sc); rtwn_usb_free_rx_list(sc); /* Detach all USB transfers. */ - usbd_transfer_unsetup(uc->uc_xfer, RTWN_N_TRANSFER); + usbd_transfer_unsetup(uc->uc_xfer, RTWN_BULK_EP_COUNT); rtwn_detach_private(sc); mtx_destroy(&sc->sc_mtx); return (0); } static int rtwn_usb_suspend(device_t self) { struct rtwn_usb_softc *uc = device_get_softc(self); rtwn_suspend(&uc->uc_sc); return (0); } static int rtwn_usb_resume(device_t self) { struct rtwn_usb_softc *uc = device_get_softc(self); rtwn_resume(&uc->uc_sc); return (0); } static device_method_t rtwn_usb_methods[] = { /* Device interface */ DEVMETHOD(device_probe, rtwn_usb_match), DEVMETHOD(device_attach, rtwn_usb_attach), DEVMETHOD(device_detach, rtwn_usb_detach), DEVMETHOD(device_suspend, rtwn_usb_suspend), DEVMETHOD(device_resume, rtwn_usb_resume), DEVMETHOD_END }; static driver_t rtwn_usb_driver = { "rtwn", rtwn_usb_methods, sizeof(struct rtwn_usb_softc) }; DRIVER_MODULE(rtwn_usb, uhub, rtwn_usb_driver, NULL, NULL); MODULE_VERSION(rtwn_usb, 1); MODULE_DEPEND(rtwn_usb, usb, 1, 1, 1); MODULE_DEPEND(rtwn_usb, wlan, 1, 1, 1); MODULE_DEPEND(rtwn_usb, rtwn, 2, 2, 2); USB_PNP_HOST_INFO(rtwn_devs); diff --git a/sys/dev/rtwn/usb/rtwn_usb_ep.c b/sys/dev/rtwn/usb/rtwn_usb_ep.c index 0848a45a9f86..f9b0672324fe 100644 --- a/sys/dev/rtwn/usb/rtwn_usb_ep.c +++ b/sys/dev/rtwn/usb/rtwn_usb_ep.c @@ -1,257 +1,268 @@ /* $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 #include #include -static const struct usb_config rtwn_config_common[RTWN_N_TRANSFER] = { +static const struct usb_config rtwn_config_common[RTWN_BULK_EP_COUNT] = { [RTWN_BULK_RX] = { .type = UE_BULK, .endpoint = UE_ADDR_ANY, .direction = UE_DIR_IN, .flags = { .pipe_bof = 1, .short_xfer_ok = 1 }, .callback = rtwn_bulk_rx_callback, }, [RTWN_BULK_TX_BE] = { .type = UE_BULK, .endpoint = UE_ADDR_ANY, .direction = UE_DIR_OUT, .bufsize = RTWN_USB_TXBUFSZ, .flags = { .ext_buffer = 1, .pipe_bof = 1, .force_short_xfer = 1, }, - .callback = rtwn_bulk_tx_callback, + .callback = rtwn_bulk_tx_callback_be, .timeout = RTWN_TX_TIMEOUT, /* ms */ }, [RTWN_BULK_TX_BK] = { .type = UE_BULK, .endpoint = UE_ADDR_ANY, .direction = UE_DIR_OUT, .bufsize = RTWN_USB_TXBUFSZ, .flags = { .ext_buffer = 1, .pipe_bof = 1, .force_short_xfer = 1, }, - .callback = rtwn_bulk_tx_callback, + .callback = rtwn_bulk_tx_callback_bk, .timeout = RTWN_TX_TIMEOUT, /* ms */ }, [RTWN_BULK_TX_VI] = { .type = UE_BULK, .endpoint = UE_ADDR_ANY, .direction = UE_DIR_OUT, .bufsize = RTWN_USB_TXBUFSZ, .flags = { .ext_buffer = 1, .pipe_bof = 1, .force_short_xfer = 1 }, - .callback = rtwn_bulk_tx_callback, + .callback = rtwn_bulk_tx_callback_vi, .timeout = RTWN_TX_TIMEOUT, /* ms */ }, [RTWN_BULK_TX_VO] = { .type = UE_BULK, .endpoint = UE_ADDR_ANY, .direction = UE_DIR_OUT, .bufsize = RTWN_USB_TXBUFSZ, .flags = { .ext_buffer = 1, .pipe_bof = 1, .force_short_xfer = 1 }, - .callback = rtwn_bulk_tx_callback, + .callback = rtwn_bulk_tx_callback_vo, .timeout = RTWN_TX_TIMEOUT, /* ms */ }, }; static void rtwn_usb_setup_queues(struct rtwn_usb_softc *uc) { struct rtwn_softc *sc = &uc->uc_sc; int hasnq, haslq, nqueues, nqpages, nrempages; /* Get Tx queues to USB endpoints mapping. */ hasnq = haslq = 0; switch (uc->ntx) { case 4: case 3: haslq = 1; /* FALLTHROUGH */ case 2: hasnq = 1; /* FALLTHROUGH */ default: break; } nqueues = 1 + hasnq + haslq; /* Get the number of pages for each queue. */ nqpages = (sc->page_count - sc->npubqpages) / nqueues; /* * The remaining pages are assigned to the high priority * queue. */ nrempages = (sc->page_count - sc->npubqpages) % nqueues; sc->nhqpages = nqpages + nrempages; sc->nnqpages = (hasnq ? nqpages : 0); sc->nlqpages = (haslq ? nqpages : 0); } int rtwn_usb_setup_endpoints(struct rtwn_usb_softc *uc) { struct usb_config *rtwn_config; struct rtwn_softc *sc = &uc->uc_sc; const uint8_t iface_index = RTWN_IFACE_INDEX; struct usb_endpoint *ep, *ep_end; uint8_t addr[RTWN_MAX_EPOUT]; int error; /* Determine the number of bulk-out pipes. */ uc->ntx = 0; ep = uc->uc_udev->endpoints; ep_end = uc->uc_udev->endpoints + uc->uc_udev->endpoints_max; for (; ep != ep_end; ep++) { uint8_t eaddr; if ((ep->edesc == NULL) || (ep->iface_index != iface_index)) continue; eaddr = ep->edesc->bEndpointAddress; RTWN_DPRINTF(sc, RTWN_DEBUG_USB, "%s: endpoint: addr %u, direction %s\n", __func__, UE_GET_ADDR(eaddr), UE_GET_DIR(eaddr) == UE_DIR_OUT ? "output" : "input"); if (UE_GET_DIR(eaddr) == UE_DIR_OUT) { if (uc->ntx == RTWN_MAX_EPOUT) break; addr[uc->ntx++] = UE_GET_ADDR(eaddr); } } if (uc->ntx == 0 || uc->ntx > RTWN_MAX_EPOUT) { device_printf(sc->sc_dev, "%s: invalid number of Tx bulk pipes (%d)\n", __func__, uc->ntx); return (EINVAL); } rtwn_config = malloc(sizeof(rtwn_config_common), M_TEMP, M_WAITOK); memcpy(rtwn_config, rtwn_config_common, sizeof(rtwn_config_common)); /* NB: keep in sync with rtwn_dma_init(). */ rtwn_config[RTWN_BULK_TX_VO].endpoint = addr[0]; + uc->wme2qid[WME_AC_VO] = RTWN_BULK_TX_VO; switch (uc->ntx) { case 4: case 3: rtwn_config[RTWN_BULK_TX_BE].endpoint = addr[2]; rtwn_config[RTWN_BULK_TX_BK].endpoint = addr[2]; rtwn_config[RTWN_BULK_TX_VI].endpoint = addr[1]; + uc->wme2qid[WME_AC_BE] = RTWN_BULK_TX_BE; + uc->wme2qid[WME_AC_BK] = RTWN_BULK_TX_BE; + uc->wme2qid[WME_AC_VI] = RTWN_BULK_TX_VI; break; case 2: rtwn_config[RTWN_BULK_TX_BE].endpoint = addr[1]; rtwn_config[RTWN_BULK_TX_BK].endpoint = addr[1]; rtwn_config[RTWN_BULK_TX_VI].endpoint = addr[0]; + uc->wme2qid[WME_AC_BE] = RTWN_BULK_TX_VI; + uc->wme2qid[WME_AC_BK] = RTWN_BULK_TX_VI; + uc->wme2qid[WME_AC_VI] = RTWN_BULK_TX_VO; break; case 1: rtwn_config[RTWN_BULK_TX_BE].endpoint = addr[0]; rtwn_config[RTWN_BULK_TX_BK].endpoint = addr[0]; rtwn_config[RTWN_BULK_TX_VI].endpoint = addr[0]; + + uc->wme2qid[WME_AC_BE] = RTWN_BULK_TX_VO; + uc->wme2qid[WME_AC_BK] = RTWN_BULK_TX_VO; + uc->wme2qid[WME_AC_VI] = RTWN_BULK_TX_VO; break; default: KASSERT(0, ("unhandled number of endpoints %d\n", uc->ntx)); break; } rtwn_config[RTWN_BULK_RX].bufsize = uc->uc_rx_buf_size * RTWN_USB_RXBUFSZ_UNIT; error = usbd_transfer_setup(uc->uc_udev, &iface_index, - uc->uc_xfer, rtwn_config, RTWN_N_TRANSFER, uc, &sc->sc_mtx); + uc->uc_xfer, rtwn_config, RTWN_BULK_EP_COUNT, uc, &sc->sc_mtx); free(rtwn_config, M_TEMP); if (error) { device_printf(sc->sc_dev, "could not allocate USB transfers, " "err=%s\n", usbd_errstr(error)); return (error); } /* Assign pages for each queue (if not done). */ if (sc->nhqpages == 0 && sc->nnqpages == 0 && sc->nlqpages == 0) rtwn_usb_setup_queues(uc); return (0); } uint16_t rtwn_usb_get_qmap(struct rtwn_softc *sc) { struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); switch (uc->ntx) { case 1: return (R92C_TRXDMA_CTRL_QMAP_HQ); case 2: return (R92C_TRXDMA_CTRL_QMAP_HQ_NQ); default: return (R92C_TRXDMA_CTRL_QMAP_3EP); } } diff --git a/sys/dev/rtwn/usb/rtwn_usb_tx.c b/sys/dev/rtwn/usb/rtwn_usb_tx.c index 0fb8632d9a16..86d41ed10d91 100644 --- a/sys/dev/rtwn/usb/rtwn_usb_tx.c +++ b/sys/dev/rtwn/usb/rtwn_usb_tx.c @@ -1,281 +1,345 @@ /* $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 #include #include #include #include #include #include static struct rtwn_data * _rtwn_usb_getbuf(struct rtwn_usb_softc *); static struct rtwn_data * rtwn_usb_getbuf(struct rtwn_usb_softc *); static void rtwn_usb_txeof(struct rtwn_usb_softc *, struct rtwn_data *, int); -static const uint8_t wme2qid[] = - { RTWN_BULK_TX_BE, RTWN_BULK_TX_BK, - RTWN_BULK_TX_VI, RTWN_BULK_TX_VO }; - static struct rtwn_data * _rtwn_usb_getbuf(struct rtwn_usb_softc *uc) { struct rtwn_softc *sc = &uc->uc_sc; struct rtwn_data *bf; bf = STAILQ_FIRST(&uc->uc_tx_inactive); if (bf != NULL) STAILQ_REMOVE_HEAD(&uc->uc_tx_inactive, next); else { RTWN_DPRINTF(sc, RTWN_DEBUG_XMIT, "%s: out of xmit buffers\n", __func__); } return (bf); } static struct rtwn_data * rtwn_usb_getbuf(struct rtwn_usb_softc *uc) { struct rtwn_softc *sc = &uc->uc_sc; struct rtwn_data *bf; RTWN_ASSERT_LOCKED(sc); bf = _rtwn_usb_getbuf(uc); if (bf == NULL) { RTWN_DPRINTF(sc, RTWN_DEBUG_XMIT, "%s: stop queue\n", __func__); } return (bf); } static void rtwn_usb_txeof(struct rtwn_usb_softc *uc, struct rtwn_data *data, int status) { struct rtwn_softc *sc = &uc->uc_sc; + bool is_empty = true; RTWN_ASSERT_LOCKED(sc); if (data->ni != NULL) /* not a beacon frame */ ieee80211_tx_complete(data->ni, data->m, status); if (sc->sc_ratectl != RTWN_RATECTL_NET80211) if (sc->sc_tx_n_active > 0) sc->sc_tx_n_active--; data->ni = NULL; data->m = NULL; STAILQ_INSERT_TAIL(&uc->uc_tx_inactive, data, next); sc->qfullmsk = 0; + #ifndef D4054 - if (STAILQ_EMPTY(&uc->uc_tx_active) && STAILQ_EMPTY(&uc->uc_tx_pending)) + for (int i = RTWN_BULK_TX_FIRST; i < RTWN_BULK_EP_COUNT; i++) { + if (!STAILQ_EMPTY(&uc->uc_tx_active[i]) || + !STAILQ_EMPTY(&uc->uc_tx_pending[i])) + is_empty = false; + } + + if (is_empty) sc->sc_tx_timer = 0; else sc->sc_tx_timer = 5; #endif } -void -rtwn_bulk_tx_callback(struct usb_xfer *xfer, usb_error_t error) +static void +rtwn_bulk_tx_callback_qid(struct usb_xfer *xfer, usb_error_t error, int qid) { struct rtwn_usb_softc *uc = usbd_xfer_softc(xfer); struct rtwn_softc *sc = &uc->uc_sc; struct rtwn_data *data; + bool do_is_empty_check = false; + int i; + + RTWN_DPRINTF(sc, RTWN_DEBUG_XMIT, + "%s: called, qid=%d\n", __func__, qid); RTWN_ASSERT_LOCKED(sc); switch (USB_GET_STATE(xfer)){ case USB_ST_TRANSFERRED: - data = STAILQ_FIRST(&uc->uc_tx_active); + data = STAILQ_FIRST(&uc->uc_tx_active[qid]); if (data == NULL) goto tr_setup; - STAILQ_REMOVE_HEAD(&uc->uc_tx_active, next); + STAILQ_REMOVE_HEAD(&uc->uc_tx_active[qid], next); rtwn_usb_txeof(uc, data, 0); /* FALLTHROUGH */ case USB_ST_SETUP: tr_setup: - data = STAILQ_FIRST(&uc->uc_tx_pending); + data = STAILQ_FIRST(&uc->uc_tx_pending[qid]); if (data == NULL) { RTWN_DPRINTF(sc, RTWN_DEBUG_XMIT, "%s: empty pending queue\n", __func__); - sc->sc_tx_n_active = 0; + do_is_empty_check = true; goto finish; } - STAILQ_REMOVE_HEAD(&uc->uc_tx_pending, next); - STAILQ_INSERT_TAIL(&uc->uc_tx_active, data, next); + STAILQ_REMOVE_HEAD(&uc->uc_tx_pending[qid], next); + STAILQ_INSERT_TAIL(&uc->uc_tx_active[qid], data, next); /* * Note: if this is a beacon frame, ensure that it will go * into appropriate queue. */ if (data->ni == NULL && RTWN_CHIP_HAS_BCNQ1(sc)) rtwn_switch_bcnq(sc, data->id); usbd_xfer_set_frame_data(xfer, 0, data->buf, data->buflen); usbd_transfer_submit(xfer); if (sc->sc_ratectl != RTWN_RATECTL_NET80211) sc->sc_tx_n_active++; break; default: - data = STAILQ_FIRST(&uc->uc_tx_active); + data = STAILQ_FIRST(&uc->uc_tx_active[qid]); if (data == NULL) goto tr_setup; - STAILQ_REMOVE_HEAD(&uc->uc_tx_active, next); + STAILQ_REMOVE_HEAD(&uc->uc_tx_active[qid], next); rtwn_usb_txeof(uc, data, 1); + if (error != 0) + device_printf(sc->sc_dev, + "%s: called; txeof qid=%d, error=%s\n", + __func__, + qid, + usbd_errstr(error)); if (error != USB_ERR_CANCELLED) { usbd_xfer_set_stall(xfer); goto tr_setup; } break; } finish: + + /* + * Clear sc_tx_n_active if all the pending transfers are 0. + * + * This is currently a crutch because net80211 doesn't provide + * a way to defer all the FF checks or one of the FF checks. + * Eventually this should just be tracked per-endpoint. + */ + for (i = RTWN_BULK_TX_FIRST; i < RTWN_BULK_EP_COUNT; i++) + if (STAILQ_FIRST(&uc->uc_tx_pending[i]) != NULL) + do_is_empty_check = false; + if (do_is_empty_check) + sc->sc_tx_n_active = 0; #ifdef IEEE80211_SUPPORT_SUPERG /* * If the TX active queue drops below a certain * threshold, ensure we age fast-frames out so they're * transmitted. */ if (sc->sc_ratectl != RTWN_RATECTL_NET80211 && sc->sc_tx_n_active <= 1) { /* XXX ew - net80211 should defer this for us! */ /* * Note: this sc_tx_n_active currently tracks * the number of pending transmit submissions * and not the actual depth of the TX frames * pending to the hardware. That means that * we're going to end up with some sub-optimal * aggregation behaviour. */ /* * XXX TODO: just make this a callout timer schedule so we can * flush the FF staging queue if we're approaching idle. */ rtwn_cmd_sleepable(sc, NULL, 0, rtwn_ff_flush_all); } #endif /* Kick-start more transmit */ rtwn_start(sc); } +void +rtwn_bulk_tx_callback_be(struct usb_xfer *xfer, usb_error_t error) +{ + + rtwn_bulk_tx_callback_qid(xfer, error, RTWN_BULK_TX_BE); +} + +void +rtwn_bulk_tx_callback_bk(struct usb_xfer *xfer, usb_error_t error) +{ + + rtwn_bulk_tx_callback_qid(xfer, error, RTWN_BULK_TX_BK); +} + +void +rtwn_bulk_tx_callback_vi(struct usb_xfer *xfer, usb_error_t error) +{ + + rtwn_bulk_tx_callback_qid(xfer, error, RTWN_BULK_TX_VI); +} + +void +rtwn_bulk_tx_callback_vo(struct usb_xfer *xfer, usb_error_t error) +{ + + rtwn_bulk_tx_callback_qid(xfer, error, RTWN_BULK_TX_VO); +} + static void rtwn_usb_tx_checksum(struct rtwn_tx_desc_common *txd) { txd->txdw7.usb_checksum = 0; txd->txdw7.usb_checksum = rtwn_usb_calc_tx_checksum(txd); } int rtwn_usb_tx_start(struct rtwn_softc *sc, struct ieee80211_node *ni, struct mbuf *m, uint8_t *tx_desc, uint8_t type, int id) { struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); struct rtwn_tx_desc_common *txd; struct rtwn_data *data; struct usb_xfer *xfer; uint16_t ac; + int qid = 0; RTWN_ASSERT_LOCKED(sc); if (m->m_pkthdr.len + sc->txdesc_len > RTWN_USB_TXBUFSZ) return (EINVAL); data = rtwn_usb_getbuf(uc); if (data == NULL) return (ENOBUFS); + /* TODO: should really get a consistent AC/TID, ath(4) style */ ac = M_WME_GETAC(m); switch (type) { case IEEE80211_FC0_TYPE_CTL: case IEEE80211_FC0_TYPE_MGT: - xfer = uc->uc_xfer[RTWN_BULK_TX_VO]; + qid = RTWN_BULK_TX_VO; break; default: - xfer = uc->uc_xfer[wme2qid[ac]]; + qid = uc->wme2qid[ac]; break; } + xfer = uc->uc_xfer[qid]; + + RTWN_DPRINTF(sc, RTWN_DEBUG_XMIT, + "%s: called, ac=%d, qid=%d, xfer=%p\n", + __func__, ac, qid, xfer); txd = (struct rtwn_tx_desc_common *)tx_desc; txd->pktlen = htole16(m->m_pkthdr.len); txd->offset = sc->txdesc_len; txd->flags0 |= RTWN_FLAGS0_OWN; rtwn_usb_tx_checksum(txd); /* Dump Tx descriptor. */ rtwn_dump_tx_desc(sc, tx_desc); memcpy(data->buf, tx_desc, sc->txdesc_len); m_copydata(m, 0, m->m_pkthdr.len, (caddr_t)(data->buf + sc->txdesc_len)); data->buflen = m->m_pkthdr.len + sc->txdesc_len; data->id = id; data->ni = ni; + data->qid = qid; if (data->ni != NULL) { data->m = m; #ifndef D4054 sc->sc_tx_timer = 5; #endif } - STAILQ_INSERT_TAIL(&uc->uc_tx_pending, data, next); + STAILQ_INSERT_TAIL(&uc->uc_tx_pending[qid], data, next); if (STAILQ_EMPTY(&uc->uc_tx_inactive)) sc->qfullmsk = 1; usbd_transfer_start(xfer); return (0); } diff --git a/sys/dev/rtwn/usb/rtwn_usb_tx.h b/sys/dev/rtwn/usb/rtwn_usb_tx.h index 7b762cc01a00..193103f32707 100644 --- a/sys/dev/rtwn/usb/rtwn_usb_tx.h +++ b/sys/dev/rtwn/usb/rtwn_usb_tx.h @@ -1,24 +1,27 @@ /*- * Copyright (c) 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. */ #ifndef RTWN_USB_TX_H #define RTWN_USB_TX_H -void rtwn_bulk_tx_callback(struct usb_xfer *, usb_error_t); +void rtwn_bulk_tx_callback_bk(struct usb_xfer *, usb_error_t); +void rtwn_bulk_tx_callback_be(struct usb_xfer *, usb_error_t); +void rtwn_bulk_tx_callback_vi(struct usb_xfer *, usb_error_t); +void rtwn_bulk_tx_callback_vo(struct usb_xfer *, usb_error_t); int rtwn_usb_tx_start(struct rtwn_softc *, struct ieee80211_node *, struct mbuf *, uint8_t *, uint8_t, int); #endif /* RTWN_USB_TX_H */ diff --git a/sys/dev/rtwn/usb/rtwn_usb_var.h b/sys/dev/rtwn/usb/rtwn_usb_var.h index bad697bfa1db..646dde66aeab 100644 --- a/sys/dev/rtwn/usb/rtwn_usb_var.h +++ b/sys/dev/rtwn/usb/rtwn_usb_var.h @@ -1,87 +1,91 @@ /*- * Copyright (c) 2010 Damien Bergamini * Copyright (c) 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 RTWN_USBVAR_H #define RTWN_USBVAR_H #include /* for struct rtwn_rx_stat_common */ #define RTWN_USB_RXBUFSZ_UNIT (512) #define RTWN_USB_RXBUFSZ_MIN ( 4) #define RTWN_USB_RXBUFSZ_DEF (24) #define RTWN_USB_RXBUFSZ_MAX (64) #define RTWN_USB_TXBUFSZ (16 * 1024) #define RTWN_IFACE_INDEX 0 #define RTWN_USB_RX_LIST_COUNT 1 #define RTWN_USB_TX_LIST_COUNT 16 struct rtwn_data { uint8_t *buf; /* 'id' is meaningful for beacons only */ int id; + int qid; uint16_t buflen; struct mbuf *m; struct ieee80211_node *ni; STAILQ_ENTRY(rtwn_data) next; }; typedef STAILQ_HEAD(, rtwn_data) rtwn_datahead; enum { RTWN_BULK_RX, RTWN_BULK_TX_BE, /* = WME_AC_BE */ RTWN_BULK_TX_BK, /* = WME_AC_BK */ RTWN_BULK_TX_VI, /* = WME_AC_VI */ RTWN_BULK_TX_VO, /* = WME_AC_VO */ - RTWN_N_TRANSFER = 5, + RTWN_BULK_EP_COUNT = 5, }; #define RTWN_EP_QUEUES RTWN_BULK_RX +#define RTWN_BULK_TX_FIRST RTWN_BULK_TX_BE struct rtwn_usb_softc { struct rtwn_softc uc_sc; /* must be the first */ struct usb_device *uc_udev; - struct usb_xfer *uc_xfer[RTWN_N_TRANSFER]; + struct usb_xfer *uc_xfer[RTWN_BULK_EP_COUNT]; struct rtwn_data uc_rx[RTWN_USB_RX_LIST_COUNT]; rtwn_datahead uc_rx_active; rtwn_datahead uc_rx_inactive; int uc_rx_buf_size; struct rtwn_rx_stat_common uc_rx_stat; int uc_rx_stat_len; int uc_rx_off; struct rtwn_data uc_tx[RTWN_USB_TX_LIST_COUNT]; - rtwn_datahead uc_tx_active; + rtwn_datahead uc_tx_active[RTWN_BULK_EP_COUNT]; rtwn_datahead uc_tx_inactive; - rtwn_datahead uc_tx_pending; + rtwn_datahead uc_tx_pending[RTWN_BULK_EP_COUNT]; int (*uc_align_rx)(int, int); int ntx; int tx_agg_desc_num; + + uint8_t wme2qid[4]; }; #define RTWN_USB_SOFTC(sc) ((struct rtwn_usb_softc *)(sc)) #define rtwn_usb_align_rx(_uc, _totlen, _len) \ (((_uc)->uc_align_rx)((_totlen), (_len))) #endif /* RTWN_USBVAR_H */