ipw2x00: age scan results on resume
authorDan Williams <dcbw@redhat.com>
Wed, 11 Feb 2009 18:26:06 +0000 (13:26 -0500)
committerJohn W. Linville <linville@tuxdriver.com>
Fri, 27 Feb 2009 19:52:43 +0000 (14:52 -0500)
Scanned BSS entries are timestamped with jiffies, which doesn't
increment across suspend and hibernate.  On resume, every BSS in the
scan list looks like it was scanned within the last 10 seconds,
irregardless of how long the machine was actually asleep.  Age scan
results on resume with the time spent during sleep so userspace has a
clue how old they really are.

Signed-off-by: Dan Williams <dcbw@redhat.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/ipw2x00/ieee80211.h
drivers/net/wireless/ipw2x00/ipw2100.c
drivers/net/wireless/ipw2x00/ipw2100.h
drivers/net/wireless/ipw2x00/ipw2200.c
drivers/net/wireless/ipw2x00/ipw2200.h
drivers/net/wireless/ipw2x00/libipw_module.c
drivers/net/wireless/ipw2x00/libipw_rx.c
drivers/net/wireless/ipw2x00/libipw_wx.c

index adb7cf31f781f48cd564df727400f173b8e93d66..7515fad00f9237164d4be6749f665eeb58f4ea0a 100644 (file)
@@ -1119,6 +1119,9 @@ static inline int ieee80211_is_cck_rate(u8 rate)
 extern void free_ieee80211(struct net_device *dev);
 extern struct net_device *alloc_ieee80211(int sizeof_priv);
 
+extern void ieee80211_networks_age(struct ieee80211_device *ieee,
+                                  unsigned long age_secs);
+
 extern int ieee80211_set_encryption(struct ieee80211_device *ieee);
 
 /* ieee80211_tx.c */
index 52b1cf5160f7c1cf40e8ebce5b19a507303d5b8a..3a6d810a7608bdfc88ec540f9c95dc3d96ee4a74 100644 (file)
@@ -1692,7 +1692,13 @@ static int ipw2100_up(struct ipw2100_priv *priv, int deferred)
        u32 lock;
        u32 ord_len = sizeof(lock);
 
-       /* Quite if manually disabled. */
+       /* Age scan list entries found before suspend */
+       if (priv->suspend_time) {
+               ieee80211_networks_age(priv->ieee, priv->suspend_time);
+               priv->suspend_time = 0;
+       }
+
+       /* Quiet if manually disabled. */
        if (priv->status & STATUS_RF_KILL_SW) {
                IPW_DEBUG_INFO("%s: Radio is disabled by Manual Disable "
                               "switch\n", priv->net_dev->name);
@@ -6415,6 +6421,8 @@ static int ipw2100_suspend(struct pci_dev *pci_dev, pm_message_t state)
        pci_disable_device(pci_dev);
        pci_set_power_state(pci_dev, PCI_D3hot);
 
+       priv->suspend_at = get_seconds();
+
        mutex_unlock(&priv->action_mutex);
 
        return 0;
@@ -6458,6 +6466,8 @@ static int ipw2100_resume(struct pci_dev *pci_dev)
         * the queue of needed */
        netif_device_attach(dev);
 
+       priv->suspend_time = get_seconds() - priv->suspend_at;
+
        /* Bring the device back up */
        if (!(priv->status & STATUS_RF_KILL_SW))
                ipw2100_up(priv, 0);
index 46b135d2167032daf75d1b939a2e21b5859411a8..f183d951cd32754c7812c419303a4ce343ff1e19 100644 (file)
@@ -591,6 +591,10 @@ struct ipw2100_priv {
 
        int user_requested_scan;
 
+       /* Track time in suspend */
+       unsigned long suspend_at;
+       unsigned long suspend_time;
+
        u32 interrupts;
        int tx_interrupts;
        int rx_interrupts;
index 01c4ede90662b760368c507a69a97f2464bbe228..a7fb08aecf3f37f786563f439a5041c4e85cb03e 100644 (file)
@@ -11238,6 +11238,12 @@ static int ipw_up(struct ipw_priv *priv)
 {
        int rc, i, j;
 
+       /* Age scan list entries found before suspend */
+       if (priv->suspend_time) {
+               ieee80211_networks_age(priv->ieee, priv->suspend_time);
+               priv->suspend_time = 0;
+       }
+
        if (priv->status & STATUS_EXIT_PENDING)
                return -EIO;
 
@@ -11838,6 +11844,8 @@ static int ipw_pci_suspend(struct pci_dev *pdev, pm_message_t state)
        pci_disable_device(pdev);
        pci_set_power_state(pdev, pci_choose_state(pdev, state));
 
+       priv->suspend_at = get_seconds();
+
        return 0;
 }
 
@@ -11873,6 +11881,8 @@ static int ipw_pci_resume(struct pci_dev *pdev)
         * the queue of needed */
        netif_device_attach(dev);
 
+       priv->suspend_time = get_seconds() - priv->suspend_at;
+
        /* Bring the device back up */
        queue_work(priv->workqueue, &priv->up);
 
index 3e66c998dfea867a7c1589e3f6774b6917e6d0f5..05e8ccf01c5ff907bdfa07dbc937090bd32f29db 100644 (file)
@@ -1347,6 +1347,10 @@ struct ipw_priv {
 
        s8 tx_power;
 
+       /* Track time in suspend */
+       unsigned long suspend_at;
+       unsigned long suspend_time;
+
 #ifdef CONFIG_PM
        u32 pm_state[16];
 #endif
index 0f233ab6a95b0ba0d87f8283513bfd1ea7ed8572..ec7753446bd31fdac753c09761207920d09ddbf9 100644 (file)
@@ -105,6 +105,21 @@ static inline void ieee80211_networks_free(struct ieee80211_device *ieee)
        ieee->networks = NULL;
 }
 
+void ieee80211_networks_age(struct ieee80211_device *ieee,
+                            unsigned long age_secs)
+{
+       struct ieee80211_network *network = NULL;
+       unsigned long flags;
+       unsigned long age_jiffies = msecs_to_jiffies(age_secs * MSEC_PER_SEC);
+
+       spin_lock_irqsave(&ieee->lock, flags);
+       list_for_each_entry(network, &ieee->network_list, list) {
+               network->last_scanned -= age_jiffies;
+       }
+       spin_unlock_irqrestore(&ieee->lock, flags);
+}
+EXPORT_SYMBOL(ieee80211_networks_age);
+
 static void ieee80211_networks_initialize(struct ieee80211_device *ieee)
 {
        int i;
index 4865475e8a81b0373d65466d619be9de1cb0b793..8d9e96f9eb2844449ed73214958871bfdfa5d7a0 100644 (file)
@@ -1616,7 +1616,7 @@ static void ieee80211_process_probe_response(struct ieee80211_device
                        break;
 
                if ((oldest == NULL) ||
-                   (target->last_scanned < oldest->last_scanned))
+                   time_before(target->last_scanned, oldest->last_scanned))
                        oldest = target;
        }
 
index dfbadb3b9bd527b682882e6f6ff5546ef1795470..3c0812db030a0389c2400f933dc8ff1c069cce4d 100644 (file)
@@ -43,6 +43,16 @@ static const char *ieee80211_modes[] = {
        "?", "a", "b", "ab", "g", "ag", "bg", "abg"
 };
 
+static inline unsigned int elapsed_jiffies_msecs(unsigned long start)
+{
+       unsigned long end = jiffies;
+
+       if (end >= start)
+               return jiffies_to_msecs(end - start);
+
+       return jiffies_to_msecs(end + (MAX_JIFFY_OFFSET - start) + 1);
+}
+
 #define MAX_CUSTOM_LEN 64
 static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
                                      char *start, char *stop,
@@ -216,8 +226,8 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
        iwe.cmd = IWEVCUSTOM;
        p = custom;
        p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
-                     " Last beacon: %dms ago",
-                     jiffies_to_msecs(jiffies - network->last_scanned));
+                     " Last beacon: %ums ago",
+                     elapsed_jiffies_msecs(network->last_scanned));
        iwe.u.data.length = p - custom;
        if (iwe.u.data.length)
                start = iwe_stream_add_point(info, start, stop, &iwe, custom);
@@ -277,15 +287,15 @@ int ieee80211_wx_get_scan(struct ieee80211_device *ieee,
                    time_after(network->last_scanned + ieee->scan_age, jiffies))
                        ev = ieee80211_translate_scan(ieee, ev, stop, network,
                                                      info);
-               else
+               else {
                        IEEE80211_DEBUG_SCAN("Not showing network '%s ("
-                                            "%pM)' due to age (%dms).\n",
+                                            "%pM)' due to age (%ums).\n",
                                             print_ssid(ssid, network->ssid,
                                                         network->ssid_len),
                                             network->bssid,
-                                            jiffies_to_msecs(jiffies -
-                                                             network->
-                                                             last_scanned));
+                                            elapsed_jiffies_msecs(
+                                                      network->last_scanned));
+               }
        }
 
        spin_unlock_irqrestore(&ieee->lock, flags);