diff options
-rw-r--r-- | include/net/mac80211.h | 38 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 13 | ||||
-rw-r--r-- | net/mac80211/iface.c | 1 | ||||
-rw-r--r-- | net/mac80211/led.c | 121 | ||||
-rw-r--r-- | net/mac80211/led.h | 44 | ||||
-rw-r--r-- | net/mac80211/rx.c | 3 | ||||
-rw-r--r-- | net/mac80211/tx.c | 3 | ||||
-rw-r--r-- | net/mac80211/util.c | 2 |
8 files changed, 216 insertions, 9 deletions
diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 69ded1ee49ce..40a93d582c79 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h | |||
@@ -1852,11 +1852,26 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
1852 | */ | 1852 | */ |
1853 | int ieee80211_register_hw(struct ieee80211_hw *hw); | 1853 | int ieee80211_register_hw(struct ieee80211_hw *hw); |
1854 | 1854 | ||
1855 | /** | ||
1856 | * struct ieee80211_tpt_blink - throughput blink description | ||
1857 | * @throughput: throughput in Kbit/sec | ||
1858 | * @blink_time: blink time in milliseconds | ||
1859 | * (full cycle, ie. one off + one on period) | ||
1860 | */ | ||
1861 | struct ieee80211_tpt_blink { | ||
1862 | int throughput; | ||
1863 | int blink_time; | ||
1864 | }; | ||
1865 | |||
1855 | #ifdef CONFIG_MAC80211_LEDS | 1866 | #ifdef CONFIG_MAC80211_LEDS |
1856 | extern char *__ieee80211_get_tx_led_name(struct ieee80211_hw *hw); | 1867 | extern char *__ieee80211_get_tx_led_name(struct ieee80211_hw *hw); |
1857 | extern char *__ieee80211_get_rx_led_name(struct ieee80211_hw *hw); | 1868 | extern char *__ieee80211_get_rx_led_name(struct ieee80211_hw *hw); |
1858 | extern char *__ieee80211_get_assoc_led_name(struct ieee80211_hw *hw); | 1869 | extern char *__ieee80211_get_assoc_led_name(struct ieee80211_hw *hw); |
1859 | extern char *__ieee80211_get_radio_led_name(struct ieee80211_hw *hw); | 1870 | extern char *__ieee80211_get_radio_led_name(struct ieee80211_hw *hw); |
1871 | extern char *__ieee80211_create_tpt_led_trigger( | ||
1872 | struct ieee80211_hw *hw, | ||
1873 | const struct ieee80211_tpt_blink *blink_table, | ||
1874 | unsigned int blink_table_len); | ||
1860 | #endif | 1875 | #endif |
1861 | /** | 1876 | /** |
1862 | * ieee80211_get_tx_led_name - get name of TX LED | 1877 | * ieee80211_get_tx_led_name - get name of TX LED |
@@ -1935,6 +1950,29 @@ static inline char *ieee80211_get_radio_led_name(struct ieee80211_hw *hw) | |||
1935 | } | 1950 | } |
1936 | 1951 | ||
1937 | /** | 1952 | /** |
1953 | * ieee80211_create_tpt_led_trigger - create throughput LED trigger | ||
1954 | * @hw: the hardware to create the trigger for | ||
1955 | * @blink_table: the blink table -- needs to be ordered by throughput | ||
1956 | * @blink_table_len: size of the blink table | ||
1957 | * | ||
1958 | * This function returns %NULL (in case of error, or if no LED | ||
1959 | * triggers are configured) or the name of the new trigger. | ||
1960 | * This function must be called before ieee80211_register_hw(). | ||
1961 | */ | ||
1962 | static inline char * | ||
1963 | ieee80211_create_tpt_led_trigger(struct ieee80211_hw *hw, | ||
1964 | const struct ieee80211_tpt_blink *blink_table, | ||
1965 | unsigned int blink_table_len) | ||
1966 | { | ||
1967 | #ifdef CONFIG_MAC80211_LEDS | ||
1968 | return __ieee80211_create_tpt_led_trigger(hw, blink_table, | ||
1969 | blink_table_len); | ||
1970 | #else | ||
1971 | return NULL; | ||
1972 | #endif | ||
1973 | } | ||
1974 | |||
1975 | /** | ||
1938 | * ieee80211_unregister_hw - Unregister a hardware device | 1976 | * ieee80211_unregister_hw - Unregister a hardware device |
1939 | * | 1977 | * |
1940 | * This function instructs mac80211 to free allocated resources | 1978 | * This function instructs mac80211 to free allocated resources |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index eadaa243a3da..523b90be8dc5 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/types.h> | 23 | #include <linux/types.h> |
24 | #include <linux/spinlock.h> | 24 | #include <linux/spinlock.h> |
25 | #include <linux/etherdevice.h> | 25 | #include <linux/etherdevice.h> |
26 | #include <linux/leds.h> | ||
26 | #include <net/ieee80211_radiotap.h> | 27 | #include <net/ieee80211_radiotap.h> |
27 | #include <net/cfg80211.h> | 28 | #include <net/cfg80211.h> |
28 | #include <net/mac80211.h> | 29 | #include <net/mac80211.h> |
@@ -630,6 +631,17 @@ enum queue_stop_reason { | |||
630 | IEEE80211_QUEUE_STOP_REASON_SKB_ADD, | 631 | IEEE80211_QUEUE_STOP_REASON_SKB_ADD, |
631 | }; | 632 | }; |
632 | 633 | ||
634 | struct tpt_led_trigger { | ||
635 | struct led_trigger trig; | ||
636 | char name[32]; | ||
637 | const struct ieee80211_tpt_blink *blink_table; | ||
638 | unsigned int blink_table_len; | ||
639 | struct timer_list timer; | ||
640 | bool running; | ||
641 | unsigned long prev_traffic; | ||
642 | unsigned long tx_bytes, rx_bytes; | ||
643 | }; | ||
644 | |||
633 | /** | 645 | /** |
634 | * mac80211 scan flags - currently active scan mode | 646 | * mac80211 scan flags - currently active scan mode |
635 | * | 647 | * |
@@ -838,6 +850,7 @@ struct ieee80211_local { | |||
838 | #ifdef CONFIG_MAC80211_LEDS | 850 | #ifdef CONFIG_MAC80211_LEDS |
839 | int tx_led_counter, rx_led_counter; | 851 | int tx_led_counter, rx_led_counter; |
840 | struct led_trigger *tx_led, *rx_led, *assoc_led, *radio_led; | 852 | struct led_trigger *tx_led, *rx_led, *assoc_led, *radio_led; |
853 | struct tpt_led_trigger *tpt_led_trigger; | ||
841 | char tx_led_name[32], rx_led_name[32], | 854 | char tx_led_name[32], rx_led_name[32], |
842 | assoc_led_name[32], radio_led_name[32]; | 855 | assoc_led_name[32], radio_led_name[32]; |
843 | #endif | 856 | #endif |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index f0f11bb794af..989df7065c21 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -220,6 +220,7 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up) | |||
220 | /* we're brought up, everything changes */ | 220 | /* we're brought up, everything changes */ |
221 | hw_reconf_flags = ~0; | 221 | hw_reconf_flags = ~0; |
222 | ieee80211_led_radio(local, true); | 222 | ieee80211_led_radio(local, true); |
223 | ieee80211_start_tpt_led_trig(local); | ||
223 | } | 224 | } |
224 | 225 | ||
225 | /* | 226 | /* |
diff --git a/net/mac80211/led.c b/net/mac80211/led.c index 740a1d4e0a9c..79b13090aed7 100644 --- a/net/mac80211/led.c +++ b/net/mac80211/led.c | |||
@@ -103,6 +103,13 @@ void ieee80211_led_init(struct ieee80211_local *local) | |||
103 | local->radio_led = NULL; | 103 | local->radio_led = NULL; |
104 | } | 104 | } |
105 | } | 105 | } |
106 | |||
107 | if (local->tpt_led_trigger) { | ||
108 | if (led_trigger_register(&local->tpt_led_trigger->trig)) { | ||
109 | kfree(local->tpt_led_trigger); | ||
110 | local->tpt_led_trigger = NULL; | ||
111 | } | ||
112 | } | ||
106 | } | 113 | } |
107 | 114 | ||
108 | void ieee80211_led_exit(struct ieee80211_local *local) | 115 | void ieee80211_led_exit(struct ieee80211_local *local) |
@@ -123,6 +130,11 @@ void ieee80211_led_exit(struct ieee80211_local *local) | |||
123 | led_trigger_unregister(local->rx_led); | 130 | led_trigger_unregister(local->rx_led); |
124 | kfree(local->rx_led); | 131 | kfree(local->rx_led); |
125 | } | 132 | } |
133 | |||
134 | if (local->tpt_led_trigger) { | ||
135 | led_trigger_unregister(&local->tpt_led_trigger->trig); | ||
136 | kfree(local->tpt_led_trigger); | ||
137 | } | ||
126 | } | 138 | } |
127 | 139 | ||
128 | char *__ieee80211_get_radio_led_name(struct ieee80211_hw *hw) | 140 | char *__ieee80211_get_radio_led_name(struct ieee80211_hw *hw) |
@@ -156,3 +168,112 @@ char *__ieee80211_get_rx_led_name(struct ieee80211_hw *hw) | |||
156 | return local->rx_led_name; | 168 | return local->rx_led_name; |
157 | } | 169 | } |
158 | EXPORT_SYMBOL(__ieee80211_get_rx_led_name); | 170 | EXPORT_SYMBOL(__ieee80211_get_rx_led_name); |
171 | |||
172 | static unsigned long tpt_trig_traffic(struct ieee80211_local *local, | ||
173 | struct tpt_led_trigger *tpt_trig) | ||
174 | { | ||
175 | unsigned long traffic, delta; | ||
176 | |||
177 | traffic = tpt_trig->tx_bytes + tpt_trig->rx_bytes; | ||
178 | |||
179 | delta = traffic - tpt_trig->prev_traffic; | ||
180 | tpt_trig->prev_traffic = traffic; | ||
181 | return DIV_ROUND_UP(delta, 1024 / 8); | ||
182 | } | ||
183 | |||
184 | static void tpt_trig_timer(unsigned long data) | ||
185 | { | ||
186 | struct ieee80211_local *local = (void *)data; | ||
187 | struct tpt_led_trigger *tpt_trig = local->tpt_led_trigger; | ||
188 | struct led_classdev *led_cdev; | ||
189 | unsigned long on, off, tpt; | ||
190 | int i; | ||
191 | |||
192 | if (!tpt_trig->running) | ||
193 | return; | ||
194 | |||
195 | mod_timer(&tpt_trig->timer, round_jiffies(jiffies + HZ)); | ||
196 | |||
197 | tpt = tpt_trig_traffic(local, tpt_trig); | ||
198 | |||
199 | /* default to just solid on */ | ||
200 | on = 1; | ||
201 | off = 0; | ||
202 | |||
203 | for (i = tpt_trig->blink_table_len - 1; i >= 0; i--) { | ||
204 | if (tpt_trig->blink_table[i].throughput < 0 || | ||
205 | tpt > tpt_trig->blink_table[i].throughput) { | ||
206 | off = tpt_trig->blink_table[i].blink_time / 2; | ||
207 | on = tpt_trig->blink_table[i].blink_time - off; | ||
208 | break; | ||
209 | } | ||
210 | } | ||
211 | |||
212 | read_lock(&tpt_trig->trig.leddev_list_lock); | ||
213 | list_for_each_entry(led_cdev, &tpt_trig->trig.led_cdevs, trig_list) | ||
214 | led_blink_set(led_cdev, &on, &off); | ||
215 | read_unlock(&tpt_trig->trig.leddev_list_lock); | ||
216 | } | ||
217 | |||
218 | extern char *__ieee80211_create_tpt_led_trigger( | ||
219 | struct ieee80211_hw *hw, | ||
220 | const struct ieee80211_tpt_blink *blink_table, | ||
221 | unsigned int blink_table_len) | ||
222 | { | ||
223 | struct ieee80211_local *local = hw_to_local(hw); | ||
224 | struct tpt_led_trigger *tpt_trig; | ||
225 | |||
226 | if (WARN_ON(local->tpt_led_trigger)) | ||
227 | return NULL; | ||
228 | |||
229 | tpt_trig = kzalloc(sizeof(struct tpt_led_trigger), GFP_KERNEL); | ||
230 | if (!tpt_trig) | ||
231 | return NULL; | ||
232 | |||
233 | snprintf(tpt_trig->name, sizeof(tpt_trig->name), | ||
234 | "%stpt", wiphy_name(local->hw.wiphy)); | ||
235 | |||
236 | tpt_trig->trig.name = tpt_trig->name; | ||
237 | |||
238 | tpt_trig->blink_table = blink_table; | ||
239 | tpt_trig->blink_table_len = blink_table_len; | ||
240 | |||
241 | setup_timer(&tpt_trig->timer, tpt_trig_timer, (unsigned long)local); | ||
242 | |||
243 | local->tpt_led_trigger = tpt_trig; | ||
244 | |||
245 | return tpt_trig->name; | ||
246 | } | ||
247 | EXPORT_SYMBOL(__ieee80211_create_tpt_led_trigger); | ||
248 | |||
249 | void ieee80211_start_tpt_led_trig(struct ieee80211_local *local) | ||
250 | { | ||
251 | struct tpt_led_trigger *tpt_trig = local->tpt_led_trigger; | ||
252 | |||
253 | if (!tpt_trig) | ||
254 | return; | ||
255 | |||
256 | /* reset traffic */ | ||
257 | tpt_trig_traffic(local, tpt_trig); | ||
258 | tpt_trig->running = true; | ||
259 | |||
260 | tpt_trig_timer((unsigned long)local); | ||
261 | mod_timer(&tpt_trig->timer, round_jiffies(jiffies + HZ)); | ||
262 | } | ||
263 | |||
264 | void ieee80211_stop_tpt_led_trig(struct ieee80211_local *local) | ||
265 | { | ||
266 | struct tpt_led_trigger *tpt_trig = local->tpt_led_trigger; | ||
267 | struct led_classdev *led_cdev; | ||
268 | |||
269 | if (!tpt_trig) | ||
270 | return; | ||
271 | |||
272 | tpt_trig->running = false; | ||
273 | del_timer_sync(&tpt_trig->timer); | ||
274 | |||
275 | read_lock(&tpt_trig->trig.leddev_list_lock); | ||
276 | list_for_each_entry(led_cdev, &tpt_trig->trig.led_cdevs, trig_list) | ||
277 | led_brightness_set(led_cdev, LED_OFF); | ||
278 | read_unlock(&tpt_trig->trig.leddev_list_lock); | ||
279 | } | ||
diff --git a/net/mac80211/led.h b/net/mac80211/led.h index 8320cbac61c6..6c215dc0fc96 100644 --- a/net/mac80211/led.h +++ b/net/mac80211/led.h | |||
@@ -12,15 +12,17 @@ | |||
12 | #include "ieee80211_i.h" | 12 | #include "ieee80211_i.h" |
13 | 13 | ||
14 | #ifdef CONFIG_MAC80211_LEDS | 14 | #ifdef CONFIG_MAC80211_LEDS |
15 | extern void ieee80211_led_rx(struct ieee80211_local *local); | 15 | void ieee80211_led_rx(struct ieee80211_local *local); |
16 | extern void ieee80211_led_tx(struct ieee80211_local *local, int q); | 16 | void ieee80211_led_tx(struct ieee80211_local *local, int q); |
17 | extern void ieee80211_led_assoc(struct ieee80211_local *local, | 17 | void ieee80211_led_assoc(struct ieee80211_local *local, |
18 | bool associated); | 18 | bool associated); |
19 | extern void ieee80211_led_radio(struct ieee80211_local *local, | 19 | void ieee80211_led_radio(struct ieee80211_local *local, |
20 | bool enabled); | 20 | bool enabled); |
21 | extern void ieee80211_led_names(struct ieee80211_local *local); | 21 | void ieee80211_led_names(struct ieee80211_local *local); |
22 | extern void ieee80211_led_init(struct ieee80211_local *local); | 22 | void ieee80211_led_init(struct ieee80211_local *local); |
23 | extern void ieee80211_led_exit(struct ieee80211_local *local); | 23 | void ieee80211_led_exit(struct ieee80211_local *local); |
24 | void ieee80211_start_tpt_led_trig(struct ieee80211_local *local); | ||
25 | void ieee80211_stop_tpt_led_trig(struct ieee80211_local *local); | ||
24 | #else | 26 | #else |
25 | static inline void ieee80211_led_rx(struct ieee80211_local *local) | 27 | static inline void ieee80211_led_rx(struct ieee80211_local *local) |
26 | { | 28 | { |
@@ -45,4 +47,28 @@ static inline void ieee80211_led_init(struct ieee80211_local *local) | |||
45 | static inline void ieee80211_led_exit(struct ieee80211_local *local) | 47 | static inline void ieee80211_led_exit(struct ieee80211_local *local) |
46 | { | 48 | { |
47 | } | 49 | } |
50 | static inline void ieee80211_start_tpt_led_trig(struct ieee80211_local *local) | ||
51 | { | ||
52 | } | ||
53 | static inline void ieee80211_stop_tpt_led_trig(struct ieee80211_local *local) | ||
54 | { | ||
55 | } | ||
56 | #endif | ||
57 | |||
58 | static inline void | ||
59 | ieee80211_tpt_led_trig_tx(struct ieee80211_local *local, __le16 fc, int bytes) | ||
60 | { | ||
61 | #ifdef CONFIG_MAC80211_LEDS | ||
62 | if (local->tpt_led_trigger && ieee80211_is_data(fc)) | ||
63 | local->tpt_led_trigger->tx_bytes += bytes; | ||
48 | #endif | 64 | #endif |
65 | } | ||
66 | |||
67 | static inline void | ||
68 | ieee80211_tpt_led_trig_rx(struct ieee80211_local *local, __le16 fc, int bytes) | ||
69 | { | ||
70 | #ifdef CONFIG_MAC80211_LEDS | ||
71 | if (local->tpt_led_trigger && ieee80211_is_data(fc)) | ||
72 | local->tpt_led_trigger->rx_bytes += bytes; | ||
73 | #endif | ||
74 | } | ||
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 7c5d1b2ec453..01a3f2630eaf 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -2928,6 +2928,9 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
2928 | return; | 2928 | return; |
2929 | } | 2929 | } |
2930 | 2930 | ||
2931 | ieee80211_tpt_led_trig_rx(local, | ||
2932 | ((struct ieee80211_hdr *)skb->data)->frame_control, | ||
2933 | skb->len); | ||
2931 | __ieee80211_rx_handle_packet(hw, skb); | 2934 | __ieee80211_rx_handle_packet(hw, skb); |
2932 | 2935 | ||
2933 | rcu_read_unlock(); | 2936 | rcu_read_unlock(); |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index d2b4b67a7b53..68c2fbd16ebb 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -1297,6 +1297,7 @@ static int __ieee80211_tx(struct ieee80211_local *local, | |||
1297 | 1297 | ||
1298 | while (skb) { | 1298 | while (skb) { |
1299 | int q = skb_get_queue_mapping(skb); | 1299 | int q = skb_get_queue_mapping(skb); |
1300 | __le16 fc; | ||
1300 | 1301 | ||
1301 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); | 1302 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); |
1302 | ret = IEEE80211_TX_OK; | 1303 | ret = IEEE80211_TX_OK; |
@@ -1339,6 +1340,7 @@ static int __ieee80211_tx(struct ieee80211_local *local, | |||
1339 | else | 1340 | else |
1340 | info->control.sta = NULL; | 1341 | info->control.sta = NULL; |
1341 | 1342 | ||
1343 | fc = ((struct ieee80211_hdr *)skb->data)->frame_control; | ||
1342 | ret = drv_tx(local, skb); | 1344 | ret = drv_tx(local, skb); |
1343 | if (WARN_ON(ret != NETDEV_TX_OK && skb->len != len)) { | 1345 | if (WARN_ON(ret != NETDEV_TX_OK && skb->len != len)) { |
1344 | dev_kfree_skb(skb); | 1346 | dev_kfree_skb(skb); |
@@ -1349,6 +1351,7 @@ static int __ieee80211_tx(struct ieee80211_local *local, | |||
1349 | return IEEE80211_TX_AGAIN; | 1351 | return IEEE80211_TX_AGAIN; |
1350 | } | 1352 | } |
1351 | 1353 | ||
1354 | ieee80211_tpt_led_trig_tx(local, fc, len); | ||
1352 | *skbp = skb = next; | 1355 | *skbp = skb = next; |
1353 | ieee80211_led_tx(local, 1); | 1356 | ieee80211_led_tx(local, 1); |
1354 | fragm = true; | 1357 | fragm = true; |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index e497476174ce..48306415a1cb 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -1116,6 +1116,7 @@ u32 ieee80211_sta_get_rates(struct ieee80211_local *local, | |||
1116 | void ieee80211_stop_device(struct ieee80211_local *local) | 1116 | void ieee80211_stop_device(struct ieee80211_local *local) |
1117 | { | 1117 | { |
1118 | ieee80211_led_radio(local, false); | 1118 | ieee80211_led_radio(local, false); |
1119 | ieee80211_stop_tpt_led_trig(local); | ||
1119 | 1120 | ||
1120 | cancel_work_sync(&local->reconfig_filter); | 1121 | cancel_work_sync(&local->reconfig_filter); |
1121 | 1122 | ||
@@ -1150,6 +1151,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1150 | } | 1151 | } |
1151 | 1152 | ||
1152 | ieee80211_led_radio(local, true); | 1153 | ieee80211_led_radio(local, true); |
1154 | ieee80211_start_tpt_led_trig(local); | ||
1153 | } | 1155 | } |
1154 | 1156 | ||
1155 | /* add interfaces */ | 1157 | /* add interfaces */ |