コード例 #1
0
static int ath9k_beacon_choose_slot(struct ath_softc *sc)
{
	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
	struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
	u16 intval;
	u32 tsftu;
	u64 tsf;
	int slot;

	if (sc->sc_ah->opmode != NL80211_IFTYPE_AP) {
		ath_dbg(common, BEACON, "slot 0, tsf: %llu\n",
			ath9k_hw_gettsf64(sc->sc_ah));
		return 0;
	}

	intval = cur_conf->beacon_interval ? : ATH_DEFAULT_BINTVAL;
	tsf = ath9k_hw_gettsf64(sc->sc_ah);
	tsf += TU_TO_USEC(sc->sc_ah->config.sw_beacon_response_time);
	tsftu = TSF_TO_TU((tsf * ATH_BCBUF) >>32, tsf * ATH_BCBUF);
	slot = (tsftu % (intval * ATH_BCBUF)) / intval;

	ath_dbg(common, BEACON, "slot: %d tsf: %llu tsftu: %u\n",
		slot, tsf, tsftu / ATH_BCBUF);

	return slot;
}
コード例 #2
0
static uint64_t
arn_extend_tsf(struct arn_softc *sc, uint32_t rstamp)
{
	uint64_t tsf;

	tsf = ath9k_hw_gettsf64(sc->sc_ah);
	if ((tsf & 0x7fff) < rstamp)
		tsf -= 0x8000;
	return ((tsf & ~0x7fff) | rstamp);
}
コード例 #3
0
ファイル: htc_drv_beacon.c プロジェクト: CSCLOG/beaglebone
static void ath9k_htc_beacon_config_ap(struct ath9k_htc_priv *priv,
				       struct htc_beacon_config *bss_conf)
{
	struct ath_common *common = ath9k_hw_common(priv->ah);
	enum ath9k_int imask = 0;
	u32 nexttbtt, intval, tsftu;
	__be32 htc_imask = 0;
	int ret __attribute__ ((unused));
	u8 cmd_rsp;
	u64 tsf;

	intval = bss_conf->beacon_interval;
	intval /= ATH9K_HTC_MAX_BCN_VIF;
	nexttbtt = intval;

	/*
	 * To reduce beacon misses under heavy TX load,
	 * set the beacon response time to a larger value.
	 */
	if (intval > DEFAULT_SWBA_RESPONSE)
		priv->ah->config.sw_beacon_response_time = DEFAULT_SWBA_RESPONSE;
	else
		priv->ah->config.sw_beacon_response_time = MIN_SWBA_RESPONSE;

	if (priv->op_flags & OP_TSF_RESET) {
		ath9k_hw_reset_tsf(priv->ah);
		priv->op_flags &= ~OP_TSF_RESET;
	} else {
		/*
		 * Pull nexttbtt forward to reflect the current TSF.
		 */
		tsf = ath9k_hw_gettsf64(priv->ah);
		tsftu = TSF_TO_TU(tsf >> 32, tsf) + FUDGE;
		do {
			nexttbtt += intval;
		} while (nexttbtt < tsftu);
	}

	if (priv->op_flags & OP_ENABLE_BEACON)
		imask |= ATH9K_INT_SWBA;

	ath_dbg(common, ATH_DBG_CONFIG,
		"AP Beacon config, intval: %d, nexttbtt: %u, resp_time: %d "
		"imask: 0x%x\n",
		bss_conf->beacon_interval, nexttbtt,
		priv->ah->config.sw_beacon_response_time, imask);

	ath9k_htc_beaconq_config(priv);

	WMI_CMD(WMI_DISABLE_INTR_CMDID);
	ath9k_hw_beaconinit(priv->ah, TU_TO_USEC(nexttbtt), TU_TO_USEC(intval));
	priv->cur_beacon_conf.bmiss_cnt = 0;
	htc_imask = cpu_to_be32(imask);
	WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask);
}
コード例 #4
0
ファイル: htc_drv_main.c プロジェクト: ANFS/ANFS-kernel
static u64 ath9k_htc_get_tsf(struct ieee80211_hw *hw)
{
	struct ath9k_htc_priv *priv = hw->priv;
	u64 tsf;

	mutex_lock(&priv->mutex);
	ath9k_htc_ps_wakeup(priv);
	tsf = ath9k_hw_gettsf64(priv->ah);
	ath9k_htc_ps_restore(priv);
	mutex_unlock(&priv->mutex);

	return tsf;
}
コード例 #5
0
ファイル: beacon.c プロジェクト: Cool-Joe/imx23-audio
static void ath9k_beacon_config_adhoc(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 intval, nexttbtt;

	ath9k_reset_beacon_status(sc);

	intval = TU_TO_USEC(conf->beacon_interval);

	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);

	/*
	 * 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);
}
コード例 #6
0
ファイル: htc_drv_beacon.c プロジェクト: CSCLOG/beaglebone
static void ath9k_htc_beacon_config_adhoc(struct ath9k_htc_priv *priv,
					  struct htc_beacon_config *bss_conf)
{
	struct ath_common *common = ath9k_hw_common(priv->ah);
	enum ath9k_int imask = 0;
	u32 nexttbtt, intval, tsftu;
	__be32 htc_imask = 0;
	int ret __attribute__ ((unused));
	u8 cmd_rsp;
	u64 tsf;

	intval = bss_conf->beacon_interval;
	nexttbtt = intval;

	/*
	 * Pull nexttbtt forward to reflect the current TSF.
	 */
	tsf = ath9k_hw_gettsf64(priv->ah);
	tsftu = TSF_TO_TU(tsf >> 32, tsf) + FUDGE;
	do {
		nexttbtt += intval;
	} while (nexttbtt < tsftu);

	/*
	 * Only one IBSS interfce is allowed.
	 */
	if (intval > DEFAULT_SWBA_RESPONSE)
		priv->ah->config.sw_beacon_response_time = DEFAULT_SWBA_RESPONSE;
	else
		priv->ah->config.sw_beacon_response_time = MIN_SWBA_RESPONSE;

	if (priv->op_flags & OP_ENABLE_BEACON)
		imask |= ATH9K_INT_SWBA;

	ath_dbg(common, ATH_DBG_CONFIG,
		"IBSS Beacon config, intval: %d, nexttbtt: %u, "
		"resp_time: %d, imask: 0x%x\n",
		bss_conf->beacon_interval, nexttbtt,
		priv->ah->config.sw_beacon_response_time, imask);

	WMI_CMD(WMI_DISABLE_INTR_CMDID);
	ath9k_hw_beaconinit(priv->ah, TU_TO_USEC(nexttbtt), TU_TO_USEC(intval));
	priv->cur_beacon_conf.bmiss_cnt = 0;
	htc_imask = cpu_to_be32(imask);
	WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask);
}
コード例 #7
0
static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv,
					struct htc_beacon_config *bss_conf)
{
	struct ath_common *common = ath9k_hw_common(priv->ah);
	struct ath9k_beacon_state bs;
	enum ath9k_int imask = 0;
	int dtimperiod, dtimcount, sleepduration;
	int cfpperiod, cfpcount, bmiss_timeout;
	u32 nexttbtt = 0, intval, tsftu;
	__be32 htc_imask = 0;
	u64 tsf;
	int num_beacons, offset, dtim_dec_count, cfp_dec_count;
	int ret __attribute__ ((unused));
	u8 cmd_rsp;

	memset(&bs, 0, sizeof(bs));

	intval = bss_conf->beacon_interval;
	bmiss_timeout = (ATH_DEFAULT_BMISS_LIMIT * bss_conf->beacon_interval);

	/*
	 * Setup dtim and cfp parameters according to
	 * last beacon we received (which may be none).
	 */
	dtimperiod = bss_conf->dtim_period;
	if (dtimperiod <= 0)		/* NB: 0 if not known */
		dtimperiod = 1;
	dtimcount = 1;
	if (dtimcount >= dtimperiod)	/* NB: sanity check */
		dtimcount = 0;
	cfpperiod = 1;			/* NB: no PCF support yet */
	cfpcount = 0;

	sleepduration = intval;
	if (sleepduration <= 0)
		sleepduration = intval;

	/*
	 * Pull nexttbtt forward to reflect the current
	 * TSF and calculate dtim+cfp state for the result.
	 */
	tsf = ath9k_hw_gettsf64(priv->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 = ATH_DEFAULT_BMISS_LIMIT / 2;
	} else {
		bs.bs_bmissthreshold = DIV_ROUND_UP(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, CONFIG, "intval: %u tsf: %llu tsftu: %u\n",
		intval, tsf, tsftu);
	ath_dbg(common, CONFIG,
		"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 */

	WMI_CMD(WMI_DISABLE_INTR_CMDID);
	ath9k_hw_set_sta_beacon_timers(priv->ah, &bs);
	imask |= ATH9K_INT_BMISS;
	htc_imask = cpu_to_be32(imask);
	WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask);
}
コード例 #8
0
static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv,
					struct htc_beacon_config *bss_conf)
{
	struct ath_common *common = ath9k_hw_common(priv->ah);
	struct ath9k_beacon_state bs;
	enum ath9k_int imask = 0;
	int dtimperiod, dtimcount, sleepduration;
	int cfpperiod, cfpcount, bmiss_timeout;
	u32 nexttbtt = 0, intval, tsftu;
	__be32 htc_imask = 0;
	u64 tsf;
	int num_beacons, offset, dtim_dec_count, cfp_dec_count;
	int ret __attribute__ ((unused));
	u8 cmd_rsp;

	memset(&bs, 0, sizeof(bs));

	intval = bss_conf->beacon_interval;
	bmiss_timeout = (ATH_DEFAULT_BMISS_LIMIT * bss_conf->beacon_interval);

	/*
                                              
                                                
  */
	dtimperiod = bss_conf->dtim_period;
	if (dtimperiod <= 0)		/*                    */
		dtimperiod = 1;
	dtimcount = 1;
	if (dtimcount >= dtimperiod)	/*                  */
		dtimcount = 0;
	cfpperiod = 1;			/*                        */
	cfpcount = 0;

	sleepduration = intval;
	if (sleepduration <= 0)
		sleepduration = intval;

	/*
                                                
                                                    
  */
	tsf = ath9k_hw_gettsf64(priv->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_dec_count = num_beacons % dtimperiod;
	/*                                 */
	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;

	/*
                                                                      
                                                                      
                                                                        
                                 
  */
	if (sleepduration > intval) {
		bs.bs_bmissthreshold = ATH_DEFAULT_BMISS_LIMIT / 2;
	} else {
		bs.bs_bmissthreshold = DIV_ROUND_UP(bmiss_timeout, intval);
		if (bs.bs_bmissthreshold > 15)
			bs.bs_bmissthreshold = 15;
		else if (bs.bs_bmissthreshold <= 0)
			bs.bs_bmissthreshold = 1;
	}

	/*
                                                               
                                                                         
                                                                 
                                  
   
                      
  */

	bs.bs_sleepduration = roundup(IEEE80211_MS_TO_TU(100), sleepduration);
	if (bs.bs_sleepduration > bs.bs_dtimperiod)
		bs.bs_sleepduration = bs.bs_dtimperiod;

	/*                                              */
	bs.bs_tsfoor_threshold = ATH9K_TSFOOR_THRESHOLD;

	ath_dbg(common, CONFIG, "intval: %u tsf: %llu tsftu: %u\n",
		intval, tsf, tsftu);
	ath_dbg(common, CONFIG,
		"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);

	/*                                    */

	WMI_CMD(WMI_DISABLE_INTR_CMDID);
	ath9k_hw_set_sta_beacon_timers(priv->ah, &bs);
	imask |= ATH9K_INT_BMISS;
	htc_imask = cpu_to_be32(imask);
	WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask);
}
コード例 #9
0
static void
arn_rx_handler(struct arn_softc *sc)
{
#define	PA2DESC(_sc, _pa) \
		((struct ath_desc *)((caddr_t)(_sc)->sc_desc + \
		((_pa) - (_sc)->sc_desc_dma.cookie.dmac_address)))

	ieee80211com_t *ic = (ieee80211com_t *)sc;
	struct ath_buf *bf;
	struct ath_hal *ah = sc->sc_ah;
	struct ath_desc *ds;
	struct ath_rx_status *rs;
	mblk_t *rx_mp;
	struct ieee80211_frame *wh;
	int32_t len, ngood, loop = 1;
	uint8_t phyerr;
	int status;
	struct ieee80211_node *in;

	ngood = 0;
	do {
		mutex_enter(&sc->sc_rxbuflock);
		bf = list_head(&sc->sc_rxbuf_list);
		if (bf == NULL) {
			ARN_DBG((ARN_DBG_RECV, "arn: arn_rx_handler(): "
			    "no buffer\n"));
			mutex_exit(&sc->sc_rxbuflock);
			break;
		}
		ASSERT(bf->bf_dma.cookie.dmac_address != NULL);
		ds = bf->bf_desc;
		if (ds->ds_link == bf->bf_daddr) {
			/*
			 * Never process the self-linked entry at the end,
			 * this may be met at heavy load.
			 */
			mutex_exit(&sc->sc_rxbuflock);
			break;
		}

		/*
		 * Must provide the virtual address of the current
		 * descriptor, the physical address, and the virtual
		 * address of the next descriptor in the h/w chain.
		 * This allows the HAL to look ahead to see if the
		 * hardware is done with a descriptor by checking the
		 * done bit in the following descriptor and the address
		 * of the current descriptor the DMA engine is working
		 * on.  All this is necessary because of our use of
		 * a self-linked list to avoid rx overruns.
		 */
		status = ath9k_hw_rxprocdesc(ah, ds,
		    bf->bf_daddr,
		    PA2DESC(sc, ds->ds_link), 0);
		if (status == EINPROGRESS) {
			mutex_exit(&sc->sc_rxbuflock);
			break;
		}
		list_remove(&sc->sc_rxbuf_list, bf);
		mutex_exit(&sc->sc_rxbuflock);

		rs = &ds->ds_rxstat;
		if (rs->rs_status != 0) {
			if (rs->rs_status & ATH9K_RXERR_CRC) {
				sc->sc_stats.ast_rx_crcerr++;
			}
			if (rs->rs_status & ATH9K_RXERR_FIFO) {
				sc->sc_stats.ast_rx_fifoerr++;
			}
			if (rs->rs_status & ATH9K_RXERR_DECRYPT) {
				sc->sc_stats.ast_rx_badcrypt++;
			}
			if (rs->rs_status & ATH9K_RXERR_PHY) {
				sc->sc_stats.ast_rx_phyerr++;
				phyerr = rs->rs_phyerr & 0x1f;
				sc->sc_stats.ast_rx_phy[phyerr]++;
			}
			goto rx_next;
		}
		len = rs->rs_datalen;

		/* less than sizeof(struct ieee80211_frame) */
		if (len < 20) {
			sc->sc_stats.ast_rx_tooshort++;
			goto rx_next;
		}

		if ((rx_mp = allocb(sc->sc_dmabuf_size, BPRI_MED)) == NULL) {
			arn_problem("arn: arn_rx_handler(): "
			    "allocing mblk buffer failed.\n");
			return;
		}

		ARN_DMA_SYNC(bf->bf_dma, DDI_DMA_SYNC_FORCPU);
		bcopy(bf->bf_dma.mem_va, rx_mp->b_rptr, len);

		rx_mp->b_wptr += len;
		wh = (struct ieee80211_frame *)rx_mp->b_rptr;

		if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) ==
		    IEEE80211_FC0_TYPE_CTL) {
			/*
			 * Ignore control frame received in promisc mode.
			 */
			freemsg(rx_mp);
			goto rx_next;
		}
		/* Remove the CRC at the end of IEEE80211 frame */
		rx_mp->b_wptr -= IEEE80211_CRC_LEN;

#ifdef DEBUG
		arn_printrxbuf(bf, status == 0);
#endif

		/*
		 * Locate the node for sender, track state, and then
		 * pass the (referenced) node up to the 802.11 layer
		 * for its use.
		 */
		in = ieee80211_find_rxnode(ic, wh);

		/*
		 * Send the frame to net80211 for processing
		 */
		(void) ieee80211_input(ic, rx_mp, in,
		    rs->rs_rssi, rs->rs_tstamp);

		/* release node */
		ieee80211_free_node(in);

		/*
		 * Arrange to update the last rx timestamp only for
		 * frames from our ap when operating in station mode.
		 * This assumes the rx key is always setup when associated.
		 */
		if (ic->ic_opmode == IEEE80211_M_STA &&
		    rs->rs_keyix != ATH9K_RXKEYIX_INVALID) {
			ngood++;
		}

		/*
		 * change the default rx antenna if rx diversity chooses the
		 * other antenna 3 times in a row.
		 */
		if (sc->sc_defant != ds->ds_rxstat.rs_antenna) {
			if (++sc->sc_rxotherant >= 3) {
				ath9k_hw_setantenna(sc->sc_ah,
				    ds->ds_rxstat.rs_antenna);
				sc->sc_defant = ds->ds_rxstat.rs_antenna;
				sc->sc_rxotherant = 0;
			}
		} else {
			sc->sc_rxotherant = 0;
		}

rx_next:
		mutex_enter(&sc->sc_rxbuflock);
		list_insert_tail(&sc->sc_rxbuf_list, bf);
		mutex_exit(&sc->sc_rxbuflock);
		arn_rx_buf_link(sc, bf);
	} while (loop);

	if (ngood)
		sc->sc_lastrx = ath9k_hw_gettsf64(ah);

#undef PA2DESC
}
コード例 #10
0
/*
 * 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,
				    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");
		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);
	ah->imask |= ATH9K_INT_BMISS;

	ath9k_hw_set_interrupts(ah);
	ath9k_hw_enable_interrupts(ah);
}