>From f795503c5966a69001dc79084ca63a1d2650fd7b Mon Sep 17 00:00:00 2001
From: Tim Gardner <tim.gardner@canonical.com>
Date: Wed, 8 Apr 2009 06:51:49 -0700
Subject: [PATCH] UBUNTU: SAUCE: (drop after 2.6.28) Wifi suspend/resume scan timeout fixes

OriginalAuthor: Dan Williams
OriginalLocation: https://bugzilla.redhat.com/attachment.cgi?id=333270
Bug: #336055
BumpABI: yes

ABI changes:
- 199 symbols changed hash and weren't ignored
- Module hash change summary...
    drivers/net/wireless/iwlwifi/iwlcore            : 101
    net/mac80211/mac80211                           :  39
    drivers/net/wireless/rt2x00/rt2x00lib           :  23
    drivers/net/wireless/rt2x00/rt2x00usb           :  11
    drivers/net/wireless/libertas_tf/libertas_tf    :   8
    net/wireless/cfg80211                           :   6
    drivers/net/wireless/p54/p54common              :   5
    drivers/net/wireless/rt2x00/rt2x00pci           :   4
    drivers/net/wireless/libertas_tf/libertas_tf_usb:   2

https://bugzilla.redhat.com/show_bug.cgi?id=466136

Signed-off-by: Tim Gardner <tim.gardner@canonical.com>
Acked-by: Stefan Bader <stefan.bader@canonical.com>
---
 include/net/cfg80211.h |    6 ++++++
 include/net/wireless.h |    3 +++
 net/mac80211/cfg.c     |   28 ++++++++++++++++++++++++++++
 net/mac80211/rx.c      |    1 +
 net/mac80211/scan.c    |   13 +++++++++++--
 net/mac80211/tx.c      |    1 +
 net/wireless/core.h    |    2 ++
 net/wireless/sysfs.c   |   35 +++++++++++++++++++++++++++++++++++
 8 files changed, 87 insertions(+), 2 deletions(-)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 0e85ec3..44fb3b9 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -363,6 +363,9 @@ struct wiphy;
  * wireless extensions but this is subject to reevaluation as soon as this
  * code is used more widely and we have a first user without wext.
  *
+ * @suspend: wiphy device needs to be suspended
+ * @resume: wiphy device needs to be resumed
+ *
  * @add_virtual_intf: create a new virtual interface with the given name,
  *	must set the struct wireless_dev's iftype.
  *
@@ -402,6 +405,9 @@ struct wiphy;
  * @change_bss: Modify parameters for a given BSS.
  */
 struct cfg80211_ops {
+	int	(*suspend)(struct wiphy *wiphy);
+	int	(*resume)(struct wiphy *wiphy);
+
 	int	(*add_virtual_intf)(struct wiphy *wiphy, char *name,
 				    enum nl80211_iftype type, u32 *flags,
 				    struct vif_params *params);
diff --git a/include/net/wireless.h b/include/net/wireless.h
index 721efb3..4c87939 100644
--- a/include/net/wireless.h
+++ b/include/net/wireless.h
@@ -212,6 +212,9 @@ struct wiphy {
 	/* dir in debugfs: ieee80211/<wiphyname> */
 	struct dentry *debugfsdir;
 
+	/* time spent in suspend, in seconds */
+	unsigned long suspend_duration;
+
 	char priv[0] __attribute__((__aligned__(NETDEV_ALIGN)));
 };
 
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 855126a..33d931f 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -991,6 +991,32 @@ static int ieee80211_change_bss(struct wiphy *wiphy,
 	return 0;
 }
 
+#ifdef CONFIG_PM
+static int ieee80211_suspend(struct wiphy *wiphy)
+{
+	return 0;
+}
+
+static int ieee80211_resume(struct wiphy *wiphy)
+{
+	struct ieee80211_local *local = wiphy_priv(wiphy);
+	unsigned long age_jiffies;
+	struct ieee80211_bss *bss;
+
+	age_jiffies = msecs_to_jiffies(wiphy->suspend_duration * MSEC_PER_SEC);
+	spin_lock_bh(&local->bss_lock);
+	list_for_each_entry(bss, &local->bss_list, list) {
+		bss->last_update -= age_jiffies;
+	}
+	spin_unlock_bh(&local->bss_lock);
+
+	return 0;
+}
+#else
+#define ieee80211_suspend NULL
+#define ieee80211_resume NULL
+#endif
+
 struct cfg80211_ops mac80211_config_ops = {
 	.add_virtual_intf = ieee80211_add_iface,
 	.del_virtual_intf = ieee80211_del_iface,
@@ -1015,4 +1041,6 @@ struct cfg80211_ops mac80211_config_ops = {
 	.dump_mpath = ieee80211_dump_mpath,
 #endif
 	.change_bss = ieee80211_change_bss,
+	.suspend = ieee80211_suspend,
+	.resume = ieee80211_resume,
 };
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index cf6b121..2d7dfad 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -1,3 +1,4 @@
+#define ETH_P_PAE	0x888E
 /*
  * Copyright 2002-2005, Instant802 Networks, Inc.
  * Copyright 2005-2006, Devicescape Software, Inc.
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index 416bb41..8164740 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -749,6 +749,15 @@ static void ieee80211_scan_add_ies(struct iw_request_info *info,
 	}
 }
 
+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);
+}
 
 static char *
 ieee80211_scan_result(struct ieee80211_local *local,
@@ -861,8 +870,8 @@ ieee80211_scan_result(struct ieee80211_local *local,
 						  &iwe, buf);
 		memset(&iwe, 0, sizeof(iwe));
 		iwe.cmd = IWEVCUSTOM;
-		sprintf(buf, " Last beacon: %dms ago",
-			jiffies_to_msecs(jiffies - bss->last_update));
+		sprintf(buf, " Last beacon: %ums ago",
+			elapsed_jiffies_msecs(bss->last_update));
 		iwe.u.data.length = strlen(buf);
 		current_ev = iwe_stream_add_point(info, current_ev,
 						  end_buf, &iwe, buf);
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index e24ae1b..67b2dc5 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1,3 +1,4 @@
+#define ETH_P_PAE	0x888E
 /*
  * Copyright 2002-2005, Instant802 Networks, Inc.
  * Copyright 2005-2006, Devicescape Software, Inc.
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 771cc5c..ff01ec3 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -28,6 +28,8 @@ struct cfg80211_registered_device {
 	struct mutex devlist_mtx;
 	struct list_head netdev_list;
 
+	unsigned long suspend_at;
+
 	/* must be last because of the way we do wiphy_priv(),
 	 * and it should at least be aligned to NETDEV_ALIGN */
 	struct wiphy wiphy __attribute__((__aligned__(NETDEV_ALIGN)));
diff --git a/net/wireless/sysfs.c b/net/wireless/sysfs.c
index 29f820e..cc9e9e4 100644
--- a/net/wireless/sysfs.c
+++ b/net/wireless/sysfs.c
@@ -60,6 +60,39 @@ static int wiphy_uevent(struct device *dev, struct kobj_uevent_env *env)
 }
 #endif
 
+static int wiphy_suspend(struct device *dev, pm_message_t state)
+{
+	struct cfg80211_registered_device *rdev = dev_to_rdev(dev);
+	int ret = 0;
+
+	rdev->wiphy.suspend_duration = 0;
+	rdev->suspend_at = get_seconds();
+
+	if (rdev->ops->suspend) {
+		rtnl_lock();
+		ret = rdev->ops->suspend(&rdev->wiphy);
+		rtnl_unlock();
+	}
+
+	return ret;
+}
+
+static int wiphy_resume(struct device *dev)
+{
+	struct cfg80211_registered_device *rdev = dev_to_rdev(dev);
+	int ret = 0;
+
+	rdev->wiphy.suspend_duration = get_seconds() - rdev->suspend_at;
+
+	if (rdev->ops->resume) {
+		rtnl_lock();
+		ret = rdev->ops->resume(&rdev->wiphy);
+		rtnl_unlock();
+	}
+
+	return ret;
+}
+
 struct class ieee80211_class = {
 	.name = "ieee80211",
 	.owner = THIS_MODULE,
@@ -68,6 +101,8 @@ struct class ieee80211_class = {
 #ifdef CONFIG_HOTPLUG
 	.dev_uevent = wiphy_uevent,
 #endif
+	.suspend = wiphy_suspend,
+	.resume = wiphy_resume,
 };
 
 int wiphy_sysfs_init(void)
-- 
1.5.4.3

