Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright (c) 2008-2011 Atheros Communications Inc.
0003  *
0004  * Permission to use, copy, modify, and/or distribute this software for any
0005  * purpose with or without fee is hereby granted, provided that the above
0006  * copyright notice and this permission notice appear in all copies.
0007  *
0008  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
0009  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
0010  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
0011  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
0012  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
0013  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
0014  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
0015  */
0016 
0017 #include "common.h"
0018 
0019 #define FUDGE 2
0020 
0021 static u32 ath9k_get_next_tbtt(struct ath_hw *ah, u64 tsf,
0022                    unsigned int interval)
0023 {
0024     unsigned int offset, divisor;
0025 
0026     tsf += TU_TO_USEC(FUDGE + ah->config.sw_beacon_response_time);
0027     divisor = TU_TO_USEC(interval);
0028     div_u64_rem(tsf, divisor, &offset);
0029 
0030     return (u32) tsf + divisor - offset;
0031 }
0032 
0033 /*
0034  * This sets up the beacon timers according to the timestamp of the last
0035  * received beacon and the current TSF, configures PCF and DTIM
0036  * handling, programs the sleep registers so the hardware will wakeup in
0037  * time to receive beacons, and configures the beacon miss handling so
0038  * we'll receive a BMISS interrupt when we stop seeing beacons from the AP
0039  * we've associated with.
0040  */
0041 int ath9k_cmn_beacon_config_sta(struct ath_hw *ah,
0042                  struct ath_beacon_config *conf,
0043                  struct ath9k_beacon_state *bs)
0044 {
0045     struct ath_common *common = ath9k_hw_common(ah);
0046     int dtim_intval;
0047     u64 tsf;
0048 
0049     /* No need to configure beacon if we are not associated */
0050     if (!test_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags)) {
0051         ath_dbg(common, BEACON,
0052             "STA is not yet associated..skipping beacon config\n");
0053         return -EPERM;
0054     }
0055 
0056     memset(bs, 0, sizeof(*bs));
0057     conf->intval = conf->beacon_interval;
0058 
0059     /*
0060      * Setup dtim parameters according to
0061      * last beacon we received (which may be none).
0062      */
0063     dtim_intval = conf->intval * conf->dtim_period;
0064 
0065     /*
0066      * Pull nexttbtt forward to reflect the current
0067      * TSF and calculate dtim state for the result.
0068      */
0069     tsf = ath9k_hw_gettsf64(ah);
0070     conf->nexttbtt = ath9k_get_next_tbtt(ah, tsf, conf->intval);
0071 
0072     bs->bs_intval = TU_TO_USEC(conf->intval);
0073     bs->bs_dtimperiod = conf->dtim_period * bs->bs_intval;
0074     bs->bs_nexttbtt = conf->nexttbtt;
0075     bs->bs_nextdtim = conf->nexttbtt;
0076     if (conf->dtim_period > 1)
0077         bs->bs_nextdtim = ath9k_get_next_tbtt(ah, tsf, dtim_intval);
0078 
0079     /*
0080      * Calculate the number of consecutive beacons to miss* before taking
0081      * a BMISS interrupt. The configuration is specified in TU so we only
0082      * need calculate based on the beacon interval.  Note that we clamp the
0083      * result to at most 15 beacons.
0084      */
0085     bs->bs_bmissthreshold = DIV_ROUND_UP(conf->bmiss_timeout, conf->intval);
0086     if (bs->bs_bmissthreshold > 15)
0087         bs->bs_bmissthreshold = 15;
0088     else if (bs->bs_bmissthreshold <= 0)
0089         bs->bs_bmissthreshold = 1;
0090 
0091     /*
0092      * Calculate sleep duration. The configuration is given in ms.
0093      * We ensure a multiple of the beacon period is used. Also, if the sleep
0094      * duration is greater than the DTIM period then it makes senses
0095      * to make it a multiple of that.
0096      *
0097      * XXX fixed at 100ms
0098      */
0099 
0100     bs->bs_sleepduration = TU_TO_USEC(roundup(IEEE80211_MS_TO_TU(100),
0101                           conf->intval));
0102     if (bs->bs_sleepduration > bs->bs_dtimperiod)
0103         bs->bs_sleepduration = bs->bs_dtimperiod;
0104 
0105     /* TSF out of range threshold fixed at 1 second */
0106     bs->bs_tsfoor_threshold = ATH9K_TSFOOR_THRESHOLD;
0107 
0108     ath_dbg(common, BEACON, "bmiss: %u sleep: %u\n",
0109         bs->bs_bmissthreshold, bs->bs_sleepduration);
0110     return 0;
0111 }
0112 EXPORT_SYMBOL(ath9k_cmn_beacon_config_sta);
0113 
0114 void ath9k_cmn_beacon_config_adhoc(struct ath_hw *ah,
0115                    struct ath_beacon_config *conf)
0116 {
0117     struct ath_common *common = ath9k_hw_common(ah);
0118 
0119     conf->intval = TU_TO_USEC(conf->beacon_interval);
0120 
0121     if (conf->ibss_creator)
0122         conf->nexttbtt = conf->intval;
0123     else
0124         conf->nexttbtt = ath9k_get_next_tbtt(ah, ath9k_hw_gettsf64(ah),
0125                            conf->beacon_interval);
0126 
0127     if (conf->enable_beacon)
0128         ah->imask |= ATH9K_INT_SWBA;
0129     else
0130         ah->imask &= ~ATH9K_INT_SWBA;
0131 
0132     ath_dbg(common, BEACON,
0133         "IBSS (%s) nexttbtt: %u intval: %u conf_intval: %u\n",
0134         (conf->enable_beacon) ? "Enable" : "Disable",
0135         conf->nexttbtt, conf->intval, conf->beacon_interval);
0136 }
0137 EXPORT_SYMBOL(ath9k_cmn_beacon_config_adhoc);
0138 
0139 /*
0140  * For multi-bss ap support beacons are either staggered evenly over N slots or
0141  * burst together.  For the former arrange for the SWBA to be delivered for each
0142  * slot. Slots that are not occupied will generate nothing.
0143  */
0144 void ath9k_cmn_beacon_config_ap(struct ath_hw *ah,
0145                 struct ath_beacon_config *conf,
0146                 unsigned int bc_buf)
0147 {
0148     struct ath_common *common = ath9k_hw_common(ah);
0149 
0150     /* NB: the beacon interval is kept internally in TU's */
0151     conf->intval = TU_TO_USEC(conf->beacon_interval);
0152     conf->intval /= bc_buf;
0153     conf->nexttbtt = ath9k_get_next_tbtt(ah, ath9k_hw_gettsf64(ah),
0154                        conf->beacon_interval);
0155 
0156     if (conf->enable_beacon)
0157         ah->imask |= ATH9K_INT_SWBA;
0158     else
0159         ah->imask &= ~ATH9K_INT_SWBA;
0160 
0161     ath_dbg(common, BEACON,
0162         "AP (%s) nexttbtt: %u intval: %u conf_intval: %u\n",
0163         (conf->enable_beacon) ? "Enable" : "Disable",
0164         conf->nexttbtt, conf->intval, conf->beacon_interval);
0165 }
0166 EXPORT_SYMBOL(ath9k_cmn_beacon_config_ap);