summaryrefslogtreecommitdiffstats
path: root/freed-ora/current/f13-2.6.33/linux-2.6-mac80211-age-scan-results-on-resume.patch
blob: d9e9631bd54bc8f76b1cfdbaf96b02fde1a4815f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
Backport of "cfg80211: age scan results on resume" by Dan Williams.

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 23c0ab7..0432eb6 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -450,6 +450,9 @@ struct ieee80211_channel;
  * 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.
  *
@@ -499,6 +502,9 @@ struct ieee80211_channel;
  * @set_channel: Set channel
  */
 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 21c5d96..ae2d34d 100644
--- a/include/net/wireless.h
+++ b/include/net/wireless.h
@@ -220,6 +220,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 9d4e4d8..691183e 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1141,6 +1141,32 @@ static int ieee80211_set_channel(struct wiphy *wiphy,
 	return ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
 }
 
+#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,
@@ -1169,4 +1195,6 @@ struct cfg80211_ops mac80211_config_ops = {
 	.change_bss = ieee80211_change_bss,
 	.set_txq_params = ieee80211_set_txq_params,
 	.set_channel = ieee80211_set_channel,
+	.suspend = ieee80211_suspend,
+	.resume = ieee80211_resume,
 };
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index f5c7c33..eb43ff5 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -745,6 +745,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,
@@ -857,8 +866,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/wireless/core.h b/net/wireless/core.h
index f7fb9f4..a4031a9 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -41,6 +41,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 79a3828..dc92564 100644
--- a/net/wireless/sysfs.c
+++ b/net/wireless/sysfs.c
@@ -55,6 +55,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,
@@ -63,6 +96,8 @@ struct class ieee80211_class = {
 #ifdef CONFIG_HOTPLUG
 	.dev_uevent = wiphy_uevent,
 #endif
+	.suspend = wiphy_suspend,
+	.resume = wiphy_resume,
 };
 
 int wiphy_sysfs_init(void)
OpenPOWER on IntegriCloud