diff options
Diffstat (limited to 'drivers/net/wireless/ath/ath9k/beacon.c')
| -rw-r--r-- | drivers/net/wireless/ath/ath9k/beacon.c | 256 | 
1 files changed, 61 insertions, 195 deletions
diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index b5c16b3a37b..e387f0b2954 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -80,7 +80,7 @@ static void ath9k_beacon_setup(struct ath_softc *sc, struct ieee80211_vif *vif,  	u8 chainmask = ah->txchainmask;  	u8 rate = 0; -	sband = &sc->sbands[common->hw->conf.chandef.chan->band]; +	sband = &common->sbands[common->hw->conf.chandef.chan->band];  	rate = sband->bitrates[rateidx].hw_value;  	if (vif->bss_conf.use_short_preamble)  		rate |= sband->bitrates[rateidx].hw_value_short; @@ -274,28 +274,26 @@ static int ath9k_beacon_choose_slot(struct ath_softc *sc)  	return slot;  } -void ath9k_set_tsfadjust(struct ath_softc *sc, struct ieee80211_vif *vif) +static void ath9k_set_tsfadjust(struct ath_softc *sc, struct ieee80211_vif *vif)  {  	struct ath_common *common = ath9k_hw_common(sc->sc_ah);  	struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;  	struct ath_vif *avp = (void *)vif->drv_priv; -	u64 tsfadjust; +	u32 tsfadjust;  	if (avp->av_bslot == 0)  		return; -	tsfadjust = cur_conf->beacon_interval * avp->av_bslot / ATH_BCBUF; -	avp->tsf_adjust = cpu_to_le64(TU_TO_USEC(tsfadjust)); +	tsfadjust = cur_conf->beacon_interval * avp->av_bslot; +	tsfadjust = TU_TO_USEC(tsfadjust) / ATH_BCBUF; +	avp->tsf_adjust = cpu_to_le64(tsfadjust);  	ath_dbg(common, CONFIG, "tsfadjust is: %llu for bslot: %d\n",  		(unsigned long long)tsfadjust, avp->av_bslot);  } -bool ath9k_csa_is_finished(struct ath_softc *sc) +bool ath9k_csa_is_finished(struct ath_softc *sc, struct ieee80211_vif *vif)  { -	struct ieee80211_vif *vif; - -	vif = sc->csa_vif;  	if (!vif || !vif->csa_active)  		return false; @@ -303,11 +301,22 @@ bool ath9k_csa_is_finished(struct ath_softc *sc)  		return false;  	ieee80211_csa_finish(vif); - -	sc->csa_vif = NULL;  	return true;  } +static void ath9k_csa_update_vif(void *data, u8 *mac, struct ieee80211_vif *vif) +{ +	struct ath_softc *sc = data; +	ath9k_csa_is_finished(sc, vif); +} + +void ath9k_csa_update(struct ath_softc *sc) +{ +	ieee80211_iterate_active_interfaces_atomic(sc->hw, +						   IEEE80211_IFACE_ITER_NORMAL, +						   ath9k_csa_update_vif, sc); +} +  void ath9k_beacon_tasklet(unsigned long data)  {  	struct ath_softc *sc = (struct ath_softc *)data; @@ -318,7 +327,7 @@ void ath9k_beacon_tasklet(unsigned long data)  	bool edma = !!(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA);  	int slot; -	if (test_bit(SC_OP_HW_RESET, &sc->sc_flags)) { +	if (test_bit(ATH_OP_HW_RESET, &common->op_flags)) {  		ath_dbg(common, RESET,  			"reset work is pending, skip beaconing now\n");  		return; @@ -334,8 +343,16 @@ void ath9k_beacon_tasklet(unsigned long data)  	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); +		ath9k_hw_check_nav(ah); + +		/* +		 * If the previous beacon has not been transmitted +		 * and a MAC/BB hang has been identified, return +		 * here because a chip reset would have been +		 * initiated. +		 */ +		if (!ath_hw_check(sc)) +			return;  		if (sc->beacon.bmisscnt < BSTUCK_THRESH * sc->nbcnvifs) {  			ath_dbg(common, BSTUCK, @@ -353,13 +370,13 @@ void ath9k_beacon_tasklet(unsigned long data)  		return;  	} -	/* EDMA devices check that in the tx completion function. */ -	if (!edma && ath9k_csa_is_finished(sc)) -		return; -  	slot = ath9k_beacon_choose_slot(sc);  	vif = sc->beacon.bslot[slot]; +	/* EDMA devices check that in the tx completion function. */ +	if (!edma && ath9k_csa_is_finished(sc, vif)) +		return; +  	if (!vif || !vif->bss_conf.enable_beacon)  		return; @@ -438,146 +455,18 @@ static void ath9k_beacon_config_ap(struct ath_softc *sc,  				   struct ath_beacon_config *conf)  {  	struct ath_hw *ah = sc->sc_ah; -	struct ath_common *common = ath9k_hw_common(ah); -	u32 nexttbtt, intval; - -	/* NB: the beacon interval is kept internally in TU's */ -	intval = TU_TO_USEC(conf->beacon_interval); -	intval /= ATH_BCBUF; -	nexttbtt = intval; - -	if (conf->enable_beacon) -		ah->imask |= ATH9K_INT_SWBA; -	else -		ah->imask &= ~ATH9K_INT_SWBA; - -	ath_dbg(common, BEACON, -		"AP (%s) nexttbtt: %u intval: %u conf_intval: %u\n", -		(conf->enable_beacon) ? "Enable" : "Disable", -		nexttbtt, intval, conf->beacon_interval); -	ath9k_beacon_init(sc, nexttbtt, intval, true); +	ath9k_cmn_beacon_config_ap(ah, conf, ATH_BCBUF); +	ath9k_beacon_init(sc, conf->nexttbtt, conf->intval, false);  } -/* - * This sets up the beacon timers according to the timestamp of the last - * received beacon and the current TSF, configures PCF and DTIM - * handling, programs the sleep registers so the hardware will wakeup in - * time to receive beacons, and configures the beacon miss handling so - * we'll receive a BMISS interrupt when we stop seeing beacons from the AP - * we've associated with. - */ -static void ath9k_beacon_config_sta(struct ath_softc *sc, +static void ath9k_beacon_config_sta(struct ath_hw *ah,  				    struct ath_beacon_config *conf)  { -	struct ath_hw *ah = sc->sc_ah; -	struct ath_common *common = ath9k_hw_common(ah);  	struct ath9k_beacon_state bs; -	int dtimperiod, dtimcount, sleepduration; -	int cfpperiod, cfpcount; -	u32 nexttbtt = 0, intval, tsftu; -	u64 tsf; -	int num_beacons, offset, dtim_dec_count, cfp_dec_count; -	/* No need to configure beacon if we are not associated */ -	if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) { -		ath_dbg(common, BEACON, -			"STA is not yet associated..skipping beacon config\n"); +	if (ath9k_cmn_beacon_config_sta(ah, conf, &bs) == -EPERM)  		return; -	} - -	memset(&bs, 0, sizeof(bs)); -	intval = conf->beacon_interval; - -	/* -	 * Setup dtim and cfp parameters according to -	 * last beacon we received (which may be none). -	 */ -	dtimperiod = conf->dtim_period; -	dtimcount = conf->dtim_count; -	if (dtimcount >= dtimperiod)	/* NB: sanity check */ -		dtimcount = 0; -	cfpperiod = 1;			/* NB: no PCF support yet */ -	cfpcount = 0; - -	sleepduration = conf->listen_interval * intval; - -	/* -	 * Pull nexttbtt forward to reflect the current -	 * TSF and calculate dtim+cfp state for the result. -	 */ -	tsf = ath9k_hw_gettsf64(ah); -	tsftu = TSF_TO_TU(tsf>>32, tsf) + FUDGE; - -	num_beacons = tsftu / intval + 1; -	offset = tsftu % intval; -	nexttbtt = tsftu - offset; -	if (offset) -		nexttbtt += intval; - -	/* DTIM Beacon every dtimperiod Beacon */ -	dtim_dec_count = num_beacons % dtimperiod; -	/* CFP every cfpperiod DTIM Beacon */ -	cfp_dec_count = (num_beacons / dtimperiod) % cfpperiod; -	if (dtim_dec_count) -		cfp_dec_count++; - -	dtimcount -= dtim_dec_count; -	if (dtimcount < 0) -		dtimcount += dtimperiod; - -	cfpcount -= cfp_dec_count; -	if (cfpcount < 0) -		cfpcount += cfpperiod; - -	bs.bs_intval = intval; -	bs.bs_nexttbtt = nexttbtt; -	bs.bs_dtimperiod = dtimperiod*intval; -	bs.bs_nextdtim = bs.bs_nexttbtt + dtimcount*intval; -	bs.bs_cfpperiod = cfpperiod*bs.bs_dtimperiod; -	bs.bs_cfpnext = bs.bs_nextdtim + cfpcount*bs.bs_dtimperiod; -	bs.bs_cfpmaxduration = 0; - -	/* -	 * Calculate the number of consecutive beacons to miss* before taking -	 * a BMISS interrupt. The configuration is specified in TU so we only -	 * need calculate based	on the beacon interval.  Note that we clamp the -	 * result to at most 15 beacons. -	 */ -	if (sleepduration > intval) { -		bs.bs_bmissthreshold = conf->listen_interval * -			ATH_DEFAULT_BMISS_LIMIT / 2; -	} else { -		bs.bs_bmissthreshold = DIV_ROUND_UP(conf->bmiss_timeout, intval); -		if (bs.bs_bmissthreshold > 15) -			bs.bs_bmissthreshold = 15; -		else if (bs.bs_bmissthreshold <= 0) -			bs.bs_bmissthreshold = 1; -	} - -	/* -	 * Calculate sleep duration. The configuration is given in ms. -	 * We ensure a multiple of the beacon period is used. Also, if the sleep -	 * duration is greater than the DTIM period then it makes senses -	 * to make it a multiple of that. -	 * -	 * XXX fixed at 100ms -	 */ - -	bs.bs_sleepduration = roundup(IEEE80211_MS_TO_TU(100), sleepduration); -	if (bs.bs_sleepduration > bs.bs_dtimperiod) -		bs.bs_sleepduration = bs.bs_dtimperiod; - -	/* TSF out of range threshold fixed at 1 second */ -	bs.bs_tsfoor_threshold = ATH9K_TSFOOR_THRESHOLD; - -	ath_dbg(common, BEACON, "tsf: %llu tsftu: %u\n", tsf, tsftu); -	ath_dbg(common, BEACON, -		"bmiss: %u sleep: %u cfp-period: %u maxdur: %u next: %u\n", -		bs.bs_bmissthreshold, bs.bs_sleepduration, -		bs.bs_cfpperiod, bs.bs_cfpmaxduration, bs.bs_cfpnext); - -	/* Set the computed STA beacon timers */  	ath9k_hw_disable_interrupts(ah);  	ath9k_hw_set_sta_beacon_timers(ah, &bs); @@ -592,53 +481,23 @@ static void ath9k_beacon_config_adhoc(struct ath_softc *sc,  {  	struct ath_hw *ah = sc->sc_ah;  	struct ath_common *common = ath9k_hw_common(ah); -	u32 intval, nexttbtt;  	ath9k_reset_beacon_status(sc); -	intval = TU_TO_USEC(conf->beacon_interval); +	ath9k_cmn_beacon_config_adhoc(ah, conf); -	if (conf->ibss_creator) { -		nexttbtt = intval; -	} else { -		u32 tbtt, offset, tsftu; -		u64 tsf; - -		/* -		 * Pull nexttbtt forward to reflect the current -		 * sync'd TSF. -		 */ -		tsf = ath9k_hw_gettsf64(ah); -		tsftu = TSF_TO_TU(tsf >> 32, tsf) + FUDGE; -		offset = tsftu % conf->beacon_interval; -		tbtt = tsftu - offset; -		if (offset) -			tbtt += conf->beacon_interval; - -		nexttbtt = TU_TO_USEC(tbtt); -	} - -	if (conf->enable_beacon) -		ah->imask |= ATH9K_INT_SWBA; -	else -		ah->imask &= ~ATH9K_INT_SWBA; - -	ath_dbg(common, BEACON, -		"IBSS (%s) nexttbtt: %u intval: %u conf_intval: %u\n", -		(conf->enable_beacon) ? "Enable" : "Disable", -		nexttbtt, intval, conf->beacon_interval); - -	ath9k_beacon_init(sc, nexttbtt, intval, conf->ibss_creator); +	ath9k_beacon_init(sc, conf->nexttbtt, conf->intval, conf->ibss_creator);  	/*  	 * Set the global 'beacon has been configured' flag for the  	 * joiner case in IBSS mode.  	 */  	if (!conf->ibss_creator && conf->enable_beacon) -		set_bit(SC_OP_BEACONS, &sc->sc_flags); +		set_bit(ATH_OP_BEACONS, &common->op_flags);  } -bool ath9k_allow_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif) +static bool ath9k_allow_beacon_config(struct ath_softc *sc, +				      struct ieee80211_vif *vif)  {  	struct ath_common *common = ath9k_hw_common(sc->sc_ah);  	struct ath_vif *avp = (void *)vif->drv_priv; @@ -654,7 +513,7 @@ bool ath9k_allow_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif)  	if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) {  		if ((vif->type == NL80211_IFTYPE_STATION) && -		    test_bit(SC_OP_BEACONS, &sc->sc_flags) && +		    test_bit(ATH_OP_BEACONS, &common->op_flags) &&  		    !avp->primary_sta_vif) {  			ath_dbg(common, CONFIG,  				"Beacon already configured for a station interface\n"); @@ -676,11 +535,8 @@ static void ath9k_cache_beacon_config(struct ath_softc *sc,  	cur_conf->beacon_interval = bss_conf->beacon_int;  	cur_conf->dtim_period = bss_conf->dtim_period; -	cur_conf->listen_interval = 1;  	cur_conf->dtim_count = 1;  	cur_conf->ibss_creator = bss_conf->ibss_creator; -	cur_conf->bmiss_timeout = -		ATH_DEFAULT_BMISS_LIMIT * cur_conf->beacon_interval;  	/*  	 * It looks like mac80211 may end up using beacon interval of zero in @@ -691,6 +547,9 @@ static void ath9k_cache_beacon_config(struct ath_softc *sc,  	if (cur_conf->beacon_interval == 0)  		cur_conf->beacon_interval = 100; +	cur_conf->bmiss_timeout = +		ATH_DEFAULT_BMISS_LIMIT * cur_conf->beacon_interval; +  	/*  	 * We don't parse dtim period from mac80211 during the driver  	 * initialization as it breaks association with hidden-ssid @@ -706,15 +565,22 @@ void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif,  {  	struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;  	struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; +        struct ath_hw *ah = sc->sc_ah; +        struct ath_common *common = ath9k_hw_common(ah);  	unsigned long flags;  	bool skip_beacon = false; +	if (vif->type == NL80211_IFTYPE_AP) +		ath9k_set_tsfadjust(sc, vif); + +	if (!ath9k_allow_beacon_config(sc, vif)) +		return; +  	if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) {  		ath9k_cache_beacon_config(sc, bss_conf);  		ath9k_set_beacon(sc); -		set_bit(SC_OP_BEACONS, &sc->sc_flags); +		set_bit(ATH_OP_BEACONS, &common->op_flags);  		return; -  	}  	/* @@ -752,13 +618,13 @@ void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif,  		}  		/* -		 * Do not set the SC_OP_BEACONS flag for IBSS joiner mode +		 * Do not set the ATH_OP_BEACONS flag for IBSS joiner mode  		 * here, it is done in ath9k_beacon_config_adhoc().  		 */  		if (cur_conf->enable_beacon && !skip_beacon) -			set_bit(SC_OP_BEACONS, &sc->sc_flags); +			set_bit(ATH_OP_BEACONS, &common->op_flags);  		else -			clear_bit(SC_OP_BEACONS, &sc->sc_flags); +			clear_bit(ATH_OP_BEACONS, &common->op_flags);  	}  } @@ -776,7 +642,7 @@ void ath9k_set_beacon(struct ath_softc *sc)  		ath9k_beacon_config_adhoc(sc, cur_conf);  		break;  	case NL80211_IFTYPE_STATION: -		ath9k_beacon_config_sta(sc, cur_conf); +		ath9k_beacon_config_sta(sc->sc_ah, cur_conf);  		break;  	default:  		ath_dbg(common, CONFIG, "Unsupported beaconing mode\n");  | 
