diff options
author | Matt Smith <mgsmith@netgate.com> | 2015-11-18 10:33:06 -0600 |
---|---|---|
committer | Matt Smith <mgsmith@netgate.com> | 2015-11-18 10:33:06 -0600 |
commit | a5d857c46178a8f007d57d8c9464f87be6cff363 (patch) | |
tree | 8a2a2ea905626a6a15e41b022fb9b917ba3670ad | |
parent | 86a5f7f4a9d06ce713d5b0f97c87b33683d3fce6 (diff) | |
download | FreeBSD-src-a5d857c46178a8f007d57d8c9464f87be6cff363.zip FreeBSD-src-a5d857c46178a8f007d57d8c9464f87be6cff363.tar.gz |
Importing pfSense patch HEAD-wireless-ath.tgz
287 files changed, 8168 insertions, 1860 deletions
diff --git a/sys/contrib/dev/ath/ath_hal/ar9300/ar9300.h b/sys/contrib/dev/ath/ath_hal/ar9300/ar9300.h index 73b902f..e63b517 100644 --- a/sys/contrib/dev/ath/ath_hal/ar9300/ar9300.h +++ b/sys/contrib/dev/ath/ath_hal/ar9300/ar9300.h @@ -185,6 +185,8 @@ struct ar9300_ani_state { int32_t rssi; /* The current RSSI */ u_int32_t tx_frame_count; /* Last tx_frame_count */ u_int32_t rx_frame_count; /* Last rx Frame count */ + u_int32_t rx_busy_count; /* Last rx busy count */ + u_int32_t rx_ext_busy_count; /* Last rx busy count; extension channel */ u_int32_t cycle_count; /* Last cycle_count (can detect wrap-around) */ u_int32_t ofdm_phy_err_count;/* OFDM err count since last reset */ u_int32_t cck_phy_err_count; /* CCK err count since last reset */ @@ -204,6 +206,7 @@ struct ar9300_ani_state { #define DO_ANI(ah) \ ((AH9300(ah)->ah_proc_phy_err & HAL_PROCESS_ANI)) +#if 0 struct ar9300_stats { u_int32_t ast_ani_niup; /* ANI increased noise immunity */ u_int32_t ast_ani_nidown; /* ANI decreased noise immunity */ @@ -223,6 +226,7 @@ struct ar9300_stats { HAL_MIB_STATS ast_mibstats; /* MIB counter stats */ HAL_NODE_STATS ast_nodestats; /* Latest rssi stats from driver */ }; +#endif struct ar9300_rad_reader { u_int16_t rd_index; @@ -317,12 +321,12 @@ typedef struct { /* Support for multiple INIs */ struct ar9300_ini_array { - u_int32_t *ia_array; + const u_int32_t *ia_array; u_int32_t ia_rows; u_int32_t ia_columns; }; #define INIT_INI_ARRAY(iniarray, array, rows, columns) do { \ - (iniarray)->ia_array = (u_int32_t *)(array); \ + (iniarray)->ia_array = (const u_int32_t *)(array); \ (iniarray)->ia_rows = (rows); \ (iniarray)->ia_columns = (columns); \ } while (0) @@ -429,7 +433,7 @@ struct ath_hal_9300 { u_int32_t ah_mask2Reg; /* copy of AR_IMR_S2 */ u_int32_t ah_msi_reg; /* copy of AR_PCIE_MSI */ os_atomic_t ah_ier_ref_count; /* reference count for enabling interrupts */ - struct ar9300_stats ah_stats; /* various statistics */ + HAL_ANI_STATS ah_stats; /* various statistics */ RF_HAL_FUNCS ah_rf_hal; u_int32_t ah_tx_desc_mask; /* mask for TXDESC */ u_int32_t ah_tx_ok_interrupt_mask; @@ -576,6 +580,9 @@ struct ath_hal_9300 { u_int8_t ah_tx_chainmask; /* tx chain mask */ u_int8_t ah_rx_chainmask; /* rx chain mask */ + /* optional tx chainmask */ + u_int8_t ah_tx_chainmaskopt; + u_int8_t ah_tx_cal_chainmask; /* tx cal chain mask */ u_int8_t ah_rx_cal_chainmask; /* rx cal chain mask */ @@ -845,6 +852,7 @@ struct ath_hal_9300 { HAL_BOOL ah_aic_enabled; u_int32_t ah_aic_sram[ATH_AIC_MAX_BT_CHANNEL]; #endif + #endif /* ATH_SUPPORT_MCI */ u_int8_t ah_cac_quiet_enabled; #if ATH_WOW_OFFLOAD @@ -852,6 +860,14 @@ struct ath_hal_9300 { u_int32_t ah_mcast_filter_u32_set; #endif HAL_BOOL ah_reduced_self_gen_mask; + HAL_BOOL ah_chip_reset_done; + HAL_BOOL ah_abort_txdma_norx; + /* store previous passive RX Cal info */ + HAL_BOOL ah_skip_rx_iq_cal; + HAL_BOOL ah_rx_cal_complete; /* previous rx cal completed or not */ + u_int32_t ah_rx_cal_chan; /* chan on which rx cal is done */ + u_int32_t ah_rx_cal_chan_flag; + u_int32_t ah_rx_cal_corr[AR9300_MAX_CHAINS]; /* Local additions for FreeBSD */ /* @@ -873,11 +889,11 @@ struct ath_hal_9300 { int ah_fccaifs; int ah_reset_reason; int ah_dcs_enable; + HAL_ANI_STATE ext_ani_state; /* FreeBSD; external facing ANI state */ struct ar9300NfLimits nf_2GHz; struct ar9300NfLimits nf_5GHz; struct ar9300NfLimits *nfp; - }; #define AH9300(_ah) ((struct ath_hal_9300 *)(_ah)) @@ -1181,10 +1197,11 @@ struct ath_hal; extern struct ath_hal_9300 * ar9300_new_state(u_int16_t devid, HAL_SOFTC sc, HAL_BUS_TAG st, HAL_BUS_HANDLE sh, uint16_t *eepromdata, + HAL_OPS_CONFIG *ah_config, HAL_STATUS *status); extern struct ath_hal * ar9300_attach(u_int16_t devid, HAL_SOFTC sc, HAL_BUS_TAG st, HAL_BUS_HANDLE sh, uint16_t *eepromdata, - HAL_STATUS *status); + HAL_OPS_CONFIG *ah_config, HAL_STATUS *status); extern void ar9300_detach(struct ath_hal *ah); extern void ar9300_read_revisions(struct ath_hal *ah); extern HAL_BOOL ar9300_chip_test(struct ath_hal *ah); @@ -1193,7 +1210,8 @@ extern HAL_BOOL ar9300_get_channel_edges(struct ath_hal *ah, extern HAL_BOOL ar9300_fill_capability_info(struct ath_hal *ah); extern void ar9300_beacon_init(struct ath_hal *ah, - u_int32_t next_beacon, u_int32_t beacon_period, HAL_OPMODE opmode); + u_int32_t next_beacon, u_int32_t beacon_period, + u_int32_t beacon_period_fraction, HAL_OPMODE opmode); extern void ar9300_set_sta_beacon_timers(struct ath_hal *ah, const HAL_BEACON_STATE *); @@ -1216,12 +1234,21 @@ extern HAL_BOOL ar9300_set_key_cache_entry_mac(struct ath_hal *, extern HAL_BOOL ar9300_set_key_cache_entry(struct ath_hal *ah, u_int16_t entry, const HAL_KEYVAL *k, const u_int8_t *mac, int xor_key); extern HAL_BOOL ar9300_print_keycache(struct ath_hal *ah); +#if ATH_SUPPORT_KEYPLUMB_WAR +extern HAL_BOOL ar9300_check_key_cache_entry(struct ath_hal *ah, u_int16_t entry, + const HAL_KEYVAL *k, int xorKey); +#endif extern void ar9300_get_mac_address(struct ath_hal *ah, u_int8_t *mac); extern HAL_BOOL ar9300_set_mac_address(struct ath_hal *ah, const u_int8_t *); extern void ar9300_get_bss_id_mask(struct ath_hal *ah, u_int8_t *mac); extern HAL_BOOL ar9300_set_bss_id_mask(struct ath_hal *, const u_int8_t *); extern HAL_STATUS ar9300_select_ant_config(struct ath_hal *ah, u_int32_t cfg); +#if 0 +extern u_int32_t ar9300_ant_ctrl_common_get(struct ath_hal *ah, HAL_BOOL is_2ghz); +#endif +extern HAL_BOOL ar9300_ant_swcom_sel(struct ath_hal *ah, u_int8_t ops, + u_int32_t *common_tbl1, u_int32_t *common_tbl2); extern HAL_BOOL ar9300_set_regulatory_domain(struct ath_hal *ah, u_int16_t reg_domain, HAL_STATUS *stats); extern u_int ar9300_get_wireless_modes(struct ath_hal *ah); @@ -1396,6 +1423,8 @@ extern HAL_BOOL ar9300_set_tx_power_limit(struct ath_hal *ah, u_int32_t limit, u_int16_t extra_txpow, u_int16_t tpc_in_db); extern void ar9300_chain_noise_floor(struct ath_hal *ah, int16_t *nf_buf, struct ieee80211_channel *chan, int is_scan); +extern int16_t ar9300_get_nf_from_reg(struct ath_hal *ah, struct ieee80211_channel *chan, int wait_time); +extern int ar9300_get_rx_nf_offset(struct ath_hal *ah, struct ieee80211_channel *chan, int8_t *nf_pwr, int8_t *nf_cal); extern HAL_BOOL ar9300_load_nf(struct ath_hal *ah, int16_t nf[]); extern HAL_RFGAIN ar9300_get_rfgain(struct ath_hal *ah); @@ -1417,7 +1446,7 @@ extern void ar9300_disable_mib_counters(struct ath_hal *); extern void ar9300_ani_attach(struct ath_hal *); extern void ar9300_ani_detach(struct ath_hal *); extern struct ar9300_ani_state *ar9300_ani_get_current_state(struct ath_hal *); -extern struct ar9300_stats *ar9300_ani_get_current_stats(struct ath_hal *); +extern HAL_ANI_STATS *ar9300_ani_get_current_stats(struct ath_hal *); extern HAL_BOOL ar9300_ani_control(struct ath_hal *, HAL_ANI_CMD cmd, int param); struct ath_rx_status; @@ -1680,6 +1709,8 @@ extern void ar9300_tx99_start(struct ath_hal *ah, u_int8_t *data); extern void ar9300_tx99_stop(struct ath_hal *ah); #endif /* ATH_SUPPORT_HTC */ #endif /* ATH_TX99_DIAG */ +extern HAL_BOOL ar9300_set_ctl_pwr(struct ath_hal *ah, u_int8_t *ctl_array); +extern void ar9300_set_txchainmaskopt(struct ath_hal *ah, u_int8_t mask); enum { AR9300_COEFF_TX_TYPE = 0, diff --git a/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_ani.c b/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_ani.c index b07ca71..9c2c3ed 100644 --- a/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_ani.c +++ b/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_ani.c @@ -210,7 +210,7 @@ ar9300_ani_get_current_state(struct ath_hal *ah) /* * Return the current statistics. */ -struct ar9300_stats * +HAL_ANI_STATS * ar9300_ani_get_current_stats(struct ath_hal *ah) { return &AH9300(ah)->ah_stats; @@ -484,6 +484,9 @@ ar9300_ani_control(struct ath_hal *ah, HAL_ANI_CMD cmd, int param) */ is_on = param ? 1 : 0; + if (AR_SREV_JUPITER(ah) || AR_SREV_APHRODITE(ah)) + goto skip_ws_det; + /* * make register setting for default (weak sig detect ON) * come from INI file @@ -528,6 +531,7 @@ ar9300_ani_control(struct ath_hal *ah, HAL_ANI_CMD cmd, int param) m1_thresh_ext); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, AR_PHY_SFCORR_EXT_M2_THRESH, m2_thresh_ext); +skip_ws_det: if (is_on) { OS_REG_SET_BIT(ah, AR_PHY_SFCORR_LOW, AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); @@ -1057,10 +1061,13 @@ ar9300_ani_get_listen_time(struct ath_hal *ah, HAL_ANISTATS *ani_stats) struct ath_hal_9300 *ahp = AH9300(ah); struct ar9300_ani_state *ani_state; u_int32_t tx_frame_count, rx_frame_count, cycle_count; + u_int32_t rx_busy_count, rx_ext_busy_count; int32_t listen_time; tx_frame_count = OS_REG_READ(ah, AR_TFCNT); rx_frame_count = OS_REG_READ(ah, AR_RFCNT); + rx_busy_count = OS_REG_READ(ah, AR_RCCNT); + rx_ext_busy_count = OS_REG_READ(ah, AR_EXTRCCNT); cycle_count = OS_REG_READ(ah, AR_CCCNT); ani_state = ahp->ah_curani; @@ -1081,17 +1088,30 @@ ar9300_ani_get_listen_time(struct ath_hal *ah, HAL_ANISTATS *ani_stats) int32_t ccdelta = cycle_count - ani_state->cycle_count; int32_t rfdelta = rx_frame_count - ani_state->rx_frame_count; int32_t tfdelta = tx_frame_count - ani_state->tx_frame_count; + int32_t rcdelta = rx_busy_count - ani_state->rx_busy_count; + int32_t extrcdelta = rx_ext_busy_count - ani_state->rx_ext_busy_count; listen_time = (ccdelta - rfdelta - tfdelta) / CLOCK_RATE(ah); -#if HAL_ANI_DEBUG +//#if HAL_ANI_DEBUG HALDEBUG(ah, HAL_DEBUG_ANI, - "%s: cyclecount=%d, rfcount=%d, tfcount=%d, listen_time=%d " + "%s: cyclecount=%d, rfcount=%d, tfcount=%d, rcdelta=%d, extrcdelta=%d, listen_time=%d " "CLOCK_RATE=%d\n", - __func__, ccdelta, rfdelta, tfdelta, listen_time, CLOCK_RATE(ah)); -#endif + __func__, ccdelta, rfdelta, tfdelta, rcdelta, extrcdelta, + listen_time, CLOCK_RATE(ah)); +//#endif + /* Populate as appropriate */ + ani_stats->cyclecnt_diff = ccdelta; + ani_stats->rxclr_cnt = rcdelta; + ani_stats->txframecnt_diff = tfdelta; + ani_stats->rxframecnt_diff = rfdelta; + ani_stats->extrxclr_cnt = extrcdelta; + ani_stats->listen_time = listen_time; + ani_stats->valid = AH_TRUE; } ani_state->cycle_count = cycle_count; ani_state->tx_frame_count = tx_frame_count; ani_state->rx_frame_count = rx_frame_count; + ani_state->rx_busy_count = rx_busy_count; + ani_state->rx_ext_busy_count = rx_ext_busy_count; return listen_time; } @@ -1151,7 +1171,13 @@ ar9300_ani_ar_poll(struct ath_hal *ah, const HAL_NODE_STATS *stats, ofdm_phy_err_cnt = OS_REG_READ(ah, AR_PHY_ERR_1); cck_phy_err_cnt = OS_REG_READ(ah, AR_PHY_ERR_2); - + /* Populate HAL_ANISTATS */ + if (ani_stats) { + ani_stats->cckphyerr_cnt = + cck_phy_err_cnt - ani_state->cck_phy_err_count; + ani_stats->ofdmphyerrcnt_diff = + ofdm_phy_err_cnt - ani_state->ofdm_phy_err_count; + } /* NB: only use ast_ani_*errs with AH_PRIVATE_DIAG */ ahp->ah_stats.ast_ani_ofdmerrs += diff --git a/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_attach.c b/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_attach.c index 335414e..a446f96 100644 --- a/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_attach.c +++ b/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_attach.c @@ -302,6 +302,7 @@ static const struct ath_hal_private ar9300hal = { ar9300_get_desc_info, /* ah_get_desc_info */ ar9300_select_ant_config, /* ah_select_ant_config */ ar9300_ant_ctrl_common_get, /* ah_ant_ctrl_common_get */ + ar9300_ant_swcom_sel, /* ah_ant_swcom_sel */ ar9300_enable_tpc, /* ah_enable_tpc */ AH_NULL, /* ah_olpc_temp_compensation */ #if ATH_SUPPORT_CRDC @@ -319,7 +320,9 @@ static const struct ath_hal_private ar9300hal = { ar9300_set_key_cache_entry, /* ah_set_key_cache_entry */ ar9300_set_key_cache_entry_mac, /* ah_set_key_cache_entry_mac */ ar9300_print_keycache, /* ah_print_key_cache */ - +#if ATH_SUPPORT_KEYPLUMB_WAR + ar9300_check_key_cache_entry, /* ah_check_key_cache_entry */ +#endif /* Power Management Functions */ ar9300_set_power_mode, /* ah_set_power_mode */ ar9300_set_sm_power_mode, /* ah_set_sm_ps_mode */ @@ -342,6 +345,8 @@ static const struct ath_hal_private ar9300hal = { /* Get Channel Noise */ ath_hal_get_chan_noise, /* ah_get_chan_noise */ ar9300_chain_noise_floor, /* ah_get_chain_noise_floor */ + ar9300_get_nf_from_reg, /* ah_get_nf_from_reg */ + ar9300_get_rx_nf_offset, /* ah_get_rx_nf_offset */ /* Beacon Functions */ ar9300_beacon_init, /* ah_beacon_init */ @@ -499,11 +504,11 @@ static const struct ath_hal_private ar9300hal = { #else AH_NULL, AH_NULL, - ar9300TX99TgtChannelPwrUpdate, /* ah_tx99channelpwrupdate */ - ar9300TX99TgtStart, /* ah_tx99start */ - ar9300TX99TgtStop, /* ah_tx99stop */ - ar9300TX99TgtChainmskSetup, /* ah_tx99_chainmsk_setup */ - ar9300TX99SetSingleCarrier, /* ah_tx99_set_single_carrier */ + ar9300_tx99_channel_pwr_update, /* ah_tx99channelpwrupdate */ + ar9300_tx99_start, /* ah_tx99start */ + ar9300_tx99_stop, /* ah_tx99stop */ + ar9300_tx99_chainmsk_setup, /* ah_tx99_chainmsk_setup */ + ar9300_tx99_set_single_carrier, /* ah_tx99_set_single_carrier */ #endif #endif ar9300_chk_rssi_update_tx_pwr, @@ -525,6 +530,8 @@ static const struct ath_hal_private ar9300hal = { ar9300_dump_keycache, /* ah_dump_keycache */ ar9300_is_ani_noise_spur, /* ah_is_ani_noise_spur */ ar9300_set_hw_beacon_proc, /* ah_set_hw_beacon_proc */ + ar9300_set_ctl_pwr, /* ah_set_ctl_pwr */ + ar9300_set_txchainmaskopt, /* ah_set_txchainmaskopt */ }, ar9300_get_channel_edges, /* ah_get_channel_edges */ @@ -618,7 +625,8 @@ ar9300_read_revisions(struct ath_hal *ah) */ struct ath_hal * ar9300_attach(u_int16_t devid, HAL_SOFTC sc, HAL_BUS_TAG st, - HAL_BUS_HANDLE sh, uint16_t *eepromdata, HAL_STATUS *status) + HAL_BUS_HANDLE sh, uint16_t *eepromdata, HAL_OPS_CONFIG *ah_config, + HAL_STATUS *status) { struct ath_hal_9300 *ahp; struct ath_hal *ah; @@ -628,7 +636,7 @@ ar9300_attach(u_int16_t devid, HAL_SOFTC sc, HAL_BUS_TAG st, HAL_NO_INTERSPERSED_READS; /* NB: memory is returned zero'd */ - ahp = ar9300_new_state(devid, sc, st, sh, eepromdata, status); + ahp = ar9300_new_state(devid, sc, st, sh, eepromdata, ah_config, status); if (ahp == AH_NULL) { return AH_NULL; } @@ -654,12 +662,6 @@ ar9300_attach(u_int16_t devid, HAL_SOFTC sc, HAL_BUS_TAG st, /* XXX FreeBSD: enable RX mitigation */ ah->ah_config.ath_hal_intr_mitigation_rx = 1; - /* - * XXX what's this do? Check in the qcamain driver code - * as to what it does. - */ - ah->ah_config.ath_hal_ext_atten_margin_cfg = 0; - /* interrupt mitigation */ #ifdef AR5416_INT_MITIGATION if (ah->ah_config.ath_hal_intr_mitigation_rx != 0) { @@ -843,6 +845,18 @@ ar9300_attach(u_int16_t devid, HAL_SOFTC sc, HAL_BUS_TAG st, /* Enable RIFS */ ahp->ah_rifs_enabled = AH_TRUE; + /* by default, stop RX also in abort txdma, due to + "Unable to stop TxDMA" msg observed */ + ahp->ah_abort_txdma_norx = AH_TRUE; + + /* do not use optional tx chainmask by default */ + ahp->ah_tx_chainmaskopt = 0; + + ahp->ah_skip_rx_iq_cal = AH_FALSE; + ahp->ah_rx_cal_complete = AH_FALSE; + ahp->ah_rx_cal_chan = 0; + ahp->ah_rx_cal_chan_flag = 0; + HALDEBUG(ah, HAL_DEBUG_RESET, "%s: This Mac Chip Rev 0x%02x.%x is \n", __func__, ahpriv->ah_macVersion, @@ -2378,7 +2392,9 @@ ar9300_detach(struct ath_hal *ah) struct ath_hal_9300 * ar9300_new_state(u_int16_t devid, HAL_SOFTC sc, HAL_BUS_TAG st, HAL_BUS_HANDLE sh, - uint16_t *eepromdata, HAL_STATUS *status) + uint16_t *eepromdata, + HAL_OPS_CONFIG *ah_config, + HAL_STATUS *status) { static const u_int8_t defbssidmask[IEEE80211_ADDR_LEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; @@ -2430,7 +2446,7 @@ ar9300_new_state(u_int16_t devid, HAL_SOFTC sc, ** Initialize factory defaults in the private space */ // ath_hal_factory_defaults(AH_PRIVATE(ah), hal_conf_parm); - ar9300_config_defaults_freebsd(ah); + ar9300_config_defaults_freebsd(ah, ah_config); /* XXX FreeBSD: cal is always in EEPROM */ #if 0 @@ -2456,6 +2472,7 @@ ar9300_new_state(u_int16_t devid, HAL_SOFTC sc, AH_PRIVATE(ah)->ah_tpScale = HAL_TP_SCALE_MAX; /* no scaling */ ahp->ah_atim_window = 0; /* [0..1000] */ + ahp->ah_diversity_control = ah->ah_config.ath_hal_diversity_control; ahp->ah_antenna_switch_swap = @@ -2934,6 +2951,10 @@ ar9300_fill_capability_info(struct ath_hal *ah) p_cap->halRxUsingLnaMixing = AH_TRUE; } + /* + * AR5416 and later NICs support MYBEACON filtering. + */ + p_cap->halRxDoMyBeacon = AH_TRUE; #if ATH_WOW_OFFLOAD if (AR_SREV_JUPITER_20_OR_LATER(ah) || AR_SREV_APHRODITE(ah)) { @@ -3831,6 +3852,11 @@ ar9300_ant_div_comb_get_config(struct ath_hal *ah, } else { div_comb_conf->antdiv_configgroup = DEFAULT_ANTDIV_CONFIG_GROUP; } + + /* + * XXX TODO: allow the HAL to override the rssithres and fast_div_bias + * values (eg CUS198.) + */ } void @@ -4109,6 +4135,8 @@ ar9300_probe(uint16_t vendorid, uint16_t devid) return "Qualcomm Atheros QCA955x"; case AR9300_DEVID_QCA9565: /* Aphrodite */ return "Qualcomm Atheros AR9565"; + case AR9300_DEVID_AR1111_PCIE: + return "Atheros AR1111"; default: return AH_NULL; } diff --git a/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_beacon.c b/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_beacon.c index 17943a9..f4da88c 100644 --- a/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_beacon.c +++ b/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_beacon.c @@ -34,7 +34,8 @@ extern u_int32_t ar9300_num_tx_pending(struct ath_hal *ah, u_int q); */ void ar9300_beacon_init(struct ath_hal *ah, - u_int32_t next_beacon, u_int32_t beacon_period, HAL_OPMODE opmode) + u_int32_t next_beacon, u_int32_t beacon_period, + u_int32_t beacon_period_fraction, HAL_OPMODE opmode) { u_int32_t beacon_period_usec; @@ -52,6 +53,14 @@ ar9300_beacon_init(struct ath_hal *ah, beacon_period_usec = ONE_EIGHTH_TU_TO_USEC(beacon_period & HAL_BEACON_PERIOD_TU8); + + /* Add the fraction adjustment lost due to unit conversions. */ + beacon_period_usec += beacon_period_fraction; + + HALDEBUG(ah, HAL_DEBUG_BEACON, + "%s: next_beacon=0x%08x, beacon_period=%d, opmode=%d, beacon_period_usec=%d\n", + __func__, next_beacon, beacon_period, opmode, beacon_period_usec); + OS_REG_WRITE(ah, AR_BEACON_PERIOD, beacon_period_usec); OS_REG_WRITE(ah, AR_DMA_BEACON_PERIOD, beacon_period_usec); OS_REG_WRITE(ah, AR_SWBA_PERIOD, beacon_period_usec); diff --git a/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_eeprom.c b/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_eeprom.c index ba7777e..9028ab7 100644 --- a/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_eeprom.c +++ b/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_eeprom.c @@ -1200,6 +1200,44 @@ ar9300_noise_floor_cal_or_power_get(struct ath_hal *ah, int32_t frequency, return nf_use; } +/* + * Return the Rx NF offset for specific channel. + * The values saved in EEPROM/OTP/Flash is converted through the following way: + * ((_p) - NOISE_PWR_DATA_OFFSET) << 2 + * So we need to convert back to the original values. + */ +int ar9300_get_rx_nf_offset(struct ath_hal *ah, struct ieee80211_channel *chan, int8_t *nf_pwr, int8_t *nf_cal) { + HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan); + int8_t rx_nf_pwr, rx_nf_cal; + int i; + //HALASSERT(ichan); + + /* Fill 0 if valid internal channel is not found */ + if (ichan == AH_NULL) { + OS_MEMZERO(nf_pwr, sizeof(nf_pwr[0])*OSPREY_MAX_CHAINS); + OS_MEMZERO(nf_cal, sizeof(nf_cal[0])*OSPREY_MAX_CHAINS); + return -1; + } + + for (i = 0; i < OSPREY_MAX_CHAINS; i++) { + if ((rx_nf_pwr = ar9300_noise_floor_cal_or_power_get(ah, ichan->channel, i, 0)) == 1) { + nf_pwr[i] = 0; + } else { + //printk("%s: raw nf_pwr[%d] = %d\n", __func__, i, rx_nf_pwr); + nf_pwr[i] = NOISE_PWR_DBM_2_INT(rx_nf_pwr); + } + + if ((rx_nf_cal = ar9300_noise_floor_cal_or_power_get(ah, ichan->channel, i, 1)) == 1) { + nf_cal[i] = 0; + } else { + //printk("%s: raw nf_cal[%d] = %d\n", __func__, i, rx_nf_cal); + nf_cal[i] = NOISE_PWR_DBM_2_INT(rx_nf_cal); + } + } + + return 0; +} + int32_t ar9300_rx_gain_index_get(struct ath_hal *ah) { ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom; @@ -1530,6 +1568,61 @@ u_int16_t ar9300_ant_ctrl_chain_get(struct ath_hal *ah, int chain, return 0; } +/* + * Select the usage of antenna via the RF switch. + * Default values are loaded from eeprom. + */ +HAL_BOOL ar9300_ant_swcom_sel(struct ath_hal *ah, u_int8_t ops, + u_int32_t *common_tbl1, u_int32_t *common_tbl2) +{ + ar9300_eeprom_t *eep = &AH9300(ah)->ah_eeprom; + struct ath_hal_private *ap = AH_PRIVATE(ah); + const struct ieee80211_channel *curchan = ap->ah_curchan; + enum { + ANT_SELECT_OPS_GET, + ANT_SELECT_OPS_SET, + }; + + if (AR_SREV_JUPITER(ah) || AR_SREV_SCORPION(ah)) + return AH_FALSE; + + if (!curchan) + return AH_FALSE; + +#define AR_SWITCH_TABLE_COM_ALL (0xffff) +#define AR_SWITCH_TABLE_COM_ALL_S (0) +#define AR_SWITCH_TABLE_COM2_ALL (0xffffff) +#define AR_SWITCH_TABLE_COM2_ALL_S (0) + switch (ops) { + case ANT_SELECT_OPS_GET: + *common_tbl1 = OS_REG_READ_FIELD(ah, AR_PHY_SWITCH_COM, + AR_SWITCH_TABLE_COM_ALL); + *common_tbl2 = OS_REG_READ_FIELD(ah, AR_PHY_SWITCH_COM_2, + AR_SWITCH_TABLE_COM2_ALL); + break; + case ANT_SELECT_OPS_SET: + OS_REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM, + AR_SWITCH_TABLE_COM_ALL, *common_tbl1); + OS_REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM_2, + AR_SWITCH_TABLE_COM2_ALL, *common_tbl2); + + /* write back to eeprom */ + if (IEEE80211_IS_CHAN_2GHZ(curchan)) { + eep->modal_header_2g.ant_ctrl_common = *common_tbl1; + eep->modal_header_2g.ant_ctrl_common2 = *common_tbl2; + } else { + eep->modal_header_5g.ant_ctrl_common = *common_tbl1; + eep->modal_header_5g.ant_ctrl_common2 = *common_tbl2; + } + + break; + default: + break; + } + + return AH_TRUE; +} + HAL_BOOL ar9300_ant_ctrl_apply(struct ath_hal *ah, HAL_BOOL is_2ghz) { u_int32_t value; @@ -1606,6 +1699,7 @@ HAL_BOOL ar9300_ant_ctrl_apply(struct ath_hal *ah, HAL_BOOL is_2ghz) if ( AR_SREV_POSEIDON(ah) && (ahp->ah_lna_div_use_bt_ant_enable == TRUE) ) { value &= ~AR_SWITCH_TABLE_COM2_ALL; value |= ah->ah_config.ath_hal_ant_ctrl_comm2g_switch_enable; + HALDEBUG(ah, HAL_DEBUG_RESET, "%s: com2=0x%08x\n", __func__, value) } #endif /* ATH_ANT_DIV_COMB */ OS_REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM_2, AR_SWITCH_TABLE_COM2_ALL, value); @@ -1711,6 +1805,8 @@ HAL_BOOL ar9300_ant_ctrl_apply(struct ath_hal *ah, HAL_BOOL is_2ghz) /* For WB225, need to swith ANT2 from BT to Wifi * This will not affect HB125 LNA diversity feature. */ + HALDEBUG(ah, HAL_DEBUG_RESET, "%s: com2=0x%08x\n", __func__, + ah->ah_config.ath_hal_ant_ctrl_comm2g_switch_enable) OS_REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM_2, AR_SWITCH_TABLE_COM2_ALL, ah->ah_config.ath_hal_ant_ctrl_comm2g_switch_enable); break; @@ -1776,6 +1872,7 @@ ar9300_attenuation_margin_chain_get(struct ath_hal *ah, int chain, return 0; } +#if 0 HAL_BOOL ar9300_attenuation_apply(struct ath_hal *ah, u_int16_t channel) { u_int32_t value; @@ -1814,6 +1911,75 @@ HAL_BOOL ar9300_attenuation_apply(struct ath_hal *ah, u_int16_t channel) } return 0; } +#endif +HAL_BOOL +ar9300_attenuation_apply(struct ath_hal *ah, u_int16_t channel) +{ + int i; + uint32_t value; + uint32_t ext_atten_reg[3] = { + AR_PHY_EXT_ATTEN_CTL_0, + AR_PHY_EXT_ATTEN_CTL_1, + AR_PHY_EXT_ATTEN_CTL_2 + }; + + /* + * If it's an AR9462 and we're receiving on the second + * chain only, set the chain 0 details from chain 1 + * calibration. + * + * This is from ath9k. + */ + if (AR_SREV_JUPITER(ah) && (AH9300(ah)->ah_rx_chainmask == 0x2)) { + value = ar9300_attenuation_chain_get(ah, 1, channel); + OS_REG_RMW_FIELD(ah, ext_atten_reg[0], + AR_PHY_EXT_ATTEN_CTL_XATTEN1_DB, value); + value = ar9300_attenuation_margin_chain_get(ah, 1, channel); + OS_REG_RMW_FIELD(ah, ext_atten_reg[0], + AR_PHY_EXT_ATTEN_CTL_XATTEN1_MARGIN, value); + } + + /* + * Now, loop over the configured transmit chains and + * load in the attenuation/margin settings as appropriate. + */ + for (i = 0; i < 3; i++) { + if ((AH9300(ah)->ah_tx_chainmask & (1 << i)) == 0) + continue; + + value = ar9300_attenuation_chain_get(ah, i, channel); + OS_REG_RMW_FIELD(ah, ext_atten_reg[i], + AR_PHY_EXT_ATTEN_CTL_XATTEN1_DB, + value); + + if (AR_SREV_POSEIDON(ah) && + (ar9300_rx_gain_index_get(ah) == 0) && + ah->ah_config.ath_hal_ext_atten_margin_cfg) { + value = 5; + } else { + value = ar9300_attenuation_margin_chain_get(ah, 0, + channel); + } + + /* + * I'm not sure why it's loading in this setting into + * the chain 0 margin regardless of the current chain. + */ + if (ah->ah_config.ath_hal_min_gainidx) + OS_REG_RMW_FIELD(ah, + AR_PHY_EXT_ATTEN_CTL_0, + AR_PHY_EXT_ATTEN_CTL_XATTEN1_MARGIN, + value); + + OS_REG_RMW_FIELD(ah, + ext_atten_reg[i], + AR_PHY_EXT_ATTEN_CTL_XATTEN1_MARGIN, + value); + } + + return (0); +} + static u_int16_t ar9300_quick_drop_get(struct ath_hal *ah, int chain, u_int16_t channel) @@ -2339,16 +2505,31 @@ ar9300_eeprom_set_power_per_rate_table( HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan); #endif - tx_chainmask = chainmask ? chainmask : ahp->ah_tx_chainmask; + if (chainmask) + tx_chainmask = chainmask; + else + tx_chainmask = ahp->ah_tx_chainmaskopt ? + ahp->ah_tx_chainmaskopt :ahp->ah_tx_chainmask; ar9300_get_channel_centers(ah, chan, ¢ers); +#if 1 if (IEEE80211_IS_CHAN_2GHZ(chan)) { ahp->twice_antenna_gain = p_eep_data->modal_header_2g.antenna_gain; } else { ahp->twice_antenna_gain = p_eep_data->modal_header_5g.antenna_gain; } +#else + if (IEEE80211_IS_CHAN_2GHZ(chan)) { + ahp->twice_antenna_gain = AH_MAX(p_eep_data->modal_header_2g.antenna_gain, + AH_PRIVATE(ah)->ah_antenna_gain_2g); + } else { + ahp->twice_antenna_gain = AH_MAX(p_eep_data->modal_header_5g.antenna_gain, + AH_PRIVATE(ah)->ah_antenna_gain_5g); + } +#endif + /* Save max allowed antenna gain to ease future lookups */ ahp->twice_antenna_reduction = twice_antenna_reduction; @@ -2885,7 +3066,8 @@ ar9300_eeprom_set_transmit_power(struct ath_hal *ah, } max_power_level = target_power_val_t2[i]; /* Adjusting the ah_max_power_level based on chains and antennaGain*/ - switch (ar9300_get_ntxchains(ahp->ah_tx_chainmask)) + switch (ar9300_get_ntxchains(((ahp->ah_tx_chainmaskopt > 0) ? + ahp->ah_tx_chainmaskopt : ahp->ah_tx_chainmask))) { case 1: break; diff --git a/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_freebsd.c b/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_freebsd.c index 251957e..5bdd74f 100644 --- a/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_freebsd.c +++ b/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_freebsd.c @@ -36,6 +36,9 @@ static HAL_BOOL ar9300ClrMulticastFilterIndex(struct ath_hal *ah, uint32_t ix); static HAL_BOOL ar9300SetMulticastFilterIndex(struct ath_hal *ah, uint32_t ix); +static void ar9300_beacon_set_beacon_timers(struct ath_hal *ah, + const HAL_BEACON_TIMERS *bt); + static void ar9300SetChainMasks(struct ath_hal *ah, uint32_t tx_chainmask, uint32_t rx_chainmask) @@ -60,14 +63,44 @@ ar9300_freebsd_set_tx_power_limit(struct ath_hal *ah, uint32_t limit) return (ar9300_set_tx_power_limit(ah, limit, 0, 0)); } +static uint64_t +ar9300_get_next_tbtt(struct ath_hal *ah) +{ + return (OS_REG_READ(ah, AR_NEXT_TBTT_TIMER)); +} + + +/* + * TODO: implement the antenna diversity control for AR9485 and + * other LNA mixing based NICs. + * + * For now we'll just go with the HAL default and make these no-ops. + */ +static HAL_ANT_SETTING +ar9300_freebsd_get_antenna_switch(struct ath_hal *ah) +{ + + return (HAL_ANT_VARIABLE); +} + +static HAL_BOOL +ar9300_freebsd_set_antenna_switch(struct ath_hal *ah, HAL_ANT_SETTING setting) +{ + + return (AH_TRUE); +} + +static u_int +ar9300_freebsd_get_cts_timeout(struct ath_hal *ah) +{ + u_int clks = MS(OS_REG_READ(ah, AR_TIME_OUT), AR_TIME_OUT_CTS); + return ath_hal_mac_usec(ah, clks); /* convert from system clocks */ +} void ar9300_attach_freebsd_ops(struct ath_hal *ah) { - /* stub everything first */ - ar9300_set_stub_functions(ah); - /* Global functions */ ah->ah_detach = ar9300_detach; ah->ah_getRateTable = ar9300_get_rate_table; @@ -154,8 +187,8 @@ ar9300_attach_freebsd_ops(struct ath_hal *ah) ah->ah_getRfGain = ar9300_get_rfgain; ah->ah_getDefAntenna = ar9300_get_def_antenna; ah->ah_setDefAntenna = ar9300_set_def_antenna; - // ah->ah_getAntennaSwitch = ar9300_get_antenna_switch; - // ah->ah_setAntennaSwitch = ar9300_set_antenna_switch; + ah->ah_getAntennaSwitch = ar9300_freebsd_get_antenna_switch; + ah->ah_setAntennaSwitch = ar9300_freebsd_set_antenna_switch; // ah->ah_setSifsTime = ar9300_set_sifs_time; // ah->ah_getSifsTime = ar9300_get_sifs_time; ah->ah_setSlotTime = ar9300_set_slot_time; @@ -164,6 +197,7 @@ ar9300_attach_freebsd_ops(struct ath_hal *ah) ah->ah_setAckTimeout = ar9300_set_ack_timeout; // XXX ack/ctsrate // XXX CTS timeout + ah->ah_getCTSTimeout = ar9300_freebsd_get_cts_timeout; // XXX decompmask // coverageclass ah->ah_setQuiet = ar9300_set_quiet; @@ -191,10 +225,10 @@ ar9300_attach_freebsd_ops(struct ath_hal *ah) /* Beacon functions */ /* ah_setBeaconTimers */ ah->ah_beaconInit = ar9300_freebsd_beacon_init; - /* ah_setBeaconTimers */ + ah->ah_setBeaconTimers = ar9300_beacon_set_beacon_timers; ah->ah_setStationBeaconTimers = ar9300_set_sta_beacon_timers; /* ah_resetStationBeaconTimers */ - /* ah_getNextTBTT */ + ah->ah_getNextTBTT = ar9300_get_next_tbtt; /* Interrupt functions */ ah->ah_isInterruptPending = ar9300_is_interrupt_pending; @@ -246,12 +280,21 @@ ar9300_attach_freebsd_ops(struct ath_hal *ah) ah->ah_btCoexDisable = ar9300_bt_coex_disable; ah->ah_btCoexEnable = ar9300_bt_coex_enable; + /* MCI bluetooth functions */ + if (AR_SREV_JUPITER(ah) || AR_SREV_APHRODITE(ah)) { + ah->ah_btCoexSetWeights = ar9300_mci_bt_coex_set_weights; + ah->ah_btCoexDisable = ar9300_mci_bt_coex_disable; + ah->ah_btCoexEnable = ar9300_mci_bt_coex_enable; + } + ah->ah_btMciSetup = ar9300_mci_setup; + ah->ah_btMciSendMessage = ar9300_mci_send_message; + ah->ah_btMciGetInterrupt = ar9300_mci_get_interrupt; + ah->ah_btMciGetState = ar9300_mci_state; + ah->ah_btMciDetach = ar9300_mci_detach; + /* LNA diversity functions */ ah->ah_divLnaConfGet = ar9300_ant_div_comb_get_config; ah->ah_divLnaConfSet = ar9300_ant_div_comb_set_config; - - /* Setup HAL configuration defaults */ - ah->ah_config.ath_hal_ant_ctrl_comm2g_switch_enable = 0x000bbb88; } HAL_BOOL @@ -323,11 +366,26 @@ ar9300_ani_poll_freebsd(struct ath_hal *ah, HAL_NODE_STATS stats; HAL_ANISTATS anistats; + HAL_SURVEY_SAMPLE survey; OS_MEMZERO(&stats, sizeof(stats)); OS_MEMZERO(&anistats, sizeof(anistats)); + OS_MEMZERO(&survey, sizeof(survey)); ar9300_ani_ar_poll(ah, &stats, chan, &anistats); + + /* + * If ANI stats are valid, use them to update the + * channel survey. + */ + if (anistats.valid) { + survey.cycle_count = anistats.cyclecnt_diff; + survey.chan_busy = anistats.rxclr_cnt; + survey.ext_chan_busy = anistats.extrxclr_cnt; + survey.tx_busy = anistats.txframecnt_diff; + survey.rx_busy = anistats.rxframecnt_diff; + ath_hal_survey_add_sample(ah, &survey); + } } /* @@ -335,9 +393,11 @@ ar9300_ani_poll_freebsd(struct ath_hal *ah, * wants. */ void -ar9300_config_defaults_freebsd(struct ath_hal *ah) +ar9300_config_defaults_freebsd(struct ath_hal *ah, HAL_OPS_CONFIG *ah_config) { + /* Until FreeBSD's HAL does this by default - just copy */ + OS_MEMCPY(&ah->ah_config, ah_config, sizeof(HAL_OPS_CONFIG)); ah->ah_config.ath_hal_enable_ani = AH_TRUE; } @@ -465,11 +525,13 @@ ar9300_freebsd_setup_x_tx_desc(struct ath_hal *ah, struct ath_desc *ds, u_int txRate3, u_int txTries3) { +#if 0 ath_hal_printf(ah, "%s: called, 0x%x/%d, 0x%x/%d, 0x%x/%d\n", __func__, txRate1, txTries1, txRate2, txTries2, txRate3, txTries3); +#endif /* XXX should only be called during probe */ return (AH_TRUE); @@ -590,8 +652,8 @@ ar9300_freebsd_beacon_init(struct ath_hal *ah, uint32_t next_beacon, uint32_t beacon_period) { - ar9300_beacon_init(ah, AH_PRIVATE(ah)->ah_opmode, - next_beacon, beacon_period); + ar9300_beacon_init(ah, next_beacon, beacon_period, 0, + AH_PRIVATE(ah)->ah_opmode); } HAL_BOOL @@ -653,6 +715,55 @@ ar9300SetMulticastFilterIndex(struct ath_hal *ah, uint32_t ix) return (AH_TRUE); } +#define TU_TO_USEC(_tu) ((_tu) << 10) +#define ONE_EIGHTH_TU_TO_USEC(_tu8) ((_tu8) << 7) + +/* + * Initializes all of the hardware registers used to + * send beacons. Note that for station operation the + * driver calls ar9300_set_sta_beacon_timers instead. + */ +static void +ar9300_beacon_set_beacon_timers(struct ath_hal *ah, + const HAL_BEACON_TIMERS *bt) +{ + uint32_t bperiod; + +#if 0 + HALASSERT(opmode == HAL_M_IBSS || opmode == HAL_M_HOSTAP); + if (opmode == HAL_M_IBSS) { + OS_REG_SET_BIT(ah, AR_TXCFG, AR_TXCFG_ADHOC_BEACON_ATIM_TX_POLICY); + } +#endif + + /* XXX TODO: should migrate the HAL code to always use ONE_EIGHTH_TU */ + OS_REG_WRITE(ah, AR_NEXT_TBTT_TIMER, TU_TO_USEC(bt->bt_nexttbtt)); + OS_REG_WRITE(ah, AR_NEXT_DMA_BEACON_ALERT, ONE_EIGHTH_TU_TO_USEC(bt->bt_nextdba)); + OS_REG_WRITE(ah, AR_NEXT_SWBA, ONE_EIGHTH_TU_TO_USEC(bt->bt_nextswba)); + OS_REG_WRITE(ah, AR_NEXT_NDP_TIMER, TU_TO_USEC(bt->bt_nextatim)); + + bperiod = TU_TO_USEC(bt->bt_intval & HAL_BEACON_PERIOD); + /* XXX TODO! */ +// ahp->ah_beaconInterval = bt->bt_intval & HAL_BEACON_PERIOD; + OS_REG_WRITE(ah, AR_BEACON_PERIOD, bperiod); + OS_REG_WRITE(ah, AR_DMA_BEACON_PERIOD, bperiod); + OS_REG_WRITE(ah, AR_SWBA_PERIOD, bperiod); + OS_REG_WRITE(ah, AR_NDP_PERIOD, bperiod); + + /* + * Reset TSF if required. + */ + if (bt->bt_intval & HAL_BEACON_RESET_TSF) + ar9300_reset_tsf(ah); + + /* enable timers */ + /* NB: flags == 0 handled specially for backwards compatibility */ + OS_REG_SET_BIT(ah, AR_TIMER_MODE, + bt->bt_flags != 0 ? bt->bt_flags : + AR_TBTT_TIMER_EN | AR_DBA_TIMER_EN | AR_SWBA_TIMER_EN); +} + + /* * RF attach stubs */ diff --git a/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_freebsd.h b/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_freebsd.h index c07c32f..524c3f3 100644 --- a/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_freebsd.h +++ b/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_freebsd.h @@ -11,7 +11,8 @@ extern HAL_STATUS ar9300_eeprom_get_freebsd(struct ath_hal *, int param, extern HAL_BOOL ar9300_stop_tx_dma_freebsd(struct ath_hal *ah, u_int q); extern void ar9300_ani_poll_freebsd(struct ath_hal *ah, const struct ieee80211_channel *chan); -extern void ar9300_config_defaults_freebsd(struct ath_hal *ah); +extern void ar9300_config_defaults_freebsd(struct ath_hal *ah, + HAL_OPS_CONFIG *ah_config); extern HAL_BOOL ar9300_stop_dma_receive_freebsd(struct ath_hal *ah); extern HAL_BOOL ar9300_get_pending_interrupts_freebsd(struct ath_hal *ah, HAL_INT *masked); diff --git a/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_freebsd_inc.h b/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_freebsd_inc.h index a159c2c..1af621b 100644 --- a/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_freebsd_inc.h +++ b/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_freebsd_inc.h @@ -35,6 +35,7 @@ #define ATH_SUPPORT_PAPRD 1 #define ATH_SUPPORT_TxBF 0 #define AH_PRIVATE_DIAG 1 +#define ATH_SUPPORT_KEYPLUMB_WAR 0 /* XXX need to reverify these; they came in with qcamain */ #define ATH_SUPPORT_FAST_CC 0 @@ -57,7 +58,9 @@ #ifdef AH_SUPPORT_AR9340 #define AH_SUPPORT_WASP 1 #endif /* AH_SUPPORT_AR9340 */ -//#define AH_SUPPORT_SCORPION 1 +#ifdef AH_SUPPORT_QCA9550 +#define AH_SUPPORT_SCORPION 1 +#endif /* AH_SUPPORT_QCA9550 */ #define FIX_NOISE_FLOOR 1 /* XXX this needs to be removed! No atomics in the HAL! */ diff --git a/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_gpio.c b/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_gpio.c index 5660c1f..1dcdafe 100644 --- a/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_gpio.c +++ b/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_gpio.c @@ -162,7 +162,6 @@ ar9300_gpio_cfg_output( HALASSERT(gpio < AH_PRIVATE(ah)->ah_caps.halNumGpioPins); if ((gpio == AR9382_GPIO_PIN_8_RESERVED) || - (gpio == AR9382_GPIO_PIN_11_RESERVED) || (gpio == AR9382_GPIO_9_INPUT_ONLY)) { return AH_FALSE; @@ -348,7 +347,6 @@ ar9300_gpio_cfg_input(struct ath_hal *ah, u_int32_t gpio) HALASSERT(gpio < AH_PRIVATE(ah)->ah_caps.halNumGpioPins); if ((gpio == AR9382_GPIO_PIN_8_RESERVED) || - (gpio == AR9382_GPIO_PIN_11_RESERVED) || (gpio > AR9382_MAX_GPIO_INPUT_PIN_NUM)) { return AH_FALSE; @@ -378,7 +376,6 @@ ar9300_gpio_set(struct ath_hal *ah, u_int32_t gpio, u_int32_t val) { HALASSERT(gpio < AH_PRIVATE(ah)->ah_caps.halNumGpioPins); if ((gpio == AR9382_GPIO_PIN_8_RESERVED) || - (gpio == AR9382_GPIO_PIN_11_RESERVED) || (gpio == AR9382_GPIO_9_INPUT_ONLY)) { return AH_FALSE; @@ -397,8 +394,7 @@ ar9300_gpio_get(struct ath_hal *ah, u_int32_t gpio) { u_int32_t gpio_in; HALASSERT(gpio < AH_PRIVATE(ah)->ah_caps.halNumGpioPins); - if ((gpio == AR9382_GPIO_PIN_8_RESERVED) || - (gpio == AR9382_GPIO_PIN_11_RESERVED)) + if (gpio == AR9382_GPIO_PIN_8_RESERVED) { return 0xffffffff; } @@ -453,7 +449,6 @@ ar9300_gpio_set_intr(struct ath_hal *ah, u_int gpio, u_int32_t ilevel) HALASSERT(gpio < AH_PRIVATE(ah)->ah_caps.halNumGpioPins); if ((gpio == AR9382_GPIO_PIN_8_RESERVED) || - (gpio == AR9382_GPIO_PIN_11_RESERVED) || (gpio > AR9382_MAX_GPIO_INPUT_PIN_NUM)) { return; @@ -549,8 +544,7 @@ ar9300_gpio_get_mask(struct ath_hal *ah) if (AH_PRIVATE(ah)->ah_devid == AR9300_DEVID_AR9380_PCIE) { mask = (1 << AR9382_MAX_GPIO_PIN_NUM) - 1; - mask &= ~(1 << AR9382_GPIO_PIN_8_RESERVED | - 1 << AR9382_GPIO_PIN_11_RESERVED); + mask &= ~(1 << AR9382_GPIO_PIN_8_RESERVED); } return mask; } @@ -562,8 +556,7 @@ ar9300_gpio_set_mask(struct ath_hal *ah, u_int32_t mask, u_int32_t pol_map) if (AH_PRIVATE(ah)->ah_devid == AR9300_DEVID_AR9380_PCIE) { invalid = ~((1 << AR9382_MAX_GPIO_PIN_NUM) - 1); - invalid |= 1 << AR9382_GPIO_PIN_8_RESERVED | - 1 << AR9382_GPIO_PIN_11_RESERVED; + invalid |= 1 << AR9382_GPIO_PIN_8_RESERVED; } if (mask & invalid) { ath_hal_printf(ah, "%s: invalid GPIO mask 0x%x\n", __func__, mask); diff --git a/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_interrupts.c b/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_interrupts.c index 51ee3cd..acc14b3 100644 --- a/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_interrupts.c +++ b/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_interrupts.c @@ -142,6 +142,21 @@ ar9300_get_pending_interrupts( sync_en_def = AR9340_INTR_SYNC_DEFAULT; } + /* Store away the async and sync cause registers */ + /* XXX Do this before the filtering done below */ +#ifdef AH_INTERRUPT_DEBUGGING + ah->ah_intrstate[0] = OS_REG_READ(ah, AR_ISR); + ah->ah_intrstate[1] = OS_REG_READ(ah, AR_ISR_S0); + ah->ah_intrstate[2] = OS_REG_READ(ah, AR_ISR_S1); + ah->ah_intrstate[3] = OS_REG_READ(ah, AR_ISR_S2); + ah->ah_intrstate[4] = OS_REG_READ(ah, AR_ISR_S3); + ah->ah_intrstate[5] = OS_REG_READ(ah, AR_ISR_S4); + ah->ah_intrstate[6] = OS_REG_READ(ah, AR_ISR_S5); + + /* XXX double reading? */ + ah->ah_syncstate = OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_INTR_SYNC_CAUSE)); +#endif + sync_cause = OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_INTR_SYNC_CAUSE)) & (sync_en_def | AR_INTR_SYNC_MASK_GPIO); diff --git a/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_keycache.c b/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_keycache.c index 8b9a143..0f4fab9 100644 --- a/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_keycache.c +++ b/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_keycache.c @@ -436,3 +436,156 @@ void ar9300_dump_keycache(struct ath_hal *ah, int n, u_int32_t *entry) } #undef AH_KEY_REG_SIZE } + +#if ATH_SUPPORT_KEYPLUMB_WAR +/* + * Check the contents of the specified key cache entry + * and any associated MIC entry. + */ + HAL_BOOL +ar9300_check_key_cache_entry(struct ath_hal *ah, u_int16_t entry, + const HAL_KEYVAL *k, int xorKey) +{ + const HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps; + u_int32_t key0, key1, key2, key3, key4; + u_int32_t keyType; + u_int32_t xorMask = xorKey ? + (KEY_XOR << 24 | KEY_XOR << 16 | KEY_XOR << 8 | KEY_XOR) : 0; + struct ath_hal_9300 *ahp = AH9300(ah); + + + if (entry >= pCap->hal_key_cache_size) { + HALDEBUG(ah, HAL_DEBUG_KEYCACHE, + "%s: entry %u out of range\n", __func__, entry); + return AH_FALSE; + } + switch (k->kv_type) { + case HAL_CIPHER_AES_OCB: + keyType = AR_KEYTABLE_TYPE_AES; + break; + case HAL_CIPHER_AES_CCM: + if (!pCap->hal_cipher_aes_ccm_support) { + HALDEBUG(ah, HAL_DEBUG_KEYCACHE, "%s: AES-CCM not supported by " + "mac rev 0x%x\n", + __func__, AH_PRIVATE(ah)->ah_macRev); + return AH_FALSE; + } + keyType = AR_KEYTABLE_TYPE_CCM; + break; + case HAL_CIPHER_TKIP: + keyType = AR_KEYTABLE_TYPE_TKIP; + if (IS_MIC_ENABLED(ah) && entry + 64 >= pCap->hal_key_cache_size) { + HALDEBUG(ah, HAL_DEBUG_KEYCACHE, + "%s: entry %u inappropriate for TKIP\n", + __func__, entry); + return AH_FALSE; + } + break; + case HAL_CIPHER_WEP: + if (k->kv_len < 40 / NBBY) { + HALDEBUG(ah, HAL_DEBUG_KEYCACHE, "%s: WEP key length %u too small\n", + __func__, k->kv_len); + return AH_FALSE; + } + if (k->kv_len <= 40 / NBBY) { + keyType = AR_KEYTABLE_TYPE_40; + } else if (k->kv_len <= 104 / NBBY) { + keyType = AR_KEYTABLE_TYPE_104; + } else { + keyType = AR_KEYTABLE_TYPE_128; + } + break; + case HAL_CIPHER_CLR: + keyType = AR_KEYTABLE_TYPE_CLR; + return AH_TRUE; + default: + HALDEBUG(ah, HAL_DEBUG_KEYCACHE, "%s: cipher %u not supported\n", + __func__, k->kv_type); + return AH_TRUE; + } + + key0 = LE_READ_4(k->kv_val + 0) ^ xorMask; + key1 = (LE_READ_2(k->kv_val + 4) ^ xorMask) & 0xffff; + key2 = LE_READ_4(k->kv_val + 6) ^ xorMask; + key3 = (LE_READ_2(k->kv_val + 10) ^ xorMask) & 0xffff; + key4 = LE_READ_4(k->kv_val + 12) ^ xorMask; + if (k->kv_len <= 104 / NBBY) { + key4 &= 0xff; + } + + /* + * Note: key cache hardware requires that each double-word + * pair be written in even/odd order (since the destination is + * a 64-bit register). Don't reorder these writes w/o + * considering this! + */ + if (keyType == AR_KEYTABLE_TYPE_TKIP && IS_MIC_ENABLED(ah)) { + u_int16_t micentry = entry + 64; /* MIC goes at slot+64 */ + + + /* + * Invalidate the encrypt/decrypt key until the MIC + * key is installed so pending rx frames will fail + * with decrypt errors rather than a MIC error. + */ + if ((OS_REG_READ(ah, AR_KEYTABLE_KEY0(entry)) == key0) && + (OS_REG_READ(ah, AR_KEYTABLE_KEY1(entry)) == key1) && + (OS_REG_READ(ah, AR_KEYTABLE_KEY2(entry)) == key2) && + (OS_REG_READ(ah, AR_KEYTABLE_KEY3(entry)) == key3) && + (OS_REG_READ(ah, AR_KEYTABLE_KEY4(entry)) == key4) && + ((OS_REG_READ(ah, AR_KEYTABLE_TYPE(entry)) & AR_KEY_TYPE) == (keyType & AR_KEY_TYPE))) + { + + /* + * since the AR_MISC_MODE register was written with the contents of + * ah_miscMode (if any) in ar9300Attach, just check ah_miscMode and + * save a pci read per key set. + */ + if (ahp->ah_misc_mode & AR_PCU_MIC_NEW_LOC_ENA) { + u_int32_t mic0,mic1,mic2,mic3,mic4; + /* + * both RX and TX mic values can be combined into + * one cache slot entry. + * 8*N + 800 31:0 RX Michael key 0 + * 8*N + 804 15:0 TX Michael key 0 [31:16] + * 8*N + 808 31:0 RX Michael key 1 + * 8*N + 80C 15:0 TX Michael key 0 [15:0] + * 8*N + 810 31:0 TX Michael key 1 + * 8*N + 814 15:0 reserved + * 8*N + 818 31:0 reserved + * 8*N + 81C 14:0 reserved + * 15 key valid == 0 + */ + /* RX mic */ + mic0 = LE_READ_4(k->kv_mic + 0); + mic2 = LE_READ_4(k->kv_mic + 4); + /* TX mic */ + mic1 = LE_READ_2(k->kv_txmic + 2) & 0xffff; + mic3 = LE_READ_2(k->kv_txmic + 0) & 0xffff; + mic4 = LE_READ_4(k->kv_txmic + 4); + if ((OS_REG_READ(ah, AR_KEYTABLE_KEY0(micentry)) == mic0) && + (OS_REG_READ(ah, AR_KEYTABLE_KEY1(micentry)) == mic1) && + (OS_REG_READ(ah, AR_KEYTABLE_KEY2(micentry)) == mic2) && + (OS_REG_READ(ah, AR_KEYTABLE_KEY3(micentry)) == mic3) && + (OS_REG_READ(ah, AR_KEYTABLE_KEY4(micentry)) == mic4) && + ((OS_REG_READ(ah, AR_KEYTABLE_TYPE(micentry)) & AR_KEY_TYPE) == (AR_KEYTABLE_TYPE_CLR & AR_KEY_TYPE))) { + return AH_TRUE; + } + + } else { + return AH_TRUE; + } + } + } else { + if ((OS_REG_READ(ah, AR_KEYTABLE_KEY0(entry)) == key0) && + (OS_REG_READ(ah, AR_KEYTABLE_KEY1(entry)) == key1) && + (OS_REG_READ(ah, AR_KEYTABLE_KEY2(entry)) == key2) && + (OS_REG_READ(ah, AR_KEYTABLE_KEY3(entry)) == key3) && + (OS_REG_READ(ah, AR_KEYTABLE_KEY4(entry)) == key4) && + ((OS_REG_READ(ah, AR_KEYTABLE_TYPE(entry)) & AR_KEY_TYPE) == (keyType & AR_KEY_TYPE))) { + return AH_TRUE; + } + } + return AH_FALSE; +} +#endif diff --git a/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_misc.c b/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_misc.c index a0722b7..e9caa43 100644 --- a/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_misc.c +++ b/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_misc.c @@ -683,6 +683,7 @@ ar9300_get_capability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type, { struct ath_hal_9300 *ahp = AH9300(ah); const HAL_CAPABILITIES *p_cap = &AH_PRIVATE(ah)->ah_caps; + struct ar9300_ani_state *ani; switch (type) { case HAL_CAP_CIPHER: /* cipher handled in hardware */ @@ -911,6 +912,34 @@ ar9300_get_capability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type, return HAL_ENOTSUPP; } #endif + + /* FreeBSD ANI */ + case HAL_CAP_INTMIT: /* interference mitigation */ + switch (capability) { + case HAL_CAP_INTMIT_PRESENT: /* hardware capability */ + return HAL_OK; + case HAL_CAP_INTMIT_ENABLE: + return (ahp->ah_proc_phy_err & HAL_PROCESS_ANI) ? + HAL_OK : HAL_ENXIO; + case HAL_CAP_INTMIT_NOISE_IMMUNITY_LEVEL: + case HAL_CAP_INTMIT_OFDM_WEAK_SIGNAL_LEVEL: +// case HAL_CAP_INTMIT_CCK_WEAK_SIGNAL_THR: + case HAL_CAP_INTMIT_FIRSTEP_LEVEL: + case HAL_CAP_INTMIT_SPUR_IMMUNITY_LEVEL: + ani = ar9300_ani_get_current_state(ah); + if (ani == AH_NULL) + return HAL_ENXIO; + switch (capability) { + /* XXX AR9300 HAL has OFDM/CCK noise immunity level params? */ + case 2: *result = ani->ofdm_noise_immunity_level; break; + case 3: *result = !ani->ofdm_weak_sig_detect_off; break; + // case 4: *result = ani->cck_weak_sig_threshold; break; + case 5: *result = ani->firstep_level; break; + case 6: *result = ani->spur_immunity_level; break; + } + return HAL_OK; + } + return HAL_EINVAL; default: return ath_hal_getcapability(ah, type, capability, result); } @@ -986,6 +1015,27 @@ ar9300_set_capability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type, return AH_TRUE; } return AH_FALSE; + + /* FreeBSD interrupt mitigation / ANI */ + case HAL_CAP_INTMIT: { /* interference mitigation */ + /* This maps the public ANI commands to the internal ANI commands */ + /* Private: HAL_ANI_CMD; Public: HAL_CAP_INTMIT_CMD */ + static const HAL_ANI_CMD cmds[] = { + HAL_ANI_PRESENT, + HAL_ANI_MODE, + HAL_ANI_NOISE_IMMUNITY_LEVEL, + HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, + HAL_ANI_CCK_WEAK_SIGNAL_THR, + HAL_ANI_FIRSTEP_LEVEL, + HAL_ANI_SPUR_IMMUNITY_LEVEL, + }; +#define N(a) (sizeof(a) / sizeof(a[0])) + return capability < N(cmds) ? + ar9300_ani_control(ah, cmds[capability], setting) : + AH_FALSE; +#undef N + } + case HAL_CAP_RXBUFSIZE: /* set MAC receive buffer size */ ahp->rx_buf_size = setting & AR_DATABUF_MASK; OS_REG_WRITE(ah, AR_DATABUF, ahp->rx_buf_size); @@ -1129,6 +1179,7 @@ ar9300_get_diag_state(struct ath_hal *ah, int request, void **result, u_int32_t *resultsize) { struct ath_hal_9300 *ahp = AH9300(ah); + struct ar9300_ani_state *ani; (void) ahp; if (ath_hal_getdiagstate(ah, request, args, argsize, result, resultsize)) { @@ -1169,14 +1220,35 @@ ar9300_get_diag_state(struct ath_hal *ah, int request, return AH_TRUE; #endif case HAL_DIAG_ANI_CURRENT: + + ani = ar9300_ani_get_current_state(ah); + if (ani == AH_NULL) + return AH_FALSE; + /* Convert ar9300 HAL to FreeBSD HAL ANI state */ + /* XXX TODO: add all of these to the HAL ANI state structure */ + bzero(&ahp->ext_ani_state, sizeof(ahp->ext_ani_state)); + /* XXX should this be OFDM or CCK noise immunity level? */ + ahp->ext_ani_state.noiseImmunityLevel = ani->ofdm_noise_immunity_level; + ahp->ext_ani_state.spurImmunityLevel = ani->spur_immunity_level; + ahp->ext_ani_state.firstepLevel = ani->firstep_level; + ahp->ext_ani_state.ofdmWeakSigDetectOff = ani->ofdm_weak_sig_detect_off; + /* mrc_cck_off */ + /* cck_noise_immunity_level */ + + ahp->ext_ani_state.listenTime = ani->listen_time; + + *result = &ahp->ext_ani_state; + *resultsize = sizeof(ahp->ext_ani_state); +#if 0 *result = ar9300_ani_get_current_state(ah); *resultsize = (*result == AH_NULL) ? 0 : sizeof(struct ar9300_ani_state); +#endif return AH_TRUE; case HAL_DIAG_ANI_STATS: *result = ar9300_ani_get_current_stats(ah); *resultsize = (*result == AH_NULL) ? - 0 : sizeof(struct ar9300_stats); + 0 : sizeof(HAL_ANI_STATS); return AH_TRUE; case HAL_DIAG_ANI_CMD: if (argsize != 2*sizeof(u_int32_t)) { @@ -1697,10 +1769,10 @@ ar9300_get_bb_panic_info(struct ath_hal *ah, struct hal_bb_panic_info *bb_panic) /* Suppress BB Status mesg following signature */ switch (bb_panic->status) { - case 0x04000539: - case 0x04008009: - case 0x04000b09: - case 0x1300000a: + case 0x04000539: + case 0x04008009: + case 0x04000b09: + case 0x1300000a: return -1; } @@ -3718,8 +3790,6 @@ ar9300_tx99_start(struct ath_hal *ah, u_int8_t *data) /* Disable AGC to A2 */ OS_REG_WRITE(ah, AR_PHY_TEST, (OS_REG_READ(ah, AR_PHY_TEST) | PHY_AGC_CLR)); - OS_REG_WRITE(ah, 0x9864, OS_REG_READ(ah, 0x9864) | 0x7f000); - OS_REG_WRITE(ah, 0x9924, OS_REG_READ(ah, 0x9924) | 0x7f00fe); OS_REG_WRITE(ah, AR_DIAG_SW, OS_REG_READ(ah, AR_DIAG_SW) &~ AR_DIAG_RX_DIS); OS_REG_WRITE(ah, AR_CR, AR_CR_RXD); /* set receive disable */ @@ -3763,3 +3833,47 @@ ar9300SetDfs3StreamFix(struct ath_hal *ah, u_int32_t val) { return AH_FALSE; } + +HAL_BOOL +ar9300_set_ctl_pwr(struct ath_hal *ah, u_int8_t *ctl_array) +{ + struct ath_hal_9300 *ahp = AH9300(ah); + ar9300_eeprom_t *p_eep_data = &ahp->ah_eeprom; + u_int8_t *ctl_index; + u_int32_t offset = 0; + + if (!ctl_array) + return AH_FALSE; + + /* copy 2G ctl freqbin and power data */ + ctl_index = p_eep_data->ctl_index_2g; + OS_MEMCPY(ctl_index + OSPREY_NUM_CTLS_2G, ctl_array, + OSPREY_NUM_CTLS_2G * OSPREY_NUM_BAND_EDGES_2G + /* ctl_freqbin_2G */ + OSPREY_NUM_CTLS_2G * sizeof(OSP_CAL_CTL_DATA_2G)); /* ctl_power_data_2g */ + offset = (OSPREY_NUM_CTLS_2G * OSPREY_NUM_BAND_EDGES_2G) + + ( OSPREY_NUM_CTLS_2G * sizeof(OSP_CAL_CTL_DATA_2G)); + + + /* copy 2G ctl freqbin and power data */ + ctl_index = p_eep_data->ctl_index_5g; + OS_MEMCPY(ctl_index + OSPREY_NUM_CTLS_5G, ctl_array + offset, + OSPREY_NUM_CTLS_5G * OSPREY_NUM_BAND_EDGES_5G + /* ctl_freqbin_5G */ + OSPREY_NUM_CTLS_5G * sizeof(OSP_CAL_CTL_DATA_5G)); /* ctl_power_data_5g */ + + return AH_FALSE; +} + +void +ar9300_set_txchainmaskopt(struct ath_hal *ah, u_int8_t mask) +{ + struct ath_hal_9300 *ahp = AH9300(ah); + + /* optional txchainmask should be subset of primary txchainmask */ + if ((mask & ahp->ah_tx_chainmask) != mask) { + ahp->ah_tx_chainmaskopt = 0; + ath_hal_printf(ah, "Error: ah_tx_chainmask=%d, mask=%d\n", ahp->ah_tx_chainmask, mask); + return; + } + + ahp->ah_tx_chainmaskopt = mask; +} diff --git a/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_osprey22.ini b/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_osprey22.ini index 9814dab..fffaf7a 100644 --- a/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_osprey22.ini +++ b/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_osprey22.ini @@ -881,7 +881,7 @@ static const u_int32_t ar9300_osprey_2p2_mac_core[][2] = { { 0x00008258 , 0x00000000 }, { 0x0000825c , 0x40000000 }, { 0x00008260 , 0x00080922 }, - { 0x00008264 , 0x9bc00010 }, + { 0x00008264 , 0x9d400010 }, { 0x00008268 , 0xffffffff }, { 0x0000826c , 0x0000ffff }, { 0x00008270 , 0x00000000 }, @@ -1171,7 +1171,7 @@ static const u_int32_t ar9300_osprey_2p2_mac_postamble[][5] = { { 0x000010b0 , 0x00000e60 , 0x00001cc0 , 0x00007c70 , 0x00003e38 }, { 0x00008014 , 0x03e803e8 , 0x07d007d0 , 0x10801600 , 0x08400b00 }, { 0x0000801c , 0x128d8027 , 0x128d804f , 0x12e00057 , 0x12e0002b }, - { 0x00008120 , 0x08f04800 , 0x08f04800 , 0x08f04810 , 0x08f04810 }, + { 0x00008120 , 0x18f04800 , 0x18f04800 , 0x18f04810 , 0x18f04810 }, { 0x000081d0 , 0x00003210 , 0x00003210 , 0x0000320a , 0x0000320a }, { 0x00008318 , 0x00003e80 , 0x00007d00 , 0x00006880 , 0x00003440 }, }; diff --git a/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_power.c b/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_power.c index 44bebe4..2a8f7f8 100644 --- a/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_power.c +++ b/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_power.c @@ -469,7 +469,7 @@ u_int32_t ar9300_wow_offload_handshake(struct ath_hal *ah, u_int32_t pattern_ena OS_REG_SET_BIT(ah, AR_MBOX_CTRL_STATUS, AR_MBOX_WOW_REQ); OS_REG_SET_BIT(ah, AR_MBOX_CTRL_STATUS, AR_MBOX_INT_EMB_CPU); - if (!ath_hal_wait(ah, AR_MBOX_CTRL_STATUS, AR_MBOX_WOW_CONF, AR_MBOX_WOW_CONF, bt_handshake_timeout_us)) { + if (!ath_hal_waitfor(ah, AR_MBOX_CTRL_STATUS, AR_MBOX_WOW_CONF, AR_MBOX_WOW_CONF, bt_handshake_timeout_us)) { HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "%s: WoW offload handshake failed", __func__); return 0; } @@ -666,15 +666,19 @@ ar9300_set_power_mode(struct ath_hal *ah, HAL_POWER_MODE mode, int set_chip) HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: %s -> %s (%s)\n", __func__, modes[ar9300_get_power_mode(ah)], modes[mode], set_chip ? "set chip " : ""); + OS_MARK(ah, AH_MARK_CHIP_POWER, mode); switch (mode) { case HAL_PM_AWAKE: + if (set_chip) + ah->ah_powerMode = mode; status = ar9300_set_power_mode_awake(ah, set_chip); #if ATH_SUPPORT_MCI if (AH_PRIVATE(ah)->ah_caps.halMciSupport) { OS_REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2); } #endif + ahp->ah_chip_full_sleep = AH_FALSE; break; case HAL_PM_FULL_SLEEP: #if ATH_SUPPORT_MCI @@ -698,7 +702,10 @@ ar9300_set_power_mode(struct ath_hal *ah, HAL_POWER_MODE mode, int set_chip) } #endif ar9300_set_power_mode_sleep(ah, set_chip); - ahp->ah_chip_full_sleep = AH_TRUE; + if (set_chip) { + ahp->ah_chip_full_sleep = AH_TRUE; + ah->ah_powerMode = mode; + } break; case HAL_PM_NETWORK_SLEEP: #if ATH_SUPPORT_MCI @@ -707,12 +714,17 @@ ar9300_set_power_mode(struct ath_hal *ah, HAL_POWER_MODE mode, int set_chip) } #endif ar9300_set_power_mode_network_sleep(ah, set_chip); + if (set_chip) { + ah->ah_powerMode = mode; + } break; default: HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: unknown power mode %u\n", __func__, mode); + OS_MARK(ah, AH_MARK_CHIP_POWER_DONE, -1); return AH_FALSE; } + OS_MARK(ah, AH_MARK_CHIP_POWER_DONE, status); return status; } @@ -976,7 +988,7 @@ ar9300_set_power_mode_wow_sleep(struct ath_hal *ah) OS_REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); OS_REG_WRITE(ah, AR_CR, AR_CR_RXD); /* Set receive disable bit */ - if (!ath_hal_wait(ah, AR_CR, AR_CR_RXE, 0, AH_WAIT_TIMEOUT)) { + if (!ath_hal_waitfor(ah, AR_CR, AR_CR_RXE, 0, AH_WAIT_TIMEOUT)) { HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: dma failed to stop in 10ms\n" "AR_CR=0x%08x\nAR_DIAG_SW=0x%08x\n", __func__, OS_REG_READ(ah, AR_CR), OS_REG_READ(ah, AR_DIAG_SW)); diff --git a/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_recv.c b/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_recv.c index e13c00b..c919d3c 100644 --- a/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_recv.c +++ b/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_recv.c @@ -113,6 +113,8 @@ ar9300_stop_dma_receive(struct ath_hal *ah, u_int timeout) #define AH_RX_STOP_DMA_TIMEOUT 10000 /* usec */ #define AH_TIME_QUANTUM 100 /* usec */ + OS_MARK(ah, AH_MARK_RX_CTL, AH_MARK_RX_CTL_DMA_STOP); + if (timeout == 0) { timeout = AH_RX_STOP_DMA_TIMEOUT; } @@ -157,6 +159,9 @@ ar9300_stop_dma_receive(struct ath_hal *ah, u_int timeout) OS_REG_WRITE(ah, AR_MACMISC, org_value); + OS_MARK(ah, AH_MARK_RX_CTL, + status ? AH_MARK_RX_CTL_DMA_STOP_OK : AH_MARK_RX_CTL_DMA_STOP_ERR); + return status; #undef AH_RX_STOP_DMA_TIMEOUT #undef AH_TIME_QUANTUM diff --git a/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_recv_ds.c b/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_recv_ds.c index a83099e..d4065d8 100644 --- a/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_recv_ds.c +++ b/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_recv_ds.c @@ -68,6 +68,7 @@ ar9300_proc_rx_desc_fast(struct ath_hal *ah, struct ath_desc *ds, rxs->rs_status = 0; rxs->rs_flags = 0; + rxs->rs_phyerr = 0; rxs->rs_datalen = rxsp->status2 & AR_data_len; rxs->rs_tstamp = rxsp->status3; @@ -129,17 +130,16 @@ ar9300_proc_rx_desc_fast(struct ath_hal *ah, struct ath_desc *ds, * Consequently we filter them out here so we don't * confuse and/or complicate drivers. */ + if (rxsp->status11 & AR_crc_err) { rxs->rs_status |= HAL_RXERR_CRC; /* - * ignore CRC flag for spectral phy reports + * ignore CRC flag for phy reports */ if (rxsp->status11 & AR_phyerr) { u_int phyerr = MS(rxsp->status11, AR_phy_err_code); - if (phyerr == HAL_PHYERR_SPECTRAL) { - rxs->rs_status |= HAL_RXERR_PHY; - rxs->rs_phyerr = phyerr; - } + rxs->rs_status |= HAL_RXERR_PHY; + rxs->rs_phyerr = phyerr; } } else if (rxsp->status11 & AR_phyerr) { u_int phyerr; @@ -165,7 +165,9 @@ ar9300_proc_rx_desc_fast(struct ath_hal *ah, struct ath_desc *ds, rxs->rs_status |= HAL_RXERR_MIC; } } - +#if 0 + rxs->rs_channel = AH_PRIVATE(ah)->ah_curchan->channel; +#endif return HAL_OK; } diff --git a/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_reset.c b/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_reset.c index 642aba1..01845b9 100644 --- a/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_reset.c +++ b/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_reset.c @@ -31,7 +31,6 @@ #define FIX_NOISE_FLOOR 1 - /* Additional Time delay to wait after activiting the Base band */ #define BASE_ACTIVATE_DELAY 100 /* usec */ #define RTC_PLL_SETTLE_DELAY 100 /* usec */ @@ -325,6 +324,7 @@ int16_t ar9300_get_min_cca_pwr(struct ath_hal *ah) int16_t nf; // struct ath_hal_private *ahpriv = AH_PRIVATE(ah); + if ((OS_REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) == 0) { nf = MS(OS_REG_READ(ah, AR_PHY_CCA_0), AR9280_PHY_MINCCA_PWR); if (nf & 0x100) { @@ -402,6 +402,33 @@ void ar9300_chain_noise_floor(struct ath_hal *ah, int16_t *nf_buf, } } +/* + * Return the current NF value in register. + * If the current NF cal is not completed, return 0. + */ +int16_t ar9300_get_nf_from_reg(struct ath_hal *ah, struct ieee80211_channel *chan, int wait_time) +{ + int16_t nfarray[HAL_NUM_NF_READINGS] = {0}; + int is_2g = 0; + HAL_CHANNEL_INTERNAL *ichan = NULL; + + ichan = ath_hal_checkchannel(ah, chan); + if (ichan == NULL) + return (0); + + if (wait_time <= 0) { + return 0; + } + + if (!ath_hal_waitfor(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF, 0, wait_time)) { + ath_hal_printf(ah, "%s: NF cal is not complete in %dus", __func__, wait_time); + return 0; + } + is_2g = !! (IS_CHAN_2GHZ(ichan)); + ar9300_upload_noise_floor(ah, is_2g, nfarray); + + return nfarray[0]; +} /* * Pick up the medium one in the noise floor buffer and update the @@ -415,6 +442,7 @@ ar9300_get_nf_hist_mid(struct ath_hal *ah, HAL_NFCAL_HIST_FULL *h, int reading, int16_t sort[HAL_NF_CAL_HIST_LEN_FULL]; /* upper bound for hist_len */ int i, j; + for (i = 0; i < hist_len; i++) { sort[i] = h->nf_cal_buffer[i][reading]; HALDEBUG(ah, HAL_DEBUG_NFCAL, @@ -451,7 +479,7 @@ ar9300_reset_nf_hist_buff(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *ichan) HAL_CHAN_NFCAL_HIST *h = &ichan->nf_cal_hist; HAL_NFCAL_HIST_FULL *home = &AH_PRIVATE(ah)->nf_cal_hist; int i; - + /* * Copy the value for the channel in question into the home-channel * NF history buffer. The channel NF is probably a value filled in by @@ -538,6 +566,7 @@ get_noise_floor_thresh(struct ath_hal *ah, const HAL_CHANNEL_INTERNAL *chan, { struct ath_hal_9300 *ahp = AH9300(ah); + switch (chan->channel_flags & CHANNEL_ALL_NOTURBO) { case CHANNEL_A: case CHANNEL_A_HT20: @@ -1332,7 +1361,7 @@ ar9300_set_operating_mode(struct ath_hal *ah, int opmode) } /* XXX need the logic for Osprey */ -inline void +void ar9300_init_pll(struct ath_hal *ah, struct ieee80211_channel *chan) { u_int32_t pll; @@ -1609,6 +1638,7 @@ ar9300_set_reset(struct ath_hal *ah, int type) { u_int32_t rst_flags; u_int32_t tmp_reg; + struct ath_hal_9300 *ahp = AH9300(ah); HALASSERT(type == HAL_RESET_WARM || type == HAL_RESET_COLD); @@ -1802,6 +1832,7 @@ ar9300_set_reset(struct ath_hal *ah, int type) ar9300_attach_hw_platform(ah); + ahp->ah_chip_reset_done = 1; return AH_TRUE; } @@ -1987,13 +2018,25 @@ HAL_BOOL ar9300_chip_reset(struct ath_hal *ah, struct ieee80211_channel *chan) { struct ath_hal_9300 *ahp = AH9300(ah); + int type = HAL_RESET_WARM; OS_MARK(ah, AH_MARK_CHIPRESET, chan ? chan->ic_freq : 0); /* * Warm reset is optimistic. + * + * If the TX/RX DMA engines aren't shut down (eg, they're + * wedged) then we're better off doing a full cold reset + * to try and shake that condition. */ - if (!ar9300_set_reset_reg(ah, HAL_RESET_WARM)) { + if (ahp->ah_chip_full_sleep || + (ah->ah_config.ah_force_full_reset == 1) || + OS_REG_READ(ah, AR_Q_TXE) || + (OS_REG_READ(ah, AR_CR) & AR_CR_RXE)) { + type = HAL_RESET_COLD; + } + + if (!ar9300_set_reset_reg(ah, type)) { return AH_FALSE; } @@ -2300,10 +2343,22 @@ ar9300_per_calibration(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *ichan, static void ar9300_start_nf_cal(struct ath_hal *ah) { + struct ath_hal_9300 *ahp = AH9300(ah); OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_ENABLE_NF); OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NO_UPDATE_NF); OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF); AH9300(ah)->nf_tsf32 = ar9300_get_tsf32(ah); + +/* + * We are reading the NF values before we start the NF operation, because + * of that we are getting very high values like -45. + * This triggers the CW_INT detected and EACS module triggers the channel change + * chip_reset_done value is used to fix this issue. + * chip_reset_flag is set during the RTC reset. + * chip_reset_flag is cleared during the starting NF operation. + * if flag is set we will clear the flag and will not read the NF values. + */ + ahp->ah_chip_reset_done = 0; } /* ar9300_calibration @@ -2397,7 +2452,7 @@ ar9300_calibration(struct ath_hal *ah, struct ieee80211_channel *chan, u_int8_t ar9300_load_nf(ah, nf_buf); /* start NF calibration, without updating BB NF register*/ - ar9300_start_nf_cal(ah); + ar9300_start_nf_cal(ah); } } return AH_TRUE; @@ -2447,12 +2502,15 @@ ar9300_iq_calibration(struct ath_hal *ah, u_int8_t num_chains) u_int32_t q_coff_denom, i_coff_denom; int32_t q_coff, i_coff; int iq_corr_neg, i; + HAL_CHANNEL_INTERNAL *ichan; static const u_int32_t offset_array[3] = { AR_PHY_RX_IQCAL_CORR_B0, AR_PHY_RX_IQCAL_CORR_B1, AR_PHY_RX_IQCAL_CORR_B2, }; + ichan = ath_hal_checkchannel(ah, AH_PRIVATE(ah)->ah_curchan); + for (i = 0; i < num_chains; i++) { power_meas_i = ahp->ah_total_power_meas_i[i]; power_meas_q = ahp->ah_total_power_meas_q[i]; @@ -2525,6 +2583,19 @@ ar9300_iq_calibration(struct ath_hal *ah, u_int8_t num_chains) OS_REG_RMW_FIELD(ah, offset_array[i], AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF, q_coff); + /* store the RX cal results */ + if (ichan != NULL) { + ahp->ah_rx_cal_corr[i] = OS_REG_READ(ah, offset_array[i]) & 0x7fff; + ahp->ah_rx_cal_complete = AH_TRUE; + ahp->ah_rx_cal_chan = ichan->channel; +// ahp->ah_rx_cal_chan_flag = ichan->channel_flags &~ CHANNEL_PASSIVE; + ahp->ah_rx_cal_chan_flag = 0; /* XXX */ + } else { + /* XXX? Is this what I should do? */ + ahp->ah_rx_cal_complete = AH_FALSE; + + } + HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "Register offset (0x%04x) QI COFF (bitfields 0x%08x) " "after update = 0x%x\n", @@ -2551,6 +2622,55 @@ ar9300_iq_calibration(struct ath_hal *ah, u_int8_t num_chains) } /* + * When coming back from offchan, we do not perform RX IQ Cal. + * But the chip reset will clear all previous results + * We store the previous results and restore here. + */ +static void +ar9300_rx_iq_cal_restore(struct ath_hal *ah) +{ + struct ath_hal_9300 *ahp = AH9300(ah); + u_int32_t i_coff, q_coff; + HAL_BOOL is_restore = AH_FALSE; + int i; + static const u_int32_t offset_array[3] = { + AR_PHY_RX_IQCAL_CORR_B0, + AR_PHY_RX_IQCAL_CORR_B1, + AR_PHY_RX_IQCAL_CORR_B2, + }; + + for (i=0; i<AR9300_MAX_CHAINS; i++) { + if (ahp->ah_rx_cal_corr[i]) { + i_coff = (ahp->ah_rx_cal_corr[i] & + AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF) >> + AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF_S; + q_coff = (ahp->ah_rx_cal_corr[i] & + AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF) >> + AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF_S; + + OS_REG_RMW_FIELD(ah, offset_array[i], + AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF, i_coff); + OS_REG_RMW_FIELD(ah, offset_array[i], + AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF, q_coff); + + is_restore = AH_TRUE; + } + } + + if (is_restore) + OS_REG_SET_BIT(ah, + AR_PHY_RX_IQCAL_CORR_B0, AR_PHY_RX_IQCAL_CORR_IQCORR_ENABLE); + + HALDEBUG(ah, HAL_DEBUG_CALIBRATE, + "%s: IQ Cal and Correction (offset 0x%04x) enabled " + "(bit position 0x%08x). New Value 0x%08x\n", + __func__, + (unsigned) (AR_PHY_RX_IQCAL_CORR_B0), + AR_PHY_RX_IQCAL_CORR_IQCORR_ENABLE, + OS_REG_READ(ah, AR_PHY_RX_IQCAL_CORR_B0)); +} + +/* * Set a limit on the overall output power. Used for dynamic * transmit power control and the like. * @@ -3727,6 +3847,13 @@ ar9300_init_cal_internal(struct ath_hal *ah, struct ieee80211_channel *chan, #endif /* end - Init time calibrations */ + /* Do not do RX cal in case of offchan, or cal data already exists on same channel*/ + if (ahp->ah_skip_rx_iq_cal) { + HALDEBUG(ah, HAL_DEBUG_CALIBRATE, + "Skip RX IQ Cal\n"); + return AH_TRUE; + } + /* If Cals are supported, add them to list via INIT/INSERT_CAL */ if (AH_TRUE == ar9300_is_cal_supp(ah, chan, IQ_MISMATCH_CAL)) { INIT_CAL(&ahp->ah_iq_cal_data); @@ -3827,6 +3954,8 @@ ar9300_set_dma(struct ath_hal *ah) { u_int32_t regval; struct ath_hal_9300 *ahp = AH9300(ah); + struct ath_hal_private *ahpriv = AH_PRIVATE(ah); + HAL_CAPABILITIES *pCap = &ahpriv->ah_caps; #if 0 /* @@ -3886,9 +4015,14 @@ ar9300_set_dma(struct ath_hal *ah) /* * Enable HPQ for UAPSD */ - if (AH_PRIVATE(ah)->ah_opmode == HAL_M_HOSTAP) { - OS_REG_WRITE(ah, AR_HP_Q_CONTROL, - AR_HPQ_ENABLE | AR_HPQ_UAPSD | AR_HPQ_UAPSD_TRIGGER_EN); + if (pCap->halHwUapsdTrig == AH_TRUE) { + /* Only enable this if HAL capabilities says it is OK */ + if (AH_PRIVATE(ah)->ah_opmode == HAL_M_HOSTAP) { + OS_REG_WRITE(ah, AR_HP_Q_CONTROL, + AR_HPQ_ENABLE | AR_HPQ_UAPSD | AR_HPQ_UAPSD_TRIGGER_EN); + } + } else { + /* use default value from ini file - which disable HPQ queue usage */ } /* @@ -4307,6 +4441,7 @@ ar9300_reset(struct ath_hal *ah, HAL_OPMODE opmode, struct ieee80211_channel *ch HAL_BOOL stopped, cal_ret; HAL_BOOL apply_last_iqcorr = AH_FALSE; + if (OS_REG_READ(ah, AR_IER) == AR_IER_ENABLE) { HALDEBUG(AH_NULL, HAL_DEBUG_UNMASKABLE, "** Reset called with WLAN " "interrupt enabled %08x **\n", ar9300_get_interrupts(ah)); @@ -4335,6 +4470,11 @@ ar9300_reset(struct ath_hal *ah, HAL_OPMODE opmode, struct ieee80211_channel *ch ahp->ah_rx_chainmask = rxchainmask & ap->ah_caps.halRxChainMask; ahp->ah_tx_cal_chainmask = ap->ah_caps.halTxChainMask; ahp->ah_rx_cal_chainmask = ap->ah_caps.halRxChainMask; + + /* + * Keep the previous optinal txchainmask value + */ + HALASSERT(ar9300_check_op_mode(opmode)); OS_MARK(ah, AH_MARK_RESET, b_channel_change); @@ -4441,7 +4581,21 @@ ar9300_reset(struct ath_hal *ah, HAL_OPMODE opmode, struct ieee80211_channel *ch #if 0 /* Get the value from the previous NF cal and update history buffer */ if (curchan && (ahp->ah_chip_full_sleep != AH_TRUE)) { - ar9300_store_new_nf(ah, curchan, is_scan); + + if(ahp->ah_chip_reset_done){ + ahp->ah_chip_reset_done = 0; + } else { + /* + * is_scan controls updating NF for home channel or off channel. + * Home -> Off, update home channel + * Off -> Home, update off channel + * Home -> Home, uppdate home channel + */ + if (ap->ah_curchan->channel != chan->channel) + ar9300_store_new_nf(ah, curchan, !is_scan); + else + ar9300_store_new_nf(ah, curchan, is_scan); + } } #endif @@ -4452,7 +4606,7 @@ ar9300_reset(struct ath_hal *ah, HAL_OPMODE opmode, struct ieee80211_channel *ch AH9300(ah)->nfp = IS_CHAN_2GHZ(ichan) ? &ahp->nf_2GHz : &ahp->nf_5GHz; /* - * XXX For now, don't apply the last IQ correction. + * XXX FreeBSD For now, don't apply the last IQ correction. * * This should be done when scorpion is enabled on FreeBSD; just be * sure to fix this channel match code so it uses net80211 flags @@ -4489,6 +4643,34 @@ ar9300_reset(struct ath_hal *ah, HAL_OPMODE opmode, struct ieee80211_channel *ch } #endif /* + * In case of + * - offchan scan, or + * - same channel and RX IQ Cal already available + * disable RX IQ Cal. + */ + if (is_scan) { + ahp->ah_skip_rx_iq_cal = AH_TRUE; + HALDEBUG(ah, HAL_DEBUG_CALIBRATE, + "Skip RX IQ Cal due to scanning\n"); + } else { +#if 0 + /* XXX FreeBSD: always just do the RX IQ cal */ + /* XXX I think it's just going to speed things up; I don't think it's to avoid chan bugs */ + if (ahp->ah_rx_cal_complete && + ahp->ah_rx_cal_chan == ichan->channel && + ahp->ah_rx_cal_chan_flag == chan->channel_flags) { + ahp->ah_skip_rx_iq_cal = AH_TRUE; + HALDEBUG(ah, HAL_DEBUG_CALIBRATE, + "Skip RX IQ Cal due to same channel with completed RX IQ Cal\n"); + } else +#endif + ahp->ah_skip_rx_iq_cal = AH_FALSE; + } + + /* FreeBSD: clear the channel survey data */ + ath_hal_survey_clear(ah); + + /* * Fast channel change (Change synthesizer based on channel freq * without resetting chip) * Don't do it when @@ -4854,6 +5036,23 @@ ar9300_reset(struct ath_hal *ah, HAL_OPMODE opmode, struct ieee80211_channel *ch ar9300_init_bb(ah, chan); /* BB Step 7: Calibration */ + /* + * Only kick off calibration not on offchan. + * If coming back from offchan, restore prevous Cal results + * since chip reset will clear existings. + */ + if (!ahp->ah_skip_rx_iq_cal) { + int i; + /* clear existing RX cal data */ + for (i=0; i<AR9300_MAX_CHAINS; i++) + ahp->ah_rx_cal_corr[i] = 0; + + ahp->ah_rx_cal_complete = AH_FALSE; +// ahp->ah_rx_cal_chan = chan->channel; +// ahp->ah_rx_cal_chan_flag = ichan->channel_flags; + ahp->ah_rx_cal_chan = 0; + ahp->ah_rx_cal_chan_flag = 0; /* XXX FreeBSD */ + } ar9300_invalidate_saved_cals(ah, ichan); cal_ret = ar9300_init_cal(ah, chan, AH_FALSE, apply_last_iqcorr); @@ -5009,6 +5208,11 @@ ar9300_reset(struct ath_hal *ah, HAL_OPMODE opmode, struct ieee80211_channel *ch nf_hist_buff_reset = 0; #ifndef ATH_NF_PER_CHAN if (First_NFCal(ah, ichan, is_scan, chan)){ + if (ahp->ah_skip_rx_iq_cal && !is_scan) { + /* restore RX Cal result if existing */ + ar9300_rx_iq_cal_restore(ah); + ahp->ah_skip_rx_iq_cal = AH_FALSE; + } } #endif /* ATH_NF_PER_CHAN */ } @@ -5082,12 +5286,24 @@ ar9300_reset(struct ath_hal *ah, HAL_OPMODE opmode, struct ieee80211_channel *ch ar9300_set_smart_antenna(ah, ahp->ah_smartantenna_enable); + if (ahp->ah_skip_rx_iq_cal && !is_scan) { + /* restore RX Cal result if existing */ + ar9300_rx_iq_cal_restore(ah); + ahp->ah_skip_rx_iq_cal = AH_FALSE; + } + return AH_TRUE; bad: OS_MARK(ah, AH_MARK_RESET_DONE, ecode); *status = ecode; + if (ahp->ah_skip_rx_iq_cal && !is_scan) { + /* restore RX Cal result if existing */ + ar9300_rx_iq_cal_restore(ah); + ahp->ah_skip_rx_iq_cal = AH_FALSE; + } + return AH_FALSE; #undef FAIL } @@ -6139,6 +6355,7 @@ ar9300_ant_ctrl_set_lna_div_use_bt_ant(struct ath_hal *ah, HAL_BOOL enable, cons value &= ~AR_SWITCH_TABLE_COM2_ALL; value |= ah->ah_config.ath_hal_ant_ctrl_comm2g_switch_enable; } + HALDEBUG(ah, HAL_DEBUG_RESET, "%s: com2=0x%08x\n", __func__, value); OS_REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM_2, AR_SWITCH_TABLE_COM2_ALL, value); value = ar9300_eeprom_get(ahp, EEP_ANTDIV_control); @@ -6186,5 +6403,7 @@ ar9300_ant_ctrl_set_lna_div_use_bt_ant(struct ath_hal *ah, HAL_BOOL enable, cons } else { return AH_TRUE; } + + /* XXX TODO: Add AR9565 support? */ } #endif /* ATH_ANT_DIV_COMB */ diff --git a/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_stub.c b/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_stub.c index 2dd9472..211e201 100644 --- a/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_stub.c +++ b/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_stub.c @@ -33,7 +33,7 @@ void ar9300_set_stub_functions(struct ath_hal *ah) { - ath_hal_printf(ah, "%s: setting stub functions\n", __func__); +// ath_hal_printf(ah, "%s: setting stub functions\n", __func__); ah->ah_getRateTable = ar9300_Stub_GetRateTable; // ah->ah_detach = ar9300_Stub_detach; diff --git a/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_xmit.c b/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_xmit.c index ab39284..530b29a 100644 --- a/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_xmit.c +++ b/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_xmit.c @@ -583,6 +583,14 @@ ar9300_num_tx_pending(struct ath_hal *ah, u_int q) HAL_BOOL ar9300_stop_tx_dma(struct ath_hal *ah, u_int q, u_int timeout) { + struct ath_hal_9300 *ahp = AH9300(ah); + + /* + * If we call abort txdma instead, no need to stop RX. + * Otherwise, the RX logic might not be restarted properly. + */ + ahp->ah_abort_txdma_norx = AH_FALSE; + /* * Directly call abort. It is better, hardware-wise, to stop all * queues at once than individual ones. @@ -798,10 +806,40 @@ ar9300_stop_tx_dma_indv_que(struct ath_hal *ah, u_int q, u_int timeout) */ #define AR9300_ABORT_LOOPS 1000 #define AR9300_ABORT_WAIT 5 +#define NEXT_TBTT_NOW 10 HAL_BOOL ar9300_abort_tx_dma(struct ath_hal *ah) { + struct ath_hal_9300 *ahp = AH9300(ah); int i, q; + u_int32_t nexttbtt, nextdba, tsf_tbtt, tbtt, dba; + HAL_BOOL stopped; + HAL_BOOL status = AH_TRUE; + + if (ahp->ah_abort_txdma_norx) { + /* + * First of all, make sure RX has been stopped + */ + if (ar9300_get_power_mode(ah) != HAL_PM_FULL_SLEEP) { + /* Need to stop RX DMA before reset otherwise chip might hang */ + stopped = ar9300_set_rx_abort(ah, AH_TRUE); /* abort and disable PCU */ + ar9300_set_rx_filter(ah, 0); + stopped &= ar9300_stop_dma_receive(ah, 0); /* stop and disable RX DMA */ + if (!stopped) { + /* + * During the transition from full sleep to reset, + * recv DMA regs are not available to be read + */ + HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, + "%s[%d]: ar9300_stop_dma_receive failed\n", __func__, __LINE__); + //We still continue to stop TX dma + //return AH_FALSE; + } + } else { + HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, + "%s[%d]: Chip is already in full sleep\n", __func__, __LINE__); + } + } /* * set txd on all queues @@ -812,13 +850,27 @@ ar9300_abort_tx_dma(struct ath_hal *ah) * set tx abort bits (also disable rx) */ OS_REG_SET_BIT(ah, AR_PCU_MISC, AR_PCU_FORCE_QUIET_COLL | AR_PCU_CLEAR_VMF); - OS_REG_SET_BIT(ah, AR_DIAG_SW, (AR_DIAG_FORCE_CH_IDLE_HIGH | AR_DIAG_RX_DIS | - AR_DIAG_RX_ABORT | AR_DIAG_FORCE_RX_CLEAR)); + /* Add a new receipe from K31 code */ + OS_REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH | AR_DIAG_RX_DIS | + AR_DIAG_RX_ABORT | AR_DIAG_FORCE_RX_CLEAR); + /* beacon Q flush */ + nexttbtt = OS_REG_READ(ah, AR_NEXT_TBTT_TIMER); + nextdba = OS_REG_READ(ah, AR_NEXT_DMA_BEACON_ALERT); + //printk("%s[%d]:dba: %d, nt: %d \n", __func__, __LINE__, nextdba, nexttbtt); + tsf_tbtt = OS_REG_READ(ah, AR_TSF_L32); + tbtt = tsf_tbtt + NEXT_TBTT_NOW; + dba = tsf_tbtt; + OS_REG_WRITE(ah, AR_NEXT_DMA_BEACON_ALERT, dba); + OS_REG_WRITE(ah, AR_NEXT_TBTT_TIMER, tbtt); OS_REG_SET_BIT(ah, AR_D_GBL_IFS_MISC, AR_D_GBL_IFS_MISC_IGNORE_BACKOFF); - /* Let TXE (all queues) clear before waiting on any pending frames */ - for (i = 0; i < AR9300_ABORT_LOOPS; i++) { - if (OS_REG_READ(ah, AR_Q_TXE) == 0) { + /* + * Let TXE (all queues) clear before waiting for any pending frames + * This is needed before starting the RF_BUS GRANT sequence other wise causes kernel + * panic + */ + for(i = 0; i < AR9300_ABORT_LOOPS; i++) { + if(OS_REG_READ(ah, AR_Q_TXE) == 0) { break; } OS_DELAY(AR9300_ABORT_WAIT); @@ -830,28 +882,38 @@ ar9300_abort_tx_dma(struct ath_hal *ah) /* * wait on all tx queues + * This need to be checked in the last to gain extra 50 usec. on avg. + * Currently checked first since we dont have a previous channel information currently. + * Which is needed to revert the rf changes. */ - for (q = 0; q < AR_NUM_QCU; q++) { + for (q = AR_NUM_QCU - 1; q >= 0; q--) { for (i = 0; i < AR9300_ABORT_LOOPS; i++) { - if (!ar9300_num_tx_pending(ah, q)) { + if (!(ar9300_num_tx_pending(ah, q))) { break; } OS_DELAY(AR9300_ABORT_WAIT); } if (i == AR9300_ABORT_LOOPS) { - HALDEBUG(ah, HAL_DEBUG_TX, - "%s[%d] reached max wait on pending tx, q %d\n", - __func__, __LINE__, q); - return AH_FALSE; + status = AH_FALSE; + HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, + "ABORT LOOP finsihsed for Q: %d, num_pending: %d \n", + q, ar9300_num_tx_pending(ah, q)); + goto exit; } } + /* Updating the beacon alert register with correct value */ + OS_REG_WRITE(ah, AR_NEXT_DMA_BEACON_ALERT, nextdba); + OS_REG_WRITE(ah, AR_NEXT_TBTT_TIMER, nexttbtt); + +exit: /* * clear tx abort bits */ OS_REG_CLR_BIT(ah, AR_PCU_MISC, AR_PCU_FORCE_QUIET_COLL | AR_PCU_CLEAR_VMF); - OS_REG_CLR_BIT(ah, AR_DIAG_SW, (AR_DIAG_FORCE_CH_IDLE_HIGH | AR_DIAG_RX_DIS | - AR_DIAG_RX_ABORT | AR_DIAG_FORCE_RX_CLEAR)); + /* Added a new receipe from K31 code */ + OS_REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH | AR_DIAG_RX_DIS | + AR_DIAG_RX_ABORT | AR_DIAG_FORCE_RX_CLEAR); OS_REG_CLR_BIT(ah, AR_D_GBL_IFS_MISC, AR_D_GBL_IFS_MISC_IGNORE_BACKOFF); /* @@ -859,7 +921,9 @@ ar9300_abort_tx_dma(struct ath_hal *ah) */ OS_REG_WRITE(ah, AR_Q_TXD, 0); - return AH_TRUE; + ahp->ah_abort_txdma_norx = AH_TRUE; + + return status; } /* diff --git a/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_xmit_ds.c b/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_xmit_ds.c index 596f6dc..72ed110 100644 --- a/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_xmit_ds.c +++ b/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_xmit_ds.c @@ -68,9 +68,11 @@ ar9300_fill_tx_desc( const void *ds0) { struct ar9300_txc *ads = AR9300TXC(ds); + short desclen; /* Fill TXC info field */ - ads->ds_info = TXC_INFO(qcu); + desclen = (AR_SREV_JUPITER(ah) || AR_SREV_APHRODITE(ah)) ? 0x18 : 0x17; + ads->ds_info = TXC_INFO(qcu, desclen); /* Set the buffer addresses */ ads->ds_data0 = buf_addr[0]; @@ -124,6 +126,9 @@ ar9300_fill_tx_desc( ads->ds_ctl17 = SM(key_type, AR_encr_type); } + /* Only relevant for Jupiter/Aphrodite */ + ads->ds_ctl23 = 0; + return AH_TRUE; } diff --git a/sys/contrib/dev/ath/ath_hal/ar9300/ar9300desc.h b/sys/contrib/dev/ath/ath_hal/ar9300/ar9300desc.h index 9054db0..5dbf927 100644 --- a/sys/contrib/dev/ath/ath_hal/ar9300/ar9300desc.h +++ b/sys/contrib/dev/ath/ath_hal/ar9300/ar9300desc.h @@ -78,7 +78,8 @@ struct ar9300_txc { u_int32_t ds_ctl20; /* DMA control 20 */ u_int32_t ds_ctl21; /* DMA control 21 */ u_int32_t ds_ctl22; /* DMA control 22 */ - u_int32_t ds_pad[9]; /* pad to cache line (128 bytes/32 dwords) */ + u_int32_t ds_ctl23; /* DMA control 23 */ + u_int32_t ds_pad[8]; /* pad to cache line (128 bytes/32 dwords) */ }; @@ -347,6 +348,7 @@ struct ar9300_txc { /* ds_status2 */ #define AR_data_len 0x00000fff +#define AR_data_len_S 0 #define AR_rx_more 0x00001000 #define AR_num_delim 0x003fc000 #define AR_num_delim_S 14 @@ -428,11 +430,11 @@ struct ar9300_txc { #define RXSTATUS_NUMWORDS(ah) 11 -#define TXC_INFO(_qcu) (ATHEROS_VENDOR_ID << AR_desc_id_S) \ +#define TXC_INFO(_qcu, _desclen) (ATHEROS_VENDOR_ID << AR_desc_id_S) \ | (1 << AR_tx_rx_desc_S) \ | (1 << AR_ctrl_stat_S) \ | (_qcu << AR_tx_qcu_num_S) \ - | (0x17) + | (_desclen) #define VALID_KEY_TYPES \ ((1 << HAL_KEY_TYPE_CLEAR) | (1 << HAL_KEY_TYPE_WEP)|\ diff --git a/sys/contrib/dev/ath/ath_hal/ar9300/ar9340.ini b/sys/contrib/dev/ath/ath_hal/ar9300/ar9340.ini index 81894de..ef7dbca 100644 --- a/sys/contrib/dev/ath/ath_hal/ar9300/ar9340.ini +++ b/sys/contrib/dev/ath/ath_hal/ar9300/ar9340.ini @@ -1078,7 +1078,7 @@ static const u_int32_t ar9340_wasp_1p0_mac_postamble[][5] = { { 0x0000801c , 0x128d8027 , 0x128d804f , 0x12e00057 , 0x12e0002b }, - { 0x00008120 , 0x08f04800 , 0x08f04800 , 0x08f04810 , 0x08f04810 }, + { 0x00008120 , 0x18f04800 , 0x18f04800 , 0x18f04810 , 0x18f04810 }, { 0x000081d0 , 0x00003210 , 0x00003210 , 0x0000320a , 0x0000320a }, @@ -1212,7 +1212,7 @@ static const u_int32_t ar9340_wasp_1p0_baseband_postamble[][5] = { { 0x00009e18 , 0x00000000 , 0x00000000 , 0x00000000 , 0x00000000 }, - { 0x00009e1c , 0x0001cf9c , 0x0001cf9c , 0x00021f9c , 0x00021f9c }, + { 0x00009e1c , 0x0001c59c , 0x0001c59c , 0x0002159c , 0x0002159c }, { 0x00009e20 , 0x000003b5 , 0x000003b5 , 0x000003ce , 0x000003ce }, @@ -1586,10 +1586,14 @@ static const u_int32_t ar9340_wasp_1p0_baseband_postamble_dfs_channel[][3] = { { 0x00009824 , 0x5ac668d0 , 0x5ac668d0 }, + { 0x00009828 , 0x06903080 , 0x06903080 }, + { 0x00009e0c , 0x6d4000e2 , 0x6d4000e2 }, { 0x00009e14 , 0x37b9625e , 0x37b9625e }, + { 0x00009814 , 0x3400c00f , 0x3400c00f }, + }; diff --git a/sys/contrib/dev/ath/ath_hal/ar9300/ar9580.ini b/sys/contrib/dev/ath/ath_hal/ar9300/ar9580.ini index 32124db..52b92ff 100644 --- a/sys/contrib/dev/ath/ath_hal/ar9300/ar9580.ini +++ b/sys/contrib/dev/ath/ath_hal/ar9300/ar9580.ini @@ -34,8 +34,10 @@ static const u_int32_t ar9300_ar9580_1p0_baseband_postamble_dfs_channel[][3] = { /* Addr 5G_HT20 5G_HT40 */ { 0x00009824 , 0x5ac668d0 , 0x5ac668d0 }, + { 0x00009828 , 0x06903080 , 0x06903080 }, { 0x00009e0c , 0x6d4000e2 , 0x6d4000e2 }, { 0x00009e14 , 0x37b9625e , 0x37b9625e }, + { 0x00009814 , 0x3400c00f , 0x3400c00f }, }; static const u_int32_t ar9300Modes_fast_clock_ar9580_1p0[][3] = { @@ -257,7 +259,7 @@ static const u_int32_t ar9300_ar9580_1p0_mac_postamble[][5] = { { 0x000010b0 , 0x00000e60 , 0x00001cc0 , 0x00007c70 , 0x00003e38 }, { 0x00008014 , 0x03e803e8 , 0x07d007d0 , 0x10801600 , 0x08400b00 }, { 0x0000801c , 0x128d8027 , 0x128d804f , 0x12e00057 , 0x12e0002b }, - { 0x00008120 , 0x08f04800 , 0x08f04800 , 0x08f04810 , 0x08f04810 }, + { 0x00008120 , 0x18f04800 , 0x18f04800 , 0x18f04810 , 0x18f04810 }, { 0x000081d0 , 0x00003210 , 0x00003210 , 0x0000320a , 0x0000320a }, { 0x00008318 , 0x00003e80 , 0x00007d00 , 0x00006880 , 0x00003440 }, }; @@ -1091,7 +1093,7 @@ static const u_int32_t ar9300_ar9580_1p0_mac_core[][2] = { { 0x00008258 , 0x00000000 }, { 0x0000825c , 0x40000000 }, { 0x00008260 , 0x00080922 }, - { 0x00008264 , 0x9bc00010 }, + { 0x00008264 , 0x9d400010 }, { 0x00008268 , 0xffffffff }, { 0x0000826c , 0x0000ffff }, { 0x00008270 , 0x00000000 }, @@ -2155,7 +2157,7 @@ static const u_int32_t ar9300_ar9580_1p0_baseband_postamble[][5] = { { 0x00009e10 , 0x7ec88d2e , 0x7ec88d2e , 0x7ec84d2e , 0x7ec84d2e }, { 0x00009e14 , 0x37b95d5e , 0x37b9605e , 0x3379605e , 0x33795d5e }, { 0x00009e18 , 0x00000000 , 0x00000000 , 0x00000000 , 0x00000000 }, - { 0x00009e1c , 0x0001cf9c , 0x0001cf9c , 0x00021f9c , 0x00021f9c }, + { 0x00009e1c , 0x0001c59c , 0x0001c59c , 0x0002159c , 0x0002159c }, { 0x00009e20 , 0x000003b5 , 0x000003b5 , 0x000003ce , 0x000003ce }, { 0x00009e2c , 0x0000001c , 0x0000001c , 0x00000021 , 0x00000021 }, { 0x00009e3c , 0xcf946220 , 0xcf946220 , 0xcf946222 , 0xcf946222 }, diff --git a/sys/dev/ath/ah_osdep.c b/sys/dev/ath/ah_osdep.c index 043ebed..5c29e26 100644 --- a/sys/dev/ath/ah_osdep.c +++ b/sys/dev/ath/ah_osdep.c @@ -26,7 +26,7 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGES. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ah_osdep.c 267992 2014-06-28 03:56:17Z hselasky $ */ #include "opt_ah.h" @@ -96,9 +96,8 @@ static SYSCTL_NODE(_hw_ath, OID_AUTO, hal, CTLFLAG_RD, 0, #ifdef AH_DEBUG int ath_hal_debug = 0; -SYSCTL_INT(_hw_ath_hal, OID_AUTO, debug, CTLFLAG_RW, &ath_hal_debug, +SYSCTL_INT(_hw_ath_hal, OID_AUTO, debug, CTLFLAG_RWTUN, &ath_hal_debug, 0, "Atheros HAL debugging printfs"); -TUNABLE_INT("hw.ath.hal.debug", &ath_hal_debug); #endif /* AH_DEBUG */ static MALLOC_DEFINE(M_ATH_HAL, "ath_hal", "ath hal data"); @@ -138,6 +137,24 @@ ath_hal_ether_sprintf(const u_int8_t *mac) #ifdef AH_DEBUG +/* + * XXX This is highly relevant only for the AR5416 and later + * PCI/PCIe NICs. It'll need adjustment for other hardware + * variations. + */ +static int +ath_hal_reg_whilst_asleep(struct ath_hal *ah, uint32_t reg) +{ + + if (reg >= 0x4000 && reg < 0x5000) + return (1); + if (reg >= 0x6000 && reg < 0x7000) + return (1); + if (reg >= 0x7000 && reg < 0x8000) + return (1); + return (0); +} + void DO_HALDEBUG(struct ath_hal *ah, u_int mask, const char* fmt, ...) { @@ -253,6 +270,13 @@ ath_hal_reg_write(struct ath_hal *ah, u_int32_t reg, u_int32_t val) bus_space_tag_t tag = BUSTAG(ah); bus_space_handle_t h = ah->ah_sh; + /* Debug - complain if we haven't fully waken things up */ + if (! ath_hal_reg_whilst_asleep(ah, reg) && + ah->ah_powerMode != HAL_PM_AWAKE) { + ath_hal_printf(ah, "%s: reg=0x%08x, val=0x%08x, pm=%d\n", + __func__, reg, val, ah->ah_powerMode); + } + if (ath_hal_alq) { struct ale *ale = ath_hal_alq_get(ah); if (ale) { @@ -278,6 +302,13 @@ ath_hal_reg_read(struct ath_hal *ah, u_int32_t reg) bus_space_handle_t h = ah->ah_sh; u_int32_t val; + /* Debug - complain if we haven't fully waken things up */ + if (! ath_hal_reg_whilst_asleep(ah, reg) && + ah->ah_powerMode != HAL_PM_AWAKE) { + ath_hal_printf(ah, "%s: reg=0x%08x, pm=%d\n", + __func__, reg, ah->ah_powerMode); + } + if (ah->ah_config.ah_serialise_reg_war) mtx_lock_spin(&ah_regser_mtx); val = bus_space_read_4(tag, h, reg); @@ -330,6 +361,13 @@ ath_hal_reg_write(struct ath_hal *ah, u_int32_t reg, u_int32_t val) bus_space_tag_t tag = BUSTAG(ah); bus_space_handle_t h = ah->ah_sh; + /* Debug - complain if we haven't fully waken things up */ + if (! ath_hal_reg_whilst_asleep(ah, reg) && + ah->ah_powerMode != HAL_PM_AWAKE) { + ath_hal_printf(ah, "%s: reg=0x%08x, val=0x%08x, pm=%d\n", + __func__, reg, val, ah->ah_powerMode); + } + if (ah->ah_config.ah_serialise_reg_war) mtx_lock_spin(&ah_regser_mtx); bus_space_write_4(tag, h, reg, val); @@ -344,6 +382,13 @@ ath_hal_reg_read(struct ath_hal *ah, u_int32_t reg) bus_space_handle_t h = ah->ah_sh; u_int32_t val; + /* Debug - complain if we haven't fully waken things up */ + if (! ath_hal_reg_whilst_asleep(ah, reg) && + ah->ah_powerMode != HAL_PM_AWAKE) { + ath_hal_printf(ah, "%s: reg=0x%08x, pm=%d\n", + __func__, reg, ah->ah_powerMode); + } + if (ah->ah_config.ah_serialise_reg_war) mtx_lock_spin(&ah_regser_mtx); val = bus_space_read_4(tag, h, reg); diff --git a/sys/dev/ath/ah_osdep.h b/sys/dev/ath/ah_osdep.h index 50778f2..3c31327 100644 --- a/sys/dev/ath/ah_osdep.h +++ b/sys/dev/ath/ah_osdep.h @@ -26,7 +26,7 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGES. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ah_osdep.h 239051 2012-08-05 10:12:27Z adrian $ */ #ifndef _ATH_AH_OSDEP_H_ #define _ATH_AH_OSDEP_H_ diff --git a/sys/dev/ath/ath_dfs/null/dfs_null.c b/sys/dev/ath/ath_dfs/null/dfs_null.c index 36b2042..94a391d 100644 --- a/sys/dev/ath/ath_dfs/null/dfs_null.c +++ b/sys/dev/ath/ath_dfs/null/dfs_null.c @@ -26,10 +26,10 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGES. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_dfs/null/dfs_null.c 257176 2013-10-26 17:58:36Z glebius $ */ #include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); +__FBSDID("$FreeBSD: head/sys/dev/ath/ath_dfs/null/dfs_null.c 257176 2013-10-26 17:58:36Z glebius $"); /* * This implements an empty DFS module. @@ -43,6 +43,7 @@ __FBSDID("$FreeBSD$"); #include <sys/sysctl.h> #include <sys/kernel.h> #include <sys/lock.h> +#include <sys/malloc.h> #include <sys/mutex.h> #include <sys/errno.h> @@ -53,6 +54,7 @@ __FBSDID("$FreeBSD$"); #include <sys/socket.h> #include <net/if.h> +#include <net/if_var.h> #include <net/if_media.h> #include <net/if_arp.h> #include <net/ethernet.h> /* XXX for ether_sprintf */ diff --git a/sys/dev/ath/ath_hal/ah.c b/sys/dev/ath/ath_hal/ah.c index 7187d57..0fab78b 100644 --- a/sys/dev/ath/ath_hal/ah.c +++ b/sys/dev/ath/ath_hal/ah.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ah.c 280828 2015-03-29 21:50:21Z adrian $ */ #include "opt_ah.h" @@ -55,7 +55,9 @@ ath_hal_probe(uint16_t vendorid, uint16_t devid) */ struct ath_hal* ath_hal_attach(uint16_t devid, HAL_SOFTC sc, - HAL_BUS_TAG st, HAL_BUS_HANDLE sh, uint16_t *eepromdata, HAL_STATUS *error) + HAL_BUS_TAG st, HAL_BUS_HANDLE sh, uint16_t *eepromdata, + HAL_OPS_CONFIG *ah_config, + HAL_STATUS *error) { struct ath_hal_chip * const *pchip; @@ -66,7 +68,8 @@ ath_hal_attach(uint16_t devid, HAL_SOFTC sc, /* XXX don't have vendorid, assume atheros one works */ if (chip->probe(ATHEROS_VENDOR_ID, devid) == AH_NULL) continue; - ah = chip->attach(devid, sc, st, sh, eepromdata, error); + ah = chip->attach(devid, sc, st, sh, eepromdata, ah_config, + error); if (ah != AH_NULL) { /* copy back private state to public area */ ah->ah_devid = AH_PRIVATE(ah)->ah_devid; @@ -786,6 +789,8 @@ ath_hal_getcapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type, return HAL_OK; case HAL_CAP_RX_LNA_MIXING: /* Hardware uses an RX LNA mixer to map 2 antennas to a 1 stream receiver */ return pCap->halRxUsingLnaMixing ? HAL_OK : HAL_ENOTSUPP; + case HAL_CAP_DO_MYBEACON: /* Hardware supports filtering my-beacons */ + return pCap->halRxDoMyBeacon ? HAL_OK : HAL_ENOTSUPP; default: return HAL_EINVAL; } @@ -848,10 +853,11 @@ ath_hal_getregdump(struct ath_hal *ah, const HAL_REGRANGE *regs, int i; for (i = 0; space >= 2*sizeof(uint32_t); i++) { - u_int r = regs[i].start; - u_int e = regs[i].end; - *dp++ = (r<<16) | e; - space -= sizeof(uint32_t); + uint32_t r = regs[i].start; + uint32_t e = regs[i].end; + *dp++ = r; + *dp++ = e; + space -= 2*sizeof(uint32_t); do { *dp++ = OS_REG_READ(ah, r); r += sizeof(uint32_t); @@ -875,6 +881,7 @@ ath_hal_getdiagstate(struct ath_hal *ah, int request, const void *args, uint32_t argsize, void **result, uint32_t *resultsize) { + switch (request) { case HAL_DIAG_REVS: *result = &AH_PRIVATE(ah)->ah_devid; @@ -932,6 +939,10 @@ ath_hal_getdiagstate(struct ath_hal *ah, int request, } else return AH_FALSE; return AH_TRUE; + case HAL_DIAG_CHANSURVEY: + *result = &AH_PRIVATE(ah)->ah_chansurvey; + *resultsize = sizeof(HAL_CHANNEL_SURVEY); + return AH_TRUE; } return AH_FALSE; } @@ -1427,3 +1438,32 @@ ath_hal_mhz2ieee_2ghz(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *ichan) else return 15 + ((ichan->channel - 2512) / 20); } + +/* + * Clear the current survey data. + * + * This should be done during a channel change. + */ +void +ath_hal_survey_clear(struct ath_hal *ah) +{ + + OS_MEMZERO(&AH_PRIVATE(ah)->ah_chansurvey, + sizeof(AH_PRIVATE(ah)->ah_chansurvey)); +} + +/* + * Add a sample to the channel survey. + */ +void +ath_hal_survey_add_sample(struct ath_hal *ah, HAL_SURVEY_SAMPLE *hs) +{ + HAL_CHANNEL_SURVEY *cs; + + cs = &AH_PRIVATE(ah)->ah_chansurvey; + + OS_MEMCPY(&cs->samples[cs->cur_sample], hs, sizeof(*hs)); + cs->samples[cs->cur_sample].seq_num = cs->cur_seq; + cs->cur_sample = (cs->cur_sample + 1) % CHANNEL_SURVEY_SAMPLE_COUNT; + cs->cur_seq++; +} diff --git a/sys/dev/ath/ath_hal/ah.h b/sys/dev/ath/ath_hal/ah.h index 2480803..a17d74e 100644 --- a/sys/dev/ath/ath_hal/ah.h +++ b/sys/dev/ath/ath_hal/ah.h @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ah.h 280940 2015-04-01 03:42:46Z adrian $ */ #ifndef _ATH_AH_H_ @@ -199,6 +199,7 @@ typedef enum { HAL_CAP_SERIALISE_WAR = 245, /* serialise register access on PCI */ HAL_CAP_ENFORCE_TXOP = 246, /* Enforce TXOP if supported */ HAL_CAP_RX_LNA_MIXING = 247, /* RX hardware uses LNA mixing */ + HAL_CAP_DO_MYBEACON = 248, /* Supports HAL_RX_FILTER_MYBEACON */ } HAL_CAPABILITY_TYPE; /* @@ -404,6 +405,7 @@ typedef enum { HAL_RX_FILTER_PROM = 0x00000020, /* Promiscuous mode */ HAL_RX_FILTER_PROBEREQ = 0x00000080, /* Allow probe request frames */ HAL_RX_FILTER_PHYERR = 0x00000100, /* Allow phy errors */ + HAL_RX_FILTER_MYBEACON = 0x00000200, /* Filter beacons other than mine */ HAL_RX_FILTER_COMPBAR = 0x00000400, /* Allow compressed BAR */ HAL_RX_FILTER_COMP_BA = 0x00000800, /* Allow compressed blockack */ HAL_RX_FILTER_PHYRADAR = 0x00002000, /* Allow phy radar errors */ @@ -538,6 +540,7 @@ typedef enum { typedef struct { u_int32_t cyclecnt_diff; /* delta cycle count */ u_int32_t rxclr_cnt; /* rx clear count */ + u_int32_t extrxclr_cnt; /* ext chan rx clear count */ u_int32_t txframecnt_diff; /* delta tx frame count */ u_int32_t rxframecnt_diff; /* delta rx frame count */ u_int32_t listen_time; /* listen time in msec - time for which ch is free */ @@ -847,6 +850,48 @@ typedef struct { #define HAL_RSSI_EP_MULTIPLIER (1<<7) /* pow2 to optimize out * and / */ +/* + * This is the ANI state and MIB stats. + * + * It's used by the HAL modules to keep state /and/ by the debug ioctl + * to fetch ANI information. + */ +typedef struct { + uint32_t ast_ani_niup; /* ANI increased noise immunity */ + uint32_t ast_ani_nidown; /* ANI decreased noise immunity */ + uint32_t ast_ani_spurup; /* ANI increased spur immunity */ + uint32_t ast_ani_spurdown;/* ANI descreased spur immunity */ + uint32_t ast_ani_ofdmon; /* ANI OFDM weak signal detect on */ + uint32_t ast_ani_ofdmoff;/* ANI OFDM weak signal detect off */ + uint32_t ast_ani_cckhigh;/* ANI CCK weak signal threshold high */ + uint32_t ast_ani_ccklow; /* ANI CCK weak signal threshold low */ + uint32_t ast_ani_stepup; /* ANI increased first step level */ + uint32_t ast_ani_stepdown;/* ANI decreased first step level */ + uint32_t ast_ani_ofdmerrs;/* ANI cumulative ofdm phy err count */ + uint32_t ast_ani_cckerrs;/* ANI cumulative cck phy err count */ + uint32_t ast_ani_reset; /* ANI parameters zero'd for non-STA */ + uint32_t ast_ani_lzero; /* ANI listen time forced to zero */ + uint32_t ast_ani_lneg; /* ANI listen time calculated < 0 */ + HAL_MIB_STATS ast_mibstats; /* MIB counter stats */ + HAL_NODE_STATS ast_nodestats; /* Latest rssi stats from driver */ +} HAL_ANI_STATS; + +typedef struct { + uint8_t noiseImmunityLevel; + uint8_t spurImmunityLevel; + uint8_t firstepLevel; + uint8_t ofdmWeakSigDetectOff; + uint8_t cckWeakSigThreshold; + uint32_t listenTime; + + /* NB: intentionally ordered so data exported to user space is first */ + uint32_t txFrameCount; /* Last txFrameCount */ + uint32_t rxFrameCount; /* Last rx Frame count */ + uint32_t cycleCount; /* Last cycleCount + (to detect wrap-around) */ + uint32_t ofdmPhyErrCount;/* OFDM err count since last reset */ + uint32_t cckPhyErrCount; /* CCK err count since last reset */ +} HAL_ANI_STATE; struct ath_desc; struct ath_tx_status; @@ -1262,6 +1307,7 @@ typedef struct int ath_hal_show_bb_panic; int ath_hal_ant_ctrl_comm2g_switch_enable; int ath_hal_ext_atten_margin_cfg; + int ath_hal_min_gainidx; int ath_hal_war70c; uint32_t ath_hal_mci_config; } HAL_OPS_CONFIG; @@ -1297,6 +1343,9 @@ struct ath_hal { uint32_t ah_intrstate[8]; /* last int state */ uint32_t ah_syncstate; /* last sync intr state */ + /* Current powerstate from HAL calls */ + HAL_POWER_MODE ah_powerMode; + HAL_OPS_CONFIG ah_config; const HAL_RATE_TABLE *__ahdecl(*ah_getRateTable)(struct ath_hal *, u_int mode); @@ -1583,6 +1632,18 @@ struct ath_hal { void __ahdecl(*ah_btCoexDisable)(struct ath_hal *); int __ahdecl(*ah_btCoexEnable)(struct ath_hal *); + /* Bluetooth MCI methods */ + void __ahdecl(*ah_btMciSetup)(struct ath_hal *, + uint32_t, void *, uint16_t, uint32_t); + HAL_BOOL __ahdecl(*ah_btMciSendMessage)(struct ath_hal *, + uint8_t, uint32_t, uint32_t *, uint8_t, + HAL_BOOL, HAL_BOOL); + uint32_t __ahdecl(*ah_btMciGetInterrupt)(struct ath_hal *, + uint32_t *, uint32_t *); + uint32_t __ahdecl(*ah_btMciGetState)(struct ath_hal *, + uint32_t, uint32_t *); + void __ahdecl(*ah_btMciDetach)(struct ath_hal *); + /* LNA diversity configuration */ void __ahdecl(*ah_divLnaConfGet)(struct ath_hal *, HAL_ANT_COMB_CONFIG *); @@ -1611,7 +1672,8 @@ extern const char *__ahdecl ath_hal_probe(uint16_t vendorid, uint16_t devid); * be returned if the status parameter is non-zero. */ extern struct ath_hal * __ahdecl ath_hal_attach(uint16_t devid, HAL_SOFTC, - HAL_BUS_TAG, HAL_BUS_HANDLE, uint16_t *eepromdata, HAL_STATUS* status); + HAL_BUS_TAG, HAL_BUS_HANDLE, uint16_t *eepromdata, + HAL_OPS_CONFIG *ah_config, HAL_STATUS* status); extern const char *ath_hal_mac_name(struct ath_hal *); extern const char *ath_hal_rf_name(struct ath_hal *); diff --git a/sys/dev/ath/ath_hal/ah_debug.h b/sys/dev/ath/ath_hal/ah_debug.h index 933811f..a10226b 100644 --- a/sys/dev/ath/ath_hal/ah_debug.h +++ b/sys/dev/ath/ath_hal/ah_debug.h @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ah_debug.h 249131 2013-04-05 07:41:47Z adrian $ */ #ifndef _ATH_AH_DEBUG_H_ #define _ATH_AH_DEBUG_H_ diff --git a/sys/dev/ath/ath_hal/ah_decode.h b/sys/dev/ath/ath_hal/ah_decode.h index 07c4ac7..7c2ff5b 100644 --- a/sys/dev/ath/ath_hal/ah_decode.h +++ b/sys/dev/ath/ath_hal/ah_decode.h @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ah_decode.h 269749 2014-08-09 09:13:10Z adrian $ */ #ifndef _ATH_AH_DECODE_H_ #define _ATH_AH_DECODE_H_ @@ -53,6 +53,8 @@ enum { AH_MARK_ANI_POLL, /* ar*AniReset, listen time */ AH_MARK_ANI_CONTROL, /* ar*AniReset, cmd */ AH_MARK_RX_CTL, /* RX DMA control */ + AH_MARK_CHIP_POWER, /* chip power control, mode */ + AH_MARK_CHIP_POWER_DONE, /* chip power control done, status */ }; enum { @@ -61,6 +63,7 @@ enum { AH_MARK_RX_CTL_DMA_START, AH_MARK_RX_CTL_DMA_STOP, AH_MARK_RX_CTL_DMA_STOP_ERR, + AH_MARK_RX_CTL_DMA_STOP_OK, }; #endif /* _ATH_AH_DECODE_H_ */ diff --git a/sys/dev/ath/ath_hal/ah_desc.h b/sys/dev/ath/ath_hal/ah_desc.h index 9f58dce..badc73f 100644 --- a/sys/dev/ath/ath_hal/ah_desc.h +++ b/sys/dev/ath/ath_hal/ah_desc.h @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ah_desc.h 251399 2013-06-05 00:39:20Z adrian $ */ #ifndef _DEV_ATH_DESC_H diff --git a/sys/dev/ath/ath_hal/ah_devid.h b/sys/dev/ath/ath_hal/ah_devid.h index 43d994d..4f0bb50 100644 --- a/sys/dev/ath/ath_hal/ah_devid.h +++ b/sys/dev/ath/ath_hal/ah_devid.h @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ah_devid.h 265348 2014-05-05 07:58:05Z adrian $ */ #ifndef _DEV_ATH_DEVID_H_ @@ -92,6 +92,7 @@ #define AR9300_DEVID_AR946X_PCIE 0x0034 #define AR9300_DEVID_AR9330 0x0035 #define AR9300_DEVID_QCA9565 0x0036 +#define AR9300_DEVID_AR1111_PCIE 0x0037 #define AR9300_DEVID_QCA955X 0x0039 #define AR_SUBVENDOR_ID_NOG 0x0e11 /* No 11G subvendor ID */ diff --git a/sys/dev/ath/ath_hal/ah_diagcodes.h b/sys/dev/ath/ath_hal/ah_diagcodes.h index df23242..efad838 100644 --- a/sys/dev/ath/ath_hal/ah_diagcodes.h +++ b/sys/dev/ath/ath_hal/ah_diagcodes.h @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ah_diagcodes.h 239629 2012-08-24 00:17:39Z adrian $ */ #ifndef _ATH_AH_DIAGCODES_H_ #define _ATH_AH_DIAGCODES_H_ diff --git a/sys/dev/ath/ath_hal/ah_eeprom.h b/sys/dev/ath/ath_hal/ah_eeprom.h index 3e9330b..247b9e8 100644 --- a/sys/dev/ath/ath_hal/ah_eeprom.h +++ b/sys/dev/ath/ath_hal/ah_eeprom.h @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ah_eeprom.h 239637 2012-08-24 01:14:00Z adrian $ */ #ifndef _ATH_AH_EEPROM_H_ #define _ATH_AH_EEPROM_H_ diff --git a/sys/dev/ath/ath_hal/ah_eeprom_9287.c b/sys/dev/ath/ath_hal/ah_eeprom_9287.c index abdbce0..4e5d895 100644 --- a/sys/dev/ath/ath_hal/ah_eeprom_9287.c +++ b/sys/dev/ath/ath_hal/ah_eeprom_9287.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ah_eeprom_9287.c 239704 2012-08-26 04:26:49Z adrian $ */ #include "opt_ah.h" diff --git a/sys/dev/ath/ath_hal/ah_eeprom_9287.h b/sys/dev/ath/ath_hal/ah_eeprom_9287.h index ff8080a..d6e1a24 100644 --- a/sys/dev/ath/ath_hal/ah_eeprom_9287.h +++ b/sys/dev/ath/ath_hal/ah_eeprom_9287.h @@ -13,7 +13,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ah_eeprom_9287.h 223615 2011-06-28 00:01:55Z adrian $ */ #ifndef __AH_EEPROM_9287_H__ diff --git a/sys/dev/ath/ath_hal/ah_eeprom_v1.c b/sys/dev/ath/ath_hal/ah_eeprom_v1.c index 8b4664f..9925b8d 100644 --- a/sys/dev/ath/ath_hal/ah_eeprom_v1.c +++ b/sys/dev/ath/ath_hal/ah_eeprom_v1.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ah_eeprom_v1.c 221896 2011-05-14 15:12:02Z adrian $ */ #include "opt_ah.h" diff --git a/sys/dev/ath/ath_hal/ah_eeprom_v1.h b/sys/dev/ath/ath_hal/ah_eeprom_v1.h index 22fce8a..3f34ab5 100644 --- a/sys/dev/ath/ath_hal/ah_eeprom_v1.h +++ b/sys/dev/ath/ath_hal/ah_eeprom_v1.h @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ah_eeprom_v1.h 204644 2010-03-03 17:32:32Z rpaulo $ */ #ifndef _ATH_AH_EEPROM_V1_H_ #define _ATH_AH_EEPROM_V1_H_ diff --git a/sys/dev/ath/ath_hal/ah_eeprom_v14.c b/sys/dev/ath/ath_hal/ah_eeprom_v14.c index 37e973c..71597e1 100644 --- a/sys/dev/ath/ath_hal/ah_eeprom_v14.c +++ b/sys/dev/ath/ath_hal/ah_eeprom_v14.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ah_eeprom_v14.c 224519 2011-07-30 13:45:12Z adrian $ */ #include "opt_ah.h" diff --git a/sys/dev/ath/ath_hal/ah_eeprom_v14.h b/sys/dev/ath/ath_hal/ah_eeprom_v14.h index 7b2c898..ba8c581 100644 --- a/sys/dev/ath/ath_hal/ah_eeprom_v14.h +++ b/sys/dev/ath/ath_hal/ah_eeprom_v14.h @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ah_eeprom_v14.h 224519 2011-07-30 13:45:12Z adrian $ */ #ifndef _AH_EEPROM_V14_H_ #define _AH_EEPROM_V14_H_ diff --git a/sys/dev/ath/ath_hal/ah_eeprom_v3.c b/sys/dev/ath/ath_hal/ah_eeprom_v3.c index 3a7b0cc..df69550 100644 --- a/sys/dev/ath/ath_hal/ah_eeprom_v3.c +++ b/sys/dev/ath/ath_hal/ah_eeprom_v3.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ah_eeprom_v3.c 221896 2011-05-14 15:12:02Z adrian $ */ #include "opt_ah.h" diff --git a/sys/dev/ath/ath_hal/ah_eeprom_v3.h b/sys/dev/ath/ath_hal/ah_eeprom_v3.h index cde9a10..33e8241 100644 --- a/sys/dev/ath/ath_hal/ah_eeprom_v3.h +++ b/sys/dev/ath/ath_hal/ah_eeprom_v3.h @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ah_eeprom_v3.h 204644 2010-03-03 17:32:32Z rpaulo $ */ #ifndef _ATH_AH_EEPROM_V3_H_ #define _ATH_AH_EEPROM_V3_H_ diff --git a/sys/dev/ath/ath_hal/ah_eeprom_v4k.c b/sys/dev/ath/ath_hal/ah_eeprom_v4k.c index 12cb67e..66f4f4c 100644 --- a/sys/dev/ath/ath_hal/ah_eeprom_v4k.c +++ b/sys/dev/ath/ath_hal/ah_eeprom_v4k.c @@ -15,7 +15,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ah_eeprom_v4k.c 234508 2012-04-20 21:56:13Z adrian $ */ #include "opt_ah.h" diff --git a/sys/dev/ath/ath_hal/ah_eeprom_v4k.h b/sys/dev/ath/ath_hal/ah_eeprom_v4k.h index 3487de4..b9af2bc 100644 --- a/sys/dev/ath/ath_hal/ah_eeprom_v4k.h +++ b/sys/dev/ath/ath_hal/ah_eeprom_v4k.h @@ -15,7 +15,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ah_eeprom_v4k.h 220946 2011-04-22 10:57:46Z adrian $ */ #ifndef _AH_EEPROM_V4K_H_ #define _AH_EEPROM_V4K_H_ diff --git a/sys/dev/ath/ath_hal/ah_internal.h b/sys/dev/ath/ath_hal/ah_internal.h index 908f33e..d229b94 100644 --- a/sys/dev/ath/ath_hal/ah_internal.h +++ b/sys/dev/ath/ath_hal/ah_internal.h @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ah_internal.h 280828 2015-03-29 21:50:21Z adrian $ */ #ifndef _ATH_AH_INTERAL_H_ #define _ATH_AH_INTERAL_H_ @@ -50,8 +50,8 @@ #endif typedef struct { - uint16_t start; /* first register */ - uint16_t end; /* ending register or zero */ + uint32_t start; /* first register */ + uint32_t end; /* ending register or zero */ } HAL_REGRANGE; typedef struct { @@ -91,6 +91,7 @@ struct ath_hal_chip { const char *(*probe)(uint16_t vendorid, uint16_t devid); struct ath_hal *(*attach)(uint16_t devid, HAL_SOFTC, HAL_BUS_TAG, HAL_BUS_HANDLE, uint16_t *eepromdata, + HAL_OPS_CONFIG *ah, HAL_STATUS *error); }; #ifndef AH_CHIP @@ -280,7 +281,9 @@ typedef struct { halAntDivCombSupportOrg : 1, halRadioRetentionSupport : 1, halSpectralScanSupport : 1, - halRxUsingLnaMixing : 1; + halRxUsingLnaMixing : 1, + halRxDoMyBeacon : 1, + halHwUapsdTrig : 1; uint32_t halWirelessModes; uint16_t halTotalQueues; @@ -419,9 +422,13 @@ struct ath_hal_private { uint32_t ah_fatalState[6]; /* AR_ISR+shadow regs */ int ah_rxornIsFatal; /* how to treat HAL_INT_RXORN */ -#ifndef ATH_NF_PER_CHAN + /* Only used if ATH_NF_PER_CHAN is defined */ HAL_NFCAL_HIST_FULL nf_cal_hist; -#endif /* ! ATH_NF_PER_CHAN */ + + /* + * Channel survey history - current channel only. + */ + HAL_CHANNEL_SURVEY ah_chansurvey; /* channel survey */ }; #define AH_PRIVATE(_ah) ((struct ath_hal_private *)(_ah)) @@ -1026,4 +1033,15 @@ ath_hal_getantennaallowed(struct ath_hal *ah, */ extern int ath_hal_mhz2ieee_2ghz(struct ath_hal *, HAL_CHANNEL_INTERNAL *); +/* + * Clear the channel survey data. + */ +extern void ath_hal_survey_clear(struct ath_hal *ah); + +/* + * Add a sample to the channel survey data. + */ +extern void ath_hal_survey_add_sample(struct ath_hal *ah, + HAL_SURVEY_SAMPLE *hs); + #endif /* _ATH_AH_INTERAL_H_ */ diff --git a/sys/dev/ath/ath_hal/ah_regdomain.c b/sys/dev/ath/ath_hal/ah_regdomain.c index 807db44..1148c59 100644 --- a/sys/dev/ath/ath_hal/ah_regdomain.c +++ b/sys/dev/ath/ath_hal/ah_regdomain.c @@ -15,7 +15,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ah_regdomain.c 262375 2014-02-23 18:07:17Z hiren $ */ #include "opt_ah.h" @@ -169,6 +169,11 @@ isEepromValid(struct ath_hal *ah) if (regDomainPairs[i].regDmnEnum == rd) return AH_TRUE; } + + if (rd == FCC_UBNT) { + return AH_TRUE; + } + HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, "%s: invalid regulatory domain/country code 0x%x\n", __func__, rd); return AH_FALSE; diff --git a/sys/dev/ath/ath_hal/ah_regdomain.h b/sys/dev/ath/ath_hal/ah_regdomain.h index e17e79a..e950370 100644 --- a/sys/dev/ath/ath_hal/ah_regdomain.h +++ b/sys/dev/ath/ath_hal/ah_regdomain.h @@ -15,7 +15,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ah_regdomain.h 219442 2011-03-10 03:13:56Z adrian $ */ #ifndef __AH_REGDOMAIN_H__ #define __AH_REGDOMAIN_H__ diff --git a/sys/dev/ath/ath_hal/ah_regdomain/ah_rd_ctry.h b/sys/dev/ath/ath_hal/ah_regdomain/ah_rd_ctry.h index af4824c..5a086ae 100644 --- a/sys/dev/ath/ath_hal/ah_regdomain/ah_rd_ctry.h +++ b/sys/dev/ath/ath_hal/ah_regdomain/ah_rd_ctry.h @@ -15,7 +15,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ah_regdomain/ah_rd_ctry.h 224226 2011-07-20 12:46:58Z adrian $ */ #ifndef __AH_REGDOMAIN_CTRY_H__ diff --git a/sys/dev/ath/ath_hal/ah_regdomain/ah_rd_domains.h b/sys/dev/ath/ath_hal/ah_regdomain/ah_rd_domains.h index 04a6ccd..0be44c0 100644 --- a/sys/dev/ath/ath_hal/ah_regdomain/ah_rd_domains.h +++ b/sys/dev/ath/ath_hal/ah_regdomain/ah_rd_domains.h @@ -15,7 +15,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ah_regdomain/ah_rd_domains.h 248677 2013-03-24 04:42:56Z adrian $ */ #ifndef __AH_REGDOMAIN_DOMAINS_H__ diff --git a/sys/dev/ath/ath_hal/ah_regdomain/ah_rd_freqbands.h b/sys/dev/ath/ath_hal/ah_regdomain/ah_rd_freqbands.h index 79d418f..e8c6d78 100644 --- a/sys/dev/ath/ath_hal/ah_regdomain/ah_rd_freqbands.h +++ b/sys/dev/ath/ath_hal/ah_regdomain/ah_rd_freqbands.h @@ -15,7 +15,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ah_regdomain/ah_rd_freqbands.h 219442 2011-03-10 03:13:56Z adrian $ */ #ifndef __AH_REGDOMAIN_FREQBANDS_H__ diff --git a/sys/dev/ath/ath_hal/ah_regdomain/ah_rd_regenum.h b/sys/dev/ath/ath_hal/ah_regdomain/ah_rd_regenum.h index bc569cb..8f6b3e5 100644 --- a/sys/dev/ath/ath_hal/ah_regdomain/ah_rd_regenum.h +++ b/sys/dev/ath/ath_hal/ah_regdomain/ah_rd_regenum.h @@ -15,7 +15,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ah_regdomain/ah_rd_regenum.h 262375 2014-02-23 18:07:17Z hiren $ */ #ifndef __AH_REGDOMAIN_REGENUM_H__ @@ -51,6 +51,7 @@ enum { FCC2_FCCA = 0x20, /* Canada */ FCC2_WORLD = 0x21, /* Australia & HK */ FCC2_ETSIC = 0x22, + FCC_UBNT = 0x2A, /* Ubiquity PicoStation M2HP */ FRANCE_RES = 0x31, /* Legacy France for OEM */ FCC3_FCCA = 0x3A, /* USA & Canada w/5470 band, 11h, DFS enabled */ FCC3_WORLD = 0x3B, /* USA & Canada w/5470 band, 11h, DFS enabled */ diff --git a/sys/dev/ath/ath_hal/ah_regdomain/ah_rd_regmap.h b/sys/dev/ath/ath_hal/ah_regdomain/ah_rd_regmap.h index f77be22..b7d8450 100644 --- a/sys/dev/ath/ath_hal/ah_regdomain/ah_rd_regmap.h +++ b/sys/dev/ath/ath_hal/ah_regdomain/ah_rd_regmap.h @@ -15,7 +15,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ah_regdomain/ah_rd_regmap.h 248677 2013-03-24 04:42:56Z adrian $ */ #ifndef __AH_REGDOMAIN_REGMAP_H__ diff --git a/sys/dev/ath/ath_hal/ah_soc.h b/sys/dev/ath/ath_hal/ah_soc.h index ca75ae9..021e35b 100644 --- a/sys/dev/ath/ath_hal/ah_soc.h +++ b/sys/dev/ath/ath_hal/ah_soc.h @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ah_soc.h 204644 2010-03-03 17:32:32Z rpaulo $ */ #ifndef _ATH_AH_SOC_H_ #define _ATH_AH_SOC_H_ diff --git a/sys/dev/ath/ath_hal/ar5210/ar5210.h b/sys/dev/ath/ath_hal/ar5210/ar5210.h index 48ccc20..f70eeae 100644 --- a/sys/dev/ath/ath_hal/ar5210/ar5210.h +++ b/sys/dev/ath/ath_hal/ar5210/ar5210.h @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5210/ar5210.h 264899 2014-04-24 23:11:18Z adrian $ */ #ifndef _ATH_AR5210_H_ #define _ATH_AR5210_H_ @@ -108,7 +108,6 @@ struct ath_hal_5210 { uint32_t ah_txDescInterruptMask; uint32_t ah_txEolInterruptMask; uint32_t ah_txUrnInterruptMask; - HAL_POWER_MODE ah_powerMode; uint8_t ah_bssid[IEEE80211_ADDR_LEN]; HAL_TX_QUEUE_INFO ah_txq[HAL_NUM_TX_QUEUES]; /* beacon+cab+data */ /* @@ -121,6 +120,8 @@ struct ath_hal_5210 { u_int ah_slottime; /* user-specified slot time */ u_int ah_acktimeout; /* user-specified ack timeout */ u_int ah_ctstimeout; /* user-specified cts timeout */ + + uint16_t ah_associd; /* association id */ }; #define AH5210(ah) ((struct ath_hal_5210 *)(ah)) diff --git a/sys/dev/ath/ath_hal/ar5210/ar5210_attach.c b/sys/dev/ath/ath_hal/ar5210/ar5210_attach.c index 3c0ed71..fab58f6 100644 --- a/sys/dev/ath/ath_hal/ar5210/ar5210_attach.c +++ b/sys/dev/ath/ath_hal/ar5210/ar5210_attach.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5210/ar5210_attach.c 272292 2014-09-30 03:19:29Z adrian $ */ #include "opt_ah.h" @@ -183,7 +183,7 @@ static HAL_BOOL ar5210FillCapabilityInfo(struct ath_hal *ah); */ static struct ath_hal * ar5210Attach(uint16_t devid, HAL_SOFTC sc, HAL_BUS_TAG st, HAL_BUS_HANDLE sh, - uint16_t *eepromdata, HAL_STATUS *status) + uint16_t *eepromdata, HAL_OPS_CONFIG *ah_config, HAL_STATUS *status) { #define N(a) (sizeof(a)/sizeof(a[0])) struct ath_hal_5210 *ahp; @@ -219,7 +219,7 @@ ar5210Attach(uint16_t devid, HAL_SOFTC sc, HAL_BUS_TAG st, HAL_BUS_HANDLE sh, AH_PRIVATE(ah)->ah_powerLimit = AR5210_MAX_RATE_POWER; AH_PRIVATE(ah)->ah_tpScale = HAL_TP_SCALE_MAX; /* no scaling */ - ahp->ah_powerMode = HAL_PM_UNDEFINED; + ah->ah_powerMode = HAL_PM_UNDEFINED; ahp->ah_staId1Defaults = 0; ahp->ah_rssiThr = INIT_RSSI_THR; ahp->ah_sifstime = (u_int) -1; diff --git a/sys/dev/ath/ath_hal/ar5210/ar5210_beacon.c b/sys/dev/ath/ath_hal/ar5210/ar5210_beacon.c index e12b039..162ef88 100644 --- a/sys/dev/ath/ath_hal/ar5210/ar5210_beacon.c +++ b/sys/dev/ath/ath_hal/ar5210/ar5210_beacon.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5210/ar5210_beacon.c 225444 2011-09-08 01:23:05Z adrian $ */ #include "opt_ah.h" diff --git a/sys/dev/ath/ath_hal/ar5210/ar5210_interrupts.c b/sys/dev/ath/ath_hal/ar5210/ar5210_interrupts.c index 96b1a2c..5f755d3 100644 --- a/sys/dev/ath/ath_hal/ar5210/ar5210_interrupts.c +++ b/sys/dev/ath/ath_hal/ar5210/ar5210_interrupts.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5210/ar5210_interrupts.c 192397 2009-05-19 17:35:15Z sam $ */ #include "opt_ah.h" diff --git a/sys/dev/ath/ath_hal/ar5210/ar5210_keycache.c b/sys/dev/ath/ath_hal/ar5210/ar5210_keycache.c index 87fb067..a9e0eb8 100644 --- a/sys/dev/ath/ath_hal/ar5210/ar5210_keycache.c +++ b/sys/dev/ath/ath_hal/ar5210/ar5210_keycache.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5210/ar5210_keycache.c 204644 2010-03-03 17:32:32Z rpaulo $ */ #include "opt_ah.h" diff --git a/sys/dev/ath/ath_hal/ar5210/ar5210_misc.c b/sys/dev/ath/ath_hal/ar5210/ar5210_misc.c index 8170880..cfaa58b 100644 --- a/sys/dev/ath/ath_hal/ar5210/ar5210_misc.c +++ b/sys/dev/ath/ath_hal/ar5210/ar5210_misc.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5210/ar5210_misc.c 264899 2014-04-24 23:11:18Z adrian $ */ #include "opt_ah.h" @@ -315,6 +315,7 @@ ar5210WriteAssocid(struct ath_hal *ah, const uint8_t *bssid, uint16_t assocId) /* XXX save bssid for possible re-use on reset */ OS_MEMCPY(ahp->ah_bssid, bssid, IEEE80211_ADDR_LEN); + ahp->ah_associd = assocId; OS_REG_WRITE(ah, AR_BSS_ID0, LE_READ_4(ahp->ah_bssid)); OS_REG_WRITE(ah, AR_BSS_ID1, LE_READ_2(ahp->ah_bssid+4) | ((assocId & 0x3fff)<<AR_BSS_ID1_AID_S)); diff --git a/sys/dev/ath/ath_hal/ar5210/ar5210_phy.c b/sys/dev/ath/ath_hal/ar5210/ar5210_phy.c index 0455d65..62fe89c 100644 --- a/sys/dev/ath/ath_hal/ar5210/ar5210_phy.c +++ b/sys/dev/ath/ath_hal/ar5210/ar5210_phy.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5210/ar5210_phy.c 191022 2009-04-13 21:01:08Z sam $ */ #include "opt_ah.h" diff --git a/sys/dev/ath/ath_hal/ar5210/ar5210_power.c b/sys/dev/ath/ath_hal/ar5210/ar5210_power.c index 1c6909b..12faade 100644 --- a/sys/dev/ath/ath_hal/ar5210/ar5210_power.c +++ b/sys/dev/ath/ath_hal/ar5210/ar5210_power.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5210/ar5210_power.c 265112 2014-04-30 02:03:13Z adrian $ */ #include "opt_ah.h" @@ -93,7 +93,6 @@ ar5210SetPowerModeSleep(struct ath_hal *ah, int setChip) HAL_BOOL ar5210SetPowerMode(struct ath_hal *ah, HAL_POWER_MODE mode, int setChip) { - struct ath_hal_5210 *ahp = AH5210(ah); #ifdef AH_DEBUG static const char* modes[] = { "AWAKE", @@ -105,25 +104,30 @@ ar5210SetPowerMode(struct ath_hal *ah, HAL_POWER_MODE mode, int setChip) int status = AH_TRUE; HALDEBUG(ah, HAL_DEBUG_POWER, "%s: %s -> %s (%s)\n", __func__, - modes[ahp->ah_powerMode], modes[mode], + modes[ah->ah_powerMode], modes[mode], setChip ? "set chip " : ""); switch (mode) { case HAL_PM_AWAKE: + if (setChip) + ah->ah_powerMode = mode; status = ar5210SetPowerModeAwake(ah, setChip); break; case HAL_PM_FULL_SLEEP: ar5210SetPowerModeSleep(ah, setChip); + if (setChip) + ah->ah_powerMode = mode; break; case HAL_PM_NETWORK_SLEEP: ar5210SetPowerModeAuto(ah, setChip); + if (setChip) + ah->ah_powerMode = mode; break; default: HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unknown power mode %u\n", __func__, mode); return AH_FALSE; } - ahp->ah_powerMode = mode; - return status; + return status; } HAL_POWER_MODE diff --git a/sys/dev/ath/ath_hal/ar5210/ar5210_recv.c b/sys/dev/ath/ath_hal/ar5210/ar5210_recv.c index b43d807..7e187ec 100644 --- a/sys/dev/ath/ath_hal/ar5210/ar5210_recv.c +++ b/sys/dev/ath/ath_hal/ar5210/ar5210_recv.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5210/ar5210_recv.c 243317 2012-11-19 23:42:46Z adrian $ */ #include "opt_ah.h" diff --git a/sys/dev/ath/ath_hal/ar5210/ar5210_reset.c b/sys/dev/ath/ath_hal/ar5210/ar5210_reset.c index 1d50f99..34d7db4 100644 --- a/sys/dev/ath/ath_hal/ar5210/ar5210_reset.c +++ b/sys/dev/ath/ath_hal/ar5210/ar5210_reset.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5210/ar5210_reset.c 264899 2014-04-24 23:11:18Z adrian $ */ #include "opt_ah.h" @@ -152,8 +152,12 @@ ar5210Reset(struct ath_hal *ah, HAL_OPMODE opmode, /* Restore previous led state */ OS_REG_WRITE(ah, AR_PCICFG, OS_REG_READ(ah, AR_PCICFG) | ledstate); +#if 0 OS_REG_WRITE(ah, AR_BSS_ID0, LE_READ_4(ahp->ah_bssid)); OS_REG_WRITE(ah, AR_BSS_ID1, LE_READ_2(ahp->ah_bssid + 4)); +#endif + /* BSSID, association id, ps-poll */ + ar5210WriteAssocid(ah, ahp->ah_bssid, ahp->ah_associd); OS_REG_WRITE(ah, AR_TXDP0, 0); OS_REG_WRITE(ah, AR_TXDP1, 0); diff --git a/sys/dev/ath/ath_hal/ar5210/ar5210_xmit.c b/sys/dev/ath/ath_hal/ar5210/ar5210_xmit.c index d376996..ac2c03d 100644 --- a/sys/dev/ath/ath_hal/ar5210/ar5210_xmit.c +++ b/sys/dev/ath/ath_hal/ar5210/ar5210_xmit.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5210/ar5210_xmit.c 243174 2012-11-17 02:39:37Z adrian $ */ #include "opt_ah.h" diff --git a/sys/dev/ath/ath_hal/ar5210/ar5210desc.h b/sys/dev/ath/ath_hal/ar5210/ar5210desc.h index da5c51f..18fe231 100644 --- a/sys/dev/ath/ath_hal/ar5210/ar5210desc.h +++ b/sys/dev/ath/ath_hal/ar5210/ar5210desc.h @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5210/ar5210desc.h 243173 2012-11-17 02:39:09Z adrian $ */ #ifndef _DEV_ATH_AR5210DESC_H #define _DEV_ATH_AR5210DESC_H diff --git a/sys/dev/ath/ath_hal/ar5210/ar5210phy.h b/sys/dev/ath/ath_hal/ar5210/ar5210phy.h index 4ab3025..1235a90 100644 --- a/sys/dev/ath/ath_hal/ar5210/ar5210phy.h +++ b/sys/dev/ath/ath_hal/ar5210/ar5210phy.h @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5210/ar5210phy.h 204644 2010-03-03 17:32:32Z rpaulo $ */ #ifndef _DEV_ATH_AR5210PHY_H #define _DEV_ATH_AR5210PHY_H diff --git a/sys/dev/ath/ath_hal/ar5210/ar5210reg.h b/sys/dev/ath/ath_hal/ar5210/ar5210reg.h index 16cd74e..139fc62 100644 --- a/sys/dev/ath/ath_hal/ar5210/ar5210reg.h +++ b/sys/dev/ath/ath_hal/ar5210/ar5210reg.h @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5210/ar5210reg.h 243317 2012-11-19 23:42:46Z adrian $ */ #ifndef _DEV_ATH_AR5210REG_H #define _DEV_ATH_AR5210REG_H diff --git a/sys/dev/ath/ath_hal/ar5210/ar5k_0007.ini b/sys/dev/ath/ath_hal/ar5210/ar5k_0007.ini index b536483..71295b0 100644 --- a/sys/dev/ath/ath_hal/ar5210/ar5k_0007.ini +++ b/sys/dev/ath/ath_hal/ar5210/ar5k_0007.ini @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5210/ar5k_0007.ini 204644 2010-03-03 17:32:32Z rpaulo $ */ /* crete register init */ diff --git a/sys/dev/ath/ath_hal/ar5211/ar5211.h b/sys/dev/ath/ath_hal/ar5211/ar5211.h index c50531e..2be9306 100644 --- a/sys/dev/ath/ath_hal/ar5211/ar5211.h +++ b/sys/dev/ath/ath_hal/ar5211/ar5211.h @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5211/ar5211.h 262969 2014-03-10 06:03:35Z adrian $ */ #ifndef _ATH_AR5211_H_ #define _ATH_AR5211_H_ @@ -119,7 +119,6 @@ struct ath_hal_5211 { uint32_t ah_txEolInterruptMask; uint32_t ah_txUrnInterruptMask; HAL_TX_QUEUE_INFO ah_txq[HAL_NUM_TX_QUEUES]; - HAL_POWER_MODE ah_powerMode; HAL_ANT_SETTING ah_diversityControl; /* antenna setting */ uint32_t ah_calibrationTime; HAL_BOOL ah_bIQCalibration; diff --git a/sys/dev/ath/ath_hal/ar5211/ar5211_attach.c b/sys/dev/ath/ath_hal/ar5211/ar5211_attach.c index 4549295..791f14d 100644 --- a/sys/dev/ath/ath_hal/ar5211/ar5211_attach.c +++ b/sys/dev/ath/ath_hal/ar5211/ar5211_attach.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5211/ar5211_attach.c 272292 2014-09-30 03:19:29Z adrian $ */ #include "opt_ah.h" @@ -203,7 +203,7 @@ ar5211GetRadioRev(struct ath_hal *ah) static struct ath_hal * ar5211Attach(uint16_t devid, HAL_SOFTC sc, HAL_BUS_TAG st, HAL_BUS_HANDLE sh, uint16_t *eepromdata, - HAL_STATUS *status) + HAL_OPS_CONFIG *ah_config, HAL_STATUS *status) { #define N(a) (sizeof(a)/sizeof(a[0])) struct ath_hal_5211 *ahp; diff --git a/sys/dev/ath/ath_hal/ar5211/ar5211_beacon.c b/sys/dev/ath/ath_hal/ar5211/ar5211_beacon.c index b2775d0..6d59405 100644 --- a/sys/dev/ath/ath_hal/ar5211/ar5211_beacon.c +++ b/sys/dev/ath/ath_hal/ar5211/ar5211_beacon.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5211/ar5211_beacon.c 225444 2011-09-08 01:23:05Z adrian $ */ #include "opt_ah.h" diff --git a/sys/dev/ath/ath_hal/ar5211/ar5211_interrupts.c b/sys/dev/ath/ath_hal/ar5211/ar5211_interrupts.c index 4c20ca1b..f08fa2c 100644 --- a/sys/dev/ath/ath_hal/ar5211/ar5211_interrupts.c +++ b/sys/dev/ath/ath_hal/ar5211/ar5211_interrupts.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5211/ar5211_interrupts.c 192397 2009-05-19 17:35:15Z sam $ */ #include "opt_ah.h" diff --git a/sys/dev/ath/ath_hal/ar5211/ar5211_keycache.c b/sys/dev/ath/ath_hal/ar5211/ar5211_keycache.c index 3e0f922..dce99d2 100644 --- a/sys/dev/ath/ath_hal/ar5211/ar5211_keycache.c +++ b/sys/dev/ath/ath_hal/ar5211/ar5211_keycache.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5211/ar5211_keycache.c 204644 2010-03-03 17:32:32Z rpaulo $ */ #include "opt_ah.h" diff --git a/sys/dev/ath/ath_hal/ar5211/ar5211_misc.c b/sys/dev/ath/ath_hal/ar5211/ar5211_misc.c index a1a5967..f23e770 100644 --- a/sys/dev/ath/ath_hal/ar5211/ar5211_misc.c +++ b/sys/dev/ath/ath_hal/ar5211/ar5211_misc.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5211/ar5211_misc.c 247286 2013-02-25 22:42:43Z adrian $ */ #include "opt_ah.h" diff --git a/sys/dev/ath/ath_hal/ar5211/ar5211_phy.c b/sys/dev/ath/ath_hal/ar5211/ar5211_phy.c index d224732..c531caf 100644 --- a/sys/dev/ath/ath_hal/ar5211/ar5211_phy.c +++ b/sys/dev/ath/ath_hal/ar5211/ar5211_phy.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5211/ar5211_phy.c 191022 2009-04-13 21:01:08Z sam $ */ #include "opt_ah.h" diff --git a/sys/dev/ath/ath_hal/ar5211/ar5211_power.c b/sys/dev/ath/ath_hal/ar5211/ar5211_power.c index 776cfb3..3fb1990 100644 --- a/sys/dev/ath/ath_hal/ar5211/ar5211_power.c +++ b/sys/dev/ath/ath_hal/ar5211/ar5211_power.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5211/ar5211_power.c 265112 2014-04-30 02:03:13Z adrian $ */ #include "opt_ah.h" @@ -95,7 +95,6 @@ ar5211SetPowerModeNetworkSleep(struct ath_hal *ah, int setChip) HAL_BOOL ar5211SetPowerMode(struct ath_hal *ah, HAL_POWER_MODE mode, int setChip) { - struct ath_hal_5211 *ahp = AH5211(ah); #ifdef AH_DEBUG static const char* modes[] = { "AWAKE", @@ -107,25 +106,30 @@ ar5211SetPowerMode(struct ath_hal *ah, HAL_POWER_MODE mode, int setChip) int status = AH_TRUE; HALDEBUG(ah, HAL_DEBUG_POWER, "%s: %s -> %s (%s)\n", __func__, - modes[ahp->ah_powerMode], modes[mode], + modes[ah->ah_powerMode], modes[mode], setChip ? "set chip " : ""); switch (mode) { case HAL_PM_AWAKE: + if (setChip) + ah->ah_powerMode = mode; status = ar5211SetPowerModeAwake(ah, setChip); break; case HAL_PM_FULL_SLEEP: ar5211SetPowerModeSleep(ah, setChip); + if (setChip) + ah->ah_powerMode = mode; break; case HAL_PM_NETWORK_SLEEP: ar5211SetPowerModeNetworkSleep(ah, setChip); + if (setChip) + ah->ah_powerMode = mode; break; default: HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unknown power mode %u\n", __func__, mode); return AH_FALSE; } - ahp->ah_powerMode = mode; - return status; + return status; } HAL_POWER_MODE diff --git a/sys/dev/ath/ath_hal/ar5211/ar5211_recv.c b/sys/dev/ath/ath_hal/ar5211/ar5211_recv.c index 27c4835..632652b 100644 --- a/sys/dev/ath/ath_hal/ar5211/ar5211_recv.c +++ b/sys/dev/ath/ath_hal/ar5211/ar5211_recv.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5211/ar5211_recv.c 238278 2012-07-09 07:19:11Z adrian $ */ #include "opt_ah.h" diff --git a/sys/dev/ath/ath_hal/ar5211/ar5211_reset.c b/sys/dev/ath/ath_hal/ar5211/ar5211_reset.c index 01e3967..0624689 100644 --- a/sys/dev/ath/ath_hal/ar5211/ar5211_reset.c +++ b/sys/dev/ath/ath_hal/ar5211/ar5211_reset.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5211/ar5211_reset.c 234450 2012-04-19 03:26:21Z adrian $ */ #include "opt_ah.h" diff --git a/sys/dev/ath/ath_hal/ar5211/ar5211_xmit.c b/sys/dev/ath/ath_hal/ar5211/ar5211_xmit.c index dc0ad3f..05e8696 100644 --- a/sys/dev/ath/ath_hal/ar5211/ar5211_xmit.c +++ b/sys/dev/ath/ath_hal/ar5211/ar5211_xmit.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5211/ar5211_xmit.c 239051 2012-08-05 10:12:27Z adrian $ */ #include "opt_ah.h" diff --git a/sys/dev/ath/ath_hal/ar5211/ar5211desc.h b/sys/dev/ath/ath_hal/ar5211/ar5211desc.h index 8702e91..45c8bd7 100644 --- a/sys/dev/ath/ath_hal/ar5211/ar5211desc.h +++ b/sys/dev/ath/ath_hal/ar5211/ar5211desc.h @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5211/ar5211desc.h 243249 2012-11-18 20:41:46Z adrian $ */ #ifndef _DEV_ATH_AR5211DESC_H #define _DEV_ATH_AR5211DESC_H diff --git a/sys/dev/ath/ath_hal/ar5211/ar5211phy.h b/sys/dev/ath/ath_hal/ar5211/ar5211phy.h index bf5b67e..db24339 100644 --- a/sys/dev/ath/ath_hal/ar5211/ar5211phy.h +++ b/sys/dev/ath/ath_hal/ar5211/ar5211phy.h @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5211/ar5211phy.h 204644 2010-03-03 17:32:32Z rpaulo $ */ #ifndef _DEV_ATH_AR5211PHY_H #define _DEV_ATH_AR5211PHY_H diff --git a/sys/dev/ath/ath_hal/ar5211/ar5211reg.h b/sys/dev/ath/ath_hal/ar5211/ar5211reg.h index 93d4fc5..b315f36 100644 --- a/sys/dev/ath/ath_hal/ar5211/ar5211reg.h +++ b/sys/dev/ath/ath_hal/ar5211/ar5211reg.h @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5211/ar5211reg.h 228980 2011-12-30 02:58:37Z dim $ */ #ifndef _DEV_ATH_AR5211REG_H #define _DEV_ATH_AR5211REG_H diff --git a/sys/dev/ath/ath_hal/ar5211/boss.ini b/sys/dev/ath/ath_hal/ar5211/boss.ini index e054436..ce3397d 100644 --- a/sys/dev/ath/ath_hal/ar5211/boss.ini +++ b/sys/dev/ath/ath_hal/ar5211/boss.ini @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5211/boss.ini 245952 2013-01-26 22:08:21Z pfg $ */ /* Auto Generated PCI Register Writes. Created: 09/12/02 */ diff --git a/sys/dev/ath/ath_hal/ar5212/ar2316.c b/sys/dev/ath/ath_hal/ar5212/ar2316.c index 9bfc482..9217cb5 100644 --- a/sys/dev/ath/ath_hal/ar5212/ar2316.c +++ b/sys/dev/ath/ath_hal/ar5212/ar2316.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5212/ar2316.c 187831 2009-01-28 18:00:22Z sam $ */ #include "opt_ah.h" diff --git a/sys/dev/ath/ath_hal/ar5212/ar2317.c b/sys/dev/ath/ath_hal/ar5212/ar2317.c index fdf88e3..6ac7529 100644 --- a/sys/dev/ath/ath_hal/ar5212/ar2317.c +++ b/sys/dev/ath/ath_hal/ar5212/ar2317.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5212/ar2317.c 187831 2009-01-28 18:00:22Z sam $ */ #include "opt_ah.h" diff --git a/sys/dev/ath/ath_hal/ar5212/ar2413.c b/sys/dev/ath/ath_hal/ar5212/ar2413.c index e069444..082b99e 100644 --- a/sys/dev/ath/ath_hal/ar5212/ar2413.c +++ b/sys/dev/ath/ath_hal/ar5212/ar2413.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5212/ar2413.c 187831 2009-01-28 18:00:22Z sam $ */ #include "opt_ah.h" diff --git a/sys/dev/ath/ath_hal/ar5212/ar2425.c b/sys/dev/ath/ath_hal/ar5212/ar2425.c index e487489..883d706 100644 --- a/sys/dev/ath/ath_hal/ar5212/ar2425.c +++ b/sys/dev/ath/ath_hal/ar5212/ar2425.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5212/ar2425.c 188979 2009-02-24 01:07:06Z sam $ */ #include "opt_ah.h" diff --git a/sys/dev/ath/ath_hal/ar5212/ar5111.c b/sys/dev/ath/ath_hal/ar5212/ar5111.c index f9fd3f3..23367c6 100644 --- a/sys/dev/ath/ath_hal/ar5212/ar5111.c +++ b/sys/dev/ath/ath_hal/ar5212/ar5111.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5212/ar5111.c 187831 2009-01-28 18:00:22Z sam $ */ #include "opt_ah.h" diff --git a/sys/dev/ath/ath_hal/ar5212/ar5112.c b/sys/dev/ath/ath_hal/ar5212/ar5112.c index c1920b9..82deb87 100644 --- a/sys/dev/ath/ath_hal/ar5212/ar5112.c +++ b/sys/dev/ath/ath_hal/ar5212/ar5112.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5212/ar5112.c 225883 2011-09-30 05:17:57Z adrian $ */ #include "opt_ah.h" diff --git a/sys/dev/ath/ath_hal/ar5212/ar5212.h b/sys/dev/ath/ath_hal/ar5212/ar5212.h index 6d38d65..166170e 100644 --- a/sys/dev/ath/ath_hal/ar5212/ar5212.h +++ b/sys/dev/ath/ath_hal/ar5212/ar5212.h @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5212/ar5212.h 281128 2015-04-06 01:12:53Z adrian $ */ #ifndef _ATH_AR5212_H_ #define _ATH_AR5212_H_ @@ -200,6 +200,7 @@ struct ar5212AniState { #define HAL_ANI_ENA 0x00000001 /* ANI operation enabled */ #define HAL_RSSI_ANI_ENA 0x00000002 /* rssi-based processing ena'd*/ +#if 0 struct ar5212Stats { uint32_t ast_ani_niup; /* ANI increased noise immunity */ uint32_t ast_ani_nidown; /* ANI decreased noise immunity */ @@ -219,6 +220,7 @@ struct ar5212Stats { HAL_MIB_STATS ast_mibstats; /* MIB counter stats */ HAL_NODE_STATS ast_nodestats; /* Latest rssi stats from driver */ }; +#endif /* * NF Cal history buffer @@ -258,7 +260,7 @@ struct ath_hal_5212 { * Runtime state. */ uint32_t ah_maskReg; /* copy of AR_IMR */ - struct ar5212Stats ah_stats; /* various statistics */ + HAL_ANI_STATS ah_stats; /* various statistics */ RF_HAL_FUNCS *ah_rfHal; uint32_t ah_txDescMask; /* mask for TXDESC */ uint32_t ah_txOkInterruptMask; @@ -270,7 +272,6 @@ struct ath_hal_5212 { uint32_t ah_intrTxqs; /* tx q interrupt state */ /* decomp mask array */ uint8_t ah_decompMask[HAL_DECOMP_MASK_SIZE]; - HAL_POWER_MODE ah_powerMode; HAL_ANT_SETTING ah_antControl; /* antenna setting */ HAL_BOOL ah_diversity; /* fast diversity setting */ enum { @@ -320,7 +321,6 @@ struct ath_hal_5212 { struct ar5212AniParams ah_aniParams5; /* 5GHz parameters */ struct ar5212AniState *ah_curani; /* cached last reference */ struct ar5212AniState ah_ani[AH_MAXCHAN]; /* per-channel state */ - HAL_CHANNEL_SURVEY ah_chansurvey; /* channel survey */ /* AR5416 uses some of the AR5212 ANI code; these are the ANI methods */ HAL_BOOL (*ah_aniControl) (struct ath_hal *, HAL_ANI_CMD cmd, int param); @@ -345,6 +345,9 @@ struct ath_hal_5212 { uint32_t ah_txBusy; uint32_t ah_rx_chainmask; uint32_t ah_tx_chainmask; + + /* Used to return ANI statistics to the diagnostic API */ + HAL_ANI_STATS ext_ani_stats; }; #define AH5212(_ah) ((struct ath_hal_5212 *)(_ah)) @@ -627,7 +630,7 @@ extern void ar5212AniAttach(struct ath_hal *, const struct ar5212AniParams *, const struct ar5212AniParams *, HAL_BOOL ena); extern void ar5212AniDetach(struct ath_hal *); extern struct ar5212AniState *ar5212AniGetCurrentState(struct ath_hal *); -extern struct ar5212Stats *ar5212AniGetCurrentStats(struct ath_hal *); +extern HAL_ANI_STATS *ar5212AniGetCurrentStats(struct ath_hal *); extern HAL_BOOL ar5212AniControl(struct ath_hal *, HAL_ANI_CMD cmd, int param); extern HAL_BOOL ar5212AniSetParams(struct ath_hal *, const struct ar5212AniParams *, const struct ar5212AniParams *); diff --git a/sys/dev/ath/ath_hal/ar5212/ar5212.ini b/sys/dev/ath/ath_hal/ar5212/ar5212.ini index 608f91f..37e2d96 100644 --- a/sys/dev/ath/ath_hal/ar5212/ar5212.ini +++ b/sys/dev/ath/ath_hal/ar5212/ar5212.ini @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5212/ar5212.ini 204644 2010-03-03 17:32:32Z rpaulo $ */ /* Auto Generated PCI Register Writes. Created: 09/01/04 */ diff --git a/sys/dev/ath/ath_hal/ar5212/ar5212_ani.c b/sys/dev/ath/ath_hal/ar5212/ar5212_ani.c index 8e87a2f..5674ec1 100644 --- a/sys/dev/ath/ath_hal/ar5212/ar5212_ani.c +++ b/sys/dev/ath/ath_hal/ar5212/ar5212_ani.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5212/ar5212_ani.c 280940 2015-04-01 03:42:46Z adrian $ */ #include "opt_ah.h" @@ -110,7 +110,7 @@ ar5212AniGetCurrentState(struct ath_hal *ah) /* * Return the current statistics. */ -struct ar5212Stats * +HAL_ANI_STATS * ar5212AniGetCurrentStats(struct ath_hal *ah) { struct ath_hal_5212 *ahp = AH5212(ah); @@ -869,7 +869,6 @@ ar5212AniGetListenTime(struct ath_hal *ah) int32_t listenTime = 0; int good; HAL_SURVEY_SAMPLE hs; - HAL_CHANNEL_SURVEY *cs = AH_NULL; /* * We shouldn't see ah_curchan be NULL, but just in case.. @@ -879,21 +878,13 @@ ar5212AniGetListenTime(struct ath_hal *ah) return (0); } - cs = &ahp->ah_chansurvey; - /* * Fetch the current statistics, squirrel away the current * sample, bump the sequence/sample counter. */ OS_MEMZERO(&hs, sizeof(hs)); good = ar5212GetMibCycleCounts(ah, &hs); - if (cs != AH_NULL) { - OS_MEMCPY(&cs->samples[cs->cur_sample], &hs, sizeof(hs)); - cs->samples[cs->cur_sample].seq_num = cs->cur_seq; - cs->cur_sample = - (cs->cur_sample + 1) % CHANNEL_SURVEY_SAMPLE_COUNT; - cs->cur_seq++; - } + ath_hal_survey_add_sample(ah, &hs); if (ANI_ENA(ah)) aniState = ahp->ah_curani; diff --git a/sys/dev/ath/ath_hal/ar5212/ar5212_attach.c b/sys/dev/ath/ath_hal/ar5212/ar5212_attach.c index e0af27c..ee18ce7 100644 --- a/sys/dev/ath/ath_hal/ar5212/ar5212_attach.c +++ b/sys/dev/ath/ath_hal/ar5212/ar5212_attach.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5212/ar5212_attach.c 272292 2014-09-30 03:19:29Z adrian $ */ #include "opt_ah.h" @@ -317,7 +317,7 @@ ar5212IsMacSupported(uint8_t macVersion, uint8_t macRev) static struct ath_hal * ar5212Attach(uint16_t devid, HAL_SOFTC sc, HAL_BUS_TAG st, HAL_BUS_HANDLE sh, uint16_t *eepromdata, - HAL_STATUS *status) + HAL_OPS_CONFIG *ah_config, HAL_STATUS *status) { #define AH_EEPROM_PROTECT(ah) \ (AH_PRIVATE(ah)->ah_ispcie)? AR_EEPROM_PROTECT_PCIE : AR_EEPROM_PROTECT) diff --git a/sys/dev/ath/ath_hal/ar5212/ar5212_beacon.c b/sys/dev/ath/ath_hal/ar5212/ar5212_beacon.c index b52077f..e84bab3 100644 --- a/sys/dev/ath/ath_hal/ar5212/ar5212_beacon.c +++ b/sys/dev/ath/ath_hal/ar5212/ar5212_beacon.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5212/ar5212_beacon.c 243588 2012-11-27 02:18:41Z adrian $ */ #include "opt_ah.h" diff --git a/sys/dev/ath/ath_hal/ar5212/ar5212_eeprom.c b/sys/dev/ath/ath_hal/ar5212/ar5212_eeprom.c index f4b6771..3e897e4 100644 --- a/sys/dev/ath/ath_hal/ar5212/ar5212_eeprom.c +++ b/sys/dev/ath/ath_hal/ar5212/ar5212_eeprom.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5212/ar5212_eeprom.c 204644 2010-03-03 17:32:32Z rpaulo $ */ #include "opt_ah.h" diff --git a/sys/dev/ath/ath_hal/ar5212/ar5212_gpio.c b/sys/dev/ath/ath_hal/ar5212/ar5212_gpio.c index b2363af..be57458 100644 --- a/sys/dev/ath/ath_hal/ar5212/ar5212_gpio.c +++ b/sys/dev/ath/ath_hal/ar5212/ar5212_gpio.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5212/ar5212_gpio.c 188974 2009-02-24 00:12:16Z sam $ */ #include "opt_ah.h" diff --git a/sys/dev/ath/ath_hal/ar5212/ar5212_interrupts.c b/sys/dev/ath/ath_hal/ar5212/ar5212_interrupts.c index 47f9e74..a3ec20d 100644 --- a/sys/dev/ath/ath_hal/ar5212/ar5212_interrupts.c +++ b/sys/dev/ath/ath_hal/ar5212/ar5212_interrupts.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5212/ar5212_interrupts.c 201758 2010-01-07 21:01:37Z mbr $ */ #include "opt_ah.h" diff --git a/sys/dev/ath/ath_hal/ar5212/ar5212_keycache.c b/sys/dev/ath/ath_hal/ar5212/ar5212_keycache.c index bf7db49..6364bf5 100644 --- a/sys/dev/ath/ath_hal/ar5212/ar5212_keycache.c +++ b/sys/dev/ath/ath_hal/ar5212/ar5212_keycache.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5212/ar5212_keycache.c 218483 2011-02-09 15:23:16Z adrian $ */ #include "opt_ah.h" diff --git a/sys/dev/ath/ath_hal/ar5212/ar5212_misc.c b/sys/dev/ath/ath_hal/ar5212/ar5212_misc.c index 71ee845..1e1f10b 100644 --- a/sys/dev/ath/ath_hal/ar5212/ar5212_misc.c +++ b/sys/dev/ath/ath_hal/ar5212/ar5212_misc.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5212/ar5212_misc.c 281128 2015-04-06 01:12:53Z adrian $ */ #include "opt_ah.h" @@ -1052,6 +1052,7 @@ ar5212GetDiagState(struct ath_hal *ah, int request, void **result, uint32_t *resultsize) { struct ath_hal_5212 *ahp = AH5212(ah); + HAL_ANI_STATS *astats; (void) ahp; if (ath_hal_getdiagstate(ah, request, args, argsize, result, resultsize)) @@ -1083,9 +1084,16 @@ ar5212GetDiagState(struct ath_hal *ah, int request, 0 : sizeof(struct ar5212AniState); return AH_TRUE; case HAL_DIAG_ANI_STATS: - *result = ar5212AniGetCurrentStats(ah); - *resultsize = (*result == AH_NULL) ? - 0 : sizeof(struct ar5212Stats); + OS_MEMZERO(&ahp->ext_ani_stats, sizeof(ahp->ext_ani_stats)); + astats = ar5212AniGetCurrentStats(ah); + if (astats == NULL) { + *result = NULL; + *resultsize = 0; + } else { + OS_MEMCPY(&ahp->ext_ani_stats, astats, sizeof(HAL_ANI_STATS)); + *result = &ahp->ext_ani_stats; + *resultsize = sizeof(ahp->ext_ani_stats); + } return AH_TRUE; case HAL_DIAG_ANI_CMD: if (argsize != 2*sizeof(uint32_t)) @@ -1113,10 +1121,6 @@ ar5212GetDiagState(struct ath_hal *ah, int request, return ar5212AniSetParams(ah, args, args); } break; - case HAL_DIAG_CHANSURVEY: - *result = &ahp->ah_chansurvey; - *resultsize = sizeof(HAL_CHANNEL_SURVEY); - return AH_TRUE; } return AH_FALSE; } diff --git a/sys/dev/ath/ath_hal/ar5212/ar5212_phy.c b/sys/dev/ath/ath_hal/ar5212/ar5212_phy.c index ac55be6..e92a52e 100644 --- a/sys/dev/ath/ath_hal/ar5212/ar5212_phy.c +++ b/sys/dev/ath/ath_hal/ar5212/ar5212_phy.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5212/ar5212_phy.c 191022 2009-04-13 21:01:08Z sam $ */ #include "opt_ah.h" diff --git a/sys/dev/ath/ath_hal/ar5212/ar5212_power.c b/sys/dev/ath/ath_hal/ar5212/ar5212_power.c index 3f755bd..435c975 100644 --- a/sys/dev/ath/ath_hal/ar5212/ar5212_power.c +++ b/sys/dev/ath/ath_hal/ar5212/ar5212_power.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5212/ar5212_power.c 265112 2014-04-30 02:03:13Z adrian $ */ #include "opt_ah.h" @@ -119,7 +119,6 @@ ar5212SetPowerModeNetworkSleep(struct ath_hal *ah, int setChip) HAL_BOOL ar5212SetPowerMode(struct ath_hal *ah, HAL_POWER_MODE mode, int setChip) { - struct ath_hal_5212 *ahp = AH5212(ah); #ifdef AH_DEBUG static const char* modes[] = { "AWAKE", @@ -131,24 +130,29 @@ ar5212SetPowerMode(struct ath_hal *ah, HAL_POWER_MODE mode, int setChip) int status = AH_TRUE; HALDEBUG(ah, HAL_DEBUG_POWER, "%s: %s -> %s (%s)\n", __func__, - modes[ahp->ah_powerMode], modes[mode], + modes[ah->ah_powerMode], modes[mode], setChip ? "set chip " : ""); switch (mode) { case HAL_PM_AWAKE: + if (setChip) + ah->ah_powerMode = mode; status = ar5212SetPowerModeAwake(ah, setChip); break; case HAL_PM_FULL_SLEEP: ar5212SetPowerModeSleep(ah, setChip); + if (setChip) + ah->ah_powerMode = mode; break; case HAL_PM_NETWORK_SLEEP: ar5212SetPowerModeNetworkSleep(ah, setChip); + if (setChip) + ah->ah_powerMode = mode; break; default: HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unknown power mode %u\n", __func__, mode); return AH_FALSE; } - ahp->ah_powerMode = mode; return status; } diff --git a/sys/dev/ath/ath_hal/ar5212/ar5212_recv.c b/sys/dev/ath/ath_hal/ar5212/ar5212_recv.c index 958a954..82d2f67 100644 --- a/sys/dev/ath/ath_hal/ar5212/ar5212_recv.c +++ b/sys/dev/ath/ath_hal/ar5212/ar5212_recv.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5212/ar5212_recv.c 243169 2012-11-17 02:02:36Z adrian $ */ #include "opt_ah.h" diff --git a/sys/dev/ath/ath_hal/ar5212/ar5212_reset.c b/sys/dev/ath/ath_hal/ar5212/ar5212_reset.c index eca2e1f..2851268 100644 --- a/sys/dev/ath/ath_hal/ar5212/ar5212_reset.c +++ b/sys/dev/ath/ath_hal/ar5212/ar5212_reset.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5212/ar5212_reset.c 280828 2015-03-29 21:50:21Z adrian $ */ #include "opt_ah.h" @@ -197,7 +197,8 @@ ar5212Reset(struct ath_hal *ah, HAL_OPMODE opmode, saveFrameSeqCount = 0; /* NB: silence compiler */ /* Blank the channel survey statistics */ - OS_MEMZERO(&ahp->ah_chansurvey, sizeof(ahp->ah_chansurvey)); + ath_hal_survey_clear(ah); + #if 0 /* * XXX disable for now; this appears to sometimes cause OFDM @@ -2605,6 +2606,12 @@ ar5212GetTargetPowers(struct ath_hal *ah, const struct ieee80211_channel *chan, powInfo[ixlo].twicePwr54, powInfo[ixhi].twicePwr54); } +static uint32_t +udiff(uint32_t u, uint32_t v) +{ + return (u >= v ? u - v : v - u); +} + /* * Search a list for a specified value v that is within * EEP_DELTA of the search values. Return the closest @@ -2639,7 +2646,7 @@ ar5212GetLowerUpperValues(uint16_t v, uint16_t *lp, uint16_t listSize, * If value is close to the current value of the list * then target is not between values, it is one of the values */ - if (abs(lp[0] * EEP_SCALE - target) < EEP_DELTA) { + if (udiff(lp[0] * EEP_SCALE, target) < EEP_DELTA) { *vlo = *vhi = lp[0]; return; } diff --git a/sys/dev/ath/ath_hal/ar5212/ar5212_rfgain.c b/sys/dev/ath/ath_hal/ar5212/ar5212_rfgain.c index f9fbc9c..6236142 100644 --- a/sys/dev/ath/ath_hal/ar5212/ar5212_rfgain.c +++ b/sys/dev/ath/ath_hal/ar5212/ar5212_rfgain.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5212/ar5212_rfgain.c 188197 2009-02-05 21:13:31Z sam $ */ #include "opt_ah.h" diff --git a/sys/dev/ath/ath_hal/ar5212/ar5212_xmit.c b/sys/dev/ath/ath_hal/ar5212/ar5212_xmit.c index 5aeefed..665af67 100644 --- a/sys/dev/ath/ath_hal/ar5212/ar5212_xmit.c +++ b/sys/dev/ath/ath_hal/ar5212/ar5212_xmit.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5212/ar5212_xmit.c 243169 2012-11-17 02:02:36Z adrian $ */ #include "opt_ah.h" diff --git a/sys/dev/ath/ath_hal/ar5212/ar5212desc.h b/sys/dev/ath/ath_hal/ar5212/ar5212desc.h index ce01dd2..6c66920 100644 --- a/sys/dev/ath/ath_hal/ar5212/ar5212desc.h +++ b/sys/dev/ath/ath_hal/ar5212/ar5212desc.h @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5212/ar5212desc.h 243168 2012-11-17 02:00:33Z adrian $ */ #ifndef _ATH_AR5212_DESC_H_ #define _ATH_AR5212_DESC_H_ diff --git a/sys/dev/ath/ath_hal/ar5212/ar5212phy.h b/sys/dev/ath/ath_hal/ar5212/ar5212phy.h index 9e9bbbf..d5dd261 100644 --- a/sys/dev/ath/ath_hal/ar5212/ar5212phy.h +++ b/sys/dev/ath/ath_hal/ar5212/ar5212phy.h @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5212/ar5212phy.h 239801 2012-08-29 03:58:13Z adrian $ */ #ifndef _DEV_ATH_AR5212PHY_H_ #define _DEV_ATH_AR5212PHY_H_ diff --git a/sys/dev/ath/ath_hal/ar5212/ar5212reg.h b/sys/dev/ath/ath_hal/ar5212/ar5212reg.h index 96dfa9d..0cdd1b5 100644 --- a/sys/dev/ath/ath_hal/ar5212/ar5212reg.h +++ b/sys/dev/ath/ath_hal/ar5212/ar5212reg.h @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5212/ar5212reg.h 226489 2011-10-18 03:17:06Z adrian $ */ #ifndef _DEV_ATH_AR5212REG_H_ #define _DEV_ATH_AR5212REG_H_ diff --git a/sys/dev/ath/ath_hal/ar5212/ar5311reg.h b/sys/dev/ath/ath_hal/ar5212/ar5311reg.h index b79370e..220723c 100644 --- a/sys/dev/ath/ath_hal/ar5212/ar5311reg.h +++ b/sys/dev/ath/ath_hal/ar5212/ar5311reg.h @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5212/ar5311reg.h 204644 2010-03-03 17:32:32Z rpaulo $ */ #ifndef _DEV_ATH_AR5311REG_H_ #define _DEV_ATH_AR5311REG_H_ diff --git a/sys/dev/ath/ath_hal/ar5212/ar5413.c b/sys/dev/ath/ath_hal/ar5212/ar5413.c index ab6cc65..6b1af69 100644 --- a/sys/dev/ath/ath_hal/ar5212/ar5413.c +++ b/sys/dev/ath/ath_hal/ar5212/ar5413.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5212/ar5413.c 188979 2009-02-24 01:07:06Z sam $ */ #include "opt_ah.h" diff --git a/sys/dev/ath/ath_hal/ar5312/ar5312.h b/sys/dev/ath/ath_hal/ar5312/ar5312.h index 0fb9b75..da8860f 100644 --- a/sys/dev/ath/ath_hal/ar5312/ar5312.h +++ b/sys/dev/ath/ath_hal/ar5312/ar5312.h @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5312/ar5312.h 188974 2009-02-24 00:12:16Z sam $ */ #ifndef _ATH_AR5312_H_ #define _ATH_AR5312_H_ diff --git a/sys/dev/ath/ath_hal/ar5312/ar5312_attach.c b/sys/dev/ath/ath_hal/ar5312/ar5312_attach.c index 4ca1a4d..66447fa 100644 --- a/sys/dev/ath/ath_hal/ar5312/ar5312_attach.c +++ b/sys/dev/ath/ath_hal/ar5312/ar5312_attach.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5312/ar5312_attach.c 272292 2014-09-30 03:19:29Z adrian $ */ #include "opt_ah.h" @@ -62,7 +62,7 @@ ar5312AniSetup(struct ath_hal *ah) static struct ath_hal * ar5312Attach(uint16_t devid, HAL_SOFTC sc, HAL_BUS_TAG st, HAL_BUS_HANDLE sh, uint16_t *eepromdata, - HAL_STATUS *status) + HAL_OPS_CONFIG *ah_config, HAL_STATUS *status) { struct ath_hal_5212 *ahp = AH_NULL; struct ath_hal *ah; diff --git a/sys/dev/ath/ath_hal/ar5312/ar5312_eeprom.c b/sys/dev/ath/ath_hal/ar5312/ar5312_eeprom.c index 7a84232..2f89dcc 100644 --- a/sys/dev/ath/ath_hal/ar5312/ar5312_eeprom.c +++ b/sys/dev/ath/ath_hal/ar5312/ar5312_eeprom.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5312/ar5312_eeprom.c 204644 2010-03-03 17:32:32Z rpaulo $ */ #include "opt_ah.h" diff --git a/sys/dev/ath/ath_hal/ar5312/ar5312_gpio.c b/sys/dev/ath/ath_hal/ar5312/ar5312_gpio.c index 20a575d..7d2e7e3 100644 --- a/sys/dev/ath/ath_hal/ar5312/ar5312_gpio.c +++ b/sys/dev/ath/ath_hal/ar5312/ar5312_gpio.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5312/ar5312_gpio.c 188974 2009-02-24 00:12:16Z sam $ */ #include "opt_ah.h" diff --git a/sys/dev/ath/ath_hal/ar5312/ar5312_interrupts.c b/sys/dev/ath/ath_hal/ar5312/ar5312_interrupts.c index 0a1545c..1360875 100644 --- a/sys/dev/ath/ath_hal/ar5312/ar5312_interrupts.c +++ b/sys/dev/ath/ath_hal/ar5312/ar5312_interrupts.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5312/ar5312_interrupts.c 204644 2010-03-03 17:32:32Z rpaulo $ */ #include "opt_ah.h" diff --git a/sys/dev/ath/ath_hal/ar5312/ar5312_misc.c b/sys/dev/ath/ath_hal/ar5312/ar5312_misc.c index 3d85ece..318ff24 100644 --- a/sys/dev/ath/ath_hal/ar5312/ar5312_misc.c +++ b/sys/dev/ath/ath_hal/ar5312/ar5312_misc.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5312/ar5312_misc.c 204644 2010-03-03 17:32:32Z rpaulo $ */ #include "opt_ah.h" diff --git a/sys/dev/ath/ath_hal/ar5312/ar5312_power.c b/sys/dev/ath/ath_hal/ar5312/ar5312_power.c index 94a0f1c..0aa52460 100644 --- a/sys/dev/ath/ath_hal/ar5312/ar5312_power.c +++ b/sys/dev/ath/ath_hal/ar5312/ar5312_power.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5312/ar5312_power.c 262969 2014-03-10 06:03:35Z adrian $ */ #include "opt_ah.h" @@ -71,7 +71,6 @@ ar5312SetPowerModeNetworkSleep(struct ath_hal *ah, int setChip) HAL_BOOL ar5312SetPowerMode(struct ath_hal *ah, HAL_POWER_MODE mode, int setChip) { - struct ath_hal_5212 *ahp = AH5212(ah); #ifdef AH_DEBUG static const char* modes[] = { "AWAKE", @@ -83,7 +82,7 @@ ar5312SetPowerMode(struct ath_hal *ah, HAL_POWER_MODE mode, int setChip) int status = AH_TRUE; HALDEBUG(ah, HAL_DEBUG_POWER, "%s: %s -> %s (%s)\n", __func__, - modes[ahp->ah_powerMode], modes[mode], + modes[ah->ah_powerMode], modes[mode], setChip ? "set chip " : ""); switch (mode) { case HAL_PM_AWAKE: @@ -100,7 +99,7 @@ ar5312SetPowerMode(struct ath_hal *ah, HAL_POWER_MODE mode, int setChip) __func__, mode); return AH_FALSE; } - ahp->ah_powerMode = mode; + ah->ah_powerMode = mode; return status; } diff --git a/sys/dev/ath/ath_hal/ar5312/ar5312_reset.c b/sys/dev/ath/ath_hal/ar5312/ar5312_reset.c index fdba35d..1b03f10 100644 --- a/sys/dev/ath/ath_hal/ar5312/ar5312_reset.c +++ b/sys/dev/ath/ath_hal/ar5312/ar5312_reset.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5312/ar5312_reset.c 234450 2012-04-19 03:26:21Z adrian $ */ #include "opt_ah.h" diff --git a/sys/dev/ath/ath_hal/ar5312/ar5312phy.h b/sys/dev/ath/ath_hal/ar5312/ar5312phy.h index fcb8564..513014d 100644 --- a/sys/dev/ath/ath_hal/ar5312/ar5312phy.h +++ b/sys/dev/ath/ath_hal/ar5312/ar5312phy.h @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5312/ar5312phy.h 204644 2010-03-03 17:32:32Z rpaulo $ */ #ifndef _DEV_ATH_AR5312PHY_H_ #define _DEV_ATH_AR5312PHY_H_ diff --git a/sys/dev/ath/ath_hal/ar5312/ar5312reg.h b/sys/dev/ath/ath_hal/ar5312/ar5312reg.h index bdfeffa..4210950 100644 --- a/sys/dev/ath/ath_hal/ar5312/ar5312reg.h +++ b/sys/dev/ath/ath_hal/ar5312/ar5312reg.h @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5312/ar5312reg.h 204644 2010-03-03 17:32:32Z rpaulo $ */ #ifndef _DEV_ATH_AR5312REG_H_ #define _DEV_ATH_AR5312REG_H_ diff --git a/sys/dev/ath/ath_hal/ar5312/ar5315_gpio.c b/sys/dev/ath/ath_hal/ar5312/ar5315_gpio.c index 4c04c86..45666bb 100644 --- a/sys/dev/ath/ath_hal/ar5312/ar5315_gpio.c +++ b/sys/dev/ath/ath_hal/ar5312/ar5315_gpio.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5312/ar5315_gpio.c 188974 2009-02-24 00:12:16Z sam $ */ #include "opt_ah.h" diff --git a/sys/dev/ath/ath_hal/ar5416/ar2133.c b/sys/dev/ath/ath_hal/ar5416/ar2133.c index 457a7c3..c2f9534 100644 --- a/sys/dev/ath/ath_hal/ar5416/ar2133.c +++ b/sys/dev/ath/ath_hal/ar5416/ar2133.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5416/ar2133.c 241195 2012-10-04 15:42:45Z adrian $ */ #include "opt_ah.h" diff --git a/sys/dev/ath/ath_hal/ar5416/ar5416.h b/sys/dev/ath/ath_hal/ar5416/ar5416.h index a631aad..d1d6d26 100644 --- a/sys/dev/ath/ath_hal/ar5416/ar5416.h +++ b/sys/dev/ath/ath_hal/ar5416/ar5416.h @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5416/ar5416.h 249580 2013-04-17 07:31:53Z adrian $ */ #ifndef _ATH_AR5416_H_ #define _ATH_AR5416_H_ diff --git a/sys/dev/ath/ath_hal/ar5416/ar5416.ini b/sys/dev/ath/ath_hal/ar5416/ar5416.ini index 7f8c793..229b7de 100644 --- a/sys/dev/ath/ath_hal/ar5416/ar5416.ini +++ b/sys/dev/ath/ath_hal/ar5416/ar5416.ini @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5416/ar5416.ini 225420 2011-09-06 10:49:05Z adrian $ */ /* Auto Generated PCI Register Writes. Created: 09/20/06 */ diff --git a/sys/dev/ath/ath_hal/ar5416/ar5416_ani.c b/sys/dev/ath/ath_hal/ar5416/ar5416_ani.c index 3f9bc69..fb13241 100644 --- a/sys/dev/ath/ath_hal/ar5416/ar5416_ani.c +++ b/sys/dev/ath/ath_hal/ar5416/ar5416_ani.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5416/ar5416_ani.c 280828 2015-03-29 21:50:21Z adrian $ */ #include "opt_ah.h" @@ -818,7 +818,6 @@ ar5416AniGetListenTime(struct ath_hal *ah) int32_t listenTime = 0; int good; HAL_SURVEY_SAMPLE hs; - HAL_CHANNEL_SURVEY *cs = AH_NULL; /* * We shouldn't see ah_curchan be NULL, but just in case.. @@ -828,21 +827,13 @@ ar5416AniGetListenTime(struct ath_hal *ah) return (0); } - cs = &ahp->ah_chansurvey; - /* * Fetch the current statistics, squirrel away the current - * sample, bump the sequence/sample counter. + * sample. */ OS_MEMZERO(&hs, sizeof(hs)); good = ar5416GetMibCycleCounts(ah, &hs); - if (cs != AH_NULL) { - OS_MEMCPY(&cs->samples[cs->cur_sample], &hs, sizeof(hs)); - cs->samples[cs->cur_sample].seq_num = cs->cur_seq; - cs->cur_sample = - (cs->cur_sample + 1) % CHANNEL_SURVEY_SAMPLE_COUNT; - cs->cur_seq++; - } + ath_hal_survey_add_sample(ah, &hs); if (ANI_ENA(ah)) aniState = ahp->ah_curani; diff --git a/sys/dev/ath/ath_hal/ar5416/ar5416_attach.c b/sys/dev/ath/ath_hal/ar5416/ar5416_attach.c index 99bab06..2b6d93a 100644 --- a/sys/dev/ath/ath_hal/ar5416/ar5416_attach.c +++ b/sys/dev/ath/ath_hal/ar5416/ar5416_attach.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5416/ar5416_attach.c 272292 2014-09-30 03:19:29Z adrian $ */ #include "opt_ah.h" @@ -297,7 +297,7 @@ ar5416GetRadioRev(struct ath_hal *ah) static struct ath_hal * ar5416Attach(uint16_t devid, HAL_SOFTC sc, HAL_BUS_TAG st, HAL_BUS_HANDLE sh, uint16_t *eepromdata, - HAL_STATUS *status) + HAL_OPS_CONFIG *ah_config, HAL_STATUS *status) { struct ath_hal_5416 *ahp5416; struct ath_hal_5212 *ahp; @@ -1059,6 +1059,11 @@ ar5416FillCapabilityInfo(struct ath_hal *ah) if (! AH_PRIVATE(ah)->ah_ispcie) pCap->halSerialiseRegWar = 1; + /* + * AR5416 and later NICs support MYBEACON filtering. + */ + pCap->halRxDoMyBeacon = AH_TRUE; + return AH_TRUE; } diff --git a/sys/dev/ath/ath_hal/ar5416/ar5416_beacon.c b/sys/dev/ath/ath_hal/ar5416/ar5416_beacon.c index e2bf6c7..2f2997e 100644 --- a/sys/dev/ath/ath_hal/ar5416/ar5416_beacon.c +++ b/sys/dev/ath/ath_hal/ar5416/ar5416_beacon.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5416/ar5416_beacon.c 265031 2014-04-27 23:35:05Z adrian $ */ #include "opt_ah.h" @@ -197,6 +197,25 @@ ar5416SetStaBeaconTimers(struct ath_hal *ah, const HAL_BEACON_STATE *bs) * beacon jitter; cab timeout is max time to wait for cab * after seeing the last DTIM or MORE CAB bit */ + +/* + * I've bumped these to 30TU for now. + * + * Some APs (AR933x/AR934x?) in 2GHz especially seem to not always + * transmit beacon frames at exactly the right times and with it set + * to 10TU, the NIC starts not waking up at the right times to hear + * these slightly-larger-jitering beacons. It also never recovers + * from that (it doesn't resync? I'm not sure.) + * + * So for now bump this to 30TU. Ideally we'd cap this based on + * the beacon interval so the sum of CAB+BEACON timeouts never + * exceeded the beacon interval. + * + * Now, since we're doing all the math in the ath(4) driver in TU + * rather than TSF, we may be seeing the result of dumb rounding + * errors causing the jitter to actually be a much bigger problem. + * I'll have to investigate that with a fine tooth comb. + */ #define CAB_TIMEOUT_VAL 10 /* in TU */ #define BEACON_TIMEOUT_VAL 10 /* in TU */ #define SLEEP_SLOP 3 /* in TU */ @@ -248,6 +267,13 @@ ar5416SetStaBeaconTimers(struct ath_hal *ah, const HAL_BEACON_STATE *bs) OS_REG_SET_BIT(ah, AR_TIMER_MODE, AR_TIMER_MODE_TBTT | AR_TIMER_MODE_TIM | AR_TIMER_MODE_DTIM); + +#define HAL_TSFOOR_THRESHOLD 0x00004240 /* TSF OOR threshold (16k us) */ + + /* TSF out of range threshold */ +// OS_REG_WRITE(ah, AR_TSFOOR_THRESHOLD, bs->bs_tsfoor_threshold); + OS_REG_WRITE(ah, AR_TSFOOR_THRESHOLD, HAL_TSFOOR_THRESHOLD); + HALDEBUG(ah, HAL_DEBUG_BEACON, "%s: next DTIM %d\n", __func__, bs->bs_nextdtim); HALDEBUG(ah, HAL_DEBUG_BEACON, "%s: next beacon %d\n", diff --git a/sys/dev/ath/ath_hal/ar5416/ar5416_btcoex.c b/sys/dev/ath/ath_hal/ar5416/ar5416_btcoex.c index c73b0ee..4f15e4f 100644 --- a/sys/dev/ath/ath_hal/ar5416/ar5416_btcoex.c +++ b/sys/dev/ath/ath_hal/ar5416/ar5416_btcoex.c @@ -15,7 +15,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5416/ar5416_btcoex.c 251483 2013-06-07 05:17:58Z adrian $ */ #include "opt_ah.h" diff --git a/sys/dev/ath/ath_hal/ar5416/ar5416_btcoex.h b/sys/dev/ath/ath_hal/ar5416/ar5416_btcoex.h index 0d3e316..7d5f359 100644 --- a/sys/dev/ath/ath_hal/ar5416/ar5416_btcoex.h +++ b/sys/dev/ath/ath_hal/ar5416/ar5416_btcoex.h @@ -13,7 +13,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5416/ar5416_btcoex.h 237621 2012-06-27 03:00:29Z adrian $ */ #ifndef __ATH_AR5416_BTCOEX_H__ diff --git a/sys/dev/ath/ath_hal/ar5416/ar5416_cal.c b/sys/dev/ath/ath_hal/ar5416/ar5416_cal.c index d51417f4..8bbfdcd 100644 --- a/sys/dev/ath/ath_hal/ar5416/ar5416_cal.c +++ b/sys/dev/ath/ath_hal/ar5416/ar5416_cal.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5416/ar5416_cal.c 277290 2015-01-17 07:33:02Z adrian $ */ #include "opt_ah.h" @@ -663,7 +663,7 @@ ar5416LoadNF(struct ath_hal *ah, const struct ieee80211_channel *chan) * by the median we just loaded. This will be initial (and max) value * of next noise floor calibration the baseband does. */ - for (i = 0; i < AR5416_NUM_NF_READINGS; i ++) + for (i = 0; i < AR5416_NUM_NF_READINGS; i ++) { /* Don't write to EXT radio CCA registers unless in HT/40 mode */ /* XXX this check should really be cleaner! */ @@ -676,6 +676,7 @@ ar5416LoadNF(struct ath_hal *ah, const struct ieee80211_channel *chan) val |= (((uint32_t)(-50) << 1) & 0x1ff); OS_REG_WRITE(ah, ar5416_cca_regs[i], val); } + } } /* diff --git a/sys/dev/ath/ath_hal/ar5416/ar5416_cal.h b/sys/dev/ath/ath_hal/ar5416/ar5416_cal.h index a4f19e5..342b9b3c 100644 --- a/sys/dev/ath/ath_hal/ar5416/ar5416_cal.h +++ b/sys/dev/ath/ath_hal/ar5416/ar5416_cal.h @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5416/ar5416_cal.h 219480 2011-03-11 11:35:36Z adrian $ */ #ifndef _ATH_AR5416_CAL_H_ #define _ATH_AR5416_CAL_H_ diff --git a/sys/dev/ath/ath_hal/ar5416/ar5416_cal_adcdc.c b/sys/dev/ath/ath_hal/ar5416/ar5416_cal_adcdc.c index 9083d3a..ee912ed 100644 --- a/sys/dev/ath/ath_hal/ar5416/ar5416_cal_adcdc.c +++ b/sys/dev/ath/ath_hal/ar5416/ar5416_cal_adcdc.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5416/ar5416_cal_adcdc.c 203158 2010-01-29 10:07:17Z rpaulo $ */ #include "opt_ah.h" diff --git a/sys/dev/ath/ath_hal/ar5416/ar5416_cal_adcgain.c b/sys/dev/ath/ath_hal/ar5416/ar5416_cal_adcgain.c index 4af1ca4..590f23a 100644 --- a/sys/dev/ath/ath_hal/ar5416/ar5416_cal_adcgain.c +++ b/sys/dev/ath/ath_hal/ar5416/ar5416_cal_adcgain.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5416/ar5416_cal_adcgain.c 203158 2010-01-29 10:07:17Z rpaulo $ */ #include "opt_ah.h" diff --git a/sys/dev/ath/ath_hal/ar5416/ar5416_cal_iq.c b/sys/dev/ath/ath_hal/ar5416/ar5416_cal_iq.c index 939ba12..75f71f9 100644 --- a/sys/dev/ath/ath_hal/ar5416/ar5416_cal_iq.c +++ b/sys/dev/ath/ath_hal/ar5416/ar5416_cal_iq.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5416/ar5416_cal_iq.c 211306 2010-08-14 15:28:15Z adrian $ */ #include "opt_ah.h" diff --git a/sys/dev/ath/ath_hal/ar5416/ar5416_eeprom.c b/sys/dev/ath/ath_hal/ar5416/ar5416_eeprom.c index 2947726..d3cdfc6 100644 --- a/sys/dev/ath/ath_hal/ar5416/ar5416_eeprom.c +++ b/sys/dev/ath/ath_hal/ar5416/ar5416_eeprom.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5416/ar5416_eeprom.c 203158 2010-01-29 10:07:17Z rpaulo $ */ #include "opt_ah.h" diff --git a/sys/dev/ath/ath_hal/ar5416/ar5416_gpio.c b/sys/dev/ath/ath_hal/ar5416/ar5416_gpio.c index 3c493b4..75139a0 100644 --- a/sys/dev/ath/ath_hal/ar5416/ar5416_gpio.c +++ b/sys/dev/ath/ath_hal/ar5416/ar5416_gpio.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5416/ar5416_gpio.c 237611 2012-06-26 22:16:53Z adrian $ */ #include "opt_ah.h" diff --git a/sys/dev/ath/ath_hal/ar5416/ar5416_interrupts.c b/sys/dev/ath/ath_hal/ar5416/ar5416_interrupts.c index 631ca2f..56312ab 100644 --- a/sys/dev/ath/ath_hal/ar5416/ar5416_interrupts.c +++ b/sys/dev/ath/ath_hal/ar5416/ar5416_interrupts.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5416/ar5416_interrupts.c 265029 2014-04-27 23:31:42Z adrian $ */ #include "opt_ah.h" @@ -337,6 +337,9 @@ ar5416SetInterrupts(struct ath_hal *ah, HAL_INT ints) /* Write the new IMR and store off our SW copy. */ HALDEBUG(ah, HAL_DEBUG_INTERRUPT, "%s: new IMR 0x%x\n", __func__, mask); OS_REG_WRITE(ah, AR_IMR, mask); + /* Flush write */ + (void) OS_REG_READ(ah, AR_IMR); + mask = OS_REG_READ(ah, AR_IMR_S2) & ~(AR_IMR_S2_TIM | AR_IMR_S2_DTIM | AR_IMR_S2_DTIMSYNC | diff --git a/sys/dev/ath/ath_hal/ar5416/ar5416_keycache.c b/sys/dev/ath/ath_hal/ar5416/ar5416_keycache.c index 533fe03..c687152 100644 --- a/sys/dev/ath/ath_hal/ar5416/ar5416_keycache.c +++ b/sys/dev/ath/ath_hal/ar5416/ar5416_keycache.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5416/ar5416_keycache.c 203158 2010-01-29 10:07:17Z rpaulo $ */ #include "opt_ah.h" diff --git a/sys/dev/ath/ath_hal/ar5416/ar5416_misc.c b/sys/dev/ath/ath_hal/ar5416/ar5416_misc.c index dd76843..3c0b775 100644 --- a/sys/dev/ath/ath_hal/ar5416/ar5416_misc.c +++ b/sys/dev/ath/ath_hal/ar5416/ar5416_misc.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5416/ar5416_misc.c 250856 2013-05-21 14:28:05Z adrian $ */ #include "opt_ah.h" diff --git a/sys/dev/ath/ath_hal/ar5416/ar5416_phy.c b/sys/dev/ath/ath_hal/ar5416/ar5416_phy.c index 1cfd964..1b704b8 100644 --- a/sys/dev/ath/ath_hal/ar5416/ar5416_phy.c +++ b/sys/dev/ath/ath_hal/ar5416/ar5416_phy.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5416/ar5416_phy.c 218908 2011-02-21 05:10:34Z adrian $ */ #include "opt_ah.h" diff --git a/sys/dev/ath/ath_hal/ar5416/ar5416_power.c b/sys/dev/ath/ath_hal/ar5416/ar5416_power.c index 43a9241..8e471a9 100644 --- a/sys/dev/ath/ath_hal/ar5416/ar5416_power.c +++ b/sys/dev/ath/ath_hal/ar5416/ar5416_power.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5416/ar5416_power.c 265112 2014-04-30 02:03:13Z adrian $ */ #include "opt_ah.h" @@ -124,7 +124,6 @@ ar5416SetPowerModeNetworkSleep(struct ath_hal *ah, int setChip) HAL_BOOL ar5416SetPowerMode(struct ath_hal *ah, HAL_POWER_MODE mode, int setChip) { - struct ath_hal_5212 *ahp = AH5212(ah); #ifdef AH_DEBUG static const char* modes[] = { "AWAKE", @@ -134,27 +133,35 @@ ar5416SetPowerMode(struct ath_hal *ah, HAL_POWER_MODE mode, int setChip) }; #endif int status = AH_TRUE; + +#if 0 if (!setChip) return AH_TRUE; +#endif HALDEBUG(ah, HAL_DEBUG_POWER, "%s: %s -> %s (%s)\n", __func__, - modes[ahp->ah_powerMode], modes[mode], setChip ? "set chip " : ""); + modes[ah->ah_powerMode], modes[mode], setChip ? "set chip " : ""); switch (mode) { case HAL_PM_AWAKE: + if (setChip) + ah->ah_powerMode = mode; status = ar5416SetPowerModeAwake(ah, setChip); break; case HAL_PM_FULL_SLEEP: ar5416SetPowerModeSleep(ah, setChip); + if (setChip) + ah->ah_powerMode = mode; break; case HAL_PM_NETWORK_SLEEP: ar5416SetPowerModeNetworkSleep(ah, setChip); + if (setChip) + ah->ah_powerMode = mode; break; default: HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unknown power mode 0x%x\n", __func__, mode); return AH_FALSE; } - ahp->ah_powerMode = mode; return status; } diff --git a/sys/dev/ath/ath_hal/ar5416/ar5416_radar.c b/sys/dev/ath/ath_hal/ar5416/ar5416_radar.c index edac235..563e187 100644 --- a/sys/dev/ath/ath_hal/ar5416/ar5416_radar.c +++ b/sys/dev/ath/ath_hal/ar5416/ar5416_radar.c @@ -13,7 +13,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5416/ar5416_radar.c 239638 2012-08-24 01:29:46Z adrian $ */ #include "opt_ah.h" diff --git a/sys/dev/ath/ath_hal/ar5416/ar5416_recv.c b/sys/dev/ath/ath_hal/ar5416/ar5416_recv.c index df096f9..0852ad9 100644 --- a/sys/dev/ath/ath_hal/ar5416/ar5416_recv.c +++ b/sys/dev/ath/ath_hal/ar5416/ar5416_recv.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5416/ar5416_recv.c 250346 2013-05-08 01:11:25Z adrian $ */ #include "opt_ah.h" diff --git a/sys/dev/ath/ath_hal/ar5416/ar5416_reset.c b/sys/dev/ath/ath_hal/ar5416/ar5416_reset.c index eb31f08..21e2a87 100644 --- a/sys/dev/ath/ath_hal/ar5416/ar5416_reset.c +++ b/sys/dev/ath/ath_hal/ar5416/ar5416_reset.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5416/ar5416_reset.c 280828 2015-03-29 21:50:21Z adrian $ */ #include "opt_ah.h" @@ -120,9 +120,10 @@ ar5416Reset(struct ath_hal *ah, HAL_OPMODE opmode, HALASSERT(AH_PRIVATE(ah)->ah_eeversion >= AR_EEPROM_VER14_1); /* Blank the channel survey statistics */ - OS_MEMZERO(&ahp->ah_chansurvey, sizeof(ahp->ah_chansurvey)); + ath_hal_survey_clear(ah); /* XXX Turn on fast channel change for 5416 */ + /* * Preserve the bmiss rssi threshold and count threshold * across resets diff --git a/sys/dev/ath/ath_hal/ar5416/ar5416_spectral.c b/sys/dev/ath/ath_hal/ar5416/ar5416_spectral.c index 6bdd722..f19c47d 100644 --- a/sys/dev/ath/ath_hal/ar5416/ar5416_spectral.c +++ b/sys/dev/ath/ath_hal/ar5416/ar5416_spectral.c @@ -13,7 +13,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5416/ar5416_spectral.c 244950 2013-01-02 03:56:20Z adrian $ */ #include "opt_ah.h" diff --git a/sys/dev/ath/ath_hal/ar5416/ar5416_xmit.c b/sys/dev/ath/ath_hal/ar5416/ar5416_xmit.c index 47e8c35..c792f07 100644 --- a/sys/dev/ath/ath_hal/ar5416/ar5416_xmit.c +++ b/sys/dev/ath/ath_hal/ar5416/ar5416_xmit.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5416/ar5416_xmit.c 249580 2013-04-17 07:31:53Z adrian $ */ #include "opt_ah.h" diff --git a/sys/dev/ath/ath_hal/ar5416/ar5416desc.h b/sys/dev/ath/ath_hal/ar5416/ar5416desc.h index 2730394..a4a8d06 100644 --- a/sys/dev/ath/ath_hal/ar5416/ar5416desc.h +++ b/sys/dev/ath/ath_hal/ar5416/ar5416desc.h @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5416/ar5416desc.h 250346 2013-05-08 01:11:25Z adrian $ */ #ifndef _ATH_AR5416_DESC_H_ #define _ATH_AR5416_DESC_H_ diff --git a/sys/dev/ath/ath_hal/ar5416/ar5416phy.h b/sys/dev/ath/ath_hal/ar5416/ar5416phy.h index 4884dac..f6707db 100644 --- a/sys/dev/ath/ath_hal/ar5416/ar5416phy.h +++ b/sys/dev/ath/ath_hal/ar5416/ar5416phy.h @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5416/ar5416phy.h 244943 2013-01-02 00:38:01Z adrian $ */ #ifndef _DEV_ATH_AR5416PHY_H_ #define _DEV_ATH_AR5416PHY_H_ diff --git a/sys/dev/ath/ath_hal/ar5416/ar5416reg.h b/sys/dev/ath/ath_hal/ar5416/ar5416reg.h index 435599c..c3acb67 100644 --- a/sys/dev/ath/ath_hal/ar5416/ar5416reg.h +++ b/sys/dev/ath/ath_hal/ar5416/ar5416reg.h @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar5416/ar5416reg.h 265030 2014-04-27 23:33:37Z adrian $ */ #ifndef _DEV_ATH_AR5416REG_H #define _DEV_ATH_AR5416REG_H @@ -476,10 +476,10 @@ /* Sleep control */ #define AR5416_SLEEP1_ASSUME_DTIM 0x00080000 #define AR5416_SLEEP1_CAB_TIMEOUT 0xFFE00000 /* Cab timeout (TU) */ -#define AR5416_SLEEP1_CAB_TIMEOUT_S 22 +#define AR5416_SLEEP1_CAB_TIMEOUT_S 21 #define AR5416_SLEEP2_BEACON_TIMEOUT 0xFFE00000 /* Beacon timeout (TU)*/ -#define AR5416_SLEEP2_BEACON_TIMEOUT_S 22 +#define AR5416_SLEEP2_BEACON_TIMEOUT_S 21 /* Sleep Registers */ #define AR_SLP32_HALFCLK_LATENCY 0x000FFFFF /* rising <-> falling edge */ diff --git a/sys/dev/ath/ath_hal/ar9001/ar9130.ini b/sys/dev/ath/ath_hal/ar9001/ar9130.ini index 0bd9f8e..fa207c1 100644 --- a/sys/dev/ath/ath_hal/ar9001/ar9130.ini +++ b/sys/dev/ath/ath_hal/ar9001/ar9130.ini @@ -13,7 +13,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar9001/ar9130.ini 221163 2011-04-28 12:47:40Z adrian $ */ static const uint32_t ar5416Modes_9100[][6] = { diff --git a/sys/dev/ath/ath_hal/ar9001/ar9130_attach.c b/sys/dev/ath/ath_hal/ar9001/ar9130_attach.c index 4f478c0..22669d9 100644 --- a/sys/dev/ath/ath_hal/ar9001/ar9130_attach.c +++ b/sys/dev/ath/ath_hal/ar9001/ar9130_attach.c @@ -15,7 +15,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar9001/ar9130_attach.c 272292 2014-09-30 03:19:29Z adrian $ */ #include "opt_ah.h" @@ -69,7 +69,9 @@ static HAL_BOOL ar9130FillCapabilityInfo(struct ath_hal *ah); */ static struct ath_hal * ar9130Attach(uint16_t devid, HAL_SOFTC sc, - HAL_BUS_TAG st, HAL_BUS_HANDLE sh, uint16_t *eepromdata, HAL_STATUS *status) + HAL_BUS_TAG st, HAL_BUS_HANDLE sh, uint16_t *eepromdata, + HAL_OPS_CONFIG *ah_config, + HAL_STATUS *status) { struct ath_hal_5416 *ahp5416; struct ath_hal_5212 *ahp; diff --git a/sys/dev/ath/ath_hal/ar9001/ar9130_eeprom.c b/sys/dev/ath/ath_hal/ar9001/ar9130_eeprom.c index 81bd0fe..212be72 100644 --- a/sys/dev/ath/ath_hal/ar9001/ar9130_eeprom.c +++ b/sys/dev/ath/ath_hal/ar9001/ar9130_eeprom.c @@ -14,5 +14,5 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar9001/ar9130_eeprom.c 230147 2012-01-15 19:22:34Z adrian $ */ diff --git a/sys/dev/ath/ath_hal/ar9001/ar9130_eeprom.h b/sys/dev/ath/ath_hal/ar9001/ar9130_eeprom.h index 5d1013b..08dab1f 100644 --- a/sys/dev/ath/ath_hal/ar9001/ar9130_eeprom.h +++ b/sys/dev/ath/ath_hal/ar9001/ar9130_eeprom.h @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar9001/ar9130_eeprom.h 230147 2012-01-15 19:22:34Z adrian $ */ #ifndef __AR9130_EEPROM_H__ #define __AR9130_EEPROM_H__ diff --git a/sys/dev/ath/ath_hal/ar9001/ar9130_phy.c b/sys/dev/ath/ath_hal/ar9001/ar9130_phy.c index a71fdfa..11c4e0c 100644 --- a/sys/dev/ath/ath_hal/ar9001/ar9130_phy.c +++ b/sys/dev/ath/ath_hal/ar9001/ar9130_phy.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar9001/ar9130_phy.c 242412 2012-10-31 21:14:25Z adrian $ */ #include "opt_ah.h" diff --git a/sys/dev/ath/ath_hal/ar9001/ar9130_phy.h b/sys/dev/ath/ath_hal/ar9001/ar9130_phy.h index 516df92..cddc0d5 100644 --- a/sys/dev/ath/ath_hal/ar9001/ar9130_phy.h +++ b/sys/dev/ath/ath_hal/ar9001/ar9130_phy.h @@ -15,7 +15,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar9001/ar9130_phy.h 221163 2011-04-28 12:47:40Z adrian $ */ #ifndef __AR9130_PHY_H__ #define __AR9130_PHY_H__ diff --git a/sys/dev/ath/ath_hal/ar9001/ar9130reg.h b/sys/dev/ath/ath_hal/ar9001/ar9130reg.h index c289c32..64a6848 100644 --- a/sys/dev/ath/ath_hal/ar9001/ar9130reg.h +++ b/sys/dev/ath/ath_hal/ar9001/ar9130reg.h @@ -15,7 +15,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar9001/ar9130reg.h 221163 2011-04-28 12:47:40Z adrian $ */ #ifndef __AR9130REG_H__ #define __AR9130REG_H__ diff --git a/sys/dev/ath/ath_hal/ar9001/ar9160.ini b/sys/dev/ath/ath_hal/ar9001/ar9160.ini index 963b000..45a0855 100644 --- a/sys/dev/ath/ath_hal/ar9001/ar9160.ini +++ b/sys/dev/ath/ath_hal/ar9001/ar9160.ini @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar9001/ar9160.ini 220293 2011-04-03 11:59:52Z adrian $ */ /* Auto Generated PCI Register Writes. Created: 05/22/08 */ diff --git a/sys/dev/ath/ath_hal/ar9001/ar9160_attach.c b/sys/dev/ath/ath_hal/ar9001/ar9160_attach.c index 979ba1a..f073a1e 100644 --- a/sys/dev/ath/ath_hal/ar9001/ar9160_attach.c +++ b/sys/dev/ath/ath_hal/ar9001/ar9160_attach.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar9001/ar9160_attach.c 272292 2014-09-30 03:19:29Z adrian $ */ #include "opt_ah.h" @@ -114,6 +114,7 @@ ar9160InitPLL(struct ath_hal *ah, const struct ieee80211_channel *chan) static struct ath_hal * ar9160Attach(uint16_t devid, HAL_SOFTC sc, HAL_BUS_TAG st, HAL_BUS_HANDLE sh, uint16_t *eepromdata, + HAL_OPS_CONFIG *ah_config, HAL_STATUS *status) { struct ath_hal_5416 *ahp5416; diff --git a/sys/dev/ath/ath_hal/ar9002/ar9002phy.h b/sys/dev/ath/ath_hal/ar9002/ar9002phy.h index 3d837cf..0d10d8c 100644 --- a/sys/dev/ath/ath_hal/ar9002/ar9002phy.h +++ b/sys/dev/ath/ath_hal/ar9002/ar9002phy.h @@ -22,7 +22,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar9002/ar9002phy.h 220590 2011-04-13 04:40:59Z adrian $ */ #ifndef __ATH_AR9002PHY_H__ #define __ATH_AR9002PHY_H__ diff --git a/sys/dev/ath/ath_hal/ar9002/ar9280.c b/sys/dev/ath/ath_hal/ar9002/ar9280.c index c9aabf0..68e7069 100644 --- a/sys/dev/ath/ath_hal/ar9002/ar9280.c +++ b/sys/dev/ath/ath_hal/ar9002/ar9280.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar9002/ar9280.c 241195 2012-10-04 15:42:45Z adrian $ */ #include "opt_ah.h" diff --git a/sys/dev/ath/ath_hal/ar9002/ar9280.h b/sys/dev/ath/ath_hal/ar9002/ar9280.h index e383918..6e33e51 100644 --- a/sys/dev/ath/ath_hal/ar9002/ar9280.h +++ b/sys/dev/ath/ath_hal/ar9002/ar9280.h @@ -13,7 +13,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar9002/ar9280.h 224243 2011-07-21 08:35:10Z adrian $ */ #ifndef _ATH_AR9280_H_ #define _ATH_AR9280_H_ diff --git a/sys/dev/ath/ath_hal/ar9002/ar9280_attach.c b/sys/dev/ath/ath_hal/ar9002/ar9280_attach.c index 2a67fe5..643b82f 100644 --- a/sys/dev/ath/ath_hal/ar9002/ar9280_attach.c +++ b/sys/dev/ath/ath_hal/ar9002/ar9280_attach.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar9002/ar9280_attach.c 272292 2014-09-30 03:19:29Z adrian $ */ #include "opt_ah.h" @@ -148,6 +148,7 @@ ar9280InitPLL(struct ath_hal *ah, const struct ieee80211_channel *chan) static struct ath_hal * ar9280Attach(uint16_t devid, HAL_SOFTC sc, HAL_BUS_TAG st, HAL_BUS_HANDLE sh, uint16_t *eepromdata, + HAL_OPS_CONFIG *ah_config, HAL_STATUS *status) { struct ath_hal_9280 *ahp9280; diff --git a/sys/dev/ath/ath_hal/ar9002/ar9280_olc.c b/sys/dev/ath/ath_hal/ar9002/ar9280_olc.c index 361930b..3cf3bfc 100644 --- a/sys/dev/ath/ath_hal/ar9002/ar9280_olc.c +++ b/sys/dev/ath/ath_hal/ar9002/ar9280_olc.c @@ -22,7 +22,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar9002/ar9280_olc.c 221837 2011-05-13 14:33:45Z adrian $ */ #include "opt_ah.h" diff --git a/sys/dev/ath/ath_hal/ar9002/ar9280_olc.h b/sys/dev/ath/ath_hal/ar9002/ar9280_olc.h index e08639c..8ca2b50 100644 --- a/sys/dev/ath/ath_hal/ar9002/ar9280_olc.h +++ b/sys/dev/ath/ath_hal/ar9002/ar9280_olc.h @@ -22,7 +22,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar9002/ar9280_olc.h 219393 2011-03-08 06:59:59Z adrian $ */ #ifndef __ATH_AR9280_OLC_H__ diff --git a/sys/dev/ath/ath_hal/ar9002/ar9280v1.ini b/sys/dev/ath/ath_hal/ar9002/ar9280v1.ini index 96e0f44..310c450 100644 --- a/sys/dev/ath/ath_hal/ar9002/ar9280v1.ini +++ b/sys/dev/ath/ath_hal/ar9002/ar9280v1.ini @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar9002/ar9280v1.ini 217631 2011-01-20 09:03:40Z adrian $ */ /* Auto Generated PCI Register Writes. Created: 10/12/07 */ diff --git a/sys/dev/ath/ath_hal/ar9002/ar9280v2.ini b/sys/dev/ath/ath_hal/ar9002/ar9280v2.ini index 60286ec0..a227c11 100644 --- a/sys/dev/ath/ath_hal/ar9002/ar9280v2.ini +++ b/sys/dev/ath/ath_hal/ar9002/ar9280v2.ini @@ -13,7 +13,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar9002/ar9280v2.ini 217751 2011-01-23 14:30:35Z adrian $ */ static const uint32_t ar9280Modes_v2[][6] = { diff --git a/sys/dev/ath/ath_hal/ar9002/ar9285.c b/sys/dev/ath/ath_hal/ar9002/ar9285.c index 9e9f95c..1724ebe 100644 --- a/sys/dev/ath/ath_hal/ar9002/ar9285.c +++ b/sys/dev/ath/ath_hal/ar9002/ar9285.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar9002/ar9285.c 228517 2011-12-15 00:59:11Z adrian $ */ #include "opt_ah.h" diff --git a/sys/dev/ath/ath_hal/ar9002/ar9285.h b/sys/dev/ath/ath_hal/ar9002/ar9285.h index b37b297..257bb3f 100644 --- a/sys/dev/ath/ath_hal/ar9002/ar9285.h +++ b/sys/dev/ath/ath_hal/ar9002/ar9285.h @@ -13,7 +13,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar9002/ar9285.h 251655 2013-06-12 14:52:57Z adrian $ */ #ifndef _ATH_AR9285_H_ #define _ATH_AR9285_H_ diff --git a/sys/dev/ath/ath_hal/ar9002/ar9285.ini b/sys/dev/ath/ath_hal/ar9002/ar9285.ini index ef0ff2d..4a24808 100644 --- a/sys/dev/ath/ath_hal/ar9002/ar9285.ini +++ b/sys/dev/ath/ath_hal/ar9002/ar9285.ini @@ -13,7 +13,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar9002/ar9285.ini 217631 2011-01-20 09:03:40Z adrian $ */ /* AR9285 Revsion 10 */ diff --git a/sys/dev/ath/ath_hal/ar9002/ar9285_attach.c b/sys/dev/ath/ath_hal/ar9002/ar9285_attach.c index edb6f26..dc16e69 100644 --- a/sys/dev/ath/ath_hal/ar9002/ar9285_attach.c +++ b/sys/dev/ath/ath_hal/ar9002/ar9285_attach.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar9002/ar9285_attach.c 272292 2014-09-30 03:19:29Z adrian $ */ #include "opt_ah.h" @@ -133,6 +133,7 @@ ar9285_eeprom_print_diversity_settings(struct ath_hal *ah) static struct ath_hal * ar9285Attach(uint16_t devid, HAL_SOFTC sc, HAL_BUS_TAG st, HAL_BUS_HANDLE sh, uint16_t *eepromdata, + HAL_OPS_CONFIG *ah_config, HAL_STATUS *status) { struct ath_hal_9285 *ahp9285; diff --git a/sys/dev/ath/ath_hal/ar9002/ar9285_btcoex.c b/sys/dev/ath/ath_hal/ar9002/ar9285_btcoex.c index 4d79a4f..b49c8ab 100644 --- a/sys/dev/ath/ath_hal/ar9002/ar9285_btcoex.c +++ b/sys/dev/ath/ath_hal/ar9002/ar9285_btcoex.c @@ -15,7 +15,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar9002/ar9285_btcoex.c 251483 2013-06-07 05:17:58Z adrian $ */ #include "opt_ah.h" diff --git a/sys/dev/ath/ath_hal/ar9002/ar9285_cal.c b/sys/dev/ath/ath_hal/ar9002/ar9285_cal.c index a743e21..5bcfb15 100644 --- a/sys/dev/ath/ath_hal/ar9002/ar9285_cal.c +++ b/sys/dev/ath/ath_hal/ar9002/ar9285_cal.c @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar9002/ar9285_cal.c 221806 2011-05-12 10:11:24Z adrian $ */ #include "opt_ah.h" #include "ah.h" diff --git a/sys/dev/ath/ath_hal/ar9002/ar9285_cal.h b/sys/dev/ath/ath_hal/ar9002/ar9285_cal.h index c6ecc41..497cd57 100644 --- a/sys/dev/ath/ath_hal/ar9002/ar9285_cal.h +++ b/sys/dev/ath/ath_hal/ar9002/ar9285_cal.h @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar9002/ar9285_cal.h 219481 2011-03-11 11:58:54Z adrian $ */ #ifndef __AR9285_CAL_H__ #define __AR9285_CAL_H__ diff --git a/sys/dev/ath/ath_hal/ar9002/ar9285_diversity.c b/sys/dev/ath/ath_hal/ar9002/ar9285_diversity.c index 5fd01b7..ca594bf 100644 --- a/sys/dev/ath/ath_hal/ar9002/ar9285_diversity.c +++ b/sys/dev/ath/ath_hal/ar9002/ar9285_diversity.c @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar9002/ar9285_diversity.c 251655 2013-06-12 14:52:57Z adrian $ */ #include "opt_ah.h" diff --git a/sys/dev/ath/ath_hal/ar9002/ar9285_diversity.h b/sys/dev/ath/ath_hal/ar9002/ar9285_diversity.h index 59d53b6..fae4799 100644 --- a/sys/dev/ath/ath_hal/ar9002/ar9285_diversity.h +++ b/sys/dev/ath/ath_hal/ar9002/ar9285_diversity.h @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar9002/ar9285_diversity.h 251655 2013-06-12 14:52:57Z adrian $ */ #ifndef __AR9285_DIVERSITY_H__ #define __AR9285_DIVERSITY_H__ diff --git a/sys/dev/ath/ath_hal/ar9002/ar9285_phy.c b/sys/dev/ath/ath_hal/ar9002/ar9285_phy.c index c91048a..d0370c6 100644 --- a/sys/dev/ath/ath_hal/ar9002/ar9285_phy.c +++ b/sys/dev/ath/ath_hal/ar9002/ar9285_phy.c @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar9002/ar9285_phy.c 251656 2013-06-12 15:18:10Z adrian $ */ #include "opt_ah.h" diff --git a/sys/dev/ath/ath_hal/ar9002/ar9285_phy.h b/sys/dev/ath/ath_hal/ar9002/ar9285_phy.h index 0255e17..3d4efc6 100644 --- a/sys/dev/ath/ath_hal/ar9002/ar9285_phy.h +++ b/sys/dev/ath/ath_hal/ar9002/ar9285_phy.h @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar9002/ar9285_phy.h 251643 2013-06-12 06:01:53Z adrian $ */ #ifndef __AR9285_PHY_H__ #define __AR9285_PHY_H__ diff --git a/sys/dev/ath/ath_hal/ar9002/ar9285_reset.c b/sys/dev/ath/ath_hal/ar9002/ar9285_reset.c index cb5940f..715d715 100644 --- a/sys/dev/ath/ath_hal/ar9002/ar9285_reset.c +++ b/sys/dev/ath/ath_hal/ar9002/ar9285_reset.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar9002/ar9285_reset.c 251655 2013-06-12 14:52:57Z adrian $ */ /* diff --git a/sys/dev/ath/ath_hal/ar9002/ar9285an.h b/sys/dev/ath/ath_hal/ar9002/ar9285an.h index 3b80938..ffe4cc7 100644 --- a/sys/dev/ath/ath_hal/ar9002/ar9285an.h +++ b/sys/dev/ath/ath_hal/ar9002/ar9285an.h @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar9002/ar9285an.h 221806 2011-05-12 10:11:24Z adrian $ */ #ifndef __AR9285_AN_H__ diff --git a/sys/dev/ath/ath_hal/ar9002/ar9285phy.h b/sys/dev/ath/ath_hal/ar9002/ar9285phy.h index f823053..f526789 100644 --- a/sys/dev/ath/ath_hal/ar9002/ar9285phy.h +++ b/sys/dev/ath/ath_hal/ar9002/ar9285phy.h @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar9002/ar9285phy.h 219481 2011-03-11 11:58:54Z adrian $ */ #ifndef __ATH_AR9285PHY_H__ #define __ATH_AR9285PHY_H__ diff --git a/sys/dev/ath/ath_hal/ar9002/ar9285v2.ini b/sys/dev/ath/ath_hal/ar9002/ar9285v2.ini index 9126dc4..c22ee7f 100644 --- a/sys/dev/ath/ath_hal/ar9002/ar9285v2.ini +++ b/sys/dev/ath/ath_hal/ar9002/ar9285v2.ini @@ -13,7 +13,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar9002/ar9285v2.ini 217811 2011-01-25 05:36:29Z adrian $ */ static const u_int32_t ar9285Modes_v2[][6] = { diff --git a/sys/dev/ath/ath_hal/ar9002/ar9287.c b/sys/dev/ath/ath_hal/ar9002/ar9287.c index 724fb7c..7fed99a 100644 --- a/sys/dev/ath/ath_hal/ar9002/ar9287.c +++ b/sys/dev/ath/ath_hal/ar9002/ar9287.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar9002/ar9287.c 228517 2011-12-15 00:59:11Z adrian $ */ #include "opt_ah.h" diff --git a/sys/dev/ath/ath_hal/ar9002/ar9287.h b/sys/dev/ath/ath_hal/ar9002/ar9287.h index 3122ea4..5aed2cd 100644 --- a/sys/dev/ath/ath_hal/ar9002/ar9287.h +++ b/sys/dev/ath/ath_hal/ar9002/ar9287.h @@ -13,7 +13,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar9002/ar9287.h 228833 2011-12-23 04:05:39Z adrian $ */ #ifndef _ATH_AR9287_H_ diff --git a/sys/dev/ath/ath_hal/ar9002/ar9287.ini b/sys/dev/ath/ath_hal/ar9002/ar9287.ini index 7f4ca05..7d1bfaf 100644 --- a/sys/dev/ath/ath_hal/ar9002/ar9287.ini +++ b/sys/dev/ath/ath_hal/ar9002/ar9287.ini @@ -13,7 +13,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar9002/ar9287.ini 222301 2011-05-26 09:15:33Z adrian $ */ static const uint32_t ar9287Modes_9287_1_1[][6] = { diff --git a/sys/dev/ath/ath_hal/ar9002/ar9287_attach.c b/sys/dev/ath/ath_hal/ar9002/ar9287_attach.c index 010e2c3..fa0da6f 100644 --- a/sys/dev/ath/ath_hal/ar9002/ar9287_attach.c +++ b/sys/dev/ath/ath_hal/ar9002/ar9287_attach.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar9002/ar9287_attach.c 272292 2014-09-30 03:19:29Z adrian $ */ #include "opt_ah.h" @@ -111,6 +111,7 @@ ar9287AniSetup(struct ath_hal *ah) static struct ath_hal * ar9287Attach(uint16_t devid, HAL_SOFTC sc, HAL_BUS_TAG st, HAL_BUS_HANDLE sh, uint16_t *eepromdata, + HAL_OPS_CONFIG *ah_config, HAL_STATUS *status) { struct ath_hal_9287 *ahp9287; diff --git a/sys/dev/ath/ath_hal/ar9002/ar9287_cal.c b/sys/dev/ath/ath_hal/ar9002/ar9287_cal.c index d5024b0..cbb9473 100644 --- a/sys/dev/ath/ath_hal/ar9002/ar9287_cal.c +++ b/sys/dev/ath/ath_hal/ar9002/ar9287_cal.c @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar9002/ar9287_cal.c 222301 2011-05-26 09:15:33Z adrian $ */ #include "opt_ah.h" #include "ah.h" diff --git a/sys/dev/ath/ath_hal/ar9002/ar9287_cal.h b/sys/dev/ath/ath_hal/ar9002/ar9287_cal.h index 1a7cda2..dcb55dd 100644 --- a/sys/dev/ath/ath_hal/ar9002/ar9287_cal.h +++ b/sys/dev/ath/ath_hal/ar9002/ar9287_cal.h @@ -22,7 +22,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar9002/ar9287_cal.h 222301 2011-05-26 09:15:33Z adrian $ */ #ifndef __AR9287_CAL_H__ #define __AR9287_CAL_H__ diff --git a/sys/dev/ath/ath_hal/ar9002/ar9287_olc.c b/sys/dev/ath/ath_hal/ar9002/ar9287_olc.c index cbbe017..0342cb0 100644 --- a/sys/dev/ath/ath_hal/ar9002/ar9287_olc.c +++ b/sys/dev/ath/ath_hal/ar9002/ar9287_olc.c @@ -22,7 +22,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar9002/ar9287_olc.c 222314 2011-05-26 16:52:37Z adrian $ */ #include "opt_ah.h" diff --git a/sys/dev/ath/ath_hal/ar9002/ar9287_olc.h b/sys/dev/ath/ath_hal/ar9002/ar9287_olc.h index ff21ce6..fdb4468 100644 --- a/sys/dev/ath/ath_hal/ar9002/ar9287_olc.h +++ b/sys/dev/ath/ath_hal/ar9002/ar9287_olc.h @@ -13,7 +13,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar9002/ar9287_olc.h 222308 2011-05-26 14:29:05Z adrian $ */ #ifndef __AR9287_OLC_H__ diff --git a/sys/dev/ath/ath_hal/ar9002/ar9287_reset.c b/sys/dev/ath/ath_hal/ar9002/ar9287_reset.c index 5ed4af2..5db38496 100644 --- a/sys/dev/ath/ath_hal/ar9002/ar9287_reset.c +++ b/sys/dev/ath/ath_hal/ar9002/ar9287_reset.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar9002/ar9287_reset.c 249580 2013-04-17 07:31:53Z adrian $ */ #include "opt_ah.h" diff --git a/sys/dev/ath/ath_hal/ar9002/ar9287_reset.h b/sys/dev/ath/ath_hal/ar9002/ar9287_reset.h index 679fb8c..f5e1687 100644 --- a/sys/dev/ath/ath_hal/ar9002/ar9287_reset.h +++ b/sys/dev/ath/ath_hal/ar9002/ar9287_reset.h @@ -13,7 +13,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar9002/ar9287_reset.h 222301 2011-05-26 09:15:33Z adrian $ */ #ifndef __AR9287_RESET_H__ diff --git a/sys/dev/ath/ath_hal/ar9002/ar9287an.h b/sys/dev/ath/ath_hal/ar9002/ar9287an.h index ba7a92c..f6570c8 100644 --- a/sys/dev/ath/ath_hal/ar9002/ar9287an.h +++ b/sys/dev/ath/ath_hal/ar9002/ar9287an.h @@ -13,7 +13,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar9002/ar9287an.h 222301 2011-05-26 09:15:33Z adrian $ */ #ifndef __AR9287AN_H__ diff --git a/sys/dev/ath/ath_hal/ar9002/ar9287phy.h b/sys/dev/ath/ath_hal/ar9002/ar9287phy.h index 8f28194..d4c377c 100644 --- a/sys/dev/ath/ath_hal/ar9002/ar9287phy.h +++ b/sys/dev/ath/ath_hal/ar9002/ar9287phy.h @@ -13,7 +13,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar9002/ar9287phy.h 222301 2011-05-26 09:15:33Z adrian $ */ #ifndef __AR9287PHY_H__ diff --git a/sys/dev/ath/ath_hal/ar9003/ar9300_btcoex.h b/sys/dev/ath/ath_hal/ar9003/ar9300_btcoex.h index 583636e..94a79b3 100644 --- a/sys/dev/ath/ath_hal/ar9003/ar9300_btcoex.h +++ b/sys/dev/ath/ath_hal/ar9003/ar9300_btcoex.h @@ -13,7 +13,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar9003/ar9300_btcoex.h 237611 2012-06-26 22:16:53Z adrian $ */ #ifndef __ATH_AR9300_BTCOEX_H__ diff --git a/sys/dev/ath/ath_hal/ar9003/ar9300_devid.h b/sys/dev/ath/ath_hal/ar9003/ar9300_devid.h index 8d0a39a..188969b 100644 --- a/sys/dev/ath/ath_hal/ar9003/ar9300_devid.h +++ b/sys/dev/ath/ath_hal/ar9003/ar9300_devid.h @@ -32,7 +32,7 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGES. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_hal/ar9003/ar9300_devid.h 250166 2013-05-02 00:59:39Z adrian $ * */ #ifndef __AR9300_DEVID_H__ diff --git a/sys/dev/ath/ath_rate/amrr/amrr.c b/sys/dev/ath/ath_rate/amrr/amrr.c index c252009..bfaadec 100644 --- a/sys/dev/ath/ath_rate/amrr/amrr.c +++ b/sys/dev/ath/ath_rate/amrr/amrr.c @@ -37,7 +37,7 @@ */ #include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); +__FBSDID("$FreeBSD: head/sys/dev/ath/ath_rate/amrr/amrr.c 238633 2012-07-20 01:36:02Z adrian $"); /* * AMRR rate control. See: diff --git a/sys/dev/ath/ath_rate/amrr/amrr.h b/sys/dev/ath/ath_rate/amrr/amrr.h index c97a007..a66a214 100644 --- a/sys/dev/ath/ath_rate/amrr/amrr.h +++ b/sys/dev/ath/ath_rate/amrr/amrr.h @@ -34,7 +34,7 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGES. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_rate/amrr/amrr.h 178354 2008-04-20 20:35:46Z sam $ */ #ifndef _DEV_ATH_RATE_AMRR_H diff --git a/sys/dev/ath/ath_rate/onoe/onoe.c b/sys/dev/ath/ath_rate/onoe/onoe.c index 7c73926..baf5dd1 100644 --- a/sys/dev/ath/ath_rate/onoe/onoe.c +++ b/sys/dev/ath/ath_rate/onoe/onoe.c @@ -28,7 +28,7 @@ */ #include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); +__FBSDID("$FreeBSD: head/sys/dev/ath/ath_rate/onoe/onoe.c 238633 2012-07-20 01:36:02Z adrian $"); /* * Atsushi Onoe's rate control algorithm. diff --git a/sys/dev/ath/ath_rate/onoe/onoe.h b/sys/dev/ath/ath_rate/onoe/onoe.h index 27bbe94..b15932d 100644 --- a/sys/dev/ath/ath_rate/onoe/onoe.h +++ b/sys/dev/ath/ath_rate/onoe/onoe.h @@ -26,7 +26,7 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGES. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_rate/onoe/onoe.h 178354 2008-04-20 20:35:46Z sam $ */ /* diff --git a/sys/dev/ath/ath_rate/sample/sample.c b/sys/dev/ath/ath_rate/sample/sample.c index b3f82fa..2fdd40e 100644 --- a/sys/dev/ath/ath_rate/sample/sample.c +++ b/sys/dev/ath/ath_rate/sample/sample.c @@ -36,7 +36,7 @@ */ #include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); +__FBSDID("$FreeBSD: head/sys/dev/ath/ath_rate/sample/sample.c 277822 2015-01-28 04:42:40Z adrian $"); /* * John Bicket's SampleRate control algorithm. @@ -51,6 +51,7 @@ __FBSDID("$FreeBSD$"); #include <sys/sysctl.h> #include <sys/kernel.h> #include <sys/lock.h> +#include <sys/malloc.h> #include <sys/mutex.h> #include <sys/errno.h> @@ -61,6 +62,7 @@ __FBSDID("$FreeBSD$"); #include <sys/socket.h> #include <net/if.h> +#include <net/if_var.h> #include <net/if_media.h> #include <net/if_arp.h> #include <net/ethernet.h> /* XXX for ether_sprintf */ @@ -889,8 +891,8 @@ ath_rate_tx_complete(struct ath_softc *sc, struct ath_node *an, if (!mrr || ts->ts_finaltsi == 0) { if (!IS_RATE_DEFINED(sn, final_rix)) { - device_printf(sc->sc_dev, "%s: ts_rate=%d ts_finaltsi=%d\n", - __func__, ts->ts_rate, ts->ts_finaltsi); + device_printf(sc->sc_dev, "%s: ts_rate=%d ts_finaltsi=%d, final_rix=%d\n", + __func__, ts->ts_rate, ts->ts_finaltsi, final_rix); badrate(ifp, 0, ts->ts_rate, long_tries, status); return; } diff --git a/sys/dev/ath/ath_rate/sample/sample.h b/sys/dev/ath/ath_rate/sample/sample.h index 7438a3d..e1bcbf8 100644 --- a/sys/dev/ath/ath_rate/sample/sample.h +++ b/sys/dev/ath/ath_rate/sample/sample.h @@ -33,7 +33,7 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGES. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/ath_rate/sample/sample.h 277823 2015-01-28 04:44:42Z adrian $ */ /* @@ -113,7 +113,7 @@ struct sample_node { #ifdef _KERNEL #define ATH_NODE_SAMPLE(an) ((struct sample_node *)&(an)[1]) -#define IS_RATE_DEFINED(sn, rix) (((sn)->ratemask & (1<<(rix))) != 0) +#define IS_RATE_DEFINED(sn, rix) (((uint64_t) (sn)->ratemask & (1ULL<<((uint64_t) rix))) != 0) #ifndef MIN #define MIN(a,b) ((a) < (b) ? (a) : (b)) diff --git a/sys/dev/ath/ath_rate/sample/tx_schedules.h b/sys/dev/ath/ath_rate/sample/tx_schedules.h index f749e57..832d45e 100644 --- a/sys/dev/ath/ath_rate/sample/tx_schedules.h +++ b/sys/dev/ath/ath_rate/sample/tx_schedules.h @@ -38,7 +38,7 @@ #define __ATH_RATE_SAMPLE_TXSCHEDULES_H__ #include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); +__FBSDID("$FreeBSD: head/sys/dev/ath/ath_rate/sample/tx_schedules.h 239286 2012-08-15 07:50:42Z adrian $"); #define A(_r) \ (((_r) == 6) ? 0 : (((_r) == 9) ? 1 : (((_r) == 12) ? 2 : \ diff --git a/sys/dev/ath/if_ath.c b/sys/dev/ath/if_ath.c index 6e58896..6a84643 100644 --- a/sys/dev/ath/if_ath.c +++ b/sys/dev/ath/if_ath.c @@ -28,7 +28,7 @@ */ #include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); +__FBSDID("$FreeBSD: head/sys/dev/ath/if_ath.c 280825 2015-03-29 21:41:05Z adrian $"); /* * Driver for the Atheros Wireless LAN controller. @@ -73,6 +73,7 @@ __FBSDID("$FreeBSD$"); #include <machine/bus.h> #include <net/if.h> +#include <net/if_var.h> #include <net/if_dl.h> #include <net/if_media.h> #include <net/if_types.h> @@ -164,6 +165,7 @@ static void ath_bmiss_vap(struct ieee80211vap *); static void ath_bmiss_proc(void *, int); static void ath_key_update_begin(struct ieee80211vap *); static void ath_key_update_end(struct ieee80211vap *); +static void ath_update_mcast_hw(struct ath_softc *); static void ath_update_mcast(struct ifnet *); static void ath_update_promisc(struct ifnet *); static void ath_updateslot(struct ifnet *); @@ -238,17 +240,14 @@ SYSCTL_INT(_hw_ath, OID_AUTO, anical, CTLFLAG_RW, &ath_anicalinterval, 0, "ANI calibration (msecs)"); int ath_rxbuf = ATH_RXBUF; /* # rx buffers to allocate */ -SYSCTL_INT(_hw_ath, OID_AUTO, rxbuf, CTLFLAG_RW, &ath_rxbuf, +SYSCTL_INT(_hw_ath, OID_AUTO, rxbuf, CTLFLAG_RWTUN, &ath_rxbuf, 0, "rx buffers allocated"); -TUNABLE_INT("hw.ath.rxbuf", &ath_rxbuf); int ath_txbuf = ATH_TXBUF; /* # tx buffers to allocate */ -SYSCTL_INT(_hw_ath, OID_AUTO, txbuf, CTLFLAG_RW, &ath_txbuf, +SYSCTL_INT(_hw_ath, OID_AUTO, txbuf, CTLFLAG_RWTUN, &ath_txbuf, 0, "tx buffers allocated"); -TUNABLE_INT("hw.ath.txbuf", &ath_txbuf); int ath_txbuf_mgmt = ATH_MGMT_TXBUF; /* # mgmt tx buffers to allocate */ -SYSCTL_INT(_hw_ath, OID_AUTO, txbuf_mgmt, CTLFLAG_RW, &ath_txbuf_mgmt, +SYSCTL_INT(_hw_ath, OID_AUTO, txbuf_mgmt, CTLFLAG_RWTUN, &ath_txbuf_mgmt, 0, "tx (mgmt) buffers allocated"); -TUNABLE_INT("hw.ath.txbuf_mgmt", &ath_txbuf_mgmt); int ath_bstuck_threshold = 4; /* max missed beacons */ SYSCTL_INT(_hw_ath, OID_AUTO, bstuck, CTLFLAG_RW, &ath_bstuck_threshold, @@ -278,6 +277,293 @@ ath_legacy_attach_comp_func(struct ath_softc *sc) } } +/* + * Set the target power mode. + * + * If this is called during a point in time where + * the hardware is being programmed elsewhere, it will + * simply store it away and update it when all current + * uses of the hardware are completed. + */ +void +_ath_power_setpower(struct ath_softc *sc, int power_state, const char *file, int line) +{ + ATH_LOCK_ASSERT(sc); + + sc->sc_target_powerstate = power_state; + + DPRINTF(sc, ATH_DEBUG_PWRSAVE, "%s: (%s:%d) state=%d, refcnt=%d\n", + __func__, + file, + line, + power_state, + sc->sc_powersave_refcnt); + + if (sc->sc_powersave_refcnt == 0 && + power_state != sc->sc_cur_powerstate) { + sc->sc_cur_powerstate = power_state; + ath_hal_setpower(sc->sc_ah, power_state); + + /* + * If the NIC is force-awake, then set the + * self-gen frame state appropriately. + * + * If the nic is in network sleep or full-sleep, + * we let the above call leave the self-gen + * state as "sleep". + */ + if (sc->sc_cur_powerstate == HAL_PM_AWAKE && + sc->sc_target_selfgen_state != HAL_PM_AWAKE) { + ath_hal_setselfgenpower(sc->sc_ah, + sc->sc_target_selfgen_state); + } + } +} + +/* + * Set the current self-generated frames state. + * + * This is separate from the target power mode. The chip may be + * awake but the desired state is "sleep", so frames sent to the + * destination has PWRMGT=1 in the 802.11 header. The NIC also + * needs to know to set PWRMGT=1 in self-generated frames. + */ +void +_ath_power_set_selfgen(struct ath_softc *sc, int power_state, const char *file, int line) +{ + + ATH_LOCK_ASSERT(sc); + + DPRINTF(sc, ATH_DEBUG_PWRSAVE, "%s: (%s:%d) state=%d, refcnt=%d\n", + __func__, + file, + line, + power_state, + sc->sc_target_selfgen_state); + + sc->sc_target_selfgen_state = power_state; + + /* + * If the NIC is force-awake, then set the power state. + * Network-state and full-sleep will already transition it to + * mark self-gen frames as sleeping - and we can't + * guarantee the NIC is awake to program the self-gen frame + * setting anyway. + */ + if (sc->sc_cur_powerstate == HAL_PM_AWAKE) { + ath_hal_setselfgenpower(sc->sc_ah, power_state); + } +} + +/* + * Set the hardware power mode and take a reference. + * + * This doesn't update the target power mode in the driver; + * it just updates the hardware power state. + * + * XXX it should only ever force the hardware awake; it should + * never be called to set it asleep. + */ +void +_ath_power_set_power_state(struct ath_softc *sc, int power_state, const char *file, int line) +{ + ATH_LOCK_ASSERT(sc); + + DPRINTF(sc, ATH_DEBUG_PWRSAVE, "%s: (%s:%d) state=%d, refcnt=%d\n", + __func__, + file, + line, + power_state, + sc->sc_powersave_refcnt); + + sc->sc_powersave_refcnt++; + + if (power_state != sc->sc_cur_powerstate) { + ath_hal_setpower(sc->sc_ah, power_state); + sc->sc_cur_powerstate = power_state; + + /* + * Adjust the self-gen powerstate if appropriate. + */ + if (sc->sc_cur_powerstate == HAL_PM_AWAKE && + sc->sc_target_selfgen_state != HAL_PM_AWAKE) { + ath_hal_setselfgenpower(sc->sc_ah, + sc->sc_target_selfgen_state); + } + + } +} + +/* + * Restore the power save mode to what it once was. + * + * This will decrement the reference counter and once it hits + * zero, it'll restore the powersave state. + */ +void +_ath_power_restore_power_state(struct ath_softc *sc, const char *file, int line) +{ + + ATH_LOCK_ASSERT(sc); + + DPRINTF(sc, ATH_DEBUG_PWRSAVE, "%s: (%s:%d) refcnt=%d, target state=%d\n", + __func__, + file, + line, + sc->sc_powersave_refcnt, + sc->sc_target_powerstate); + + if (sc->sc_powersave_refcnt == 0) + device_printf(sc->sc_dev, "%s: refcnt=0?\n", __func__); + else + sc->sc_powersave_refcnt--; + + if (sc->sc_powersave_refcnt == 0 && + sc->sc_target_powerstate != sc->sc_cur_powerstate) { + sc->sc_cur_powerstate = sc->sc_target_powerstate; + ath_hal_setpower(sc->sc_ah, sc->sc_target_powerstate); + } + + /* + * Adjust the self-gen powerstate if appropriate. + */ + if (sc->sc_cur_powerstate == HAL_PM_AWAKE && + sc->sc_target_selfgen_state != HAL_PM_AWAKE) { + ath_hal_setselfgenpower(sc->sc_ah, + sc->sc_target_selfgen_state); + } + +} + +/* + * Configure the initial HAL configuration values based on bus + * specific parameters. + * + * Some PCI IDs and other information may need tweaking. + * + * XXX TODO: ath9k and the Atheros HAL only program comm2g_switch_enable + * if BT antenna diversity isn't enabled. + * + * So, let's also figure out how to enable BT diversity for AR9485. + */ +static void +ath_setup_hal_config(struct ath_softc *sc, HAL_OPS_CONFIG *ah_config) +{ + /* XXX TODO: only for PCI devices? */ + + if (sc->sc_pci_devinfo & (ATH_PCI_CUS198 | ATH_PCI_CUS230)) { + ah_config->ath_hal_ext_lna_ctl_gpio = 0x200; /* bit 9 */ + ah_config->ath_hal_ext_atten_margin_cfg = AH_TRUE; + ah_config->ath_hal_min_gainidx = AH_TRUE; + ah_config->ath_hal_ant_ctrl_comm2g_switch_enable = 0x000bbb88; + /* XXX low_rssi_thresh */ + /* XXX fast_div_bias */ + device_printf(sc->sc_dev, "configuring for %s\n", + (sc->sc_pci_devinfo & ATH_PCI_CUS198) ? + "CUS198" : "CUS230"); + } + + if (sc->sc_pci_devinfo & ATH_PCI_CUS217) + device_printf(sc->sc_dev, "CUS217 card detected\n"); + + if (sc->sc_pci_devinfo & ATH_PCI_CUS252) + device_printf(sc->sc_dev, "CUS252 card detected\n"); + + if (sc->sc_pci_devinfo & ATH_PCI_AR9565_1ANT) + device_printf(sc->sc_dev, "WB335 1-ANT card detected\n"); + + if (sc->sc_pci_devinfo & ATH_PCI_AR9565_2ANT) + device_printf(sc->sc_dev, "WB335 2-ANT card detected\n"); + + if (sc->sc_pci_devinfo & ATH_PCI_KILLER) + device_printf(sc->sc_dev, "Killer Wireless card detected\n"); + +#if 0 + /* + * Some WB335 cards do not support antenna diversity. Since + * we use a hardcoded value for AR9565 instead of using the + * EEPROM/OTP data, remove the combining feature from + * the HW capabilities bitmap. + */ + if (sc->sc_pci_devinfo & (ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_AR9565_2ANT)) { + if (!(sc->sc_pci_devinfo & ATH9K_PCI_BT_ANT_DIV)) + pCap->hw_caps &= ~ATH9K_HW_CAP_ANT_DIV_COMB; + } + + if (sc->sc_pci_devinfo & ATH9K_PCI_BT_ANT_DIV) { + pCap->hw_caps |= ATH9K_HW_CAP_BT_ANT_DIV; + device_printf(sc->sc_dev, "Set BT/WLAN RX diversity capability\n"); + } +#endif + + if (sc->sc_pci_devinfo & ATH_PCI_D3_L1_WAR) { + ah_config->ath_hal_pcie_waen = 0x0040473b; + device_printf(sc->sc_dev, "Enable WAR for ASPM D3/L1\n"); + } + +#if 0 + if (sc->sc_pci_devinfo & ATH9K_PCI_NO_PLL_PWRSAVE) { + ah->config.no_pll_pwrsave = true; + device_printf(sc->sc_dev, "Disable PLL PowerSave\n"); + } +#endif + +} + +/* + * Attempt to fetch the MAC address from the kernel environment. + * + * Returns 0, macaddr in macaddr if successful; -1 otherwise. + */ +static int +ath_fetch_mac_kenv(struct ath_softc *sc, uint8_t *macaddr) +{ + char devid_str[32]; + int local_mac = 0; + char *local_macstr; + + /* + * Fetch from the kenv rather than using hints. + * + * Hints would be nice but the transition to dynamic + * hints/kenv doesn't happen early enough for this + * to work reliably (eg on anything embedded.) + */ + snprintf(devid_str, 32, "hint.%s.%d.macaddr", + device_get_name(sc->sc_dev), + device_get_unit(sc->sc_dev)); + + if ((local_macstr = getenv(devid_str)) != NULL) { + uint32_t tmpmac[ETHER_ADDR_LEN]; + int count; + int i; + + /* Have a MAC address; should use it */ + device_printf(sc->sc_dev, + "Overriding MAC address from environment: '%s'\n", + local_macstr); + + /* Extract out the MAC address */ + count = sscanf(local_macstr, "%x%*c%x%*c%x%*c%x%*c%x%*c%x", + &tmpmac[0], &tmpmac[1], + &tmpmac[2], &tmpmac[3], + &tmpmac[4], &tmpmac[5]); + if (count == 6) { + /* Valid! */ + local_mac = 1; + for (i = 0; i < ETHER_ADDR_LEN; i++) + macaddr[i] = tmpmac[i]; + } + /* Done! */ + freeenv(local_macstr); + local_macstr = NULL; + } + + if (local_mac) + return (0); + return (-1); +} + #define HAL_MODE_HT20 (HAL_MODE_11NG_HT20 | HAL_MODE_11NA_HT20) #define HAL_MODE_HT40 \ (HAL_MODE_11NG_HT40PLUS | HAL_MODE_11NG_HT40MINUS | \ @@ -293,6 +579,7 @@ ath_attach(u_int16_t devid, struct ath_softc *sc) u_int wmodes; uint8_t macaddr[IEEE80211_ADDR_LEN]; int rx_chainmask, tx_chainmask; + HAL_OPS_CONFIG ah_config; DPRINTF(sc, ATH_DEBUG_ANY, "%s: devid 0x%x\n", __func__, devid); @@ -311,8 +598,17 @@ ath_attach(u_int16_t devid, struct ath_softc *sc) device_get_unit(sc->sc_dev)); CURVNET_RESTORE(); + /* + * Configure the initial configuration data. + * + * This is stuff that may be needed early during attach + * rather than done via configuration calls later. + */ + bzero(&ah_config, sizeof(ah_config)); + ath_setup_hal_config(sc, &ah_config); + ah = ath_hal_attach(devid, sc, sc->sc_st, sc->sc_sh, - sc->sc_eepromdata, &status); + sc->sc_eepromdata, &ah_config, &status); if (ah == NULL) { if_printf(ifp, "unable to attach hardware; HAL status %u\n", status); @@ -340,6 +636,10 @@ ath_attach(u_int16_t devid, struct ath_softc *sc) ath_xmit_setup_legacy(sc); } + if (ath_hal_hasmybeacon(sc->sc_ah)) { + sc->sc_do_mybeacon = 1; + } + /* * Check if the MAC has multi-rate retry support. * We do this by trying to setup a fake extended @@ -604,6 +904,8 @@ ath_attach(u_int16_t devid, struct ath_softc *sc) #ifdef ATH_ENABLE_DFS | IEEE80211_C_DFS /* Enable radar detection */ #endif + | IEEE80211_C_PMGT /* Station side power mgmt */ + | IEEE80211_C_SWSLEEP ; /* * Query the hal to figure out h/w crypto support. @@ -901,8 +1203,14 @@ ath_attach(u_int16_t devid, struct ath_softc *sc) */ sc->sc_hasveol = ath_hal_hasveol(ah); - /* get mac address from hardware */ - ath_hal_getmac(ah, macaddr); + /* get mac address from kenv first, then hardware */ + if (ath_fetch_mac_kenv(sc, macaddr) == 0) { + /* Tell the HAL now about the new MAC */ + ath_hal_setmac(ah, macaddr); + } else { + ath_hal_getmac(ah, macaddr); + } + if (sc->sc_hasbmask) ath_hal_getbssidmask(ah, sc->sc_hwbssidmask); @@ -993,6 +1301,14 @@ ath_attach(u_int16_t devid, struct ath_softc *sc) if (bootverbose) ieee80211_announce(ic); ath_announce(sc); + + /* + * Put it to sleep for now. + */ + ATH_LOCK(sc); + ath_power_setpower(sc, HAL_PM_FULL_SLEEP); + ATH_UNLOCK(sc); + return 0; bad2: ath_tx_cleanup(sc); @@ -1038,7 +1354,22 @@ ath_detach(struct ath_softc *sc) * it last * Other than that, it's straightforward... */ + + /* + * XXX Wake the hardware up first. ath_stop() will still + * wake it up first, but I'd rather do it here just to + * ensure it's awake. + */ + ATH_LOCK(sc); + ath_power_set_power_state(sc, HAL_PM_AWAKE); + ath_power_setpower(sc, HAL_PM_AWAKE); + ATH_UNLOCK(sc); + + /* + * Stop things cleanly. + */ ath_stop(ifp); + ieee80211_ifdetach(ifp->if_l2com); taskqueue_free(sc->sc_tq); #ifdef ATH_TX99_DIAG @@ -1401,6 +1732,10 @@ ath_vap_delete(struct ieee80211vap *vap) struct ath_hal *ah = sc->sc_ah; struct ath_vap *avp = ATH_VAP(vap); + ATH_LOCK(sc); + ath_power_set_power_state(sc, HAL_PM_AWAKE); + ATH_UNLOCK(sc); + DPRINTF(sc, ATH_DEBUG_RESET, "%s: called\n", __func__); if (ifp->if_drv_flags & IFF_DRV_RUNNING) { /* @@ -1409,11 +1744,13 @@ ath_vap_delete(struct ieee80211vap *vap) * the vap state by any frames pending on the tx queues. */ ath_hal_intrset(ah, 0); /* disable interrupts */ - ath_draintxq(sc, ATH_RESET_DEFAULT); /* stop hw xmit side */ /* XXX Do all frames from all vaps/nodes need draining here? */ ath_stoprecv(sc, 1); /* stop recv side */ + ath_draintxq(sc, ATH_RESET_DEFAULT); /* stop hw xmit side */ } + /* .. leave the hardware awake for now. */ + ieee80211_vap_detach(vap); /* @@ -1501,6 +1838,9 @@ ath_vap_delete(struct ieee80211vap *vap) } ath_hal_intrset(ah, sc->sc_imask); } + + /* Ok, let the hardware asleep. */ + ath_power_restore_power_state(sc); ATH_UNLOCK(sc); } @@ -1520,12 +1860,25 @@ ath_suspend(struct ath_softc *sc) * NB: don't worry about putting the chip in low power * mode; pci will power off our socket on suspend and * CardBus detaches the device. + * + * XXX TODO: well, that's great, except for non-cardbus + * devices! */ /* - * XXX ensure none of the taskqueues are running + * XXX This doesn't wait until all pending taskqueue + * items and parallel transmit/receive/other threads + * are running! + */ + ath_hal_intrset(sc->sc_ah, 0); + taskqueue_block(sc->sc_tq); + + ATH_LOCK(sc); + callout_stop(&sc->sc_cal_ch); + ATH_UNLOCK(sc); + + /* * XXX ensure sc_invalid is 1 - * XXX ensure the calibration callout is disabled */ /* Disable the PCIe PHY, complete with workarounds */ @@ -1546,8 +1899,12 @@ ath_reset_keycache(struct ath_softc *sc) struct ath_hal *ah = sc->sc_ah; int i; + ATH_LOCK(sc); + ath_power_set_power_state(sc, HAL_PM_AWAKE); for (i = 0; i < sc->sc_keymax; i++) ath_hal_keyreset(ah, i); + ath_power_restore_power_state(sc); + ATH_UNLOCK(sc); ieee80211_crypto_reload_keys(ic); } @@ -1599,11 +1956,24 @@ ath_resume(struct ath_softc *sc) sc->sc_curchan != NULL ? sc->sc_curchan : ic->ic_curchan); ath_hal_setchainmasks(sc->sc_ah, sc->sc_cur_txchainmask, sc->sc_cur_rxchainmask); + + /* Ensure we set the current power state to on */ + ATH_LOCK(sc); + ath_power_setselfgen(sc, HAL_PM_AWAKE); + ath_power_set_power_state(sc, HAL_PM_AWAKE); + ath_power_setpower(sc, HAL_PM_AWAKE); + ATH_UNLOCK(sc); + ath_hal_reset(ah, sc->sc_opmode, sc->sc_curchan != NULL ? sc->sc_curchan : ic->ic_curchan, AH_FALSE, &status); ath_reset_keycache(sc); + ATH_RX_LOCK(sc); + sc->sc_rx_stopped = 1; + sc->sc_rx_resetted = 1; + ATH_RX_UNLOCK(sc); + /* Let DFS at it in case it's a DFS channel */ ath_dfs_radar_enable(sc, ic->ic_curchan); @@ -1631,6 +2001,10 @@ ath_resume(struct ath_softc *sc) if (sc->sc_resume_up) ieee80211_resume_all(ic); + ATH_LOCK(sc); + ath_power_restore_power_state(sc); + ATH_UNLOCK(sc); + /* XXX beacons ? */ } @@ -1688,6 +2062,10 @@ ath_intr(void *arg) return; } + ATH_LOCK(sc); + ath_power_set_power_state(sc, HAL_PM_AWAKE); + ATH_UNLOCK(sc); + if ((ifp->if_flags & IFF_UP) == 0 || (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { HAL_INT status; @@ -1697,6 +2075,10 @@ ath_intr(void *arg) ath_hal_getisr(ah, &status); /* clear ISR */ ath_hal_intrset(ah, 0); /* disable further intr's */ ATH_PCU_UNLOCK(sc); + + ATH_LOCK(sc); + ath_power_restore_power_state(sc); + ATH_UNLOCK(sc); return; } @@ -1736,6 +2118,11 @@ ath_intr(void *arg) /* Short-circuit un-handled interrupts */ if (status == 0x0) { ATH_PCU_UNLOCK(sc); + + ATH_LOCK(sc); + ath_power_restore_power_state(sc); + ATH_UNLOCK(sc); + return; } @@ -1791,44 +2178,46 @@ ath_intr(void *arg) if (status & HAL_INT_RXEOL) { int imask; ATH_KTR(sc, ATH_KTR_ERROR, 0, "ath_intr: RXEOL"); - ATH_PCU_LOCK(sc); - /* - * NB: the hardware should re-read the link when - * RXE bit is written, but it doesn't work at - * least on older hardware revs. - */ - sc->sc_stats.ast_rxeol++; - /* - * Disable RXEOL/RXORN - prevent an interrupt - * storm until the PCU logic can be reset. - * In case the interface is reset some other - * way before "sc_kickpcu" is called, don't - * modify sc_imask - that way if it is reset - * by a call to ath_reset() somehow, the - * interrupt mask will be correctly reprogrammed. - */ - imask = sc->sc_imask; - imask &= ~(HAL_INT_RXEOL | HAL_INT_RXORN); - ath_hal_intrset(ah, imask); - /* - * Only blank sc_rxlink if we've not yet kicked - * the PCU. - * - * This isn't entirely correct - the correct solution - * would be to have a PCU lock and engage that for - * the duration of the PCU fiddling; which would include - * running the RX process. Otherwise we could end up - * messing up the RX descriptor chain and making the - * RX desc list much shorter. - */ - if (! sc->sc_kickpcu) - sc->sc_rxlink = NULL; - sc->sc_kickpcu = 1; - ATH_PCU_UNLOCK(sc); + if (! sc->sc_isedma) { + ATH_PCU_LOCK(sc); + /* + * NB: the hardware should re-read the link when + * RXE bit is written, but it doesn't work at + * least on older hardware revs. + */ + sc->sc_stats.ast_rxeol++; + /* + * Disable RXEOL/RXORN - prevent an interrupt + * storm until the PCU logic can be reset. + * In case the interface is reset some other + * way before "sc_kickpcu" is called, don't + * modify sc_imask - that way if it is reset + * by a call to ath_reset() somehow, the + * interrupt mask will be correctly reprogrammed. + */ + imask = sc->sc_imask; + imask &= ~(HAL_INT_RXEOL | HAL_INT_RXORN); + ath_hal_intrset(ah, imask); + /* + * Only blank sc_rxlink if we've not yet kicked + * the PCU. + * + * This isn't entirely correct - the correct solution + * would be to have a PCU lock and engage that for + * the duration of the PCU fiddling; which would include + * running the RX process. Otherwise we could end up + * messing up the RX descriptor chain and making the + * RX desc list much shorter. + */ + if (! sc->sc_kickpcu) + sc->sc_rxlink = NULL; + sc->sc_kickpcu = 1; + ATH_PCU_UNLOCK(sc); + } /* - * Enqueue an RX proc, to handled whatever + * Enqueue an RX proc to handle whatever * is in the RX queue. - * This will then kick the PCU. + * This will then kick the PCU if required. */ sc->sc_rx.recv_sched(sc, 1); } @@ -1902,10 +2291,18 @@ ath_intr(void *arg) ATH_KTR(sc, ATH_KTR_ERROR, 0, "ath_intr: RXORN"); sc->sc_stats.ast_rxorn++; } + if (status & HAL_INT_TSFOOR) { + device_printf(sc->sc_dev, "%s: TSFOOR\n", __func__); + sc->sc_syncbeacon = 1; + } } ATH_PCU_LOCK(sc); sc->sc_intr_cnt--; ATH_PCU_UNLOCK(sc); + + ATH_LOCK(sc); + ath_power_restore_power_state(sc); + ATH_UNLOCK(sc); } static void @@ -1936,6 +2333,8 @@ ath_fatal_proc(void *arg, int pending) static void ath_bmiss_vap(struct ieee80211vap *vap) { + struct ath_softc *sc = vap->iv_ic->ic_ifp->if_softc; + /* * Workaround phantom bmiss interrupts by sanity-checking * the time of our last rx'd frame. If it is within the @@ -1944,6 +2343,16 @@ ath_bmiss_vap(struct ieee80211vap *vap) * be dispatched up for processing. Note this applies only * for h/w beacon miss events. */ + + /* + * XXX TODO: Just read the TSF during the interrupt path; + * that way we don't have to wake up again just to read it + * again. + */ + ATH_LOCK(sc); + ath_power_set_power_state(sc, HAL_PM_AWAKE); + ATH_UNLOCK(sc); + if ((vap->iv_flags_ext & IEEE80211_FEXT_SWBMISS) == 0) { struct ifnet *ifp = vap->iv_ic->ic_ifp; struct ath_softc *sc = ifp->if_softc; @@ -1961,12 +2370,32 @@ ath_bmiss_vap(struct ieee80211vap *vap) if (tsf - lastrx <= bmisstimeout) { sc->sc_stats.ast_bmiss_phantom++; + + ATH_LOCK(sc); + ath_power_restore_power_state(sc); + ATH_UNLOCK(sc); + return; } } + + /* + * There's no need to keep the hardware awake during the call + * to av_bmiss(). + */ + ATH_LOCK(sc); + ath_power_restore_power_state(sc); + ATH_UNLOCK(sc); + + /* + * Attempt to force a beacon resync. + */ + sc->sc_syncbeacon = 1; + ATH_VAP(vap)->av_bmiss(vap); } +/* XXX this needs a force wakeup! */ int ath_hal_gethangstate(struct ath_hal *ah, uint32_t mask, uint32_t *hangs) { @@ -1989,6 +2418,12 @@ ath_bmiss_proc(void *arg, int pending) DPRINTF(sc, ATH_DEBUG_ANY, "%s: pending %u\n", __func__, pending); + ATH_LOCK(sc); + ath_power_set_power_state(sc, HAL_PM_AWAKE); + ATH_UNLOCK(sc); + + ath_beacon_miss(sc); + /* * Do a reset upon any becaon miss event. * @@ -2002,6 +2437,13 @@ ath_bmiss_proc(void *arg, int pending) ath_reset(ifp, ATH_RESET_NOLOSS); ieee80211_beacon_miss(ifp->if_l2com); } + + /* Force a beacon resync, in case they've drifted */ + sc->sc_syncbeacon = 1; + + ATH_LOCK(sc); + ath_power_restore_power_state(sc); + ATH_UNLOCK(sc); } /* @@ -2041,6 +2483,13 @@ ath_init(void *arg) ATH_LOCK(sc); /* + * Force the sleep state awake. + */ + ath_power_setselfgen(sc, HAL_PM_AWAKE); + ath_power_set_power_state(sc, HAL_PM_AWAKE); + ath_power_setpower(sc, HAL_PM_AWAKE); + + /* * Stop anything previously setup. This is safe * whether this is the first time through or not. */ @@ -2057,12 +2506,19 @@ ath_init(void *arg) ath_update_chainmasks(sc, ic->ic_curchan); ath_hal_setchainmasks(sc->sc_ah, sc->sc_cur_txchainmask, sc->sc_cur_rxchainmask); + if (!ath_hal_reset(ah, sc->sc_opmode, ic->ic_curchan, AH_FALSE, &status)) { if_printf(ifp, "unable to reset hardware; hal status %u\n", status); ATH_UNLOCK(sc); return; } + + ATH_RX_LOCK(sc); + sc->sc_rx_stopped = 1; + sc->sc_rx_resetted = 1; + ATH_RX_UNLOCK(sc); + ath_chan_change(sc, ic->ic_curchan); /* Let DFS at it in case it's a DFS channel */ @@ -2090,11 +2546,11 @@ ath_init(void *arg) * state cached in the driver. */ sc->sc_diversity = ath_hal_getdiversity(ah); - sc->sc_lastlongcal = 0; + sc->sc_lastlongcal = ticks; sc->sc_resetcal = 1; sc->sc_lastcalreset = 0; - sc->sc_lastani = 0; - sc->sc_lastshortcal = 0; + sc->sc_lastani = ticks; + sc->sc_lastshortcal = ticks; sc->sc_doresetcal = AH_FALSE; /* * Beacon timers were cleared here; give ath_newstate() @@ -2112,6 +2568,7 @@ ath_init(void *arg) */ if (ath_startrecv(sc) != 0) { if_printf(ifp, "unable to start recv logic\n"); + ath_power_restore_power_state(sc); ATH_UNLOCK(sc); return; } @@ -2120,8 +2577,7 @@ ath_init(void *arg) * Enable interrupts. */ sc->sc_imask = HAL_INT_RX | HAL_INT_TX - | HAL_INT_RXEOL | HAL_INT_RXORN - | HAL_INT_TXURN + | HAL_INT_RXORN | HAL_INT_TXURN | HAL_INT_FATAL | HAL_INT_GLOBAL; /* @@ -2132,12 +2588,29 @@ ath_init(void *arg) sc->sc_imask |= (HAL_INT_RXHP | HAL_INT_RXLP); /* + * If we're an EDMA NIC, we don't care about RXEOL. + * Writing a new descriptor in will simply restart + * RX DMA. + */ + if (! sc->sc_isedma) + sc->sc_imask |= HAL_INT_RXEOL; + + /* * Enable MIB interrupts when there are hardware phy counters. * Note we only do this (at the moment) for station mode. */ if (sc->sc_needmib && ic->ic_opmode == IEEE80211_M_STA) sc->sc_imask |= HAL_INT_MIB; + /* + * XXX add capability for this. + * + * If we're in STA mode (and maybe IBSS?) then register for + * TSFOOR interrupts. + */ + if (ic->ic_opmode == IEEE80211_M_STA) + sc->sc_imask |= HAL_INT_TSFOOR; + /* Enable global TX timeout and carrier sense timeout if available */ if (ath_hal_gtxto_supported(ah)) sc->sc_imask |= HAL_INT_GTT; @@ -2149,6 +2622,7 @@ ath_init(void *arg) callout_reset(&sc->sc_wd_ch, hz, ath_watchdog, sc); ath_hal_intrset(ah, sc->sc_imask); + ath_power_restore_power_state(sc); ATH_UNLOCK(sc); #ifdef ATH_TX99_DIAG @@ -2169,6 +2643,12 @@ ath_stop_locked(struct ifnet *ifp) __func__, sc->sc_invalid, ifp->if_flags); ATH_LOCK_ASSERT(sc); + + /* + * Wake the hardware up before fiddling with it. + */ + ath_power_set_power_state(sc, HAL_PM_AWAKE); + if (ifp->if_drv_flags & IFF_DRV_RUNNING) { /* * Shutdown the hardware and driver: @@ -2201,17 +2681,29 @@ ath_stop_locked(struct ifnet *ifp) } ath_hal_intrset(ah, 0); } - ath_draintxq(sc, ATH_RESET_DEFAULT); + /* XXX we should stop RX regardless of whether it's valid */ if (!sc->sc_invalid) { ath_stoprecv(sc, 1); ath_hal_phydisable(ah); } else sc->sc_rxlink = NULL; + ath_draintxq(sc, ATH_RESET_DEFAULT); ath_beacon_free(sc); /* XXX not needed */ } + + /* And now, restore the current power state */ + ath_power_restore_power_state(sc); } -#define MAX_TXRX_ITERATIONS 1000 +/* + * Wait until all pending TX/RX has completed. + * + * This waits until all existing transmit, receive and interrupts + * have completed. It's assumed that the caller has first + * grabbed the reset lock so it doesn't try to do overlapping + * chip resets. + */ +#define MAX_TXRX_ITERATIONS 100 static void ath_txrx_stop_locked(struct ath_softc *sc) { @@ -2230,7 +2722,8 @@ ath_txrx_stop_locked(struct ath_softc *sc) sc->sc_txstart_cnt || sc->sc_intr_cnt) { if (i <= 0) break; - msleep(sc, &sc->sc_pcu_mtx, 0, "ath_txrx_stop", 1); + msleep(sc, &sc->sc_pcu_mtx, 0, "ath_txrx_stop", + msecs_to_ticks(10)); i--; } @@ -2277,7 +2770,7 @@ ath_txrx_start(struct ath_softc *sc) * Another, cleaner way should be found to serialise all of * these operations. */ -#define MAX_RESET_ITERATIONS 10 +#define MAX_RESET_ITERATIONS 25 static int ath_reset_grablock(struct ath_softc *sc, int dowait) { @@ -2295,7 +2788,11 @@ ath_reset_grablock(struct ath_softc *sc, int dowait) break; } ATH_PCU_UNLOCK(sc); - pause("ath_reset_grablock", 1); + /* + * 1 tick is likely not enough time for long calibrations + * to complete. So we should wait quite a while. + */ + pause("ath_reset_grablock", msecs_to_ticks(100)); i--; ATH_PCU_LOCK(sc); } while (i > 0); @@ -2360,6 +2857,13 @@ ath_reset(struct ifnet *ifp, ATH_RESET_TYPE reset_type) /* Try to (stop any further TX/RX from occuring */ taskqueue_block(sc->sc_tq); + /* + * Wake the hardware up. + */ + ATH_LOCK(sc); + ath_power_set_power_state(sc, HAL_PM_AWAKE); + ATH_UNLOCK(sc); + ATH_PCU_LOCK(sc); /* @@ -2385,13 +2889,6 @@ ath_reset(struct ifnet *ifp, ATH_RESET_TYPE reset_type) ATH_PCU_UNLOCK(sc); /* - * Should now wait for pending TX/RX to complete - * and block future ones from occuring. This needs to be - * done before the TX queue is drained. - */ - ath_draintxq(sc, reset_type); /* stop xmit side */ - - /* * Regardless of whether we're doing a no-loss flush or * not, stop the PCU and handle what's in the RX queue. * That way frames aren't dropped which shouldn't be. @@ -2399,6 +2896,13 @@ ath_reset(struct ifnet *ifp, ATH_RESET_TYPE reset_type) ath_stoprecv(sc, (reset_type != ATH_RESET_NOLOSS)); ath_rx_flush(sc); + /* + * Should now wait for pending TX/RX to complete + * and block future ones from occuring. This needs to be + * done before the TX queue is drained. + */ + ath_draintxq(sc, reset_type); /* stop xmit side */ + ath_settkipmic(sc); /* configure TKIP MIC handling */ /* NB: indicate channel change so we do a full reset */ ath_update_chainmasks(sc, ic->ic_curchan); @@ -2409,6 +2913,11 @@ ath_reset(struct ifnet *ifp, ATH_RESET_TYPE reset_type) __func__, status); sc->sc_diversity = ath_hal_getdiversity(ah); + ATH_RX_LOCK(sc); + sc->sc_rx_stopped = 1; + sc->sc_rx_resetted = 1; + ATH_RX_UNLOCK(sc); + /* Let DFS at it in case it's a DFS channel */ ath_dfs_radar_enable(sc, ic->ic_curchan); @@ -2454,9 +2963,13 @@ ath_reset(struct ifnet *ifp, ATH_RESET_TYPE reset_type) * reset counter - this way ath_intr() doesn't end up * disabling interrupts without a corresponding enable * in the rest or channel change path. + * + * Grab the TX reference in case we need to transmit. + * That way a parallel transmit doesn't. */ ATH_PCU_LOCK(sc); sc->sc_inreset_cnt--; + sc->sc_txstart_cnt++; /* XXX only do this if sc_inreset_cnt == 0? */ ath_hal_intrset(ah, sc->sc_imask); ATH_PCU_UNLOCK(sc); @@ -2473,6 +2986,8 @@ ath_reset(struct ifnet *ifp, ATH_RESET_TYPE reset_type) /* Restart TX/RX as needed */ ath_txrx_start(sc); + /* XXX TODO: we need to hold the tx refcount here! */ + /* Restart TX completion and pending TX */ if (reset_type == ATH_RESET_NOLOSS) { for (i = 0; i < HAL_NUM_TX_QUEUES; i++) { @@ -2497,6 +3012,14 @@ ath_reset(struct ifnet *ifp, ATH_RESET_TYPE reset_type) ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; IF_UNLOCK(&ifp->if_snd); + ATH_LOCK(sc); + ath_power_restore_power_state(sc); + ATH_UNLOCK(sc); + + ATH_PCU_LOCK(sc); + sc->sc_txstart_cnt--; + ATH_PCU_UNLOCK(sc); + /* Handle any frames in the TX queue */ /* * XXX should this be done by the caller, rather than @@ -2637,6 +3160,7 @@ ath_buf_clone(struct ath_softc *sc, struct ath_buf *bf) tbf->bf_status = bf->bf_status; tbf->bf_m = bf->bf_m; tbf->bf_node = bf->bf_node; + KASSERT((bf->bf_node != NULL), ("%s: bf_node=NULL!", __func__)); /* will be setup by the chain/setup function */ tbf->bf_lastds = NULL; /* for now, last == self */ @@ -2738,6 +3262,11 @@ ath_transmit(struct ifnet *ifp, struct mbuf *m) sc->sc_txstart_cnt++; ATH_PCU_UNLOCK(sc); + /* Wake the hardware up already */ + ATH_LOCK(sc); + ath_power_set_power_state(sc, HAL_PM_AWAKE); + ATH_UNLOCK(sc); + ATH_KTR(sc, ATH_KTR_TX, 0, "ath_transmit: start"); /* * Grab the TX lock - it's ok to do this here; we haven't @@ -2971,6 +3500,11 @@ finish: sc->sc_txstart_cnt--; ATH_PCU_UNLOCK(sc); + /* Sleep the hardware if required */ + ATH_LOCK(sc); + ath_power_restore_power_state(sc); + ATH_UNLOCK(sc); + ATH_KTR(sc, ATH_KTR_TX, 0, "ath_transmit: finished"); return (retval); @@ -2998,7 +3532,6 @@ ath_key_update_begin(struct ieee80211vap *vap) DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s:\n", __func__); taskqueue_block(sc->sc_tq); - IF_LOCK(&ifp->if_snd); /* NB: doesn't block mgmt frames */ } static void @@ -3008,7 +3541,6 @@ ath_key_update_end(struct ieee80211vap *vap) struct ath_softc *sc = ifp->if_softc; DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s:\n", __func__); - IF_UNLOCK(&ifp->if_snd); taskqueue_unblock(sc->sc_tq); } @@ -3019,16 +3551,25 @@ ath_update_promisc(struct ifnet *ifp) u_int32_t rfilt; /* configure rx filter */ + ATH_LOCK(sc); + ath_power_set_power_state(sc, HAL_PM_AWAKE); rfilt = ath_calcrxfilter(sc); ath_hal_setrxfilter(sc->sc_ah, rfilt); + ath_power_restore_power_state(sc); + ATH_UNLOCK(sc); DPRINTF(sc, ATH_DEBUG_MODE, "%s: RX filter 0x%x\n", __func__, rfilt); } +/* + * Driver-internal mcast update call. + * + * Assumes the hardware is already awake. + */ static void -ath_update_mcast(struct ifnet *ifp) +ath_update_mcast_hw(struct ath_softc *sc) { - struct ath_softc *sc = ifp->if_softc; + struct ifnet *ifp = sc->sc_ifp; u_int32_t mfilt[2]; /* calculate and install multicast filter */ @@ -3056,11 +3597,33 @@ ath_update_mcast(struct ifnet *ifp) if_maddr_runlock(ifp); } else mfilt[0] = mfilt[1] = ~0; + ath_hal_setmcastfilter(sc->sc_ah, mfilt[0], mfilt[1]); + DPRINTF(sc, ATH_DEBUG_MODE, "%s: MC filter %08x:%08x\n", __func__, mfilt[0], mfilt[1]); } +/* + * Called from the net80211 layer - force the hardware + * awake before operating. + */ +static void +ath_update_mcast(struct ifnet *ifp) +{ + struct ath_softc *sc = ifp->if_softc; + + ATH_LOCK(sc); + ath_power_set_power_state(sc, HAL_PM_AWAKE); + ATH_UNLOCK(sc); + + ath_update_mcast_hw(sc); + + ATH_LOCK(sc); + ath_power_restore_power_state(sc); + ATH_UNLOCK(sc); +} + void ath_mode_init(struct ath_softc *sc) { @@ -3086,7 +3649,7 @@ ath_mode_init(struct ath_softc *sc) ath_hal_setmac(ah, IF_LLADDR(ifp)); /* calculate and install multicast filter */ - ath_update_mcast(ifp); + ath_update_mcast_hw(sc); } /* @@ -3118,8 +3681,13 @@ ath_setslottime(struct ath_softc *sc) __func__, ic->ic_curchan->ic_freq, ic->ic_curchan->ic_flags, ic->ic_flags & IEEE80211_F_SHSLOT ? "short" : "long", usec); + /* Wake up the hardware first before updating the slot time */ + ATH_LOCK(sc); + ath_power_set_power_state(sc, HAL_PM_AWAKE); ath_hal_setslottime(ah, usec); + ath_power_restore_power_state(sc); sc->sc_updateslot = OK; + ATH_UNLOCK(sc); } /* @@ -3136,6 +3704,8 @@ ath_updateslot(struct ifnet *ifp) * When not coordinating the BSS, change the hardware * immediately. For other operation we defer the change * until beacon updates have propagated to the stations. + * + * XXX sc_updateslot isn't changed behind a lock? */ if (ic->ic_opmode == IEEE80211_M_HOSTAP || ic->ic_opmode == IEEE80211_M_MBSS) @@ -4041,14 +4611,12 @@ ath_tx_process_buf_completion(struct ath_softc *sc, struct ath_txq *txq, struct ath_tx_status *ts, struct ath_buf *bf) { struct ieee80211_node *ni = bf->bf_node; - struct ath_node *an = NULL; ATH_TX_UNLOCK_ASSERT(sc); ATH_TXQ_UNLOCK_ASSERT(txq); /* If unicast frame, update general statistics */ if (ni != NULL) { - an = ATH_NODE(ni); /* update statistics */ ath_tx_update_stats(sc, ts, bf); } @@ -4257,6 +4825,10 @@ ath_tx_proc_q0(void *arg, int npending) sc->sc_txq_active &= ~txqs; ATH_PCU_UNLOCK(sc); + ATH_LOCK(sc); + ath_power_set_power_state(sc, HAL_PM_AWAKE); + ATH_UNLOCK(sc); + ATH_KTR(sc, ATH_KTR_TXCOMP, 1, "ath_tx_proc_q0: txqs=0x%08x", txqs); @@ -4277,6 +4849,10 @@ ath_tx_proc_q0(void *arg, int npending) sc->sc_txproc_cnt--; ATH_PCU_UNLOCK(sc); + ATH_LOCK(sc); + ath_power_restore_power_state(sc); + ATH_UNLOCK(sc); + ath_tx_kick(sc); } @@ -4298,6 +4874,10 @@ ath_tx_proc_q0123(void *arg, int npending) sc->sc_txq_active &= ~txqs; ATH_PCU_UNLOCK(sc); + ATH_LOCK(sc); + ath_power_set_power_state(sc, HAL_PM_AWAKE); + ATH_UNLOCK(sc); + ATH_KTR(sc, ATH_KTR_TXCOMP, 1, "ath_tx_proc_q0123: txqs=0x%08x", txqs); @@ -4330,6 +4910,10 @@ ath_tx_proc_q0123(void *arg, int npending) sc->sc_txproc_cnt--; ATH_PCU_UNLOCK(sc); + ATH_LOCK(sc); + ath_power_restore_power_state(sc); + ATH_UNLOCK(sc); + ath_tx_kick(sc); } @@ -4350,6 +4934,10 @@ ath_tx_proc(void *arg, int npending) sc->sc_txq_active &= ~txqs; ATH_PCU_UNLOCK(sc); + ATH_LOCK(sc); + ath_power_set_power_state(sc, HAL_PM_AWAKE); + ATH_UNLOCK(sc); + ATH_KTR(sc, ATH_KTR_TXCOMP, 1, "ath_tx_proc: txqs=0x%08x", txqs); /* @@ -4375,6 +4963,10 @@ ath_tx_proc(void *arg, int npending) sc->sc_txproc_cnt--; ATH_PCU_UNLOCK(sc); + ATH_LOCK(sc); + ath_power_restore_power_state(sc); + ATH_UNLOCK(sc); + ath_tx_kick(sc); } #undef TXQACTIVE @@ -4401,6 +4993,10 @@ ath_txq_sched_tasklet(void *arg, int npending) sc->sc_txproc_cnt++; ATH_PCU_UNLOCK(sc); + ATH_LOCK(sc); + ath_power_set_power_state(sc, HAL_PM_AWAKE); + ATH_UNLOCK(sc); + ATH_TX_LOCK(sc); for (i = 0; i < HAL_NUM_TX_QUEUES; i++) { if (ATH_TXQ_SETUP(sc, i)) { @@ -4409,6 +5005,10 @@ ath_txq_sched_tasklet(void *arg, int npending) } ATH_TX_UNLOCK(sc); + ATH_LOCK(sc); + ath_power_restore_power_state(sc); + ATH_UNLOCK(sc); + ATH_PCU_LOCK(sc); sc->sc_txproc_cnt--; ATH_PCU_UNLOCK(sc); @@ -4916,14 +5516,15 @@ ath_chan_set(struct ath_softc *sc, struct ieee80211_channel *chan) ATH_PCU_LOCK(sc); + /* Disable interrupts */ + ath_hal_intrset(ah, 0); + /* Stop new RX/TX/interrupt completion */ if (ath_reset_grablock(sc, 1) == 0) { device_printf(sc->sc_dev, "%s: concurrent reset! Danger!\n", __func__); } - ath_hal_intrset(ah, 0); - /* Stop pending RX/TX completion */ ath_txrx_stop_locked(sc); @@ -4967,6 +5568,11 @@ ath_chan_set(struct ath_softc *sc, struct ieee80211_channel *chan) } sc->sc_diversity = ath_hal_getdiversity(ah); + ATH_RX_LOCK(sc); + sc->sc_rx_stopped = 1; + sc->sc_rx_resetted = 1; + ATH_RX_UNLOCK(sc); + /* Let DFS at it in case it's a DFS channel */ ath_dfs_radar_enable(sc, chan); @@ -5056,6 +5662,17 @@ ath_calibrate(void *arg) HAL_BOOL aniCal, shortCal = AH_FALSE; int nextcal; + ATH_LOCK_ASSERT(sc); + + /* + * Force the hardware awake for ANI work. + */ + ath_power_set_power_state(sc, HAL_PM_AWAKE); + + /* Skip trying to do this if we're in reset */ + if (sc->sc_inreset_cnt) + goto restart; + if (ic->ic_flags & IEEE80211_F_SCAN) /* defer, off channel */ goto restart; longCal = (ticks - sc->sc_lastlongcal >= ath_longcalinterval*hz); @@ -5085,6 +5702,7 @@ ath_calibrate(void *arg) sc->sc_doresetcal = AH_TRUE; taskqueue_enqueue(sc->sc_tq, &sc->sc_resettask); callout_reset(&sc->sc_cal_ch, 1, ath_calibrate, sc); + ath_power_restore_power_state(sc); return; } /* @@ -5156,6 +5774,10 @@ restart: __func__); /* NB: don't rearm timer */ } + /* + * Restore power state now that we're done. + */ + ath_power_restore_power_state(sc); } static void @@ -5241,6 +5863,10 @@ ath_set_channel(struct ieee80211com *ic) struct ifnet *ifp = ic->ic_ifp; struct ath_softc *sc = ifp->if_softc; + ATH_LOCK(sc); + ath_power_set_power_state(sc, HAL_PM_AWAKE); + ATH_UNLOCK(sc); + (void) ath_chan_set(sc, ic->ic_curchan); /* * If we are returning to our bss channel then mark state @@ -5251,6 +5877,7 @@ ath_set_channel(struct ieee80211com *ic) ATH_LOCK(sc); if (!sc->sc_scanning && ic->ic_curchan == ic->ic_bsschan) sc->sc_syncbeacon = 1; + ath_power_restore_power_state(sc); ATH_UNLOCK(sc); } @@ -5283,6 +5910,7 @@ ath_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) int i, error, stamode; u_int32_t rfilt; int csa_run_transition = 0; + enum ieee80211_state ostate = vap->iv_state; static const HAL_LED_STATE leds[] = { HAL_LED_INIT, /* IEEE80211_S_INIT */ @@ -5296,7 +5924,7 @@ ath_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) }; DPRINTF(sc, ATH_DEBUG_STATE, "%s: %s -> %s\n", __func__, - ieee80211_state_name[vap->iv_state], + ieee80211_state_name[ostate], ieee80211_state_name[nstate]); /* @@ -5308,10 +5936,34 @@ ath_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) */ IEEE80211_LOCK_ASSERT(ic); - if (vap->iv_state == IEEE80211_S_CSA && nstate == IEEE80211_S_RUN) + /* Before we touch the hardware - wake it up */ + ATH_LOCK(sc); + /* + * If the NIC is in anything other than SLEEP state, + * we need to ensure that self-generated frames are + * set for PWRMGT=0. Otherwise we may end up with + * strange situations. + * + * XXX TODO: is this actually the case? :-) + */ + if (nstate != IEEE80211_S_SLEEP) + ath_power_setselfgen(sc, HAL_PM_AWAKE); + + /* + * Now, wake the thing up. + */ + ath_power_set_power_state(sc, HAL_PM_AWAKE); + + /* + * And stop the calibration callout whilst we have + * ATH_LOCK held. + */ + callout_stop(&sc->sc_cal_ch); + ATH_UNLOCK(sc); + + if (ostate == IEEE80211_S_CSA && nstate == IEEE80211_S_RUN) csa_run_transition = 1; - callout_drain(&sc->sc_cal_ch); ath_hal_setledstate(ah, leds[nstate]); /* set LED */ if (nstate == IEEE80211_S_SCAN) { @@ -5321,6 +5973,13 @@ ath_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) * [re]setup beacons. Unblock the task q thread so * deferred interrupt processing is done. */ + + /* Ensure we stay awake during scan */ + ATH_LOCK(sc); + ath_power_setselfgen(sc, HAL_PM_AWAKE); + ath_power_setpower(sc, HAL_PM_AWAKE); + ATH_UNLOCK(sc); + ath_hal_intrset(ah, sc->sc_imask &~ (HAL_INT_SWBA | HAL_INT_BMISS)); sc->sc_imask &= ~(HAL_INT_SWBA | HAL_INT_BMISS); @@ -5333,6 +5992,11 @@ ath_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) stamode = (vap->iv_opmode == IEEE80211_M_STA || vap->iv_opmode == IEEE80211_M_AHDEMO || vap->iv_opmode == IEEE80211_M_IBSS); + + /* + * XXX Dont need to do this (and others) if we've transitioned + * from SLEEP->RUN. + */ if (stamode && nstate == IEEE80211_S_RUN) { sc->sc_curaid = ni->ni_associd; IEEE80211_ADDR_COPY(sc->sc_curbssid, ni->ni_bssid); @@ -5435,11 +6099,14 @@ ath_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) * beacon to update the beacon timer and thus we * won't get notified of the missing beacons. */ - sc->sc_syncbeacon = 1; -#if 0 - if (csa_run_transition) -#endif - ath_beacon_config(sc, vap); + if (ostate != IEEE80211_S_RUN && + ostate != IEEE80211_S_SLEEP) { + DPRINTF(sc, ATH_DEBUG_BEACON, + "%s: STA; syncbeacon=1\n", __func__); + sc->sc_syncbeacon = 1; + + if (csa_run_transition) + ath_beacon_config(sc, vap); /* * PR: kern/175227 @@ -5453,7 +6120,8 @@ ath_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) * timer fires (too often), leading to a STA * disassociation. */ - sc->sc_beacons = 1; + sc->sc_beacons = 1; + } break; case IEEE80211_M_MONITOR: /* @@ -5479,6 +6147,14 @@ ath_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) sc->sc_halstats.ns_avgbrssi = ATH_RSSI_DUMMY_MARKER; sc->sc_halstats.ns_avgrssi = ATH_RSSI_DUMMY_MARKER; sc->sc_halstats.ns_avgtxrssi = ATH_RSSI_DUMMY_MARKER; + + /* + * Force awake for RUN mode. + */ + ATH_LOCK(sc); + ath_power_setselfgen(sc, HAL_PM_AWAKE); + ath_power_setpower(sc, HAL_PM_AWAKE); + /* * Finally, start any timers and the task q thread * (in case we didn't go through SCAN state). @@ -5490,6 +6166,8 @@ ath_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) DPRINTF(sc, ATH_DEBUG_CALIBRATE, "%s: calibration disabled\n", __func__); } + ATH_UNLOCK(sc); + taskqueue_unblock(sc->sc_tq); } else if (nstate == IEEE80211_S_INIT) { /* @@ -5509,9 +6187,43 @@ ath_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) #ifdef IEEE80211_SUPPORT_TDMA ath_hal_setcca(ah, AH_TRUE); #endif + } else if (nstate == IEEE80211_S_SLEEP) { + /* We're going to sleep, so transition appropriately */ + /* For now, only do this if we're a single STA vap */ + if (sc->sc_nvaps == 1 && + vap->iv_opmode == IEEE80211_M_STA) { + DPRINTF(sc, ATH_DEBUG_BEACON, "%s: syncbeacon=%d\n", __func__, sc->sc_syncbeacon); + ATH_LOCK(sc); + /* + * Always at least set the self-generated + * frame config to set PWRMGT=1. + */ + ath_power_setselfgen(sc, HAL_PM_NETWORK_SLEEP); + + /* + * If we're not syncing beacons, transition + * to NETWORK_SLEEP. + * + * We stay awake if syncbeacon > 0 in case + * we need to listen for some beacons otherwise + * our beacon timer config may be wrong. + */ + if (sc->sc_syncbeacon == 0) { + ath_power_setpower(sc, HAL_PM_NETWORK_SLEEP); + } + ATH_UNLOCK(sc); + } } bad: ieee80211_free_node(ni); + + /* + * Restore the power state - either to what it was, or + * to network_sleep if it's alright. + */ + ATH_LOCK(sc); + ath_power_restore_power_state(sc); + ATH_UNLOCK(sc); return error; } @@ -5566,7 +6278,16 @@ ath_newassoc(struct ieee80211_node *ni, int isnew) an->an_mcastrix = ath_tx_findrix(sc, tp->mcastrate); an->an_mgmtrix = ath_tx_findrix(sc, tp->mgmtrate); + DPRINTF(sc, ATH_DEBUG_NODE, "%s: %6D: reassoc; isnew=%d, is_powersave=%d\n", + __func__, + ni->ni_macaddr, + ":", + isnew, + an->an_is_powersave); + + ATH_NODE_LOCK(an); ath_rate_newassoc(sc, an, isnew); + ATH_NODE_UNLOCK(an); if (isnew && (vap->iv_flags & IEEE80211_F_PRIVACY) == 0 && sc->sc_hasclrkey && @@ -5806,10 +6527,14 @@ ath_watchdog(void *arg) struct ath_softc *sc = arg; int do_reset = 0; + ATH_LOCK_ASSERT(sc); + if (sc->sc_wd_timer != 0 && --sc->sc_wd_timer == 0) { struct ifnet *ifp = sc->sc_ifp; uint32_t hangs; + ath_power_set_power_state(sc, HAL_PM_AWAKE); + if (ath_hal_gethangstate(sc->sc_ah, 0xffff, &hangs) && hangs != 0) { if_printf(ifp, "%s hang detected (0x%x)\n", @@ -5819,6 +6544,8 @@ ath_watchdog(void *arg) do_reset = 1; ifp->if_oerrors++; sc->sc_stats.ast_watchdog++; + + ath_power_restore_power_state(sc); } /* @@ -5916,6 +6643,13 @@ ath_ioctl_diag(struct ath_softc *sc, struct ath_diag *ad) goto bad; } } + + + ATH_LOCK(sc); + if (id != HAL_DIAG_REGS) + ath_power_set_power_state(sc, HAL_PM_AWAKE); + ATH_UNLOCK(sc); + if (ath_hal_getdiagstate(ah, id, indata, insize, &outdata, &outsize)) { if (outsize < ad->ad_out_size) ad->ad_out_size = outsize; @@ -5925,6 +6659,12 @@ ath_ioctl_diag(struct ath_softc *sc, struct ath_diag *ad) } else { error = EINVAL; } + + ATH_LOCK(sc); + if (id != HAL_DIAG_REGS) + ath_power_restore_power_state(sc); + ATH_UNLOCK(sc); + bad: if ((ad->ad_id & ATH_DIAG_IN) && indata != NULL) free(indata, M_TEMP); @@ -5947,14 +6687,17 @@ ath_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) switch (cmd) { case SIOCSIFFLAGS: - ATH_LOCK(sc); if (IS_RUNNING(ifp)) { /* * To avoid rescanning another access point, * do not call ath_init() here. Instead, * only reflect promisc mode settings. */ + ATH_LOCK(sc); + ath_power_set_power_state(sc, HAL_PM_AWAKE); ath_mode_init(sc); + ath_power_restore_power_state(sc); + ATH_UNLOCK(sc); } else if (ifp->if_flags & IFF_UP) { /* * Beware of being called during attach/detach @@ -5968,14 +6711,12 @@ ath_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) if (!sc->sc_invalid) ath_init(sc); /* XXX lose error */ } else { + ATH_LOCK(sc); ath_stop_locked(ifp); -#ifdef notyet - /* XXX must wakeup in places like ath_vap_delete */ if (!sc->sc_invalid) - ath_hal_setpower(sc->sc_ah, HAL_PM_FULL_SLEEP); -#endif + ath_power_setpower(sc, HAL_PM_FULL_SLEEP); + ATH_UNLOCK(sc); } - ATH_UNLOCK(sc); break; case SIOCGIFMEDIA: case SIOCSIFMEDIA: @@ -6341,7 +7082,7 @@ ath_tx_update_tim(struct ath_softc *sc, struct ieee80211_node *ni, /* * Don't bother grabbing the lock unless the queue is empty. */ - if (&an->an_swq_depth != 0) + if (an->an_swq_depth != 0) return; if (an->an_is_powersave && @@ -6511,6 +7252,6 @@ ath_node_recv_pspoll(struct ieee80211_node *ni, struct mbuf *m) MODULE_VERSION(if_ath, 1); MODULE_DEPEND(if_ath, wlan, 1, 1, 1); /* 802.11 media layer */ -#if defined(IEEE80211_ALQ) || defined(AH_DEBUG_ALQ) +#if defined(IEEE80211_ALQ) || defined(AH_DEBUG_ALQ) || defined(ATH_DEBUG_ALQ) MODULE_DEPEND(if_ath, alq, 1, 1, 1); #endif diff --git a/sys/dev/ath/if_ath_ahb.c b/sys/dev/ath/if_ath_ahb.c index 59593b6..c400d93 100644 --- a/sys/dev/ath/if_ath_ahb.c +++ b/sys/dev/ath/if_ath_ahb.c @@ -29,7 +29,7 @@ */ #include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); +__FBSDID("$FreeBSD: head/sys/dev/ath/if_ath_ahb.c 279512 2015-03-02 02:14:44Z adrian $"); /* * AHB bus front-end for the Atheros Wireless LAN controller driver. @@ -39,6 +39,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/systm.h> +#include <sys/malloc.h> #include <sys/module.h> #include <sys/kernel.h> #include <sys/lock.h> @@ -55,6 +56,7 @@ __FBSDID("$FreeBSD$"); #include <net/if.h> #include <net/if_media.h> #include <net/if_arp.h> +#include <net/ethernet.h> #include <net80211/ieee80211_var.h> @@ -151,19 +153,30 @@ ath_ahb_attach(device_t dev) eepromsize = ATH_EEPROM_DATA_SIZE * 2; } - rid = 0; device_printf(sc->sc_dev, "eeprom @ %p (%d bytes)\n", (void *) eepromaddr, eepromsize); - psc->sc_eeprom = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, (uintptr_t) eepromaddr, - (uintptr_t) eepromaddr + (uintptr_t) (eepromsize - 1), 0, RF_ACTIVE); + /* + * XXX this assumes that the parent device is the nexus + * and will just pass through requests for all of memory. + * + * Later on, when this has to attach off of the actual + * AHB, this won't work. + * + * Ideally this would be done in machdep code in mips/atheros/ + * and it'd expose the EEPROM via the firmware interface, + * so the ath/ath_ahb drivers can be loaded as modules + * after boot-time. + */ + psc->sc_eeprom = bus_alloc_resource(dev, SYS_RES_MEMORY, + &rid, (uintptr_t) eepromaddr, + (uintptr_t) eepromaddr + (uintptr_t) (eepromsize - 1), 0, RF_ACTIVE); if (psc->sc_eeprom == NULL) { device_printf(dev, "cannot map eeprom space\n"); goto bad0; } - /* XXX uintptr_t is a bandaid for ia64; to be fixed */ - sc->sc_st = (HAL_BUS_TAG)(uintptr_t) rman_get_bustag(psc->sc_sr); + sc->sc_st = (HAL_BUS_TAG) rman_get_bustag(psc->sc_sr); sc->sc_sh = (HAL_BUS_HANDLE) rman_get_bushandle(psc->sc_sr); /* * Mark device invalid so any interrupts (shared or otherwise) @@ -348,6 +361,7 @@ static driver_t ath_ahb_driver = { }; static devclass_t ath_devclass; DRIVER_MODULE(ath, nexus, ath_ahb_driver, ath_devclass, 0, 0); +DRIVER_MODULE(ath, apb, ath_ahb_driver, ath_devclass, 0, 0); MODULE_VERSION(ath, 1); MODULE_DEPEND(ath, wlan, 1, 1, 1); /* 802.11 media layer */ MODULE_DEPEND(ath, if_ath, 1, 1, 1); /* if_ath driver */ diff --git a/sys/dev/ath/if_ath_alq.c b/sys/dev/ath/if_ath_alq.c index 8ca53ae..79ad48c 100644 --- a/sys/dev/ath/if_ath_alq.c +++ b/sys/dev/ath/if_ath_alq.c @@ -26,7 +26,7 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGES. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/if_ath_alq.c 250618 2013-05-13 21:17:27Z adrian $ */ #include "opt_ah.h" #include "opt_ath.h" diff --git a/sys/dev/ath/if_ath_alq.h b/sys/dev/ath/if_ath_alq.h index 9f6ceac..b8b0c0d 100644 --- a/sys/dev/ath/if_ath_alq.h +++ b/sys/dev/ath/if_ath_alq.h @@ -26,7 +26,7 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGES. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/if_ath_alq.h 250619 2013-05-13 21:18:00Z adrian $ */ #ifndef __IF_ATH_ALQ_H__ #define __IF_ATH_ALQ_H__ diff --git a/sys/dev/ath/if_ath_beacon.c b/sys/dev/ath/if_ath_beacon.c index 11b0426..758ad6f 100644 --- a/sys/dev/ath/if_ath_beacon.c +++ b/sys/dev/ath/if_ath_beacon.c @@ -28,7 +28,7 @@ */ #include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); +__FBSDID("$FreeBSD: head/sys/dev/ath/if_ath_beacon.c 270430 2014-08-23 18:55:51Z adrian $"); /* * Driver for the Atheros Wireless LAN controller. @@ -73,6 +73,7 @@ __FBSDID("$FreeBSD$"); #include <machine/bus.h> #include <net/if.h> +#include <net/if_var.h> #include <net/if_dl.h> #include <net/if_media.h> #include <net/if_types.h> @@ -381,7 +382,7 @@ ath_beacon_update(struct ieee80211vap *vap, int item) /* * Handle a beacon miss. */ -static void +void ath_beacon_miss(struct ath_softc *sc) { HAL_SURVEY_SAMPLE hs; @@ -748,6 +749,11 @@ ath_beacon_generate(struct ath_softc *sc, struct ieee80211vap *vap) * * More thought is required here. */ + /* + * XXX can we even stop TX DMA here? Check what the + * reference driver does for cabq for beacons, given + * that stopping TX requires RX is paused. + */ ath_tx_draintxq(sc, cabq); } } @@ -915,7 +921,7 @@ ath_beacon_config(struct ath_softc *sc, struct ieee80211vap *vap) struct ieee80211_node *ni; u_int32_t nexttbtt, intval, tsftu; u_int32_t nexttbtt_u8, intval_u8; - u_int64_t tsf; + u_int64_t tsf, tsf_beacon; if (vap == NULL) vap = TAILQ_FIRST(&ic->ic_vaps); /* XXX */ @@ -931,9 +937,17 @@ ath_beacon_config(struct ath_softc *sc, struct ieee80211vap *vap) ni = ieee80211_ref_node(vap->iv_bss); + ATH_LOCK(sc); + ath_power_set_power_state(sc, HAL_PM_AWAKE); + ATH_UNLOCK(sc); + /* extract tstamp from last beacon and convert to TU */ nexttbtt = TSF_TO_TU(LE_READ_4(ni->ni_tstamp.data + 4), LE_READ_4(ni->ni_tstamp.data)); + + tsf_beacon = ((uint64_t) LE_READ_4(ni->ni_tstamp.data + 4)) << 32; + tsf_beacon |= LE_READ_4(ni->ni_tstamp.data); + if (ic->ic_opmode == IEEE80211_M_HOSTAP || ic->ic_opmode == IEEE80211_M_MBSS) { /* @@ -979,14 +993,63 @@ ath_beacon_config(struct ath_softc *sc, struct ieee80211vap *vap) */ tsf = ath_hal_gettsf64(ah); tsftu = TSF_TO_TU(tsf>>32, tsf) + FUDGE; - do { - nexttbtt += intval; - if (--dtimcount < 0) { - dtimcount = dtimperiod - 1; - if (--cfpcount < 0) - cfpcount = cfpperiod - 1; + + DPRINTF(sc, ATH_DEBUG_BEACON, + "%s: beacon tsf=%llu, hw tsf=%llu, nexttbtt=%u, tsftu=%u\n", + __func__, + (unsigned long long) tsf_beacon, + (unsigned long long) tsf, + nexttbtt, + tsftu); + DPRINTF(sc, ATH_DEBUG_BEACON, + "%s: beacon tsf=%llu, hw tsf=%llu, tsf delta=%lld\n", + __func__, + (unsigned long long) tsf_beacon, + (unsigned long long) tsf, + (long long) tsf - + (long long) tsf_beacon); + + DPRINTF(sc, ATH_DEBUG_BEACON, + "%s: nexttbtt=%llu, beacon tsf delta=%lld\n", + __func__, + (unsigned long long) nexttbtt, + (long long) ((long long) nexttbtt * 1024LL) - (long long) tsf_beacon); + + /* XXX cfpcount? */ + + if (nexttbtt > tsftu) { + uint32_t countdiff, oldtbtt, remainder; + + oldtbtt = nexttbtt; + remainder = (nexttbtt - tsftu) % intval; + nexttbtt = tsftu + remainder; + + countdiff = (oldtbtt - nexttbtt) / intval % dtimperiod; + if (dtimcount > countdiff) { + dtimcount -= countdiff; + } else { + dtimcount += dtimperiod - countdiff; + } + } else { //nexttbtt <= tsftu + uint32_t countdiff, oldtbtt, remainder; + + oldtbtt = nexttbtt; + remainder = (tsftu - nexttbtt) % intval; + nexttbtt = tsftu - remainder + intval; + countdiff = (nexttbtt - oldtbtt) / intval % dtimperiod; + if (dtimcount > countdiff) { + dtimcount -= countdiff; + } else { + dtimcount += dtimperiod - countdiff; } - } while (nexttbtt < tsftu); + } + + DPRINTF(sc, ATH_DEBUG_BEACON, + "%s: adj nexttbtt=%llu, rx tsf delta=%lld\n", + __func__, + (unsigned long long) nexttbtt, + (long long) ((long long)nexttbtt * 1024LL) - (long long)tsf); + memset(&bs, 0, sizeof(bs)); bs.bs_intval = intval; bs.bs_nexttbtt = nexttbtt; @@ -1033,9 +1096,12 @@ ath_beacon_config(struct ath_softc *sc, struct ieee80211vap *vap) bs.bs_sleepduration = roundup(bs.bs_sleepduration, bs.bs_dtimperiod); DPRINTF(sc, ATH_DEBUG_BEACON, - "%s: tsf %ju tsf:tu %u intval %u nexttbtt %u dtim %u nextdtim %u bmiss %u sleep %u cfp:period %u maxdur %u next %u timoffset %u\n" + "%s: tsf %ju tsf:tu %u intval %u nexttbtt %u dtim %u " + "nextdtim %u bmiss %u sleep %u cfp:period %u " + "maxdur %u next %u timoffset %u\n" , __func__ - , tsf, tsftu + , tsf + , tsftu , bs.bs_intval , bs.bs_nexttbtt , bs.bs_dtimperiod @@ -1112,8 +1178,11 @@ ath_beacon_config(struct ath_softc *sc, struct ieee80211vap *vap) if (ic->ic_opmode == IEEE80211_M_IBSS && sc->sc_hasveol) ath_beacon_start_adhoc(sc, vap); } - sc->sc_syncbeacon = 0; ieee80211_free_node(ni); + + ATH_LOCK(sc); + ath_power_restore_power_state(sc); + ATH_UNLOCK(sc); #undef FUDGE #undef TSF_TO_TU } diff --git a/sys/dev/ath/if_ath_beacon.h b/sys/dev/ath/if_ath_beacon.h index f3f73d7..b8a4a5d 100644 --- a/sys/dev/ath/if_ath_beacon.h +++ b/sys/dev/ath/if_ath_beacon.h @@ -26,7 +26,7 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGES. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/if_ath_beacon.h 265115 2014-04-30 02:19:41Z adrian $ */ #ifndef __IF_ATH_BEACON_H__ #define __IF_ATH_BEACON_H__ @@ -48,5 +48,7 @@ extern int ath_beacon_alloc(struct ath_softc *sc, struct ieee80211_node *ni); extern void ath_beacon_return(struct ath_softc *sc, struct ath_buf *bf); extern void ath_beacon_free(struct ath_softc *sc); extern void ath_beacon_proc(void *arg, int pending); +extern void ath_beacon_miss(struct ath_softc *sc); #endif + diff --git a/sys/dev/ath/if_ath_btcoex.c b/sys/dev/ath/if_ath_btcoex.c index fff6f3b..f3f44a6 100644 --- a/sys/dev/ath/if_ath_btcoex.c +++ b/sys/dev/ath/if_ath_btcoex.c @@ -26,10 +26,10 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGES. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/if_ath_btcoex.c 277277 2015-01-17 00:02:18Z adrian $ */ #include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); +__FBSDID("$FreeBSD: head/sys/dev/ath/if_ath_btcoex.c 277277 2015-01-17 00:02:18Z adrian $"); /* * This implements some very basic bluetooth coexistence methods for @@ -44,6 +44,7 @@ __FBSDID("$FreeBSD$"); #include <sys/sysctl.h> #include <sys/kernel.h> #include <sys/lock.h> +#include <sys/malloc.h> #include <sys/mutex.h> #include <sys/errno.h> @@ -54,6 +55,7 @@ __FBSDID("$FreeBSD$"); #include <sys/socket.h> #include <net/if.h> +#include <net/if_var.h> #include <net/if_media.h> #include <net/if_arp.h> #include <net/ethernet.h> /* XXX for ether_sprintf */ @@ -186,6 +188,72 @@ ath_btcoex_cfg_wb225(struct ath_softc *sc) return (0); } +/* + * Initial AR9462 / (WB222) bluetooth coexistence settings, + * just for experimentation. + * + * Return 0 for OK; errno for error. + */ +static int +ath_btcoex_cfg_wb222(struct ath_softc *sc) +{ + HAL_BT_COEX_INFO btinfo; + HAL_BT_COEX_CONFIG btconfig; + struct ath_hal *ah = sc->sc_ah; + + if (! ath_hal_btcoex_supported(ah)) + return (EINVAL); + + bzero(&btinfo, sizeof(btinfo)); + bzero(&btconfig, sizeof(btconfig)); + + device_printf(sc->sc_dev, "Enabling WB222 BTCOEX\n"); + + btinfo.bt_module = HAL_BT_MODULE_JANUS; /* XXX not used? */ + btinfo.bt_coex_config = HAL_BT_COEX_CFG_MCI; + + /* + * MCI uses a completely different interface to speak + * to the bluetooth module - it's a command based + * thing over a serial line, rather than + * state pins to/from the bluetooth module. + * + * So, the GPIO configuration, polarity, etc + * doesn't matter on MCI devices; it's just + * completely ignored by the HAL. + */ + btinfo.bt_gpio_bt_active = 4; + btinfo.bt_gpio_bt_priority = 8; + btinfo.bt_gpio_wlan_active = 5; + + btinfo.bt_active_polarity = 1; /* XXX not used */ + btinfo.bt_single_ant = 0; /* 2 antenna on WB222 */ + btinfo.bt_isolation = 0; /* in dB, not used */ + + ath_hal_btcoex_set_info(ah, &btinfo); + + btconfig.bt_time_extend = 0; + btconfig.bt_txstate_extend = 1; /* true */ + btconfig.bt_txframe_extend = 1; /* true */ + btconfig.bt_mode = HAL_BT_COEX_MODE_SLOTTED; + btconfig.bt_quiet_collision = 1; /* true */ + btconfig.bt_rxclear_polarity = 1; /* true */ + btconfig.bt_priority_time = 2; + btconfig.bt_first_slot_time = 5; + btconfig.bt_hold_rxclear = 1; /* true */ + + ath_hal_btcoex_set_config(ah, &btconfig); + + /* + * Enable antenna diversity. + */ + ath_hal_btcoex_set_parameter(ah, HAL_BT_COEX_ANTENNA_DIVERSITY, 1); + + return (0); +} + + + #if 0 /* @@ -241,6 +309,8 @@ ath_btcoex_attach(struct ath_softc *sc) if (strncmp(profname, "wb195", 5) == 0) { ret = ath_btcoex_cfg_wb195(sc); + } else if (strncmp(profname, "wb222", 5) == 0) { + ret = ath_btcoex_cfg_wb222(sc); } else if (strncmp(profname, "wb225", 5) == 0) { ret = ath_btcoex_cfg_wb225(sc); } else { diff --git a/sys/dev/ath/if_ath_btcoex.h b/sys/dev/ath/if_ath_btcoex.h index 8b175d2..7faf418 100644 --- a/sys/dev/ath/if_ath_btcoex.h +++ b/sys/dev/ath/if_ath_btcoex.h @@ -26,7 +26,7 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGES. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/if_ath_btcoex.h 251487 2013-06-07 09:02:02Z adrian $ */ #ifndef __IF_ATH_BTCOEX_H__ #define __IF_ATH_BTCOEX_H__ diff --git a/sys/dev/ath/if_ath_debug.c b/sys/dev/ath/if_ath_debug.c index e3c73f5..6b5cc16 100644 --- a/sys/dev/ath/if_ath_debug.c +++ b/sys/dev/ath/if_ath_debug.c @@ -28,7 +28,7 @@ */ #include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); +__FBSDID("$FreeBSD: head/sys/dev/ath/if_ath_debug.c 267992 2014-06-28 03:56:17Z hselasky $"); #include "opt_inet.h" #include "opt_ath.h" @@ -92,9 +92,8 @@ __FBSDID("$FreeBSD$"); uint64_t ath_debug = 0; SYSCTL_DECL(_hw_ath); -SYSCTL_QUAD(_hw_ath, OID_AUTO, debug, CTLFLAG_RW, &ath_debug, +SYSCTL_QUAD(_hw_ath, OID_AUTO, debug, CTLFLAG_RWTUN, &ath_debug, 0, "control debugging printfs"); -TUNABLE_QUAD("hw.ath.debug", &ath_debug); void ath_printrxbuf(struct ath_softc *sc, const struct ath_buf *bf, diff --git a/sys/dev/ath/if_ath_debug.h b/sys/dev/ath/if_ath_debug.h index 83597af..80d81a9 100644 --- a/sys/dev/ath/if_ath_debug.h +++ b/sys/dev/ath/if_ath_debug.h @@ -26,7 +26,7 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGES. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/if_ath_debug.h 265115 2014-04-30 02:19:41Z adrian $ */ #ifndef __IF_ATH_DEBUG_H__ #define __IF_ATH_DEBUG_H__ @@ -68,6 +68,7 @@ enum { ATH_DEBUG_SW_TX_FILT = 0x400000000ULL, /* SW TX FF */ ATH_DEBUG_NODE_PWRSAVE = 0x800000000ULL, /* node powersave */ ATH_DEBUG_DIVERSITY = 0x1000000000ULL, /* Diversity logic */ + ATH_DEBUG_PWRSAVE = 0x2000000000ULL, ATH_DEBUG_ANY = 0xffffffffffffffffULL }; diff --git a/sys/dev/ath/if_ath_keycache.c b/sys/dev/ath/if_ath_keycache.c index 6c2749f..cfeb895 100644 --- a/sys/dev/ath/if_ath_keycache.c +++ b/sys/dev/ath/if_ath_keycache.c @@ -28,7 +28,7 @@ */ #include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); +__FBSDID("$FreeBSD: head/sys/dev/ath/if_ath_keycache.c 265115 2014-04-30 02:19:41Z adrian $"); /* * Driver for the Atheros Wireless LAN controller. @@ -62,6 +62,7 @@ __FBSDID("$FreeBSD$"); #include <machine/bus.h> #include <net/if.h> +#include <net/if_var.h> #include <net/if_dl.h> #include <net/if_media.h> #include <net/if_types.h> @@ -77,6 +78,7 @@ __FBSDID("$FreeBSD$"); #include <dev/ath/if_ath_debug.h> #include <dev/ath/if_ath_keycache.h> +#include <dev/ath/if_ath_misc.h> #ifdef ATH_DEBUG static void @@ -197,6 +199,7 @@ ath_keyset(struct ath_softc *sc, struct ieee80211vap *vap, u_int8_t gmac[IEEE80211_ADDR_LEN]; const u_int8_t *mac; HAL_KEYVAL hk; + int ret; memset(&hk, 0, sizeof(hk)); /* @@ -250,13 +253,19 @@ ath_keyset(struct ath_softc *sc, struct ieee80211vap *vap, } else mac = k->wk_macaddr; + ATH_LOCK(sc); + ath_power_set_power_state(sc, HAL_PM_AWAKE); if (hk.kv_type == HAL_CIPHER_TKIP && (k->wk_flags & IEEE80211_KEY_SWMIC) == 0) { - return ath_keyset_tkip(sc, k, &hk, mac); + ret = ath_keyset_tkip(sc, k, &hk, mac); } else { KEYPRINTF(sc, k->wk_keyix, &hk, mac); - return ath_hal_keyset(ah, k->wk_keyix, &hk, mac); + ret = ath_hal_keyset(ah, k->wk_keyix, &hk, mac); } + ath_power_restore_power_state(sc); + ATH_UNLOCK(sc); + + return (ret); #undef N } @@ -491,6 +500,8 @@ ath_key_delete(struct ieee80211vap *vap, const struct ieee80211_key *k) DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s: delete key %u\n", __func__, keyix); + ATH_LOCK(sc); + ath_power_set_power_state(sc, HAL_PM_AWAKE); ath_hal_keyreset(ah, keyix); /* * Handle split tx/rx keying required for TKIP with h/w MIC. @@ -514,6 +525,8 @@ ath_key_delete(struct ieee80211vap *vap, const struct ieee80211_key *k) } } } + ath_power_restore_power_state(sc); + ATH_UNLOCK(sc); return 1; } diff --git a/sys/dev/ath/if_ath_keycache.h b/sys/dev/ath/if_ath_keycache.h index 0b79e6f..1e5c6f3 100644 --- a/sys/dev/ath/if_ath_keycache.h +++ b/sys/dev/ath/if_ath_keycache.h @@ -26,7 +26,7 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGES. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/if_ath_keycache.h 227357 2011-11-08 19:25:52Z adrian $ */ #ifndef __IF_ATH_CRYPTO_H__ diff --git a/sys/dev/ath/if_ath_led.c b/sys/dev/ath/if_ath_led.c index 33cc512..2e11df0 100644 --- a/sys/dev/ath/if_ath_led.c +++ b/sys/dev/ath/if_ath_led.c @@ -28,7 +28,7 @@ */ #include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); +__FBSDID("$FreeBSD: head/sys/dev/ath/if_ath_led.c 265115 2014-04-30 02:19:41Z adrian $"); /* * Driver for the Atheros Wireless LAN controller. @@ -122,6 +122,11 @@ __FBSDID("$FreeBSD$"); void ath_led_config(struct ath_softc *sc) { + + ATH_LOCK(sc); + ath_power_set_power_state(sc, HAL_PM_AWAKE); + ATH_UNLOCK(sc); + /* Software LED blinking - GPIO controlled LED */ if (sc->sc_softled) { ath_hal_gpioCfgOutput(sc->sc_ah, sc->sc_ledpin, @@ -144,6 +149,10 @@ ath_led_config(struct ath_softc *sc) ath_hal_gpioCfgOutput(sc->sc_ah, sc->sc_led_net_pin, HAL_GPIO_OUTPUT_MUX_MAC_NETWORK_LED); } + + ATH_LOCK(sc); + ath_power_restore_power_state(sc); + ATH_UNLOCK(sc); } static void diff --git a/sys/dev/ath/if_ath_led.h b/sys/dev/ath/if_ath_led.h index 54de4c4..52a5602 100644 --- a/sys/dev/ath/if_ath_led.h +++ b/sys/dev/ath/if_ath_led.h @@ -26,7 +26,7 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGES. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/if_ath_led.h 228888 2011-12-26 05:46:22Z adrian $ */ #ifndef __IF_ATH_LED_H__ #define __IF_ATH_LED_H__ diff --git a/sys/dev/ath/if_ath_lna_div.c b/sys/dev/ath/if_ath_lna_div.c index 4ae81a3..373dc10 100644 --- a/sys/dev/ath/if_ath_lna_div.c +++ b/sys/dev/ath/if_ath_lna_div.c @@ -26,10 +26,10 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGES. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/if_ath_lna_div.c 272292 2014-09-30 03:19:29Z adrian $ */ #include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); +__FBSDID("$FreeBSD: head/sys/dev/ath/if_ath_lna_div.c 272292 2014-09-30 03:19:29Z adrian $"); /* * This module handles LNA diversity for those chips which implement LNA @@ -44,6 +44,7 @@ __FBSDID("$FreeBSD$"); #include <sys/sysctl.h> #include <sys/kernel.h> #include <sys/lock.h> +#include <sys/malloc.h> #include <sys/mutex.h> #include <sys/errno.h> @@ -54,6 +55,7 @@ __FBSDID("$FreeBSD$"); #include <sys/socket.h> #include <net/if.h> +#include <net/if_var.h> #include <net/if_media.h> #include <net/if_arp.h> #include <net/ethernet.h> /* XXX for ether_sprintf */ @@ -207,6 +209,10 @@ bad: return (error); } +/* + * XXX need to low_rssi_thresh config from ath9k, to support CUS198 + * antenna diversity correctly. + */ static HAL_BOOL ath_is_alt_ant_ratio_better(int alt_ratio, int maxdelta, int mindelta, int main_rssi_avg, int alt_rssi_avg, int pkt_count) diff --git a/sys/dev/ath/if_ath_lna_div.h b/sys/dev/ath/if_ath_lna_div.h index 997466a..d988269 100644 --- a/sys/dev/ath/if_ath_lna_div.h +++ b/sys/dev/ath/if_ath_lna_div.h @@ -26,7 +26,7 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGES. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/if_ath_lna_div.h 251730 2013-06-14 03:42:10Z adrian $ */ #ifndef __IF_ATH_LNA_DIV_H__ #define __IF_ATH_LNA_DIV_H__ diff --git a/sys/dev/ath/if_ath_misc.h b/sys/dev/ath/if_ath_misc.h index 0c99bc7..1e14a9f 100644 --- a/sys/dev/ath/if_ath_misc.h +++ b/sys/dev/ath/if_ath_misc.h @@ -26,7 +26,7 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGES. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/if_ath_misc.h 265205 2014-05-02 00:48:09Z adrian $ */ #ifndef __IF_ATH_MISC_H__ #define __IF_ATH_MISC_H__ @@ -128,6 +128,19 @@ extern void ath_start_task(void *arg, int npending); extern void ath_tx_dump(struct ath_softc *sc, struct ath_txq *txq); /* + * Power state tracking. + */ +extern void _ath_power_setpower(struct ath_softc *sc, int power_state, const char *file, int line); +extern void _ath_power_set_selfgen(struct ath_softc *sc, int power_state, const char *file, int line); +extern void _ath_power_set_power_state(struct ath_softc *sc, int power_state, const char *file, int line); +extern void _ath_power_restore_power_state(struct ath_softc *sc, const char *file, int line); + +#define ath_power_setpower(sc, ps) _ath_power_setpower(sc, ps, __FILE__, __LINE__) +#define ath_power_setselfgen(sc, ps) _ath_power_set_selfgen(sc, ps, __FILE__, __LINE__) +#define ath_power_set_power_state(sc, ps) _ath_power_set_power_state(sc, ps, __FILE__, __LINE__) +#define ath_power_restore_power_state(sc) _ath_power_restore_power_state(sc, __FILE__, __LINE__) + +/* * Kick the frame TX task. */ static inline void diff --git a/sys/dev/ath/if_ath_pci.c b/sys/dev/ath/if_ath_pci.c index 91cb425..8cc0d00 100644 --- a/sys/dev/ath/if_ath_pci.c +++ b/sys/dev/ath/if_ath_pci.c @@ -28,7 +28,7 @@ */ #include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); +__FBSDID("$FreeBSD: head/sys/dev/ath/if_ath_pci.c 278765 2015-02-14 18:14:45Z adrian $"); /* * PCI/Cardbus front-end for the Atheros Wireless LAN controller driver. @@ -37,6 +37,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/systm.h> +#include <sys/malloc.h> #include <sys/module.h> #include <sys/kernel.h> #include <sys/lock.h> @@ -53,6 +54,7 @@ __FBSDID("$FreeBSD$"); #include <net/if.h> #include <net/if_media.h> #include <net/if_arp.h> +#include <net/ethernet.h> #include <net80211/ieee80211_var.h> @@ -78,6 +80,98 @@ struct ath_pci_softc { void *sc_ih; /* interrupt handler */ }; +/* + * XXX eventually this should be some system level definition + * so modules will hvae probe/attach information like USB. + * But for now.. + */ +struct pci_device_id { + int vendor_id; + int device_id; + + int sub_vendor_id; + int sub_device_id; + + int driver_data; + + int match_populated:1; + int match_vendor_id:1; + int match_device_id:1; + int match_sub_vendor_id:1; + int match_sub_device_id:1; +}; + +#define PCI_VDEVICE(v, s) \ + .vendor_id = (v), \ + .device_id = (s), \ + .match_populated = 1, \ + .match_vendor_id = 1, \ + .match_device_id = 1 + +#define PCI_DEVICE_SUB(v, d, dv, ds) \ + .match_populated = 1, \ + .vendor_id = (v), .match_vendor_id = 1, \ + .device_id = (d), .match_device_id = 1, \ + .sub_vendor_id = (dv), .match_sub_vendor_id = 1, \ + .sub_device_id = (ds), .match_sub_device_id = 1 + +#define PCI_VENDOR_ID_ATHEROS 0x168c +#define PCI_VENDOR_ID_SAMSUNG 0x144d +#define PCI_VENDOR_ID_AZWAVE 0x1a3b +#define PCI_VENDOR_ID_FOXCONN 0x105b +#define PCI_VENDOR_ID_ATTANSIC 0x1969 +#define PCI_VENDOR_ID_ASUSTEK 0x1043 +#define PCI_VENDOR_ID_DELL 0x1028 +#define PCI_VENDOR_ID_QMI 0x1a32 +#define PCI_VENDOR_ID_LENOVO 0x17aa +#define PCI_VENDOR_ID_HP 0x103c + +#include "if_ath_pci_devlist.h" + +/* + * Attempt to find a match for the given device in + * the given device table. + * + * Returns the device structure or NULL if no matching + * PCI device is found. + */ +static const struct pci_device_id * +ath_pci_probe_device(device_t dev, const struct pci_device_id *dev_table, int nentries) +{ + int i; + int vendor_id, device_id; + int sub_vendor_id, sub_device_id; + + vendor_id = pci_get_vendor(dev); + device_id = pci_get_device(dev); + sub_vendor_id = pci_get_subvendor(dev); + sub_device_id = pci_get_subdevice(dev); + + for (i = 0; i < nentries; i++) { + /* Don't match on non-populated (eg empty) entries */ + if (! dev_table[i].match_populated) + continue; + + if (dev_table[i].match_vendor_id && + (dev_table[i].vendor_id != vendor_id)) + continue; + if (dev_table[i].match_device_id && + (dev_table[i].device_id != device_id)) + continue; + if (dev_table[i].match_sub_vendor_id && + (dev_table[i].sub_vendor_id != sub_vendor_id)) + continue; + if (dev_table[i].match_sub_device_id && + (dev_table[i].sub_device_id != sub_device_id)) + continue; + + /* Match */ + return (&dev_table[i]); + } + + return (NULL); +} + #define BS_BAR 0x10 #define PCIR_RETRY_TIMEOUT 0x41 #define PCIR_CFG_PMCSR 0x48 @@ -148,9 +242,15 @@ ath_pci_attach(device_t dev) const struct firmware *fw = NULL; const char *buf; #endif + const struct pci_device_id *pd; sc->sc_dev = dev; + /* Do this lookup anyway; figure out what to do with it later */ + pd = ath_pci_probe_device(dev, ath_pci_id_table, nitems(ath_pci_id_table)); + if (pd) + sc->sc_pci_devinfo = pd->driver_data; + /* * Enable bus mastering. */ @@ -171,8 +271,7 @@ ath_pci_attach(device_t dev) device_printf(dev, "cannot map register space\n"); goto bad; } - /* XXX uintptr_t is a bandaid for ia64; to be fixed */ - sc->sc_st = (HAL_BUS_TAG)(uintptr_t) rman_get_bustag(psc->sc_sr); + sc->sc_st = (HAL_BUS_TAG) rman_get_bustag(psc->sc_sr); sc->sc_sh = (HAL_BUS_HANDLE) rman_get_bushandle(psc->sc_sr); /* * Mark device invalid so any interrupts (shared or otherwise) @@ -180,6 +279,13 @@ ath_pci_attach(device_t dev) */ sc->sc_invalid = 1; + ATH_LOCK_INIT(sc); + ATH_PCU_LOCK_INIT(sc); + ATH_RX_LOCK_INIT(sc); + ATH_TX_LOCK_INIT(sc); + ATH_TX_IC_LOCK_INIT(sc); + ATH_TXSTATUS_LOCK_INIT(sc); + /* * Arrange interrupt line. */ @@ -230,7 +336,7 @@ ath_pci_attach(device_t dev) if (fw == NULL) { device_printf(dev, "%s: couldn't find firmware\n", __func__); - goto bad3; + goto bad4; } device_printf(dev, "%s: EEPROM firmware @ %p\n", @@ -240,30 +346,20 @@ ath_pci_attach(device_t dev) if (! sc->sc_eepromdata) { device_printf(dev, "%s: can't malloc eepromdata\n", __func__); - goto bad3; + goto bad4; } memcpy(sc->sc_eepromdata, fw->data, fw->datasize); firmware_put(fw, 0); } #endif /* ATH_EEPROM_FIRMWARE */ - ATH_LOCK_INIT(sc); - ATH_PCU_LOCK_INIT(sc); - ATH_RX_LOCK_INIT(sc); - ATH_TX_LOCK_INIT(sc); - ATH_TX_IC_LOCK_INIT(sc); - ATH_TXSTATUS_LOCK_INIT(sc); - error = ath_attach(pci_get_device(dev), sc); if (error == 0) /* success */ return 0; - ATH_TXSTATUS_LOCK_DESTROY(sc); - ATH_PCU_LOCK_DESTROY(sc); - ATH_RX_LOCK_DESTROY(sc); - ATH_TX_IC_LOCK_DESTROY(sc); - ATH_TX_LOCK_DESTROY(sc); - ATH_LOCK_DESTROY(sc); +#ifdef ATH_EEPROM_FIRMWARE +bad4: +#endif bus_dma_tag_destroy(sc->sc_dmat); bad3: bus_teardown_intr(dev, psc->sc_irq, psc->sc_ih); @@ -271,6 +367,14 @@ bad2: bus_release_resource(dev, SYS_RES_IRQ, 0, psc->sc_irq); bad1: bus_release_resource(dev, SYS_RES_MEMORY, BS_BAR, psc->sc_sr); + + ATH_TXSTATUS_LOCK_DESTROY(sc); + ATH_PCU_LOCK_DESTROY(sc); + ATH_RX_LOCK_DESTROY(sc); + ATH_TX_IC_LOCK_DESTROY(sc); + ATH_TX_LOCK_DESTROY(sc); + ATH_LOCK_DESTROY(sc); + bad: return (error); } diff --git a/sys/dev/ath/if_ath_pci_devlist.h b/sys/dev/ath/if_ath_pci_devlist.h new file mode 100644 index 0000000..c699f04 --- /dev/null +++ b/sys/dev/ath/if_ath_pci_devlist.h @@ -0,0 +1,669 @@ +/*- + * Copyright (c) 2014 Qualcomm Atheros. + * 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, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. + * + * $FreeBSD: head/sys/dev/ath/if_ath_pci_devlist.h 272295 2014-09-30 05:50:34Z adrian $ + */ + +static const struct pci_device_id ath_pci_id_table[] = { + { PCI_VDEVICE(PCI_VENDOR_ID_ATHEROS, 0x0023) }, /* PCI */ + { PCI_VDEVICE(PCI_VENDOR_ID_ATHEROS, 0x0024) }, /* PCI-E */ + { PCI_VDEVICE(PCI_VENDOR_ID_ATHEROS, 0x0027) }, /* PCI */ + { PCI_VDEVICE(PCI_VENDOR_ID_ATHEROS, 0x0029) }, /* PCI */ + { PCI_VDEVICE(PCI_VENDOR_ID_ATHEROS, 0x002A) }, /* PCI-E */ + + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x002A, + PCI_VENDOR_ID_AZWAVE, + 0x1C71), + .driver_data = ATH_PCI_D3_L1_WAR }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x002A, + PCI_VENDOR_ID_FOXCONN, + 0xE01F), + .driver_data = ATH_PCI_D3_L1_WAR }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x002A, + 0x11AD, /* LITEON */ + 0x6632), + .driver_data = ATH_PCI_D3_L1_WAR }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x002A, + 0x11AD, /* LITEON */ + 0x6642), + .driver_data = ATH_PCI_D3_L1_WAR }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x002A, + PCI_VENDOR_ID_QMI, + 0x0306), + .driver_data = ATH_PCI_D3_L1_WAR }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x002A, + 0x185F, /* WNC */ + 0x309D), + .driver_data = ATH_PCI_D3_L1_WAR }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x002A, + 0x10CF, /* Fujitsu */ + 0x147C), + .driver_data = ATH_PCI_D3_L1_WAR }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x002A, + 0x10CF, /* Fujitsu */ + 0x147D), + .driver_data = ATH_PCI_D3_L1_WAR }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x002A, + 0x10CF, /* Fujitsu */ + 0x1536), + .driver_data = ATH_PCI_D3_L1_WAR }, + + /* AR9285 card for Asus */ + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x002B, + PCI_VENDOR_ID_AZWAVE, + 0x2C37), + .driver_data = ATH_PCI_BT_ANT_DIV }, + + { PCI_VDEVICE(PCI_VENDOR_ID_ATHEROS, 0x002B) }, /* PCI-E */ + { PCI_VDEVICE(PCI_VENDOR_ID_ATHEROS, 0x002C) }, /* PCI-E 802.11n bonded out */ + { PCI_VDEVICE(PCI_VENDOR_ID_ATHEROS, 0x002D) }, /* PCI */ + { PCI_VDEVICE(PCI_VENDOR_ID_ATHEROS, 0x002E) }, /* PCI-E */ + + /* Killer Wireless (3x3) */ + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0030, + 0x1A56, + 0x2000), + .driver_data = ATH_PCI_KILLER }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0030, + 0x1A56, + 0x2001), + .driver_data = ATH_PCI_KILLER }, + + { PCI_VDEVICE(PCI_VENDOR_ID_ATHEROS, 0x0030) }, /* PCI-E AR9300 */ + + /* PCI-E CUS198 */ + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + PCI_VENDOR_ID_AZWAVE, + 0x2086), + .driver_data = ATH_PCI_CUS198 | ATH_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + PCI_VENDOR_ID_AZWAVE, + 0x1237), + .driver_data = ATH_PCI_CUS198 | ATH_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + PCI_VENDOR_ID_AZWAVE, + 0x2126), + .driver_data = ATH_PCI_CUS198 | ATH_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + PCI_VENDOR_ID_AZWAVE, + 0x126A), + .driver_data = ATH_PCI_CUS198 | ATH_PCI_BT_ANT_DIV }, + + /* PCI-E CUS230 */ + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + PCI_VENDOR_ID_AZWAVE, + 0x2152), + .driver_data = ATH_PCI_CUS230 | ATH_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + PCI_VENDOR_ID_FOXCONN, + 0xE075), + .driver_data = ATH_PCI_CUS230 | ATH_PCI_BT_ANT_DIV }, + + /* WB225 */ + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + PCI_VENDOR_ID_ATHEROS, + 0x3119), + .driver_data = ATH_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + PCI_VENDOR_ID_ATHEROS, + 0x3122), + .driver_data = ATH_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + 0x185F, /* WNC */ + 0x3119), + .driver_data = ATH_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + 0x185F, /* WNC */ + 0x3027), + .driver_data = ATH_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + PCI_VENDOR_ID_SAMSUNG, + 0x4105), + .driver_data = ATH_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + PCI_VENDOR_ID_SAMSUNG, + 0x4106), + .driver_data = ATH_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + PCI_VENDOR_ID_SAMSUNG, + 0x410D), + .driver_data = ATH_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + PCI_VENDOR_ID_SAMSUNG, + 0x410E), + .driver_data = ATH_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + PCI_VENDOR_ID_SAMSUNG, + 0x410F), + .driver_data = ATH_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + PCI_VENDOR_ID_SAMSUNG, + 0xC706), + .driver_data = ATH_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + PCI_VENDOR_ID_SAMSUNG, + 0xC680), + .driver_data = ATH_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + PCI_VENDOR_ID_SAMSUNG, + 0xC708), + .driver_data = ATH_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + PCI_VENDOR_ID_LENOVO, + 0x3218), + .driver_data = ATH_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + PCI_VENDOR_ID_LENOVO, + 0x3219), + .driver_data = ATH_PCI_BT_ANT_DIV }, + + /* AR9485 cards with PLL power-save disabled by default. */ + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + PCI_VENDOR_ID_AZWAVE, + 0x2C97), + .driver_data = ATH_PCI_NO_PLL_PWRSAVE }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + PCI_VENDOR_ID_AZWAVE, + 0x2100), + .driver_data = ATH_PCI_NO_PLL_PWRSAVE }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + 0x1C56, /* ASKEY */ + 0x4001), + .driver_data = ATH_PCI_NO_PLL_PWRSAVE }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + 0x11AD, /* LITEON */ + 0x6627), + .driver_data = ATH_PCI_NO_PLL_PWRSAVE }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + 0x11AD, /* LITEON */ + 0x6628), + .driver_data = ATH_PCI_NO_PLL_PWRSAVE }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + PCI_VENDOR_ID_FOXCONN, + 0xE04E), + .driver_data = ATH_PCI_NO_PLL_PWRSAVE }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + PCI_VENDOR_ID_FOXCONN, + 0xE04F), + .driver_data = ATH_PCI_NO_PLL_PWRSAVE }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + 0x144F, /* ASKEY */ + 0x7197), + .driver_data = ATH_PCI_NO_PLL_PWRSAVE }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + 0x1B9A, /* XAVI */ + 0x2000), + .driver_data = ATH_PCI_NO_PLL_PWRSAVE }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + 0x1B9A, /* XAVI */ + 0x2001), + .driver_data = ATH_PCI_NO_PLL_PWRSAVE }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + PCI_VENDOR_ID_AZWAVE, + 0x1186), + .driver_data = ATH_PCI_NO_PLL_PWRSAVE }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + PCI_VENDOR_ID_AZWAVE, + 0x1F86), + .driver_data = ATH_PCI_NO_PLL_PWRSAVE }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + PCI_VENDOR_ID_AZWAVE, + 0x1195), + .driver_data = ATH_PCI_NO_PLL_PWRSAVE }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + PCI_VENDOR_ID_AZWAVE, + 0x1F95), + .driver_data = ATH_PCI_NO_PLL_PWRSAVE }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + 0x1B9A, /* XAVI */ + 0x1C00), + .driver_data = ATH_PCI_NO_PLL_PWRSAVE }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + 0x1B9A, /* XAVI */ + 0x1C01), + .driver_data = ATH_PCI_NO_PLL_PWRSAVE }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + PCI_VENDOR_ID_ASUSTEK, + 0x850D), + .driver_data = ATH_PCI_NO_PLL_PWRSAVE }, + + { PCI_VDEVICE(PCI_VENDOR_ID_ATHEROS, 0x0032) }, /* PCI-E AR9485 */ + { PCI_VDEVICE(PCI_VENDOR_ID_ATHEROS, 0x0033) }, /* PCI-E AR9580 */ + + /* PCI-E CUS217 */ + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0034, + PCI_VENDOR_ID_AZWAVE, + 0x2116), + .driver_data = ATH_PCI_CUS217 }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0034, + 0x11AD, /* LITEON */ + 0x6661), + .driver_data = ATH_PCI_CUS217 }, + + /* AR9462 with WoW support */ + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0034, + PCI_VENDOR_ID_ATHEROS, + 0x3117), + .driver_data = ATH_PCI_WOW }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0034, + PCI_VENDOR_ID_LENOVO, + 0x3214), + .driver_data = ATH_PCI_WOW }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0034, + PCI_VENDOR_ID_ATTANSIC, + 0x0091), + .driver_data = ATH_PCI_WOW }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0034, + PCI_VENDOR_ID_AZWAVE, + 0x2110), + .driver_data = ATH_PCI_WOW }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0034, + PCI_VENDOR_ID_ASUSTEK, + 0x850E), + .driver_data = ATH_PCI_WOW }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0034, + 0x11AD, /* LITEON */ + 0x6631), + .driver_data = ATH_PCI_WOW }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0034, + 0x11AD, /* LITEON */ + 0x6641), + .driver_data = ATH_PCI_WOW }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0034, + PCI_VENDOR_ID_HP, + 0x1864), + .driver_data = ATH_PCI_WOW }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0034, + 0x14CD, /* USI */ + 0x0063), + .driver_data = ATH_PCI_WOW }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0034, + 0x14CD, /* USI */ + 0x0064), + .driver_data = ATH_PCI_WOW }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0034, + 0x10CF, /* Fujitsu */ + 0x1783), + .driver_data = ATH_PCI_WOW }, + + /* Killer Wireless (2x2) */ + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0030, + 0x1A56, + 0x2003), + .driver_data = ATH_PCI_KILLER }, + + { PCI_VDEVICE(PCI_VENDOR_ID_ATHEROS, 0x0034) }, /* PCI-E AR9462 */ + { PCI_VDEVICE(PCI_VENDOR_ID_ATHEROS, 0x0037) }, /* PCI-E AR1111/AR9485 */ + + /* CUS252 */ + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_ATHEROS, + 0x3028), + .driver_data = ATH_PCI_CUS252 | + ATH_PCI_AR9565_2ANT | + ATH_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_AZWAVE, + 0x2176), + .driver_data = ATH_PCI_CUS252 | + ATH_PCI_AR9565_2ANT | + ATH_PCI_BT_ANT_DIV }, + + /* WB335 1-ANT */ + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_FOXCONN, + 0xE068), + .driver_data = ATH_PCI_AR9565_1ANT }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + 0x185F, /* WNC */ + 0xA119), + .driver_data = ATH_PCI_AR9565_1ANT }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + 0x11AD, /* LITEON */ + 0x0632), + .driver_data = ATH_PCI_AR9565_1ANT }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + 0x11AD, /* LITEON */ + 0x06B2), + .driver_data = ATH_PCI_AR9565_1ANT }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + 0x11AD, /* LITEON */ + 0x0842), + .driver_data = ATH_PCI_AR9565_1ANT }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + 0x11AD, /* LITEON */ + 0x6671), + .driver_data = ATH_PCI_AR9565_1ANT }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + 0x1B9A, /* XAVI */ + 0x2811), + .driver_data = ATH_PCI_AR9565_1ANT }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + 0x1B9A, /* XAVI */ + 0x2812), + .driver_data = ATH_PCI_AR9565_1ANT }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + 0x1B9A, /* XAVI */ + 0x28A1), + .driver_data = ATH_PCI_AR9565_1ANT }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_AZWAVE, + 0x218A), + .driver_data = ATH_PCI_AR9565_1ANT }, + + /* WB335 1-ANT / Antenna Diversity */ + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_ATHEROS, + 0x3025), + .driver_data = ATH_PCI_AR9565_1ANT | ATH_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_ATHEROS, + 0x3026), + .driver_data = ATH_PCI_AR9565_1ANT | ATH_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_ATHEROS, + 0x302B), + .driver_data = ATH_PCI_AR9565_1ANT | ATH_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_FOXCONN, + 0xE069), + .driver_data = ATH_PCI_AR9565_1ANT | ATH_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + 0x185F, /* WNC */ + 0x3028), + .driver_data = ATH_PCI_AR9565_1ANT | ATH_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + 0x11AD, /* LITEON */ + 0x0622), + .driver_data = ATH_PCI_AR9565_1ANT | ATH_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + 0x11AD, /* LITEON */ + 0x0672), + .driver_data = ATH_PCI_AR9565_1ANT | ATH_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + 0x11AD, /* LITEON */ + 0x0662), + .driver_data = ATH_PCI_AR9565_1ANT | ATH_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + 0x11AD, /* LITEON */ + 0x06A2), + .driver_data = ATH_PCI_AR9565_1ANT | ATH_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + 0x11AD, /* LITEON */ + 0x0682), + .driver_data = ATH_PCI_AR9565_1ANT | ATH_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_AZWAVE, + 0x213A), + .driver_data = ATH_PCI_AR9565_1ANT | ATH_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_HP, + 0x18E3), + .driver_data = ATH_PCI_AR9565_1ANT | ATH_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_HP, + 0x217F), + .driver_data = ATH_PCI_AR9565_1ANT | ATH_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_HP, + 0x2005), + .driver_data = ATH_PCI_AR9565_1ANT | ATH_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_DELL, + 0x020C), + .driver_data = ATH_PCI_AR9565_1ANT | ATH_PCI_BT_ANT_DIV }, + + /* WB335 2-ANT / Antenna-Diversity */ + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_SAMSUNG, + 0x411A), + .driver_data = ATH_PCI_AR9565_2ANT | ATH_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_SAMSUNG, + 0x411B), + .driver_data = ATH_PCI_AR9565_2ANT | ATH_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_SAMSUNG, + 0x411C), + .driver_data = ATH_PCI_AR9565_2ANT | ATH_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_SAMSUNG, + 0x411D), + .driver_data = ATH_PCI_AR9565_2ANT | ATH_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_SAMSUNG, + 0x411E), + .driver_data = ATH_PCI_AR9565_2ANT | ATH_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_ATHEROS, + 0x3027), + .driver_data = ATH_PCI_AR9565_2ANT | ATH_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_ATHEROS, + 0x302C), + .driver_data = ATH_PCI_AR9565_2ANT | ATH_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + 0x11AD, /* LITEON */ + 0x0642), + .driver_data = ATH_PCI_AR9565_2ANT | ATH_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + 0x11AD, /* LITEON */ + 0x0652), + .driver_data = ATH_PCI_AR9565_2ANT | ATH_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + 0x11AD, /* LITEON */ + 0x0612), + .driver_data = ATH_PCI_AR9565_2ANT | ATH_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + 0x11AD, /* LITEON */ + 0x0832), + .driver_data = ATH_PCI_AR9565_2ANT | ATH_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + 0x11AD, /* LITEON */ + 0x0692), + .driver_data = ATH_PCI_AR9565_2ANT | ATH_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_AZWAVE, + 0x2130), + .driver_data = ATH_PCI_AR9565_2ANT | ATH_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_AZWAVE, + 0x213B), + .driver_data = ATH_PCI_AR9565_2ANT | ATH_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_AZWAVE, + 0x2182), + .driver_data = ATH_PCI_AR9565_2ANT | ATH_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + 0x144F, /* ASKEY */ + 0x7202), + .driver_data = ATH_PCI_AR9565_2ANT | ATH_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + 0x1B9A, /* XAVI */ + 0x2810), + .driver_data = ATH_PCI_AR9565_2ANT | ATH_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + 0x1B9A, /* XAVI */ + 0x28A2), + .driver_data = ATH_PCI_AR9565_2ANT | ATH_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + 0x185F, /* WNC */ + 0x3027), + .driver_data = ATH_PCI_AR9565_2ANT | ATH_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + 0x185F, /* WNC */ + 0xA120), + .driver_data = ATH_PCI_AR9565_2ANT | ATH_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_FOXCONN, + 0xE07F), + .driver_data = ATH_PCI_AR9565_2ANT | ATH_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_FOXCONN, + 0xE081), + .driver_data = ATH_PCI_AR9565_2ANT | ATH_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_LENOVO, + 0x3026), + .driver_data = ATH_PCI_AR9565_2ANT | ATH_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_LENOVO, + 0x4026), + .driver_data = ATH_PCI_AR9565_2ANT | ATH_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_ASUSTEK, + 0x85F2), + .driver_data = ATH_PCI_AR9565_2ANT | ATH_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_DELL, + 0x020E), + .driver_data = ATH_PCI_AR9565_2ANT | ATH_PCI_BT_ANT_DIV }, + + /* PCI-E AR9565 (WB335) */ + { PCI_VDEVICE(PCI_VENDOR_ID_ATHEROS, 0x0036), + .driver_data = ATH_PCI_BT_ANT_DIV }, + + { 0 } +}; + diff --git a/sys/dev/ath/if_ath_rx.c b/sys/dev/ath/if_ath_rx.c index d9e212b..2799ffd 100644 --- a/sys/dev/ath/if_ath_rx.c +++ b/sys/dev/ath/if_ath_rx.c @@ -28,7 +28,7 @@ */ #include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); +__FBSDID("$FreeBSD: head/sys/dev/ath/if_ath_rx.c 271823 2014-09-18 20:47:39Z glebius $"); /* * Driver for the Atheros Wireless LAN controller. @@ -73,6 +73,7 @@ __FBSDID("$FreeBSD$"); #include <machine/bus.h> #include <net/if.h> +#include <net/if_var.h> #include <net/if_dl.h> #include <net/if_media.h> #include <net/if_types.h> @@ -165,10 +166,22 @@ ath_calcrxfilter(struct ath_softc *sc) /* XXX ic->ic_monvaps != 0? */ if (ic->ic_opmode == IEEE80211_M_MONITOR || (ifp->if_flags & IFF_PROMISC)) rfilt |= HAL_RX_FILTER_PROM; + + /* + * Only listen to all beacons if we're scanning. + * + * Otherwise we only really need to hear beacons from + * our own BSSID. + */ if (ic->ic_opmode == IEEE80211_M_STA || - ic->ic_opmode == IEEE80211_M_IBSS || - sc->sc_swbmiss || sc->sc_scanning) - rfilt |= HAL_RX_FILTER_BEACON; + ic->ic_opmode == IEEE80211_M_IBSS || sc->sc_swbmiss) { + if (sc->sc_do_mybeacon && ! sc->sc_scanning) { + rfilt |= HAL_RX_FILTER_MYBEACON; + } else { /* scanning, non-mybeacon chips */ + rfilt |= HAL_RX_FILTER_BEACON; + } + } + /* * NB: We don't recalculate the rx filter when * ic_protmode changes; otherwise we could do @@ -232,6 +245,8 @@ ath_legacy_rxbuf_init(struct ath_softc *sc, struct ath_buf *bf) struct mbuf *m; struct ath_desc *ds; + /* XXX TODO: ATH_RX_LOCK_ASSERT(sc); */ + m = bf->bf_m; if (m == NULL) { /* @@ -316,6 +331,23 @@ ath_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m, { struct ieee80211vap *vap = ni->ni_vap; struct ath_softc *sc = vap->iv_ic->ic_ifp->if_softc; + uint64_t tsf_beacon_old, tsf_beacon; + uint64_t nexttbtt; + int64_t tsf_delta; + int32_t tsf_delta_bmiss; + int32_t tsf_remainder; + uint64_t tsf_beacon_target; + int tsf_intval; + + tsf_beacon_old = ((uint64_t) LE_READ_4(ni->ni_tstamp.data + 4)) << 32; + tsf_beacon_old |= LE_READ_4(ni->ni_tstamp.data); + +#define TU_TO_TSF(_tu) (((u_int64_t)(_tu)) << 10) + tsf_intval = 1; + if (ni->ni_intval > 0) { + tsf_intval = TU_TO_TSF(ni->ni_intval); + } +#undef TU_TO_TSF /* * Call up first so subsequent work can use information @@ -327,14 +359,79 @@ ath_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m, /* update rssi statistics for use by the hal */ /* XXX unlocked check against vap->iv_bss? */ ATH_RSSI_LPF(sc->sc_halstats.ns_avgbrssi, rssi); + + tsf_beacon = ((uint64_t) LE_READ_4(ni->ni_tstamp.data + 4)) << 32; + tsf_beacon |= LE_READ_4(ni->ni_tstamp.data); + + nexttbtt = ath_hal_getnexttbtt(sc->sc_ah); + + /* + * Let's calculate the delta and remainder, so we can see + * if the beacon timer from the AP is varying by more than + * a few TU. (Which would be a huge, huge problem.) + */ + tsf_delta = (long long) tsf_beacon - (long long) tsf_beacon_old; + + tsf_delta_bmiss = tsf_delta / tsf_intval; + + /* + * If our delta is greater than half the beacon interval, + * let's round the bmiss value up to the next beacon + * interval. Ie, we're running really, really early + * on the next beacon. + */ + if (tsf_delta % tsf_intval > (tsf_intval / 2)) + tsf_delta_bmiss ++; + + tsf_beacon_target = tsf_beacon_old + + (((unsigned long long) tsf_delta_bmiss) * (long long) tsf_intval); + + /* + * The remainder using '%' is between 0 .. intval-1. + * If we're actually running too fast, then the remainder + * will be some large number just under intval-1. + * So we need to look at whether we're running + * before or after the target beacon interval + * and if we are, modify how we do the remainder + * calculation. + */ + if (tsf_beacon < tsf_beacon_target) { + tsf_remainder = + -(tsf_intval - ((tsf_beacon - tsf_beacon_old) % tsf_intval)); + } else { + tsf_remainder = (tsf_beacon - tsf_beacon_old) % tsf_intval; + } + + DPRINTF(sc, ATH_DEBUG_BEACON, "%s: old_tsf=%llu, new_tsf=%llu, target_tsf=%llu, delta=%lld, bmiss=%d, remainder=%d\n", + __func__, + (unsigned long long) tsf_beacon_old, + (unsigned long long) tsf_beacon, + (unsigned long long) tsf_beacon_target, + (long long) tsf_delta, + tsf_delta_bmiss, + tsf_remainder); + + DPRINTF(sc, ATH_DEBUG_BEACON, "%s: tsf=%llu, nexttbtt=%llu, delta=%d\n", + __func__, + (unsigned long long) tsf_beacon, + (unsigned long long) nexttbtt, + (int32_t) tsf_beacon - (int32_t) nexttbtt + tsf_intval); + if (sc->sc_syncbeacon && - ni == vap->iv_bss && vap->iv_state == IEEE80211_S_RUN) { + ni == vap->iv_bss && + (vap->iv_state == IEEE80211_S_RUN || vap->iv_state == IEEE80211_S_SLEEP)) { + DPRINTF(sc, ATH_DEBUG_BEACON, + "%s: syncbeacon=1; syncing\n", + __func__); /* * Resync beacon timers using the tsf of the beacon * frame we just received. */ ath_beacon_config(sc, vap); + sc->sc_syncbeacon = 0; } + + /* fall thru... */ case IEEE80211_FC0_SUBTYPE_PROBE_RESP: if (vap->iv_opmode == IEEE80211_M_IBSS && @@ -879,6 +976,14 @@ rx_next: #define ATH_RX_MAX 128 +/* + * XXX TODO: break out the "get buffers" from "call ath_rx_pkt()" like + * the EDMA code does. + * + * XXX TODO: then, do all of the RX list management stuff inside + * ATH_RX_LOCK() so we don't end up potentially racing. The EDMA + * code is doing it right. + */ static void ath_rx_proc(struct ath_softc *sc, int resched) { @@ -900,6 +1005,7 @@ ath_rx_proc(struct ath_softc *sc, int resched) u_int64_t tsf; int npkts = 0; int kickpcu = 0; + int ret; /* XXX we must not hold the ATH_LOCK here */ ATH_UNLOCK_ASSERT(sc); @@ -910,6 +1016,10 @@ ath_rx_proc(struct ath_softc *sc, int resched) kickpcu = sc->sc_kickpcu; ATH_PCU_UNLOCK(sc); + ATH_LOCK(sc); + ath_power_set_power_state(sc, HAL_PM_AWAKE); + ATH_UNLOCK(sc); + DPRINTF(sc, ATH_DEBUG_RX_PROC, "%s: called\n", __func__); ngood = 0; nf = ath_hal_getchannoise(ah, sc->sc_curchan); @@ -995,8 +1105,26 @@ ath_rx_proc(struct ath_softc *sc, int resched) if (ath_rx_pkt(sc, rs, status, tsf, nf, HAL_RX_QUEUE_HP, bf, m)) ngood++; rx_proc_next: - TAILQ_INSERT_TAIL(&sc->sc_rxbuf, bf, bf_list); - } while (ath_rxbuf_init(sc, bf) == 0); + /* + * If there's a holding buffer, insert that onto + * the RX list; the hardware is now definitely not pointing + * to it now. + */ + ret = 0; + if (sc->sc_rxedma[HAL_RX_QUEUE_HP].m_holdbf != NULL) { + TAILQ_INSERT_TAIL(&sc->sc_rxbuf, + sc->sc_rxedma[HAL_RX_QUEUE_HP].m_holdbf, + bf_list); + ret = ath_rxbuf_init(sc, + sc->sc_rxedma[HAL_RX_QUEUE_HP].m_holdbf); + } + /* + * Next, throw our buffer into the holding entry. The hardware + * may use the descriptor to read the link pointer before + * DMAing the next descriptor in to write out a packet. + */ + sc->sc_rxedma[HAL_RX_QUEUE_HP].m_holdbf = bf; + } while (ret == 0); /* rx signal state monitoring */ ath_hal_rxmonitor(ah, &sc->sc_halstats, sc->sc_curchan); @@ -1028,6 +1156,13 @@ rx_proc_next: * constantly write over the same frame, leading * the RX driver code here to get heavily confused. */ + /* + * XXX Has RX DMA stopped enough here to just call + * ath_startrecv()? + * XXX Do we need to use the holding buffer to restart + * RX DMA by appending entries to the final + * descriptor? Quite likely. + */ #if 1 ath_startrecv(sc); #else @@ -1065,6 +1200,13 @@ rx_proc_next: #undef PA2DESC /* + * Put the hardware to sleep again if we're done with it. + */ + ATH_LOCK(sc); + ath_power_restore_power_state(sc); + ATH_UNLOCK(sc); + + /* * If we hit the maximum number of frames in this round, * reschedule for another immediate pass. This gives * the TX and TX completion routines time to run, which @@ -1111,6 +1253,58 @@ ath_legacy_flushrecv(struct ath_softc *sc) ath_rx_proc(sc, 0); } +static void +ath_legacy_flush_rxpending(struct ath_softc *sc) +{ + + /* XXX ATH_RX_LOCK_ASSERT(sc); */ + + if (sc->sc_rxedma[HAL_RX_QUEUE_LP].m_rxpending != NULL) { + m_freem(sc->sc_rxedma[HAL_RX_QUEUE_LP].m_rxpending); + sc->sc_rxedma[HAL_RX_QUEUE_LP].m_rxpending = NULL; + } + if (sc->sc_rxedma[HAL_RX_QUEUE_HP].m_rxpending != NULL) { + m_freem(sc->sc_rxedma[HAL_RX_QUEUE_HP].m_rxpending); + sc->sc_rxedma[HAL_RX_QUEUE_HP].m_rxpending = NULL; + } +} + +static int +ath_legacy_flush_rxholdbf(struct ath_softc *sc) +{ + struct ath_buf *bf; + + /* XXX ATH_RX_LOCK_ASSERT(sc); */ + /* + * If there are RX holding buffers, free them here and return + * them to the list. + * + * XXX should just verify that bf->bf_m is NULL, as it must + * be at this point! + */ + bf = sc->sc_rxedma[HAL_RX_QUEUE_HP].m_holdbf; + if (bf != NULL) { + if (bf->bf_m != NULL) + m_freem(bf->bf_m); + bf->bf_m = NULL; + TAILQ_INSERT_TAIL(&sc->sc_rxbuf, bf, bf_list); + (void) ath_rxbuf_init(sc, bf); + } + sc->sc_rxedma[HAL_RX_QUEUE_HP].m_holdbf = NULL; + + bf = sc->sc_rxedma[HAL_RX_QUEUE_LP].m_holdbf; + if (bf != NULL) { + if (bf->bf_m != NULL) + m_freem(bf->bf_m); + bf->bf_m = NULL; + TAILQ_INSERT_TAIL(&sc->sc_rxbuf, bf, bf_list); + (void) ath_rxbuf_init(sc, bf); + } + sc->sc_rxedma[HAL_RX_QUEUE_LP].m_holdbf = NULL; + + return (0); +} + /* * Disable the receive h/w in preparation for a reset. */ @@ -1122,6 +1316,8 @@ ath_legacy_stoprecv(struct ath_softc *sc, int dodelay) ((_pa) - (_sc)->sc_rxdma.dd_desc_paddr))) struct ath_hal *ah = sc->sc_ah; + ATH_RX_LOCK(sc); + ath_hal_stoppcurecv(ah); /* disable PCU */ ath_hal_setrxfilter(ah, 0); /* clear recv filter */ ath_hal_stopdmarecv(ah); /* disable DMA engine */ @@ -1155,22 +1351,23 @@ ath_legacy_stoprecv(struct ath_softc *sc, int dodelay) } } #endif - /* - * Free both high/low RX pending, just in case. - */ - if (sc->sc_rxedma[HAL_RX_QUEUE_LP].m_rxpending != NULL) { - m_freem(sc->sc_rxedma[HAL_RX_QUEUE_LP].m_rxpending); - sc->sc_rxedma[HAL_RX_QUEUE_LP].m_rxpending = NULL; - } - if (sc->sc_rxedma[HAL_RX_QUEUE_HP].m_rxpending != NULL) { - m_freem(sc->sc_rxedma[HAL_RX_QUEUE_HP].m_rxpending); - sc->sc_rxedma[HAL_RX_QUEUE_HP].m_rxpending = NULL; - } + + (void) ath_legacy_flush_rxpending(sc); + (void) ath_legacy_flush_rxholdbf(sc); + sc->sc_rxlink = NULL; /* just in case */ + + ATH_RX_UNLOCK(sc); #undef PA2DESC } /* + * XXX TODO: something was calling startrecv without calling + * stoprecv. Let's figure out what/why. It was showing up + * as a mbuf leak (rxpending) and ath_buf leak (holdbf.) + */ + +/* * Enable the receive h/w following a reset. */ static int @@ -1179,9 +1376,18 @@ ath_legacy_startrecv(struct ath_softc *sc) struct ath_hal *ah = sc->sc_ah; struct ath_buf *bf; + ATH_RX_LOCK(sc); + + /* + * XXX should verify these are already all NULL! + */ sc->sc_rxlink = NULL; - sc->sc_rxedma[HAL_RX_QUEUE_LP].m_rxpending = NULL; - sc->sc_rxedma[HAL_RX_QUEUE_HP].m_rxpending = NULL; + (void) ath_legacy_flush_rxpending(sc); + (void) ath_legacy_flush_rxholdbf(sc); + + /* + * Re-chain all of the buffers in the RX buffer list. + */ TAILQ_FOREACH(bf, &sc->sc_rxbuf, bf_list) { int error = ath_rxbuf_init(sc, bf); if (error != 0) { @@ -1197,6 +1403,8 @@ ath_legacy_startrecv(struct ath_softc *sc) ath_hal_rxena(ah); /* enable recv descriptors */ ath_mode_init(sc); /* set filters, etc. */ ath_hal_startpcurecv(ah); /* re-enable PCU/DMA engine */ + + ATH_RX_UNLOCK(sc); return 0; } diff --git a/sys/dev/ath/if_ath_rx.h b/sys/dev/ath/if_ath_rx.h index f831148..9a33df7 100644 --- a/sys/dev/ath/if_ath_rx.h +++ b/sys/dev/ath/if_ath_rx.h @@ -26,7 +26,7 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGES. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/if_ath_rx.h 249085 2013-04-04 08:21:56Z adrian $ */ #ifndef __IF_ATH_RX_H__ #define __IF_ATH_RX_H__ diff --git a/sys/dev/ath/if_ath_rx_edma.c b/sys/dev/ath/if_ath_rx_edma.c index 2be8627..33bf31a 100644 --- a/sys/dev/ath/if_ath_rx_edma.c +++ b/sys/dev/ath/if_ath_rx_edma.c @@ -28,7 +28,7 @@ */ #include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); +__FBSDID("$FreeBSD: head/sys/dev/ath/if_ath_rx_edma.c 271887 2014-09-20 01:22:17Z adrian $"); /* * Driver for the Atheros Wireless LAN controller. @@ -73,6 +73,7 @@ __FBSDID("$FreeBSD$"); #include <machine/bus.h> #include <net/if.h> +#include <net/if_var.h> #include <net/if_dl.h> #include <net/if_media.h> #include <net/if_types.h> @@ -159,10 +160,20 @@ ath_edma_stoprecv(struct ath_softc *sc, int dodelay) struct ath_hal *ah = sc->sc_ah; ATH_RX_LOCK(sc); + ath_hal_stoppcurecv(ah); ath_hal_setrxfilter(ah, 0); - ath_hal_stopdmarecv(ah); + /* + * + */ + if (ath_hal_stopdmarecv(ah) == AH_TRUE) + sc->sc_rx_stopped = 1; + + /* + * Give the various bus FIFOs (not EDMA descriptor FIFO) + * time to finish flushing out data. + */ DELAY(3000); /* Flush RX pending for each queue */ @@ -217,10 +228,6 @@ ath_edma_reinit_fifo(struct ath_softc *sc, HAL_RX_QUEUE qtype) /* * Start receive. - * - * XXX TODO: this needs to reallocate the FIFO entries when a reset - * occurs, in case the FIFO is filled up and no new descriptors get - * thrown into the FIFO. */ static int ath_edma_startrecv(struct ath_softc *sc) @@ -229,35 +236,31 @@ ath_edma_startrecv(struct ath_softc *sc) ATH_RX_LOCK(sc); + /* + * Sanity check - are we being called whilst RX + * isn't stopped? If so, we may end up pushing + * too many entries into the RX FIFO and + * badness occurs. + */ + /* Enable RX FIFO */ ath_hal_rxena(ah); /* - * Entries should only be written out if the - * FIFO is empty. - * - * XXX This isn't correct. I should be looking - * at the value of AR_RXDP_SIZE (0x0070) to determine - * how many entries are in here. - * - * A warm reset will clear the registers but not the FIFO. - * - * And I believe this is actually the address of the last - * handled buffer rather than the current FIFO pointer. - * So if no frames have been (yet) seen, we'll reinit the - * FIFO. - * - * I'll chase that up at some point. + * In theory the hardware has been initialised, right? */ - if (ath_hal_getrxbuf(sc->sc_ah, HAL_RX_QUEUE_HP) == 0) { + if (sc->sc_rx_resetted == 1) { DPRINTF(sc, ATH_DEBUG_EDMA_RX, "%s: Re-initing HP FIFO\n", __func__); ath_edma_reinit_fifo(sc, HAL_RX_QUEUE_HP); - } - if (ath_hal_getrxbuf(sc->sc_ah, HAL_RX_QUEUE_LP) == 0) { DPRINTF(sc, ATH_DEBUG_EDMA_RX, "%s: Re-initing LP FIFO\n", __func__); ath_edma_reinit_fifo(sc, HAL_RX_QUEUE_LP); + sc->sc_rx_resetted = 0; + } else { + device_printf(sc->sc_dev, + "%s: called without resetting chip?\n", + __func__); } /* Add up to m_fifolen entries in each queue */ @@ -265,6 +268,9 @@ ath_edma_startrecv(struct ath_softc *sc) * These must occur after the above write so the FIFO buffers * are pushed/tracked in the same order as the hardware will * process them. + * + * XXX TODO: is this really necessary? We should've stopped + * the hardware already and reinitialised it, so it's a no-op. */ ath_edma_rxfifo_alloc(sc, HAL_RX_QUEUE_HP, sc->sc_rxedma[HAL_RX_QUEUE_HP].m_fifolen); @@ -275,6 +281,11 @@ ath_edma_startrecv(struct ath_softc *sc) ath_mode_init(sc); ath_hal_startpcurecv(ah); + /* + * We're now doing RX DMA! + */ + sc->sc_rx_stopped = 0; + ATH_RX_UNLOCK(sc); return (0); @@ -285,7 +296,16 @@ ath_edma_recv_sched_queue(struct ath_softc *sc, HAL_RX_QUEUE qtype, int dosched) { + ATH_LOCK(sc); + ath_power_set_power_state(sc, HAL_PM_AWAKE); + ATH_UNLOCK(sc); + ath_edma_recv_proc_queue(sc, qtype, dosched); + + ATH_LOCK(sc); + ath_power_restore_power_state(sc); + ATH_UNLOCK(sc); + taskqueue_enqueue(sc->sc_tq, &sc->sc_rxtask); } @@ -293,8 +313,17 @@ static void ath_edma_recv_sched(struct ath_softc *sc, int dosched) { + ATH_LOCK(sc); + ath_power_set_power_state(sc, HAL_PM_AWAKE); + ATH_UNLOCK(sc); + ath_edma_recv_proc_queue(sc, HAL_RX_QUEUE_HP, dosched); ath_edma_recv_proc_queue(sc, HAL_RX_QUEUE_LP, dosched); + + ATH_LOCK(sc); + ath_power_restore_power_state(sc); + ATH_UNLOCK(sc); + taskqueue_enqueue(sc->sc_tq, &sc->sc_rxtask); } @@ -308,6 +337,10 @@ ath_edma_recv_flush(struct ath_softc *sc) sc->sc_rxproc_cnt++; ATH_PCU_UNLOCK(sc); + ATH_LOCK(sc); + ath_power_set_power_state(sc, HAL_PM_AWAKE); + ATH_UNLOCK(sc); + /* * Flush any active frames from FIFO -> deferred list */ @@ -317,9 +350,18 @@ ath_edma_recv_flush(struct ath_softc *sc) /* * Process what's in the deferred queue */ + /* + * XXX: If we read the tsf/channoise here and then pass it in, + * we could restore the power state before processing + * the deferred queue. + */ ath_edma_recv_proc_deferred_queue(sc, HAL_RX_QUEUE_HP, 0); ath_edma_recv_proc_deferred_queue(sc, HAL_RX_QUEUE_LP, 0); + ATH_LOCK(sc); + ath_power_restore_power_state(sc); + ATH_UNLOCK(sc); + ATH_PCU_LOCK(sc); sc->sc_rxproc_cnt--; ATH_PCU_UNLOCK(sc); @@ -348,6 +390,21 @@ ath_edma_recv_proc_queue(struct ath_softc *sc, HAL_RX_QUEUE qtype, ATH_RX_LOCK(sc); +#if 1 + if (sc->sc_rx_resetted == 1) { + /* + * XXX We shouldn't ever be scheduled if + * receive has been stopped - so complain + * loudly! + */ + device_printf(sc->sc_dev, + "%s: sc_rx_resetted=1! Bad!\n", + __func__); + ATH_RX_UNLOCK(sc); + return; + } +#endif + do { bf = re->m_fifo[re->m_fifo_head]; /* This shouldn't occur! */ @@ -419,24 +476,6 @@ ath_edma_recv_proc_queue(struct ath_softc *sc, HAL_RX_QUEUE qtype, "ath edma rx proc: npkts=%d\n", npkts); - /* Handle resched and kickpcu appropriately */ - ATH_PCU_LOCK(sc); - if (dosched && sc->sc_kickpcu) { - ATH_KTR(sc, ATH_KTR_ERROR, 0, - "ath_edma_recv_proc_queue(): kickpcu"); - if (npkts > 0) - device_printf(sc->sc_dev, - "%s: handled npkts %d\n", - __func__, npkts); - - /* - * XXX TODO: what should occur here? Just re-poke and - * re-enable the RX FIFO? - */ - sc->sc_kickpcu = 0; - } - ATH_PCU_UNLOCK(sc); - return; } @@ -449,18 +488,20 @@ ath_edma_recv_proc_queue(struct ath_softc *sc, HAL_RX_QUEUE qtype, static void ath_edma_flush_deferred_queue(struct ath_softc *sc) { - struct ath_buf *bf, *next; + struct ath_buf *bf; ATH_RX_LOCK_ASSERT(sc); /* Free in one set, inside the lock */ - TAILQ_FOREACH_SAFE(bf, - &sc->sc_rx_rxlist[HAL_RX_QUEUE_LP], bf_list, next) { + while (! TAILQ_EMPTY(&sc->sc_rx_rxlist[HAL_RX_QUEUE_LP])) { + bf = TAILQ_FIRST(&sc->sc_rx_rxlist[HAL_RX_QUEUE_LP]); + TAILQ_REMOVE(&sc->sc_rx_rxlist[HAL_RX_QUEUE_LP], bf, bf_list); /* Free the buffer/mbuf */ ath_edma_rxbuf_free(sc, bf); } - TAILQ_FOREACH_SAFE(bf, - &sc->sc_rx_rxlist[HAL_RX_QUEUE_HP], bf_list, next) { + while (! TAILQ_EMPTY(&sc->sc_rx_rxlist[HAL_RX_QUEUE_HP])) { + bf = TAILQ_FIRST(&sc->sc_rx_rxlist[HAL_RX_QUEUE_HP]); + TAILQ_REMOVE(&sc->sc_rx_rxlist[HAL_RX_QUEUE_HP], bf, bf_list); /* Free the buffer/mbuf */ ath_edma_rxbuf_free(sc, bf); } @@ -494,6 +535,10 @@ ath_edma_recv_proc_deferred_queue(struct ath_softc *sc, HAL_RX_QUEUE qtype, ATH_RX_UNLOCK(sc); /* Handle the completed descriptors */ + /* + * XXX is this SAFE call needed? The ath_buf entries + * aren't modified by ath_rx_pkt, right? + */ TAILQ_FOREACH_SAFE(bf, &rxlist, bf_list, next) { /* * Skip the RX descriptor status - start at the data offset @@ -519,7 +564,9 @@ ath_edma_recv_proc_deferred_queue(struct ath_softc *sc, HAL_RX_QUEUE qtype, /* Free in one set, inside the lock */ ATH_RX_LOCK(sc); - TAILQ_FOREACH_SAFE(bf, &rxlist, bf_list, next) { + while (! TAILQ_EMPTY(&rxlist)) { + bf = TAILQ_FIRST(&rxlist); + TAILQ_REMOVE(&rxlist, bf, bf_list); /* Free the buffer/mbuf */ ath_edma_rxbuf_free(sc, bf); } @@ -551,12 +598,25 @@ ath_edma_recv_tasklet(void *arg, int npending) sc->sc_rxproc_cnt++; ATH_PCU_UNLOCK(sc); + ATH_LOCK(sc); + ath_power_set_power_state(sc, HAL_PM_AWAKE); + ATH_UNLOCK(sc); + ath_edma_recv_proc_queue(sc, HAL_RX_QUEUE_HP, 1); ath_edma_recv_proc_queue(sc, HAL_RX_QUEUE_LP, 1); ath_edma_recv_proc_deferred_queue(sc, HAL_RX_QUEUE_HP, 1); ath_edma_recv_proc_deferred_queue(sc, HAL_RX_QUEUE_LP, 1); + /* + * XXX: If we read the tsf/channoise here and then pass it in, + * we could restore the power state before processing + * the deferred queue. + */ + ATH_LOCK(sc); + ath_power_restore_power_state(sc); + ATH_UNLOCK(sc); + /* XXX inside IF_LOCK ? */ if ((ifp->if_drv_flags & IFF_DRV_OACTIVE) == 0) { #ifdef IEEE80211_SUPPORT_SUPERG @@ -835,10 +895,13 @@ ath_edma_setup_rxfifo(struct ath_softc *sc, HAL_RX_QUEUE qtype) qtype); return (-EINVAL); } - device_printf(sc->sc_dev, "%s: type=%d, FIFO depth = %d entries\n", - __func__, - qtype, - re->m_fifolen); + + if (bootverbose) + device_printf(sc->sc_dev, + "%s: type=%d, FIFO depth = %d entries\n", + __func__, + qtype, + re->m_fifolen); /* Allocate ath_buf FIFO array, pre-zero'ed */ re->m_fifo = malloc(sizeof(struct ath_buf *) * re->m_fifolen, @@ -929,10 +992,12 @@ ath_recv_setup_edma(struct ath_softc *sc) (void) ath_hal_setrxbufsize(sc->sc_ah, sc->sc_edma_bufsize - sc->sc_rx_statuslen); - device_printf(sc->sc_dev, "RX status length: %d\n", - sc->sc_rx_statuslen); - device_printf(sc->sc_dev, "RX buffer size: %d\n", - sc->sc_edma_bufsize); + if (bootverbose) { + device_printf(sc->sc_dev, "RX status length: %d\n", + sc->sc_rx_statuslen); + device_printf(sc->sc_dev, "RX buffer size: %d\n", + sc->sc_edma_bufsize); + } sc->sc_rx.recv_stop = ath_edma_stoprecv; sc->sc_rx.recv_start = ath_edma_startrecv; diff --git a/sys/dev/ath/if_ath_rx_edma.h b/sys/dev/ath/if_ath_rx_edma.h index e786daa..6635abc 100644 --- a/sys/dev/ath/if_ath_rx_edma.h +++ b/sys/dev/ath/if_ath_rx_edma.h @@ -26,7 +26,7 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGES. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/if_ath_rx_edma.h 238055 2012-07-03 06:59:12Z adrian $ */ #ifndef __IF_ATH_RX_EDMA_H__ #define __IF_ATH_RX_EDMA_H__ diff --git a/sys/dev/ath/if_ath_spectral.c b/sys/dev/ath/if_ath_spectral.c index 5cfb1a9..2a2013f 100644 --- a/sys/dev/ath/if_ath_spectral.c +++ b/sys/dev/ath/if_ath_spectral.c @@ -26,10 +26,10 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGES. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/if_ath_spectral.c 257176 2013-10-26 17:58:36Z glebius $ */ #include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); +__FBSDID("$FreeBSD: head/sys/dev/ath/if_ath_spectral.c 257176 2013-10-26 17:58:36Z glebius $"); /* * Implement some basic spectral scan control logic. @@ -43,6 +43,7 @@ __FBSDID("$FreeBSD$"); #include <sys/sysctl.h> #include <sys/kernel.h> #include <sys/lock.h> +#include <sys/malloc.h> #include <sys/mutex.h> #include <sys/errno.h> @@ -53,6 +54,7 @@ __FBSDID("$FreeBSD$"); #include <sys/socket.h> #include <net/if.h> +#include <net/if_var.h> #include <net/if_media.h> #include <net/if_arp.h> #include <net/ethernet.h> /* XXX for ether_sprintf */ diff --git a/sys/dev/ath/if_ath_spectral.h b/sys/dev/ath/if_ath_spectral.h index 3e069db..4d21395 100644 --- a/sys/dev/ath/if_ath_spectral.h +++ b/sys/dev/ath/if_ath_spectral.h @@ -26,7 +26,7 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGES. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/if_ath_spectral.h 244951 2013-01-02 03:59:02Z adrian $ */ #ifndef __IF_ATH_SPECTRAL_H__ #define __IF_ATH_SPECTRAL_H__ diff --git a/sys/dev/ath/if_ath_sysctl.c b/sys/dev/ath/if_ath_sysctl.c index 0a5719a..15593ca 100644 --- a/sys/dev/ath/if_ath_sysctl.c +++ b/sys/dev/ath/if_ath_sysctl.c @@ -28,7 +28,7 @@ */ #include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); +__FBSDID("$FreeBSD: head/sys/dev/ath/if_ath_sysctl.c 276150 2014-12-23 18:48:45Z adrian $"); /* * Driver for the Atheros Wireless LAN controller. @@ -62,6 +62,7 @@ __FBSDID("$FreeBSD$"); #include <machine/bus.h> #include <net/if.h> +#include <net/if_var.h> #include <net/if_dl.h> #include <net/if_media.h> #include <net/if_types.h> @@ -107,13 +108,26 @@ static int ath_sysctl_slottime(SYSCTL_HANDLER_ARGS) { struct ath_softc *sc = arg1; - u_int slottime = ath_hal_getslottime(sc->sc_ah); + u_int slottime; int error; + ATH_LOCK(sc); + ath_power_set_power_state(sc, HAL_PM_AWAKE); + slottime = ath_hal_getslottime(sc->sc_ah); + ATH_UNLOCK(sc); + error = sysctl_handle_int(oidp, &slottime, 0, req); if (error || !req->newptr) - return error; - return !ath_hal_setslottime(sc->sc_ah, slottime) ? EINVAL : 0; + goto finish; + + error = !ath_hal_setslottime(sc->sc_ah, slottime) ? EINVAL : 0; + +finish: + ATH_LOCK(sc); + ath_power_restore_power_state(sc); + ATH_UNLOCK(sc); + + return error; } static int @@ -399,12 +413,14 @@ ath_sysctl_txagg(SYSCTL_HANDLER_ARGS) ATH_RX_LOCK(sc); for (i = 0; i < 2; i++) { - printf("%d: fifolen: %d/%d; head=%d; tail=%d\n", + printf("%d: fifolen: %d/%d; head=%d; tail=%d; m_pending=%p, m_holdbf=%p\n", i, sc->sc_rxedma[i].m_fifo_depth, sc->sc_rxedma[i].m_fifolen, sc->sc_rxedma[i].m_fifo_head, - sc->sc_rxedma[i].m_fifo_tail); + sc->sc_rxedma[i].m_fifo_tail, + sc->sc_rxedma[i].m_rxpending, + sc->sc_rxedma[i].m_holdbf); } i = 0; TAILQ_FOREACH(bf, &sc->sc_rxbuf, bf_list) { @@ -430,7 +446,15 @@ ath_sysctl_rfsilent(SYSCTL_HANDLER_ARGS) return error; if (!ath_hal_setrfsilent(sc->sc_ah, rfsilent)) return EINVAL; - sc->sc_rfsilentpin = rfsilent & 0x1c; + /* + * Earlier chips (< AR5212) have up to 8 GPIO + * pins exposed. + * + * AR5416 and later chips have many more GPIO + * pins (up to 16) so the mask is expanded to + * four bits. + */ + sc->sc_rfsilentpin = rfsilent & 0x3c; sc->sc_rfsilentpol = (rfsilent & 0x2) != 0; return 0; } diff --git a/sys/dev/ath/if_ath_sysctl.h b/sys/dev/ath/if_ath_sysctl.h index 1fef2be..9a53488 100644 --- a/sys/dev/ath/if_ath_sysctl.h +++ b/sys/dev/ath/if_ath_sysctl.h @@ -26,7 +26,7 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGES. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/if_ath_sysctl.h 223459 2011-06-23 02:38:36Z adrian $ */ #ifndef __IF_ATH_SYSCTL_H__ diff --git a/sys/dev/ath/if_ath_tdma.c b/sys/dev/ath/if_ath_tdma.c index c075d01..fbf936d 100644 --- a/sys/dev/ath/if_ath_tdma.c +++ b/sys/dev/ath/if_ath_tdma.c @@ -28,7 +28,7 @@ */ #include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); +__FBSDID("$FreeBSD: head/sys/dev/ath/if_ath_tdma.c 265588 2014-05-07 19:07:45Z adrian $"); /* * Driver for the Atheros Wireless LAN controller. @@ -73,6 +73,7 @@ __FBSDID("$FreeBSD$"); #include <machine/bus.h> #include <net/if.h> +#include <net/if_var.h> #include <net/if_dl.h> #include <net/if_media.h> #include <net/if_types.h> @@ -476,16 +477,19 @@ ath_tdma_update(struct ieee80211_node *ni, DPRINTF(sc, ATH_DEBUG_TDMA_TIMER, "rs->rstamp %llu rstamp %llu tsf %llu txtime %d, nextslot %llu, " "nextslottu %d, nextslottume %d\n", - (unsigned long long) rs->rs_tstamp, rstamp, tsf, txtime, - nextslot, nextslottu, TSF_TO_TU(nextslot >> 32, nextslot)); + (unsigned long long) rs->rs_tstamp, + (unsigned long long) rstamp, + (unsigned long long) tsf, txtime, + (unsigned long long) nextslot, + nextslottu, TSF_TO_TU(nextslot >> 32, nextslot)); DPRINTF(sc, ATH_DEBUG_TDMA, " beacon tstamp: %llu (0x%016llx)\n", - le64toh(ni->ni_tstamp.tsf), - le64toh(ni->ni_tstamp.tsf)); + (unsigned long long) le64toh(ni->ni_tstamp.tsf), + (unsigned long long) le64toh(ni->ni_tstamp.tsf)); DPRINTF(sc, ATH_DEBUG_TDMA_TIMER, "nexttbtt %llu (0x%08llx) tsfdelta %d avg +%d/-%d\n", - nexttbtt, + (unsigned long long) nexttbtt, (long long) nexttbtt, tsfdelta, TDMA_AVG(sc->sc_avgtsfdeltap), TDMA_AVG(sc->sc_avgtsfdeltam)); @@ -579,7 +583,7 @@ ath_tdma_update(struct ieee80211_node *ni, DPRINTF(sc, ATH_DEBUG_TDMA_TIMER, "%s: calling ath_hal_adjusttsf: TSF=%llu, tsfdelta=%d\n", __func__, - tsf, + (unsigned long long) tsf, tsfdelta); #ifdef ATH_DEBUG_ALQ diff --git a/sys/dev/ath/if_ath_tdma.h b/sys/dev/ath/if_ath_tdma.h index 1e90a5f..010ed11 100644 --- a/sys/dev/ath/if_ath_tdma.h +++ b/sys/dev/ath/if_ath_tdma.h @@ -26,7 +26,7 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGES. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/if_ath_tdma.h 235679 2012-05-20 02:49:42Z adrian $ */ #ifndef __IF_ATH_TDMA_H__ #define __IF_ATH_TDMA_H__ diff --git a/sys/dev/ath/if_ath_tsf.h b/sys/dev/ath/if_ath_tsf.h index cce089f..f6ab268 100644 --- a/sys/dev/ath/if_ath_tsf.h +++ b/sys/dev/ath/if_ath_tsf.h @@ -26,7 +26,7 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGES. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/if_ath_tsf.h 235676 2012-05-20 02:05:10Z adrian $ */ #ifndef __IF_ATH_TSF_H__ #define __IF_ATH_TSF_H__ diff --git a/sys/dev/ath/if_ath_tx.c b/sys/dev/ath/if_ath_tx.c index 8bacd92..2ae4862 100644 --- a/sys/dev/ath/if_ath_tx.c +++ b/sys/dev/ath/if_ath_tx.c @@ -29,7 +29,7 @@ */ #include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); +__FBSDID("$FreeBSD: head/sys/dev/ath/if_ath_tx.c 271823 2014-09-18 20:47:39Z glebius $"); /* * Driver for the Atheros Wireless LAN controller. @@ -59,10 +59,12 @@ __FBSDID("$FreeBSD$"); #include <sys/kthread.h> #include <sys/taskqueue.h> #include <sys/priv.h> +#include <sys/ktr.h> #include <machine/bus.h> #include <net/if.h> +#include <net/if_var.h> #include <net/if_dl.h> #include <net/if_media.h> #include <net/if_types.h> @@ -759,37 +761,21 @@ ath_tx_handoff_hw(struct ath_softc *sc, struct ath_txq *txq, ("ath_tx_handoff_hw called for mcast queue")); /* - * XXX racy, should hold the PCU lock when checking this, - * and also should ensure that the TX counter is >0! + * XXX We should instead just verify that sc_txstart_cnt + * or ath_txproc_cnt > 0. That would mean that + * the reset is going to be waiting for us to complete. */ - KASSERT((sc->sc_inreset_cnt == 0), - ("%s: TX during reset?\n", __func__)); + if (sc->sc_txproc_cnt == 0 && sc->sc_txstart_cnt == 0) { + device_printf(sc->sc_dev, + "%s: TX dispatch without holding txcount/txstart refcnt!\n", + __func__); + } -#if 0 /* - * This causes a LOR. Find out where the PCU lock is being - * held whilst the TXQ lock is grabbed - that shouldn't - * be occuring. + * XXX .. this is going to cause the hardware to get upset; + * so we really should find some way to drop or queue + * things. */ - ATH_PCU_LOCK(sc); - if (sc->sc_inreset_cnt) { - ATH_PCU_UNLOCK(sc); - DPRINTF(sc, ATH_DEBUG_RESET, - "%s: called with sc_in_reset != 0\n", - __func__); - DPRINTF(sc, ATH_DEBUG_XMIT, - "%s: queued: TXDP[%u] = %p (%p) depth %d\n", - __func__, txq->axq_qnum, - (caddr_t)bf->bf_daddr, bf->bf_desc, - txq->axq_depth); - /* XXX axq_link needs to be set and updated! */ - ATH_TXQ_INSERT_TAIL(txq, bf, bf_list); - if (bf->bf_state.bfs_aggr) - txq->axq_aggr_depth++; - return; - } - ATH_PCU_UNLOCK(sc); -#endif ATH_TXQ_LOCK(txq); @@ -1613,6 +1599,7 @@ ath_tx_normal_setup(struct ath_softc *sc, struct ieee80211_node *ni, error = ath_tx_dmasetup(sc, bf, m0); if (error != 0) return error; + KASSERT((ni != NULL), ("%s: ni=NULL!", __func__)); bf->bf_node = ni; /* NB: held reference */ m0 = bf->bf_m; /* NB: may have changed */ wh = mtod(m0, struct ieee80211_frame *); @@ -2104,6 +2091,7 @@ ath_tx_raw_start(struct ath_softc *sc, struct ieee80211_node *ni, int do_override; uint8_t type, subtype; int queue_to_head; + struct ath_node *an = ATH_NODE(ni); ATH_TX_LOCK_ASSERT(sc); @@ -2163,6 +2151,7 @@ ath_tx_raw_start(struct ath_softc *sc, struct ieee80211_node *ni, return error; m0 = bf->bf_m; /* NB: may have changed */ wh = mtod(m0, struct ieee80211_frame *); + KASSERT((ni != NULL), ("%s: ni=NULL!", __func__)); bf->bf_node = ni; /* NB: held reference */ /* Always enable CLRDMASK for raw frames for now.. */ @@ -2181,12 +2170,24 @@ ath_tx_raw_start(struct ath_softc *sc, struct ieee80211_node *ni, rt = sc->sc_currates; KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode)); + + /* Fetch first rate information */ rix = ath_tx_findrix(sc, params->ibp_rate0); + try0 = params->ibp_try0; + + /* + * Override EAPOL rate as appropriate. + */ + if (m0->m_flags & M_EAPOL) { + /* XXX? maybe always use long preamble? */ + rix = an->an_mgmtrix; + try0 = ATH_TXMAXTRY; /* XXX?too many? */ + } + txrate = rt->info[rix].rateCode; if (params->ibp_flags & IEEE80211_BPF_SHORTPRE) txrate |= rt->info[rix].shortPreamble; sc->sc_txrix = rix; - try0 = params->ibp_try0; ismrr = (params->ibp_try1 != 0); txantenna = params->ibp_pri >> 2; if (txantenna == 0) /* XXX? */ @@ -2259,8 +2260,7 @@ ath_tx_raw_start(struct ath_softc *sc, struct ieee80211_node *ni, /* Blank the legacy rate array */ bzero(&bf->bf_state.bfs_rc, sizeof(bf->bf_state.bfs_rc)); - bf->bf_state.bfs_rc[0].rix = - ath_tx_findrix(sc, params->ibp_rate0); + bf->bf_state.bfs_rc[0].rix = rix; bf->bf_state.bfs_rc[0].tries = try0; bf->bf_state.bfs_rc[0].ratecode = txrate; @@ -2352,11 +2352,16 @@ ath_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, "%s: sc_inreset_cnt > 0; bailing\n", __func__); error = EIO; ATH_PCU_UNLOCK(sc); - goto bad0; + goto badbad; } sc->sc_txstart_cnt++; ATH_PCU_UNLOCK(sc); + /* Wake the hardware up already */ + ATH_LOCK(sc); + ath_power_set_power_state(sc, HAL_PM_AWAKE); + ATH_UNLOCK(sc); + ATH_TX_LOCK(sc); if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || sc->sc_invalid) { @@ -2435,7 +2440,14 @@ ath_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, sc->sc_txstart_cnt--; ATH_PCU_UNLOCK(sc); + + /* Put the hardware back to sleep if required */ + ATH_LOCK(sc); + ath_power_restore_power_state(sc); + ATH_UNLOCK(sc); + return 0; + bad2: ATH_KTR(sc, ATH_KTR_TX, 3, "ath_raw_xmit: bad2: m=%p, params=%p, " "bf=%p", @@ -2445,14 +2457,20 @@ bad2: ATH_TXBUF_LOCK(sc); ath_returnbuf_head(sc, bf); ATH_TXBUF_UNLOCK(sc); -bad: +bad: ATH_TX_UNLOCK(sc); ATH_PCU_LOCK(sc); sc->sc_txstart_cnt--; ATH_PCU_UNLOCK(sc); -bad0: + + /* Put the hardware back to sleep if required */ + ATH_LOCK(sc); + ath_power_restore_power_state(sc); + ATH_UNLOCK(sc); + +badbad: ATH_KTR(sc, ATH_KTR_TX, 2, "ath_raw_xmit: bad0: m=%p, params=%p", m, params); ifp->if_oerrors++; @@ -2748,8 +2766,8 @@ ath_tx_update_baw(struct ath_softc *sc, struct ath_node *an, INCR(tid->baw_head, ATH_TID_MAX_BUFS); } DPRINTF(sc, ATH_DEBUG_SW_TX_BAW, - "%s: baw is now %d:%d, baw head=%d\n", - __func__, tap->txa_start, tap->txa_wnd, tid->baw_head); + "%s: tid=%d: baw is now %d:%d, baw head=%d\n", + __func__, tid->tid, tap->txa_start, tap->txa_wnd, tid->baw_head); } static void @@ -3242,8 +3260,11 @@ ath_tx_tid_pause(struct ath_softc *sc, struct ath_tid *tid) ATH_TX_LOCK_ASSERT(sc); tid->paused++; - DPRINTF(sc, ATH_DEBUG_SW_TX_CTRL, "%s: paused = %d\n", - __func__, tid->paused); + DPRINTF(sc, ATH_DEBUG_SW_TX_CTRL, "%s: [%6D]: tid=%d, paused = %d\n", + __func__, + tid->an->an_node.ni_macaddr, ":", + tid->tid, + tid->paused); } /* @@ -3260,15 +3281,21 @@ ath_tx_tid_resume(struct ath_softc *sc, struct ath_tid *tid) * until it's actually resolved. */ if (tid->paused == 0) { - DPRINTF(sc, ATH_DEBUG_SW_TX_CTRL, - "%s: %6D: paused=0?\n", __func__, - tid->an->an_node.ni_macaddr, ":"); + device_printf(sc->sc_dev, + "%s: [%6D]: tid=%d, paused=0?\n", + __func__, + tid->an->an_node.ni_macaddr, ":", + tid->tid); } else { tid->paused--; } - DPRINTF(sc, ATH_DEBUG_SW_TX_CTRL, "%s: unpaused = %d\n", - __func__, tid->paused); + DPRINTF(sc, ATH_DEBUG_SW_TX_CTRL, + "%s: [%6D]: tid=%d, unpaused = %d\n", + __func__, + tid->an->an_node.ni_macaddr, ":", + tid->tid, + tid->paused); if (tid->paused) return; @@ -3334,8 +3361,8 @@ ath_tx_tid_filt_comp_buf(struct ath_softc *sc, struct ath_tid *tid, ATH_TX_LOCK_ASSERT(sc); if (! tid->isfiltered) { - DPRINTF(sc, ATH_DEBUG_SW_TX_FILT, "%s: filter transition\n", - __func__); + DPRINTF(sc, ATH_DEBUG_SW_TX_FILT, "%s: tid=%d; filter transition\n", + __func__, tid->tid); tid->isfiltered = 1; ath_tx_tid_pause(sc, tid); } @@ -3355,15 +3382,20 @@ static void ath_tx_tid_filt_comp_complete(struct ath_softc *sc, struct ath_tid *tid) { struct ath_buf *bf; + int do_resume = 0; ATH_TX_LOCK_ASSERT(sc); if (tid->hwq_depth != 0) return; - DPRINTF(sc, ATH_DEBUG_SW_TX_FILT, "%s: hwq=0, transition back\n", - __func__); - tid->isfiltered = 0; + DPRINTF(sc, ATH_DEBUG_SW_TX_FILT, "%s: tid=%d, hwq=0, transition back\n", + __func__, tid->tid); + if (tid->isfiltered == 1) { + tid->isfiltered = 0; + do_resume = 1; + } + /* XXX ath_tx_tid_resume() also calls ath_tx_set_clrdmask()! */ ath_tx_set_clrdmask(sc, tid->an); @@ -3373,16 +3405,21 @@ ath_tx_tid_filt_comp_complete(struct ath_softc *sc, struct ath_tid *tid) ATH_TID_INSERT_HEAD(tid, bf, bf_list); } - ath_tx_tid_resume(sc, tid); + /* And only resume if we had paused before */ + if (do_resume) + ath_tx_tid_resume(sc, tid); } /* * Called when a single (aggregate or otherwise) frame is completed. * - * Returns 1 if the buffer could be added to the filtered list - * (cloned or otherwise), 0 if the buffer couldn't be added to the + * Returns 0 if the buffer could be added to the filtered list + * (cloned or otherwise), 1 if the buffer couldn't be added to the * filtered list (failed clone; expired retry) and the caller should * free it and handle it like a failure (eg by sending a BAR.) + * + * since the buffer may be cloned, bf must be not touched after this + * if the return value is 0. */ static int ath_tx_tid_filt_comp_single(struct ath_softc *sc, struct ath_tid *tid, @@ -3402,8 +3439,9 @@ ath_tx_tid_filt_comp_single(struct ath_softc *sc, struct ath_tid *tid, "%s: bf=%p, seqno=%d, exceeded retries\n", __func__, bf, - bf->bf_state.bfs_seqno); - return (0); + SEQNO(bf->bf_state.bfs_seqno)); + retval = 1; /* error */ + goto finish; } /* @@ -3423,11 +3461,12 @@ ath_tx_tid_filt_comp_single(struct ath_softc *sc, struct ath_tid *tid, DPRINTF(sc, ATH_DEBUG_SW_TX_FILT, "%s: busy buffer couldn't be cloned (%p)!\n", __func__, bf); - retval = 1; + retval = 1; /* error */ } else { ath_tx_tid_filt_comp_buf(sc, tid, nbf); - retval = 0; + retval = 0; /* ok */ } +finish: ath_tx_tid_filt_comp_complete(sc, tid); return (retval); @@ -3452,10 +3491,11 @@ ath_tx_tid_filt_comp_aggr(struct ath_softc *sc, struct ath_tid *tid, if (bf->bf_state.bfs_retries > SWMAX_RETRIES) { sc->sc_stats.ast_tx_swretrymax++; DPRINTF(sc, ATH_DEBUG_SW_TX_FILT, - "%s: bf=%p, seqno=%d, exceeded retries\n", + "%s: tid=%d, bf=%p, seqno=%d, exceeded retries\n", __func__, + tid->tid, bf, - bf->bf_state.bfs_seqno); + SEQNO(bf->bf_state.bfs_seqno)); TAILQ_INSERT_TAIL(bf_q, bf, bf_list); goto next; } @@ -3463,8 +3503,8 @@ ath_tx_tid_filt_comp_aggr(struct ath_softc *sc, struct ath_tid *tid, if (bf->bf_flags & ATH_BUF_BUSY) { nbf = ath_tx_retry_clone(sc, tid->an, tid, bf); DPRINTF(sc, ATH_DEBUG_SW_TX_FILT, - "%s: busy buffer cloned: %p -> %p", - __func__, bf, nbf); + "%s: tid=%d, busy buffer cloned: %p -> %p, seqno=%d\n", + __func__, tid->tid, bf, nbf, SEQNO(bf->bf_state.bfs_seqno)); } else { nbf = bf; } @@ -3475,8 +3515,8 @@ ath_tx_tid_filt_comp_aggr(struct ath_softc *sc, struct ath_tid *tid, */ if (nbf == NULL) { DPRINTF(sc, ATH_DEBUG_SW_TX_FILT, - "%s: buffer couldn't be cloned! (%p)\n", - __func__, bf); + "%s: tid=%d, buffer couldn't be cloned! (%p) seqno=%d\n", + __func__, tid->tid, bf, SEQNO(bf->bf_state.bfs_seqno)); TAILQ_INSERT_TAIL(bf_q, bf, bf_list); } else { ath_tx_tid_filt_comp_buf(sc, tid, nbf); @@ -3717,7 +3757,7 @@ ath_tx_tid_drain_print(struct ath_softc *sc, struct ath_node *an, txq = sc->sc_ac2q[tid->ac]; tap = ath_tx_get_tx_tid(an, tid->tid); - DPRINTF(sc, ATH_DEBUG_SW_TX, + DPRINTF(sc, ATH_DEBUG_SW_TX | ATH_DEBUG_RESET, "%s: %s: %6D: bf=%p: addbaw=%d, dobaw=%d, " "seqno=%d, retry=%d\n", __func__, @@ -3729,7 +3769,7 @@ ath_tx_tid_drain_print(struct ath_softc *sc, struct ath_node *an, bf->bf_state.bfs_dobaw, SEQNO(bf->bf_state.bfs_seqno), bf->bf_state.bfs_retries); - DPRINTF(sc, ATH_DEBUG_SW_TX, + DPRINTF(sc, ATH_DEBUG_SW_TX | ATH_DEBUG_RESET, "%s: %s: %6D: bf=%p: txq[%d] axq_depth=%d, axq_aggr_depth=%d\n", __func__, pfx, @@ -3739,7 +3779,7 @@ ath_tx_tid_drain_print(struct ath_softc *sc, struct ath_node *an, txq->axq_qnum, txq->axq_depth, txq->axq_aggr_depth); - DPRINTF(sc, ATH_DEBUG_SW_TX, + DPRINTF(sc, ATH_DEBUG_SW_TX | ATH_DEBUG_RESET, "%s: %s: %6D: bf=%p: tid txq_depth=%d hwq_depth=%d, bar_wait=%d, " "isfiltered=%d\n", __func__, @@ -3751,7 +3791,7 @@ ath_tx_tid_drain_print(struct ath_softc *sc, struct ath_node *an, tid->hwq_depth, tid->bar_wait, tid->isfiltered); - DPRINTF(sc, ATH_DEBUG_SW_TX, + DPRINTF(sc, ATH_DEBUG_SW_TX | ATH_DEBUG_RESET, "%s: %s: %6D: tid %d: " "sched=%d, paused=%d, " "incomp=%d, baw_head=%d, " @@ -3811,7 +3851,7 @@ ath_tx_tid_drain(struct ath_softc *sc, struct ath_node *an, if (t == 0) { ath_tx_tid_drain_print(sc, an, "norm", tid, bf); - t = 1; +// t = 1; } ATH_TID_REMOVE(tid, bf, bf_list); @@ -3827,7 +3867,7 @@ ath_tx_tid_drain(struct ath_softc *sc, struct ath_node *an, if (t == 0) { ath_tx_tid_drain_print(sc, an, "filt", tid, bf); - t = 1; +// t = 1; } ATH_TID_FILT_REMOVE(tid, bf, bf_list); @@ -4084,6 +4124,19 @@ ath_tx_normal_comp(struct ath_softc *sc, struct ath_buf *bf, int fail) DPRINTF(sc, ATH_DEBUG_SW_TX, "%s: hwq_depth < 0: %d\n", __func__, atid->hwq_depth); + /* If the TID is being cleaned up, track things */ + /* XXX refactor! */ + if (atid->cleanup_inprogress) { + atid->incomp--; + if (atid->incomp == 0) { + DPRINTF(sc, ATH_DEBUG_SW_TX_CTRL, + "%s: TID %d: cleaned up! resume!\n", + __func__, tid); + atid->cleanup_inprogress = 0; + ath_tx_tid_resume(sc, atid); + } + } + /* * If the queue is filtered, potentially mark it as complete * and reschedule it as needed. @@ -4131,6 +4184,16 @@ ath_tx_comp_cleanup_unaggr(struct ath_softc *sc, struct ath_buf *bf) ATH_TX_LOCK(sc); atid->incomp--; + + /* XXX refactor! */ + if (bf->bf_state.bfs_dobaw) { + ath_tx_update_baw(sc, an, atid, bf); + if (!bf->bf_state.bfs_addedbaw) + DPRINTF(sc, ATH_DEBUG_SW_TX, + "%s: wasn't added: seqno %d\n", + __func__, SEQNO(bf->bf_state.bfs_seqno)); + } + if (atid->incomp == 0) { DPRINTF(sc, ATH_DEBUG_SW_TX_CTRL, "%s: TID %d: cleaned up! resume!\n", @@ -4143,14 +4206,72 @@ ath_tx_comp_cleanup_unaggr(struct ath_softc *sc, struct ath_buf *bf) ath_tx_default_comp(sc, bf, 0); } + +/* + * This as it currently stands is a bit dumb. Ideally we'd just + * fail the frame the normal way and have it permanently fail + * via the normal aggregate completion path. + */ +static void +ath_tx_tid_cleanup_frame(struct ath_softc *sc, struct ath_node *an, + int tid, struct ath_buf *bf_head, ath_bufhead *bf_cq) +{ + struct ath_tid *atid = &an->an_tid[tid]; + struct ath_buf *bf, *bf_next; + + ATH_TX_LOCK_ASSERT(sc); + + /* + * Remove this frame from the queue. + */ + ATH_TID_REMOVE(atid, bf_head, bf_list); + + /* + * Loop over all the frames in the aggregate. + */ + bf = bf_head; + while (bf != NULL) { + bf_next = bf->bf_next; /* next aggregate frame, or NULL */ + + /* + * If it's been added to the BAW we need to kick + * it out of the BAW before we continue. + * + * XXX if it's an aggregate, assert that it's in the + * BAW - we shouldn't have it be in an aggregate + * otherwise! + */ + if (bf->bf_state.bfs_addedbaw) { + ath_tx_update_baw(sc, an, atid, bf); + bf->bf_state.bfs_dobaw = 0; + } + + /* + * Give it the default completion handler. + */ + bf->bf_comp = ath_tx_normal_comp; + bf->bf_next = NULL; + + /* + * Add it to the list to free. + */ + TAILQ_INSERT_TAIL(bf_cq, bf, bf_list); + + /* + * Now advance to the next frame in the aggregate. + */ + bf = bf_next; + } +} + /* * Performs transmit side cleanup when TID changes from aggregated to - * unaggregated. + * unaggregated and during reassociation. * - * - Discard all retry frames from the s/w queue. - * - Fix the tx completion function for all buffers in s/w queue. - * - Count the number of unacked frames, and let transmit completion - * handle it later. + * For now, this just tosses everything from the TID software queue + * whether or not it has been retried and marks the TID as + * pending completion if there's anything for this TID queued to + * the hardware. * * The caller is responsible for pausing the TID and unpausing the * TID if no cleanup was required. Otherwise the cleanup path will @@ -4161,18 +4282,19 @@ ath_tx_tid_cleanup(struct ath_softc *sc, struct ath_node *an, int tid, ath_bufhead *bf_cq) { struct ath_tid *atid = &an->an_tid[tid]; - struct ieee80211_tx_ampdu *tap; struct ath_buf *bf, *bf_next; ATH_TX_LOCK_ASSERT(sc); DPRINTF(sc, ATH_DEBUG_SW_TX_BAW, - "%s: TID %d: called\n", __func__, tid); + "%s: TID %d: called; inprogress=%d\n", __func__, tid, + atid->cleanup_inprogress); /* * Move the filtered frames to the TX queue, before * we run off and discard/process things. */ + /* XXX this is really quite inefficient */ while ((bf = ATH_TID_FILT_LAST(atid, ath_bufhead_s)) != NULL) { ATH_TID_FILT_REMOVE(atid, bf, bf_list); @@ -4187,47 +4309,35 @@ ath_tx_tid_cleanup(struct ath_softc *sc, struct ath_node *an, int tid, */ bf = ATH_TID_FIRST(atid); while (bf) { - if (bf->bf_state.bfs_isretried) { - bf_next = TAILQ_NEXT(bf, bf_list); - ATH_TID_REMOVE(atid, bf, bf_list); - if (bf->bf_state.bfs_dobaw) { - ath_tx_update_baw(sc, an, atid, bf); - if (!bf->bf_state.bfs_addedbaw) - DPRINTF(sc, ATH_DEBUG_SW_TX_BAW, - "%s: wasn't added: seqno %d\n", - __func__, - SEQNO(bf->bf_state.bfs_seqno)); - } - bf->bf_state.bfs_dobaw = 0; - /* - * Call the default completion handler with "fail" just - * so upper levels are suitably notified about this. - */ - TAILQ_INSERT_TAIL(bf_cq, bf, bf_list); - bf = bf_next; - continue; - } - /* Give these the default completion handler */ - bf->bf_comp = ath_tx_normal_comp; - bf = TAILQ_NEXT(bf, bf_list); + /* + * Grab the next frame in the list, we may + * be fiddling with the list. + */ + bf_next = TAILQ_NEXT(bf, bf_list); + + /* + * Free the frame and all subframes. + */ + ath_tx_tid_cleanup_frame(sc, an, tid, bf, bf_cq); + + /* + * Next frame! + */ + bf = bf_next; } /* - * Calculate what hardware-queued frames exist based - * on the current BAW size. Ie, what frames have been - * added to the TX hardware queue for this TID but - * not yet ACKed. + * If there's anything in the hardware queue we wait + * for the TID HWQ to empty. */ - tap = ath_tx_get_tx_tid(an, tid); - /* Need the lock - fiddling with BAW */ - while (atid->baw_head != atid->baw_tail) { - if (atid->tx_buf[atid->baw_head]) { - atid->incomp++; - atid->cleanup_inprogress = 1; - atid->tx_buf[atid->baw_head] = NULL; - } - INCR(atid->baw_head, ATH_TID_MAX_BUFS); - INCR(tap->txa_start, IEEE80211_SEQ_RANGE); + if (atid->hwq_depth > 0) { + /* + * XXX how about we kill atid->incomp, and instead + * replace it with a macro that checks that atid->hwq_depth + * is 0? + */ + atid->incomp = atid->hwq_depth; + atid->cleanup_inprogress = 1; } if (atid->cleanup_inprogress) @@ -4560,9 +4670,19 @@ ath_tx_comp_cleanup_aggr(struct ath_softc *sc, struct ath_buf *bf_first) ATH_TX_LOCK(sc); /* update incomp */ + atid->incomp--; + + /* Update the BAW */ bf = bf_first; while (bf) { - atid->incomp--; + /* XXX refactor! */ + if (bf->bf_state.bfs_dobaw) { + ath_tx_update_baw(sc, an, atid, bf); + if (!bf->bf_state.bfs_addedbaw) + DPRINTF(sc, ATH_DEBUG_SW_TX, + "%s: wasn't added: seqno %d\n", + __func__, SEQNO(bf->bf_state.bfs_seqno)); + } bf = bf->bf_next; } @@ -4585,10 +4705,11 @@ ath_tx_comp_cleanup_aggr(struct ath_softc *sc, struct ath_buf *bf_first) ATH_TX_UNLOCK(sc); - /* Handle frame completion */ + /* Handle frame completion as individual frames */ bf = bf_first; while (bf) { bf_next = bf->bf_next; + bf->bf_next = NULL; ath_tx_default_comp(sc, bf, 1); bf = bf_next; } @@ -5030,6 +5151,10 @@ ath_tx_aggr_comp_unaggr(struct ath_softc *sc, struct ath_buf *bf, int fail) "%s: isfiltered=1, fail=%d\n", __func__, fail); freeframe = ath_tx_tid_filt_comp_single(sc, atid, bf); + /* + * If freeframe=0 then bf is no longer ours; don't + * touch it. + */ if (freeframe) { /* Remove from BAW */ if (bf->bf_state.bfs_addedbaw) @@ -5065,7 +5190,6 @@ ath_tx_aggr_comp_unaggr(struct ath_softc *sc, struct ath_buf *bf, int fail) if (freeframe) ath_tx_default_comp(sc, bf, fail); - return; } /* @@ -5495,7 +5619,7 @@ ath_txq_sched(struct ath_softc *sc, struct ath_txq *txq) * a frame; be careful. */ if (! ath_tx_tid_can_tx_or_sched(sc, tid)) { - continue; + goto loop_done; } if (ath_tx_ampdu_running(sc, tid->an, tid->tid)) ath_tx_tid_hw_queue_aggr(sc, tid->an, tid); @@ -5518,7 +5642,7 @@ ath_txq_sched(struct ath_softc *sc, struct ath_txq *txq) if (txq->axq_depth >= sc->sc_hwq_limit_nonaggr) { break; } - +loop_done: /* * If this was the last entry on the original list, stop. * Otherwise nodes that have been rescheduled onto the end @@ -5771,12 +5895,26 @@ ath_addba_stop(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap) */ TAILQ_INIT(&bf_cq); ATH_TX_LOCK(sc); - ath_tx_tid_cleanup(sc, an, tid, &bf_cq); + /* - * Unpause the TID if no cleanup is required. + * In case there's a followup call to this, only call it + * if we don't have a cleanup in progress. + * + * Since we've paused the queue above, we need to make + * sure we unpause if there's already a cleanup in + * progress - it means something else is also doing + * this stuff, so we don't need to also keep it paused. */ - if (! atid->cleanup_inprogress) + if (atid->cleanup_inprogress) { ath_tx_tid_resume(sc, atid); + } else { + ath_tx_tid_cleanup(sc, an, tid, &bf_cq); + /* + * Unpause the TID if no cleanup is required. + */ + if (! atid->cleanup_inprogress) + ath_tx_tid_resume(sc, atid); + } ATH_TX_UNLOCK(sc); /* Handle completing frames and fail them */ @@ -5810,19 +5948,25 @@ ath_tx_node_reassoc(struct ath_softc *sc, struct ath_node *an) tid = &an->an_tid[i]; if (tid->hwq_depth == 0) continue; - ath_tx_tid_pause(sc, tid); DPRINTF(sc, ATH_DEBUG_NODE, "%s: %6D: TID %d: cleaning up TID\n", __func__, an->an_node.ni_macaddr, ":", i); - ath_tx_tid_cleanup(sc, an, i, &bf_cq); /* - * Unpause the TID if no cleanup is required. + * In case there's a followup call to this, only call it + * if we don't have a cleanup in progress. */ - if (! tid->cleanup_inprogress) - ath_tx_tid_resume(sc, tid); + if (! tid->cleanup_inprogress) { + ath_tx_tid_pause(sc, tid); + ath_tx_tid_cleanup(sc, an, i, &bf_cq); + /* + * Unpause the TID if no cleanup is required. + */ + if (! tid->cleanup_inprogress) + ath_tx_tid_resume(sc, tid); + } } ATH_TX_UNLOCK(sc); @@ -5852,19 +5996,43 @@ ath_bar_response(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap, struct ath_node *an = ATH_NODE(ni); struct ath_tid *atid = &an->an_tid[tid]; int attempts = tap->txa_attempts; + int old_txa_start; DPRINTF(sc, ATH_DEBUG_SW_TX_BAR, - "%s: %6D: called; txa_tid=%d, atid->tid=%d, status=%d, attempts=%d\n", + "%s: %6D: called; txa_tid=%d, atid->tid=%d, status=%d, attempts=%d, txa_start=%d, txa_seqpending=%d\n", __func__, ni->ni_macaddr, ":", tap->txa_tid, atid->tid, status, - attempts); + attempts, + tap->txa_start, + tap->txa_seqpending); /* Note: This may update the BAW details */ + /* + * XXX What if this does slide the BAW along? We need to somehow + * XXX either fix things when it does happen, or prevent the + * XXX seqpending value to be anything other than exactly what + * XXX the hell we want! + * + * XXX So for now, how I do this inside the TX lock for now + * XXX and just correct it afterwards? The below condition should + * XXX never happen and if it does I need to fix all kinds of things. + */ + ATH_TX_LOCK(sc); + old_txa_start = tap->txa_start; sc->sc_bar_response(ni, tap, status); + if (tap->txa_start != old_txa_start) { + device_printf(sc->sc_dev, "%s: tid=%d; txa_start=%d, old=%d, adjusting\n", + __func__, + tid, + tap->txa_start, + old_txa_start); + } + tap->txa_start = old_txa_start; + ATH_TX_UNLOCK(sc); /* Unpause the TID */ /* diff --git a/sys/dev/ath/if_ath_tx.h b/sys/dev/ath/if_ath_tx.h index 281dbcb..490f955 100644 --- a/sys/dev/ath/if_ath_tx.h +++ b/sys/dev/ath/if_ath_tx.h @@ -26,7 +26,7 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGES. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/if_ath_tx.h 250866 2013-05-21 18:13:57Z adrian $ */ #ifndef __IF_ATH_TX_H__ #define __IF_ATH_TX_H__ diff --git a/sys/dev/ath/if_ath_tx_edma.c b/sys/dev/ath/if_ath_tx_edma.c index 5498dd5..0b507f7 100644 --- a/sys/dev/ath/if_ath_tx_edma.c +++ b/sys/dev/ath/if_ath_tx_edma.c @@ -28,7 +28,7 @@ */ #include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); +__FBSDID("$FreeBSD: head/sys/dev/ath/if_ath_tx_edma.c 265349 2014-05-05 08:00:50Z adrian $"); /* * Driver for the Atheros Wireless LAN controller. @@ -73,6 +73,7 @@ __FBSDID("$FreeBSD$"); #include <machine/bus.h> #include <net/if.h> +#include <net/if_var.h> #include <net/if_dl.h> #include <net/if_media.h> #include <net/if_types.h> @@ -865,12 +866,14 @@ ath_xmit_setup_edma(struct ath_softc *sc) (void) ath_hal_gettxstatuslen(sc->sc_ah, &sc->sc_tx_statuslen); (void) ath_hal_getntxmaps(sc->sc_ah, &sc->sc_tx_nmaps); - device_printf(sc->sc_dev, "TX descriptor length: %d\n", - sc->sc_tx_desclen); - device_printf(sc->sc_dev, "TX status length: %d\n", - sc->sc_tx_statuslen); - device_printf(sc->sc_dev, "TX buffers per descriptor: %d\n", - sc->sc_tx_nmaps); + if (bootverbose) { + device_printf(sc->sc_dev, "TX descriptor length: %d\n", + sc->sc_tx_desclen); + device_printf(sc->sc_dev, "TX status length: %d\n", + sc->sc_tx_statuslen); + device_printf(sc->sc_dev, "TX buffers per descriptor: %d\n", + sc->sc_tx_nmaps); + } sc->sc_tx.xmit_setup = ath_edma_dma_txsetup; sc->sc_tx.xmit_teardown = ath_edma_dma_txteardown; diff --git a/sys/dev/ath/if_ath_tx_edma.h b/sys/dev/ath/if_ath_tx_edma.h index d4975a6..f2e0aed 100644 --- a/sys/dev/ath/if_ath_tx_edma.h +++ b/sys/dev/ath/if_ath_tx_edma.h @@ -26,7 +26,7 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGES. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/if_ath_tx_edma.h 238710 2012-07-23 03:52:18Z adrian $ */ #ifndef __IF_ATH_TX_EDMA_H__ #define __IF_ATH_TX_EDMA_H__ diff --git a/sys/dev/ath/if_ath_tx_ht.c b/sys/dev/ath/if_ath_tx_ht.c index 36c3dff..8b13496 100644 --- a/sys/dev/ath/if_ath_tx_ht.c +++ b/sys/dev/ath/if_ath_tx_ht.c @@ -28,7 +28,7 @@ */ #include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); +__FBSDID("$FreeBSD: head/sys/dev/ath/if_ath_tx_ht.c 250665 2013-05-15 18:33:05Z adrian $"); #include "opt_inet.h" #include "opt_ath.h" diff --git a/sys/dev/ath/if_ath_tx_ht.h b/sys/dev/ath/if_ath_tx_ht.h index 38885ef..6af7848 100644 --- a/sys/dev/ath/if_ath_tx_ht.h +++ b/sys/dev/ath/if_ath_tx_ht.h @@ -26,7 +26,7 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGES. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/if_ath_tx_ht.h 250665 2013-05-15 18:33:05Z adrian $ */ #ifndef __IF_ATH_TX_HT_H__ #define __IF_ATH_TX_HT_H__ diff --git a/sys/dev/ath/if_athdfs.h b/sys/dev/ath/if_athdfs.h index cc4db15..1dd7174 100644 --- a/sys/dev/ath/if_athdfs.h +++ b/sys/dev/ath/if_athdfs.h @@ -26,7 +26,7 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGES. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/if_athdfs.h 244946 2013-01-02 01:36:10Z adrian $ */ #ifndef __IF_ATHDFS_H__ #define __IF_ATHDFS_H__ diff --git a/sys/dev/ath/if_athioctl.h b/sys/dev/ath/if_athioctl.h index e9ce887..818838a 100644 --- a/sys/dev/ath/if_athioctl.h +++ b/sys/dev/ath/if_athioctl.h @@ -26,7 +26,7 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGES. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/if_athioctl.h 250665 2013-05-15 18:33:05Z adrian $ */ /* diff --git a/sys/dev/ath/if_athrate.h b/sys/dev/ath/if_athrate.h index a97d686..0fec625 100644 --- a/sys/dev/ath/if_athrate.h +++ b/sys/dev/ath/if_athrate.h @@ -27,7 +27,7 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGES. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/if_athrate.h 249578 2013-04-17 07:21:30Z adrian $ */ #ifndef _ATH_RATECTRL_H_ #define _ATH_RATECTRL_H_ diff --git a/sys/dev/ath/if_athvar.h b/sys/dev/ath/if_athvar.h index 6b074d6..3824948 100644 --- a/sys/dev/ath/if_athvar.h +++ b/sys/dev/ath/if_athvar.h @@ -26,7 +26,7 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGES. * - * $FreeBSD$ + * $FreeBSD: head/sys/dev/ath/if_athvar.h 272292 2014-09-30 03:19:29Z adrian $ */ /* @@ -82,6 +82,25 @@ #define ATH_BEACON_CWMAX_DEFAULT 0 /* default cwmax for ap beacon q */ /* + * The following bits can be set during the PCI (and perhaps non-PCI + * later) device probe path. + * + * It controls some of the driver and HAL behaviour. + */ + +#define ATH_PCI_CUS198 0x0001 +#define ATH_PCI_CUS230 0x0002 +#define ATH_PCI_CUS217 0x0004 +#define ATH_PCI_CUS252 0x0008 +#define ATH_PCI_WOW 0x0010 +#define ATH_PCI_BT_ANT_DIV 0x0020 +#define ATH_PCI_D3_L1_WAR 0x0040 +#define ATH_PCI_AR9565_1ANT 0x0080 +#define ATH_PCI_AR9565_2ANT 0x0100 +#define ATH_PCI_NO_PLL_PWRSAVE 0x0200 +#define ATH_PCI_KILLER 0x0400 + +/* * The key cache is used for h/w cipher state and also for * tracking station state such as the current tx antenna. * We also setup a mapping table between key cache slot indices @@ -510,6 +529,7 @@ struct ath_rx_edma { int m_fifo_tail; int m_fifo_depth; struct mbuf *m_rxpending; + struct ath_buf *m_holdbf; }; struct ath_tx_edma_fifo { @@ -565,6 +585,8 @@ struct ath_softc { int sc_tx_statuslen; int sc_tx_nmaps; /* Number of TX maps */ int sc_edma_bufsize; + int sc_rx_stopped; /* XXX only for EDMA */ + int sc_rx_resetted; /* XXX only for EDMA */ void (*sc_node_cleanup)(struct ieee80211_node *); void (*sc_node_free)(struct ieee80211_node *); @@ -621,7 +643,8 @@ struct ath_softc { sc_resetcal : 1,/* reset cal state next trip */ sc_rxslink : 1,/* do self-linked final descriptor */ sc_rxtsf32 : 1,/* RX dec TSF is 32 bits */ - sc_isedma : 1;/* supports EDMA */ + sc_isedma : 1,/* supports EDMA */ + sc_do_mybeacon : 1; /* supports mybeacon */ /* * Second set of flags. @@ -864,6 +887,25 @@ struct ath_softc { void (*sc_bar_response)(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap, int status); + + /* + * Powersave state tracking. + * + * target/cur powerstate is the chip power state. + * target selfgen state is the self-generated frames + * state. The chip can be awake but transmitted frames + * can have the PWRMGT bit set to 1 so the destination + * thinks the node is asleep. + */ + HAL_POWER_MODE sc_target_powerstate; + HAL_POWER_MODE sc_target_selfgen_state; + + HAL_POWER_MODE sc_cur_powerstate; + + int sc_powersave_refcnt; + + /* ATH_PCI_* flags */ + uint32_t sc_pci_devinfo; }; #define ATH_LOCK_INIT(_sc) \ @@ -1038,6 +1080,8 @@ void ath_intr(void *); ((*(_ah)->ah_updateTxTrigLevel)((_ah), (_inc))) #define ath_hal_setpower(_ah, _mode) \ ((*(_ah)->ah_setPowerMode)((_ah), (_mode), AH_TRUE)) +#define ath_hal_setselfgenpower(_ah, _mode) \ + ((*(_ah)->ah_setPowerMode)((_ah), (_mode), AH_FALSE)) #define ath_hal_keycachesize(_ah) \ ((*(_ah)->ah_getKeyCacheSize)((_ah))) #define ath_hal_keyreset(_ah, _ix) \ @@ -1266,6 +1310,8 @@ void ath_intr(void *); #define ath_hal_setintmit(_ah, _v) \ ath_hal_setcapability(_ah, HAL_CAP_INTMIT, \ HAL_CAP_INTMIT_ENABLE, _v, NULL) +#define ath_hal_hasmybeacon(_ah) \ + (ath_hal_getcapability(_ah, HAL_CAP_DO_MYBEACON, 1, NULL) == HAL_OK) #define ath_hal_hasenforcetxop(_ah) \ (ath_hal_getcapability(_ah, HAL_CAP_ENFORCE_TXOP, 0, NULL) == HAL_OK) diff --git a/sys/dev/iwn/if_iwn.c b/sys/dev/iwn/if_iwn.c index 609a703..226fe46 100644 --- a/sys/dev/iwn/if_iwn.c +++ b/sys/dev/iwn/if_iwn.c @@ -1,11 +1,10 @@ /*- - * Copyright (c) 2013 Cedric GROSS <c.gross@kreiz-it.fr> - * Copyright (c) 2011 Intel Corporation - * Copyright (c) 2007-2009 - * Damien Bergamini <damien.bergamini@free.fr> - * Copyright (c) 2008 - * Benjamin Close <benjsc@FreeBSD.org> + * Copyright (c) 2007-2009 Damien Bergamini <damien.bergamini@free.fr> + * Copyright (c) 2008 Benjamin Close <benjsc@FreeBSD.org> * Copyright (c) 2008 Sam Leffler, Errno Consulting + * Copyright (c) 2011 Intel Corporation + * Copyright (c) 2013 Cedric GROSS <c.gross@kreiz-it.fr> + * Copyright (c) 2013 Adrian Chadd <adrian@FreeBSD.org> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -57,6 +56,7 @@ __FBSDID("$FreeBSD$"); #include <net/bpf.h> #include <net/if.h> +#include <net/if_var.h> #include <net/if_arp.h> #include <net/ethernet.h> #include <net/if_dl.h> @@ -77,6 +77,9 @@ __FBSDID("$FreeBSD$"); #include <dev/iwn/if_iwnreg.h> #include <dev/iwn/if_iwnvar.h> #include <dev/iwn/if_iwn_devid.h> +#include <dev/iwn/if_iwn_chip_cfg.h> +#include <dev/iwn/if_iwn_debug.h> +#include <dev/iwn/if_iwn_ioctl.h> struct iwn_ident { uint16_t vendor; @@ -97,12 +100,19 @@ static const struct iwn_ident iwn_ident_table[] = { { 0x8086, IWN_DID_x030_4, "Intel Centrino Advanced-N 6230" }, { 0x8086, IWN_DID_6150_1, "Intel Centrino Wireless-N + WiMAX 6150" }, { 0x8086, IWN_DID_6150_2, "Intel Centrino Wireless-N + WiMAX 6150" }, + { 0x8086, IWN_DID_2x00_1, "Intel(R) Centrino(R) Wireless-N 2200 BGN" }, + { 0x8086, IWN_DID_2x00_2, "Intel(R) Centrino(R) Wireless-N 2200 BGN" }, + /* XXX 2200D is IWN_SDID_2x00_4; there's no way to express this here! */ { 0x8086, IWN_DID_2x30_1, "Intel Centrino Wireless-N 2230" }, { 0x8086, IWN_DID_2x30_2, "Intel Centrino Wireless-N 2230" }, { 0x8086, IWN_DID_130_1, "Intel Centrino Wireless-N 130" }, { 0x8086, IWN_DID_130_2, "Intel Centrino Wireless-N 130" }, { 0x8086, IWN_DID_100_1, "Intel Centrino Wireless-N 100" }, { 0x8086, IWN_DID_100_2, "Intel Centrino Wireless-N 100" }, + { 0x8086, IWN_DID_105_1, "Intel Centrino Wireless-N 105" }, + { 0x8086, IWN_DID_105_2, "Intel Centrino Wireless-N 105" }, + { 0x8086, IWN_DID_135_1, "Intel Centrino Wireless-N 135" }, + { 0x8086, IWN_DID_135_2, "Intel Centrino Wireless-N 135" }, { 0x8086, IWN_DID_4965_1, "Intel Wireless WiFi Link 4965" }, { 0x8086, IWN_DID_6x00_1, "Intel Centrino Ultimate-N 6300" }, { 0x8086, IWN_DID_6x00_2, "Intel Centrino Advanced-N 6200" }, @@ -119,6 +129,8 @@ static const struct iwn_ident iwn_ident_table[] = { { 0x8086, IWN_DID_5x50_2, "Intel WiMAX/WiFi Link 5350" }, { 0x8086, IWN_DID_5x50_3, "Intel WiMAX/WiFi Link 5150" }, { 0x8086, IWN_DID_5x50_4, "Intel WiMAX/WiFi Link 5150" }, + { 0x8086, IWN_DID_6035_1, "Intel Centrino Advanced 6235" }, + { 0x8086, IWN_DID_6035_2, "Intel Centrino Advanced 6235" }, { 0, 0, NULL } }; @@ -126,6 +138,7 @@ static int iwn_probe(device_t); static int iwn_attach(device_t); static int iwn4965_attach(struct iwn_softc *, uint16_t); static int iwn5000_attach(struct iwn_softc *, uint16_t); +static int iwn_config_specific(struct iwn_softc *, uint16_t); static void iwn_radiotap_attach(struct iwn_softc *); static void iwn_sysctlattach(struct iwn_softc *); static struct ieee80211vap *iwn_vap_create(struct ieee80211com *, @@ -200,7 +213,7 @@ static void iwn5000_tx_done(struct iwn_softc *, struct iwn_rx_desc *, struct iwn_rx_data *); static void iwn_tx_done(struct iwn_softc *, struct iwn_rx_desc *, int, uint8_t); -static void iwn_ampdu_tx_done(struct iwn_softc *, int, int, int, void *); +static void iwn_ampdu_tx_done(struct iwn_softc *, int, int, int, int, void *); static void iwn_cmd_done(struct iwn_softc *, struct iwn_rx_desc *); static void iwn_notif_intr(struct iwn_softc *); static void iwn_wakeup_intr(struct iwn_softc *); @@ -257,14 +270,17 @@ static int iwn4965_set_gains(struct iwn_softc *); static int iwn5000_set_gains(struct iwn_softc *); static void iwn_tune_sensitivity(struct iwn_softc *, const struct iwn_rx_stats *); +static void iwn_save_stats_counters(struct iwn_softc *, + const struct iwn_stats *); static int iwn_send_sensitivity(struct iwn_softc *); +static void iwn_check_rx_recovery(struct iwn_softc *, struct iwn_stats *); static int iwn_set_pslevel(struct iwn_softc *, int, int, int); static int iwn_send_btcoex(struct iwn_softc *); static int iwn_send_advanced_btcoex(struct iwn_softc *); static int iwn5000_runtime_calib(struct iwn_softc *); static int iwn_config(struct iwn_softc *); -static uint8_t *ieee80211_add_ssid(uint8_t *, const uint8_t *, u_int); -static int iwn_scan(struct iwn_softc *); +static int iwn_scan(struct iwn_softc *, struct ieee80211vap *, + struct ieee80211_scan_state *, struct ieee80211_channel *); static int iwn_auth(struct iwn_softc *, struct ieee80211vap *vap); static int iwn_run(struct iwn_softc *, struct ieee80211vap *vap); static int iwn_ampdu_rx_start(struct ieee80211_node *, @@ -292,6 +308,7 @@ static int iwn5000_send_calibration(struct iwn_softc *); static int iwn5000_send_wimax_coex(struct iwn_softc *); static int iwn5000_crystal_calib(struct iwn_softc *); static int iwn5000_temp_offset_calib(struct iwn_softc *); +static int iwn5000_temp_offset_calibv2(struct iwn_softc *); static int iwn4965_post_alive(struct iwn_softc *); static int iwn5000_post_alive(struct iwn_softc *); static int iwn4965_load_bootcode(struct iwn_softc *, const uint8_t *, @@ -316,6 +333,7 @@ static int iwn_hw_init(struct iwn_softc *); static void iwn_hw_stop(struct iwn_softc *); static void iwn_radio_on(void *, int); static void iwn_radio_off(void *, int); +static void iwn_panicked(void *, int); static void iwn_init_locked(struct iwn_softc *); static void iwn_init(void *); static void iwn_stop_locked(struct iwn_softc *); @@ -331,80 +349,6 @@ static char *iwn_get_csr_string(int); static void iwn_debug_register(struct iwn_softc *); #endif -#ifdef IWN_DEBUG -enum { - IWN_DEBUG_XMIT = 0x00000001, /* basic xmit operation */ - IWN_DEBUG_RECV = 0x00000002, /* basic recv operation */ - IWN_DEBUG_STATE = 0x00000004, /* 802.11 state transitions */ - IWN_DEBUG_TXPOW = 0x00000008, /* tx power processing */ - IWN_DEBUG_RESET = 0x00000010, /* reset processing */ - IWN_DEBUG_OPS = 0x00000020, /* iwn_ops processing */ - IWN_DEBUG_BEACON = 0x00000040, /* beacon handling */ - IWN_DEBUG_WATCHDOG = 0x00000080, /* watchdog timeout */ - IWN_DEBUG_INTR = 0x00000100, /* ISR */ - IWN_DEBUG_CALIBRATE = 0x00000200, /* periodic calibration */ - IWN_DEBUG_NODE = 0x00000400, /* node management */ - IWN_DEBUG_LED = 0x00000800, /* led management */ - IWN_DEBUG_CMD = 0x00001000, /* cmd submission */ - IWN_DEBUG_TXRATE = 0x00002000, /* TX rate debugging */ - IWN_DEBUG_PWRSAVE = 0x00004000, /* Power save operations */ - IWN_DEBUG_REGISTER = 0x20000000, /* print chipset register */ - IWN_DEBUG_TRACE = 0x40000000, /* Print begin and start driver function */ - IWN_DEBUG_FATAL = 0x80000000, /* fatal errors */ - IWN_DEBUG_ANY = 0xffffffff -}; - -#define DPRINTF(sc, m, fmt, ...) do { \ - if (sc->sc_debug & (m)) \ - printf(fmt, __VA_ARGS__); \ -} while (0) - -static const char * -iwn_intr_str(uint8_t cmd) -{ - switch (cmd) { - /* Notifications */ - case IWN_UC_READY: return "UC_READY"; - case IWN_ADD_NODE_DONE: return "ADD_NODE_DONE"; - case IWN_TX_DONE: return "TX_DONE"; - case IWN_START_SCAN: return "START_SCAN"; - case IWN_STOP_SCAN: return "STOP_SCAN"; - case IWN_RX_STATISTICS: return "RX_STATS"; - case IWN_BEACON_STATISTICS: return "BEACON_STATS"; - case IWN_STATE_CHANGED: return "STATE_CHANGED"; - case IWN_BEACON_MISSED: return "BEACON_MISSED"; - case IWN_RX_PHY: return "RX_PHY"; - case IWN_MPDU_RX_DONE: return "MPDU_RX_DONE"; - case IWN_RX_DONE: return "RX_DONE"; - - /* Command Notifications */ - case IWN_CMD_RXON: return "IWN_CMD_RXON"; - case IWN_CMD_RXON_ASSOC: return "IWN_CMD_RXON_ASSOC"; - case IWN_CMD_EDCA_PARAMS: return "IWN_CMD_EDCA_PARAMS"; - case IWN_CMD_TIMING: return "IWN_CMD_TIMING"; - case IWN_CMD_LINK_QUALITY: return "IWN_CMD_LINK_QUALITY"; - case IWN_CMD_SET_LED: return "IWN_CMD_SET_LED"; - case IWN5000_CMD_WIMAX_COEX: return "IWN5000_CMD_WIMAX_COEX"; - case IWN5000_CMD_CALIB_CONFIG: return "IWN5000_CMD_CALIB_CONFIG"; - case IWN5000_CMD_CALIB_RESULT: return "IWN5000_CMD_CALIB_RESULT"; - case IWN5000_CMD_CALIB_COMPLETE: return "IWN5000_CMD_CALIB_COMPLETE"; - case IWN_CMD_SET_POWER_MODE: return "IWN_CMD_SET_POWER_MODE"; - case IWN_CMD_SCAN: return "IWN_CMD_SCAN"; - case IWN_CMD_SCAN_RESULTS: return "IWN_CMD_SCAN_RESULTS"; - case IWN_CMD_TXPOWER: return "IWN_CMD_TXPOWER"; - case IWN_CMD_TXPOWER_DBM: return "IWN_CMD_TXPOWER_DBM"; - case IWN5000_CMD_TX_ANT_CONFIG: return "IWN5000_CMD_TX_ANT_CONFIG"; - case IWN_CMD_BT_COEX: return "IWN_CMD_BT_COEX"; - case IWN_CMD_SET_CRITICAL_TEMP: return "IWN_CMD_SET_CRITICAL_TEMP"; - case IWN_CMD_SET_SENSITIVITY: return "IWN_CMD_SET_SENSITIVITY"; - case IWN_CMD_PHY_CALIB: return "IWN_CMD_PHY_CALIB"; - } - return "UNKNOWN INTR NOTIF/CMD"; -} -#else -#define DPRINTF(sc, m, fmt, ...) do { (void) sc; } while (0) -#endif - static device_method_t iwn_methods[] = { /* Device interface */ DEVMETHOD(device_probe, iwn_probe), @@ -448,6 +392,15 @@ iwn_probe(device_t dev) } static int +iwn_is_3stream_device(struct iwn_softc *sc) +{ + /* XXX for now only 5300, until the 5350 can be tested */ + if (sc->hw_type == IWN_HW_REV_TYPE_5300) + return (1); + return (0); +} + +static int iwn_attach(device_t dev) { struct iwn_softc *sc = (struct iwn_softc *)device_get_softc(dev); @@ -515,6 +468,11 @@ iwn_attach(device_t dev) sc->hw_type = (IWN_READ(sc, IWN_HW_REV) >> IWN_HW_REV_TYPE_SHIFT) & IWN_HW_REV_TYPE_MASK; sc->subdevice_id = pci_get_subdevice(dev); + + /* + * 4965 versus 5000 and later have different methods. + * Let's set those up first. + */ if (sc->hw_type == IWN_HW_REV_TYPE_4965) error = iwn4965_attach(sc, pci_get_device(dev)); else @@ -525,6 +483,16 @@ iwn_attach(device_t dev) goto fail; } + /* + * Next, let's setup the various parameters of each NIC. + */ + error = iwn_config_specific(sc, pci_get_device(dev)); + if (error != 0) { + device_printf(dev, "could not attach device, error %d\n", + error); + goto fail; + } + if ((error = iwn_hw_prepare(sc)) != 0) { device_printf(dev, "hardware not ready, error %d\n", error); goto fail; @@ -634,17 +602,16 @@ iwn_attach(device_t dev) ic->ic_txstream = sc->ntxchains; /* - * The NICs we currently support cap out at 2x2 support - * separate from the chains being used. - * - * This is a total hack to work around that until some - * per-device method is implemented to return the - * actual stream support. + * Some of the 3 antenna devices (ie, the 4965) only supports + * 2x2 operation. So correct the number of streams if + * it's not a 3-stream device. */ - if (ic->ic_rxstream > 2) - ic->ic_rxstream = 2; - if (ic->ic_txstream > 2) - ic->ic_txstream = 2; + if (! iwn_is_3stream_device(sc)) { + if (ic->ic_rxstream > 2) + ic->ic_rxstream = 2; + if (ic->ic_txstream > 2) + ic->ic_txstream = 2; + } ic->ic_htcaps = IEEE80211_HTCAP_SMPS_OFF /* SMPS mode disabled */ @@ -710,6 +677,15 @@ iwn_attach(device_t dev) TASK_INIT(&sc->sc_reinit_task, 0, iwn_hw_reset, sc); TASK_INIT(&sc->sc_radioon_task, 0, iwn_radio_on, sc); TASK_INIT(&sc->sc_radiooff_task, 0, iwn_radio_off, sc); + TASK_INIT(&sc->sc_panic_task, 0, iwn_panicked, sc); + + sc->sc_tq = taskqueue_create("iwn_taskq", M_WAITOK, + taskqueue_thread_enqueue, &sc->sc_tq); + error = taskqueue_start_threads(&sc->sc_tq, 1, 0, "iwn_taskq"); + if (error != 0) { + device_printf(dev, "can't start threads, error %d\n", error); + goto fail; + } iwn_sysctlattach(sc); @@ -724,6 +700,13 @@ iwn_attach(device_t dev) goto fail; } +#if 0 + device_printf(sc->sc_dev, "%s: rx_stats=%d, rx_stats_bt=%d\n", + __func__, + sizeof(struct iwn_stats), + sizeof(struct iwn_stats_bt)); +#endif + if (bootverbose) ieee80211_announce(ic); DPRINTF(sc, IWN_DEBUG_TRACE, "->%s: end\n",__func__); @@ -734,6 +717,488 @@ fail: return error; } +/* + * Define specific configuration based on device id and subdevice id + * pid : PCI device id + */ +static int +iwn_config_specific(struct iwn_softc *sc, uint16_t pid) +{ + + switch (pid) { +/* 4965 series */ + case IWN_DID_4965_1: + case IWN_DID_4965_2: + case IWN_DID_4965_3: + case IWN_DID_4965_4: + sc->base_params = &iwn4965_base_params; + sc->limits = &iwn4965_sensitivity_limits; + sc->fwname = "iwn4965fw"; + /* Override chains masks, ROM is known to be broken. */ + sc->txchainmask = IWN_ANT_AB; + sc->rxchainmask = IWN_ANT_ABC; + /* Enable normal btcoex */ + sc->sc_flags |= IWN_FLAG_BTCOEX; + break; +/* 1000 Series */ + case IWN_DID_1000_1: + case IWN_DID_1000_2: + switch(sc->subdevice_id) { + case IWN_SDID_1000_1: + case IWN_SDID_1000_2: + case IWN_SDID_1000_3: + case IWN_SDID_1000_4: + case IWN_SDID_1000_5: + case IWN_SDID_1000_6: + case IWN_SDID_1000_7: + case IWN_SDID_1000_8: + case IWN_SDID_1000_9: + case IWN_SDID_1000_10: + case IWN_SDID_1000_11: + case IWN_SDID_1000_12: + sc->limits = &iwn1000_sensitivity_limits; + sc->base_params = &iwn1000_base_params; + sc->fwname = "iwn1000fw"; + break; + default: + device_printf(sc->sc_dev, "adapter type id : 0x%04x sub id :" + "0x%04x rev %d not supported (subdevice)\n", pid, + sc->subdevice_id,sc->hw_type); + return ENOTSUP; + } + break; +/* 6x00 Series */ + case IWN_DID_6x00_2: + case IWN_DID_6x00_4: + case IWN_DID_6x00_1: + case IWN_DID_6x00_3: + sc->fwname = "iwn6000fw"; + sc->limits = &iwn6000_sensitivity_limits; + switch(sc->subdevice_id) { + case IWN_SDID_6x00_1: + case IWN_SDID_6x00_2: + case IWN_SDID_6x00_8: + //iwl6000_3agn_cfg + sc->base_params = &iwn_6000_base_params; + break; + case IWN_SDID_6x00_3: + case IWN_SDID_6x00_6: + case IWN_SDID_6x00_9: + ////iwl6000i_2agn + case IWN_SDID_6x00_4: + case IWN_SDID_6x00_7: + case IWN_SDID_6x00_10: + //iwl6000i_2abg_cfg + case IWN_SDID_6x00_5: + //iwl6000i_2bg_cfg + sc->base_params = &iwn_6000i_base_params; + sc->sc_flags |= IWN_FLAG_INTERNAL_PA; + sc->txchainmask = IWN_ANT_BC; + sc->rxchainmask = IWN_ANT_BC; + break; + default: + device_printf(sc->sc_dev, "adapter type id : 0x%04x sub id :" + "0x%04x rev %d not supported (subdevice)\n", pid, + sc->subdevice_id,sc->hw_type); + return ENOTSUP; + } + break; +/* 6x05 Series */ + case IWN_DID_6x05_1: + case IWN_DID_6x05_2: + switch(sc->subdevice_id) { + case IWN_SDID_6x05_1: + case IWN_SDID_6x05_4: + case IWN_SDID_6x05_6: + //iwl6005_2agn_cfg + case IWN_SDID_6x05_2: + case IWN_SDID_6x05_5: + case IWN_SDID_6x05_7: + //iwl6005_2abg_cfg + case IWN_SDID_6x05_3: + //iwl6005_2bg_cfg + case IWN_SDID_6x05_8: + case IWN_SDID_6x05_9: + //iwl6005_2agn_sff_cfg + case IWN_SDID_6x05_10: + //iwl6005_2agn_d_cfg + case IWN_SDID_6x05_11: + //iwl6005_2agn_mow1_cfg + case IWN_SDID_6x05_12: + //iwl6005_2agn_mow2_cfg + sc->fwname = "iwn6000g2afw"; + sc->limits = &iwn6000_sensitivity_limits; + sc->base_params = &iwn_6000g2_base_params; + break; + default: + device_printf(sc->sc_dev, "adapter type id : 0x%04x sub id :" + "0x%04x rev %d not supported (subdevice)\n", pid, + sc->subdevice_id,sc->hw_type); + return ENOTSUP; + } + break; +/* 6x35 Series */ + case IWN_DID_6035_1: + case IWN_DID_6035_2: + switch(sc->subdevice_id) { + case IWN_SDID_6035_1: + case IWN_SDID_6035_2: + case IWN_SDID_6035_3: + case IWN_SDID_6035_4: + sc->fwname = "iwn6000g2bfw"; + sc->limits = &iwn6235_sensitivity_limits; + sc->base_params = &iwn_6235_base_params; + break; + default: + device_printf(sc->sc_dev, "adapter type id : 0x%04x sub id :" + "0x%04x rev %d not supported (subdevice)\n", pid, + sc->subdevice_id,sc->hw_type); + return ENOTSUP; + } + break; +/* 6x50 WiFi/WiMax Series */ + case IWN_DID_6050_1: + case IWN_DID_6050_2: + switch(sc->subdevice_id) { + case IWN_SDID_6050_1: + case IWN_SDID_6050_3: + case IWN_SDID_6050_5: + //iwl6050_2agn_cfg + case IWN_SDID_6050_2: + case IWN_SDID_6050_4: + case IWN_SDID_6050_6: + //iwl6050_2abg_cfg + sc->fwname = "iwn6050fw"; + sc->txchainmask = IWN_ANT_AB; + sc->rxchainmask = IWN_ANT_AB; + sc->limits = &iwn6000_sensitivity_limits; + sc->base_params = &iwn_6050_base_params; + break; + default: + device_printf(sc->sc_dev, "adapter type id : 0x%04x sub id :" + "0x%04x rev %d not supported (subdevice)\n", pid, + sc->subdevice_id,sc->hw_type); + return ENOTSUP; + } + break; +/* 6150 WiFi/WiMax Series */ + case IWN_DID_6150_1: + case IWN_DID_6150_2: + switch(sc->subdevice_id) { + case IWN_SDID_6150_1: + case IWN_SDID_6150_3: + case IWN_SDID_6150_5: + // iwl6150_bgn_cfg + case IWN_SDID_6150_2: + case IWN_SDID_6150_4: + case IWN_SDID_6150_6: + //iwl6150_bg_cfg + sc->fwname = "iwn6050fw"; + sc->limits = &iwn6000_sensitivity_limits; + sc->base_params = &iwn_6150_base_params; + break; + default: + device_printf(sc->sc_dev, "adapter type id : 0x%04x sub id :" + "0x%04x rev %d not supported (subdevice)\n", pid, + sc->subdevice_id,sc->hw_type); + return ENOTSUP; + } + break; +/* 6030 Series and 1030 Series */ + case IWN_DID_x030_1: + case IWN_DID_x030_2: + case IWN_DID_x030_3: + case IWN_DID_x030_4: + switch(sc->subdevice_id) { + case IWN_SDID_x030_1: + case IWN_SDID_x030_3: + case IWN_SDID_x030_5: + // iwl1030_bgn_cfg + case IWN_SDID_x030_2: + case IWN_SDID_x030_4: + case IWN_SDID_x030_6: + //iwl1030_bg_cfg + case IWN_SDID_x030_7: + case IWN_SDID_x030_10: + case IWN_SDID_x030_14: + //iwl6030_2agn_cfg + case IWN_SDID_x030_8: + case IWN_SDID_x030_11: + case IWN_SDID_x030_15: + // iwl6030_2bgn_cfg + case IWN_SDID_x030_9: + case IWN_SDID_x030_12: + case IWN_SDID_x030_16: + // iwl6030_2abg_cfg + case IWN_SDID_x030_13: + //iwl6030_2bg_cfg + sc->fwname = "iwn6000g2bfw"; + sc->limits = &iwn6000_sensitivity_limits; + sc->base_params = &iwn_6000g2b_base_params; + break; + default: + device_printf(sc->sc_dev, "adapter type id : 0x%04x sub id :" + "0x%04x rev %d not supported (subdevice)\n", pid, + sc->subdevice_id,sc->hw_type); + return ENOTSUP; + } + break; +/* 130 Series WiFi */ +/* XXX: This series will need adjustment for rate. + * see rx_with_siso_diversity in linux kernel + */ + case IWN_DID_130_1: + case IWN_DID_130_2: + switch(sc->subdevice_id) { + case IWN_SDID_130_1: + case IWN_SDID_130_3: + case IWN_SDID_130_5: + //iwl130_bgn_cfg + case IWN_SDID_130_2: + case IWN_SDID_130_4: + case IWN_SDID_130_6: + //iwl130_bg_cfg + sc->fwname = "iwn6000g2bfw"; + sc->limits = &iwn6000_sensitivity_limits; + sc->base_params = &iwn_6000g2b_base_params; + break; + default: + device_printf(sc->sc_dev, "adapter type id : 0x%04x sub id :" + "0x%04x rev %d not supported (subdevice)\n", pid, + sc->subdevice_id,sc->hw_type); + return ENOTSUP; + } + break; +/* 100 Series WiFi */ + case IWN_DID_100_1: + case IWN_DID_100_2: + switch(sc->subdevice_id) { + case IWN_SDID_100_1: + case IWN_SDID_100_2: + case IWN_SDID_100_3: + case IWN_SDID_100_4: + case IWN_SDID_100_5: + case IWN_SDID_100_6: + sc->limits = &iwn1000_sensitivity_limits; + sc->base_params = &iwn1000_base_params; + sc->fwname = "iwn100fw"; + break; + default: + device_printf(sc->sc_dev, "adapter type id : 0x%04x sub id :" + "0x%04x rev %d not supported (subdevice)\n", pid, + sc->subdevice_id,sc->hw_type); + return ENOTSUP; + } + break; + +/* 105 Series */ +/* XXX: This series will need adjustment for rate. + * see rx_with_siso_diversity in linux kernel + */ + case IWN_DID_105_1: + case IWN_DID_105_2: + switch(sc->subdevice_id) { + case IWN_SDID_105_1: + case IWN_SDID_105_2: + case IWN_SDID_105_3: + //iwl105_bgn_cfg + case IWN_SDID_105_4: + //iwl105_bgn_d_cfg + sc->limits = &iwn2030_sensitivity_limits; + sc->base_params = &iwn2000_base_params; + sc->fwname = "iwn105fw"; + break; + default: + device_printf(sc->sc_dev, "adapter type id : 0x%04x sub id :" + "0x%04x rev %d not supported (subdevice)\n", pid, + sc->subdevice_id,sc->hw_type); + return ENOTSUP; + } + break; + +/* 135 Series */ +/* XXX: This series will need adjustment for rate. + * see rx_with_siso_diversity in linux kernel + */ + case IWN_DID_135_1: + case IWN_DID_135_2: + switch(sc->subdevice_id) { + case IWN_SDID_135_1: + case IWN_SDID_135_2: + case IWN_SDID_135_3: + sc->limits = &iwn2030_sensitivity_limits; + sc->base_params = &iwn2030_base_params; + sc->fwname = "iwn135fw"; + break; + default: + device_printf(sc->sc_dev, "adapter type id : 0x%04x sub id :" + "0x%04x rev %d not supported (subdevice)\n", pid, + sc->subdevice_id,sc->hw_type); + return ENOTSUP; + } + break; + +/* 2x00 Series */ + case IWN_DID_2x00_1: + case IWN_DID_2x00_2: + switch(sc->subdevice_id) { + case IWN_SDID_2x00_1: + case IWN_SDID_2x00_2: + case IWN_SDID_2x00_3: + //iwl2000_2bgn_cfg + case IWN_SDID_2x00_4: + //iwl2000_2bgn_d_cfg + sc->limits = &iwn2030_sensitivity_limits; + sc->base_params = &iwn2000_base_params; + sc->fwname = "iwn2000fw"; + break; + default: + device_printf(sc->sc_dev, "adapter type id : 0x%04x sub id :" + "0x%04x rev %d not supported (subdevice) \n", + pid, sc->subdevice_id, sc->hw_type); + return ENOTSUP; + } + break; +/* 2x30 Series */ + case IWN_DID_2x30_1: + case IWN_DID_2x30_2: + switch(sc->subdevice_id) { + case IWN_SDID_2x30_1: + case IWN_SDID_2x30_3: + case IWN_SDID_2x30_5: + //iwl100_bgn_cfg + case IWN_SDID_2x30_2: + case IWN_SDID_2x30_4: + case IWN_SDID_2x30_6: + //iwl100_bg_cfg + sc->limits = &iwn2030_sensitivity_limits; + sc->base_params = &iwn2030_base_params; + sc->fwname = "iwn2030fw"; + break; + default: + device_printf(sc->sc_dev, "adapter type id : 0x%04x sub id :" + "0x%04x rev %d not supported (subdevice)\n", pid, + sc->subdevice_id,sc->hw_type); + return ENOTSUP; + } + break; +/* 5x00 Series */ + case IWN_DID_5x00_1: + case IWN_DID_5x00_2: + case IWN_DID_5x00_3: + case IWN_DID_5x00_4: + sc->limits = &iwn5000_sensitivity_limits; + sc->base_params = &iwn5000_base_params; + sc->fwname = "iwn5000fw"; + switch(sc->subdevice_id) { + case IWN_SDID_5x00_1: + case IWN_SDID_5x00_2: + case IWN_SDID_5x00_3: + case IWN_SDID_5x00_4: + case IWN_SDID_5x00_9: + case IWN_SDID_5x00_10: + case IWN_SDID_5x00_11: + case IWN_SDID_5x00_12: + case IWN_SDID_5x00_17: + case IWN_SDID_5x00_18: + case IWN_SDID_5x00_19: + case IWN_SDID_5x00_20: + //iwl5100_agn_cfg + sc->txchainmask = IWN_ANT_B; + sc->rxchainmask = IWN_ANT_AB; + break; + case IWN_SDID_5x00_5: + case IWN_SDID_5x00_6: + case IWN_SDID_5x00_13: + case IWN_SDID_5x00_14: + case IWN_SDID_5x00_21: + case IWN_SDID_5x00_22: + //iwl5100_bgn_cfg + sc->txchainmask = IWN_ANT_B; + sc->rxchainmask = IWN_ANT_AB; + break; + case IWN_SDID_5x00_7: + case IWN_SDID_5x00_8: + case IWN_SDID_5x00_15: + case IWN_SDID_5x00_16: + case IWN_SDID_5x00_23: + case IWN_SDID_5x00_24: + //iwl5100_abg_cfg + sc->txchainmask = IWN_ANT_B; + sc->rxchainmask = IWN_ANT_AB; + break; + case IWN_SDID_5x00_25: + case IWN_SDID_5x00_26: + case IWN_SDID_5x00_27: + case IWN_SDID_5x00_28: + case IWN_SDID_5x00_29: + case IWN_SDID_5x00_30: + case IWN_SDID_5x00_31: + case IWN_SDID_5x00_32: + case IWN_SDID_5x00_33: + case IWN_SDID_5x00_34: + case IWN_SDID_5x00_35: + case IWN_SDID_5x00_36: + //iwl5300_agn_cfg + sc->txchainmask = IWN_ANT_ABC; + sc->rxchainmask = IWN_ANT_ABC; + break; + default: + device_printf(sc->sc_dev, "adapter type id : 0x%04x sub id :" + "0x%04x rev %d not supported (subdevice)\n", pid, + sc->subdevice_id,sc->hw_type); + return ENOTSUP; + } + break; +/* 5x50 Series */ + case IWN_DID_5x50_1: + case IWN_DID_5x50_2: + case IWN_DID_5x50_3: + case IWN_DID_5x50_4: + sc->limits = &iwn5000_sensitivity_limits; + sc->base_params = &iwn5000_base_params; + sc->fwname = "iwn5000fw"; + switch(sc->subdevice_id) { + case IWN_SDID_5x50_1: + case IWN_SDID_5x50_2: + case IWN_SDID_5x50_3: + //iwl5350_agn_cfg + sc->limits = &iwn5000_sensitivity_limits; + sc->base_params = &iwn5000_base_params; + sc->fwname = "iwn5000fw"; + break; + case IWN_SDID_5x50_4: + case IWN_SDID_5x50_5: + case IWN_SDID_5x50_8: + case IWN_SDID_5x50_9: + case IWN_SDID_5x50_10: + case IWN_SDID_5x50_11: + //iwl5150_agn_cfg + case IWN_SDID_5x50_6: + case IWN_SDID_5x50_7: + case IWN_SDID_5x50_12: + case IWN_SDID_5x50_13: + //iwl5150_abg_cfg + sc->limits = &iwn5000_sensitivity_limits; + sc->fwname = "iwn5150fw"; + sc->base_params = &iwn_5x50_base_params; + break; + default: + device_printf(sc->sc_dev, "adapter type id : 0x%04x sub id :" + "0x%04x rev %d not supported (subdevice)\n", pid, + sc->subdevice_id,sc->hw_type); + return ENOTSUP; + } + break; + default: + device_printf(sc->sc_dev, "adapter type id : 0x%04x sub id : 0x%04x" + "rev 0x%08x not supported (device)\n", pid, sc->subdevice_id, + sc->hw_type); + return ENOTSUP; + } + return 0; +} + static int iwn4965_attach(struct iwn_softc *sc, uint16_t pid) { @@ -769,6 +1234,8 @@ iwn4965_attach(struct iwn_softc *sc, uint16_t pid) /* Override chains masks, ROM is known to be broken. */ sc->txchainmask = IWN_ANT_AB; sc->rxchainmask = IWN_ANT_ABC; + /* Enable normal btcoex */ + sc->sc_flags |= IWN_FLAG_BTCOEX; DPRINTF(sc, IWN_DEBUG_TRACE, "%s: end\n",__func__); @@ -809,58 +1276,6 @@ iwn5000_attach(struct iwn_softc *sc, uint16_t pid) sc->reset_noise_gain = IWN5000_PHY_CALIB_RESET_NOISE_GAIN; sc->noise_gain = IWN5000_PHY_CALIB_NOISE_GAIN; - switch (sc->hw_type) { - case IWN_HW_REV_TYPE_5100: - sc->limits = &iwn5000_sensitivity_limits; - sc->fwname = "iwn5000fw"; - /* Override chains masks, ROM is known to be broken. */ - sc->txchainmask = IWN_ANT_B; - sc->rxchainmask = IWN_ANT_AB; - break; - case IWN_HW_REV_TYPE_5150: - sc->limits = &iwn5150_sensitivity_limits; - sc->fwname = "iwn5150fw"; - break; - case IWN_HW_REV_TYPE_5300: - case IWN_HW_REV_TYPE_5350: - sc->limits = &iwn5000_sensitivity_limits; - sc->fwname = "iwn5000fw"; - break; - case IWN_HW_REV_TYPE_1000: - sc->limits = &iwn1000_sensitivity_limits; - sc->fwname = "iwn1000fw"; - break; - case IWN_HW_REV_TYPE_6000: - sc->limits = &iwn6000_sensitivity_limits; - sc->fwname = "iwn6000fw"; - if (pid == 0x422c || pid == 0x4239) { - sc->sc_flags |= IWN_FLAG_INTERNAL_PA; - /* Override chains masks, ROM is known to be broken. */ - sc->txchainmask = IWN_ANT_BC; - sc->rxchainmask = IWN_ANT_BC; - } - break; - case IWN_HW_REV_TYPE_6050: - sc->limits = &iwn6000_sensitivity_limits; - sc->fwname = "iwn6050fw"; - /* Override chains masks, ROM is known to be broken. */ - sc->txchainmask = IWN_ANT_AB; - sc->rxchainmask = IWN_ANT_AB; - break; - case IWN_HW_REV_TYPE_6005: - sc->limits = &iwn6000_sensitivity_limits; - if (pid != 0x0082 && pid != 0x0085) { - sc->fwname = "iwn6000g2bfw"; - sc->sc_flags |= IWN_FLAG_ADV_BTCOEX; - } else - sc->fwname = "iwn6000g2afw"; - break; - default: - device_printf(sc->sc_dev, "adapter type %d not supported\n", - sc->hw_type); - DPRINTF(sc, IWN_DEBUG_TRACE, "->%s: end in error\n",__func__); - return ENOTSUP; - } return 0; } @@ -959,6 +1374,10 @@ iwn_detach(device_t dev) ieee80211_draintask(ic, &sc->sc_radiooff_task); iwn_stop(sc); + + taskqueue_drain_all(sc->sc_tq); + taskqueue_free(sc->sc_tq); + callout_drain(&sc->watchdog_to); callout_drain(&sc->calib_to); ieee80211_ifdetach(ic); @@ -1184,7 +1603,7 @@ iwn_init_otprom(struct iwn_softc *sc) iwn_nic_unlock(sc); /* Set auto clock gate disable bit for HW with OTP shadow RAM. */ - if (sc->hw_type != IWN_HW_REV_TYPE_1000) { + if (sc->base_params->shadow_ram_support) { IWN_SETBITS(sc, IWN_DBG_LINK_PWR_MGMT, IWN_RESET_LINK_PWR_MGMT_DIS); } @@ -1197,11 +1616,12 @@ iwn_init_otprom(struct iwn_softc *sc) * Find the block before last block (contains the EEPROM image) * for HW without OTP shadow RAM. */ - if (sc->hw_type == IWN_HW_REV_TYPE_1000) { + if (! sc->base_params->shadow_ram_support) { /* Switch to absolute addressing mode. */ IWN_CLRBITS(sc, IWN_OTP_GP, IWN_OTP_GP_RELATIVE_ACCESS); base = prev = 0; - for (count = 0; count < IWN1000_OTP_NBLOCKS; count++) { + for (count = 0; count < sc->base_params->max_ll_items; + count++) { error = iwn_read_prom_data(sc, base, &next, 2); if (error != 0) return error; @@ -1210,7 +1630,7 @@ iwn_init_otprom(struct iwn_softc *sc) prev = base; base = le16toh(next); } - if (count == 0 || count == IWN1000_OTP_NBLOCKS) + if (count == 0 || count == sc->base_params->max_ll_items) return EIO; /* Skip "next" word. */ sc->prom_base = prev + 1; @@ -1316,16 +1736,12 @@ fail: iwn_dma_contig_free(dma); static void iwn_dma_contig_free(struct iwn_dma_info *dma) { - if (dma->map != NULL) { - if (dma->vaddr != NULL) { - bus_dmamap_sync(dma->tag, dma->map, - BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); - bus_dmamap_unload(dma->tag, dma->map); - bus_dmamem_free(dma->tag, dma->vaddr, dma->map); - dma->vaddr = NULL; - } - bus_dmamap_destroy(dma->tag, dma->map); - dma->map = NULL; + if (dma->vaddr != NULL) { + bus_dmamap_sync(dma->tag, dma->map, + BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(dma->tag, dma->map); + bus_dmamem_free(dma->tag, dma->vaddr, dma->map); + dma->vaddr = NULL; } if (dma->tag != NULL) { bus_dma_tag_destroy(dma->tag); @@ -1768,7 +2184,7 @@ iwn4965_read_eeprom(struct iwn_softc *sc) iwn_read_prom_data(sc, IWN4965_EEPROM_DOMAIN, sc->eeprom_domain, 4); /* Read the list of authorized channels (20MHz ones only). */ - for (i = 0; i < 7; i++) { + for (i = 0; i < IWN_NBANDS - 1; i++) { addr = iwn4965_regulatory_bands[i]; iwn_read_eeprom_channels(sc, i, addr); } @@ -1798,7 +2214,7 @@ iwn4965_read_eeprom(struct iwn_softc *sc) #ifdef IWN_DEBUG /* Print samples. */ if (sc->sc_debug & IWN_DEBUG_ANY) { - for (i = 0; i < IWN_NBANDS; i++) + for (i = 0; i < IWN_NBANDS - 1; i++) iwn4965_print_power_group(sc, i); } #endif @@ -1859,16 +2275,13 @@ iwn5000_read_eeprom(struct iwn_softc *sc) sc->eeprom_domain, 4); /* Read the list of authorized channels (20MHz ones only). */ - for (i = 0; i < 7; i++) { - if (sc->hw_type >= IWN_HW_REV_TYPE_6000) - addr = base + iwn6000_regulatory_bands[i]; - else - addr = base + iwn5000_regulatory_bands[i]; + for (i = 0; i < IWN_NBANDS - 1; i++) { + addr = base + sc->base_params->regulatory_bands[i]; iwn_read_eeprom_channels(sc, i, addr); } /* Read enhanced TX power information for 6000 Series. */ - if (sc->hw_type >= IWN_HW_REV_TYPE_6000) + if (sc->base_params->enhanced_TX_power) iwn_read_eeprom_enhinfo(sc); iwn_read_prom_data(sc, IWN5000_EEPROM_CAL, &val, 2); @@ -1879,6 +2292,14 @@ iwn5000_read_eeprom(struct iwn_softc *sc) hdr.version, hdr.pa_type, le16toh(hdr.volt)); sc->calib_ver = hdr.version; + if (sc->base_params->calib_need & IWN_FLG_NEED_PHY_CALIB_TEMP_OFFSETv2) { + sc->eeprom_voltage = le16toh(hdr.volt); + iwn_read_prom_data(sc, base + IWN5000_EEPROM_TEMP, &val, 2); + sc->eeprom_temp_high=le16toh(val); + iwn_read_prom_data(sc, base + IWN5000_EEPROM_VOLT, &val, 2); + sc->eeprom_temp = le16toh(val); + } + if (sc->hw_type == IWN_HW_REV_TYPE_5150) { /* Compute temperature offset. */ iwn_read_prom_data(sc, base + IWN5000_EEPROM_TEMP, &val, 2); @@ -2215,6 +2636,52 @@ rate2plcp(int rate) return 0; } +static int +iwn_get_1stream_tx_antmask(struct iwn_softc *sc) +{ + + return IWN_LSB(sc->txchainmask); +} + +static int +iwn_get_2stream_tx_antmask(struct iwn_softc *sc) +{ + int tx; + + /* + * The '2 stream' setup is a bit .. odd. + * + * For NICs that support only 1 antenna, default to IWN_ANT_AB or + * the firmware panics (eg Intel 5100.) + * + * For NICs that support two antennas, we use ANT_AB. + * + * For NICs that support three antennas, we use the two that + * wasn't the default one. + * + * XXX TODO: if bluetooth (full concurrent) is enabled, restrict + * this to only one antenna. + */ + + /* Default - transmit on the other antennas */ + tx = (sc->txchainmask & ~IWN_LSB(sc->txchainmask)); + + /* Now, if it's zero, set it to IWN_ANT_AB, so to not panic firmware */ + if (tx == 0) + tx = IWN_ANT_AB; + + /* + * If the NIC is a two-stream TX NIC, configure the TX mask to + * the default chainmask + */ + else if (sc->ntxchains == 2) + tx = sc->txchainmask; + + return (tx); +} + + + /* * Calculate the required PLCP value from the given rate, * to the given node. @@ -2228,19 +2695,14 @@ iwn_rate_to_plcp(struct iwn_softc *sc, struct ieee80211_node *ni, { #define RV(v) ((v) & IEEE80211_RATE_VAL) struct ieee80211com *ic = ni->ni_ic; - uint8_t txant1, txant2; uint32_t plcp = 0; int ridx; - /* Use the first valid TX antenna. */ - txant1 = IWN_LSB(sc->txchainmask); - txant2 = IWN_LSB(sc->txchainmask & ~txant1); - /* * If it's an MCS rate, let's set the plcp correctly * and set the relevant flags based on the node config. */ - if (IEEE80211_IS_CHAN_HT(ni->ni_chan)) { + if (rate & IEEE80211_RATE_MCS) { /* * Set the initial PLCP value to be between 0->31 for * MCS 0 -> MCS 31, then set the "I'm an MCS rate!" @@ -2267,15 +2729,15 @@ iwn_rate_to_plcp(struct iwn_softc *sc, struct ieee80211_node *ni, } /* - * If it's a two stream rate, enable TX on both - * antennas. - * - * XXX three stream rates? + * Ensure the selected rate matches the link quality + * table entries being used. */ - if (rate > 0x87) - plcp |= IWN_RFLAG_ANT(txant1 | txant2); + if (rate > 0x8f) + plcp |= IWN_RFLAG_ANT(sc->txchainmask); + else if (rate > 0x87) + plcp |= IWN_RFLAG_ANT(iwn_get_2stream_tx_antmask(sc)); else - plcp |= IWN_RFLAG_ANT(txant1); + plcp |= IWN_RFLAG_ANT(iwn_get_1stream_tx_antmask(sc)); } else { /* * Set the initial PLCP - fine for both @@ -2297,7 +2759,8 @@ iwn_rate_to_plcp(struct iwn_softc *sc, struct ieee80211_node *ni, plcp |= IWN_RFLAG_CCK; /* Set antenna configuration */ - plcp |= IWN_RFLAG_ANT(txant1); + /* XXX TODO: is this the right antenna to use for legacy? */ + plcp |= IWN_RFLAG_ANT(iwn_get_1stream_tx_antmask(sc)); } DPRINTF(sc, IWN_DEBUG_TXRATE, "%s: rate=0x%02x, plcp=0x%08x\n", @@ -2629,8 +3092,9 @@ iwn_rx_compressed_ba(struct iwn_softc *sc, struct iwn_rx_desc *desc, uint16_t ssn; uint8_t tid; int ackfailcnt = 0, i, lastidx, qid, *res, shift; + int tx_ok = 0, tx_err = 0; - DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); + DPRINTF(sc, IWN_DEBUG_TRACE | IWN_DEBUG_XMIT, "->%s begin\n", __func__); bus_dmamap_sync(sc->rxq.data_dmat, data->map, BUS_DMASYNC_POSTREAD); @@ -2660,6 +3124,7 @@ iwn_rx_compressed_ba(struct iwn_softc *sc, struct iwn_rx_desc *desc, KASSERT(ni != NULL, ("no node")); KASSERT(m != NULL, ("no mbuf")); + DPRINTF(sc, IWN_DEBUG_XMIT, "%s: freeing m=%p\n", __func__, m); ieee80211_tx_complete(ni, m, 1); txq->queued--; @@ -2685,22 +3150,32 @@ iwn_rx_compressed_ba(struct iwn_softc *sc, struct iwn_rx_desc *desc, if (wn->agg[tid].nframes > (64 - shift)) return; + /* + * Walk the bitmap and calculate how many successful and failed + * attempts are made. + * + * Yes, the rate control code doesn't know these are A-MPDU + * subframes and that it's okay to fail some of these. + */ ni = tap->txa_ni; bitmap = (le64toh(ba->bitmap) >> shift) & wn->agg[tid].bitmap; for (i = 0; bitmap; i++) { if ((bitmap & 1) == 0) { ifp->if_oerrors++; + tx_err ++; ieee80211_ratectl_tx_complete(ni->ni_vap, ni, IEEE80211_RATECTL_TX_FAILURE, &ackfailcnt, NULL); } else { ifp->if_opackets++; + tx_ok ++; ieee80211_ratectl_tx_complete(ni->ni_vap, ni, IEEE80211_RATECTL_TX_SUCCESS, &ackfailcnt, NULL); } bitmap >>= 1; } - DPRINTF(sc, IWN_DEBUG_TRACE, "->%s: end\n",__func__); + DPRINTF(sc, IWN_DEBUG_TRACE | IWN_DEBUG_XMIT, + "->%s: end; %d ok; %d err\n",__func__, tx_ok, tx_err); } @@ -2728,25 +3203,24 @@ iwn5000_rx_calib_results(struct iwn_softc *sc, struct iwn_rx_desc *desc, switch (calib->code) { case IWN5000_PHY_CALIB_DC: - if ((sc->sc_flags & IWN_FLAG_INTERNAL_PA) == 0 && - (sc->hw_type == IWN_HW_REV_TYPE_5150 || - sc->hw_type >= IWN_HW_REV_TYPE_6000) && - sc->hw_type != IWN_HW_REV_TYPE_6050) + if (sc->base_params->calib_need & IWN_FLG_NEED_PHY_CALIB_DC) idx = 0; break; case IWN5000_PHY_CALIB_LO: - idx = 1; + if (sc->base_params->calib_need & IWN_FLG_NEED_PHY_CALIB_LO) + idx = 1; break; case IWN5000_PHY_CALIB_TX_IQ: - idx = 2; + if (sc->base_params->calib_need & IWN_FLG_NEED_PHY_CALIB_TX_IQ) + idx = 2; break; case IWN5000_PHY_CALIB_TX_IQ_PERIODIC: - if (sc->hw_type < IWN_HW_REV_TYPE_6000 && - sc->hw_type != IWN_HW_REV_TYPE_5150) + if (sc->base_params->calib_need & IWN_FLG_NEED_PHY_CALIB_TX_IQ_PERIODIC) idx = 3; break; case IWN5000_PHY_CALIB_BASE_BAND: - idx = 4; + if (sc->base_params->calib_need & IWN_FLG_NEED_PHY_CALIB_BASE_BAND) + idx = 4; break; } if (idx == -1) /* Ignore other results. */ @@ -2763,11 +3237,72 @@ iwn5000_rx_calib_results(struct iwn_softc *sc, struct iwn_rx_desc *desc, return; } DPRINTF(sc, IWN_DEBUG_CALIBRATE, - "saving calibration result code=%d len=%d\n", calib->code, len); + "saving calibration result idx=%d, code=%d len=%d\n", idx, calib->code, len); sc->calibcmd[idx].len = len; memcpy(sc->calibcmd[idx].buf, calib, len); } +static void +iwn_stats_update(struct iwn_softc *sc, struct iwn_calib_state *calib, + struct iwn_stats *stats, int len) +{ + struct iwn_stats_bt *stats_bt; + struct iwn_stats *lstats; + + /* + * First - check whether the length is the bluetooth or normal. + * + * If it's normal - just copy it and bump out. + * Otherwise we have to convert things. + */ + + if (len == sizeof(struct iwn_stats) + 4) { + memcpy(&sc->last_stat, stats, sizeof(struct iwn_stats)); + sc->last_stat_valid = 1; + return; + } + + /* + * If it's not the bluetooth size - log, then just copy. + */ + if (len != sizeof(struct iwn_stats_bt) + 4) { + DPRINTF(sc, IWN_DEBUG_STATS, + "%s: size of rx statistics (%d) not an expected size!\n", + __func__, + len); + memcpy(&sc->last_stat, stats, sizeof(struct iwn_stats)); + sc->last_stat_valid = 1; + return; + } + + /* + * Ok. Time to copy. + */ + stats_bt = (struct iwn_stats_bt *) stats; + lstats = &sc->last_stat; + + /* flags */ + lstats->flags = stats_bt->flags; + /* rx_bt */ + memcpy(&lstats->rx.ofdm, &stats_bt->rx_bt.ofdm, + sizeof(struct iwn_rx_phy_stats)); + memcpy(&lstats->rx.cck, &stats_bt->rx_bt.cck, + sizeof(struct iwn_rx_phy_stats)); + memcpy(&lstats->rx.general, &stats_bt->rx_bt.general_bt.common, + sizeof(struct iwn_rx_general_stats)); + memcpy(&lstats->rx.ht, &stats_bt->rx_bt.ht, + sizeof(struct iwn_rx_ht_phy_stats)); + /* tx */ + memcpy(&lstats->tx, &stats_bt->tx, + sizeof(struct iwn_tx_stats)); + /* general */ + memcpy(&lstats->general, &stats_bt->general, + sizeof(struct iwn_general_stats)); + + /* XXX TODO: Squirrel away the extra bluetooth stats somewhere */ + sc->last_stat_valid = 1; +} + /* * Process an RX_STATISTICS or BEACON_STATISTICS firmware notification. * The latter is sent by the firmware after each received beacon. @@ -2782,6 +3317,7 @@ iwn_rx_statistics(struct iwn_softc *sc, struct iwn_rx_desc *desc, struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); struct iwn_calib_state *calib = &sc->calib; struct iwn_stats *stats = (struct iwn_stats *)(desc + 1); + struct iwn_stats *lstats; int temp; DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); @@ -2796,12 +3332,26 @@ iwn_rx_statistics(struct iwn_softc *sc, struct iwn_rx_desc *desc, bus_dmamap_sync(sc->rxq.data_dmat, data->map, BUS_DMASYNC_POSTREAD); - DPRINTF(sc, IWN_DEBUG_CALIBRATE, "%s: received statistics, cmd %d\n", - __func__, desc->type); + DPRINTF(sc, IWN_DEBUG_CALIBRATE | IWN_DEBUG_STATS, + "%s: received statistics, cmd %d, len %d\n", + __func__, desc->type, le16toh(desc->len)); sc->calib_cnt = 0; /* Reset TX power calibration timeout. */ + /* + * Collect/track general statistics for reporting. + * + * This takes care of ensuring that the bluetooth sized message + * will be correctly converted to the legacy sized message. + */ + iwn_stats_update(sc, calib, stats, le16toh(desc->len)); + + /* + * And now, let's take a reference of it to use! + */ + lstats = &sc->last_stat; + /* Test if temperature has changed. */ - if (stats->general.temp != sc->rawtemp) { + if (lstats->general.temp != sc->rawtemp) { /* Convert "raw" temperature to degC. */ sc->rawtemp = stats->general.temp; temp = ops->get_temperature(sc); @@ -2816,25 +3366,51 @@ iwn_rx_statistics(struct iwn_softc *sc, struct iwn_rx_desc *desc, if (desc->type != IWN_BEACON_STATISTICS) return; /* Reply to a statistics request. */ - sc->noise = iwn_get_noise(&stats->rx.general); + sc->noise = iwn_get_noise(&lstats->rx.general); DPRINTF(sc, IWN_DEBUG_CALIBRATE, "%s: noise %d\n", __func__, sc->noise); /* Test that RSSI and noise are present in stats report. */ - if (le32toh(stats->rx.general.flags) != 1) { + if (le32toh(lstats->rx.general.flags) != 1) { DPRINTF(sc, IWN_DEBUG_ANY, "%s\n", "received statistics without RSSI"); return; } if (calib->state == IWN_CALIB_STATE_ASSOC) - iwn_collect_noise(sc, &stats->rx.general); - else if (calib->state == IWN_CALIB_STATE_RUN) - iwn_tune_sensitivity(sc, &stats->rx); + iwn_collect_noise(sc, &lstats->rx.general); + else if (calib->state == IWN_CALIB_STATE_RUN) { + iwn_tune_sensitivity(sc, &lstats->rx); + /* + * XXX TODO: Only run the RX recovery if we're associated! + */ + iwn_check_rx_recovery(sc, lstats); + iwn_save_stats_counters(sc, lstats); + } DPRINTF(sc, IWN_DEBUG_TRACE, "->%s: end\n",__func__); } /* + * Save the relevant statistic counters for the next calibration + * pass. + */ +static void +iwn_save_stats_counters(struct iwn_softc *sc, const struct iwn_stats *rs) +{ + struct iwn_calib_state *calib = &sc->calib; + + /* Save counters values for next call. */ + calib->bad_plcp_cck = le32toh(rs->rx.cck.bad_plcp); + calib->fa_cck = le32toh(rs->rx.cck.fa); + calib->bad_plcp_ht = le32toh(rs->rx.ht.bad_plcp); + calib->bad_plcp_ofdm = le32toh(rs->rx.ofdm.bad_plcp); + calib->fa_ofdm = le32toh(rs->rx.ofdm.fa); + + /* Last time we received these tick values */ + sc->last_calib_ticks = ticks; +} + +/* * Process a TX_DONE firmware notification. Unfortunately, the 4965AGN * and 5000 adapters have different incompatible TX status formats. */ @@ -2850,15 +3426,18 @@ iwn4965_tx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc, ring = &sc->txq[qid]; DPRINTF(sc, IWN_DEBUG_XMIT, "%s: " - "qid %d idx %d retries %d nkill %d rate %x duration %d status %x\n", - __func__, desc->qid, desc->idx, stat->ackfailcnt, - stat->btkillcnt, stat->rate, le16toh(stat->duration), + "qid %d idx %d RTS retries %d ACK retries %d nkill %d rate %x duration %d status %x\n", + __func__, desc->qid, desc->idx, + stat->rtsfailcnt, + stat->ackfailcnt, + stat->btkillcnt, + stat->rate, le16toh(stat->duration), le32toh(stat->status)); bus_dmamap_sync(ring->data_dmat, data->map, BUS_DMASYNC_POSTREAD); if (qid >= sc->firstaggqueue) { iwn_ampdu_tx_done(sc, qid, desc->idx, stat->nframes, - &stat->status); + stat->ackfailcnt, &stat->status); } else { iwn_tx_done(sc, desc, stat->ackfailcnt, le32toh(stat->status) & 0xff); @@ -2877,9 +3456,12 @@ iwn5000_tx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc, ring = &sc->txq[qid]; DPRINTF(sc, IWN_DEBUG_XMIT, "%s: " - "qid %d idx %d retries %d nkill %d rate %x duration %d status %x\n", - __func__, desc->qid, desc->idx, stat->ackfailcnt, - stat->btkillcnt, stat->rate, le16toh(stat->duration), + "qid %d idx %d RTS retries %d ACK retries %d nkill %d rate %x duration %d status %x\n", + __func__, desc->qid, desc->idx, + stat->rtsfailcnt, + stat->ackfailcnt, + stat->btkillcnt, + stat->rate, le16toh(stat->duration), le32toh(stat->status)); #ifdef notyet @@ -2890,7 +3472,7 @@ iwn5000_tx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc, bus_dmamap_sync(ring->data_dmat, data->map, BUS_DMASYNC_POSTREAD); if (qid >= sc->firstaggqueue) { iwn_ampdu_tx_done(sc, qid, desc->idx, stat->nframes, - &stat->status); + stat->ackfailcnt, &stat->status); } else { iwn_tx_done(sc, desc, stat->ackfailcnt, le16toh(stat->status) & 0xff); @@ -2977,12 +3559,19 @@ iwn_tx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc, int ackfailcnt, static void iwn_cmd_done(struct iwn_softc *sc, struct iwn_rx_desc *desc) { - struct iwn_tx_ring *ring = &sc->txq[4]; + struct iwn_tx_ring *ring; struct iwn_tx_data *data; + int cmd_queue_num; + + if (sc->sc_flags & IWN_FLAG_PAN_SUPPORT) + cmd_queue_num = IWN_PAN_CMD_QUEUE; + else + cmd_queue_num = IWN_CMD_QUEUE_NUM; - if ((desc->qid & 0xf) != 4) + if ((desc->qid & IWN_RX_DESC_QID_MSK) != cmd_queue_num) return; /* Not a command ack. */ + ring = &sc->txq[cmd_queue_num]; data = &ring->data[desc->idx]; /* If the command was mapped in an mbuf, free it. */ @@ -2998,7 +3587,7 @@ iwn_cmd_done(struct iwn_softc *sc, struct iwn_rx_desc *desc) static void iwn_ampdu_tx_done(struct iwn_softc *sc, int qid, int idx, int nframes, - void *stat) + int ackfailcnt, void *stat) { struct iwn_ops *ops = &sc->ops; struct ifnet *ifp = sc->sc_ifp; @@ -3015,14 +3604,60 @@ iwn_ampdu_tx_done(struct iwn_softc *sc, int qid, int idx, int nframes, uint8_t tid; int bit, i, lastidx, *res, seqno, shift, start; + /* XXX TODO: status is le16 field! Grr */ + DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); + DPRINTF(sc, IWN_DEBUG_XMIT, "%s: nframes=%d, status=0x%08x\n", + __func__, + nframes, + *status); + + tap = sc->qid2tap[qid]; + tid = tap->txa_tid; + wn = (void *)tap->txa_ni; + ni = tap->txa_ni; + + /* + * XXX TODO: ACK and RTS failures would be nice here! + */ -#ifdef NOT_YET + /* + * A-MPDU single frame status - if we failed to transmit it + * in A-MPDU, then it may be a permanent failure. + * + * XXX TODO: check what the Linux iwlwifi driver does here; + * there's some permanent and temporary failures that may be + * handled differently. + */ if (nframes == 1) { - if ((*status & 0xff) != 1 && (*status & 0xff) != 2) + if ((*status & 0xff) != 1 && (*status & 0xff) != 2) { +#ifdef NOT_YET printf("ieee80211_send_bar()\n"); - } #endif + /* + * If we completely fail a transmit, make sure a + * notification is pushed up to the rate control + * layer. + */ + ieee80211_ratectl_tx_complete(ni->ni_vap, + ni, + IEEE80211_RATECTL_TX_FAILURE, + &ackfailcnt, + NULL); + } else { + /* + * If nframes=1, then we won't be getting a BA for + * this frame. Ensure that we correctly update the + * rate control code with how many retries were + * needed to send it. + */ + ieee80211_ratectl_tx_complete(ni->ni_vap, + ni, + IEEE80211_RATECTL_TX_SUCCESS, + &ackfailcnt, + NULL); + } + } bitmap = 0; start = idx; @@ -3061,6 +3696,7 @@ iwn_ampdu_tx_done(struct iwn_softc *sc, int qid, int idx, int nframes, ssn = tap->txa_start & 0xfff; } + /* This is going nframes DWORDS into the descriptor? */ seqno = le32toh(*(status + nframes)) & 0xfff; for (lastidx = (seqno & 0xff); ring->read != lastidx;) { data = &ring->data[ring->read]; @@ -3074,7 +3710,7 @@ iwn_ampdu_tx_done(struct iwn_softc *sc, int qid, int idx, int nframes, KASSERT(ni != NULL, ("no node")); KASSERT(m != NULL, ("no mbuf")); - + DPRINTF(sc, IWN_DEBUG_XMIT, "%s: freeing m=%p\n", __func__, m); ieee80211_tx_complete(ni, m, 1); ring->queued--; @@ -3129,12 +3765,12 @@ iwn_notif_intr(struct iwn_softc *sc) desc = mtod(data->m, struct iwn_rx_desc *); DPRINTF(sc, IWN_DEBUG_RECV, - "%s: qid %x idx %d flags %x type %d(%s) len %d\n", - __func__, desc->qid & 0xf, desc->idx, desc->flags, + "%s: cur=%d; qid %x idx %d flags %x type %d(%s) len %d\n", + __func__, sc->rxq.cur, desc->qid & 0xf, desc->idx, desc->flags, desc->type, iwn_intr_str(desc->type), le16toh(desc->len)); - if (!(desc->qid & 0x80)) /* Reply to a command. */ + if (!(desc->qid & IWN_UNSOLICITED_RX_NOTIF)) /* Reply to a command. */ iwn_cmd_done(sc, desc); switch (desc->type) { @@ -3229,7 +3865,8 @@ iwn_notif_intr(struct iwn_softc *sc) BUS_DMASYNC_POSTREAD); #ifdef IWN_DEBUG uint32_t *status = (uint32_t *)(desc + 1); - DPRINTF(sc, IWN_DEBUG_INTR, "state changed to %x\n", + DPRINTF(sc, IWN_DEBUG_INTR | IWN_DEBUG_STATE, + "state changed to %x\n", le32toh(*status)); #endif break; @@ -3254,11 +3891,11 @@ iwn_notif_intr(struct iwn_softc *sc) #ifdef IWN_DEBUG struct iwn_stop_scan *scan = (struct iwn_stop_scan *)(desc + 1); - DPRINTF(sc, IWN_DEBUG_STATE, + DPRINTF(sc, IWN_DEBUG_STATE | IWN_DEBUG_SCAN, "scan finished nchan=%d status=%d chan=%d\n", scan->nchan, scan->status, scan->chan); #endif - + sc->sc_is_scanning = 0; IWN_UNLOCK(sc); ieee80211_scan_next(vap); IWN_LOCK(sc); @@ -3442,8 +4079,8 @@ iwn_intr(void *arg) #endif /* Dump firmware error log and stop. */ iwn_fatal_intr(sc); - ifp->if_flags &= ~IFF_UP; - iwn_stop_locked(sc); + + taskqueue_enqueue(sc->sc_tq, &sc->sc_panic_task); goto done; } if ((r1 & (IWN_INT_FH_RX | IWN_INT_SW_RX | IWN_INT_RX_PERIODIC)) || @@ -3541,6 +4178,115 @@ iwn5000_reset_sched(struct iwn_softc *sc, int qid, int idx) } #endif +/* + * Check whether OFDM 11g protection will be enabled for the given rate. + * + * The original driver code only enabled protection for OFDM rates. + * It didn't check to see whether it was operating in 11a or 11bg mode. + */ +static int +iwn_check_rate_needs_protection(struct iwn_softc *sc, + struct ieee80211vap *vap, uint8_t rate) +{ + struct ieee80211com *ic = vap->iv_ic; + + /* + * Not in 2GHz mode? Then there's no need to enable OFDM + * 11bg protection. + */ + if (! IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) { + return (0); + } + + /* + * 11bg protection not enabled? Then don't use it. + */ + if ((ic->ic_flags & IEEE80211_F_USEPROT) == 0) + return (0); + + /* + * If it's an 11n rate - no protection. + * We'll do it via a specific 11n check. + */ + if (rate & IEEE80211_RATE_MCS) { + return (0); + } + + /* + * Do a rate table lookup. If the PHY is CCK, + * don't do protection. + */ + if (ieee80211_rate2phytype(ic->ic_rt, rate) == IEEE80211_T_CCK) + return (0); + + /* + * Yup, enable protection. + */ + return (1); +} + +/* + * return a value between 0 and IWN_MAX_TX_RETRIES-1 as an index into + * the link quality table that reflects this particular entry. + */ +static int +iwn_tx_rate_to_linkq_offset(struct iwn_softc *sc, struct ieee80211_node *ni, + uint8_t rate) +{ + struct ieee80211_rateset *rs; + int is_11n; + int nr; + int i; + uint8_t cmp_rate; + + /* + * Figure out if we're using 11n or not here. + */ + if (IEEE80211_IS_CHAN_HT(ni->ni_chan) && ni->ni_htrates.rs_nrates > 0) + is_11n = 1; + else + is_11n = 0; + + /* + * Use the correct rate table. + */ + if (is_11n) { + rs = (struct ieee80211_rateset *) &ni->ni_htrates; + nr = ni->ni_htrates.rs_nrates; + } else { + rs = &ni->ni_rates; + nr = rs->rs_nrates; + } + + /* + * Find the relevant link quality entry in the table. + */ + for (i = 0; i < nr && i < IWN_MAX_TX_RETRIES - 1 ; i++) { + /* + * The link quality table index starts at 0 == highest + * rate, so we walk the rate table backwards. + */ + cmp_rate = rs->rs_rates[(nr - 1) - i]; + if (rate & IEEE80211_RATE_MCS) + cmp_rate |= IEEE80211_RATE_MCS; + +#if 0 + DPRINTF(sc, IWN_DEBUG_XMIT, "%s: idx %d: nr=%d, rate=0x%02x, rateentry=0x%02x\n", + __func__, + i, + nr, + rate, + cmp_rate); +#endif + + if (cmp_rate == rate) + return (i); + } + + /* Failed? Start at the end */ + return (IWN_MAX_TX_RETRIES - 1); +} + static int iwn_tx_data(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni) { @@ -3561,7 +4307,7 @@ iwn_tx_data(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni) uint16_t qos; u_int hdrlen; bus_dma_segment_t *seg, segs[IWN_MAX_SCATTER]; - uint8_t tid, ridx, txant, type; + uint8_t tid, type; int ac, i, totlen, error, pad, nsegs = 0, rate; DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); @@ -3582,6 +4328,7 @@ iwn_tx_data(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni) } ac = M_WME_GETAC(m); if (m->m_flags & M_AMPDU_MPDU) { + uint16_t seqno; struct ieee80211_tx_ampdu *tap = &ni->ni_tx_ampdu[ac]; if (!IEEE80211_AMPDU_RUNNING(tap)) { @@ -3589,9 +4336,27 @@ iwn_tx_data(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni) return EINVAL; } + /* + * Queue this frame to the hardware ring that we've + * negotiated AMPDU TX on. + * + * Note that the sequence number must match the TX slot + * being used! + */ ac = *(int *)tap->txa_private; + seqno = ni->ni_txseqs[tid]; *(uint16_t *)wh->i_seq = - htole16(ni->ni_txseqs[tid] << IEEE80211_SEQ_SEQ_SHIFT); + htole16(seqno << IEEE80211_SEQ_SEQ_SHIFT); + ring = &sc->txq[ac]; + if ((seqno % 256) != ring->cur) { + device_printf(sc->sc_dev, + "%s: m=%p: seqno (%d) (%d) != ring index (%d) !\n", + __func__, + m, + seqno, + seqno % 256, + ring->cur); + } ni->ni_txseqs[tid]++; } ring = &sc->txq[ac]; @@ -3606,13 +4371,13 @@ iwn_tx_data(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni) rate = tp->mcastrate; else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) rate = tp->ucastrate; + else if (m->m_flags & M_EAPOL) + rate = tp->mgmtrate; else { /* XXX pass pktlen */ (void) ieee80211_ratectl_rate(ni, NULL, 0); rate = ni->ni_txrate; } - ridx = ieee80211_legacy_rate_lookup(ic->ic_rt, - rate & IEEE80211_RATE_VAL); /* Encrypt the frame if need be. */ if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { @@ -3669,13 +4434,18 @@ iwn_tx_data(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni) /* NB: Group frames are sent using CCK in 802.11b/g. */ if (totlen + IEEE80211_CRC_LEN > vap->iv_rtsthreshold) { flags |= IWN_TX_NEED_RTS; - } else if ((ic->ic_flags & IEEE80211_F_USEPROT) && - ridx >= IWN_RIDX_OFDM6) { + } else if (iwn_check_rate_needs_protection(sc, vap, rate)) { if (ic->ic_protmode == IEEE80211_PROT_CTSONLY) flags |= IWN_TX_NEED_CTS; else if (ic->ic_protmode == IEEE80211_PROT_RTSCTS) flags |= IWN_TX_NEED_RTS; + } else if ((rate & IEEE80211_RATE_MCS) && + (ic->ic_htprotmode == IEEE80211_PROT_RTSCTS)) { + flags |= IWN_TX_NEED_RTS; } + + /* XXX HT protection? */ + if (flags & (IWN_TX_NEED_RTS | IWN_TX_NEED_CTS)) { if (sc->hw_type != IWN_HW_REV_TYPE_4965) { /* 5000 autoselects RTS/CTS or CTS-to-self. */ @@ -3722,13 +4492,11 @@ iwn_tx_data(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni) if (tx->id == sc->broadcast_id) { /* Group or management frame. */ tx->linkq = 0; - /* XXX Alternate between antenna A and B? */ - txant = IWN_LSB(sc->txchainmask); - tx->rate |= htole32(IWN_RFLAG_ANT(txant)); } else { - tx->linkq = ni->ni_rates.rs_nrates - ridx - 1; + tx->linkq = iwn_tx_rate_to_linkq_offset(sc, ni, rate); flags |= IWN_TX_LINKQ; /* enable MRR */ } + /* Set physical address of "scratch area". */ tx->loaddr = htole32(IWN_LOADDR(data->scratch_paddr)); tx->hiaddr = IWN_HIADDR(data->scratch_paddr); @@ -3773,8 +4541,16 @@ iwn_tx_data(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni) data->m = m; data->ni = ni; - DPRINTF(sc, IWN_DEBUG_XMIT, "%s: qid %d idx %d len %d nsegs %d\n", - __func__, ring->qid, ring->cur, m->m_pkthdr.len, nsegs); + DPRINTF(sc, IWN_DEBUG_XMIT, + "%s: qid %d idx %d len %d nsegs %d flags 0x%08x rate 0x%04x plcp 0x%08x\n", + __func__, + ring->qid, + ring->cur, + m->m_pkthdr.len, + nsegs, + flags, + rate, + tx->rate); /* Fill TX descriptor. */ desc->nsegs = 1; @@ -3821,9 +4597,9 @@ iwn_tx_data_raw(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni, const struct ieee80211_bpf_params *params) { struct iwn_ops *ops = &sc->ops; - struct ifnet *ifp = sc->sc_ifp; +// struct ifnet *ifp = sc->sc_ifp; struct ieee80211vap *vap = ni->ni_vap; - struct ieee80211com *ic = ifp->if_l2com; +// struct ieee80211com *ic = ifp->if_l2com; struct iwn_tx_cmd *cmd; struct iwn_cmd_data *tx; struct ieee80211_frame *wh; @@ -3835,7 +4611,7 @@ iwn_tx_data_raw(struct iwn_softc *sc, struct mbuf *m, uint32_t flags; u_int hdrlen; int ac, totlen, error, pad, nsegs = 0, i, rate; - uint8_t ridx, type, txant; + uint8_t type; DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); @@ -3851,16 +4627,8 @@ iwn_tx_data_raw(struct iwn_softc *sc, struct mbuf *m, desc = &ring->desc[ring->cur]; data = &ring->data[ring->cur]; - /* Choose a TX rate index. */ + /* Choose a TX rate. */ rate = params->ibp_rate0; - ridx = ieee80211_legacy_rate_lookup(ic->ic_rt, - rate & IEEE80211_RATE_VAL); - if (ridx == (uint8_t)-1) { - /* XXX fall back to mcast/mgmt rate? */ - m_freem(m); - return EINVAL; - } - totlen = m->m_pkthdr.len; /* Prepare TX firmware command. */ @@ -3930,17 +4698,10 @@ iwn_tx_data_raw(struct iwn_softc *sc, struct mbuf *m, tx->rts_ntries = params->ibp_try1; tx->data_ntries = params->ibp_try0; tx->lifetime = htole32(IWN_LIFETIME_INFINITE); - - /* XXX should just use iwn_rate_to_plcp() */ - tx->rate = htole32(rate2plcp(rate)); - if (ridx < IWN_RIDX_OFDM6 && - IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) - tx->rate |= htole32(IWN_RFLAG_CCK); + tx->rate = iwn_rate_to_plcp(sc, ni, rate); /* Group or management frame. */ tx->linkq = 0; - txant = IWN_LSB(sc->txchainmask); - tx->rate |= htole32(IWN_RFLAG_ANT(txant)); /* Set physical address of "scratch area". */ tx->loaddr = htole32(IWN_LOADDR(data->scratch_paddr)); @@ -4038,7 +4799,7 @@ iwn_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, struct iwn_softc *sc = ifp->if_softc; int error = 0; - DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); + DPRINTF(sc, IWN_DEBUG_XMIT | IWN_DEBUG_TRACE, "->%s begin\n", __func__); if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { ieee80211_free_node(ni); @@ -4069,7 +4830,7 @@ iwn_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, IWN_UNLOCK(sc); - DPRINTF(sc, IWN_DEBUG_TRACE, "->%s: end\n",__func__); + DPRINTF(sc, IWN_DEBUG_TRACE | IWN_DEBUG_XMIT, "->%s: end\n",__func__); return error; } @@ -4093,6 +4854,8 @@ iwn_start_locked(struct ifnet *ifp) IWN_LOCK_ASSERT(sc); + DPRINTF(sc, IWN_DEBUG_XMIT, "%s: called\n", __func__); + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || (ifp->if_drv_flags & IFF_DRV_OACTIVE)) return; @@ -4113,6 +4876,8 @@ iwn_start_locked(struct ifnet *ifp) } sc->sc_tx_timer = 5; } + + DPRINTF(sc, IWN_DEBUG_XMIT, "%s: done\n", __func__); } static void @@ -4174,6 +4939,19 @@ iwn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) case SIOCGIFMEDIA: error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd); break; + case SIOCGIWNSTATS: + IWN_LOCK(sc); + /* XXX validate permissions/memory/etc? */ + error = copyout(&sc->last_stat, ifr->ifr_data, + sizeof(struct iwn_stats)); + IWN_UNLOCK(sc); + break; + case SIOCZIWNSTATS: + IWN_LOCK(sc); + memset(&sc->last_stat, 0, sizeof(struct iwn_stats)); + IWN_UNLOCK(sc); + error = 0; + break; default: error = EINVAL; break; @@ -4187,19 +4965,26 @@ iwn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) static int iwn_cmd(struct iwn_softc *sc, int code, const void *buf, int size, int async) { - struct iwn_tx_ring *ring = &sc->txq[4]; + struct iwn_tx_ring *ring; struct iwn_tx_desc *desc; struct iwn_tx_data *data; struct iwn_tx_cmd *cmd; struct mbuf *m; bus_addr_t paddr; int totlen, error; + int cmd_queue_num; DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); if (async == 0) IWN_LOCK_ASSERT(sc); + if (sc->sc_flags & IWN_FLAG_PAN_SUPPORT) + cmd_queue_num = IWN_PAN_CMD_QUEUE; + else + cmd_queue_num = IWN_CMD_QUEUE_NUM; + + ring = &sc->txq[cmd_queue_num]; desc = &ring->desc[ring->cur]; data = &ring->data[ring->cur]; totlen = 4 + size; @@ -4293,42 +5078,87 @@ iwn_set_link_quality(struct iwn_softc *sc, struct ieee80211_node *ni) { #define RV(v) ((v) & IEEE80211_RATE_VAL) struct iwn_node *wn = (void *)ni; - struct ieee80211_rateset *rs = &ni->ni_rates; + struct ieee80211_rateset *rs; struct iwn_cmd_link_quality linkq; - uint8_t txant; int i, rate, txrate; + int is_11n; DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); - /* Use the first valid TX antenna. */ - txant = IWN_LSB(sc->txchainmask); - memset(&linkq, 0, sizeof linkq); linkq.id = wn->id; - linkq.antmsk_1stream = txant; - linkq.antmsk_2stream = IWN_ANT_AB; - linkq.ampdu_max = 64; + linkq.antmsk_1stream = iwn_get_1stream_tx_antmask(sc); + linkq.antmsk_2stream = iwn_get_2stream_tx_antmask(sc); + + linkq.ampdu_max = 32; /* XXX negotiated? */ linkq.ampdu_threshold = 3; linkq.ampdu_limit = htole16(4000); /* 4ms */ + DPRINTF(sc, IWN_DEBUG_XMIT, + "%s: 1stream antenna=0x%02x, 2stream antenna=0x%02x, ntxstreams=%d\n", + __func__, + linkq.antmsk_1stream, + linkq.antmsk_2stream, + sc->ntxchains); + + /* + * Are we using 11n rates? Ensure the channel is + * 11n _and_ we have some 11n rates, or don't + * try. + */ + if (IEEE80211_IS_CHAN_HT(ni->ni_chan) && ni->ni_htrates.rs_nrates > 0) { + rs = (struct ieee80211_rateset *) &ni->ni_htrates; + is_11n = 1; + } else { + rs = &ni->ni_rates; + is_11n = 0; + } + /* Start at highest available bit-rate. */ - if (IEEE80211_IS_CHAN_HT(ni->ni_chan)) + /* + * XXX this is all very dirty! + */ + if (is_11n) txrate = ni->ni_htrates.rs_nrates - 1; else txrate = rs->rs_nrates - 1; for (i = 0; i < IWN_MAX_TX_RETRIES; i++) { uint32_t plcp; - if (IEEE80211_IS_CHAN_HT(ni->ni_chan)) - rate = IEEE80211_RATE_MCS | txrate; + /* + * XXX TODO: ensure the last two slots are the two lowest + * rate entries, just for now. + */ + if (i == 14 || i == 15) + txrate = 0; + + if (is_11n) + rate = IEEE80211_RATE_MCS | rs->rs_rates[txrate]; else rate = RV(rs->rs_rates[txrate]); /* Do rate -> PLCP config mapping */ plcp = iwn_rate_to_plcp(sc, ni, rate); linkq.retry[i] = plcp; + DPRINTF(sc, IWN_DEBUG_XMIT, + "%s: i=%d, txrate=%d, rate=0x%02x, plcp=0x%08x\n", + __func__, + i, + txrate, + rate, + le32toh(plcp)); - /* Special case for dual-stream rates? */ + /* + * The mimo field is an index into the table which + * indicates the first index where it and subsequent entries + * will not be using MIMO. + * + * Since we're filling linkq from 0..15 and we're filling + * from the higest MCS rates to the lowest rates, if we + * _are_ doing a dual-stream rate, set mimo to idx+1 (ie, + * the next entry.) That way if the next entry is a non-MIMO + * entry, we're already pointing at it. + */ if ((le32toh(plcp) & IWN_RFLAG_MCS) && RV(le32toh(plcp)) > 7) linkq.mimo = i + 1; @@ -4337,6 +5167,15 @@ iwn_set_link_quality(struct iwn_softc *sc, struct ieee80211_node *ni) if (txrate > 0) txrate--; } + /* + * If we reached the end of the list and indeed we hit + * all MIMO rates (eg 5300 doing MCS23-15) then yes, + * set mimo to 15. Setting it to 16 panics the firmware. + */ + if (linkq.mimo > 15) + linkq.mimo = 15; + + DPRINTF(sc, IWN_DEBUG_XMIT, "%s: mimo = %d\n", __func__, linkq.mimo); DPRINTF(sc, IWN_DEBUG_TRACE, "->%s: end\n",__func__); @@ -4374,13 +5213,14 @@ iwn_add_broadcast_node(struct iwn_softc *sc, int async) memset(&linkq, 0, sizeof linkq); linkq.id = sc->broadcast_id; - linkq.antmsk_1stream = txant; - linkq.antmsk_2stream = IWN_ANT_AB; + linkq.antmsk_1stream = iwn_get_1stream_tx_antmask(sc); + linkq.antmsk_2stream = iwn_get_2stream_tx_antmask(sc); linkq.ampdu_max = 64; linkq.ampdu_threshold = 3; linkq.ampdu_limit = htole16(4000); /* 4ms */ /* Use lowest mandatory bit-rate. */ + /* XXX rate table lookup? */ if (IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan)) linkq.retry[0] = htole32(0xd); else @@ -4442,6 +5282,12 @@ iwn_set_led(struct iwn_softc *sc, uint8_t which, uint8_t off, uint8_t on) DPRINTF(sc, IWN_DEBUG_TRACE, "->Doing %s\n", __func__); +#if 0 + /* XXX don't set LEDs during scan? */ + if (sc->sc_is_scanning) + return; +#endif + /* Clear microcode LED ownership. */ IWN_CLRBITS(sc, IWN_LED, IWN_LED_BSM_CTRL); @@ -4681,6 +5527,7 @@ iwn5000_set_txpower(struct iwn_softc *sc, struct ieee80211_channel *ch, int async) { struct iwn5000_cmd_txpower cmd; + int cmdid; DPRINTF(sc, IWN_DEBUG_TRACE, "->Doing %s\n", __func__); @@ -4692,8 +5539,15 @@ iwn5000_set_txpower(struct iwn_softc *sc, struct ieee80211_channel *ch, cmd.global_limit = 2 * IWN5000_TXPOWER_MAX_DBM; /* 16 dBm */ cmd.flags = IWN5000_TXPOWER_NO_CLOSED; cmd.srv_limit = IWN5000_TXPOWER_AUTO; - DPRINTF(sc, IWN_DEBUG_CALIBRATE, "%s: setting TX power\n", __func__); - return iwn_cmd(sc, IWN_CMD_TXPOWER_DBM, &cmd, sizeof cmd, async); + DPRINTF(sc, IWN_DEBUG_CALIBRATE | IWN_DEBUG_XMIT, + "%s: setting TX power; rev=%d\n", + __func__, + IWN_UCODE_API(sc->ucode_rev)); + if (IWN_UCODE_API(sc->ucode_rev) == 1) + cmdid = IWN_CMD_TXPOWER_DBM_V1; + else + cmdid = IWN_CMD_TXPOWER_DBM; + return iwn_cmd(sc, cmdid, &cmd, sizeof cmd, async); } /* @@ -4893,7 +5747,7 @@ iwn_collect_noise(struct iwn_softc *sc, for (i = 0; i < 3; i++) if (val - calib->rssi[i] > 15 * 20) sc->chainmask &= ~(1 << i); - DPRINTF(sc, IWN_DEBUG_CALIBRATE, + DPRINTF(sc, IWN_DEBUG_CALIBRATE | IWN_DEBUG_XMIT, "%s: RX chains mask: theoretical=0x%x, actual=0x%x\n", __func__, sc->rxchainmask, sc->chainmask); @@ -4907,6 +5761,10 @@ iwn_collect_noise(struct iwn_softc *sc, #ifdef notyet /* XXX Disable RX chains with no antennas connected. */ sc->rxon->rxchain = htole16(IWN_RXCHAIN_SEL(sc->chainmask)); + if (sc->sc_is_scanning) + device_printf(sc->sc_dev, + "%s: is_scanning set, before RXON\n", + __func__); (void)iwn_cmd(sc, IWN_CMD_RXON, sc->rxon, sc->rxonsz, 1); #endif @@ -5014,7 +5872,7 @@ iwn5000_set_gains(struct iwn_softc *sc) cmd.gain[i - 1] |= 1 << 2; /* sign bit */ } } - DPRINTF(sc, IWN_DEBUG_CALIBRATE, + DPRINTF(sc, IWN_DEBUG_CALIBRATE | IWN_DEBUG_XMIT, "setting differential gains Ant B/C: %x/%x (%x)\n", cmd.gain[0], cmd.gain[1], sc->chainmask); return iwn_cmd(sc, IWN_CMD_PHY_CALIB, &cmd, sizeof cmd, 1); @@ -5064,10 +5922,6 @@ iwn_tune_sensitivity(struct iwn_softc *sc, const struct iwn_rx_stats *stats) fa += le32toh(stats->ofdm.fa) - calib->fa_ofdm; fa *= 200 * IEEE80211_DUR_TU; /* 200TU */ - /* Save counters values for next call. */ - calib->bad_plcp_ofdm = le32toh(stats->ofdm.bad_plcp); - calib->fa_ofdm = le32toh(stats->ofdm.fa); - if (fa > 50 * rxena) { /* High false alarm count, decrease sensitivity. */ DPRINTF(sc, IWN_DEBUG_CALIBRATE, @@ -5121,10 +5975,6 @@ iwn_tune_sensitivity(struct iwn_softc *sc, const struct iwn_rx_stats *stats) fa += le32toh(stats->cck.fa) - calib->fa_cck; fa *= 200 * IEEE80211_DUR_TU; /* 200TU */ - /* Save counters values for next call. */ - calib->bad_plcp_cck = le32toh(stats->cck.bad_plcp); - calib->fa_cck = le32toh(stats->cck.fa); - if (fa > 50 * rxena) { /* High false alarm count, decrease sensitivity. */ DPRINTF(sc, IWN_DEBUG_CALIBRATE, @@ -5205,7 +6055,7 @@ iwn_send_sensitivity(struct iwn_softc *sc) cmd.energy_cck = htole16(calib->energy_cck); /* Barker modulation: use default values. */ cmd.corr_barker = htole16(190); - cmd.corr_barker_mrc = htole16(390); + cmd.corr_barker_mrc = htole16(sc->limits->barker_mrc); DPRINTF(sc, IWN_DEBUG_CALIBRATE, "%s: set sensitivity %d/%d/%d/%d/%d/%d/%d\n", __func__, @@ -5230,6 +6080,86 @@ send: } /* + * Look at the increase of PLCP errors over time; if it exceeds + * a programmed threshold then trigger an RF retune. + */ +static void +iwn_check_rx_recovery(struct iwn_softc *sc, struct iwn_stats *rs) +{ + int32_t delta_ofdm, delta_ht, delta_cck; + struct iwn_calib_state *calib = &sc->calib; + int delta_ticks, cur_ticks; + int delta_msec; + int thresh; + + /* + * Calculate the difference between the current and + * previous statistics. + */ + delta_cck = le32toh(rs->rx.cck.bad_plcp) - calib->bad_plcp_cck; + delta_ofdm = le32toh(rs->rx.ofdm.bad_plcp) - calib->bad_plcp_ofdm; + delta_ht = le32toh(rs->rx.ht.bad_plcp) - calib->bad_plcp_ht; + + /* + * Calculate the delta in time between successive statistics + * messages. Yes, it can roll over; so we make sure that + * this doesn't happen. + * + * XXX go figure out what to do about rollover + * XXX go figure out what to do if ticks rolls over to -ve instead! + * XXX go stab signed integer overflow undefined-ness in the face. + */ + cur_ticks = ticks; + delta_ticks = cur_ticks - sc->last_calib_ticks; + + /* + * If any are negative, then the firmware likely reset; so just + * bail. We'll pick this up next time. + */ + if (delta_cck < 0 || delta_ofdm < 0 || delta_ht < 0 || delta_ticks < 0) + return; + + /* + * delta_ticks is in ticks; we need to convert it up to milliseconds + * so we can do some useful math with it. + */ + delta_msec = ticks_to_msecs(delta_ticks); + + /* + * Calculate what our threshold is given the current delta_msec. + */ + thresh = sc->base_params->plcp_err_threshold * delta_msec; + + DPRINTF(sc, IWN_DEBUG_STATE, + "%s: time delta: %d; cck=%d, ofdm=%d, ht=%d, total=%d, thresh=%d\n", + __func__, + delta_msec, + delta_cck, + delta_ofdm, + delta_ht, + (delta_msec + delta_cck + delta_ofdm + delta_ht), + thresh); + + /* + * If we need a retune, then schedule a single channel scan + * to a channel that isn't the currently active one! + * + * The math from linux iwlwifi: + * + * if ((delta * 100 / msecs) > threshold) + */ + if (thresh > 0 && (delta_cck + delta_ofdm + delta_ht) * 100 > thresh) { + DPRINTF(sc, IWN_DEBUG_ANY, + "%s: PLCP error threshold raw (%d) comparison (%d) " + "over limit (%d); retune!\n", + __func__, + (delta_cck + delta_ofdm + delta_ht), + (delta_cck + delta_ofdm + delta_ht) * 100, + thresh); + } +} + +/* * Set STA mode power saving level (between 0 and 5). * Level 0 is CAM (Continuously Aware Mode), 5 is for maximum power saving. */ @@ -5314,25 +6244,73 @@ iwn_send_advanced_btcoex(struct iwn_softc *sc) 0xc0004000, 0x00004000, 0xf0005000, 0xf0005000, }; struct iwn6000_btcoex_config btconfig; + struct iwn2000_btcoex_config btconfig2k; struct iwn_btcoex_priotable btprio; struct iwn_btcoex_prot btprot; int error, i; + uint8_t flags; memset(&btconfig, 0, sizeof btconfig); - btconfig.flags = 145; - btconfig.max_kill = 5; - btconfig.bt3_t7_timer = 1; - btconfig.kill_ack = htole32(0xffff0000); - btconfig.kill_cts = htole32(0xffff0000); - btconfig.sample_time = 2; - btconfig.bt3_t2_timer = 0xc; - for (i = 0; i < 12; i++) - btconfig.lookup_table[i] = htole32(btcoex_3wire[i]); - btconfig.valid = htole16(0xff); - btconfig.prio_boost = 0xf0; - DPRINTF(sc, IWN_DEBUG_RESET, - "%s: configuring advanced bluetooth coexistence\n", __func__); - error = iwn_cmd(sc, IWN_CMD_BT_COEX, &btconfig, sizeof(btconfig), 1); + memset(&btconfig2k, 0, sizeof btconfig2k); + + flags = IWN_BT_FLAG_COEX6000_MODE_3W << + IWN_BT_FLAG_COEX6000_MODE_SHIFT; // Done as is in linux kernel 3.2 + + if (sc->base_params->bt_sco_disable) + flags &= ~IWN_BT_FLAG_SYNC_2_BT_DISABLE; + else + flags |= IWN_BT_FLAG_SYNC_2_BT_DISABLE; + + flags |= IWN_BT_FLAG_COEX6000_CHAN_INHIBITION; + + /* Default flags result is 145 as old value */ + + /* + * Flags value has to be review. Values must change if we + * which to disable it + */ + if (sc->base_params->bt_session_2) { + btconfig2k.flags = flags; + btconfig2k.max_kill = 5; + btconfig2k.bt3_t7_timer = 1; + btconfig2k.kill_ack = htole32(0xffff0000); + btconfig2k.kill_cts = htole32(0xffff0000); + btconfig2k.sample_time = 2; + btconfig2k.bt3_t2_timer = 0xc; + + for (i = 0; i < 12; i++) + btconfig2k.lookup_table[i] = htole32(btcoex_3wire[i]); + btconfig2k.valid = htole16(0xff); + btconfig2k.prio_boost = htole32(0xf0); + DPRINTF(sc, IWN_DEBUG_RESET, + "%s: configuring advanced bluetooth coexistence" + " session 2, flags : 0x%x\n", + __func__, + flags); + error = iwn_cmd(sc, IWN_CMD_BT_COEX, &btconfig2k, + sizeof(btconfig2k), 1); + } else { + btconfig.flags = flags; + btconfig.max_kill = 5; + btconfig.bt3_t7_timer = 1; + btconfig.kill_ack = htole32(0xffff0000); + btconfig.kill_cts = htole32(0xffff0000); + btconfig.sample_time = 2; + btconfig.bt3_t2_timer = 0xc; + + for (i = 0; i < 12; i++) + btconfig.lookup_table[i] = htole32(btcoex_3wire[i]); + btconfig.valid = htole16(0xff); + btconfig.prio_boost = 0xf0; + DPRINTF(sc, IWN_DEBUG_RESET, + "%s: configuring advanced bluetooth coexistence," + " flags : 0x%x\n", + __func__, + flags); + error = iwn_cmd(sc, IWN_CMD_BT_COEX, &btconfig, + sizeof(btconfig), 1); + } + if (error != 0) return error; @@ -5387,13 +6365,32 @@ iwn_config(struct iwn_softc *sc) DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); - if (sc->hw_type == IWN_HW_REV_TYPE_6005) { - /* Set radio temperature sensor offset. */ + if ((sc->base_params->calib_need & IWN_FLG_NEED_PHY_CALIB_TEMP_OFFSET) + && (sc->base_params->calib_need & IWN_FLG_NEED_PHY_CALIB_TEMP_OFFSETv2)) { + device_printf(sc->sc_dev,"%s: temp_offset and temp_offsetv2 are" + " exclusive each together. Review NIC config file. Conf" + " : 0x%08x Flags : 0x%08x \n", __func__, + sc->base_params->calib_need, + (IWN_FLG_NEED_PHY_CALIB_TEMP_OFFSET | + IWN_FLG_NEED_PHY_CALIB_TEMP_OFFSETv2)); + return (EINVAL); + } + + /* Compute temperature calib if needed. Will be send by send calib */ + if (sc->base_params->calib_need & IWN_FLG_NEED_PHY_CALIB_TEMP_OFFSET) { error = iwn5000_temp_offset_calib(sc); if (error != 0) { device_printf(sc->sc_dev, "%s: could not set temperature offset\n", __func__); - return error; + return (error); + } + } else if (sc->base_params->calib_need & IWN_FLG_NEED_PHY_CALIB_TEMP_OFFSETv2) { + error = iwn5000_temp_offset_calibv2(sc); + if (error != 0) { + device_printf(sc->sc_dev, + "%s: could not compute temperature offset v2\n", + __func__); + return (error); } } @@ -5409,9 +6406,10 @@ iwn_config(struct iwn_softc *sc) } /* Configure valid TX chains for >=5000 Series. */ - if (sc->hw_type != IWN_HW_REV_TYPE_4965) { + if (sc->hw_type != IWN_HW_REV_TYPE_4965 && + IWN_UCODE_API(sc->ucode_rev) > 1) { txmask = htole32(sc->txchainmask); - DPRINTF(sc, IWN_DEBUG_RESET, + DPRINTF(sc, IWN_DEBUG_RESET | IWN_DEBUG_XMIT, "%s: configuring valid TX chains 0x%x\n", __func__, txmask); error = iwn_cmd(sc, IWN5000_CMD_TX_ANT_CONFIG, &txmask, sizeof txmask, 0); @@ -5424,10 +6422,14 @@ iwn_config(struct iwn_softc *sc) } /* Configure bluetooth coexistence. */ - if (sc->sc_flags & IWN_FLAG_ADV_BTCOEX) + error = 0; + + /* Configure bluetooth coexistence if needed. */ + if (sc->base_params->bt_mode == IWN_BT_ADVANCED) error = iwn_send_advanced_btcoex(sc); - else + if (sc->base_params->bt_mode == IWN_BT_SIMPLE) error = iwn_send_btcoex(sc); + if (error != 0) { device_printf(sc->sc_dev, "%s: could not configure bluetooth coexistence, error %d\n", @@ -5463,12 +6465,29 @@ iwn_config(struct iwn_softc *sc) sc->rxon->ht_single_mask = 0xff; sc->rxon->ht_dual_mask = 0xff; sc->rxon->ht_triple_mask = 0xff; + /* + * In active association mode, ensure that + * all the receive chains are enabled. + * + * Since we're not yet doing SMPS, don't allow the + * number of idle RX chains to be less than the active + * number. + */ rxchain = IWN_RXCHAIN_VALID(sc->rxchainmask) | - IWN_RXCHAIN_MIMO_COUNT(2) | - IWN_RXCHAIN_IDLE_COUNT(2); + IWN_RXCHAIN_MIMO_COUNT(sc->nrxchains) | + IWN_RXCHAIN_IDLE_COUNT(sc->nrxchains); sc->rxon->rxchain = htole16(rxchain); + DPRINTF(sc, IWN_DEBUG_RESET | IWN_DEBUG_XMIT, + "%s: rxchainmask=0x%x, nrxchains=%d\n", + __func__, + sc->rxchainmask, + sc->nrxchains); DPRINTF(sc, IWN_DEBUG_RESET, "%s: setting configuration\n", __func__); + if (sc->sc_is_scanning) + device_printf(sc->sc_dev, + "%s: is_scanning set, before RXON\n", + __func__); error = iwn_cmd(sc, IWN_CMD_RXON, sc->rxon, sc->rxonsz, 0); if (error != 0) { device_printf(sc->sc_dev, "%s: RXON command failed\n", @@ -5507,39 +6526,109 @@ iwn_config(struct iwn_softc *sc) return 0; } +static uint16_t +iwn_get_active_dwell_time(struct iwn_softc *sc, + struct ieee80211_channel *c, uint8_t n_probes) +{ + /* No channel? Default to 2GHz settings */ + if (c == NULL || IEEE80211_IS_CHAN_2GHZ(c)) { + return (IWN_ACTIVE_DWELL_TIME_2GHZ + + IWN_ACTIVE_DWELL_FACTOR_2GHZ * (n_probes + 1)); + } + + /* 5GHz dwell time */ + return (IWN_ACTIVE_DWELL_TIME_5GHZ + + IWN_ACTIVE_DWELL_FACTOR_5GHZ * (n_probes + 1)); +} + /* - * Add an ssid element to a frame. + * Limit the total dwell time to 85% of the beacon interval. + * + * Returns the dwell time in milliseconds. */ -static uint8_t * -ieee80211_add_ssid(uint8_t *frm, const uint8_t *ssid, u_int len) +static uint16_t +iwn_limit_dwell(struct iwn_softc *sc, uint16_t dwell_time) { - *frm++ = IEEE80211_ELEMID_SSID; - *frm++ = len; - memcpy(frm, ssid, len); - return frm + len; + struct ieee80211com *ic = sc->sc_ifp->if_l2com; + struct ieee80211vap *vap = NULL; + int bintval = 0; + + /* bintval is in TU (1.024mS) */ + if (! TAILQ_EMPTY(&ic->ic_vaps)) { + vap = TAILQ_FIRST(&ic->ic_vaps); + bintval = vap->iv_bss->ni_intval; + } + + /* + * If it's non-zero, we should calculate the minimum of + * it and the DWELL_BASE. + * + * XXX Yes, the math should take into account that bintval + * is 1.024mS, not 1mS.. + */ + if (bintval > 0) { + DPRINTF(sc, IWN_DEBUG_SCAN, + "%s: bintval=%d\n", + __func__, + bintval); + return (MIN(IWN_PASSIVE_DWELL_BASE, ((bintval * 85) / 100))); + } + + /* No association context? Default */ + return (IWN_PASSIVE_DWELL_BASE); +} + +static uint16_t +iwn_get_passive_dwell_time(struct iwn_softc *sc, struct ieee80211_channel *c) +{ + uint16_t passive; + + if (c == NULL || IEEE80211_IS_CHAN_2GHZ(c)) { + passive = IWN_PASSIVE_DWELL_BASE + IWN_PASSIVE_DWELL_TIME_2GHZ; + } else { + passive = IWN_PASSIVE_DWELL_BASE + IWN_PASSIVE_DWELL_TIME_5GHZ; + } + + /* Clamp to the beacon interval if we're associated */ + return (iwn_limit_dwell(sc, passive)); } static int -iwn_scan(struct iwn_softc *sc) +iwn_scan(struct iwn_softc *sc, struct ieee80211vap *vap, + struct ieee80211_scan_state *ss, struct ieee80211_channel *c) { struct ifnet *ifp = sc->sc_ifp; struct ieee80211com *ic = ifp->if_l2com; - struct ieee80211_scan_state *ss = ic->ic_scan; /*XXX*/ - struct ieee80211_node *ni = ss->ss_vap->iv_bss; + struct ieee80211_node *ni = vap->iv_bss; struct iwn_scan_hdr *hdr; struct iwn_cmd_data *tx; struct iwn_scan_essid *essid; struct iwn_scan_chan *chan; struct ieee80211_frame *wh; struct ieee80211_rateset *rs; - struct ieee80211_channel *c; uint8_t *buf, *frm; uint16_t rxchain; uint8_t txant; int buflen, error; + int is_active; + uint16_t dwell_active, dwell_passive; + uint32_t extra, scan_service_time; DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); + /* + * We are absolutely not allowed to send a scan command when another + * scan command is pending. + */ + if (sc->sc_is_scanning) { + device_printf(sc->sc_dev, "%s: called whilst scanning!\n", + __func__); + return (EAGAIN); + } + + /* Assign the scan channel */ + c = ic->ic_curchan; + sc->rxon = &sc->rx_on[IWN_RXON_BSS_CTX]; buf = malloc(IWN_SCAN_MAXSZ, M_DEVBUF, M_NOWAIT | M_ZERO); if (buf == NULL) { @@ -5555,13 +6644,29 @@ iwn_scan(struct iwn_softc *sc) */ hdr->quiet_time = htole16(10); /* timeout in milliseconds */ hdr->quiet_threshold = htole16(1); /* min # of packets */ + /* + * Max needs to be greater than active and passive and quiet! + * It's also in microseconds! + */ + hdr->max_svc = htole32(250 * 1024); + + /* + * Reset scan: interval=100 + * Normal scan: interval=becaon interval + * suspend_time: 100 (TU) + * + */ + extra = (100 /* suspend_time */ / 100 /* beacon interval */) << 22; + //scan_service_time = extra | ((100 /* susp */ % 100 /* int */) * 1024); + scan_service_time = (4 << 22) | (100 * 1024); /* Hardcode for now! */ + hdr->pause_svc = htole32(scan_service_time); /* Select antennas for scanning. */ rxchain = IWN_RXCHAIN_VALID(sc->rxchainmask) | IWN_RXCHAIN_FORCE_MIMO_SEL(sc->rxchainmask) | IWN_RXCHAIN_DRIVER_FORCE; - if (IEEE80211_IS_CHAN_A(ic->ic_curchan) && + if (IEEE80211_IS_CHAN_A(c) && sc->hw_type == IWN_HW_REV_TYPE_4965) { /* Ant A must be avoided in 5GHz because of an HW bug. */ rxchain |= IWN_RXCHAIN_FORCE_SEL(IWN_ANT_B); @@ -5575,7 +6680,7 @@ iwn_scan(struct iwn_softc *sc) tx->id = sc->broadcast_id; tx->lifetime = htole32(IWN_LIFETIME_INFINITE); - if (IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan)) { + if (IEEE80211_IS_CHAN_5GHZ(c)) { /* Send probe requests at 6Mbps. */ tx->rate = htole32(0xd); rs = &ic->ic_sup_rates[IEEE80211_MODE_11A]; @@ -5594,12 +6699,35 @@ iwn_scan(struct iwn_softc *sc) txant = IWN_LSB(sc->txchainmask); tx->rate |= htole32(IWN_RFLAG_ANT(txant)); + /* + * Only do active scanning if we're announcing a probe request + * for a given SSID (or more, if we ever add it to the driver.) + */ + is_active = 0; + + /* + * If we're scanning for a specific SSID, add it to the command. + * + * XXX maybe look at adding support for scanning multiple SSIDs? + */ essid = (struct iwn_scan_essid *)(tx + 1); - if (ss->ss_ssid[0].len != 0) { - essid[0].id = IEEE80211_ELEMID_SSID; - essid[0].len = ss->ss_ssid[0].len; - memcpy(essid[0].data, ss->ss_ssid[0].ssid, ss->ss_ssid[0].len); + if (ss != NULL) { + if (ss->ss_ssid[0].len != 0) { + essid[0].id = IEEE80211_ELEMID_SSID; + essid[0].len = ss->ss_ssid[0].len; + memcpy(essid[0].data, ss->ss_ssid[0].ssid, ss->ss_ssid[0].len); + } + + DPRINTF(sc, IWN_DEBUG_SCAN, "%s: ssid_len=%d, ssid=%*s\n", + __func__, + ss->ss_ssid[0].len, + ss->ss_ssid[0].len, + ss->ss_ssid[0].ssid); + + if (ss->ss_nssid > 0) + is_active = 1; } + /* * Build a probe request frame. Most of the following code is a * copy & paste of what is done in net80211. @@ -5625,53 +6753,102 @@ iwn_scan(struct iwn_softc *sc) /* Set length of probe request. */ tx->len = htole16(frm - (uint8_t *)wh); - c = ic->ic_curchan; + /* + * If active scanning is requested but a certain channel is + * marked passive, we can do active scanning if we detect + * transmissions. + * + * There is an issue with some firmware versions that triggers + * a sysassert on a "good CRC threshold" of zero (== disabled), + * on a radar channel even though this means that we should NOT + * send probes. + * + * The "good CRC threshold" is the number of frames that we + * need to receive during our dwell time on a channel before + * sending out probes -- setting this to a huge value will + * mean we never reach it, but at the same time work around + * the aforementioned issue. Thus use IWL_GOOD_CRC_TH_NEVER + * here instead of IWL_GOOD_CRC_TH_DISABLED. + * + * This was fixed in later versions along with some other + * scan changes, and the threshold behaves as a flag in those + * versions. + */ + + /* + * If we're doing active scanning, set the crc_threshold + * to a suitable value. This is different to active veruss + * passive scanning depending upon the channel flags; the + * firmware will obey that particular check for us. + */ + if (sc->tlv_feature_flags & IWN_UCODE_TLV_FLAGS_NEWSCAN) + hdr->crc_threshold = is_active ? + IWN_GOOD_CRC_TH_DEFAULT : IWN_GOOD_CRC_TH_DISABLED; + else + hdr->crc_threshold = is_active ? + IWN_GOOD_CRC_TH_DEFAULT : IWN_GOOD_CRC_TH_NEVER; + chan = (struct iwn_scan_chan *)frm; chan->chan = htole16(ieee80211_chan2ieee(ic, c)); chan->flags = 0; if (ss->ss_nssid > 0) chan->flags |= htole32(IWN_CHAN_NPBREQS(1)); chan->dsp_gain = 0x6e; + + /* + * Set the passive/active flag depending upon the channel mode. + * XXX TODO: take the is_active flag into account as well? + */ + if (c->ic_flags & IEEE80211_CHAN_PASSIVE) + chan->flags |= htole32(IWN_CHAN_PASSIVE); + else + chan->flags |= htole32(IWN_CHAN_ACTIVE); + + /* + * Calculate the active/passive dwell times. + */ + + dwell_active = iwn_get_active_dwell_time(sc, c, ss->ss_nssid); + dwell_passive = iwn_get_passive_dwell_time(sc, c); + + /* Make sure they're valid */ + if (dwell_passive <= dwell_active) + dwell_passive = dwell_active + 1; + + chan->active = htole16(dwell_active); + chan->passive = htole16(dwell_passive); + if (IEEE80211_IS_CHAN_5GHZ(c) && !(c->ic_flags & IEEE80211_CHAN_PASSIVE)) { chan->rf_gain = 0x3b; - chan->active = htole16(24); - chan->passive = htole16(110); - chan->flags |= htole32(IWN_CHAN_ACTIVE); } else if (IEEE80211_IS_CHAN_5GHZ(c)) { chan->rf_gain = 0x3b; - chan->active = htole16(24); - if (sc->rxon->associd) - chan->passive = htole16(78); - else - chan->passive = htole16(110); - hdr->crc_threshold = 0xffff; } else if (!(c->ic_flags & IEEE80211_CHAN_PASSIVE)) { chan->rf_gain = 0x28; - chan->active = htole16(36); - chan->passive = htole16(120); - chan->flags |= htole32(IWN_CHAN_ACTIVE); } else { chan->rf_gain = 0x28; - chan->active = htole16(36); - if (sc->rxon->associd) - chan->passive = htole16(88); - else - chan->passive = htole16(120); - hdr->crc_threshold = 0xffff; } DPRINTF(sc, IWN_DEBUG_STATE, "%s: chan %u flags 0x%x rf_gain 0x%x " - "dsp_gain 0x%x active 0x%x passive 0x%x\n", __func__, + "dsp_gain 0x%x active %d passive %d scan_svc_time %d crc 0x%x " + "isactive=%d numssid=%d\n", __func__, chan->chan, chan->flags, chan->rf_gain, chan->dsp_gain, - chan->active, chan->passive); + dwell_active, dwell_passive, scan_service_time, + hdr->crc_threshold, is_active, ss->ss_nssid); hdr->nchan++; chan++; buflen = (uint8_t *)chan - buf; hdr->len = htole16(buflen); + if (sc->sc_is_scanning) { + device_printf(sc->sc_dev, + "%s: called with is_scanning set!\n", + __func__); + } + sc->sc_is_scanning = 1; + DPRINTF(sc, IWN_DEBUG_STATE, "sending scan command nchan=%d\n", hdr->nchan); error = iwn_cmd(sc, IWN_CMD_SCAN, buf, buflen, 1); @@ -5712,12 +6889,16 @@ iwn_auth(struct iwn_softc *sc, struct ieee80211vap *vap) sc->rxon->ofdm_mask = 0; } else { /* Assume 802.11b/g. */ - sc->rxon->cck_mask = 0x0f; + sc->rxon->cck_mask = 0x03; sc->rxon->ofdm_mask = 0x15; } DPRINTF(sc, IWN_DEBUG_STATE, "rxon chan %d flags %x cck %x ofdm %x\n", sc->rxon->chan, sc->rxon->flags, sc->rxon->cck_mask, sc->rxon->ofdm_mask); + if (sc->sc_is_scanning) + device_printf(sc->sc_dev, + "%s: is_scanning set, before RXON\n", + __func__); error = iwn_cmd(sc, IWN_CMD_RXON, sc->rxon, sc->rxonsz, 1); if (error != 0) { device_printf(sc->sc_dev, "%s: RXON command failed, error %d\n", @@ -5813,6 +6994,10 @@ iwn_run(struct iwn_softc *sc, struct ieee80211vap *vap) sc->rxon->filter |= htole32(IWN_FILTER_BSS); DPRINTF(sc, IWN_DEBUG_STATE, "rxon chan %d flags %x\n", sc->rxon->chan, sc->rxon->flags); + if (sc->sc_is_scanning) + device_printf(sc->sc_dev, + "%s: is_scanning set, before RXON\n", + __func__); error = iwn_cmd(sc, IWN_CMD_RXON, sc->rxon, sc->rxonsz, 1); if (error != 0) { device_printf(sc->sc_dev, @@ -6211,10 +7396,10 @@ iwn5000_query_calibration(struct iwn_softc *sc) int error; memset(&cmd, 0, sizeof cmd); - cmd.ucode.once.enable = 0xffffffff; - cmd.ucode.once.start = 0xffffffff; - cmd.ucode.once.send = 0xffffffff; - cmd.ucode.flags = 0xffffffff; + cmd.ucode.once.enable = htole32(0xffffffff); + cmd.ucode.once.start = htole32(0xffffffff); + cmd.ucode.once.send = htole32(0xffffffff); + cmd.ucode.flags = htole32(0xffffffff); DPRINTF(sc, IWN_DEBUG_CALIBRATE, "%s: sending calibration query\n", __func__); error = iwn_cmd(sc, IWN5000_CMD_CALIB_CONFIG, &cmd, sizeof cmd, 0); @@ -6236,9 +7421,20 @@ iwn5000_send_calibration(struct iwn_softc *sc) { int idx, error; - for (idx = 0; idx < 5; idx++) { - if (sc->calibcmd[idx].buf == NULL) - continue; /* No results available. */ + for (idx = 0; idx < IWN5000_PHY_CALIB_MAX_RESULT; idx++) { + if (!(sc->base_params->calib_need & (1<<idx))) { + DPRINTF(sc, IWN_DEBUG_CALIBRATE, + "No need of calib %d\n", + idx); + continue; /* no need for this calib */ + } + if (sc->calibcmd[idx].buf == NULL) { + DPRINTF(sc, IWN_DEBUG_CALIBRATE, + "Need calib idx : %d but no available data\n", + idx); + continue; + } + DPRINTF(sc, IWN_DEBUG_CALIBRATE, "send calibration result idx=%d len=%d\n", idx, sc->calibcmd[idx].len); @@ -6259,7 +7455,7 @@ iwn5000_send_wimax_coex(struct iwn_softc *sc) { struct iwn5000_wimax_coex wimax; -#ifdef notyet +#if 0 if (sc->hw_type == IWN_HW_REV_TYPE_6050) { /* Enable WiMAX coexistence for combo adapters. */ wimax.flags = @@ -6315,6 +7511,33 @@ iwn5000_temp_offset_calib(struct iwn_softc *sc) return iwn_cmd(sc, IWN_CMD_PHY_CALIB, &cmd, sizeof cmd, 0); } +static int +iwn5000_temp_offset_calibv2(struct iwn_softc *sc) +{ + struct iwn5000_phy_calib_temp_offsetv2 cmd; + + memset(&cmd, 0, sizeof cmd); + cmd.code = IWN5000_PHY_CALIB_TEMP_OFFSET; + cmd.ngroups = 1; + cmd.isvalid = 1; + if (sc->eeprom_temp != 0) { + cmd.offset_low = htole16(sc->eeprom_temp); + cmd.offset_high = htole16(sc->eeprom_temp_high); + } else { + cmd.offset_low = htole16(IWN_DEFAULT_TEMP_OFFSET); + cmd.offset_high = htole16(IWN_DEFAULT_TEMP_OFFSET); + } + cmd.burnt_voltage_ref = htole16(sc->eeprom_voltage); + + DPRINTF(sc, IWN_DEBUG_CALIBRATE, + "setting radio sensor low offset to %d, high offset to %d, voltage to %d\n", + le16toh(cmd.offset_low), + le16toh(cmd.offset_high), + le16toh(cmd.burnt_voltage_ref)); + + return iwn_cmd(sc, IWN_CMD_PHY_CALIB, &cmd, sizeof cmd, 0); +} + /* * This function is called after the runtime firmware notifies us of its * readiness (called in a process context). @@ -6400,7 +7623,10 @@ iwn5000_post_alive(struct iwn_softc *sc) IWN_SETBITS(sc, IWN_FH_TX_CHICKEN, IWN_FH_TX_CHICKEN_SCHED_RETRY); /* Enable chain mode for all queues, except command queue. */ - iwn_prph_write(sc, IWN5000_SCHED_QCHAIN_SEL, 0xfffef); + if (sc->sc_flags & IWN_FLAG_PAN_SUPPORT) + iwn_prph_write(sc, IWN5000_SCHED_QCHAIN_SEL, 0xfffdf); + else + iwn_prph_write(sc, IWN5000_SCHED_QCHAIN_SEL, 0xfffef); iwn_prph_write(sc, IWN5000_SCHED_AGGR_SEL, 0); for (qid = 0; qid < IWN5000_NTXQUEUES; qid++) { @@ -6421,10 +7647,20 @@ iwn5000_post_alive(struct iwn_softc *sc) iwn_prph_write(sc, IWN5000_SCHED_TXFACT, 0xff); /* Mark TX rings (4 EDCA + cmd + 2 HCCA) as active. */ - for (qid = 0; qid < 7; qid++) { - static uint8_t qid2fifo[] = { 3, 2, 1, 0, 7, 5, 6 }; - iwn_prph_write(sc, IWN5000_SCHED_QUEUE_STATUS(qid), - IWN5000_TXQ_STATUS_ACTIVE | qid2fifo[qid]); + if (sc->sc_flags & IWN_FLAG_PAN_SUPPORT) { + /* Mark TX rings as active. */ + for (qid = 0; qid < 11; qid++) { + static uint8_t qid2fifo[] = { 3, 2, 1, 0, 0, 4, 2, 5, 4, 7, 5 }; + iwn_prph_write(sc, IWN5000_SCHED_QUEUE_STATUS(qid), + IWN5000_TXQ_STATUS_ACTIVE | qid2fifo[qid]); + } + } else { + /* Mark TX rings (4 EDCA + cmd + 2 HCCA) as active. */ + for (qid = 0; qid < 7; qid++) { + static uint8_t qid2fifo[] = { 3, 2, 1, 0, 7, 5, 6 }; + iwn_prph_write(sc, IWN5000_SCHED_QUEUE_STATUS(qid), + IWN5000_TXQ_STATUS_ACTIVE | qid2fifo[qid]); + } } iwn_nic_unlock(sc); @@ -6669,6 +7905,8 @@ iwn_read_firmware_leg(struct iwn_softc *sc, struct iwn_fw_info *fw) ptr = (const uint32_t *)fw->data; rev = le32toh(*ptr++); + sc->ucode_rev = rev; + /* Check firmware API version. */ if (IWN_FW_API(rev) <= 1) { device_printf(sc->sc_dev, @@ -6734,6 +7972,7 @@ iwn_read_firmware_tlv(struct iwn_softc *sc, struct iwn_fw_info *fw, } DPRINTF(sc, IWN_DEBUG_RESET, "FW: \"%.64s\", build 0x%x\n", hdr->descr, le32toh(hdr->build)); + sc->ucode_rev = le32toh(hdr->rev); /* * Select the closest supported alternative that is less than @@ -6789,7 +8028,7 @@ iwn_read_firmware_tlv(struct iwn_softc *sc, struct iwn_fw_info *fw, sc->sc_flags |= IWN_FLAG_ENH_SENS; break; case IWN_FW_TLV_PHY_CALIB: - tmp = htole32(*ptr); + tmp = le32toh(*ptr); if (tmp < 253) { sc->reset_noise_gain = tmp; sc->noise_gain = tmp + 1; @@ -6800,8 +8039,16 @@ iwn_read_firmware_tlv(struct iwn_softc *sc, struct iwn_fw_info *fw, DPRINTF(sc, IWN_DEBUG_RESET, "PAN Support found: %d\n", 1); break; - case IWN_FW_TLV_FLAGS : - sc->tlv_feature_flags = htole32(*ptr); + case IWN_FW_TLV_FLAGS: + if (len < sizeof(uint32_t)) + break; + if (len % sizeof(uint32_t)) + break; + sc->tlv_feature_flags = le32toh(*ptr); + DPRINTF(sc, IWN_DEBUG_RESET, + "%s: feature: 0x%08x\n", + __func__, + sc->tlv_feature_flags); break; case IWN_FW_TLV_PBREQ_MAXLEN: case IWN_FW_TLV_RUNT_EVTLOG_PTR: @@ -6873,6 +8120,8 @@ iwn_read_firmware(struct iwn_softc *sc) return error; } + device_printf(sc->sc_dev, "%s: ucode rev=0x%08x\n", __func__, sc->ucode_rev); + /* Make sure text and data sections fit in hardware memory. */ if (fw->main.textsz > sc->fw_text_maxsz || fw->main.datasz > sc->fw_data_maxsz || @@ -6937,9 +8186,8 @@ iwn_apm_init(struct iwn_softc *sc) else IWN_CLRBITS(sc, IWN_GIO, IWN_GIO_L0S_ENA); - if (sc->hw_type != IWN_HW_REV_TYPE_4965 && - sc->hw_type <= IWN_HW_REV_TYPE_1000) - IWN_SETBITS(sc, IWN_ANA_PLL, IWN_ANA_PLL_INIT); + if (sc->base_params->pll_cfg_val) + IWN_SETBITS(sc, IWN_ANA_PLL, sc->base_params->pll_cfg_val); /* Wait for clock stabilization before accessing prph. */ if ((error = iwn_clock_wait(sc)) != 0) @@ -7051,13 +8299,13 @@ iwn5000_nic_config(struct iwn_softc *sc) /* Use internal power amplifier only. */ IWN_WRITE(sc, IWN_GP_DRIVER, IWN_GP_DRIVER_RADIO_2X2_IPA); } - if ((sc->hw_type == IWN_HW_REV_TYPE_6050 || - sc->hw_type == IWN_HW_REV_TYPE_6005) && sc->calib_ver >= 6) { + if (sc->base_params->additional_nic_config && sc->calib_ver >= 6) { /* Indicate that ROM calibration version is >=6. */ IWN_SETBITS(sc, IWN_GP_DRIVER, IWN_GP_DRIVER_CALIB_VER6); } - if (sc->hw_type == IWN_HW_REV_TYPE_6005) - IWN_SETBITS(sc, IWN_GP_DRIVER, IWN_GP_DRIVER_6050_1X2); + if (sc->base_params->additional_gp_drv_bit) + IWN_SETBITS(sc, IWN_GP_DRIVER, + sc->base_params->additional_gp_drv_bit); return 0; } @@ -7192,7 +8440,7 @@ iwn_hw_init(struct iwn_softc *sc) IWN_WRITE(sc, IWN_UCODE_GP1_CLR, IWN_UCODE_GP1_RFKILL); /* Enable shadow registers. */ - if (sc->hw_type >= IWN_HW_REV_TYPE_6000) + if (sc->base_params->shadow_reg_enable) IWN_SETBITS(sc, IWN_SHADOW_REG_CTRL, 0x800fffff); if ((error = ops->load_firmware(sc)) != 0) { @@ -7305,6 +8553,44 @@ iwn_radio_off(void *arg0, int pending) } static void +iwn_panicked(void *arg0, int pending) +{ + struct iwn_softc *sc = arg0; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); + int error; + + if (vap == NULL) { + printf("%s: null vap\n", __func__); + return; + } + + device_printf(sc->sc_dev, "%s: controller panicked, iv_state = %d; " + "resetting...\n", __func__, vap->iv_state); + + IWN_LOCK(sc); + + iwn_stop_locked(sc); + iwn_init_locked(sc); + if (vap->iv_state >= IEEE80211_S_AUTH && + (error = iwn_auth(sc, vap)) != 0) { + device_printf(sc->sc_dev, + "%s: could not move to auth state\n", __func__); + } + if (vap->iv_state >= IEEE80211_S_RUN && + (error = iwn_run(sc, vap)) != 0) { + device_printf(sc->sc_dev, + "%s: could not move to run state\n", __func__); + } + + /* Only run start once the NIC is in a useful state, like associated */ + iwn_start_locked(sc->sc_ifp); + + IWN_UNLOCK(sc); +} + +static void iwn_init_locked(struct iwn_softc *sc) { struct ifnet *ifp = sc->sc_ifp; @@ -7396,6 +8682,7 @@ iwn_stop_locked(struct iwn_softc *sc) IWN_LOCK_ASSERT(sc); + sc->sc_is_scanning = 0; sc->sc_tx_timer = 0; callout_stop(&sc->watchdog_to); callout_stop(&sc->calib_to); @@ -7486,10 +8773,11 @@ iwn_scan_curchan(struct ieee80211_scan_state *ss, unsigned long maxdwell) { struct ieee80211vap *vap = ss->ss_vap; struct iwn_softc *sc = vap->iv_ic->ic_ifp->if_softc; + struct ieee80211com *ic = vap->iv_ic; int error; IWN_LOCK(sc); - error = iwn_scan(sc); + error = iwn_scan(sc, vap, ss, ic->ic_curchan); IWN_UNLOCK(sc); if (error != 0) ieee80211_cancel_scan(vap); diff --git a/sys/dev/iwn/if_iwn_chip_cfg.h b/sys/dev/iwn/if_iwn_chip_cfg.h new file mode 100644 index 0000000..ea6f3e1 --- /dev/null +++ b/sys/dev/iwn/if_iwn_chip_cfg.h @@ -0,0 +1,413 @@ +/*- + * Copyright (c) 2013 Cedric GROSS <cg@cgross.info> + * Copyright (c) 2011 Intel Corporation + * + * 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. + * + * $FreeBSD$ + */ + +#ifndef __IF_IWN_CHIP_CFG_H__ +#define __IF_IWN_CHIP_CFG_H__ + +/* ========================================================================== + * NIC PARAMETERS + * + * ========================================================================== + */ + +/* + * Flags for managing calibration result. See calib_need + * in iwn_base_params struct + * + * These are bitmasks that determine which indexes in the calibcmd + * array are pushed up. + */ +#define IWN_FLG_NEED_PHY_CALIB_DC (1<<0) +#define IWN_FLG_NEED_PHY_CALIB_LO (1<<1) +#define IWN_FLG_NEED_PHY_CALIB_TX_IQ (1<<2) +#define IWN_FLG_NEED_PHY_CALIB_TX_IQ_PERIODIC (1<<3) +#define IWN_FLG_NEED_PHY_CALIB_BASE_BAND (1<<4) +/* + * These aren't (yet) included in the calibcmd array, but + * are used as flags for which calibrations to use. + * + * XXX I think they should be named differently and + * stuffed in a different member in the config struct! + */ +#define IWN_FLG_NEED_PHY_CALIB_TEMP_OFFSET (1<<5) +#define IWN_FLG_NEED_PHY_CALIB_CRYSTAL (1<<6) +#define IWN_FLG_NEED_PHY_CALIB_TEMP_OFFSETv2 (1<<7) + +/* + * Each chip has a different threshold for PLCP errors that should trigger a + * retune. + */ +#define IWN_PLCP_ERR_DEFAULT_THRESHOLD 50 +#define IWN_PLCP_ERR_LONG_THRESHOLD 100 +#define IWN_PLCP_ERR_EXT_LONG_THRESHOLD 200 + +/* + * Define some parameters for managing different NIC. + * Refer to linux specific file like iwl-xxxx.c to determine correct value + * for NIC. + * + * @max_ll_items: max number of OTP blocks + * @shadow_ram_support: shadow support for OTP memory + * @shadow_reg_enable: HW shadhow register bit + * @no_idle_support: do not support idle mode + * @advanced_bt_coexist : Advanced BT management + * @bt_session_2 : NIC need a new struct for configure BT coexistence. Needed + * only if advanced_bt_coexist is true + * @bt_sco_disable : + * @additional_nic_config: For 6005 series + * @iq_invert : ? But need it for N 2000 series + * @regulatory_bands : XXX + * @enhanced_TX_power : EEPROM Has advanced TX power options. Set 'True' + * if update_enhanced_txpower = iwl_eeprom_enhanced_txpower. + * See iwl-agn-devices.c file to determine that(enhanced_txpower) + * @need_temp_offset_calib : Need to compute some temp offset for calibration. + * @calib_need : Use IWN_FLG_NEED_PHY_CALIB_* flags to specify which + * calibration data ucode need. See calib_init_cfg in iwl-xxxx.c + * linux kernel file + * @support_hostap: Define IEEE80211_C_HOSTAP for ic_caps + * @no_multi_vaps: See iwn_vap_create + * @additional_gp_drv_bit : Specific bit to defined during nic_config + * @bt_mode: BT configuration mode + */ +enum bt_mode_enum { + IWN_BT_NONE, + IWN_BT_SIMPLE, + IWN_BT_ADVANCED +}; + +struct iwn_base_params { + uint32_t pll_cfg_val; + const uint16_t max_ll_items; +#define IWN_OTP_MAX_LL_ITEMS_1000 (3) /* OTP blocks for 1000 */ +#define IWN_OTP_MAX_LL_ITEMS_6x00 (4) /* OTP blocks for 6x00 */ +#define IWN_OTP_MAX_LL_ITEMS_6x50 (7) /* OTP blocks for 6x50 */ +#define IWN_OTP_MAX_LL_ITEMS_2x00 (4) /* OTP blocks for 2x00 */ + const bool shadow_ram_support; + const bool shadow_reg_enable; + const bool bt_session_2; + const bool bt_sco_disable; + const bool additional_nic_config; + const uint32_t *regulatory_bands; + const bool enhanced_TX_power; + const uint16_t calib_need; + const bool support_hostap; + const bool no_multi_vaps; + uint8_t additional_gp_drv_bit; + enum bt_mode_enum bt_mode; + uint32_t plcp_err_threshold; +}; + +static const struct iwn_base_params iwn5000_base_params = { + .pll_cfg_val = IWN_ANA_PLL_INIT, /* pll_cfg_val; */ + .max_ll_items = IWN_OTP_MAX_LL_ITEMS_6x00, /* max_ll_items */ + .shadow_ram_support = false, /* shadow_ram_support */ + .shadow_reg_enable = false, /* shadow_reg_enable */ + .bt_session_2 = false, /* bt_session_2 */ + .bt_sco_disable = true, /* bt_sco_disable */ + .additional_nic_config = false, /* additional_nic_config */ + .regulatory_bands = iwn5000_regulatory_bands, /* regulatory_bands */ + .enhanced_TX_power = false, /* enhanced_TX_power */ + .calib_need = + ( IWN_FLG_NEED_PHY_CALIB_LO + | IWN_FLG_NEED_PHY_CALIB_TX_IQ_PERIODIC + | IWN_FLG_NEED_PHY_CALIB_TX_IQ + | IWN_FLG_NEED_PHY_CALIB_BASE_BAND ), + .support_hostap = false, /* support_hostap */ + .no_multi_vaps = true, /* no_multi_vaps */ + .additional_gp_drv_bit = IWN_GP_DRIVER_NONE, /* additional_gp_drv_bit */ + .bt_mode = IWN_BT_NONE, /* bt_mode */ + .plcp_err_threshold = IWN_PLCP_ERR_LONG_THRESHOLD, +}; + +/* + * 4965 support + */ +static const struct iwn_base_params iwn4965_base_params = { + .pll_cfg_val = 0, /* pll_cfg_val; */ + .max_ll_items = IWN_OTP_MAX_LL_ITEMS_6x00, /* max_ll_items - ignored for 4965 */ + .shadow_ram_support = true, /* shadow_ram_support */ + .shadow_reg_enable = false, /* shadow_reg_enable */ + .bt_session_2 = false, /* bt_session_2 XXX unknown? */ + .bt_sco_disable = true, /* bt_sco_disable XXX unknown? */ + .additional_nic_config = false, /* additional_nic_config - not for 4965 */ + .regulatory_bands = iwn5000_regulatory_bands, /* regulatory_bands */ + .enhanced_TX_power = false, /* enhanced_TX_power - not for 4965 */ + .calib_need = + (IWN_FLG_NEED_PHY_CALIB_DC + | IWN_FLG_NEED_PHY_CALIB_LO + | IWN_FLG_NEED_PHY_CALIB_TX_IQ_PERIODIC + | IWN_FLG_NEED_PHY_CALIB_TX_IQ + | IWN_FLG_NEED_PHY_CALIB_BASE_BAND ), + .support_hostap = false, /* support_hostap - XXX should work on fixing! */ + .no_multi_vaps = true, /* no_multi_vaps - XXX should work on fixing! */ + .additional_gp_drv_bit = IWN_GP_DRIVER_NONE, /* additional_gp_drv_bit */ + .bt_mode = IWN_BT_SIMPLE, /* bt_mode */ + .plcp_err_threshold = IWN_PLCP_ERR_DEFAULT_THRESHOLD, +}; + + +static const struct iwn_base_params iwn2000_base_params = { + .pll_cfg_val = 0, + .max_ll_items = IWN_OTP_MAX_LL_ITEMS_2x00, + .shadow_ram_support = true, + .shadow_reg_enable = false, + .bt_session_2 = false, + .bt_sco_disable = true, + .additional_nic_config = false, + .regulatory_bands = iwn2030_regulatory_bands, + .enhanced_TX_power = true, + .calib_need = + (IWN_FLG_NEED_PHY_CALIB_DC + | IWN_FLG_NEED_PHY_CALIB_LO + | IWN_FLG_NEED_PHY_CALIB_TX_IQ + | IWN_FLG_NEED_PHY_CALIB_BASE_BAND + | IWN_FLG_NEED_PHY_CALIB_TEMP_OFFSETv2 ), + .support_hostap = true, + .no_multi_vaps = false, + .additional_gp_drv_bit = IWN_GP_DRIVER_REG_BIT_RADIO_IQ_INVERT, + .bt_mode = IWN_BT_NONE, + .plcp_err_threshold = IWN_PLCP_ERR_DEFAULT_THRESHOLD, +}; + +static const struct iwn_base_params iwn2030_base_params = { + .pll_cfg_val = 0, + .max_ll_items = IWN_OTP_MAX_LL_ITEMS_2x00, + .shadow_ram_support = true, + .shadow_reg_enable = false, /* XXX check? */ + .bt_session_2 = true, + .bt_sco_disable = true, + .additional_nic_config = false, + .regulatory_bands = iwn2030_regulatory_bands, + .enhanced_TX_power = true, + .calib_need = + (IWN_FLG_NEED_PHY_CALIB_DC + | IWN_FLG_NEED_PHY_CALIB_LO + | IWN_FLG_NEED_PHY_CALIB_TX_IQ + | IWN_FLG_NEED_PHY_CALIB_BASE_BAND + | IWN_FLG_NEED_PHY_CALIB_TEMP_OFFSETv2 ), + .support_hostap = true, + .no_multi_vaps = false, + .additional_gp_drv_bit = IWN_GP_DRIVER_REG_BIT_RADIO_IQ_INVERT, + .bt_mode = IWN_BT_ADVANCED, + .plcp_err_threshold = IWN_PLCP_ERR_DEFAULT_THRESHOLD, +}; + +static const struct iwn_base_params iwn1000_base_params = { + .pll_cfg_val = IWN_ANA_PLL_INIT, + .max_ll_items = IWN_OTP_MAX_LL_ITEMS_1000, + .shadow_ram_support = false, + .shadow_reg_enable = false, /* XXX check? */ + .bt_session_2 = false, + .bt_sco_disable = false, + .additional_nic_config = false, + .regulatory_bands = iwn5000_regulatory_bands, + .enhanced_TX_power = false, + .calib_need = + ( IWN_FLG_NEED_PHY_CALIB_LO + | IWN_FLG_NEED_PHY_CALIB_TX_IQ_PERIODIC + | IWN_FLG_NEED_PHY_CALIB_TX_IQ + | IWN_FLG_NEED_PHY_CALIB_BASE_BAND + ), + .support_hostap = false, + .no_multi_vaps = true, + .additional_gp_drv_bit = IWN_GP_DRIVER_NONE, + /* XXX 1000 - no BT */ + .bt_mode = IWN_BT_SIMPLE, + .plcp_err_threshold = IWN_PLCP_ERR_EXT_LONG_THRESHOLD, +}; +static const struct iwn_base_params iwn_6000_base_params = { + .pll_cfg_val = 0, + .max_ll_items = IWN_OTP_MAX_LL_ITEMS_6x00, + .shadow_ram_support = true, + .shadow_reg_enable = true, + .bt_session_2 = false, + .bt_sco_disable = false, + .additional_nic_config = false, + .regulatory_bands = iwn6000_regulatory_bands, + .enhanced_TX_power = true, + .calib_need = + (IWN_FLG_NEED_PHY_CALIB_DC + | IWN_FLG_NEED_PHY_CALIB_LO + | IWN_FLG_NEED_PHY_CALIB_TX_IQ + | IWN_FLG_NEED_PHY_CALIB_BASE_BAND ), + .support_hostap = false, + .no_multi_vaps = true, + .additional_gp_drv_bit = IWN_GP_DRIVER_NONE, + .bt_mode = IWN_BT_SIMPLE, + .plcp_err_threshold = IWN_PLCP_ERR_DEFAULT_THRESHOLD, +}; +static const struct iwn_base_params iwn_6000i_base_params = { + .pll_cfg_val = 0, + .max_ll_items = IWN_OTP_MAX_LL_ITEMS_6x00, + .shadow_ram_support = true, + .shadow_reg_enable = true, + .bt_session_2 = false, + .bt_sco_disable = true, + .additional_nic_config = false, + .regulatory_bands = iwn6000_regulatory_bands, + .enhanced_TX_power = true, + .calib_need = + (IWN_FLG_NEED_PHY_CALIB_DC + | IWN_FLG_NEED_PHY_CALIB_LO + | IWN_FLG_NEED_PHY_CALIB_TX_IQ + | IWN_FLG_NEED_PHY_CALIB_BASE_BAND ), + .support_hostap = false, + .no_multi_vaps = true, + .additional_gp_drv_bit = IWN_GP_DRIVER_NONE, + .bt_mode = IWN_BT_SIMPLE, + .plcp_err_threshold = IWN_PLCP_ERR_DEFAULT_THRESHOLD, +}; +static const struct iwn_base_params iwn_6000g2_base_params = { + .pll_cfg_val = 0, + .max_ll_items = IWN_OTP_MAX_LL_ITEMS_6x00, + .shadow_ram_support = true, + .shadow_reg_enable = true, + .bt_session_2 = false, + .bt_sco_disable = true, + .additional_nic_config = false, + .regulatory_bands = iwn6000_regulatory_bands, + .enhanced_TX_power = true, + .calib_need = + (IWN_FLG_NEED_PHY_CALIB_DC + | IWN_FLG_NEED_PHY_CALIB_LO + | IWN_FLG_NEED_PHY_CALIB_TX_IQ + | IWN_FLG_NEED_PHY_CALIB_BASE_BAND + | IWN_FLG_NEED_PHY_CALIB_TEMP_OFFSET ), + .support_hostap = false, + .no_multi_vaps = true, + .additional_gp_drv_bit = 0, + .bt_mode = IWN_BT_SIMPLE, + .plcp_err_threshold = IWN_PLCP_ERR_DEFAULT_THRESHOLD, +}; + +static const struct iwn_base_params iwn_6050_base_params = { + .pll_cfg_val = 0, + .max_ll_items = IWN_OTP_MAX_LL_ITEMS_6x50, + .shadow_ram_support = true, + .shadow_reg_enable = true, + .bt_session_2 = false, + .bt_sco_disable = true, + .additional_nic_config = true, + .regulatory_bands = iwn6000_regulatory_bands, + .enhanced_TX_power = true, + .calib_need = + (IWN_FLG_NEED_PHY_CALIB_LO + | IWN_FLG_NEED_PHY_CALIB_TX_IQ + | IWN_FLG_NEED_PHY_CALIB_BASE_BAND ), + .support_hostap = false, + .no_multi_vaps = true, + .additional_gp_drv_bit = IWN_GP_DRIVER_NONE, + .bt_mode = IWN_BT_SIMPLE, + .plcp_err_threshold = IWN_PLCP_ERR_DEFAULT_THRESHOLD, +}; +static const struct iwn_base_params iwn_6150_base_params = { + .pll_cfg_val = 0, + .max_ll_items = IWN_OTP_MAX_LL_ITEMS_6x50, + .shadow_ram_support = true, + .shadow_reg_enable = true, + .bt_session_2 = false, + .bt_sco_disable = true, + .additional_nic_config = true, + .regulatory_bands = iwn6000_regulatory_bands, + .enhanced_TX_power = true, + .calib_need = + (IWN_FLG_NEED_PHY_CALIB_LO + | IWN_FLG_NEED_PHY_CALIB_TX_IQ + | IWN_FLG_NEED_PHY_CALIB_BASE_BAND), + .support_hostap = false, + .no_multi_vaps = true, + .additional_gp_drv_bit = IWN_GP_DRIVER_6050_1X2, + .bt_mode = IWN_BT_SIMPLE, + .plcp_err_threshold = IWN_PLCP_ERR_DEFAULT_THRESHOLD, +}; + +/* IWL_DEVICE_6035 & IWL_DEVICE_6030 */ +static const struct iwn_base_params iwn_6000g2b_base_params = { + .pll_cfg_val = 0, + .max_ll_items = IWN_OTP_MAX_LL_ITEMS_6x00, + .shadow_ram_support = true, + .shadow_reg_enable = true, + .bt_session_2 = false, + .bt_sco_disable = true, + .additional_nic_config = false, + .regulatory_bands = iwn6000_regulatory_bands, + .enhanced_TX_power = true, + .calib_need = + (IWN_FLG_NEED_PHY_CALIB_DC + | IWN_FLG_NEED_PHY_CALIB_LO + | IWN_FLG_NEED_PHY_CALIB_TX_IQ + | IWN_FLG_NEED_PHY_CALIB_BASE_BAND + | IWN_FLG_NEED_PHY_CALIB_TEMP_OFFSET ), + .support_hostap = false, + .no_multi_vaps = true, + .additional_gp_drv_bit = IWN_GP_DRIVER_NONE, + .bt_mode = IWN_BT_ADVANCED, + .plcp_err_threshold = IWN_PLCP_ERR_DEFAULT_THRESHOLD, +}; + +/* + * 6235 series NICs. + */ +static const struct iwn_base_params iwn_6235_base_params = { + .pll_cfg_val = 0, + .max_ll_items = IWN_OTP_MAX_LL_ITEMS_6x00, + .shadow_ram_support = true, + .shadow_reg_enable = true, + .bt_session_2 = false, + .bt_sco_disable = true, + .additional_nic_config = true, + .regulatory_bands = iwn6000_regulatory_bands, + .enhanced_TX_power = true, + .calib_need = + (IWN_FLG_NEED_PHY_CALIB_DC + | IWN_FLG_NEED_PHY_CALIB_LO + | IWN_FLG_NEED_PHY_CALIB_TX_IQ + | IWN_FLG_NEED_PHY_CALIB_BASE_BAND + | IWN_FLG_NEED_PHY_CALIB_TEMP_OFFSET ), + .support_hostap = false, + .no_multi_vaps = true, + /* XXX 1x2? This NIC is 2x2, right? */ + .additional_gp_drv_bit = IWN_GP_DRIVER_6050_1X2, + .bt_mode = IWN_BT_ADVANCED, + .plcp_err_threshold = IWN_PLCP_ERR_DEFAULT_THRESHOLD, +}; + +static const struct iwn_base_params iwn_5x50_base_params = { + .pll_cfg_val = IWN_ANA_PLL_INIT, + .max_ll_items = IWN_OTP_MAX_LL_ITEMS_6x00, + .shadow_ram_support = true, + .shadow_reg_enable = false, + .bt_session_2 = false, + .bt_sco_disable = true, + .additional_nic_config = false, + .regulatory_bands = iwn5000_regulatory_bands, + .enhanced_TX_power =false, + .calib_need = + (IWN_FLG_NEED_PHY_CALIB_DC + | IWN_FLG_NEED_PHY_CALIB_LO + | IWN_FLG_NEED_PHY_CALIB_TX_IQ + | IWN_FLG_NEED_PHY_CALIB_BASE_BAND ), + .support_hostap = false, + .no_multi_vaps = true, + .additional_gp_drv_bit = IWN_GP_DRIVER_NONE, + .bt_mode = IWN_BT_SIMPLE, + .plcp_err_threshold = IWN_PLCP_ERR_LONG_THRESHOLD, +}; + +#endif /* __IF_IWN_CHIP_CFG_H__ */ diff --git a/sys/dev/iwn/if_iwn_debug.h b/sys/dev/iwn/if_iwn_debug.h new file mode 100644 index 0000000..2932c7e --- /dev/null +++ b/sys/dev/iwn/if_iwn_debug.h @@ -0,0 +1,123 @@ +/*- + * Copyright (c) 2013 Cedric GROSS <c.gross@kreiz-it.fr> + * Copyright (c) 2011 Intel Corporation + * Copyright (c) 2007-2009 + * Damien Bergamini <damien.bergamini@free.fr> + * Copyright (c) 2008 + * Benjamin Close <benjsc@FreeBSD.org> + * Copyright (c) 2008 Sam Leffler, Errno Consulting + * + * 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. + * + * $FreeBSD$ + */ + +#ifndef __IF_IWN_DEBUG_H__ +#define __IF_IWN_DEBUG_H__ + +#ifdef IWN_DEBUG +enum { + IWN_DEBUG_XMIT = 0x00000001, /* basic xmit operation */ + IWN_DEBUG_RECV = 0x00000002, /* basic recv operation */ + IWN_DEBUG_STATE = 0x00000004, /* 802.11 state transitions */ + IWN_DEBUG_TXPOW = 0x00000008, /* tx power processing */ + IWN_DEBUG_RESET = 0x00000010, /* reset processing */ + IWN_DEBUG_OPS = 0x00000020, /* iwn_ops processing */ + IWN_DEBUG_BEACON = 0x00000040, /* beacon handling */ + IWN_DEBUG_WATCHDOG = 0x00000080, /* watchdog timeout */ + IWN_DEBUG_INTR = 0x00000100, /* ISR */ + IWN_DEBUG_CALIBRATE = 0x00000200, /* periodic calibration */ + IWN_DEBUG_NODE = 0x00000400, /* node management */ + IWN_DEBUG_LED = 0x00000800, /* led management */ + IWN_DEBUG_CMD = 0x00001000, /* cmd submission */ + IWN_DEBUG_TXRATE = 0x00002000, /* TX rate debugging */ + IWN_DEBUG_PWRSAVE = 0x00004000, /* Power save operations */ + IWN_DEBUG_SCAN = 0x00008000, /* Scan related operations */ + IWN_DEBUG_STATS = 0x00010000, /* Statistics updates */ + IWN_DEBUG_REGISTER = 0x20000000, /* print chipset register */ + IWN_DEBUG_TRACE = 0x40000000, /* Print begin and start driver function */ + IWN_DEBUG_FATAL = 0x80000000, /* fatal errors */ + IWN_DEBUG_ANY = 0xffffffff +}; + +#define DPRINTF(sc, m, fmt, ...) do { \ + if (sc->sc_debug & (m)) \ + printf(fmt, __VA_ARGS__); \ +} while (0) + +static const char * +iwn_intr_str(uint8_t cmd) +{ + switch (cmd) { + /* Notifications */ + case IWN_UC_READY: return "UC_READY"; + case IWN_ADD_NODE_DONE: return "ADD_NODE_DONE"; + case IWN_TX_DONE: return "TX_DONE"; + case IWN_START_SCAN: return "START_SCAN"; + case IWN_STOP_SCAN: return "STOP_SCAN"; + case IWN_RX_STATISTICS: return "RX_STATS"; + case IWN_BEACON_STATISTICS: return "BEACON_STATS"; + case IWN_STATE_CHANGED: return "STATE_CHANGED"; + case IWN_BEACON_MISSED: return "BEACON_MISSED"; + case IWN_RX_PHY: return "RX_PHY"; + case IWN_MPDU_RX_DONE: return "MPDU_RX_DONE"; + case IWN_RX_DONE: return "RX_DONE"; + + /* Command Notifications */ + case IWN_CMD_RXON: return "IWN_CMD_RXON"; + case IWN_CMD_RXON_ASSOC: return "IWN_CMD_RXON_ASSOC"; + case IWN_CMD_EDCA_PARAMS: return "IWN_CMD_EDCA_PARAMS"; + case IWN_CMD_TIMING: return "IWN_CMD_TIMING"; + case IWN_CMD_LINK_QUALITY: return "IWN_CMD_LINK_QUALITY"; + case IWN_CMD_SET_LED: return "IWN_CMD_SET_LED"; + case IWN5000_CMD_WIMAX_COEX: return "IWN5000_CMD_WIMAX_COEX"; + case IWN5000_CMD_CALIB_CONFIG: return "IWN5000_CMD_CALIB_CONFIG"; + case IWN5000_CMD_CALIB_RESULT: return "IWN5000_CMD_CALIB_RESULT"; + case IWN5000_CMD_CALIB_COMPLETE: return "IWN5000_CMD_CALIB_COMPLETE"; + case IWN_CMD_SET_POWER_MODE: return "IWN_CMD_SET_POWER_MODE"; + case IWN_CMD_SCAN: return "IWN_CMD_SCAN"; + case IWN_CMD_SCAN_RESULTS: return "IWN_CMD_SCAN_RESULTS"; + case IWN_CMD_TXPOWER: return "IWN_CMD_TXPOWER"; + case IWN_CMD_TXPOWER_DBM: return "IWN_CMD_TXPOWER_DBM"; + case IWN5000_CMD_TX_ANT_CONFIG: return "IWN5000_CMD_TX_ANT_CONFIG"; + case IWN_CMD_BT_COEX: return "IWN_CMD_BT_COEX"; + case IWN_CMD_SET_CRITICAL_TEMP: return "IWN_CMD_SET_CRITICAL_TEMP"; + case IWN_CMD_SET_SENSITIVITY: return "IWN_CMD_SET_SENSITIVITY"; + case IWN_CMD_PHY_CALIB: return "IWN_CMD_PHY_CALIB"; + + /* Bluetooth commands */ + case IWN_CMD_BT_COEX_PRIOTABLE: return "IWN_CMD_BT_COEX_PRIOTABLE"; + case IWN_CMD_BT_COEX_PROT: return "IWN_CMD_BT_COEX_PROT"; + case IWN_CMD_BT_COEX_NOTIF: return "IWN_CMD_BT_COEX_NOTIF"; + + /* PAN commands */ + case IWN_CMD_WIPAN_PARAMS: return "IWN_CMD_WIPAN_PARAMS"; + case IWN_CMD_WIPAN_RXON: return "IWN_CMD_WIPAN_RXON"; + case IWN_CMD_WIPAN_RXON_TIMING: return "IWN_CMD_WIPAN_RXON_TIMING"; + case IWN_CMD_WIPAN_RXON_ASSOC: return "IWN_CMD_WIPAN_RXON_ASSOC"; + case IWN_CMD_WIPAN_QOS_PARAM: return "IWN_CMD_WIPAN_QOS_PARAM"; + case IWN_CMD_WIPAN_WEPKEY: return "IWN_CMD_WIPAN_WEPKEY"; + case IWN_CMD_WIPAN_P2P_CHANNEL_SWITCH: + return "IWN_CMD_WIPAN_P2P_CHANNEL_SWITCH"; + case IWN_CMD_WIPAN_NOA_NOTIFICATION: + return "IWN_CMD_WIPAN_NOA_NOTIFICATION"; + case IWN_CMD_WIPAN_DEACTIVATION_COMPLETE: + return "IWN_CMD_WIPAN_DEACTIVATION_COMPLETE"; + } + return "UNKNOWN INTR NOTIF/CMD"; +} +#else +#define DPRINTF(sc, m, fmt, ...) do { (void) sc; } while (0) +#endif + +#endif /* __IF_IWN_DEBUG_H__ */ diff --git a/sys/dev/iwn/if_iwn_devid.h b/sys/dev/iwn/if_iwn_devid.h index 23fd0a1..dd08737 100644 --- a/sys/dev/iwn/if_iwn_devid.h +++ b/sys/dev/iwn/if_iwn_devid.h @@ -41,6 +41,20 @@ * DEVICE ID BLOCK * ========================================================================== */ + +/* + * -------------------------------------------------------------------------- + * Device ID for 2x00 series + * -------------------------------------------------------------------------- + */ +#define IWN_DID_2x00_1 0x0890 +#define IWN_DID_2x00_2 0x0891 +/* SubDevice ID */ +#define IWN_SDID_2x00_1 0x4022 +#define IWN_SDID_2x00_2 0x4222 +#define IWN_SDID_2x00_3 0x4422 +#define IWN_SDID_2x00_4 0x4822 + /* * -------------------------------------------------------------------------- * Device ID for 2x30 series @@ -214,6 +228,31 @@ /* * -------------------------------------------------------------------------- + * Device ID for 105 Series + * -------------------------------------------------------------------------- + */ +#define IWN_DID_105_1 0x0894 +#define IWN_DID_105_2 0x0895 +/* SubDevice ID */ +#define IWN_SDID_105_1 0x0022 +#define IWN_SDID_105_2 0x0222 +#define IWN_SDID_105_3 0x0422 +#define IWN_SDID_105_4 0x0822 + +/* + * -------------------------------------------------------------------------- + * Device ID for 135 Series + * -------------------------------------------------------------------------- + */ +#define IWN_DID_135_1 0x0892 +#define IWN_DID_135_2 0x0893 +/* SubDevice ID */ +#define IWN_SDID_135_1 0x0062 +#define IWN_SDID_135_2 0x0262 +#define IWN_SDID_135_3 0x0462 + +/* + * -------------------------------------------------------------------------- * Device ID for 5x00 Series * -------------------------------------------------------------------------- */ diff --git a/sys/dev/iwn/if_iwn_ioctl.h b/sys/dev/iwn/if_iwn_ioctl.h new file mode 100644 index 0000000..1acf464 --- /dev/null +++ b/sys/dev/iwn/if_iwn_ioctl.h @@ -0,0 +1,25 @@ +/*- + * Copyright (c) 2014 Adrian Chadd <adrian@FreeBSD.org> + * + * 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. + * + * $FreeBSD$ + */ +#ifndef __IF_IWN_IOCTL_H__ +#define __IF_IWN_IOCTL_H__ + +/* XXX how should I pick appropriate ioctl numbers? */ +#define SIOCGIWNSTATS _IOWR('i', 145, struct ifreq) +#define SIOCZIWNSTATS _IOWR('i', 146, struct ifreq) + +#endif /* __IF_IWN_IOCTL_H__ */ diff --git a/sys/dev/iwn/if_iwnreg.h b/sys/dev/iwn/if_iwnreg.h index e61d0fd..ed65c0b 100644 --- a/sys/dev/iwn/if_iwnreg.h +++ b/sys/dev/iwn/if_iwnreg.h @@ -17,6 +17,8 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#ifndef __IF_IWNREG_H__ +#define __IF_IWNREG_H__ #define IWN_CT_KILL_THRESHOLD 114 /* in Celsius */ #define IWN_CT_KILL_EXIT_THRESHOLD 95 /* in Celsius */ @@ -222,6 +224,7 @@ #define IWN_GP_DRIVER_CALIB_VER6 (1 << 2) #define IWN_GP_DRIVER_6050_1X2 (1 << 3) #define IWN_GP_DRIVER_REG_BIT_RADIO_IQ_INVERT (1 << 7) +#define IWN_GP_DRIVER_NONE 0 /* Possible flags for register IWN_UCODE_GP1_CLR. */ #define IWN_UCODE_GP1_RFKILL (1 << 1) @@ -486,6 +489,7 @@ struct iwn_tx_cmd { #define IWN_CMD_TXPOWER_DBM 149 #define IWN_CMD_TXPOWER 151 #define IWN5000_CMD_TX_ANT_CONFIG 152 +#define IWN_CMD_TXPOWER_DBM_V1 152 #define IWN_CMD_BT_COEX 155 #define IWN_CMD_GET_STATISTICS 156 #define IWN_CMD_SET_CRITICAL_TEMP 164 @@ -882,7 +886,7 @@ struct iwn_scan_essid { struct iwn_scan_hdr { uint16_t len; - uint8_t reserved1; + uint8_t scan_flags; uint8_t nchan; uint16_t quiet_time; uint16_t quiet_threshold; @@ -919,17 +923,53 @@ struct iwn_scan_chan { /* Maximum size of a scan command. */ #define IWN_SCAN_MAXSZ (MCLBYTES - 4) -#define IWN_ACTIVE_DWELL_TIME_24 (30) /* all times in msec */ -#define IWN_ACTIVE_DWELL_TIME_52 (20) -#define IWN_ACTIVE_DWELL_FACTOR_24 (3) -#define IWN_ACTIVE_DWELL_FACTOR_52 (2) +/* + * For active scan, listen ACTIVE_DWELL_TIME (msec) on each channel after + * sending probe req. This should be set long enough to hear probe responses + * from more than one AP. + */ +#define IWN_ACTIVE_DWELL_TIME_2GHZ (30) /* all times in msec */ +#define IWN_ACTIVE_DWELL_TIME_5GHZ (20) +#define IWN_ACTIVE_DWELL_FACTOR_2GHZ (3) +#define IWN_ACTIVE_DWELL_FACTOR_5GHZ (2) -#define IWN_PASSIVE_DWELL_TIME_24 (20) /* all times in msec */ -#define IWN_PASSIVE_DWELL_TIME_52 (10) +/* + * For passive scan, listen PASSIVE_DWELL_TIME (msec) on each channel. + * Must be set longer than active dwell time. + * For the most reliable scan, set > AP beacon interval (typically 100msec). + */ +#define IWN_PASSIVE_DWELL_TIME_2GHZ (20) /* all times in msec */ +#define IWN_PASSIVE_DWELL_TIME_5GHZ (10) #define IWN_PASSIVE_DWELL_BASE (100) #define IWN_CHANNEL_TUNE_TIME (5) #define IWN_SCAN_CHAN_TIMEOUT 2 +#define IWN_MAX_SCAN_CHANNEL 50 + +/* + * If active scanning is requested but a certain channel is + * marked passive, we can do active scanning if we detect + * transmissions. + * + * There is an issue with some firmware versions that triggers + * a sysassert on a "good CRC threshold" of zero (== disabled), + * on a radar channel even though this means that we should NOT + * send probes. + * + * The "good CRC threshold" is the number of frames that we + * need to receive during our dwell time on a channel before + * sending out probes -- setting this to a huge value will + * mean we never reach it, but at the same time work around + * the aforementioned issue. Thus use IWL_GOOD_CRC_TH_NEVER + * here instead of IWL_GOOD_CRC_TH_DISABLED. + * + * This was fixed in later versions along with some other + * scan changes, and the threshold behaves as a flag in those + * versions. + */ +#define IWN_GOOD_CRC_TH_DISABLED 0 +#define IWN_GOOD_CRC_TH_DEFAULT htole16(1) +#define IWN_GOOD_CRC_TH_NEVER htole16(0xffff) /* Structure for command IWN_CMD_TXPOWER (4965AGN only.) */ #define IWN_RIDX_MAX 32 @@ -1102,6 +1142,12 @@ struct iwn_enhanced_sensitivity_cmd { uint16_t reserved; } __packed; +/* + * Define maximal number of calib result send to runtime firmware + * PS: TEMP_OFFSET count for 2 (std and v2) + */ +#define IWN5000_PHY_CALIB_MAX_RESULT 8 + /* Structures for command IWN_CMD_PHY_CALIB. */ struct iwn_phy_calib { uint8_t code; @@ -1221,17 +1267,91 @@ struct iwn_ucode_info { } __packed; /* Structures for IWN_TX_DONE notification. */ -#define IWN_TX_STATUS_MSK 0xff -#define TX_STATUS_SUCCESS 0x01 -#define TX_STATUS_DIRECT_DONE 0x02 - -#define IWN_TX_SUCCESS 0x00 -#define IWN_TX_FAIL 0x80 /* all failures have 0x80 set */ -#define IWN_TX_FAIL_SHORT_LIMIT 0x82 /* too many RTS retries */ -#define IWN_TX_FAIL_LONG_LIMIT 0x83 /* too many retries */ -#define IWN_TX_FAIL_FIFO_UNDERRRUN 0x84 /* tx fifo not kept running */ -#define IWN_TX_FAIL_DEST_IN_PS 0x88 /* sta found in power save */ -#define IWN_TX_FAIL_TX_LOCKED 0x90 /* waiting to see traffic */ + +/* + * TX command response is sent after *agn* transmission attempts. + * + * both postpone and abort status are expected behavior from uCode. there is + * no special operation required from driver; except for RFKILL_FLUSH, + * which required tx flush host command to flush all the tx frames in queues + */ +#define IWN_TX_STATUS_MSK 0x000000ff +#define IWN_TX_STATUS_DELAY_MSK 0x00000040 +#define IWN_TX_STATUS_ABORT_MSK 0x00000080 +#define IWN_TX_PACKET_MODE_MSK 0x0000ff00 +#define IWN_TX_FIFO_NUMBER_MSK 0x00070000 +#define IWN_TX_RESERVED 0x00780000 +#define IWN_TX_POWER_PA_DETECT_MSK 0x7f800000 +#define IWN_TX_ABORT_REQUIRED_MSK 0x80000000 + +/* Success status */ +#define IWN_TX_STATUS_SUCCESS 0x01 +#define IWN_TX_STATUS_DIRECT_DONE 0x02 + +/* postpone TX */ +#define IWN_TX_STATUS_POSTPONE_DELAY 0x40 +#define IWN_TX_STATUS_POSTPONE_FEW_BYTES 0x41 +#define IWN_TX_STATUS_POSTPONE_BT_PRIO 0x42 +#define IWN_TX_STATUS_POSTPONE_QUIET_PERIOD 0x43 +#define IWN_TX_STATUS_POSTPONE_CALC_TTAK 0x44 + +/* Failures */ +#define IWN_TX_FAIL 0x80 /* all failures have 0x80 set */ +#define IWN_TX_STATUS_FAIL_INTERNAL_CROSSED_RETRY 0x81 +#define IWN_TX_FAIL_SHORT_LIMIT 0x82 /* too many RTS retries */ +#define IWN_TX_FAIL_LONG_LIMIT 0x83 /* too many retries */ +#define IWN_TX_FAIL_FIFO_UNDERRRUN 0x84 /* tx fifo not kept running */ +#define IWN_TX_STATUS_FAIL_DRAIN_FLOW 0x85 +#define IWN_TX_STATUS_FAIL_RFKILL_FLUSH 0x86 +#define IWN_TX_STATUS_FAIL_LIFE_EXPIRE 0x87 +#define IWN_TX_FAIL_DEST_IN_PS 0x88 /* sta found in power save */ +#define IWN_TX_STATUS_FAIL_HOST_ABORTED 0x89 +#define IWN_TX_STATUS_FAIL_BT_RETRY 0x8a +#define IWN_TX_FAIL_STA_INVALID 0x8b /* XXX STA invalid (???) */ +#define IWN_TX_STATUS_FAIL_FRAG_DROPPED 0x8c +#define IWN_TX_STATUS_FAIL_TID_DISABLE 0x8d +#define IWN_TX_STATUS_FAIL_FIFO_FLUSHED 0x8e +#define IWN_TX_STATUS_FAIL_INSUFFICIENT_CF_POLL 0x8f +#define IWN_TX_FAIL_TX_LOCKED 0x90 /* waiting to see traffic */ +#define IWN_TX_STATUS_FAIL_NO_BEACON_ON_RADAR 0x91 + +/* + * TX command response for A-MPDU packet responses. + * + * The status response is different to the non A-MPDU responses. + * In addition, the sequence number is treated as the sequence + * number of the TX command, NOT the 802.11 sequence number! + */ +#define IWN_AGG_TX_STATE_TRANSMITTED 0x00 +#define IWN_AGG_TX_STATE_UNDERRUN_MSK 0x01 +#define IWN_AGG_TX_STATE_FEW_BYTES_MSK 0x04 +#define IWN_AGG_TX_STATE_ABORT_MSK 0x08 + +#define IWN_AGG_TX_STATE_LAST_SENT_TTL_MSK 0x10 +#define IWN_AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK 0x20 + +#define IWN_AGG_TX_STATE_SCD_QUERY_MSK 0x80 + +#define IWN_AGG_TX_STATE_TEST_BAD_CRC32_MSK 0x100 + +#define IWN_AGG_TX_STATE_RESPONSE_MSK 0x1ff +#define IWN_AGG_TX_STATE_DUMP_TX_MSK 0x200 +#define IWN_AGG_TX_STATE_DELAY_TX_MSK 0x400 + +#define IWN_AGG_TX_STATUS_MSK 0x00000fff +#define IWN_AGG_TX_TRY_MSK 0x0000f000 + +#define IWN_AGG_TX_STATE_LAST_SENT_MSK \ + (IWN_AGG_TX_STATE_LAST_SENT_TTL_MSK | \ + IWN_AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK) + +/* # tx attempts for first frame in aggregation */ +#define IWN_AGG_TX_STATE_TRY_CNT_POS 12 +#define IWN_AGG_TX_STATE_TRY_CNT_MSK 0xf000 + +/* Command ID and sequence number of Tx command for this frame */ +#define IWN_AGG_TX_STATE_SEQ_NUM_POS 16 +#define IWN_AGG_TX_STATE_SEQ_NUM_MSK 0xffff0000 struct iwn4965_tx_stat { uint8_t nframes; @@ -1358,6 +1478,12 @@ struct iwn_compressed_ba { uint64_t bitmap; uint16_t qid; uint16_t ssn; + /* extra fields starting with iwn5000 */ +#if 0 + uint8_t txed; /* number of frames sent */ + uint8_t txed_2_done; /* number of frames acked */ + uint16_t reserved1; +#endif } __packed; /* Structure for IWN_START_SCAN notification. */ @@ -1463,7 +1589,7 @@ struct iwn_rx_ht_phy_stats { uint32_t good_ampdu_crc32; uint32_t ampdu; uint32_t fragment; - uint32_t reserved; + uint32_t unsupport_mcs; } __packed; struct iwn_rx_stats { @@ -1473,6 +1599,20 @@ struct iwn_rx_stats { struct iwn_rx_ht_phy_stats ht; } __packed; +struct iwn_rx_general_stats_bt { + struct iwn_rx_general_stats common; + /* additional stats for bt */ + uint32_t num_bt_kills; + uint32_t reserved[2]; +} __packed; + +struct iwn_rx_stats_bt { + struct iwn_rx_phy_stats ofdm; + struct iwn_rx_phy_stats cck; + struct iwn_rx_general_stats_bt general_bt; + struct iwn_rx_ht_phy_stats ht; +} __packed; + struct iwn_tx_stats { uint32_t preamble; uint32_t rx_detected; @@ -1484,7 +1624,7 @@ struct iwn_tx_stats { uint32_t exp_ack; uint32_t ack; uint32_t msdu; - uint32_t busrt_err1; + uint32_t burst_err1; uint32_t burst_err2; uint32_t cts_collision; uint32_t ack_collision; @@ -1498,15 +1638,21 @@ struct iwn_tx_stats { uint32_t underrun; uint32_t bt_ht_kill; uint32_t rx_ba_resp; - uint32_t reserved[2]; + /* + * 6000 series only - LSB=ant A, ant B, ant C, MSB=reserved + * TX power on chain in 1/2 dBm. + */ + uint32_t tx_power; + uint32_t reserved[1]; } __packed; struct iwn_general_stats { - uint32_t temp; - uint32_t temp_m; + uint32_t temp; /* radio temperature */ + uint32_t temp_m; /* radio voltage */ uint32_t burst_check; uint32_t burst; - uint32_t reserved1[4]; + uint32_t wait_for_silence_timeout_cnt; + uint32_t reserved1[3]; uint32_t sleep; uint32_t slot_out; uint32_t slot_idle; @@ -1517,7 +1663,11 @@ struct iwn_general_stats { uint32_t probe; uint32_t reserved2[2]; uint32_t rx_enabled; - uint32_t reserved3[3]; + /* + * This is the number of times we have to re-tune + * in order to get out of bad PHY status. + */ + uint32_t num_of_sos_states; } __packed; struct iwn_stats { @@ -1525,8 +1675,30 @@ struct iwn_stats { struct iwn_rx_stats rx; struct iwn_tx_stats tx; struct iwn_general_stats general; + uint32_t reserved1[2]; } __packed; +struct iwn_bt_activity_stats { + /* Tx statistics */ + uint32_t hi_priority_tx_req_cnt; + uint32_t hi_priority_tx_denied_cnt; + uint32_t lo_priority_tx_req_cnt; + uint32_t lo_priority_tx_denied_cnt; + /* Rx statistics */ + uint32_t hi_priority_rx_req_cnt; + uint32_t hi_priority_rx_denied_cnt; + uint32_t lo_priority_rx_req_cnt; + uint32_t lo_priority_rx_denied_cnt; +} __packed; + +struct iwn_stats_bt { + uint32_t flags; + struct iwn_rx_stats_bt rx_bt; + struct iwn_tx_stats tx; + struct iwn_general_stats general; + struct iwn_bt_activity_stats activity; + uint32_t reserved1[2]; +}; /* Firmware error dump. */ struct iwn_fw_dump { @@ -1564,7 +1736,7 @@ struct iwn_fw_tlv { #define IWN_FW_TLV_INIT_DATA 4 #define IWN_FW_TLV_BOOT_TEXT 5 #define IWN_FW_TLV_PBREQ_MAXLEN 6 -#define IWN_FW_TLV_PAN 7 +#define IWN_FW_TLV_PAN 7 #define IWN_FW_TLV_RUNT_EVTLOG_PTR 8 #define IWN_FW_TLV_RUNT_EVTLOG_SIZE 9 #define IWN_FW_TLV_RUNT_ERRLOG_PTR 10 @@ -1575,7 +1747,7 @@ struct iwn_fw_tlv { #define IWN_FW_TLV_PHY_CALIB 15 #define IWN_FW_TLV_WOWLAN_INST 16 #define IWN_FW_TLV_WOWLAN_DATA 17 -#define IWN_FW_TLV_FLAGS 18 +#define IWN_FW_TLV_FLAGS 18 uint16_t alt; uint32_t len; @@ -1590,6 +1762,60 @@ struct iwn_fw_tlv { #define IWN5000_FWSZ IWN5000_FW_TEXT_MAXSZ /* + * Microcode flags TLV (18.) + */ + +/** + * enum iwn_ucode_tlv_flag - ucode API flags + * @IWN_UCODE_TLV_FLAGS_PAN: This is PAN capable microcode; this previously + * was a separate TLV but moved here to save space. + * @IWN_UCODE_TLV_FLAGS_NEWSCAN: new uCode scan behaviour on hidden SSID, + * treats good CRC threshold as a boolean + * @IWN_UCODE_TLV_FLAGS_MFP: This uCode image supports MFP (802.11w). + * @IWN_UCODE_TLV_FLAGS_P2P: This uCode image supports P2P. + * @IWN_UCODE_TLV_FLAGS_DW_BC_TABLE: The SCD byte count table is in DWORDS + * @IWN_UCODE_TLV_FLAGS_UAPSD: This uCode image supports uAPSD + * @IWN_UCODE_TLV_FLAGS_SHORT_BL: 16 entries of black list instead of 64 in scan + * offload profile config command. + * @IWN_UCODE_TLV_FLAGS_RX_ENERGY_API: supports rx signal strength api + * @IWN_UCODE_TLV_FLAGS_TIME_EVENT_API_V2: using the new time event API. + * @IWN_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS: D3 image supports up to six + * (rather than two) IPv6 addresses + * @IWN_UCODE_TLV_FLAGS_BF_UPDATED: new beacon filtering API + * @IWN_UCODE_TLV_FLAGS_NO_BASIC_SSID: not sending a probe with the SSID element + * from the probe request template. + * @IWN_UCODE_TLV_FLAGS_D3_CONTINUITY_API: modified D3 API to allow keeping + * connection when going back to D0 + * @IWN_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL: new NS offload (small version) + * @IWN_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE: new NS offload (large version) + * @IWN_UCODE_TLV_FLAGS_SCHED_SCAN: this uCode image supports scheduled scan. + * @IWN_UCODE_TLV_FLAGS_STA_KEY_CMD: new ADD_STA and ADD_STA_KEY command API + * @IWN_UCODE_TLV_FLAGS_DEVICE_PS_CMD: support device wide power command + * containing CAM (Continuous Active Mode) indication. + */ +enum iwn_ucode_tlv_flag { + IWN_UCODE_TLV_FLAGS_PAN = (1 << 0), + IWN_UCODE_TLV_FLAGS_NEWSCAN = (1 << 1), + IWN_UCODE_TLV_FLAGS_MFP = (1 << 2), + IWN_UCODE_TLV_FLAGS_P2P = (1 << 3), + IWN_UCODE_TLV_FLAGS_DW_BC_TABLE = (1 << 4), + IWN_UCODE_TLV_FLAGS_NEWBT_COEX = (1 << 5), + IWN_UCODE_TLV_FLAGS_UAPSD = (1 << 6), + IWN_UCODE_TLV_FLAGS_SHORT_BL = (1 << 7), + IWN_UCODE_TLV_FLAGS_RX_ENERGY_API = (1 << 8), + IWN_UCODE_TLV_FLAGS_TIME_EVENT_API_V2 = (1 << 9), + IWN_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS = (1 << 10), + IWN_UCODE_TLV_FLAGS_BF_UPDATED = (1 << 11), + IWN_UCODE_TLV_FLAGS_NO_BASIC_SSID = (1 << 12), + IWN_UCODE_TLV_FLAGS_D3_CONTINUITY_API = (1 << 14), + IWN_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL = (1 << 15), + IWN_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE = (1 << 16), + IWN_UCODE_TLV_FLAGS_SCHED_SCAN = (1 << 17), + IWN_UCODE_TLV_FLAGS_STA_KEY_CMD = (1 << 19), + IWN_UCODE_TLV_FLAGS_DEVICE_PS_CMD = (1 << 20), +}; + +/* * Offsets into EEPROM. */ #define IWN_EEPROM_MAC 0x015 @@ -1731,6 +1957,16 @@ static const uint32_t iwn1000_regulatory_bands[IWN_NBANDS] = { IWN5000_EEPROM_NO_HT40, }; +static const uint32_t iwn2030_regulatory_bands[IWN_NBANDS] = { + IWN5000_EEPROM_BAND1, + IWN5000_EEPROM_BAND2, + IWN5000_EEPROM_BAND3, + IWN5000_EEPROM_BAND4, + IWN5000_EEPROM_BAND5, + IWN6000_EEPROM_BAND6, + IWN5000_EEPROM_BAND7 +}; + #define IWN_CHAN_BANDS_COUNT 7 #define IWN_MAX_CHAN_PER_BAND 14 static const struct iwn_chan_band { @@ -1757,8 +1993,8 @@ static const uint8_t iwn_bss_ac_to_queue[] = { static const uint8_t iwn_pan_ac_to_queue[] = { 5, 4, 6, 7, }; -#define IWN1000_OTP_NBLOCKS 3 -#define IWN6000_OTP_NBLOCKS 4 +#define IWN1000_OTP_NBLOCKS 3 +#define IWN6000_OTP_NBLOCKS 4 #define IWN6050_OTP_NBLOCKS 7 /* HW rate indices. */ @@ -1891,6 +2127,7 @@ struct iwn_sensitivity_limits { uint32_t min_energy_cck; uint32_t energy_cck; uint32_t energy_ofdm; + uint32_t barker_mrc; }; /* @@ -1905,7 +2142,8 @@ static const struct iwn_sensitivity_limits iwn4965_sensitivity_limits = { 200, 400, 97, 100, - 100 + 100, + 390 }; static const struct iwn_sensitivity_limits iwn5000_sensitivity_limits = { @@ -1917,7 +2155,8 @@ static const struct iwn_sensitivity_limits iwn5000_sensitivity_limits = { 170, 400, 95, 95, - 95 + 95, + 390 }; static const struct iwn_sensitivity_limits iwn5150_sensitivity_limits = { @@ -1929,7 +2168,8 @@ static const struct iwn_sensitivity_limits iwn5150_sensitivity_limits = { 170, 400, 95, 95, - 95 + 95, + 390, }; static const struct iwn_sensitivity_limits iwn1000_sensitivity_limits = { @@ -1941,7 +2181,8 @@ static const struct iwn_sensitivity_limits iwn1000_sensitivity_limits = { 170, 400, 95, 95, - 95 + 95, + 390, }; static const struct iwn_sensitivity_limits iwn6000_sensitivity_limits = { @@ -1953,9 +2194,24 @@ static const struct iwn_sensitivity_limits iwn6000_sensitivity_limits = { 160, 310, 97, 97, - 100 + 100, + 390 +}; + +static const struct iwn_sensitivity_limits iwn6235_sensitivity_limits = { + 105, 110, + 192, 232, + 80, 145, + 128, 232, + 125, 175, + 160, 310, + 100, + 110, + 110, + 336 }; + /* Get value from linux kernel 3.2.+ in Drivers/net/wireless/iwlwifi/iwl-2000.c*/ static const struct iwn_sensitivity_limits iwn2030_sensitivity_limits = { 105,110, @@ -2052,3 +2308,5 @@ static const char * const iwn_fw_errmsg[] = { #define IWN_BARRIER_READ_WRITE(sc) \ bus_space_barrier((sc)->sc_st, (sc)->sc_sh, 0, (sc)->sc_sz, \ BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE) + +#endif /* __IF_IWNREG_H__ */ diff --git a/sys/dev/iwn/if_iwnvar.h b/sys/dev/iwn/if_iwnvar.h index 11a233d..b14158b 100644 --- a/sys/dev/iwn/if_iwnvar.h +++ b/sys/dev/iwn/if_iwnvar.h @@ -163,6 +163,7 @@ struct iwn_calib_state { uint32_t bad_plcp_cck; uint32_t fa_cck; uint32_t low_fa; + uint32_t bad_plcp_ht; uint8_t cck_state; #define IWN_CCK_STATE_INIT 0 #define IWN_CCK_STATE_LOFA 1 @@ -249,6 +250,7 @@ struct iwn_softc { #define IWN_FLAG_ENH_SENS (1 << 7) #define IWN_FLAG_ADV_BTCOEX (1 << 8) #define IWN_FLAG_PAN_SUPPORT (1 << 9) +#define IWN_FLAG_BTCOEX (1 << 10) uint8_t hw_type; /* subdevice_id used to adjust configuration */ @@ -306,14 +308,20 @@ struct iwn_softc { struct task sc_reinit_task; struct task sc_radioon_task; struct task sc_radiooff_task; + struct task sc_panic_task; + /* Taskqueue */ + struct taskqueue *sc_tq; + + /* Calibration information */ struct callout calib_to; int calib_cnt; struct iwn_calib_state calib; + int last_calib_ticks; struct callout watchdog_to; struct callout ct_kill_exit_to; struct iwn_fw_info fw; - struct iwn_calib_info calibcmd[5]; + struct iwn_calib_info calibcmd[IWN5000_PHY_CALIB_MAX_RESULT]; uint32_t errptr; struct iwn_rx_stat last_rx_stat; @@ -324,6 +332,22 @@ struct iwn_softc { int ctx; struct ieee80211vap *ivap[IWN_NUM_RXON_CTX]; + /* General statistics */ + /* + * The statistics are reset after each channel + * change. So it may be zeroed after things like + * a background scan. + * + * So for now, this is just a cheap hack to + * expose the last received statistics dump + * via an ioctl(). Later versions of this + * could expose the last 'n' messages, or just + * provide a pipeline for the firmware responses + * via something like BPF. + */ + struct iwn_stats last_stat; + int last_stat_valid; + uint8_t uc_scan_progress; uint32_t rawtemp; int temp; @@ -358,6 +382,9 @@ struct iwn_softc { int sc_tx_timer; int sc_scan_timer; + /* Are we doing a scan? */ + int sc_is_scanning; + struct ieee80211_tx_ampdu *qid2tap[IWN5000_NTXQUEUES]; int (*sc_ampdu_rx_start)(struct ieee80211_node *, @@ -385,8 +412,11 @@ struct iwn_softc { */ int current_pwrsave_level; - /* For specifique params */ - struct iwn_base_params *base_params; + /* For specific params */ + const struct iwn_base_params *base_params; + +#define IWN_UCODE_API(ver) (((ver) & 0x0000FF00) >> 8) + uint32_t ucode_rev; }; #define IWN_LOCK_INIT(_sc) \ diff --git a/sys/net80211/ieee80211.c b/sys/net80211/ieee80211.c index db505ab..409ac72 100644 --- a/sys/net80211/ieee80211.c +++ b/sys/net80211/ieee80211.c @@ -39,6 +39,7 @@ __FBSDID("$FreeBSD$"); #include <sys/socket.h> #include <net/if.h> +#include <net/if_var.h> #include <net/if_dl.h> #include <net/if_media.h> #include <net/if_types.h> @@ -569,15 +570,9 @@ ieee80211_vap_attach(struct ieee80211vap *vap, ifp->if_baudrate = IF_Mbps(maxrate); ether_ifattach(ifp, vap->iv_myaddr); - if (vap->iv_opmode == IEEE80211_M_MONITOR) { - /* NB: disallow transmit */ - ifp->if_transmit = null_transmit; - ifp->if_output = null_output; - } else { - /* hook output method setup by ether_ifattach */ - vap->iv_output = ifp->if_output; - ifp->if_output = ieee80211_output; - } + /* hook output method setup by ether_ifattach */ + vap->iv_output = ifp->if_output; + ifp->if_output = ieee80211_output; /* NB: if_mtu set by ether_ifattach to ETHERMTU */ IEEE80211_LOCK(ic); @@ -1407,7 +1402,8 @@ ieee80211_media_status(struct ifnet *ifp, struct ifmediareq *imr) * rate only when running; otherwise we may have a mismatch * in which case the rate will not be convertible. */ - if (vap->iv_state == IEEE80211_S_RUN) { + if (vap->iv_state == IEEE80211_S_RUN || + vap->iv_state == IEEE80211_S_SLEEP) { imr->ifm_status |= IFM_ACTIVE; mode = ieee80211_chan2mode(ic->ic_curchan); } else @@ -1751,3 +1747,23 @@ ieee80211_mac_hash(const struct ieee80211com *ic, return c; } #undef mix + +char +ieee80211_channel_type_char(const struct ieee80211_channel *c) +{ + if (IEEE80211_IS_CHAN_ST(c)) + return 'S'; + if (IEEE80211_IS_CHAN_108A(c)) + return 'T'; + if (IEEE80211_IS_CHAN_108G(c)) + return 'G'; + if (IEEE80211_IS_CHAN_HT(c)) + return 'n'; + if (IEEE80211_IS_CHAN_A(c)) + return 'a'; + if (IEEE80211_IS_CHAN_ANYG(c)) + return 'g'; + if (IEEE80211_IS_CHAN_B(c)) + return 'b'; + return 'f'; +} diff --git a/sys/net80211/ieee80211_action.c b/sys/net80211/ieee80211_action.c index a36df7c..e37863e 100644 --- a/sys/net80211/ieee80211_action.c +++ b/sys/net80211/ieee80211_action.c @@ -42,6 +42,7 @@ __FBSDID("$FreeBSD$"); #include <sys/socket.h> #include <net/if.h> +#include <net/if_var.h> #include <net/if_media.h> #include <net/ethernet.h> diff --git a/sys/net80211/ieee80211_adhoc.c b/sys/net80211/ieee80211_adhoc.c index e9e0d30..181b922 100644 --- a/sys/net80211/ieee80211_adhoc.c +++ b/sys/net80211/ieee80211_adhoc.c @@ -48,6 +48,7 @@ __FBSDID("$FreeBSD$"); #include <sys/sysctl.h> #include <net/if.h> +#include <net/if_var.h> #include <net/if_media.h> #include <net/if_llc.h> #include <net/ethernet.h> diff --git a/sys/net80211/ieee80211_ageq.c b/sys/net80211/ieee80211_ageq.c index 018ddc2..b650136 100644 --- a/sys/net80211/ieee80211_ageq.c +++ b/sys/net80211/ieee80211_ageq.c @@ -38,6 +38,7 @@ __FBSDID("$FreeBSD$"); #include <sys/socket.h> #include <net/if.h> +#include <net/if_var.h> #include <net/if_media.h> #include <net/ethernet.h> diff --git a/sys/net80211/ieee80211_alq.c b/sys/net80211/ieee80211_alq.c index e651574..a52103a 100644 --- a/sys/net80211/ieee80211_alq.c +++ b/sys/net80211/ieee80211_alq.c @@ -53,10 +53,8 @@ __FBSDID("$FreeBSD$"); #include <net/if.h> #include <net/if_var.h> -#include <net/if_dl.h> -#include <net/if_clone.h> #include <net/if_media.h> -#include <net/if_types.h> +#include <net/ethernet.h> #include <net80211/ieee80211_var.h> #include <net80211/ieee80211_freebsd.h> diff --git a/sys/net80211/ieee80211_amrr.c b/sys/net80211/ieee80211_amrr.c index 003b4bc..b1d92c8 100644 --- a/sys/net80211/ieee80211_amrr.c +++ b/sys/net80211/ieee80211_amrr.c @@ -38,7 +38,9 @@ __FBSDID("$FreeBSD$"); #include <sys/sysctl.h> #include <net/if.h> +#include <net/if_var.h> #include <net/if_media.h> +#include <net/ethernet.h> #ifdef INET #include <netinet/in.h> @@ -129,6 +131,12 @@ amrr_deinit(struct ieee80211vap *vap) free(vap->iv_rs, M_80211_RATECTL); } +/* + * Return whether 11n rates are possible. + * + * Some 11n devices may return HT information but no HT rates. + * Thus, we shouldn't treat them as an 11n node. + */ static int amrr_node_is_11n(struct ieee80211_node *ni) { @@ -137,6 +145,8 @@ amrr_node_is_11n(struct ieee80211_node *ni) return (0); if (ni->ni_chan == IEEE80211_CHAN_ANYC) return (0); + if (IEEE80211_IS_CHAN_HT(ni->ni_chan) && ni->ni_htrates.rs_nrates == 0) + return (0); return (IEEE80211_IS_CHAN_HT(ni->ni_chan)); } @@ -185,17 +195,18 @@ amrr_node_init(struct ieee80211_node *ni) rate &= IEEE80211_RATE_VAL; /* pick initial rate from the rateset - HT or otherwise */ + /* Pick something low that's likely to succeed */ for (amn->amn_rix = rs->rs_nrates - 1; amn->amn_rix > 0; amn->amn_rix--) { /* legacy - anything < 36mbit, stop searching */ - /* 11n - stop at MCS4 / MCS12 / MCS28 */ - if (amrr_node_is_11n(ni) && - (rs->rs_rates[amn->amn_rix] & 0x7) < 4) - break; - else if ((rs->rs_rates[amn->amn_rix] & IEEE80211_RATE_VAL) <= 72) + /* 11n - stop at MCS4 */ + if (amrr_node_is_11n(ni)) { + if ((rs->rs_rates[amn->amn_rix] & 0x1f) < 4) + break; + } else if ((rs->rs_rates[amn->amn_rix] & IEEE80211_RATE_VAL) <= 72) break; - rate = rs->rs_rates[amn->amn_rix] & IEEE80211_RATE_VAL; } + rate = rs->rs_rates[amn->amn_rix] & IEEE80211_RATE_VAL; /* if the rate is an 11n rate, ensure the MCS bit is set */ if (amrr_node_is_11n(ni)) diff --git a/sys/net80211/ieee80211_ddb.c b/sys/net80211/ieee80211_ddb.c index 6f7dabf..74e82e5 100644 --- a/sys/net80211/ieee80211_ddb.c +++ b/sys/net80211/ieee80211_ddb.c @@ -39,6 +39,7 @@ __FBSDID("$FreeBSD$"); #include <sys/socket.h> #include <net/if.h> +#include <net/if_var.h> #include <net/if_dl.h> #include <net/if_media.h> #include <net/if_types.h> diff --git a/sys/net80211/ieee80211_dfs.c b/sys/net80211/ieee80211_dfs.c index 82e525d..5fa9ba4 100644 --- a/sys/net80211/ieee80211_dfs.c +++ b/sys/net80211/ieee80211_dfs.c @@ -48,7 +48,9 @@ __FBSDID("$FreeBSD$"); #include <sys/sysctl.h> #include <net/if.h> +#include <net/if_var.h> #include <net/if_media.h> +#include <net/ethernet.h> #include <net80211/ieee80211_var.h> diff --git a/sys/net80211/ieee80211_freebsd.c b/sys/net80211/ieee80211_freebsd.c index 8c97f1e..ab5b26e 100644 --- a/sys/net80211/ieee80211_freebsd.c +++ b/sys/net80211/ieee80211_freebsd.c @@ -44,6 +44,7 @@ __FBSDID("$FreeBSD$"); #include <net/bpf.h> #include <net/if.h> +#include <net/if_var.h> #include <net/if_dl.h> #include <net/if_clone.h> #include <net/if_media.h> diff --git a/sys/net80211/ieee80211_hostap.c b/sys/net80211/ieee80211_hostap.c index 832a8b0..8cb97b0 100644 --- a/sys/net80211/ieee80211_hostap.c +++ b/sys/net80211/ieee80211_hostap.c @@ -48,6 +48,7 @@ __FBSDID("$FreeBSD$"); #include <sys/sysctl.h> #include <net/if.h> +#include <net/if_var.h> #include <net/if_media.h> #include <net/if_llc.h> #include <net/ethernet.h> diff --git a/sys/net80211/ieee80211_ht.c b/sys/net80211/ieee80211_ht.c index 7f41b27..5fe2e80 100644 --- a/sys/net80211/ieee80211_ht.c +++ b/sys/net80211/ieee80211_ht.c @@ -43,6 +43,7 @@ __FBSDID("$FreeBSD$"); #include <sys/socket.h> #include <net/if.h> +#include <net/if_var.h> #include <net/if_media.h> #include <net/ethernet.h> @@ -154,7 +155,7 @@ SYSCTL_PROC(_net_wlan, OID_AUTO, addba_backoff, CTLTYPE_INT | CTLFLAG_RW, &ieee80211_addba_backoff, 0, ieee80211_sysctl_msecs_ticks, "I", "ADDBA request backoff (ms)"); static int ieee80211_addba_maxtries = 3;/* max ADDBA requests before backoff */ -SYSCTL_INT(_net_wlan, OID_AUTO, addba_maxtries, CTLTYPE_INT | CTLFLAG_RW, +SYSCTL_INT(_net_wlan, OID_AUTO, addba_maxtries, CTLFLAG_RW, &ieee80211_addba_maxtries, 0, "max ADDBA requests sent before backoff"); static int ieee80211_bar_timeout = -1; /* timeout waiting for BAR response */ @@ -1046,6 +1047,7 @@ ieee80211_ht_node_init(struct ieee80211_node *ni) tap = &ni->ni_tx_ampdu[tid]; tap->txa_tid = tid; tap->txa_ni = ni; + tap->txa_lastsample = ticks; /* NB: further initialization deferred */ } ni->ni_flags |= IEEE80211_NODE_HT | IEEE80211_NODE_AMPDU; @@ -1215,6 +1217,7 @@ ieee80211_ht_wds_init(struct ieee80211_node *ni) for (tid = 0; tid < WME_NUM_TID; tid++) { tap = &ni->ni_tx_ampdu[tid]; tap->txa_tid = tid; + tap->txa_lastsample = ticks; } /* NB: AMPDU tx/rx governed by IEEE80211_FHT_AMPDU_{TX,RX} */ ni->ni_flags |= IEEE80211_NODE_HT | IEEE80211_NODE_AMPDU; @@ -1690,6 +1693,7 @@ ampdu_tx_setup(struct ieee80211_tx_ampdu *tap) { callout_init(&tap->txa_timer, CALLOUT_MPSAFE); tap->txa_flags |= IEEE80211_AGGR_SETUP; + tap->txa_lastsample = ticks; } static void @@ -1717,8 +1721,12 @@ ampdu_tx_stop(struct ieee80211_tx_ampdu *tap) */ bar_stop_timer(tap); - tap->txa_lastsample = 0; + /* + * Reset packet estimate. + */ + tap->txa_lastsample = ticks; tap->txa_avgpps = 0; + /* NB: clearing NAK means we may re-send ADDBA */ tap->txa_flags &= ~(IEEE80211_AGGR_SETUP | IEEE80211_AGGR_NAK); } diff --git a/sys/net80211/ieee80211_hwmp.c b/sys/net80211/ieee80211_hwmp.c index 751f1e7..8d57302 100644 --- a/sys/net80211/ieee80211_hwmp.c +++ b/sys/net80211/ieee80211_hwmp.c @@ -168,7 +168,7 @@ struct ieee80211_hwmp_state { static SYSCTL_NODE(_net_wlan, OID_AUTO, hwmp, CTLFLAG_RD, 0, "IEEE 802.11s HWMP parameters"); static int ieee80211_hwmp_targetonly = 0; -SYSCTL_INT(_net_wlan_hwmp, OID_AUTO, targetonly, CTLTYPE_INT | CTLFLAG_RW, +SYSCTL_INT(_net_wlan_hwmp, OID_AUTO, targetonly, CTLFLAG_RW, &ieee80211_hwmp_targetonly, 0, "Set TO bit on generated PREQs"); static int ieee80211_hwmp_pathtimeout = -1; SYSCTL_PROC(_net_wlan_hwmp, OID_AUTO, pathlifetime, CTLTYPE_INT | CTLFLAG_RW, diff --git a/sys/net80211/ieee80211_input.c b/sys/net80211/ieee80211_input.c index 5e95646..6ea4f9b 100644 --- a/sys/net80211/ieee80211_input.c +++ b/sys/net80211/ieee80211_input.c @@ -40,6 +40,7 @@ __FBSDID("$FreeBSD$"); #include <net/ethernet.h> #include <net/if.h> +#include <net/if_var.h> #include <net/if_llc.h> #include <net/if_media.h> #include <net/if_vlan_var.h> diff --git a/sys/net80211/ieee80211_ioctl.c b/sys/net80211/ieee80211_ioctl.c index 6b668cb..2798d80 100644 --- a/sys/net80211/ieee80211_ioctl.c +++ b/sys/net80211/ieee80211_ioctl.c @@ -32,7 +32,6 @@ __FBSDID("$FreeBSD$"); */ #include "opt_inet.h" -#include "opt_ipx.h" #include "opt_wlan.h" #include <sys/endian.h> @@ -44,6 +43,7 @@ __FBSDID("$FreeBSD$"); #include <sys/systm.h> #include <net/if.h> +#include <net/if_var.h> #include <net/if_dl.h> #include <net/if_media.h> #include <net/ethernet.h> @@ -53,11 +53,6 @@ __FBSDID("$FreeBSD$"); #include <netinet/if_ether.h> #endif -#ifdef IPX -#include <netipx/ipx.h> -#include <netipx/ipx_if.h> -#endif - #include <net80211/ieee80211_var.h> #include <net80211/ieee80211_ioctl.h> #include <net80211/ieee80211_regdomain.h> @@ -607,7 +602,7 @@ ieee80211_ioctl_getcurchan(struct ieee80211vap *vap, struct ieee80211req *ireq) * in use. When in RUN state report the vap-specific channel. * Otherwise return curchan. */ - if (vap->iv_state == IEEE80211_S_RUN) + if (vap->iv_state == IEEE80211_S_RUN || vap->iv_state == IEEE80211_S_SLEEP) c = vap->iv_bss->ni_chan; else c = ic->ic_curchan; @@ -925,7 +920,7 @@ ieee80211_ioctl_get80211(struct ieee80211vap *vap, u_long cmd, case IEEE80211_IOC_BSSID: if (ireq->i_len != IEEE80211_ADDR_LEN) return EINVAL; - if (vap->iv_state == IEEE80211_S_RUN) { + if (vap->iv_state == IEEE80211_S_RUN || vap->iv_state == IEEE80211_S_SLEEP) { error = copyout(vap->iv_opmode == IEEE80211_M_WDS ? vap->iv_bss->ni_macaddr : vap->iv_bss->ni_bssid, ireq->i_data, ireq->i_len); @@ -1031,7 +1026,7 @@ ieee80211_ioctl_get80211(struct ieee80211vap *vap, u_long cmd, case IEEE80211_IOC_AMPDU_LIMIT: if (vap->iv_opmode == IEEE80211_M_HOSTAP) ireq->i_val = vap->iv_ampdu_rxmax; - else if (vap->iv_state == IEEE80211_S_RUN) + else if (vap->iv_state == IEEE80211_S_RUN || vap->iv_state == IEEE80211_S_SLEEP) ireq->i_val = MS(vap->iv_bss->ni_htparam, IEEE80211_HTCAP_MAXRXAMPDU); else @@ -1039,7 +1034,7 @@ ieee80211_ioctl_get80211(struct ieee80211vap *vap, u_long cmd, break; case IEEE80211_IOC_AMPDU_DENSITY: if (vap->iv_opmode == IEEE80211_M_STA && - vap->iv_state == IEEE80211_S_RUN) + (vap->iv_state == IEEE80211_S_RUN || vap->iv_state == IEEE80211_S_SLEEP)) ireq->i_val = MS(vap->iv_bss->ni_htparam, IEEE80211_HTCAP_MPDUDENSITY); else @@ -1113,7 +1108,7 @@ ieee80211_ioctl_get80211(struct ieee80211vap *vap, u_long cmd, break; case IEEE80211_IOC_SMPS: if (vap->iv_opmode == IEEE80211_M_STA && - vap->iv_state == IEEE80211_S_RUN) { + (vap->iv_state == IEEE80211_S_RUN || vap->iv_state == IEEE80211_S_SLEEP)) { if (vap->iv_bss->ni_flags & IEEE80211_NODE_MIMO_RTS) ireq->i_val = IEEE80211_HTCAP_SMPS_DYNAMIC; else if (vap->iv_bss->ni_flags & IEEE80211_NODE_MIMO_PS) @@ -1125,7 +1120,7 @@ ieee80211_ioctl_get80211(struct ieee80211vap *vap, u_long cmd, break; case IEEE80211_IOC_RIFS: if (vap->iv_opmode == IEEE80211_M_STA && - vap->iv_state == IEEE80211_S_RUN) + (vap->iv_state == IEEE80211_S_RUN || vap->iv_state == IEEE80211_S_SLEEP)) ireq->i_val = (vap->iv_bss->ni_flags & IEEE80211_NODE_RIFS) != 0; else @@ -1954,7 +1949,7 @@ setcurchan(struct ieee80211vap *vap, struct ieee80211_channel *c) if (IEEE80211_IS_CHAN_NOADHOC(c)) return EINVAL; } - if (vap->iv_state == IEEE80211_S_RUN && + if ((vap->iv_state == IEEE80211_S_RUN || vap->iv_state == IEEE80211_S_SLEEP) && vap->iv_bss->ni_chan == c) return 0; /* NB: nothing to do */ } @@ -3419,24 +3414,6 @@ ieee80211_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) arp_ifinit(ifp, ifa); break; #endif -#ifdef IPX - /* - * XXX - This code is probably wrong, - * but has been copied many times. - */ - case AF_IPX: { - struct ipx_addr *ina = &(IA_SIPX(ifa)->sipx_addr); - - if (ipx_nullhost(*ina)) - ina->x_host = *(union ipx_host *) - IF_LLADDR(ifp); - else - bcopy((caddr_t) ina->x_host.c_host, - (caddr_t) IF_LLADDR(ifp), - ETHER_ADDR_LEN); - /* fall thru... */ - } -#endif default: if ((ifp->if_flags & IFF_UP) == 0) { ifp->if_flags |= IFF_UP; diff --git a/sys/net80211/ieee80211_mesh.c b/sys/net80211/ieee80211_mesh.c index 5cb80c3..89c024d 100644 --- a/sys/net80211/ieee80211_mesh.c +++ b/sys/net80211/ieee80211_mesh.c @@ -54,6 +54,7 @@ __FBSDID("$FreeBSD$"); #include <net/bpf.h> #include <net/if.h> +#include <net/if_var.h> #include <net/if_media.h> #include <net/if_llc.h> #include <net/ethernet.h> @@ -127,11 +128,11 @@ SYSCTL_PROC(_net_wlan_mesh, OID_AUTO, backofftimeout, CTLTYPE_INT | CTLFLAG_RW, "Backoff timeout (msec). This is to throutles peering forever when " "not receving answer or is rejected by a neighbor"); static int ieee80211_mesh_maxretries = 2; -SYSCTL_INT(_net_wlan_mesh, OID_AUTO, maxretries, CTLTYPE_INT | CTLFLAG_RW, +SYSCTL_INT(_net_wlan_mesh, OID_AUTO, maxretries, CTLFLAG_RW, &ieee80211_mesh_maxretries, 0, "Maximum retries during peer link establishment"); static int ieee80211_mesh_maxholding = 2; -SYSCTL_INT(_net_wlan_mesh, OID_AUTO, maxholding, CTLTYPE_INT | CTLFLAG_RW, +SYSCTL_INT(_net_wlan_mesh, OID_AUTO, maxholding, CTLFLAG_RW, &ieee80211_mesh_maxholding, 0, "Maximum times we are allowed to transition to HOLDING state before " "backinoff during peer link establishment"); @@ -2692,7 +2693,7 @@ mesh_send_action(struct ieee80211_node *ni, return EIO; /* XXX */ } - M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT); + M_PREPEND(m, sizeof(struct ieee80211_frame), M_NOWAIT); if (m == NULL) { ieee80211_free_node(ni); return ENOMEM; @@ -3333,7 +3334,7 @@ mesh_airtime_calc(struct ieee80211_node *ni) /* Error rate in percentage */ /* XXX assuming small failures are ok */ errrate = (((ifp->if_oerrors + - ifp->if_ierrors) / 100) << M_BITS) / 100; + ifp->if_ierrors) / 100) << M_BITS) / 100; res = (overhead + (nbits / rate)) * ((1 << S_FACTOR) / ((1 << M_BITS) - errrate)); diff --git a/sys/net80211/ieee80211_monitor.c b/sys/net80211/ieee80211_monitor.c index e324081..f52b0fb 100644 --- a/sys/net80211/ieee80211_monitor.c +++ b/sys/net80211/ieee80211_monitor.c @@ -48,6 +48,7 @@ __FBSDID("$FreeBSD$"); #include <sys/sysctl.h> #include <net/if.h> +#include <net/if_var.h> #include <net/if_media.h> #include <net/if_llc.h> #include <net/ethernet.h> diff --git a/sys/net80211/ieee80211_node.c b/sys/net80211/ieee80211_node.c index 4169255..9fc4cd4 100644 --- a/sys/net80211/ieee80211_node.c +++ b/sys/net80211/ieee80211_node.c @@ -38,6 +38,7 @@ __FBSDID("$FreeBSD$"); #include <sys/socket.h> #include <net/if.h> +#include <net/if_var.h> #include <net/if_media.h> #include <net/ethernet.h> diff --git a/sys/net80211/ieee80211_output.c b/sys/net80211/ieee80211_output.c index a1f9965..d828a35 100644 --- a/sys/net80211/ieee80211_output.c +++ b/sys/net80211/ieee80211_output.c @@ -42,6 +42,7 @@ __FBSDID("$FreeBSD$"); #include <net/bpf.h> #include <net/ethernet.h> #include <net/if.h> +#include <net/if_var.h> #include <net/if_llc.h> #include <net/if_media.h> #include <net/if_vlan_var.h> @@ -389,6 +390,19 @@ ieee80211_start_pkt(struct ieee80211vap *vap, struct mbuf *m) /* * We've resolved the sender, so attempt to transmit it. */ + + if (vap->iv_state == IEEE80211_S_SLEEP) { + /* + * In power save; queue frame and then wakeup device + * for transmit. + */ + ic->ic_lastdata = ticks; + (void) ieee80211_pwrsave(ni, m); + ieee80211_free_node(ni); + ieee80211_new_state(vap, IEEE80211_S_RUN, 0); + return (0); + } + if (ieee80211_vap_pkt_send_dest(vap, m, ni) != 0) return (ENOBUFS); return (0); @@ -419,24 +433,19 @@ ieee80211_vap_transmit(struct ifnet *ifp, struct mbuf *m) m_freem(m); return (EINVAL); } - if (vap->iv_state == IEEE80211_S_SLEEP) { - /* - * In power save, wakeup device for transmit. - */ - ieee80211_new_state(vap, IEEE80211_S_RUN, 0); - m_freem(m); - return (0); - } + /* * No data frames go out unless we're running. * Note in particular this covers CAC and CSA * states (though maybe we should check muting * for CSA). */ - if (vap->iv_state != IEEE80211_S_RUN) { + if (vap->iv_state != IEEE80211_S_RUN && + vap->iv_state != IEEE80211_S_SLEEP) { IEEE80211_LOCK(ic); /* re-check under the com lock to avoid races */ - if (vap->iv_state != IEEE80211_S_RUN) { + if (vap->iv_state != IEEE80211_S_RUN && + vap->iv_state != IEEE80211_S_SLEEP) { IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT, "%s: ignore queue, in %s state\n", __func__, ieee80211_state_name[vap->iv_state]); @@ -476,6 +485,13 @@ ieee80211_vap_qflush(struct ifnet *ifp) /* * 802.11 raw output routine. + * + * XXX TODO: this (and other send routines) should correctly + * XXX keep the pwr mgmt bit set if it decides to call into the + * XXX driver to send a frame whilst the state is SLEEP. + * + * Otherwise the peer may decide that we're awake and flood us + * with traffic we are still too asleep to receive! */ int ieee80211_raw_output(struct ieee80211vap *vap, struct ieee80211_node *ni, @@ -1686,7 +1702,7 @@ ieee80211_add_xrates(uint8_t *frm, const struct ieee80211_rateset *rs) /* * Add an ssid element to a frame. */ -static uint8_t * +uint8_t * ieee80211_add_ssid(uint8_t *frm, const uint8_t *ssid, u_int len) { *frm++ = IEEE80211_ELEMID_SSID; @@ -2306,18 +2322,33 @@ ieee80211_send_mgmt(struct ieee80211_node *ni, int type, int arg) ic->ic_curchan); frm = ieee80211_add_supportedchannels(frm, ic); } + + /* + * Check the channel - we may be using an 11n NIC with an + * 11n capable station, but we're configured to be an 11b + * channel. + */ if ((vap->iv_flags_ht & IEEE80211_FHT_HT) && + IEEE80211_IS_CHAN_HT(ni->ni_chan) && ni->ni_ies.htcap_ie != NULL && - ni->ni_ies.htcap_ie[0] == IEEE80211_ELEMID_HTCAP) + ni->ni_ies.htcap_ie[0] == IEEE80211_ELEMID_HTCAP) { frm = ieee80211_add_htcap(frm, ni); + } frm = ieee80211_add_wpa(frm, vap); if ((ic->ic_flags & IEEE80211_F_WME) && ni->ni_ies.wme_ie != NULL) frm = ieee80211_add_wme_info(frm, &ic->ic_wme); + + /* + * Same deal - only send HT info if we're on an 11n + * capable channel. + */ if ((vap->iv_flags_ht & IEEE80211_FHT_HT) && + IEEE80211_IS_CHAN_HT(ni->ni_chan) && ni->ni_ies.htcap_ie != NULL && - ni->ni_ies.htcap_ie[0] == IEEE80211_ELEMID_VENDOR) + ni->ni_ies.htcap_ie[0] == IEEE80211_ELEMID_VENDOR) { frm = ieee80211_add_htcap_vendor(frm, ni); + } #ifdef IEEE80211_SUPPORT_SUPERG if (IEEE80211_ATH_CAP(vap, ni, IEEE80211_F_ATHEROS)) { frm = ieee80211_add_ath(frm, diff --git a/sys/net80211/ieee80211_phy.c b/sys/net80211/ieee80211_phy.c index 923266c..4242ac0 100644 --- a/sys/net80211/ieee80211_phy.c +++ b/sys/net80211/ieee80211_phy.c @@ -35,12 +35,16 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/kernel.h> #include <sys/systm.h> +#include <sys/malloc.h> #include <sys/socket.h> #include <net/if.h> #include <net/if_media.h> +#include <net/ethernet.h> +#include <net/route.h> + #include <net80211/ieee80211_var.h> #include <net80211/ieee80211_phy.h> diff --git a/sys/net80211/ieee80211_power.c b/sys/net80211/ieee80211_power.c index 4542ec5..812cd70 100644 --- a/sys/net80211/ieee80211_power.c +++ b/sys/net80211/ieee80211_power.c @@ -38,6 +38,7 @@ __FBSDID("$FreeBSD$"); #include <sys/socket.h> #include <net/if.h> +#include <net/if_var.h> #include <net/if_media.h> #include <net/ethernet.h> @@ -554,3 +555,108 @@ ieee80211_sta_pwrsave(struct ieee80211vap *vap, int enable) ieee80211_send_nulldata(ieee80211_ref_node(ni)); } } + +/* + * Handle being notified that we have data available for us in a TIM/ATIM. + * + * This may schedule a transition from _SLEEP -> _RUN if it's appropriate. + * + * In STA mode, we may have put to sleep during scan and need to be dragged + * back out of powersave mode. + */ +void +ieee80211_sta_tim_notify(struct ieee80211vap *vap, int set) +{ + struct ieee80211com *ic = vap->iv_ic; + + /* + * Schedule the driver state change. It'll happen at some point soon. + * Since the hardware shouldn't know that we're running just yet + * (and thus tell the peer that we're awake before we actually wake + * up said hardware), we leave the actual node state transition + * up to the transition to RUN. + * + * XXX TODO: verify that the transition to RUN will wake up the + * BSS node! + */ + IEEE80211_LOCK(vap->iv_ic); + if (set == 1 && vap->iv_state == IEEE80211_S_SLEEP) { + ieee80211_new_state_locked(vap, IEEE80211_S_RUN, 0); + IEEE80211_DPRINTF(vap, IEEE80211_MSG_POWER, + "%s: TIM=%d; wakeup\n", __func__, set); + } else if ((set == 1) && (ic->ic_flags_ext & IEEE80211_FEXT_BGSCAN)) { + /* + * XXX only do this if we're in RUN state? + */ + IEEE80211_DPRINTF(vap, IEEE80211_MSG_POWER, + "%s: wake up from bgscan vap sleep\n", + __func__); + /* + * We may be in BGSCAN mode - this means the VAP is is in STA + * mode powersave. If it is, we need to wake it up so we + * can process outbound traffic. + */ + vap->iv_sta_ps(vap, 0); + } + IEEE80211_UNLOCK(vap->iv_ic); +} + +/* + * Timer check on whether the VAP has had any transmit activity. + * + * This may schedule a transition from _RUN -> _SLEEP if it's appropriate. + */ +void +ieee80211_sta_ps_timer_check(struct ieee80211vap *vap) +{ + struct ieee80211com *ic = vap->iv_ic; + + /* XXX lock assert */ + + /* For no, only do this in STA mode */ + if (! (vap->iv_caps & IEEE80211_C_SWSLEEP)) + goto out; + + if (vap->iv_opmode != IEEE80211_M_STA) + goto out; + + /* If we're not at run state, bail */ + if (vap->iv_state != IEEE80211_S_RUN) + goto out; + + IEEE80211_DPRINTF(vap, IEEE80211_MSG_POWER, + "%s: lastdata=%llu, ticks=%llu\n", + __func__, (unsigned long long) ic->ic_lastdata, + (unsigned long long) ticks); + + /* If powersave is disabled on the VAP, don't bother */ + if (! (vap->iv_flags & IEEE80211_F_PMGTON)) + goto out; + + /* If we've done any data within our idle interval, bail */ + /* XXX hard-coded to one second for now, ew! */ + if (time_after(ic->ic_lastdata + 500, ticks)) + goto out; + + /* + * Signify we're going into power save and transition the + * node to powersave. + */ + if ((vap->iv_bss->ni_flags & IEEE80211_NODE_PWR_MGT) == 0) + vap->iv_sta_ps(vap, 1); + + /* + * XXX The driver has to handle the fact that we're going + * to sleep but frames may still be transmitted; + * hopefully it and/or us will do the right thing and mark any + * transmitted frames with PWRMGT set to 1. + */ + ieee80211_new_state_locked(vap, IEEE80211_S_SLEEP, 0); + + IEEE80211_DPRINTF(vap, IEEE80211_MSG_POWER, + "%s: time delta=%d msec\n", __func__, + (int) ticks_to_msecs(ticks - ic->ic_lastdata)); + +out: + return; +} diff --git a/sys/net80211/ieee80211_power.h b/sys/net80211/ieee80211_power.h index 55270d2..d9bbaa5 100644 --- a/sys/net80211/ieee80211_power.h +++ b/sys/net80211/ieee80211_power.h @@ -79,6 +79,9 @@ int ieee80211_node_psq_age(struct ieee80211_node *); int ieee80211_pwrsave(struct ieee80211_node *, struct mbuf *); void ieee80211_node_pwrsave(struct ieee80211_node *, int enable); void ieee80211_sta_pwrsave(struct ieee80211vap *, int enable); +void ieee80211_sta_tim_notify(struct ieee80211vap *vap, int set); +void ieee80211_sta_ps_timer_check(struct ieee80211vap *vap); +/* XXX what's this? */ void ieee80211_power_poll(struct ieee80211com *); #endif /* _NET80211_IEEE80211_POWER_H_ */ diff --git a/sys/net80211/ieee80211_proto.c b/sys/net80211/ieee80211_proto.c index 6f75130..2f84769 100644 --- a/sys/net80211/ieee80211_proto.c +++ b/sys/net80211/ieee80211_proto.c @@ -42,6 +42,7 @@ __FBSDID("$FreeBSD$"); #include <sys/sockio.h> #include <net/if.h> +#include <net/if_var.h> #include <net/if_media.h> #include <net/ethernet.h> /* XXX for ether_sprintf */ diff --git a/sys/net80211/ieee80211_proto.h b/sys/net80211/ieee80211_proto.h index 8df5116..3b46ac4 100644 --- a/sys/net80211/ieee80211_proto.h +++ b/sys/net80211/ieee80211_proto.h @@ -149,6 +149,7 @@ struct mbuf *ieee80211_alloc_cts(struct ieee80211com *, uint8_t *ieee80211_add_rates(uint8_t *, const struct ieee80211_rateset *); uint8_t *ieee80211_add_xrates(uint8_t *, const struct ieee80211_rateset *); +uint8_t *ieee80211_add_ssid(uint8_t *, const uint8_t *, u_int); uint8_t *ieee80211_add_wpa(uint8_t *, const struct ieee80211vap *); uint8_t *ieee80211_add_rsn(uint8_t *, const struct ieee80211vap *); uint8_t *ieee80211_add_qos(uint8_t *, const struct ieee80211_node *); diff --git a/sys/net80211/ieee80211_radiotap.c b/sys/net80211/ieee80211_radiotap.c index f06f7e0..5638f52 100644 --- a/sys/net80211/ieee80211_radiotap.c +++ b/sys/net80211/ieee80211_radiotap.c @@ -42,8 +42,10 @@ __FBSDID("$FreeBSD$"); #include <net/bpf.h> #include <net/if.h> +#include <net/if_var.h> #include <net/if_llc.h> #include <net/if_media.h> +#include <net/ethernet.h> #include <net80211/ieee80211_var.h> diff --git a/sys/net80211/ieee80211_ratectl.c b/sys/net80211/ieee80211_ratectl.c index 0ad46bd3..3eff898 100644 --- a/sys/net80211/ieee80211_ratectl.c +++ b/sys/net80211/ieee80211_ratectl.c @@ -30,9 +30,12 @@ __FBSDID("$FreeBSD$"); #include <sys/kernel.h> #include <sys/systm.h> #include <sys/socket.h> +#include <sys/malloc.h> #include <net/if.h> #include <net/if_media.h> +#include <net/ethernet.h> +#include <net/route.h> #include <net80211/ieee80211_var.h> #include <net80211/ieee80211_ratectl.h> diff --git a/sys/net80211/ieee80211_ratectl.h b/sys/net80211/ieee80211_ratectl.h index be81781..5603509 100644 --- a/sys/net80211/ieee80211_ratectl.h +++ b/sys/net80211/ieee80211_ratectl.h @@ -62,13 +62,13 @@ void ieee80211_ratectl_set(struct ieee80211vap *, int); MALLOC_DECLARE(M_80211_RATECTL); -static void __inline +static __inline void ieee80211_ratectl_deinit(struct ieee80211vap *vap) { vap->iv_rate->ir_deinit(vap); } -static void __inline +static __inline void ieee80211_ratectl_node_init(struct ieee80211_node *ni) { const struct ieee80211vap *vap = ni->ni_vap; @@ -76,7 +76,7 @@ ieee80211_ratectl_node_init(struct ieee80211_node *ni) vap->iv_rate->ir_node_init(ni); } -static void __inline +static __inline void ieee80211_ratectl_node_deinit(struct ieee80211_node *ni) { const struct ieee80211vap *vap = ni->ni_vap; @@ -92,14 +92,14 @@ ieee80211_ratectl_rate(struct ieee80211_node *ni, void *arg, uint32_t iarg) return vap->iv_rate->ir_rate(ni, arg, iarg); } -static void __inline +static __inline void ieee80211_ratectl_tx_complete(const struct ieee80211vap *vap, const struct ieee80211_node *ni, int status, void *arg1, void *arg2) { vap->iv_rate->ir_tx_complete(vap, ni, status, arg1, arg2); } -static void __inline +static __inline void ieee80211_ratectl_tx_update(const struct ieee80211vap *vap, const struct ieee80211_node *ni, void *arg1, void *arg2, void *arg3) { @@ -108,7 +108,7 @@ ieee80211_ratectl_tx_update(const struct ieee80211vap *vap, vap->iv_rate->ir_tx_update(vap, ni, arg1, arg2, arg3); } -static void __inline +static __inline void ieee80211_ratectl_setinterval(const struct ieee80211vap *vap, int msecs) { if (vap->iv_rate->ir_setinterval == NULL) diff --git a/sys/net80211/ieee80211_ratectl_none.c b/sys/net80211/ieee80211_ratectl_none.c index 0edec44..a0056f3 100644 --- a/sys/net80211/ieee80211_ratectl_none.c +++ b/sys/net80211/ieee80211_ratectl_none.c @@ -29,13 +29,16 @@ __FBSDID("$FreeBSD$"); #include "opt_wlan.h" #include <sys/param.h> +#include <sys/systm.h> #include <sys/kernel.h> +#include <sys/malloc.h> #include <sys/module.h> #include <sys/socket.h> #include <sys/sysctl.h> #include <net/if.h> #include <net/if_media.h> +#include <net/ethernet.h> #ifdef INET #include <netinet/in.h> diff --git a/sys/net80211/ieee80211_regdomain.c b/sys/net80211/ieee80211_regdomain.c index 6bc5e0d..ed7f422 100644 --- a/sys/net80211/ieee80211_regdomain.c +++ b/sys/net80211/ieee80211_regdomain.c @@ -34,11 +34,14 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/systm.h> #include <sys/kernel.h> +#include <sys/malloc.h> #include <sys/socket.h> #include <net/if.h> +#include <net/if_var.h> #include <net/if_media.h> +#include <net/ethernet.h> #include <net80211/ieee80211_var.h> #include <net80211/ieee80211_regdomain.h> diff --git a/sys/net80211/ieee80211_rssadapt.c b/sys/net80211/ieee80211_rssadapt.c index aaf4057..f230f60 100644 --- a/sys/net80211/ieee80211_rssadapt.c +++ b/sys/net80211/ieee80211_rssadapt.c @@ -33,13 +33,17 @@ #include "opt_wlan.h" #include <sys/param.h> +#include <sys/systm.h> #include <sys/kernel.h> +#include <sys/malloc.h> #include <sys/module.h> #include <sys/socket.h> #include <sys/sysctl.h> #include <net/if.h> +#include <net/if_var.h> #include <net/if_media.h> +#include <net/ethernet.h> #include <net80211/ieee80211_var.h> #include <net80211/ieee80211_rssadapt.h> diff --git a/sys/net80211/ieee80211_scan.c b/sys/net80211/ieee80211_scan.c index 3a8c24d..f42ddc0 100644 --- a/sys/net80211/ieee80211_scan.c +++ b/sys/net80211/ieee80211_scan.c @@ -40,40 +40,16 @@ __FBSDID("$FreeBSD$"); #include <sys/socket.h> #include <net/if.h> +#include <net/if_var.h> #include <net/if_media.h> #include <net/ethernet.h> #include <net80211/ieee80211_var.h> -#include <net/bpf.h> - -struct scan_state { - struct ieee80211_scan_state base; /* public state */ - - u_int ss_iflags; /* flags used internally */ -#define ISCAN_MINDWELL 0x0001 /* min dwell time reached */ -#define ISCAN_DISCARD 0x0002 /* discard rx'd frames */ -#define ISCAN_CANCEL 0x0004 /* cancel current scan */ -#define ISCAN_ABORT 0x0008 /* end the scan immediately */ - unsigned long ss_chanmindwell; /* min dwell on curchan */ - unsigned long ss_scanend; /* time scan must stop */ - u_int ss_duration; /* duration for next scan */ - struct task ss_scan_task; /* scan execution */ - struct cv ss_scan_cv; /* scan signal */ - struct callout ss_scan_timer; /* scan timer */ -}; -#define SCAN_PRIVATE(ss) ((struct scan_state *) ss) +/* XXX until it's implemented as attach ops */ +#include <net80211/ieee80211_scan_sw.h> -/* - * Amount of time to go off-channel during a background - * scan. This value should be large enough to catch most - * ap's but short enough that we can return on-channel - * before our listen interval expires. - * - * XXX tunable - * XXX check against configured listen interval - */ -#define IEEE80211_SCAN_OFFCHANNEL msecs_to_ticks(150) +#include <net/bpf.h> /* * Roaming-related defaults. RSSI thresholds are as returned by the @@ -92,55 +68,32 @@ struct scan_state { #define ROAM_RATE_QUARTER_DEFAULT 2*3 /* quarter-width 11a/g bss */ #define ROAM_MCS_11N_DEFAULT (1 | IEEE80211_RATE_MCS) /* 11n bss */ -static void scan_curchan(struct ieee80211_scan_state *, unsigned long); -static void scan_mindwell(struct ieee80211_scan_state *); -static void scan_signal(void *); -static void scan_task(void *, int); - -MALLOC_DEFINE(M_80211_SCAN, "80211scan", "802.11 scan state"); - void ieee80211_scan_attach(struct ieee80211com *ic) { - struct scan_state *ss; - ss = (struct scan_state *) malloc(sizeof(struct scan_state), - M_80211_SCAN, M_NOWAIT | M_ZERO); - if (ss == NULL) { - ic->ic_scan = NULL; - return; - } - callout_init_mtx(&ss->ss_scan_timer, IEEE80211_LOCK_OBJ(ic), 0); - cv_init(&ss->ss_scan_cv, "scan"); - TASK_INIT(&ss->ss_scan_task, 0, scan_task, ss); - ic->ic_scan = &ss->base; - ss->base.ss_ic = ic; - - ic->ic_scan_curchan = scan_curchan; - ic->ic_scan_mindwell = scan_mindwell; + /* + * For now, the swscan module does both the + * allocation (so it can pad it) and sets up the net80211 + * bits. + * + * I'll split this stuff later. + */ + ieee80211_swscan_attach(ic); } void ieee80211_scan_detach(struct ieee80211com *ic) { - struct ieee80211_scan_state *ss = ic->ic_scan; - if (ss != NULL) { - IEEE80211_LOCK(ic); - SCAN_PRIVATE(ss)->ss_iflags |= ISCAN_ABORT; - scan_signal(ss); - IEEE80211_UNLOCK(ic); - ieee80211_draintask(ic, &SCAN_PRIVATE(ss)->ss_scan_task); - callout_drain(&SCAN_PRIVATE(ss)->ss_scan_timer); - KASSERT((ic->ic_flags & IEEE80211_F_SCAN) == 0, - ("scan still running")); - if (ss->ss_ops != NULL) { - ss->ss_ops->scan_detach(ss); - ss->ss_ops = NULL; - } - ic->ic_scan = NULL; - free(SCAN_PRIVATE(ss), M_80211_SCAN); - } + /* + * Ideally we'd do the ss_ops detach call here; + * but then ieee80211_swscan_detach would need + * to be split in two. + * + * I'll do that later. + */ + ieee80211_swscan_detach(ic); } static const struct ieee80211_roamparam defroam[IEEE80211_MODE_MAX] = { @@ -175,6 +128,8 @@ ieee80211_scan_vattach(struct ieee80211vap *vap) vap->iv_roaming = IEEE80211_ROAMING_AUTO; memcpy(vap->iv_roamparms, defroam, sizeof(defroam)); + + ieee80211_swscan_vattach(vap); } void @@ -185,11 +140,10 @@ ieee80211_scan_vdetach(struct ieee80211vap *vap) IEEE80211_LOCK(ic); ss = ic->ic_scan; + + ieee80211_swscan_vdetach(vap); + if (ss != NULL && ss->ss_vap == vap) { - if (ic->ic_flags & IEEE80211_F_SCAN) { - SCAN_PRIVATE(ss)->ss_iflags |= ISCAN_ABORT; - scan_signal(ss); - } if (ss->ss_ops != NULL) { ss->ss_ops->scan_detach(ss); ss->ss_ops = NULL; @@ -260,8 +214,8 @@ ieee80211_scanner_unregister_all(const struct ieee80211_scanner *scan) * ensure later callbacks find ss_ops set to properly * reflect current operating mode. */ -static void -scan_update_locked(struct ieee80211vap *vap, +void +ieee80211_scan_update_locked(struct ieee80211vap *vap, const struct ieee80211_scanner *scan) { struct ieee80211com *ic = vap->iv_ic; @@ -306,26 +260,6 @@ scan_update_locked(struct ieee80211vap *vap, } } -static char -channel_type(const struct ieee80211_channel *c) -{ - if (IEEE80211_IS_CHAN_ST(c)) - return 'S'; - if (IEEE80211_IS_CHAN_108A(c)) - return 'T'; - if (IEEE80211_IS_CHAN_108G(c)) - return 'G'; - if (IEEE80211_IS_CHAN_HT(c)) - return 'n'; - if (IEEE80211_IS_CHAN_A(c)) - return 'a'; - if (IEEE80211_IS_CHAN_ANYG(c)) - return 'g'; - if (IEEE80211_IS_CHAN_B(c)) - return 'b'; - return 'f'; -} - void ieee80211_scan_dump_channels(const struct ieee80211_scan_state *ss) { @@ -338,14 +272,14 @@ ieee80211_scan_dump_channels(const struct ieee80211_scan_state *ss) const struct ieee80211_channel *c = ss->ss_chans[i]; printf("%s%u%c", sep, ieee80211_chan2ieee(ic, c), - channel_type(c)); + ieee80211_channel_type_char(c)); sep = ", "; } } #ifdef IEEE80211_DEBUG -static void -scan_dump(struct ieee80211_scan_state *ss) +void +ieee80211_scan_dump(struct ieee80211_scan_state *ss) { struct ieee80211vap *vap = ss->ss_vap; @@ -356,8 +290,8 @@ scan_dump(struct ieee80211_scan_state *ss) } #endif /* IEEE80211_DEBUG */ -static void -copy_ssid(struct ieee80211vap *vap, struct ieee80211_scan_state *ss, +void +ieee80211_scan_copy_ssid(struct ieee80211vap *vap, struct ieee80211_scan_state *ss, int nssid, const struct ieee80211_scan_ssid ssids[]) { if (nssid > IEEE80211_SCAN_MAX_SSID) { @@ -374,8 +308,8 @@ copy_ssid(struct ieee80211vap *vap, struct ieee80211_scan_state *ss, /* * Start a scan unless one is already going. */ -static int -start_scan_locked(const struct ieee80211_scanner *scan, +int +ieee80211_start_scan_locked(const struct ieee80211_scanner *scan, struct ieee80211vap *vap, int flags, u_int duration, u_int mindwell, u_int maxdwell, u_int nssid, const struct ieee80211_scan_ssid ssids[]) @@ -403,10 +337,10 @@ start_scan_locked(const struct ieee80211_scanner *scan, , flags & IEEE80211_SCAN_ONCE ? ", once" : "" ); - scan_update_locked(vap, scan); + ieee80211_scan_update_locked(vap, scan); if (ss->ss_ops != NULL) { if ((flags & IEEE80211_SCAN_NOSSID) == 0) - copy_ssid(vap, ss, nssid, ssids); + ieee80211_scan_copy_ssid(vap, ss, nssid, ssids); /* NB: top 4 bits for internal use */ ss->ss_flags = flags & 0xfff; @@ -419,9 +353,9 @@ start_scan_locked(const struct ieee80211_scanner *scan, if (flags & IEEE80211_SCAN_BGSCAN) ic->ic_flags_ext |= IEEE80211_FEXT_BGSCAN; - /* NB: flush frames rx'd before 1st channel change */ - SCAN_PRIVATE(ss)->ss_iflags |= ISCAN_DISCARD; - SCAN_PRIVATE(ss)->ss_duration = duration; + /* Set duration for this particular scan */ + ieee80211_swscan_set_scan_duration(vap, duration); + ss->ss_next = 0; ss->ss_mindwell = mindwell; ss->ss_maxdwell = maxdwell; @@ -429,10 +363,12 @@ start_scan_locked(const struct ieee80211_scanner *scan, ss->ss_ops->scan_start(ss, vap); #ifdef IEEE80211_DEBUG if (ieee80211_msg_scan(vap)) - scan_dump(ss); + ieee80211_scan_dump(ss); #endif /* IEEE80211_DEBUG */ ic->ic_flags |= IEEE80211_F_SCAN; - ieee80211_runtask(ic, &SCAN_PRIVATE(ss)->ss_scan_task); + + /* Start scan task */ + ieee80211_swscan_run_scan_task(vap); } return 1; } else { @@ -451,9 +387,7 @@ ieee80211_start_scan(struct ieee80211vap *vap, int flags, u_int duration, u_int mindwell, u_int maxdwell, u_int nssid, const struct ieee80211_scan_ssid ssids[]) { - struct ieee80211com *ic = vap->iv_ic; const struct ieee80211_scanner *scan; - int result; scan = ieee80211_scanner_get(vap->iv_opmode); if (scan == NULL) { @@ -464,12 +398,9 @@ ieee80211_start_scan(struct ieee80211vap *vap, int flags, return 0; } - IEEE80211_LOCK(ic); - result = start_scan_locked(scan, vap, flags, duration, + /* XXX ops */ + return ieee80211_swscan_start_scan(scan, vap, flags, duration, mindwell, maxdwell, nssid, ssids); - IEEE80211_UNLOCK(ic); - - return result; } /* @@ -516,49 +447,19 @@ ieee80211_check_scan(struct ieee80211vap *vap, int flags, /* XXX re-use cache contents? e.g. adhoc<->sta */ flags |= IEEE80211_SCAN_FLUSH; } - scan_update_locked(vap, scan); - if (ss->ss_ops != NULL) { - /* XXX verify ss_ops matches vap->iv_opmode */ - if ((flags & IEEE80211_SCAN_NOSSID) == 0) { - /* - * Update the ssid list and mark flags so if - * we call start_scan it doesn't duplicate work. - */ - copy_ssid(vap, ss, nssid, ssids); - flags |= IEEE80211_SCAN_NOSSID; - } - if ((ic->ic_flags & IEEE80211_F_SCAN) == 0 && - (flags & IEEE80211_SCAN_FLUSH) == 0 && - time_before(ticks, ic->ic_lastscan + vap->iv_scanvalid)) { - /* - * We're not currently scanning and the cache is - * deemed hot enough to consult. Lock out others - * by marking IEEE80211_F_SCAN while we decide if - * something is already in the scan cache we can - * use. Also discard any frames that might come - * in while temporarily marked as scanning. - */ - SCAN_PRIVATE(ss)->ss_iflags |= ISCAN_DISCARD; - ic->ic_flags |= IEEE80211_F_SCAN; - /* NB: need to use supplied flags in check */ - ss->ss_flags = flags & 0xff; - result = ss->ss_ops->scan_end(ss, vap); + /* + * XXX TODO: separate things out a bit better. + * XXX TODO: ops + */ + ieee80211_scan_update_locked(vap, scan); - ic->ic_flags &= ~IEEE80211_F_SCAN; - SCAN_PRIVATE(ss)->ss_iflags &= ~ISCAN_DISCARD; - if (result) { - ieee80211_notify_scan_done(vap); - IEEE80211_UNLOCK(ic); - return 1; - } - } - } - result = start_scan_locked(scan, vap, flags, duration, + result = ieee80211_swscan_check_scan(scan, vap, flags, duration, mindwell, maxdwell, nssid, ssids); + IEEE80211_UNLOCK(ic); - return result; + return (result); } /* @@ -581,10 +482,10 @@ ieee80211_check_scan_current(struct ieee80211vap *vap) int ieee80211_bg_scan(struct ieee80211vap *vap, int flags) { - struct ieee80211com *ic = vap->iv_ic; - struct ieee80211_scan_state *ss = ic->ic_scan; const struct ieee80211_scanner *scan; + // IEEE80211_UNLOCK_ASSERT(sc); + scan = ieee80211_scanner_get(vap->iv_opmode); if (scan == NULL) { IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, @@ -594,84 +495,14 @@ ieee80211_bg_scan(struct ieee80211vap *vap, int flags) return 0; } - IEEE80211_LOCK(ic); - if ((ic->ic_flags & IEEE80211_F_SCAN) == 0) { - u_int duration; - /* - * Go off-channel for a fixed interval that is large - * enough to catch most ap's but short enough that - * we can return on-channel before our listen interval - * expires. - */ - duration = IEEE80211_SCAN_OFFCHANNEL; - - IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, - "%s: %s scan, ticks %u duration %lu\n", __func__, - ss->ss_flags & IEEE80211_SCAN_ACTIVE ? "active" : "passive", - ticks, duration); - - scan_update_locked(vap, scan); - if (ss->ss_ops != NULL) { - ss->ss_vap = vap; - /* - * A background scan does not select a new sta; it - * just refreshes the scan cache. Also, indicate - * the scan logic should follow the beacon schedule: - * we go off-channel and scan for a while, then - * return to the bss channel to receive a beacon, - * then go off-channel again. All during this time - * we notify the ap we're in power save mode. When - * the scan is complete we leave power save mode. - * If any beacon indicates there are frames pending - * for us then we drop out of power save mode - * (and background scan) automatically by way of the - * usual sta power save logic. - */ - ss->ss_flags |= IEEE80211_SCAN_NOPICK - | IEEE80211_SCAN_BGSCAN - | flags - ; - /* if previous scan completed, restart */ - if (ss->ss_next >= ss->ss_last) { - if (ss->ss_flags & IEEE80211_SCAN_ACTIVE) - vap->iv_stats.is_scan_active++; - else - vap->iv_stats.is_scan_passive++; - /* - * NB: beware of the scan cache being flushed; - * if the channel list is empty use the - * scan_start method to populate it. - */ - ss->ss_next = 0; - if (ss->ss_last != 0) - ss->ss_ops->scan_restart(ss, vap); - else { - ss->ss_ops->scan_start(ss, vap); -#ifdef IEEE80211_DEBUG - if (ieee80211_msg_scan(vap)) - scan_dump(ss); -#endif /* IEEE80211_DEBUG */ - } - } - /* NB: flush frames rx'd before 1st channel change */ - SCAN_PRIVATE(ss)->ss_iflags |= ISCAN_DISCARD; - SCAN_PRIVATE(ss)->ss_duration = duration; - ss->ss_maxdwell = duration; - ic->ic_flags |= IEEE80211_F_SCAN; - ic->ic_flags_ext |= IEEE80211_FEXT_BGSCAN; - ieee80211_runtask(ic, &SCAN_PRIVATE(ss)->ss_scan_task); - } else { - /* XXX msg+stat */ - } - } else { - IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, - "%s: %s scan already in progress\n", __func__, - ss->ss_flags & IEEE80211_SCAN_ACTIVE ? "active" : "passive"); - } - IEEE80211_UNLOCK(ic); - - /* NB: racey, does it matter? */ - return (ic->ic_flags & IEEE80211_F_SCAN); + /* + * XXX TODO: pull apart the bgscan logic into whatever + * belongs here and whatever belongs in the software + * scanner. + * + * XXX TODO: ops + */ + return (ieee80211_swscan_bg_scan(scan, vap, flags)); } /* @@ -680,25 +511,9 @@ ieee80211_bg_scan(struct ieee80211vap *vap, int flags) void ieee80211_cancel_scan(struct ieee80211vap *vap) { - struct ieee80211com *ic = vap->iv_ic; - struct ieee80211_scan_state *ss = ic->ic_scan; - IEEE80211_LOCK(ic); - if ((ic->ic_flags & IEEE80211_F_SCAN) && - ss->ss_vap == vap && - (SCAN_PRIVATE(ss)->ss_iflags & ISCAN_CANCEL) == 0) { - IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, - "%s: cancel %s scan\n", __func__, - ss->ss_flags & IEEE80211_SCAN_ACTIVE ? - "active" : "passive"); - - /* clear bg scan NOPICK and mark cancel request */ - ss->ss_flags &= ~IEEE80211_SCAN_NOPICK; - SCAN_PRIVATE(ss)->ss_iflags |= ISCAN_CANCEL; - /* wake up the scan task */ - scan_signal(ss); - } - IEEE80211_UNLOCK(ic); + /* XXX TODO: ops */ + ieee80211_swscan_cancel_scan(vap); } /* @@ -707,24 +522,9 @@ ieee80211_cancel_scan(struct ieee80211vap *vap) void ieee80211_cancel_anyscan(struct ieee80211vap *vap) { - struct ieee80211com *ic = vap->iv_ic; - struct ieee80211_scan_state *ss = ic->ic_scan; - IEEE80211_LOCK(ic); - if ((ic->ic_flags & IEEE80211_F_SCAN) && - (SCAN_PRIVATE(ss)->ss_iflags & ISCAN_CANCEL) == 0) { - IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, - "%s: cancel %s scan\n", __func__, - ss->ss_flags & IEEE80211_SCAN_ACTIVE ? - "active" : "passive"); - - /* clear bg scan NOPICK and mark cancel request */ - ss->ss_flags &= ~IEEE80211_SCAN_NOPICK; - SCAN_PRIVATE(ss)->ss_iflags |= ISCAN_CANCEL; - /* wake up the scan task */ - scan_signal(ss); - } - IEEE80211_UNLOCK(ic); + /* XXX TODO: ops */ + ieee80211_swscan_cancel_anyscan(vap); } /* @@ -734,13 +534,9 @@ ieee80211_cancel_anyscan(struct ieee80211vap *vap) void ieee80211_scan_next(struct ieee80211vap *vap) { - struct ieee80211com *ic = vap->iv_ic; - struct ieee80211_scan_state *ss = ic->ic_scan; - /* wake up the scan task */ - IEEE80211_LOCK(ic); - scan_signal(ss); - IEEE80211_UNLOCK(ic); + /* XXX TODO: ops */ + ieee80211_swscan_scan_next(vap); } /* @@ -753,10 +549,15 @@ ieee80211_scan_done(struct ieee80211vap *vap) struct ieee80211com *ic = vap->iv_ic; struct ieee80211_scan_state *ss; + IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, "%s: called\n", __func__); + IEEE80211_LOCK(ic); ss = ic->ic_scan; ss->ss_next = ss->ss_last; /* all channels are complete */ - scan_signal(ss); + + /* XXX TODO: ops */ + ieee80211_swscan_scan_done(vap); + IEEE80211_UNLOCK(ic); } @@ -771,293 +572,14 @@ void ieee80211_probe_curchan(struct ieee80211vap *vap, int force) { struct ieee80211com *ic = vap->iv_ic; - struct ieee80211_scan_state *ss = ic->ic_scan; - struct ifnet *ifp = vap->iv_ifp; - int i; if ((ic->ic_curchan->ic_flags & IEEE80211_CHAN_PASSIVE) && !force) { ic->ic_flags_ext |= IEEE80211_FEXT_PROBECHAN; return; } - /* - * Send directed probe requests followed by any - * broadcast probe request. - * XXX remove dependence on ic/vap->iv_bss - */ - for (i = 0; i < ss->ss_nssid; i++) - ieee80211_send_probereq(vap->iv_bss, - vap->iv_myaddr, ifp->if_broadcastaddr, - ifp->if_broadcastaddr, - ss->ss_ssid[i].ssid, ss->ss_ssid[i].len); - if ((ss->ss_flags & IEEE80211_SCAN_NOBCAST) == 0) - ieee80211_send_probereq(vap->iv_bss, - vap->iv_myaddr, ifp->if_broadcastaddr, - ifp->if_broadcastaddr, - "", 0); -} -/* - * Scan curchan. If this is an active scan and the channel - * is not marked passive then send probe request frame(s). - * Arrange for the channel change after maxdwell ticks. - */ -static void -scan_curchan(struct ieee80211_scan_state *ss, unsigned long maxdwell) -{ - struct ieee80211vap *vap = ss->ss_vap; - - IEEE80211_LOCK(vap->iv_ic); - if (ss->ss_flags & IEEE80211_SCAN_ACTIVE) - ieee80211_probe_curchan(vap, 0); - callout_reset(&SCAN_PRIVATE(ss)->ss_scan_timer, - maxdwell, scan_signal, ss); - IEEE80211_UNLOCK(vap->iv_ic); -} - -static void -scan_signal(void *arg) -{ - struct ieee80211_scan_state *ss = (struct ieee80211_scan_state *) arg; - - IEEE80211_LOCK_ASSERT(ss->ss_ic); - - cv_signal(&SCAN_PRIVATE(ss)->ss_scan_cv); -} - -/* - * Handle mindwell requirements completed; initiate a channel - * change to the next channel asap. - */ -static void -scan_mindwell(struct ieee80211_scan_state *ss) -{ - struct ieee80211com *ic = ss->ss_ic; - - IEEE80211_LOCK(ic); - scan_signal(ss); - IEEE80211_UNLOCK(ic); -} - -static void -scan_task(void *arg, int pending) -{ -#define ISCAN_REP (ISCAN_MINDWELL | ISCAN_DISCARD) - struct ieee80211_scan_state *ss = (struct ieee80211_scan_state *) arg; - struct ieee80211vap *vap = ss->ss_vap; - struct ieee80211com *ic = ss->ss_ic; - struct ieee80211_channel *chan; - unsigned long maxdwell, scanend; - int scandone = 0; - - IEEE80211_LOCK(ic); - if (vap == NULL || (ic->ic_flags & IEEE80211_F_SCAN) == 0 || - (SCAN_PRIVATE(ss)->ss_iflags & ISCAN_ABORT)) { - /* Cancelled before we started */ - goto done; - } - - if (ss->ss_next == ss->ss_last) { - IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, - "%s: no channels to scan\n", __func__); - scandone = 1; - goto done; - } - - if (vap->iv_opmode == IEEE80211_M_STA && - vap->iv_state == IEEE80211_S_RUN) { - if ((vap->iv_bss->ni_flags & IEEE80211_NODE_PWR_MGT) == 0) { - /* Enable station power save mode */ - vap->iv_sta_ps(vap, 1); - /* - * Use an 1ms delay so the null data frame has a chance - * to go out. - * XXX Should use M_TXCB mechanism to eliminate this. - */ - cv_timedwait(&SCAN_PRIVATE(ss)->ss_scan_cv, - IEEE80211_LOCK_OBJ(ic), hz / 1000); - if (SCAN_PRIVATE(ss)->ss_iflags & ISCAN_ABORT) - goto done; - } - } - - scanend = ticks + SCAN_PRIVATE(ss)->ss_duration; - IEEE80211_UNLOCK(ic); - ic->ic_scan_start(ic); /* notify driver */ - IEEE80211_LOCK(ic); - - for (;;) { - scandone = (ss->ss_next >= ss->ss_last) || - (SCAN_PRIVATE(ss)->ss_iflags & ISCAN_CANCEL) != 0; - if (scandone || (ss->ss_flags & IEEE80211_SCAN_GOTPICK) || - (SCAN_PRIVATE(ss)->ss_iflags & ISCAN_ABORT) || - time_after(ticks + ss->ss_mindwell, scanend)) - break; - - chan = ss->ss_chans[ss->ss_next++]; - - /* - * Watch for truncation due to the scan end time. - */ - if (time_after(ticks + ss->ss_maxdwell, scanend)) - maxdwell = scanend - ticks; - else - maxdwell = ss->ss_maxdwell; - - IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, - "%s: chan %3d%c -> %3d%c [%s, dwell min %lums max %lums]\n", - __func__, - ieee80211_chan2ieee(ic, ic->ic_curchan), - channel_type(ic->ic_curchan), - ieee80211_chan2ieee(ic, chan), channel_type(chan), - (ss->ss_flags & IEEE80211_SCAN_ACTIVE) && - (chan->ic_flags & IEEE80211_CHAN_PASSIVE) == 0 ? - "active" : "passive", - ticks_to_msecs(ss->ss_mindwell), ticks_to_msecs(maxdwell)); - - /* - * Potentially change channel and phy mode. - */ - ic->ic_curchan = chan; - ic->ic_rt = ieee80211_get_ratetable(chan); - IEEE80211_UNLOCK(ic); - /* - * Perform the channel change and scan unlocked so the driver - * may sleep. Once set_channel returns the hardware has - * completed the channel change. - */ - ic->ic_set_channel(ic); - ieee80211_radiotap_chan_change(ic); - - /* - * Scan curchan. Drivers for "intelligent hardware" - * override ic_scan_curchan to tell the device to do - * the work. Otherwise we manage the work outselves; - * sending a probe request (as needed), and arming the - * timeout to switch channels after maxdwell ticks. - * - * scan_curchan should only pause for the time required to - * prepare/initiate the hardware for the scan (if at all), the - * below condvar is used to sleep for the channels dwell time - * and allows it to be signalled for abort. - */ - ic->ic_scan_curchan(ss, maxdwell); - IEEE80211_LOCK(ic); - - SCAN_PRIVATE(ss)->ss_chanmindwell = ticks + ss->ss_mindwell; - /* clear mindwell lock and initial channel change flush */ - SCAN_PRIVATE(ss)->ss_iflags &= ~ISCAN_REP; - - if ((SCAN_PRIVATE(ss)->ss_iflags & (ISCAN_CANCEL|ISCAN_ABORT))) - continue; - - /* Wait to be signalled to scan the next channel */ - cv_wait(&SCAN_PRIVATE(ss)->ss_scan_cv, IEEE80211_LOCK_OBJ(ic)); - } - if (SCAN_PRIVATE(ss)->ss_iflags & ISCAN_ABORT) - goto done; - - IEEE80211_UNLOCK(ic); - ic->ic_scan_end(ic); /* notify driver */ - IEEE80211_LOCK(ic); - - /* - * Since a cancellation may have occured during one of the - * driver calls (whilst unlocked), update scandone. - */ - if (scandone == 0 && - ((SCAN_PRIVATE(ss)->ss_iflags & ISCAN_CANCEL) != 0)) { - /* XXX printf? */ - if_printf(vap->iv_ifp, - "%s: OOPS! scan cancelled during driver call!\n", - __func__); - } - scandone |= ((SCAN_PRIVATE(ss)->ss_iflags & ISCAN_CANCEL) != 0); - - /* - * Record scan complete time. Note that we also do - * this when canceled so any background scan will - * not be restarted for a while. - */ - if (scandone) - ic->ic_lastscan = ticks; - /* return to the bss channel */ - if (ic->ic_bsschan != IEEE80211_CHAN_ANYC && - ic->ic_curchan != ic->ic_bsschan) { - ieee80211_setupcurchan(ic, ic->ic_bsschan); - IEEE80211_UNLOCK(ic); - ic->ic_set_channel(ic); - ieee80211_radiotap_chan_change(ic); - IEEE80211_LOCK(ic); - } - /* clear internal flags and any indication of a pick */ - SCAN_PRIVATE(ss)->ss_iflags &= ~ISCAN_REP; - ss->ss_flags &= ~IEEE80211_SCAN_GOTPICK; - - /* - * If not canceled and scan completed, do post-processing. - * If the callback function returns 0, then it wants to - * continue/restart scanning. Unfortunately we needed to - * notify the driver to end the scan above to avoid having - * rx frames alter the scan candidate list. - */ - if ((SCAN_PRIVATE(ss)->ss_iflags & ISCAN_CANCEL) == 0 && - !ss->ss_ops->scan_end(ss, vap) && - (ss->ss_flags & IEEE80211_SCAN_ONCE) == 0 && - time_before(ticks + ss->ss_mindwell, scanend)) { - IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, - "%s: done, restart " - "[ticks %u, dwell min %lu scanend %lu]\n", - __func__, - ticks, ss->ss_mindwell, scanend); - ss->ss_next = 0; /* reset to begining */ - if (ss->ss_flags & IEEE80211_SCAN_ACTIVE) - vap->iv_stats.is_scan_active++; - else - vap->iv_stats.is_scan_passive++; - - ss->ss_ops->scan_restart(ss, vap); /* XXX? */ - ieee80211_runtask(ic, &SCAN_PRIVATE(ss)->ss_scan_task); - IEEE80211_UNLOCK(ic); - return; - } - - /* past here, scandone is ``true'' if not in bg mode */ - if ((ss->ss_flags & IEEE80211_SCAN_BGSCAN) == 0) - scandone = 1; - - IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, - "%s: %s, [ticks %u, dwell min %lu scanend %lu]\n", - __func__, scandone ? "done" : "stopped", - ticks, ss->ss_mindwell, scanend); - - /* - * Clear the SCAN bit first in case frames are - * pending on the station power save queue. If - * we defer this then the dispatch of the frames - * may generate a request to cancel scanning. - */ -done: - ic->ic_flags &= ~IEEE80211_F_SCAN; - /* - * Drop out of power save mode when a scan has - * completed. If this scan was prematurely terminated - * because it is a background scan then don't notify - * the ap; we'll either return to scanning after we - * receive the beacon frame or we'll drop out of power - * save mode because the beacon indicates we have frames - * waiting for us. - */ - if (scandone) { - vap->iv_sta_ps(vap, 0); - if (ss->ss_next >= ss->ss_last) { - ieee80211_notify_scan_done(vap); - ic->ic_flags_ext &= ~IEEE80211_FEXT_BGSCAN; - } - } - SCAN_PRIVATE(ss)->ss_iflags &= ~(ISCAN_CANCEL|ISCAN_ABORT); - ss->ss_flags &= ~(IEEE80211_SCAN_ONCE | IEEE80211_SCAN_PICK1ST); - IEEE80211_UNLOCK(ic); -#undef ISCAN_REP + /* XXX TODO: ops */ + ieee80211_swscan_probe_curchan(vap, force); } #ifdef IEEE80211_DEBUG @@ -1086,8 +608,8 @@ dump_country(const uint8_t *ie) printf("]"); } -static void -dump_probe_beacon(uint8_t subtype, int isnew, +void +ieee80211_scan_dump_probe_beacon(uint8_t subtype, int isnew, const uint8_t mac[IEEE80211_ADDR_LEN], const struct ieee80211_scanparams *sp, int rssi) { @@ -1118,45 +640,8 @@ ieee80211_add_scan(struct ieee80211vap *vap, const struct ieee80211_frame *wh, int subtype, int rssi, int noise) { - struct ieee80211com *ic = vap->iv_ic; - struct ieee80211_scan_state *ss = ic->ic_scan; - /* XXX locking */ - /* - * Frames received during startup are discarded to avoid - * using scan state setup on the initial entry to the timer - * callback. This can occur because the device may enable - * rx prior to our doing the initial channel change in the - * timer routine. - */ - if (SCAN_PRIVATE(ss)->ss_iflags & ISCAN_DISCARD) - return; -#ifdef IEEE80211_DEBUG - if (ieee80211_msg_scan(vap) && (ic->ic_flags & IEEE80211_F_SCAN)) - dump_probe_beacon(subtype, 1, wh->i_addr2, sp, rssi); -#endif - if (ss->ss_ops != NULL && - ss->ss_ops->scan_add(ss, sp, wh, subtype, rssi, noise)) { - /* - * If we've reached the min dwell time terminate - * the timer so we'll switch to the next channel. - */ - if ((SCAN_PRIVATE(ss)->ss_iflags & ISCAN_MINDWELL) == 0 && - time_after_eq(ticks, SCAN_PRIVATE(ss)->ss_chanmindwell)) { - IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, - "%s: chan %3d%c min dwell met (%u > %lu)\n", - __func__, - ieee80211_chan2ieee(ic, ic->ic_curchan), - channel_type(ic->ic_curchan), - ticks, SCAN_PRIVATE(ss)->ss_chanmindwell); - SCAN_PRIVATE(ss)->ss_iflags |= ISCAN_MINDWELL; - /* - * NB: trigger at next clock tick or wait for the - * hardware. - */ - ic->ic_scan_mindwell(ss); - } - } + return (ieee80211_swscan_add_scan(vap, sp, wh, subtype, rssi, noise)); } /* diff --git a/sys/net80211/ieee80211_scan.h b/sys/net80211/ieee80211_scan.h index 3f13e17..9c2575a 100644 --- a/sys/net80211/ieee80211_scan.h +++ b/sys/net80211/ieee80211_scan.h @@ -299,4 +299,18 @@ void ieee80211_scanner_unregister(enum ieee80211_opmode, const struct ieee80211_scanner *); void ieee80211_scanner_unregister_all(const struct ieee80211_scanner *); const struct ieee80211_scanner *ieee80211_scanner_get(enum ieee80211_opmode); +void ieee80211_scan_update_locked(struct ieee80211vap *vap, + const struct ieee80211_scanner *scan); +void ieee80211_scan_copy_ssid(struct ieee80211vap *vap, + struct ieee80211_scan_state *ss, + int nssid, const struct ieee80211_scan_ssid ssids[]); +void ieee80211_scan_dump_probe_beacon(uint8_t subtype, int isnew, + const uint8_t mac[IEEE80211_ADDR_LEN], + const struct ieee80211_scanparams *sp, int rssi); +int ieee80211_start_scan_locked(const struct ieee80211_scanner *scan, + struct ieee80211vap *vap, int flags, u_int duration, + u_int mindwell, u_int maxdwell, + u_int nssid, const struct ieee80211_scan_ssid ssids[]); +void ieee80211_scan_dump(struct ieee80211_scan_state *ss); + #endif /* _NET80211_IEEE80211_SCAN_H_ */ diff --git a/sys/net80211/ieee80211_scan_sta.c b/sys/net80211/ieee80211_scan_sta.c index c791ea1..1e87e35 100644 --- a/sys/net80211/ieee80211_scan_sta.c +++ b/sys/net80211/ieee80211_scan_sta.c @@ -39,6 +39,7 @@ __FBSDID("$FreeBSD$"); #include <sys/socket.h> #include <net/if.h> +#include <net/if_var.h> #include <net/if_media.h> #include <net/ethernet.h> @@ -599,10 +600,12 @@ makescanlist(struct ieee80211_scan_state *ss, struct ieee80211vap *vap, * so if the desired mode is 11g, then use * the 11b channel list but upgrade the mode. */ - if (vap->iv_des_mode != IEEE80211_MODE_11G || - mode != IEEE80211_MODE_11B) - continue; - mode = IEEE80211_MODE_11G; /* upgrade */ + if (vap->iv_des_mode == IEEE80211_MODE_11G) { + if (mode == IEEE80211_MODE_11G) /* Skip the G check */ + continue; + else if (mode == IEEE80211_MODE_11B) + mode = IEEE80211_MODE_11G; /* upgrade */ + } } } else { /* @@ -732,7 +735,7 @@ sta_cancel(struct ieee80211_scan_state *ss, struct ieee80211vap *vap) return 0; } -/* unalligned little endian access */ +/* unaligned little endian access */ #define LE_READ_2(p) \ ((uint16_t) \ ((((const uint8_t *)(p))[0] ) | \ diff --git a/sys/net80211/ieee80211_scan_sw.c b/sys/net80211/ieee80211_scan_sw.c new file mode 100644 index 0000000..bce92a4 --- /dev/null +++ b/sys/net80211/ieee80211_scan_sw.c @@ -0,0 +1,872 @@ +/*- + * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting + * 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 ``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 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 <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * IEEE 802.11 scanning support. + */ +#include "opt_wlan.h" + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/proc.h> +#include <sys/kernel.h> +#include <sys/condvar.h> + +#include <sys/socket.h> + +#include <net/if.h> +#include <net/if_var.h> +#include <net/if_media.h> +#include <net/ethernet.h> + +#include <net80211/ieee80211_var.h> + +#include <net80211/ieee80211_scan_sw.h> + +#include <net/bpf.h> + +struct scan_state { + struct ieee80211_scan_state base; /* public state */ + + u_int ss_iflags; /* flags used internally */ +#define ISCAN_MINDWELL 0x0001 /* min dwell time reached */ +#define ISCAN_DISCARD 0x0002 /* discard rx'd frames */ +#define ISCAN_CANCEL 0x0004 /* cancel current scan */ +#define ISCAN_ABORT 0x0008 /* end the scan immediately */ + unsigned long ss_chanmindwell; /* min dwell on curchan */ + unsigned long ss_scanend; /* time scan must stop */ + u_int ss_duration; /* duration for next scan */ + struct task ss_scan_task; /* scan execution */ + struct cv ss_scan_cv; /* scan signal */ + struct callout ss_scan_timer; /* scan timer */ +}; +#define SCAN_PRIVATE(ss) ((struct scan_state *) ss) + +/* + * Amount of time to go off-channel during a background + * scan. This value should be large enough to catch most + * ap's but short enough that we can return on-channel + * before our listen interval expires. + * + * XXX tunable + * XXX check against configured listen interval + */ +#define IEEE80211_SCAN_OFFCHANNEL msecs_to_ticks(150) + +/* + * Roaming-related defaults. RSSI thresholds are as returned by the + * driver (.5dBm). Transmit rate thresholds are IEEE rate codes (i.e + * .5M units) or MCS. + */ +/* rssi thresholds */ +#define ROAM_RSSI_11A_DEFAULT 14 /* 11a bss */ +#define ROAM_RSSI_11B_DEFAULT 14 /* 11b bss */ +#define ROAM_RSSI_11BONLY_DEFAULT 14 /* 11b-only bss */ +/* transmit rate thresholds */ +#define ROAM_RATE_11A_DEFAULT 2*12 /* 11a bss */ +#define ROAM_RATE_11B_DEFAULT 2*5 /* 11b bss */ +#define ROAM_RATE_11BONLY_DEFAULT 2*1 /* 11b-only bss */ +#define ROAM_RATE_HALF_DEFAULT 2*6 /* half-width 11a/g bss */ +#define ROAM_RATE_QUARTER_DEFAULT 2*3 /* quarter-width 11a/g bss */ +#define ROAM_MCS_11N_DEFAULT (1 | IEEE80211_RATE_MCS) /* 11n bss */ + +static void scan_curchan(struct ieee80211_scan_state *, unsigned long); +static void scan_mindwell(struct ieee80211_scan_state *); +static void scan_signal(void *); +static void scan_task(void *, int); + +MALLOC_DEFINE(M_80211_SCAN, "80211scan", "802.11 scan state"); + +void +ieee80211_swscan_attach(struct ieee80211com *ic) +{ + struct scan_state *ss; + + ss = (struct scan_state *) malloc(sizeof(struct scan_state), + M_80211_SCAN, M_NOWAIT | M_ZERO); + if (ss == NULL) { + ic->ic_scan = NULL; + return; + } + callout_init_mtx(&ss->ss_scan_timer, IEEE80211_LOCK_OBJ(ic), 0); + cv_init(&ss->ss_scan_cv, "scan"); + TASK_INIT(&ss->ss_scan_task, 0, scan_task, ss); + + ic->ic_scan = &ss->base; + ss->base.ss_ic = ic; + + ic->ic_scan_curchan = scan_curchan; + ic->ic_scan_mindwell = scan_mindwell; + + /* + * TODO: all of the non-vap scan calls should be methods! + */ +} + +void +ieee80211_swscan_detach(struct ieee80211com *ic) +{ + struct ieee80211_scan_state *ss = ic->ic_scan; + + if (ss != NULL) { + IEEE80211_LOCK(ic); + SCAN_PRIVATE(ss)->ss_iflags |= ISCAN_ABORT; + scan_signal(ss); + IEEE80211_UNLOCK(ic); + ieee80211_draintask(ic, &SCAN_PRIVATE(ss)->ss_scan_task); + callout_drain(&SCAN_PRIVATE(ss)->ss_scan_timer); + KASSERT((ic->ic_flags & IEEE80211_F_SCAN) == 0, + ("scan still running")); + + /* + * For now, do the ss_ops detach here rather + * than ieee80211_scan_detach(). + * + * I'll figure out how to cleanly split things up + * at a later date. + */ + if (ss->ss_ops != NULL) { + ss->ss_ops->scan_detach(ss); + ss->ss_ops = NULL; + } + ic->ic_scan = NULL; + free(SCAN_PRIVATE(ss), M_80211_SCAN); + } +} + +void +ieee80211_swscan_vattach(struct ieee80211vap *vap) +{ + /* nothing to do for now */ + /* + * TODO: all of the vap scan calls should be methods! + */ + +} + +void +ieee80211_swscan_vdetach(struct ieee80211vap *vap) +{ + struct ieee80211com *ic = vap->iv_ic; + struct ieee80211_scan_state *ss; + + IEEE80211_LOCK_ASSERT(ic); + ss = ic->ic_scan; + if (ss != NULL && ss->ss_vap == vap) { + if (ic->ic_flags & IEEE80211_F_SCAN) { + SCAN_PRIVATE(ss)->ss_iflags |= ISCAN_ABORT; + scan_signal(ss); + } + } +} + +void +ieee80211_swscan_set_scan_duration(struct ieee80211vap *vap, u_int duration) +{ + struct ieee80211com *ic = vap->iv_ic; + struct ieee80211_scan_state *ss = ic->ic_scan; + + IEEE80211_LOCK_ASSERT(ic); + + /* NB: flush frames rx'd before 1st channel change */ + SCAN_PRIVATE(ss)->ss_iflags |= ISCAN_DISCARD; + SCAN_PRIVATE(ss)->ss_duration = duration; +} + +void +ieee80211_swscan_run_scan_task(struct ieee80211vap *vap) +{ + struct ieee80211com *ic = vap->iv_ic; + struct ieee80211_scan_state *ss = ic->ic_scan; + + IEEE80211_LOCK_ASSERT(ic); + + ieee80211_runtask(ic, &SCAN_PRIVATE(ss)->ss_scan_task); +} + +/* + * Start a scan unless one is already going. + * + * Called without the comlock held; grab the comlock as appropriate. + */ +int +ieee80211_swscan_start_scan(const struct ieee80211_scanner *scan, + struct ieee80211vap *vap, int flags, + u_int duration, u_int mindwell, u_int maxdwell, + u_int nssid, const struct ieee80211_scan_ssid ssids[]) +{ + struct ieee80211com *ic = vap->iv_ic; + int result; + + IEEE80211_UNLOCK_ASSERT(ic); + + IEEE80211_LOCK(ic); + result = ieee80211_start_scan_locked(scan, vap, flags, duration, + mindwell, maxdwell, nssid, ssids); + IEEE80211_UNLOCK(ic); + + return result; +} + +/* + * Check the scan cache for an ap/channel to use; if that + * fails then kick off a new scan. + * + * Called with the comlock held. + * + * XXX TODO: split out! + */ +int +ieee80211_swscan_check_scan(const struct ieee80211_scanner *scan, + struct ieee80211vap *vap, int flags, + u_int duration, u_int mindwell, u_int maxdwell, + u_int nssid, const struct ieee80211_scan_ssid ssids[]) +{ + struct ieee80211com *ic = vap->iv_ic; + struct ieee80211_scan_state *ss = ic->ic_scan; + int result; + + IEEE80211_LOCK_ASSERT(ic); + + if (ss->ss_ops != NULL) { + /* XXX verify ss_ops matches vap->iv_opmode */ + if ((flags & IEEE80211_SCAN_NOSSID) == 0) { + /* + * Update the ssid list and mark flags so if + * we call start_scan it doesn't duplicate work. + */ + ieee80211_scan_copy_ssid(vap, ss, nssid, ssids); + flags |= IEEE80211_SCAN_NOSSID; + } + if ((ic->ic_flags & IEEE80211_F_SCAN) == 0 && + (flags & IEEE80211_SCAN_FLUSH) == 0 && + time_before(ticks, ic->ic_lastscan + vap->iv_scanvalid)) { + /* + * We're not currently scanning and the cache is + * deemed hot enough to consult. Lock out others + * by marking IEEE80211_F_SCAN while we decide if + * something is already in the scan cache we can + * use. Also discard any frames that might come + * in while temporarily marked as scanning. + */ + SCAN_PRIVATE(ss)->ss_iflags |= ISCAN_DISCARD; + ic->ic_flags |= IEEE80211_F_SCAN; + + /* NB: need to use supplied flags in check */ + ss->ss_flags = flags & 0xff; + result = ss->ss_ops->scan_end(ss, vap); + + ic->ic_flags &= ~IEEE80211_F_SCAN; + SCAN_PRIVATE(ss)->ss_iflags &= ~ISCAN_DISCARD; + if (result) { + ieee80211_notify_scan_done(vap); + return 1; + } + } + } + result = ieee80211_start_scan_locked(scan, vap, flags, duration, + mindwell, maxdwell, nssid, ssids); + + return result; +} + +/* + * Restart a previous scan. If the previous scan completed + * then we start again using the existing channel list. + */ +int +ieee80211_swscan_bg_scan(const struct ieee80211_scanner *scan, + struct ieee80211vap *vap, int flags) +{ + struct ieee80211com *ic = vap->iv_ic; + struct ieee80211_scan_state *ss = ic->ic_scan; + + /* XXX assert unlocked? */ + // IEEE80211_UNLOCK_ASSERT(ic); + + IEEE80211_LOCK(ic); + if ((ic->ic_flags & IEEE80211_F_SCAN) == 0) { + u_int duration; + /* + * Go off-channel for a fixed interval that is large + * enough to catch most ap's but short enough that + * we can return on-channel before our listen interval + * expires. + */ + duration = IEEE80211_SCAN_OFFCHANNEL; + + IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, + "%s: %s scan, ticks %u duration %lu\n", __func__, + ss->ss_flags & IEEE80211_SCAN_ACTIVE ? "active" : "passive", + ticks, duration); + + ieee80211_scan_update_locked(vap, scan); + if (ss->ss_ops != NULL) { + ss->ss_vap = vap; + /* + * A background scan does not select a new sta; it + * just refreshes the scan cache. Also, indicate + * the scan logic should follow the beacon schedule: + * we go off-channel and scan for a while, then + * return to the bss channel to receive a beacon, + * then go off-channel again. All during this time + * we notify the ap we're in power save mode. When + * the scan is complete we leave power save mode. + * If any beacon indicates there are frames pending + * for us then we drop out of power save mode + * (and background scan) automatically by way of the + * usual sta power save logic. + */ + ss->ss_flags |= IEEE80211_SCAN_NOPICK + | IEEE80211_SCAN_BGSCAN + | flags + ; + /* if previous scan completed, restart */ + if (ss->ss_next >= ss->ss_last) { + if (ss->ss_flags & IEEE80211_SCAN_ACTIVE) + vap->iv_stats.is_scan_active++; + else + vap->iv_stats.is_scan_passive++; + /* + * NB: beware of the scan cache being flushed; + * if the channel list is empty use the + * scan_start method to populate it. + */ + ss->ss_next = 0; + if (ss->ss_last != 0) + ss->ss_ops->scan_restart(ss, vap); + else { + ss->ss_ops->scan_start(ss, vap); +#ifdef IEEE80211_DEBUG + if (ieee80211_msg_scan(vap)) + ieee80211_scan_dump(ss); +#endif /* IEEE80211_DEBUG */ + } + } + ieee80211_swscan_set_scan_duration(vap, duration); + ss->ss_maxdwell = duration; + ic->ic_flags |= IEEE80211_F_SCAN; + ic->ic_flags_ext |= IEEE80211_FEXT_BGSCAN; + ieee80211_runtask(ic, &SCAN_PRIVATE(ss)->ss_scan_task); + } else { + /* XXX msg+stat */ + } + } else { + IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, + "%s: %s scan already in progress\n", __func__, + ss->ss_flags & IEEE80211_SCAN_ACTIVE ? "active" : "passive"); + } + IEEE80211_UNLOCK(ic); + + /* NB: racey, does it matter? */ + return (ic->ic_flags & IEEE80211_F_SCAN); +} + +/* + * Cancel any scan currently going on for the specified vap. + */ +void +ieee80211_swscan_cancel_scan(struct ieee80211vap *vap) +{ + struct ieee80211com *ic = vap->iv_ic; + struct ieee80211_scan_state *ss = ic->ic_scan; + + IEEE80211_LOCK(ic); + if ((ic->ic_flags & IEEE80211_F_SCAN) && + ss->ss_vap == vap && + (SCAN_PRIVATE(ss)->ss_iflags & ISCAN_CANCEL) == 0) { + IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, + "%s: cancel %s scan\n", __func__, + ss->ss_flags & IEEE80211_SCAN_ACTIVE ? + "active" : "passive"); + + /* clear bg scan NOPICK and mark cancel request */ + ss->ss_flags &= ~IEEE80211_SCAN_NOPICK; + SCAN_PRIVATE(ss)->ss_iflags |= ISCAN_CANCEL; + /* wake up the scan task */ + scan_signal(ss); + } else { + IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, + "%s: called; F_SCAN=%d, vap=%s, CANCEL=%d\n", + __func__, + !! (ic->ic_flags & IEEE80211_F_SCAN), + (ss->ss_vap == vap ? "match" : "nomatch"), + !! (SCAN_PRIVATE(ss)->ss_iflags & ISCAN_CANCEL)); + } + IEEE80211_UNLOCK(ic); +} + +/* + * Cancel any scan currently going on. + */ +void +ieee80211_swscan_cancel_anyscan(struct ieee80211vap *vap) +{ + struct ieee80211com *ic = vap->iv_ic; + struct ieee80211_scan_state *ss = ic->ic_scan; + + IEEE80211_LOCK(ic); + if ((ic->ic_flags & IEEE80211_F_SCAN) && + (SCAN_PRIVATE(ss)->ss_iflags & ISCAN_CANCEL) == 0) { + IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, + "%s: cancel %s scan\n", __func__, + ss->ss_flags & IEEE80211_SCAN_ACTIVE ? + "active" : "passive"); + + /* clear bg scan NOPICK and mark cancel request */ + ss->ss_flags &= ~IEEE80211_SCAN_NOPICK; + SCAN_PRIVATE(ss)->ss_iflags |= ISCAN_CANCEL; + /* wake up the scan task */ + scan_signal(ss); + } else { + IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, + "%s: called; F_SCAN=%d, vap=%s, CANCEL=%d\n", + __func__, + !! (ic->ic_flags & IEEE80211_F_SCAN), + (ss->ss_vap == vap ? "match" : "nomatch"), + !! (SCAN_PRIVATE(ss)->ss_iflags & ISCAN_CANCEL)); + } + IEEE80211_UNLOCK(ic); +} + +/* + * Public access to scan_next for drivers that manage + * scanning themselves (e.g. for firmware-based devices). + */ +void +ieee80211_swscan_scan_next(struct ieee80211vap *vap) +{ + struct ieee80211com *ic = vap->iv_ic; + struct ieee80211_scan_state *ss = ic->ic_scan; + + IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, "%s: called\n", __func__); + + /* wake up the scan task */ + IEEE80211_LOCK(ic); + scan_signal(ss); + IEEE80211_UNLOCK(ic); +} + +/* + * Public access to scan_next for drivers that are not able to scan single + * channels (e.g. for firmware-based devices). + */ +void +ieee80211_swscan_scan_done(struct ieee80211vap *vap) +{ + struct ieee80211com *ic = vap->iv_ic; + struct ieee80211_scan_state *ss; + + IEEE80211_LOCK_ASSERT(ic); + + ss = ic->ic_scan; + scan_signal(ss); +} + +/* + * Probe the curent channel, if allowed, while scanning. + * If the channel is not marked passive-only then send + * a probe request immediately. Otherwise mark state and + * listen for beacons on the channel; if we receive something + * then we'll transmit a probe request. + */ +void +ieee80211_swscan_probe_curchan(struct ieee80211vap *vap, int force) +{ + struct ieee80211com *ic = vap->iv_ic; + struct ieee80211_scan_state *ss = ic->ic_scan; + struct ifnet *ifp = vap->iv_ifp; + int i; + + /* + * Send directed probe requests followed by any + * broadcast probe request. + * XXX remove dependence on ic/vap->iv_bss + */ + for (i = 0; i < ss->ss_nssid; i++) + ieee80211_send_probereq(vap->iv_bss, + vap->iv_myaddr, ifp->if_broadcastaddr, + ifp->if_broadcastaddr, + ss->ss_ssid[i].ssid, ss->ss_ssid[i].len); + if ((ss->ss_flags & IEEE80211_SCAN_NOBCAST) == 0) + ieee80211_send_probereq(vap->iv_bss, + vap->iv_myaddr, ifp->if_broadcastaddr, + ifp->if_broadcastaddr, + "", 0); +} + +/* + * Scan curchan. If this is an active scan and the channel + * is not marked passive then send probe request frame(s). + * Arrange for the channel change after maxdwell ticks. + */ +static void +scan_curchan(struct ieee80211_scan_state *ss, unsigned long maxdwell) +{ + struct ieee80211vap *vap = ss->ss_vap; + + IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, + "%s: calling; maxdwell=%lu\n", + __func__, + maxdwell); + IEEE80211_LOCK(vap->iv_ic); + if (ss->ss_flags & IEEE80211_SCAN_ACTIVE) + ieee80211_probe_curchan(vap, 0); + callout_reset(&SCAN_PRIVATE(ss)->ss_scan_timer, + maxdwell, scan_signal, ss); + IEEE80211_UNLOCK(vap->iv_ic); +} + +static void +scan_signal(void *arg) +{ + struct ieee80211_scan_state *ss = (struct ieee80211_scan_state *) arg; + + IEEE80211_LOCK_ASSERT(ss->ss_ic); + cv_signal(&SCAN_PRIVATE(ss)->ss_scan_cv); +} + +/* + * Handle mindwell requirements completed; initiate a channel + * change to the next channel asap. + */ +static void +scan_mindwell(struct ieee80211_scan_state *ss) +{ + struct ieee80211com *ic = ss->ss_ic; + + IEEE80211_DPRINTF(ss->ss_vap, IEEE80211_MSG_SCAN, "%s: called\n", __func__); + + IEEE80211_LOCK(ic); + scan_signal(ss); + IEEE80211_UNLOCK(ic); +} + +static void +scan_task(void *arg, int pending) +{ +#define ISCAN_REP (ISCAN_MINDWELL | ISCAN_DISCARD) + struct ieee80211_scan_state *ss = (struct ieee80211_scan_state *) arg; + struct ieee80211vap *vap = ss->ss_vap; + struct ieee80211com *ic = ss->ss_ic; + struct ieee80211_channel *chan; + unsigned long maxdwell, scanend; + int scandone = 0; + + IEEE80211_LOCK(ic); + if (vap == NULL || (ic->ic_flags & IEEE80211_F_SCAN) == 0 || + (SCAN_PRIVATE(ss)->ss_iflags & ISCAN_ABORT)) { + /* Cancelled before we started */ + goto done; + } + + if (ss->ss_next == ss->ss_last) { + IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, + "%s: no channels to scan\n", __func__); + scandone = 1; + goto done; + } + + if (vap->iv_opmode == IEEE80211_M_STA && + vap->iv_state == IEEE80211_S_RUN) { + if ((vap->iv_bss->ni_flags & IEEE80211_NODE_PWR_MGT) == 0) { + /* Enable station power save mode */ + vap->iv_sta_ps(vap, 1); + /* + * Use an 1ms delay so the null data frame has a chance + * to go out. + * XXX Should use M_TXCB mechanism to eliminate this. + */ + cv_timedwait(&SCAN_PRIVATE(ss)->ss_scan_cv, + IEEE80211_LOCK_OBJ(ic), hz / 1000); + if (SCAN_PRIVATE(ss)->ss_iflags & ISCAN_ABORT) + goto done; + } + } + + scanend = ticks + SCAN_PRIVATE(ss)->ss_duration; + + /* XXX scan state can change! Re-validate scan state! */ + + IEEE80211_UNLOCK(ic); + ic->ic_scan_start(ic); /* notify driver */ + IEEE80211_LOCK(ic); + + for (;;) { + + scandone = (ss->ss_next >= ss->ss_last) || + (SCAN_PRIVATE(ss)->ss_iflags & ISCAN_CANCEL) != 0; + + IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, + "%s: loop start; scandone=%d\n", + __func__, + scandone); + + if (scandone || (ss->ss_flags & IEEE80211_SCAN_GOTPICK) || + (SCAN_PRIVATE(ss)->ss_iflags & ISCAN_ABORT) || + time_after(ticks + ss->ss_mindwell, scanend)) + break; + + chan = ss->ss_chans[ss->ss_next++]; + + /* + * Watch for truncation due to the scan end time. + */ + if (time_after(ticks + ss->ss_maxdwell, scanend)) + maxdwell = scanend - ticks; + else + maxdwell = ss->ss_maxdwell; + + IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, + "%s: chan %3d%c -> %3d%c [%s, dwell min %lums max %lums]\n", + __func__, + ieee80211_chan2ieee(ic, ic->ic_curchan), + ieee80211_channel_type_char(ic->ic_curchan), + ieee80211_chan2ieee(ic, chan), + ieee80211_channel_type_char(chan), + (ss->ss_flags & IEEE80211_SCAN_ACTIVE) && + (chan->ic_flags & IEEE80211_CHAN_PASSIVE) == 0 ? + "active" : "passive", + ticks_to_msecs(ss->ss_mindwell), ticks_to_msecs(maxdwell)); + + /* + * Potentially change channel and phy mode. + */ + ic->ic_curchan = chan; + ic->ic_rt = ieee80211_get_ratetable(chan); + IEEE80211_UNLOCK(ic); + /* + * Perform the channel change and scan unlocked so the driver + * may sleep. Once set_channel returns the hardware has + * completed the channel change. + */ + ic->ic_set_channel(ic); + ieee80211_radiotap_chan_change(ic); + + /* + * Scan curchan. Drivers for "intelligent hardware" + * override ic_scan_curchan to tell the device to do + * the work. Otherwise we manage the work outselves; + * sending a probe request (as needed), and arming the + * timeout to switch channels after maxdwell ticks. + * + * scan_curchan should only pause for the time required to + * prepare/initiate the hardware for the scan (if at all), the + * below condvar is used to sleep for the channels dwell time + * and allows it to be signalled for abort. + */ + ic->ic_scan_curchan(ss, maxdwell); + IEEE80211_LOCK(ic); + + /* XXX scan state can change! Re-validate scan state! */ + + SCAN_PRIVATE(ss)->ss_chanmindwell = ticks + ss->ss_mindwell; + /* clear mindwell lock and initial channel change flush */ + SCAN_PRIVATE(ss)->ss_iflags &= ~ISCAN_REP; + + if ((SCAN_PRIVATE(ss)->ss_iflags & (ISCAN_CANCEL|ISCAN_ABORT))) + continue; + + IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, "%s: waiting\n", __func__); + /* Wait to be signalled to scan the next channel */ + cv_wait(&SCAN_PRIVATE(ss)->ss_scan_cv, IEEE80211_LOCK_OBJ(ic)); + } + + IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, "%s: out\n", __func__); + + if (SCAN_PRIVATE(ss)->ss_iflags & ISCAN_ABORT) + goto done; + + IEEE80211_UNLOCK(ic); + ic->ic_scan_end(ic); /* notify driver */ + IEEE80211_LOCK(ic); + /* XXX scan state can change! Re-validate scan state! */ + + /* + * Since a cancellation may have occured during one of the + * driver calls (whilst unlocked), update scandone. + */ + if (scandone == 0 && + ((SCAN_PRIVATE(ss)->ss_iflags & ISCAN_CANCEL) != 0)) { + /* XXX printf? */ + if_printf(vap->iv_ifp, + "%s: OOPS! scan cancelled during driver call (1)!\n", + __func__); + scandone = 1; + } + + /* + * Record scan complete time. Note that we also do + * this when canceled so any background scan will + * not be restarted for a while. + */ + if (scandone) + ic->ic_lastscan = ticks; + /* return to the bss channel */ + if (ic->ic_bsschan != IEEE80211_CHAN_ANYC && + ic->ic_curchan != ic->ic_bsschan) { + ieee80211_setupcurchan(ic, ic->ic_bsschan); + IEEE80211_UNLOCK(ic); + ic->ic_set_channel(ic); + ieee80211_radiotap_chan_change(ic); + IEEE80211_LOCK(ic); + } + /* clear internal flags and any indication of a pick */ + SCAN_PRIVATE(ss)->ss_iflags &= ~ISCAN_REP; + ss->ss_flags &= ~IEEE80211_SCAN_GOTPICK; + + /* + * If not canceled and scan completed, do post-processing. + * If the callback function returns 0, then it wants to + * continue/restart scanning. Unfortunately we needed to + * notify the driver to end the scan above to avoid having + * rx frames alter the scan candidate list. + */ + if ((SCAN_PRIVATE(ss)->ss_iflags & ISCAN_CANCEL) == 0 && + !ss->ss_ops->scan_end(ss, vap) && + (ss->ss_flags & IEEE80211_SCAN_ONCE) == 0 && + time_before(ticks + ss->ss_mindwell, scanend)) { + IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, + "%s: done, restart " + "[ticks %u, dwell min %lu scanend %lu]\n", + __func__, + ticks, ss->ss_mindwell, scanend); + ss->ss_next = 0; /* reset to begining */ + if (ss->ss_flags & IEEE80211_SCAN_ACTIVE) + vap->iv_stats.is_scan_active++; + else + vap->iv_stats.is_scan_passive++; + + ss->ss_ops->scan_restart(ss, vap); /* XXX? */ + ieee80211_runtask(ic, &SCAN_PRIVATE(ss)->ss_scan_task); + IEEE80211_UNLOCK(ic); + return; + } + + /* past here, scandone is ``true'' if not in bg mode */ + if ((ss->ss_flags & IEEE80211_SCAN_BGSCAN) == 0) + scandone = 1; + + IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, + "%s: %s, [ticks %u, dwell min %lu scanend %lu]\n", + __func__, scandone ? "done" : "stopped", + ticks, ss->ss_mindwell, scanend); + + /* + * Since a cancellation may have occured during one of the + * driver calls (whilst unlocked), update scandone. + */ + if (scandone == 0 && + ((SCAN_PRIVATE(ss)->ss_iflags & ISCAN_CANCEL) != 0)) { + /* XXX printf? */ + if_printf(vap->iv_ifp, + "%s: OOPS! scan cancelled during driver call (2)!\n", + __func__); + scandone = 1; + } + + /* + * Clear the SCAN bit first in case frames are + * pending on the station power save queue. If + * we defer this then the dispatch of the frames + * may generate a request to cancel scanning. + */ +done: + ic->ic_flags &= ~IEEE80211_F_SCAN; + /* + * Drop out of power save mode when a scan has + * completed. If this scan was prematurely terminated + * because it is a background scan then don't notify + * the ap; we'll either return to scanning after we + * receive the beacon frame or we'll drop out of power + * save mode because the beacon indicates we have frames + * waiting for us. + */ + if (scandone) { + vap->iv_sta_ps(vap, 0); + if (ss->ss_next >= ss->ss_last) { + ieee80211_notify_scan_done(vap); + ic->ic_flags_ext &= ~IEEE80211_FEXT_BGSCAN; + } + } + SCAN_PRIVATE(ss)->ss_iflags &= ~(ISCAN_CANCEL|ISCAN_ABORT); + ss->ss_flags &= ~(IEEE80211_SCAN_ONCE | IEEE80211_SCAN_PICK1ST); + IEEE80211_UNLOCK(ic); +#undef ISCAN_REP +} + +/* + * Process a beacon or probe response frame. + */ +void +ieee80211_swscan_add_scan(struct ieee80211vap *vap, + const struct ieee80211_scanparams *sp, + const struct ieee80211_frame *wh, + int subtype, int rssi, int noise) +{ + struct ieee80211com *ic = vap->iv_ic; + struct ieee80211_scan_state *ss = ic->ic_scan; + + /* XXX locking */ + /* + * Frames received during startup are discarded to avoid + * using scan state setup on the initial entry to the timer + * callback. This can occur because the device may enable + * rx prior to our doing the initial channel change in the + * timer routine. + */ + if (SCAN_PRIVATE(ss)->ss_iflags & ISCAN_DISCARD) + return; +#ifdef IEEE80211_DEBUG + if (ieee80211_msg_scan(vap) && (ic->ic_flags & IEEE80211_F_SCAN)) + ieee80211_scan_dump_probe_beacon(subtype, 1, wh->i_addr2, sp, rssi); +#endif + if (ss->ss_ops != NULL && + ss->ss_ops->scan_add(ss, sp, wh, subtype, rssi, noise)) { + /* + * If we've reached the min dwell time terminate + * the timer so we'll switch to the next channel. + */ + if ((SCAN_PRIVATE(ss)->ss_iflags & ISCAN_MINDWELL) == 0 && + time_after_eq(ticks, SCAN_PRIVATE(ss)->ss_chanmindwell)) { + IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, + "%s: chan %3d%c min dwell met (%u > %lu)\n", + __func__, + ieee80211_chan2ieee(ic, ic->ic_curchan), + ieee80211_channel_type_char(ic->ic_curchan), + ticks, SCAN_PRIVATE(ss)->ss_chanmindwell); + SCAN_PRIVATE(ss)->ss_iflags |= ISCAN_MINDWELL; + /* + * NB: trigger at next clock tick or wait for the + * hardware. + */ + ic->ic_scan_mindwell(ss); + } + } +} + diff --git a/sys/net80211/ieee80211_scan_sw.h b/sys/net80211/ieee80211_scan_sw.h new file mode 100644 index 0000000..95fe482 --- /dev/null +++ b/sys/net80211/ieee80211_scan_sw.h @@ -0,0 +1,60 @@ +/*- + * Copyright (c) 2015 Adrian Chadd <adrian@FreeBSD.org> + * 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 ``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 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. + * + * $FreeBSD$ + */ +#ifndef __NET80211_IEEE80211_SCAN_SW_H__ +#define __NET80211_IEEE80211_SCAN_SW_H__ + +extern void ieee80211_swscan_attach(struct ieee80211com *ic); +extern void ieee80211_swscan_detach(struct ieee80211com *ic); + +extern void ieee80211_swscan_vattach(struct ieee80211vap *vap); +extern void ieee80211_swscan_vdetach(struct ieee80211vap *vap); + +extern int ieee80211_swscan_start_scan(const struct ieee80211_scanner *scan, + struct ieee80211vap *vap, int flags, + u_int duration, u_int mindwell, u_int maxdwell, + u_int nssid, const struct ieee80211_scan_ssid ssids[]); +extern void ieee80211_swscan_set_scan_duration(struct ieee80211vap *vap, + u_int duration); +extern void ieee80211_swscan_run_scan_task(struct ieee80211vap *vap); +extern int ieee80211_swscan_check_scan(const struct ieee80211_scanner *scan, + struct ieee80211vap *vap, int flags, + u_int duration, u_int mindwell, u_int maxdwell, + u_int nssid, const struct ieee80211_scan_ssid ssids[]); +extern int ieee80211_swscan_bg_scan(const struct ieee80211_scanner *scan, + struct ieee80211vap *vap, int flags); +extern void ieee80211_swscan_cancel_scan(struct ieee80211vap *vap); +extern void ieee80211_swscan_cancel_anyscan(struct ieee80211vap *vap); +extern void ieee80211_swscan_scan_next(struct ieee80211vap *vap); +extern void ieee80211_swscan_scan_done(struct ieee80211vap *vap); +extern void ieee80211_swscan_probe_curchan(struct ieee80211vap *vap, + int force); +extern void ieee80211_swscan_add_scan(struct ieee80211vap *vap, + const struct ieee80211_scanparams *sp, + const struct ieee80211_frame *wh, + int subtype, int rssi, int noise); + +#endif /* __NET80211_IEEE80211_SCAN_SW_H__ */ diff --git a/sys/net80211/ieee80211_sta.c b/sys/net80211/ieee80211_sta.c index 8685e4b..0a7298d 100644 --- a/sys/net80211/ieee80211_sta.c +++ b/sys/net80211/ieee80211_sta.c @@ -234,6 +234,7 @@ sta_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) switch (ostate) { case IEEE80211_S_SLEEP: /* XXX wakeup */ + /* XXX driver hook to wakeup the hardware? */ case IEEE80211_S_RUN: IEEE80211_SEND_MGMT(ni, IEEE80211_FC0_SUBTYPE_DISASSOC, @@ -299,12 +300,18 @@ sta_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) if (vap->iv_roaming == IEEE80211_ROAMING_AUTO) ieee80211_check_scan_current(vap); break; + case IEEE80211_S_SLEEP: /* beacon miss */ + /* + * XXX if in sleep we need to wakeup the hardware. + */ + /* FALLTHROUGH */ case IEEE80211_S_RUN: /* beacon miss */ /* * Beacon miss. Notify user space and if not * under control of a user application (roaming * manual) kick off a scan to re-connect. */ + ieee80211_sta_leave(ni); if (vap->iv_roaming == IEEE80211_ROAMING_AUTO) ieee80211_check_scan_current(vap); @@ -403,6 +410,7 @@ sta_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) arg == IEEE80211_FC0_SUBTYPE_ASSOC_RESP); break; case IEEE80211_S_SLEEP: + /* Wake up from sleep */ vap->iv_sta_ps(vap, 0); break; default: @@ -430,9 +438,11 @@ sta_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) ieee80211_node_authorize(ni); /* * Fake association when joining an existing bss. + * + * Don't do this if we're doing SLEEP->RUN. */ - if (ic->ic_newassoc != NULL) - ic->ic_newassoc(vap->iv_bss, ostate != IEEE80211_S_RUN); + if (ic->ic_newassoc != NULL && ostate != IEEE80211_S_SLEEP) + ic->ic_newassoc(vap->iv_bss, (ostate != IEEE80211_S_RUN)); break; case IEEE80211_S_CSA: if (ostate != IEEE80211_S_RUN) @@ -1312,6 +1322,7 @@ sta_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0, vap->iv_stats.is_beacon_bad++; return; } + /* * Count frame now that we know it's to be processed. */ @@ -1381,25 +1392,66 @@ sta_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0, } if (scan.quiet) ic->ic_set_quiet(ni, scan.quiet); + if (scan.tim != NULL) { struct ieee80211_tim_ie *tim = (struct ieee80211_tim_ie *) scan.tim; -#if 0 + /* + * XXX Check/debug this code; see if it's about + * the right time to force the VAP awake if we + * receive a frame destined for us? + */ int aid = IEEE80211_AID(ni->ni_associd); int ix = aid / NBBY; int min = tim->tim_bitctl &~ 1; int max = tim->tim_len + min - 4; - if ((tim->tim_bitctl&1) || - (min <= ix && ix <= max && - isset(tim->tim_bitmap - min, aid))) { - /* - * XXX Do not let bg scan kick off - * we are expecting data. + int tim_ucast = 0, tim_mcast = 0; + + /* + * Only do this for unicast traffic in the TIM + * The multicast traffic notification for + * the scan notification stuff should occur + * differently. + */ + if (min <= ix && ix <= max && + isset(tim->tim_bitmap - min, aid)) { + tim_ucast = 1; + } + + /* + * Do a separate notification + * for the multicast bit being set. + */ + if (tim->tim_bitctl & 1) { + tim_mcast = 1; + } + + /* + * If the TIM indicates there's traffic for + * us then get us out of STA mode powersave. + */ + if (tim_ucast == 1) { + + /* + * Wake us out of SLEEP state if we're + * in it; and if we're doing bgscan + * then wake us out of STA powersave. + */ + ieee80211_sta_tim_notify(vap, 1); + + /* + * This is preventing us from + * continuing a bgscan; because it + * tricks the contbgscan() + * routine to think there's always + * traffic for us. + * + * I think we need both an RX and + * TX ic_lastdata field. */ ic->ic_lastdata = ticks; - vap->iv_sta_ps(vap, 0); } -#endif + ni->ni_dtim_count = tim->tim_count; ni->ni_dtim_period = tim->tim_period; } @@ -1446,6 +1498,14 @@ sta_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0, } /* + * Put the station to sleep if we haven't seen + * traffic in a while. + */ + IEEE80211_LOCK(ic); + ieee80211_sta_ps_timer_check(vap); + IEEE80211_UNLOCK(ic); + + /* * If we've had a channel width change (eg HT20<->HT40) * then schedule a delayed driver notification. */ diff --git a/sys/net80211/ieee80211_superg.c b/sys/net80211/ieee80211_superg.c index 21f3b99..60e1283 100644 --- a/sys/net80211/ieee80211_superg.c +++ b/sys/net80211/ieee80211_superg.c @@ -38,11 +38,12 @@ __FBSDID("$FreeBSD$"); #include <sys/socket.h> -#include <net/bpf.h> -#include <net/ethernet.h> #include <net/if.h> +#include <net/if_var.h> #include <net/if_llc.h> #include <net/if_media.h> +#include <net/bpf.h> +#include <net/ethernet.h> #include <net80211/ieee80211_var.h> #include <net80211/ieee80211_input.h> @@ -86,7 +87,7 @@ __FBSDID("$FreeBSD$"); memcpy(dst, src, sizeof(struct ether_header)) static int ieee80211_ffppsmin = 2; /* pps threshold for ff aggregation */ -SYSCTL_INT(_net_wlan, OID_AUTO, ffppsmin, CTLTYPE_INT | CTLFLAG_RW, +SYSCTL_INT(_net_wlan, OID_AUTO, ffppsmin, CTLFLAG_RW, &ieee80211_ffppsmin, 0, "min packet rate before fast-frame staging"); static int ieee80211_ffagemax = -1; /* max time frames held on stage q */ SYSCTL_PROC(_net_wlan, OID_AUTO, ffagemax, CTLTYPE_INT | CTLFLAG_RW, diff --git a/sys/net80211/ieee80211_var.h b/sys/net80211/ieee80211_var.h index 174fabc..4710697 100644 --- a/sys/net80211/ieee80211_var.h +++ b/sys/net80211/ieee80211_var.h @@ -629,6 +629,7 @@ MALLOC_DECLARE(M_80211_VAP); #define IEEE80211_C_MONITOR 0x00010000 /* CAPABILITY: monitor mode */ #define IEEE80211_C_DFS 0x00020000 /* CAPABILITY: DFS/radar avail*/ #define IEEE80211_C_MBSS 0x00040000 /* CAPABILITY: MBSS available */ +#define IEEE80211_C_SWSLEEP 0x00080000 /* CAPABILITY: do sleep here */ /* 0x7c0000 available */ #define IEEE80211_C_WPA1 0x00800000 /* CAPABILITY: WPA1 avail */ #define IEEE80211_C_WPA2 0x01000000 /* CAPABILITY: WPA2 avail */ @@ -710,6 +711,7 @@ int ieee80211_setmode(struct ieee80211com *, enum ieee80211_phymode); enum ieee80211_phymode ieee80211_chan2mode(const struct ieee80211_channel *); uint32_t ieee80211_mac_hash(const struct ieee80211com *, const uint8_t addr[IEEE80211_ADDR_LEN]); +char ieee80211_channel_type_char(const struct ieee80211_channel *c); void ieee80211_radiotap_attach(struct ieee80211com *, struct ieee80211_radiotap_header *th, int tlen, diff --git a/sys/net80211/ieee80211_wds.c b/sys/net80211/ieee80211_wds.c index 8b9b3b3..fdeaf25 100644 --- a/sys/net80211/ieee80211_wds.c +++ b/sys/net80211/ieee80211_wds.c @@ -48,6 +48,7 @@ __FBSDID("$FreeBSD$"); #include <sys/sysctl.h> #include <net/if.h> +#include <net/if_var.h> #include <net/if_media.h> #include <net/if_llc.h> #include <net/ethernet.h> |