]> git.karo-electronics.de Git - mv-sheeva.git/commitdiff
ath9k_htc: Add beacon slots
authorSujith Manoharan <Sujith.Manoharan@atheros.com>
Wed, 13 Apr 2011 05:53:08 +0000 (11:23 +0530)
committerJohn W. Linville <linville@tuxdriver.com>
Wed, 13 Apr 2011 19:22:14 +0000 (15:22 -0400)
Beacon transmission is now handled through a slot mechanism.
This allows multiple beaconing interfaces to be be present.

Signed-off-by: Sujith Manoharan <Sujith.Manoharan@atheros.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/ath/ath9k/htc.h
drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
drivers/net/wireless/ath/ath9k/htc_drv_init.c
drivers/net/wireless/ath/ath9k/htc_drv_main.c
drivers/net/wireless/ath/ath9k/wmi.c

index cf7909ec07696f9fdf98b7b84f9bba12aa98eaad..31c649605d7955df12f70fedf81e31be9e2cc76c 100644 (file)
@@ -244,6 +244,7 @@ struct ath9k_htc_vif {
        u8 index;
        u16 seq_no;
        bool beacon_configured;
+       int bslot;
 };
 
 struct ath9k_vif_iter_data {
@@ -351,10 +352,14 @@ struct ath_led {
        int brightness;
 };
 
+#define BSTUCK_THRESHOLD 10
+
 struct htc_beacon_config {
+       struct ieee80211_vif *bslot[ATH9K_HTC_MAX_BCN_VIF];
        u16 beacon_interval;
        u16 dtim_period;
        u16 bmiss_timeout;
+       u32 bmiss_cnt;
 };
 
 struct ath_btcoex {
@@ -414,7 +419,6 @@ struct ath9k_htc_priv {
        u16 txpowlimit;
        u16 nvifs;
        u16 nstations;
-       u32 bmiss_cnt;
        bool rearm_ani;
        bool reconfig_beacon;
 
@@ -425,7 +429,6 @@ struct ath9k_htc_priv {
        bool tx_queues_stop;
        spinlock_t tx_lock;
 
-       struct ieee80211_vif *vif;
        struct htc_beacon_config cur_beacon_conf;
        unsigned int rxfilter;
        struct tasklet_struct swba_tasklet;
@@ -473,11 +476,15 @@ static inline void ath_read_cachesize(struct ath_common *common, int *csz)
 
 void ath9k_htc_reset(struct ath9k_htc_priv *priv);
 
+void ath9k_htc_assign_bslot(struct ath9k_htc_priv *priv,
+                           struct ieee80211_vif *vif);
+void ath9k_htc_remove_bslot(struct ath9k_htc_priv *priv,
+                           struct ieee80211_vif *vif);
 void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv);
 void ath9k_htc_beacon_config(struct ath9k_htc_priv *priv,
                             struct ieee80211_vif *vif);
 void ath9k_htc_beacon_reconfig(struct ath9k_htc_priv *priv);
-void ath9k_htc_swba(struct ath9k_htc_priv *priv, u8 beacon_pending);
+void ath9k_htc_swba(struct ath9k_htc_priv *priv);
 
 void ath9k_htc_rxep(void *priv, struct sk_buff *skb,
                    enum htc_endpoint_id ep_id);
index 8f56158e5887a49ebc23c018ecfc1105a93d3931..b561f703e467b3620398e7a62e310db237601294 100644 (file)
@@ -172,12 +172,13 @@ static void ath9k_htc_beacon_config_ap(struct ath9k_htc_priv *priv,
                imask |= ATH9K_INT_SWBA;
 
        ath_dbg(common, ATH_DBG_CONFIG,
-               "AP Beacon config, intval: %d, nexttbtt: %u imask: 0x%x\n",
+               "AP Beacon config, intval: %d, nexttbtt: %u "
+               "imask: 0x%x\n",
                bss_conf->beacon_interval, nexttbtt, imask);
 
        WMI_CMD(WMI_DISABLE_INTR_CMDID);
        ath9k_hw_beaconinit(priv->ah, TU_TO_USEC(nexttbtt), TU_TO_USEC(intval));
-       priv->bmiss_cnt = 0;
+       priv->cur_beacon_conf.bmiss_cnt = 0;
        htc_imask = cpu_to_be32(imask);
        WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask);
 }
@@ -214,7 +215,7 @@ static void ath9k_htc_beacon_config_adhoc(struct ath9k_htc_priv *priv,
 
        WMI_CMD(WMI_DISABLE_INTR_CMDID);
        ath9k_hw_beaconinit(priv->ah, TU_TO_USEC(nexttbtt), TU_TO_USEC(intval));
-       priv->bmiss_cnt = 0;
+       priv->cur_beacon_conf.bmiss_cnt = 0;
        htc_imask = cpu_to_be32(imask);
        WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask);
 }
@@ -225,9 +226,11 @@ void ath9k_htc_beaconep(void *drv_priv, struct sk_buff *skb,
        dev_kfree_skb_any(skb);
 }
 
-void ath9k_htc_swba(struct ath9k_htc_priv *priv, u8 beacon_pending)
+static void ath9k_htc_send_beacon(struct ath9k_htc_priv *priv,
+                                 int slot)
 {
-       struct ath9k_htc_vif *avp = (void *)priv->vif->drv_priv;
+       struct ieee80211_vif *vif;
+       struct ath9k_htc_vif *avp;
        struct tx_beacon_header beacon_hdr;
        struct ath9k_htc_tx_ctl tx_ctl;
        struct ieee80211_tx_info *info;
@@ -237,21 +240,18 @@ void ath9k_htc_swba(struct ath9k_htc_priv *priv, u8 beacon_pending)
        memset(&beacon_hdr, 0, sizeof(struct tx_beacon_header));
        memset(&tx_ctl, 0, sizeof(struct ath9k_htc_tx_ctl));
 
-       /* FIXME: Handle BMISS */
-       if (beacon_pending != 0) {
-               priv->bmiss_cnt++;
-               return;
-       }
-
        spin_lock_bh(&priv->beacon_lock);
 
+       vif = priv->cur_beacon_conf.bslot[slot];
+       avp = (struct ath9k_htc_vif *)vif->drv_priv;
+
        if (unlikely(priv->op_flags & OP_SCANNING)) {
                spin_unlock_bh(&priv->beacon_lock);
                return;
        }
 
        /* Get a new beacon */
-       beacon = ieee80211_beacon_get(priv->hw, priv->vif);
+       beacon = ieee80211_beacon_get(priv->hw, vif);
        if (!beacon) {
                spin_unlock_bh(&priv->beacon_lock);
                return;
@@ -276,6 +276,69 @@ void ath9k_htc_swba(struct ath9k_htc_priv *priv, u8 beacon_pending)
        spin_unlock_bh(&priv->beacon_lock);
 }
 
+static int ath9k_htc_choose_bslot(struct ath9k_htc_priv *priv)
+{
+       struct ath_common *common = ath9k_hw_common(priv->ah);
+       unsigned long flags;
+       u64 tsf;
+       u32 tsftu;
+       u16 intval;
+       int slot;
+
+       intval = priv->cur_beacon_conf.beacon_interval & ATH9K_BEACON_PERIOD;
+
+       spin_lock_irqsave(&priv->wmi->wmi_lock, flags);
+       tsf = priv->wmi->tsf;
+       spin_unlock_irqrestore(&priv->wmi->wmi_lock, flags);
+
+       tsftu = TSF_TO_TU(tsf >> 32, tsf);
+       slot = ((tsftu % intval) * ATH9K_HTC_MAX_BCN_VIF) / intval;
+       slot = ATH9K_HTC_MAX_BCN_VIF - slot - 1;
+
+       ath_dbg(common, ATH_DBG_BEACON,
+               "Choose slot: %d, tsf: %llu, tsftu: %u, intval: %u\n",
+               slot, tsf, tsftu, intval);
+
+       return slot;
+}
+
+void ath9k_htc_swba(struct ath9k_htc_priv *priv)
+{
+       struct ath_common *common = ath9k_hw_common(priv->ah);
+       unsigned long flags;
+       int slot;
+
+       spin_lock_irqsave(&priv->wmi->wmi_lock, flags);
+       if (priv->wmi->beacon_pending != 0) {
+               spin_unlock_irqrestore(&priv->wmi->wmi_lock, flags);
+               priv->cur_beacon_conf.bmiss_cnt++;
+               if (priv->cur_beacon_conf.bmiss_cnt > BSTUCK_THRESHOLD) {
+                       ath_dbg(common, ATH_DBG_BEACON,
+                               "Beacon stuck, HW reset\n");
+                       ath9k_htc_reset(priv);
+               }
+               return;
+       }
+       spin_unlock_irqrestore(&priv->wmi->wmi_lock, flags);
+
+       if (priv->cur_beacon_conf.bmiss_cnt) {
+               ath_dbg(common, ATH_DBG_BEACON,
+                       "Resuming beacon xmit after %u misses\n",
+                       priv->cur_beacon_conf.bmiss_cnt);
+               priv->cur_beacon_conf.bmiss_cnt = 0;
+       }
+
+       slot = ath9k_htc_choose_bslot(priv);
+       spin_lock_bh(&priv->beacon_lock);
+       if (priv->cur_beacon_conf.bslot[slot] == NULL) {
+               spin_unlock_bh(&priv->beacon_lock);
+               return;
+       }
+       spin_unlock_bh(&priv->beacon_lock);
+
+       ath9k_htc_send_beacon(priv, slot);
+}
+
 /* Currently, only for IBSS */
 void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv)
 {
@@ -307,6 +370,42 @@ void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv)
        }
 }
 
+void ath9k_htc_assign_bslot(struct ath9k_htc_priv *priv,
+                           struct ieee80211_vif *vif)
+{
+       struct ath_common *common = ath9k_hw_common(priv->ah);
+       struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *)vif->drv_priv;
+       int i = 0;
+
+       spin_lock_bh(&priv->beacon_lock);
+       for (i = 0; i < ATH9K_HTC_MAX_BCN_VIF; i++) {
+               if (priv->cur_beacon_conf.bslot[i] == NULL) {
+                       avp->bslot = i;
+                       break;
+               }
+       }
+
+       priv->cur_beacon_conf.bslot[avp->bslot] = vif;
+       spin_unlock_bh(&priv->beacon_lock);
+
+       ath_dbg(common, ATH_DBG_CONFIG,
+               "Added interface at beacon slot: %d\n", avp->bslot);
+}
+
+void ath9k_htc_remove_bslot(struct ath9k_htc_priv *priv,
+                           struct ieee80211_vif *vif)
+{
+       struct ath_common *common = ath9k_hw_common(priv->ah);
+       struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *)vif->drv_priv;
+
+       spin_lock_bh(&priv->beacon_lock);
+       priv->cur_beacon_conf.bslot[avp->bslot] = NULL;
+       spin_unlock_bh(&priv->beacon_lock);
+
+       ath_dbg(common, ATH_DBG_CONFIG,
+               "Removed interface at beacon slot: %d\n", avp->bslot);
+}
+
 static void ath9k_htc_beacon_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
 {
        bool *beacon_configured = (bool *)data;
index 6bbfca58deda9eea86a4707e025115641f4252ea..9405e0ad7032ae39104151c81fdc9ed01cf177dd 100644 (file)
@@ -643,7 +643,7 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv,
 {
        struct ath_hw *ah = NULL;
        struct ath_common *common;
-       int ret = 0, csz = 0;
+       int i, ret = 0, csz = 0;
 
        priv->op_flags |= OP_INVALID;
 
@@ -711,6 +711,9 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv,
        if (ret)
                goto err_queues;
 
+       for (i = 0; i < ATH9K_HTC_MAX_BCN_VIF; i++)
+               priv->cur_beacon_conf.bslot[i] = NULL;
+
        ath9k_init_crypto(priv);
        ath9k_init_channels_rates(priv);
        ath9k_init_misc(priv);
index db8c0c044e9e8498a97dc4788906624b7087c531..293a9b38e22e0a255ffa29e3446d34153409b7d5 100644 (file)
@@ -1281,9 +1281,13 @@ static int ath9k_htc_add_interface(struct ieee80211_hw *hw,
 
        priv->vif_slot |= (1 << avp->index);
        priv->nvifs++;
-       priv->vif = vif;
 
        INC_VIF(priv, vif->type);
+
+       if ((vif->type == NL80211_IFTYPE_AP) ||
+           (vif->type == NL80211_IFTYPE_ADHOC))
+               ath9k_htc_assign_bslot(priv, vif);
+
        ath9k_htc_set_opmode(priv);
 
        if ((priv->ah->opmode == NL80211_IFTYPE_AP) &&
@@ -1321,9 +1325,13 @@ static void ath9k_htc_remove_interface(struct ieee80211_hw *hw,
        priv->vif_slot &= ~(1 << avp->index);
 
        ath9k_htc_remove_station(priv, vif, NULL);
-       priv->vif = NULL;
 
        DEC_VIF(priv, vif->type);
+
+       if ((vif->type == NL80211_IFTYPE_AP) ||
+           (vif->type == NL80211_IFTYPE_ADHOC))
+               ath9k_htc_remove_bslot(priv, vif);
+
        ath9k_htc_set_opmode(priv);
 
        /*
index 96171a2c6873e9038e0ea1abe55063c38b9fef39..a39552b3077ba62b9859b9c9647408d718bc8c65 100644 (file)
@@ -126,7 +126,7 @@ void ath9k_swba_tasklet(unsigned long data)
 {
        struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data;
 
-       ath9k_htc_swba(priv, priv->wmi->beacon_pending);
+       ath9k_htc_swba(priv);
 }
 
 void ath9k_fatal_work(struct work_struct *work)
@@ -173,8 +173,10 @@ static void ath9k_wmi_ctrl_rx(void *priv, struct sk_buff *skb,
                case WMI_SWBA_EVENTID:
                        swba = (struct wmi_event_swba *) wmi_event;
 
+                       spin_lock(&wmi->wmi_lock);
                        wmi->tsf = be64_to_cpu(swba->tsf);
                        wmi->beacon_pending = swba->beacon_pending;
+                       spin_unlock(&wmi->wmi_lock);
 
                        tasklet_schedule(&wmi->drv_priv->swba_tasklet);
                        break;