wlcore/wl12xx: implement better beacon loss handling
authorBartosz.Markowski@tieto.com <Bartosz.Markowski@tieto.com>
Thu, 26 Apr 2012 07:35:07 +0000 (10:35 +0300)
committerJohn W. Linville <linville@tuxdriver.com>
Tue, 15 May 2012 21:53:25 +0000 (17:53 -0400)
Make use of REGAINED_BSS_EVENT and instead of reporting connection
loss immediately on each BEACON_LOSE event, try if not regained
in reasonable period of time.

Signed-off-by: bartosz.markowski <bartosz.markowski@tieto.com>
Signed-off-by: Luciano Coelho <coelho@ti.com>
drivers/net/wireless/ti/wlcore/boot.c
drivers/net/wireless/ti/wlcore/event.c
drivers/net/wireless/ti/wlcore/main.c
drivers/net/wireless/ti/wlcore/wlcore.h

index eb204ba979350fabbcfcec6189ffd232d36ba498..9b98230f84cecd9ae14b29c028b0e2b4bbb49a67 100644 (file)
@@ -413,6 +413,7 @@ int wlcore_boot_run_firmware(struct wl1271 *wl)
 
        /* unmask required mbox events  */
        wl->event_mask = BSS_LOSE_EVENT_ID |
+               REGAINED_BSS_EVENT_ID |
                SCAN_COMPLETE_EVENT_ID |
                ROLE_STOP_COMPLETE_EVENT_ID |
                RSSI_SNR_TRIGGER_0_EVENT_ID |
index 292632ddf8901c641a3df880bbb7d34c369a3942..28e2a633c3be0eb96689f1414520c03c10de8060 100644 (file)
@@ -103,7 +103,6 @@ static int wl1271_event_process(struct wl1271 *wl)
        struct ieee80211_vif *vif;
        struct wl12xx_vif *wlvif;
        u32 vector;
-       bool beacon_loss = false;
        bool disconnect_sta = false;
        unsigned long sta_bitmap = 0;
 
@@ -141,20 +140,23 @@ static int wl1271_event_process(struct wl1271 *wl)
                                               mbox->soft_gemini_sense_info);
 
        /*
-        * The BSS_LOSE_EVENT_ID is only needed while psm (and hence beacon
-        * filtering) is enabled. Without PSM, the stack will receive all
-        * beacons and can detect beacon loss by itself.
-        *
-        * As there's possibility that the driver disables PSM before receiving
-        * BSS_LOSE_EVENT, beacon loss has to be reported to the stack.
-        *
+        * We are HW_MONITOR device. On beacon loss - queue
+        * connection loss work. Cancel it on REGAINED event.
         */
        if (vector & BSS_LOSE_EVENT_ID) {
                /* TODO: check for multi-role */
+               int delay = wl->conf.conn.synch_fail_thold *
+                                       wl->conf.conn.bss_lose_timeout;
                wl1271_info("Beacon loss detected.");
+               cancel_delayed_work_sync(&wl->connection_loss_work);
+               ieee80211_queue_delayed_work(wl->hw, &wl->connection_loss_work,
+                     msecs_to_jiffies(delay));
+       }
 
-               /* indicate to the stack, that beacons have been lost */
-               beacon_loss = true;
+       if (vector & REGAINED_BSS_EVENT_ID) {
+               /* TODO: check for multi-role */
+               wl1271_info("Beacon regained.");
+               cancel_delayed_work_sync(&wl->connection_loss_work);
        }
 
        if (vector & RSSI_SNR_TRIGGER_0_EVENT_ID) {
@@ -257,13 +259,6 @@ static int wl1271_event_process(struct wl1271 *wl)
                        rcu_read_unlock();
                }
        }
-
-       if (beacon_loss)
-               wl12xx_for_each_wlvif_sta(wl, wlvif) {
-                       vif = wl12xx_wlvif_to_vif(wlvif);
-                       ieee80211_connection_loss(vif);
-               }
-
        return 0;
 }
 
index 6cd09646d6ed275d9de76f1d2b0465024af42ef2..45fe911a6504f92dddff5a9415bb77a643b3c4a9 100644 (file)
@@ -1120,6 +1120,7 @@ int wl1271_plt_stop(struct wl1271 *wl)
        cancel_work_sync(&wl->recovery_work);
        cancel_delayed_work_sync(&wl->elp_work);
        cancel_delayed_work_sync(&wl->tx_watchdog_work);
+       cancel_delayed_work_sync(&wl->connection_loss_work);
 
        mutex_lock(&wl->mutex);
        wl1271_power_off(wl);
@@ -1753,6 +1754,7 @@ static void wl1271_op_stop(struct ieee80211_hw *hw)
        cancel_work_sync(&wl->tx_work);
        cancel_delayed_work_sync(&wl->elp_work);
        cancel_delayed_work_sync(&wl->tx_watchdog_work);
+       cancel_delayed_work_sync(&wl->connection_loss_work);
 
        /* let's notify MAC80211 about the remaining pending TX frames */
        wl12xx_tx_reset(wl, true);
@@ -3705,6 +3707,9 @@ sta_not_found:
                        do_join = true;
                        set_assoc = true;
 
+                       /* Cancel connection_loss_work */
+                       cancel_delayed_work_sync(&wl->connection_loss_work);
+
                        /*
                         * use basic rates from AP, and determine lowest rate
                         * to use with control frames.
@@ -4815,6 +4820,34 @@ static struct bin_attribute fwlog_attr = {
        .read = wl1271_sysfs_read_fwlog,
 };
 
+void wl1271_connection_loss_work(struct work_struct *work)
+{
+       struct delayed_work *dwork;
+       struct wl1271 *wl;
+       struct ieee80211_vif *vif;
+       struct wl12xx_vif *wlvif;
+
+       dwork = container_of(work, struct delayed_work, work);
+       wl = container_of(dwork, struct wl1271, connection_loss_work);
+
+       wl1271_info("Connection loss work.");
+
+       mutex_lock(&wl->mutex);
+
+       if (unlikely(wl->state == WL1271_STATE_OFF))
+               goto out;
+
+       /* Call mac80211 connection loss */
+       wl12xx_for_each_wlvif_sta(wl, wlvif) {
+               if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
+                       goto out;
+               vif = wl12xx_wlvif_to_vif(wlvif);
+               ieee80211_connection_loss(vif);
+       }
+out:
+       mutex_unlock(&wl->mutex);
+}
+
 static void wl12xx_derive_mac_addresses(struct wl1271 *wl,
                                        u32 oui, u32 nic, int n)
 {
@@ -5070,6 +5103,8 @@ struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size)
        INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
        INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
        INIT_DELAYED_WORK(&wl->tx_watchdog_work, wl12xx_tx_watchdog_work);
+       INIT_DELAYED_WORK(&wl->connection_loss_work,
+                         wl1271_connection_loss_work);
 
        wl->freezable_wq = create_freezable_workqueue("wl12xx_wq");
        if (!wl->freezable_wq) {
index e4f7aa345b45b3f728f796078fb8affc13661cc3..0b3f0b586f4bb534802b80ebf6dcb1f97e15c8a6 100644 (file)
@@ -243,6 +243,9 @@ struct wl1271 {
        struct wl1271_scan scan;
        struct delayed_work scan_complete_work;
 
+       /* Connection loss work */
+       struct delayed_work connection_loss_work;
+
        bool sched_scanning;
 
        /* The current band */