--- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -1171,7 +1171,7 @@ ath5k_check_ibss_tsf(struct ath5k_hw *ah if (ieee80211_is_beacon(mgmt->frame_control) && le16_to_cpu(mgmt->u.beacon.capab_info) & WLAN_CAPABILITY_IBSS && - memcmp(mgmt->bssid, common->curbssid, ETH_ALEN) == 0) { + compare_ether_addr(mgmt->bssid, common->curbssid) == 0) { /* * Received an IBSS beacon with the same BSSID. Hardware *must* * have updated the local TSF. We have to work around various @@ -1235,7 +1235,7 @@ ath5k_update_beacon_rssi(struct ath5k_hw /* only beacons from our BSSID */ if (!ieee80211_is_beacon(mgmt->frame_control) || - memcmp(mgmt->bssid, common->curbssid, ETH_ALEN) != 0) + compare_ether_addr(mgmt->bssid, common->curbssid) != 0) return; ewma_add(&ah->ah_beacon_rssi_avg, rssi); @@ -2416,6 +2416,19 @@ ath5k_tx_complete_poll_work(struct work_ * Initialization routines * \*************************/ +static const struct ieee80211_iface_limit if_limits[] = { + { .max = 256, .types = BIT(NL80211_IFTYPE_STATION) }, + { .max = 4, .types = BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_MESH_POINT) }, +}; + +static const struct ieee80211_iface_combination if_comb = { + .limits = if_limits, + .n_limits = ARRAY_SIZE(if_limits), + .max_interfaces = 256, + .num_different_channels = 1, +}; + int __devinit ath5k_init_ah(struct ath5k_hw *ah, const struct ath_bus_ops *bus_ops) { @@ -2437,6 +2450,9 @@ ath5k_init_ah(struct ath5k_hw *ah, const BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_MESH_POINT); + hw->wiphy->iface_combinations = &if_comb; + hw->wiphy->n_iface_combinations = 1; + /* SW support for IBSS_RSN is provided by mac80211 */ hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; --- a/drivers/net/wireless/ath/ath9k/ani.c +++ b/drivers/net/wireless/ath/ath9k/ani.c @@ -274,7 +274,9 @@ static void ath9k_hw_set_ofdm_nil(struct aniState->rssiThrLow, aniState->rssiThrHigh); if (aniState->update_ani) - aniState->ofdmNoiseImmunityLevel = immunityLevel; + aniState->ofdmNoiseImmunityLevel = + (immunityLevel > ATH9K_ANI_OFDM_DEF_LEVEL) ? + immunityLevel : ATH9K_ANI_OFDM_DEF_LEVEL; entry_ofdm = &ofdm_level_table[aniState->ofdmNoiseImmunityLevel]; entry_cck = &cck_level_table[aniState->cckNoiseImmunityLevel]; @@ -340,7 +342,9 @@ static void ath9k_hw_set_cck_nil(struct immunityLevel = ATH9K_ANI_CCK_MAX_LEVEL_LOW_RSSI; if (aniState->update_ani) - aniState->cckNoiseImmunityLevel = immunityLevel; + aniState->cckNoiseImmunityLevel = + (immunityLevel > ATH9K_ANI_CCK_DEF_LEVEL) ? + immunityLevel : ATH9K_ANI_CCK_DEF_LEVEL; entry_ofdm = &ofdm_level_table[aniState->ofdmNoiseImmunityLevel]; entry_cck = &cck_level_table[aniState->cckNoiseImmunityLevel]; --- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c @@ -618,19 +618,10 @@ static void ar5008_hw_init_bb(struct ath u32 synthDelay; synthDelay = REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY; - if (IS_CHAN_B(chan)) - synthDelay = (4 * synthDelay) / 22; - else - synthDelay /= 10; - - if (IS_CHAN_HALF_RATE(chan)) - synthDelay *= 2; - else if (IS_CHAN_QUARTER_RATE(chan)) - synthDelay *= 4; REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); - udelay(synthDelay + BASE_ACTIVATE_DELAY); + ath9k_hw_synth_delay(ah, chan, synthDelay); } static void ar5008_hw_init_chain_masks(struct ath_hw *ah) @@ -868,7 +859,7 @@ static int ar5008_hw_process_ini(struct ar5008_hw_set_channel_regs(ah, chan); ar5008_hw_init_chain_masks(ah); ath9k_olc_init(ah); - ath9k_hw_apply_txpower(ah, chan); + ath9k_hw_apply_txpower(ah, chan, false); /* Write analog registers */ if (!ath9k_hw_set_rf_regs(ah, chan, freqIndex)) { @@ -948,12 +939,8 @@ static bool ar5008_hw_rfbus_req(struct a static void ar5008_hw_rfbus_done(struct ath_hw *ah) { u32 synthDelay = REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY; - if (IS_CHAN_B(ah->curchan)) - synthDelay = (4 * synthDelay) / 22; - else - synthDelay /= 10; - udelay(synthDelay + BASE_ACTIVATE_DELAY); + ath9k_hw_synth_delay(ah, ah->curchan, synthDelay); REG_WRITE(ah, AR_PHY_RFBUS_REQ, 0); } --- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c @@ -1000,10 +1000,12 @@ static bool ar9003_hw_init_cal(struct at if (mci && IS_CHAN_2GHZ(chan) && run_agc_cal) ar9003_mci_init_cal_req(ah, &is_reusable); - txiqcal_done = ar9003_hw_tx_iq_cal_run(ah); - REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS); - udelay(5); - REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); + if (!(IS_CHAN_HALF_RATE(chan) || IS_CHAN_QUARTER_RATE(chan))) { + txiqcal_done = ar9003_hw_tx_iq_cal_run(ah); + REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS); + udelay(5); + REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); + } skip_tx_iqcal: if (run_agc_cal || !(ah->ah_flags & AH_FASTCC)) { --- a/drivers/net/wireless/ath/ath9k/ar9003_paprd.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_paprd.c @@ -54,7 +54,7 @@ void ar9003_paprd_enable(struct ath_hw * if (val) { ah->paprd_table_write_done = true; - ath9k_hw_apply_txpower(ah, chan); + ath9k_hw_apply_txpower(ah, chan, false); } REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL0_B0, --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c @@ -524,22 +524,10 @@ static void ar9003_hw_init_bb(struct ath * Value is in 100ns increments. */ synthDelay = REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY; - if (IS_CHAN_B(chan)) - synthDelay = (4 * synthDelay) / 22; - else - synthDelay /= 10; /* Activate the PHY (includes baseband activate + synthesizer on) */ REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); - - /* - * There is an issue if the AP starts the calibration before - * the base band timeout completes. This could result in the - * rx_clear false triggering. As a workaround we add delay an - * extra BASE_ACTIVATE_DELAY usecs to ensure this condition - * does not happen. - */ - udelay(synthDelay + BASE_ACTIVATE_DELAY); + ath9k_hw_synth_delay(ah, chan, synthDelay); } static void ar9003_hw_set_chain_masks(struct ath_hw *ah, u8 rx, u8 tx) @@ -690,7 +678,7 @@ static int ar9003_hw_process_ini(struct ar9003_hw_override_ini(ah); ar9003_hw_set_channel_regs(ah, chan); ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask); - ath9k_hw_apply_txpower(ah, chan); + ath9k_hw_apply_txpower(ah, chan, false); if (AR_SREV_9462(ah)) { if (REG_READ_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_0, @@ -721,6 +709,14 @@ static void ar9003_hw_set_rfmode(struct if (IS_CHAN_A_FAST_CLOCK(ah, chan)) rfMode |= (AR_PHY_MODE_DYNAMIC | AR_PHY_MODE_DYN_CCK_DISABLE); + if (IS_CHAN_QUARTER_RATE(chan)) + rfMode |= AR_PHY_MODE_QUARTER; + if (IS_CHAN_HALF_RATE(chan)) + rfMode |= AR_PHY_MODE_HALF; + + if (rfMode & (AR_PHY_MODE_QUARTER | AR_PHY_MODE_HALF)) + REG_RMW_FIELD(ah, AR_PHY_FRAME_CTL, + AR_PHY_FRAME_CTL_CF_OVERLAP_WINDOW, 3); REG_WRITE(ah, AR_PHY_MODE, rfMode); } @@ -791,12 +787,8 @@ static bool ar9003_hw_rfbus_req(struct a static void ar9003_hw_rfbus_done(struct ath_hw *ah) { u32 synthDelay = REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY; - if (IS_CHAN_B(ah->curchan)) - synthDelay = (4 * synthDelay) / 22; - else - synthDelay /= 10; - udelay(synthDelay + BASE_ACTIVATE_DELAY); + ath9k_hw_synth_delay(ah, ah->curchan, synthDelay); REG_WRITE(ah, AR_PHY_RFBUS_REQ, 0); } --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h @@ -468,6 +468,9 @@ #define AR_PHY_ADDAC_PARA_CTL (AR_SM_BASE + 0x150) #define AR_PHY_XPA_CFG (AR_SM_BASE + 0x158) +#define AR_PHY_FRAME_CTL_CF_OVERLAP_WINDOW 3 +#define AR_PHY_FRAME_CTL_CF_OVERLAP_WINDOW_S 0 + #define AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_IDX_A 0x0001FC00 #define AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_IDX_A_S 10 #define AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_A 0x3FF --- a/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h @@ -1115,9 +1115,9 @@ static const u32 ar9462_2p0_mac_core[][2 {0x000081f8, 0x00000000}, {0x000081fc, 0x00000000}, {0x00008240, 0x00100000}, - {0x00008244, 0x0010f400}, + {0x00008244, 0x0010f424}, {0x00008248, 0x00000800}, - {0x0000824c, 0x0001e800}, + {0x0000824c, 0x0001e848}, {0x00008250, 0x00000000}, {0x00008254, 0x00000000}, {0x00008258, 0x00000000}, --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -370,7 +370,7 @@ struct ath_vif { * number of beacon intervals, the game's up. */ #define BSTUCK_THRESH 9 -#define ATH_BCBUF 4 +#define ATH_BCBUF 8 #define ATH_DEFAULT_BINTVAL 100 /* TU */ #define ATH_DEFAULT_BMISS_LIMIT 10 #define IEEE80211_MS_TO_TU(x) (((x) * 1000) / 1024) --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -91,7 +91,7 @@ static void ath_beacon_setup(struct ath_ info.txpower = MAX_RATE_POWER; info.keyix = ATH9K_TXKEYIX_INVALID; info.keytype = ATH9K_KEY_TYPE_CLEAR; - info.flags = ATH9K_TXDESC_NOACK | ATH9K_TXDESC_INTREQ; + info.flags = ATH9K_TXDESC_NOACK | ATH9K_TXDESC_CLRDMASK; info.buf_addr[0] = bf->bf_buf_addr; info.buf_len[0] = roundup(skb->len, 4); @@ -359,6 +359,11 @@ void ath_beacon_tasklet(unsigned long da int slot; u32 bfaddr, bc = 0; + if (work_pending(&sc->hw_reset_work)) { + ath_dbg(common, RESET, + "reset work is pending, skip beaconing now\n"); + return; + } /* * Check if the previous beacon has gone out. If * not don't try to post another, skip this period @@ -369,6 +374,9 @@ void ath_beacon_tasklet(unsigned long da if (ath9k_hw_numtxpending(ah, sc->beacon.beaconq) != 0) { sc->beacon.bmisscnt++; + if (!ath9k_hw_check_alive(ah)) + ieee80211_queue_work(sc->hw, &sc->hw_check_work); + if (sc->beacon.bmisscnt < BSTUCK_THRESH * sc->nbcnvifs) { ath_dbg(common, BSTUCK, "missed %u consecutive beacons\n", @@ -378,6 +386,7 @@ void ath_beacon_tasklet(unsigned long da ath9k_hw_bstuck_nfcal(ah); } else if (sc->beacon.bmisscnt >= BSTUCK_THRESH) { ath_dbg(common, BSTUCK, "beacon is officially stuck\n"); + sc->beacon.bmisscnt = 0; sc->sc_flags |= SC_OP_TSF_RESET; ieee80211_queue_work(sc->hw, &sc->hw_reset_work); } @@ -650,6 +659,8 @@ static void ath_beacon_config_adhoc(stru u32 tsf, intval, nexttbtt; ath9k_reset_beacon_status(sc); + if (!(sc->sc_flags & SC_OP_BEACONS)) + ath9k_hw_settsf64(ah, sc->beacon.bc_tstamp); intval = TU_TO_USEC(conf->beacon_interval); tsf = roundup(ath9k_hw_gettsf32(ah) + TU_TO_USEC(FUDGE), intval); --- a/drivers/net/wireless/ath/ath9k/eeprom_9287.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c @@ -824,6 +824,8 @@ static void ath9k_hw_ar9287_set_txpower( regulatory->max_power_level = ratesArray[i]; } + ath9k_hw_update_regulatory_maxpower(ah); + if (test) return; --- a/drivers/net/wireless/ath/ath9k/gpio.c +++ b/drivers/net/wireless/ath/ath9k/gpio.c @@ -41,6 +41,9 @@ void ath_init_leds(struct ath_softc *sc) { int ret; + if (AR_SREV_9100(sc->sc_ah)) + return; + if (sc->sc_ah->led_pin < 0) { if (AR_SREV_9287(sc->sc_ah)) sc->sc_ah->led_pin = ATH_LED_PIN_9287; --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -142,6 +142,22 @@ bool ath9k_hw_wait(struct ath_hw *ah, u3 } EXPORT_SYMBOL(ath9k_hw_wait); +void ath9k_hw_synth_delay(struct ath_hw *ah, struct ath9k_channel *chan, + int hw_delay) +{ + if (IS_CHAN_B(chan)) + hw_delay = (4 * hw_delay) / 22; + else + hw_delay /= 10; + + if (IS_CHAN_HALF_RATE(chan)) + hw_delay *= 2; + else if (IS_CHAN_QUARTER_RATE(chan)) + hw_delay *= 4; + + udelay(hw_delay + BASE_ACTIVATE_DELAY); +} + void ath9k_hw_write_array(struct ath_hw *ah, struct ar5416IniArray *array, int column, unsigned int *writecnt) { @@ -388,8 +404,8 @@ static void ath9k_hw_init_config(struct { int i; - ah->config.dma_beacon_response_time = 2; - ah->config.sw_beacon_response_time = 10; + ah->config.dma_beacon_response_time = 1; + ah->config.sw_beacon_response_time = 6; ah->config.additional_swba_backoff = 0; ah->config.ack_6mb = 0x0; ah->config.cwm_ignore_extcca = 0; @@ -971,7 +987,7 @@ void ath9k_hw_init_global_settings(struc struct ath_common *common = ath9k_hw_common(ah); struct ieee80211_conf *conf = &common->hw->conf; const struct ath9k_channel *chan = ah->curchan; - int acktimeout, ctstimeout; + int acktimeout, ctstimeout, ack_offset = 0; int slottime; int sifstime; int rx_lat = 0, tx_lat = 0, eifs = 0; @@ -992,6 +1008,11 @@ void ath9k_hw_init_global_settings(struc rx_lat = 37; tx_lat = 54; + if (IS_CHAN_5GHZ(chan)) + sifstime = 16; + else + sifstime = 10; + if (IS_CHAN_HALF_RATE(chan)) { eifs = 175; rx_lat *= 2; @@ -999,8 +1020,9 @@ void ath9k_hw_init_global_settings(struc if (IS_CHAN_A_FAST_CLOCK(ah, chan)) tx_lat += 11; + sifstime *= 2; + ack_offset = 16; slottime = 13; - sifstime = 32; } else if (IS_CHAN_QUARTER_RATE(chan)) { eifs = 340; rx_lat = (rx_lat * 4) - 1; @@ -1008,8 +1030,9 @@ void ath9k_hw_init_global_settings(struc if (IS_CHAN_A_FAST_CLOCK(ah, chan)) tx_lat += 22; + sifstime *= 4; + ack_offset = 32; slottime = 21; - sifstime = 64; } else { if (AR_SREV_9287(ah) && AR_SREV_9287_13_OR_LATER(ah)) { eifs = AR_D_GBL_IFS_EIFS_ASYNC_FIFO; @@ -1023,14 +1046,10 @@ void ath9k_hw_init_global_settings(struc tx_lat = MS(reg, AR_USEC_TX_LAT); slottime = ah->slottime; - if (IS_CHAN_5GHZ(chan)) - sifstime = 16; - else - sifstime = 10; } /* As defined by IEEE 802.11-2007 17.3.8.6 */ - acktimeout = slottime + sifstime + 3 * ah->coverage_class; + acktimeout = slottime + sifstime + 3 * ah->coverage_class + ack_offset; ctstimeout = acktimeout; /* @@ -1040,7 +1059,8 @@ void ath9k_hw_init_global_settings(struc * BA frames in some implementations, but it has been found to fix ACK * timeout issues in other cases as well. */ - if (conf->channel && conf->channel->band == IEEE80211_BAND_2GHZ) { + if (conf->channel && conf->channel->band == IEEE80211_BAND_2GHZ && + !IS_CHAN_HALF_RATE(chan) && !IS_CHAN_QUARTER_RATE(chan)) { acktimeout += 64 - sifstime - ah->slottime; ctstimeout += 48 - sifstime - ah->slottime; } @@ -1420,6 +1440,10 @@ static bool ath9k_hw_channel_change(stru CHANNEL_5GHZ)); mode_diff = (chan->chanmode != ah->curchan->chanmode); + if ((ah->curchan->channelFlags | chan->channelFlags) & + (CHANNEL_HALF | CHANNEL_QUARTER)) + return false; + for (qnum = 0; qnum < AR_NUM_QCU; qnum++) { if (ath9k_hw_numtxpending(ah, qnum)) { ath_dbg(common, QUEUE, @@ -1453,7 +1477,7 @@ static bool ath9k_hw_channel_change(stru return false; } ath9k_hw_set_clockrate(ah); - ath9k_hw_apply_txpower(ah, chan); + ath9k_hw_apply_txpower(ah, chan, false); ath9k_hw_rfbus_done(ah); if (IS_CHAN_OFDM(chan) || IS_CHAN_HT(chan)) @@ -2724,7 +2748,8 @@ static int get_antenna_gain(struct ath_h return ah->eep_ops->get_eeprom(ah, gain_param); } -void ath9k_hw_apply_txpower(struct ath_hw *ah, struct ath9k_channel *chan) +void ath9k_hw_apply_txpower(struct ath_hw *ah, struct ath9k_channel *chan, + bool test) { struct ath_regulatory *reg = ath9k_hw_regulatory(ah); struct ieee80211_channel *channel; @@ -2745,7 +2770,7 @@ void ath9k_hw_apply_txpower(struct ath_h ah->eep_ops->set_txpower(ah, chan, ath9k_regd_get_ctl(reg, chan), - ant_reduction, new_pwr, false); + ant_reduction, new_pwr, test); } void ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit, bool test) @@ -2758,7 +2783,7 @@ void ath9k_hw_set_txpowerlimit(struct at if (test) channel->max_power = MAX_RATE_POWER / 2; - ath9k_hw_apply_txpower(ah, chan); + ath9k_hw_apply_txpower(ah, chan, test); if (test) channel->max_power = DIV_ROUND_UP(reg->max_power_level, 2); --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -923,6 +923,8 @@ void ath9k_hw_set_gpio(struct ath_hw *ah void ath9k_hw_setantenna(struct ath_hw *ah, u32 antenna); /* General Operation */ +void ath9k_hw_synth_delay(struct ath_hw *ah, struct ath9k_channel *chan, + int hw_delay); bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout); void ath9k_hw_write_array(struct ath_hw *ah, struct ar5416IniArray *array, int column, unsigned int *writecnt); @@ -976,7 +978,8 @@ void ath9k_hw_name(struct ath_hw *ah, ch /* PHY */ void ath9k_hw_get_delta_slope_vals(struct ath_hw *ah, u32 coef_scaled, u32 *coef_mantissa, u32 *coef_exponent); -void ath9k_hw_apply_txpower(struct ath_hw *ah, struct ath9k_channel *chan); +void ath9k_hw_apply_txpower(struct ath_hw *ah, struct ath9k_channel *chan, + bool test); /* * Code Specific to AR5008, AR9001 or AR9002, --- a/drivers/net/wireless/ath/ath9k/mac.c +++ b/drivers/net/wireless/ath/ath9k/mac.c @@ -133,8 +133,16 @@ EXPORT_SYMBOL(ath9k_hw_updatetxtriglevel void ath9k_hw_abort_tx_dma(struct ath_hw *ah) { + int maxdelay = 1000; int i, q; + if (ah->curchan) { + if (IS_CHAN_HALF_RATE(ah->curchan)) + maxdelay *= 2; + else if (IS_CHAN_QUARTER_RATE(ah->curchan)) + maxdelay *= 4; + } + REG_WRITE(ah, AR_Q_TXD, AR_Q_TXD_M); REG_SET_BIT(ah, AR_PCU_MISC, AR_PCU_FORCE_QUIET_COLL | AR_PCU_CLEAR_VMF); @@ -142,7 +150,7 @@ void ath9k_hw_abort_tx_dma(struct ath_hw REG_SET_BIT(ah, AR_D_GBL_IFS_MISC, AR_D_GBL_IFS_MISC_IGNORE_BACKOFF); for (q = 0; q < AR_NUM_QCU; q++) { - for (i = 0; i < 1000; i++) { + for (i = 0; i < maxdelay; i++) { if (i) udelay(5); --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -692,17 +692,6 @@ void ath9k_tasklet(unsigned long data) goto out; } - /* - * Only run the baseband hang check if beacons stop working in AP or - * IBSS mode, because it has a high false positive rate. For station - * mode it should not be necessary, since the upper layers will detect - * this through a beacon miss automatically and the following channel - * change will trigger a hardware reset anyway - */ - if (ath9k_hw_numtxpending(ah, sc->beacon.beaconq) != 0 && - !ath9k_hw_check_alive(ah)) - ieee80211_queue_work(sc->hw, &sc->hw_check_work); - if ((status & ATH9K_INT_TSFOOR) && sc->ps_enabled) { /* * TSF sync does not look correct; remain awake to sync with --- a/net/mac80211/agg-rx.c +++ b/net/mac80211/agg-rx.c @@ -200,6 +200,8 @@ static void ieee80211_send_addba_resp(st memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN); else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) memcpy(mgmt->bssid, sdata->u.ibss.bssid, ETH_ALEN); + else if (sdata->vif.type == NL80211_IFTYPE_WDS) + memcpy(mgmt->bssid, da, ETH_ALEN); mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION); --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c @@ -81,7 +81,8 @@ static void ieee80211_send_addba_request memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); if (sdata->vif.type == NL80211_IFTYPE_AP || sdata->vif.type == NL80211_IFTYPE_AP_VLAN || - sdata->vif.type == NL80211_IFTYPE_MESH_POINT) + sdata->vif.type == NL80211_IFTYPE_MESH_POINT || + sdata->vif.type == NL80211_IFTYPE_WDS) memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN); else if (sdata->vif.type == NL80211_IFTYPE_STATION) memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN); @@ -484,6 +485,7 @@ int ieee80211_start_tx_ba_session(struct sdata->vif.type != NL80211_IFTYPE_MESH_POINT && sdata->vif.type != NL80211_IFTYPE_AP_VLAN && sdata->vif.type != NL80211_IFTYPE_AP && + sdata->vif.type != NL80211_IFTYPE_WDS && sdata->vif.type != NL80211_IFTYPE_ADHOC) return -EINVAL; --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c @@ -63,11 +63,11 @@ static ssize_t sta_flags_read(struct fil test_sta_flag(sta, WLAN_STA_##flg) ? #flg "\n" : "" int res = scnprintf(buf, sizeof(buf), - "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", + "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", TEST(AUTH), TEST(ASSOC), TEST(PS_STA), TEST(PS_DRIVER), TEST(AUTHORIZED), TEST(SHORT_PREAMBLE), - TEST(WME), TEST(WDS), TEST(CLEAR_PS_FILT), + TEST(WME), TEST(CLEAR_PS_FILT), TEST(MFP), TEST(BLOCK_BA), TEST(PSPOLL), TEST(UAPSD), TEST(SP), TEST(TDLS_PEER), TEST(TDLS_PEER_AUTH), TEST(4ADDR_EVENT), --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -163,7 +163,8 @@ static int ieee80211_check_queues(struct return -EINVAL; } - if (sdata->vif.type != NL80211_IFTYPE_AP) { + if ((sdata->vif.type != NL80211_IFTYPE_AP) || + !(sdata->local->hw.flags & IEEE80211_HW_QUEUE_CONTROL)) { sdata->vif.cab_queue = IEEE80211_INVAL_HW_QUEUE; return 0; } @@ -281,7 +282,6 @@ static int ieee80211_do_open(struct net_ { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_local *local = sdata->local; - struct sta_info *sta; u32 changed = 0; int res; u32 hw_reconf_flags = 0; @@ -427,28 +427,6 @@ static int ieee80211_do_open(struct net_ set_bit(SDATA_STATE_RUNNING, &sdata->state); - if (sdata->vif.type == NL80211_IFTYPE_WDS) { - /* Create STA entry for the WDS peer */ - sta = sta_info_alloc(sdata, sdata->u.wds.remote_addr, - GFP_KERNEL); - if (!sta) { - res = -ENOMEM; - goto err_del_interface; - } - - sta_info_pre_move_state(sta, IEEE80211_STA_AUTH); - sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC); - sta_info_pre_move_state(sta, IEEE80211_STA_AUTHORIZED); - - res = sta_info_insert(sta); - if (res) { - /* STA has been freed */ - goto err_del_interface; - } - - rate_control_rate_init(sta); - } - /* * set_multicast_list will be invoked by the networking core * which will check whether any increments here were done in @@ -845,6 +823,70 @@ static void ieee80211_if_setup(struct ne dev->destructor = free_netdev; } +static void ieee80211_wds_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, + struct sk_buff *skb) +{ + struct ieee80211_local *local = sdata->local; + struct ieee80211_rx_status *rx_status; + struct ieee802_11_elems elems; + struct ieee80211_mgmt *mgmt; + struct sta_info *sta; + size_t baselen; + u32 rates = 0; + u16 stype; + bool new = false; + enum ieee80211_band band = local->hw.conf.channel->band; + struct ieee80211_supported_band *sband = local->hw.wiphy->bands[band]; + + rx_status = IEEE80211_SKB_RXCB(skb); + mgmt = (struct ieee80211_mgmt *) skb->data; + stype = le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE; + + if (stype != IEEE80211_STYPE_BEACON) + return; + + baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt; + if (baselen > skb->len) + return; + + ieee802_11_parse_elems(mgmt->u.probe_resp.variable, + skb->len - baselen, &elems); + + rates = ieee80211_sta_get_rates(local, &elems, band, NULL); + + rcu_read_lock(); + + sta = sta_info_get(sdata, sdata->u.wds.remote_addr); + + if (!sta) { + rcu_read_unlock(); + sta = sta_info_alloc(sdata, sdata->u.wds.remote_addr, + GFP_KERNEL); + if (!sta) + return; + + new = true; + } + + sta->last_rx = jiffies; + sta->sta.supp_rates[local->hw.conf.channel->band] = rates; + + if (elems.ht_cap_elem) + ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, + elems.ht_cap_elem, &sta->sta.ht_cap); + + if (elems.wmm_param) + set_sta_flag(sta, WLAN_STA_WME); + + if (new) { + set_sta_flag(sta, WLAN_STA_AUTHORIZED); + rate_control_rate_init(sta); + sta_info_insert_rcu(sta); + } + + rcu_read_unlock(); +} + static void ieee80211_iface_work(struct work_struct *work) { struct ieee80211_sub_if_data *sdata = @@ -949,6 +991,9 @@ static void ieee80211_iface_work(struct break; ieee80211_mesh_rx_queued_mgmt(sdata, skb); break; + case NL80211_IFTYPE_WDS: + ieee80211_wds_rx_queued_mgmt(sdata, skb); + break; default: WARN(1, "frame for unexpected interface type"); break; --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -103,7 +103,7 @@ static void ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, struct sk_buff *skb, struct ieee80211_rate *rate, - int rtap_len) + int rtap_len, bool has_fcs) { struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); struct ieee80211_radiotap_header *rthdr; @@ -134,7 +134,7 @@ ieee80211_add_rx_radiotap_header(struct } /* IEEE80211_RADIOTAP_FLAGS */ - if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) + if (has_fcs && (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS)) *pos |= IEEE80211_RADIOTAP_F_FCS; if (status->flag & (RX_FLAG_FAILED_FCS_CRC | RX_FLAG_FAILED_PLCP_CRC)) *pos |= IEEE80211_RADIOTAP_F_BADFCS; @@ -294,7 +294,8 @@ ieee80211_rx_monitor(struct ieee80211_lo } /* prepend radiotap information */ - ieee80211_add_rx_radiotap_header(local, skb, rate, needed_headroom); + ieee80211_add_rx_radiotap_header(local, skb, rate, needed_headroom, + true); skb_reset_mac_header(skb); skb->ip_summed = CHECKSUM_UNNECESSARY; @@ -2282,6 +2283,7 @@ ieee80211_rx_h_action(struct ieee80211_r sdata->vif.type != NL80211_IFTYPE_MESH_POINT && sdata->vif.type != NL80211_IFTYPE_AP_VLAN && sdata->vif.type != NL80211_IFTYPE_AP && + sdata->vif.type != NL80211_IFTYPE_WDS && sdata->vif.type != NL80211_IFTYPE_ADHOC) break; @@ -2496,14 +2498,15 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_ if (!ieee80211_vif_is_mesh(&sdata->vif) && sdata->vif.type != NL80211_IFTYPE_ADHOC && - sdata->vif.type != NL80211_IFTYPE_STATION) + sdata->vif.type != NL80211_IFTYPE_STATION && + sdata->vif.type != NL80211_IFTYPE_WDS) return RX_DROP_MONITOR; switch (stype) { case cpu_to_le16(IEEE80211_STYPE_AUTH): case cpu_to_le16(IEEE80211_STYPE_BEACON): case cpu_to_le16(IEEE80211_STYPE_PROBE_RESP): - /* process for all: mesh, mlme, ibss */ + /* process for all: mesh, mlme, ibss, wds */ break; case cpu_to_le16(IEEE80211_STYPE_ASSOC_RESP): case cpu_to_le16(IEEE80211_STYPE_REASSOC_RESP): @@ -2567,7 +2570,8 @@ static void ieee80211_rx_cooked_monitor( goto out_free_skb; /* prepend radiotap information */ - ieee80211_add_rx_radiotap_header(local, skb, rate, needed_headroom); + ieee80211_add_rx_radiotap_header(local, skb, rate, needed_headroom, + false); skb_set_mac_header(skb, 0); skb->ip_summed = CHECKSUM_UNNECESSARY; @@ -2836,10 +2840,16 @@ static int prepare_for_handlers(struct i } break; case NL80211_IFTYPE_WDS: - if (bssid || !ieee80211_is_data(hdr->frame_control)) - return 0; if (compare_ether_addr(sdata->u.wds.remote_addr, hdr->addr2)) return 0; + + if (ieee80211_is_data(hdr->frame_control) || + ieee80211_is_action(hdr->frame_control)) { + if (compare_ether_addr(sdata->vif.addr, hdr->addr1)) + return 0; + } else if (!ieee80211_is_beacon(hdr->frame_control)) + return 0; + break; default: /* should never get here */ --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -32,7 +32,6 @@ * @WLAN_STA_SHORT_PREAMBLE: Station is capable of receiving short-preamble * frames. * @WLAN_STA_WME: Station is a QoS-STA. - * @WLAN_STA_WDS: Station is one of our WDS peers. * @WLAN_STA_CLEAR_PS_FILT: Clear PS filter in hardware (using the * IEEE80211_TX_CTL_CLEAR_PS_FILT control flag) when the next * frame to this station is transmitted. @@ -64,7 +63,6 @@ enum ieee80211_sta_info_flags { WLAN_STA_AUTHORIZED, WLAN_STA_SHORT_PREAMBLE, WLAN_STA_WME, - WLAN_STA_WDS, WLAN_STA_CLEAR_PS_FILT, WLAN_STA_MFP, WLAN_STA_BLOCK_BA, --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -647,6 +647,21 @@ void ath9k_reload_chainmask_settings(str setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_5GHZ].ht_cap); } +static const struct ieee80211_iface_limit if_limits[] = { + { .max = 256, .types = BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_P2P_CLIENT) | + BIT(NL80211_IFTYPE_WDS) }, + { .max = 8, .types = BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_P2P_GO) | + BIT(NL80211_IFTYPE_MESH_POINT) }, +}; + +static const struct ieee80211_iface_combination if_comb = { + .limits = if_limits, + .n_limits = ARRAY_SIZE(if_limits), + .max_interfaces = 256, + .num_different_channels = 1, +}; void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) { @@ -676,6 +691,9 @@ void ath9k_set_hw_capab(struct ath_softc BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_MESH_POINT); + hw->wiphy->iface_combinations = &if_comb; + hw->wiphy->n_iface_combinations = 1; + if (AR_SREV_5416(sc->sc_ah)) hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -455,8 +455,8 @@ static void ieee80211_rx_bss_info(struct * fall back to HT20 if we don't use or use * the other extension channel */ - if ((channel_type == NL80211_CHAN_HT40MINUS || - channel_type == NL80211_CHAN_HT40PLUS) && + if (!(channel_type == NL80211_CHAN_HT40MINUS || + channel_type == NL80211_CHAN_HT40PLUS) || channel_type != sdata->u.ibss.channel_type) sta_ht_cap_new.cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;