firmware-utils/mkzynfw: fix available flash space calculation
[openwrt.git] / package / mac80211 / patches / 310-mac80211_tpt_led.patch
1 --- a/net/mac80211/led.c
2 +++ b/net/mac80211/led.c
3 @@ -54,12 +54,22 @@ void ieee80211_led_radio(struct ieee8021
4                 led_trigger_event(local->radio_led, LED_OFF);
5  }
6  
7 +void ieee80211_led_names(struct ieee80211_local *local)
8 +{
9 +       snprintf(local->rx_led_name, sizeof(local->rx_led_name),
10 +                "%srx", wiphy_name(local->hw.wiphy));
11 +       snprintf(local->tx_led_name, sizeof(local->tx_led_name),
12 +                "%stx", wiphy_name(local->hw.wiphy));
13 +       snprintf(local->assoc_led_name, sizeof(local->assoc_led_name),
14 +                "%sassoc", wiphy_name(local->hw.wiphy));
15 +       snprintf(local->radio_led_name, sizeof(local->radio_led_name),
16 +                "%sradio", wiphy_name(local->hw.wiphy));
17 +}
18 +
19  void ieee80211_led_init(struct ieee80211_local *local)
20  {
21         local->rx_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
22         if (local->rx_led) {
23 -               snprintf(local->rx_led_name, sizeof(local->rx_led_name),
24 -                        "%srx", wiphy_name(local->hw.wiphy));
25                 local->rx_led->name = local->rx_led_name;
26                 if (led_trigger_register(local->rx_led)) {
27                         kfree(local->rx_led);
28 @@ -69,8 +79,6 @@ void ieee80211_led_init(struct ieee80211
29  
30         local->tx_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
31         if (local->tx_led) {
32 -               snprintf(local->tx_led_name, sizeof(local->tx_led_name),
33 -                        "%stx", wiphy_name(local->hw.wiphy));
34                 local->tx_led->name = local->tx_led_name;
35                 if (led_trigger_register(local->tx_led)) {
36                         kfree(local->tx_led);
37 @@ -80,8 +88,6 @@ void ieee80211_led_init(struct ieee80211
38  
39         local->assoc_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
40         if (local->assoc_led) {
41 -               snprintf(local->assoc_led_name, sizeof(local->assoc_led_name),
42 -                        "%sassoc", wiphy_name(local->hw.wiphy));
43                 local->assoc_led->name = local->assoc_led_name;
44                 if (led_trigger_register(local->assoc_led)) {
45                         kfree(local->assoc_led);
46 @@ -91,14 +97,19 @@ void ieee80211_led_init(struct ieee80211
47  
48         local->radio_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
49         if (local->radio_led) {
50 -               snprintf(local->radio_led_name, sizeof(local->radio_led_name),
51 -                        "%sradio", wiphy_name(local->hw.wiphy));
52                 local->radio_led->name = local->radio_led_name;
53                 if (led_trigger_register(local->radio_led)) {
54                         kfree(local->radio_led);
55                         local->radio_led = NULL;
56                 }
57         }
58 +
59 +       if (local->tpt_led_trigger) {
60 +               if (led_trigger_register(&local->tpt_led_trigger->trig)) {
61 +                       kfree(local->tpt_led_trigger);
62 +                       local->tpt_led_trigger = NULL;
63 +               }
64 +       }
65  }
66  
67  void ieee80211_led_exit(struct ieee80211_local *local)
68 @@ -119,15 +130,18 @@ void ieee80211_led_exit(struct ieee80211
69                 led_trigger_unregister(local->rx_led);
70                 kfree(local->rx_led);
71         }
72 +
73 +       if (local->tpt_led_trigger) {
74 +               led_trigger_unregister(&local->tpt_led_trigger->trig);
75 +               kfree(local->tpt_led_trigger);
76 +       }
77  }
78  
79  char *__ieee80211_get_radio_led_name(struct ieee80211_hw *hw)
80  {
81         struct ieee80211_local *local = hw_to_local(hw);
82  
83 -       if (local->radio_led)
84 -               return local->radio_led_name;
85 -       return NULL;
86 +       return local->radio_led_name;
87  }
88  EXPORT_SYMBOL(__ieee80211_get_radio_led_name);
89  
90 @@ -135,9 +149,7 @@ char *__ieee80211_get_assoc_led_name(str
91  {
92         struct ieee80211_local *local = hw_to_local(hw);
93  
94 -       if (local->assoc_led)
95 -               return local->assoc_led_name;
96 -       return NULL;
97 +       return local->assoc_led_name;
98  }
99  EXPORT_SYMBOL(__ieee80211_get_assoc_led_name);
100  
101 @@ -145,9 +157,7 @@ char *__ieee80211_get_tx_led_name(struct
102  {
103         struct ieee80211_local *local = hw_to_local(hw);
104  
105 -       if (local->tx_led)
106 -               return local->tx_led_name;
107 -       return NULL;
108 +       return local->tx_led_name;
109  }
110  EXPORT_SYMBOL(__ieee80211_get_tx_led_name);
111  
112 @@ -155,8 +165,115 @@ char *__ieee80211_get_rx_led_name(struct
113  {
114         struct ieee80211_local *local = hw_to_local(hw);
115  
116 -       if (local->rx_led)
117 -               return local->rx_led_name;
118 -       return NULL;
119 +       return local->rx_led_name;
120  }
121  EXPORT_SYMBOL(__ieee80211_get_rx_led_name);
122 +
123 +static unsigned long tpt_trig_traffic(struct ieee80211_local *local,
124 +                                     struct tpt_led_trigger *tpt_trig)
125 +{
126 +       unsigned long traffic, delta;
127 +
128 +       traffic = tpt_trig->tx_bytes + tpt_trig->rx_bytes;
129 +
130 +       delta = traffic - tpt_trig->prev_traffic;
131 +       tpt_trig->prev_traffic = traffic;
132 +       return DIV_ROUND_UP(delta, 1024 / 8);
133 +}
134 +
135 +static void tpt_trig_timer(unsigned long data)
136 +{
137 +       struct ieee80211_local *local = (void *)data;
138 +       struct tpt_led_trigger *tpt_trig = local->tpt_led_trigger;
139 +       struct led_classdev *led_cdev;
140 +       unsigned long on, off, tpt;
141 +       int i;
142 +
143 +       if (!tpt_trig->running)
144 +               return;
145 +
146 +       mod_timer(&tpt_trig->timer, round_jiffies(jiffies + HZ));
147 +
148 +       tpt = tpt_trig_traffic(local, tpt_trig);
149 +
150 +       /* default to just solid on */
151 +       on = 1;
152 +       off = 0;
153 +
154 +       for (i = tpt_trig->blink_table_len - 1; i >= 0; i--) {
155 +               if (tpt_trig->blink_table[i].throughput < 0 ||
156 +                   tpt > tpt_trig->blink_table[i].throughput) {
157 +                       off = tpt_trig->blink_table[i].blink_time / 2;
158 +                       on = tpt_trig->blink_table[i].blink_time - off;
159 +                       break;
160 +               }
161 +       }
162 +
163 +       read_lock(&tpt_trig->trig.leddev_list_lock);
164 +       list_for_each_entry(led_cdev, &tpt_trig->trig.led_cdevs, trig_list)
165 +               led_blink_set(led_cdev, &on, &off);
166 +       read_unlock(&tpt_trig->trig.leddev_list_lock);
167 +}
168 +
169 +extern char *__ieee80211_create_tpt_led_trigger(
170 +                               struct ieee80211_hw *hw,
171 +                               const struct ieee80211_tpt_blink *blink_table,
172 +                               unsigned int blink_table_len)
173 +{
174 +       struct ieee80211_local *local = hw_to_local(hw);
175 +       struct tpt_led_trigger *tpt_trig;
176 +
177 +       if (WARN_ON(local->tpt_led_trigger))
178 +               return NULL;
179 +
180 +       tpt_trig = kzalloc(sizeof(struct tpt_led_trigger), GFP_KERNEL);
181 +       if (!tpt_trig)
182 +               return NULL;
183 +
184 +       snprintf(tpt_trig->name, sizeof(tpt_trig->name),
185 +                "%stpt", wiphy_name(local->hw.wiphy));
186 +
187 +       tpt_trig->trig.name = tpt_trig->name;
188 +
189 +       tpt_trig->blink_table = blink_table;
190 +       tpt_trig->blink_table_len = blink_table_len;
191 +
192 +       setup_timer(&tpt_trig->timer, tpt_trig_timer, (unsigned long)local);
193 +
194 +       local->tpt_led_trigger = tpt_trig;
195 +
196 +       return tpt_trig->name;
197 +}
198 +EXPORT_SYMBOL(__ieee80211_create_tpt_led_trigger);
199 +
200 +void ieee80211_start_tpt_led_trig(struct ieee80211_local *local)
201 +{
202 +       struct tpt_led_trigger *tpt_trig = local->tpt_led_trigger;
203 +
204 +       if (!tpt_trig)
205 +               return;
206 +
207 +       /* reset traffic */
208 +       tpt_trig_traffic(local, tpt_trig);
209 +       tpt_trig->running = true;
210 +
211 +       tpt_trig_timer((unsigned long)local);
212 +       mod_timer(&tpt_trig->timer, round_jiffies(jiffies + HZ));
213 +}
214 +
215 +void ieee80211_stop_tpt_led_trig(struct ieee80211_local *local)
216 +{
217 +       struct tpt_led_trigger *tpt_trig = local->tpt_led_trigger;
218 +       struct led_classdev *led_cdev;
219 +
220 +       if (!tpt_trig)
221 +               return;
222 +
223 +       tpt_trig->running = false;
224 +       del_timer_sync(&tpt_trig->timer);
225 +
226 +       read_lock(&tpt_trig->trig.leddev_list_lock);
227 +       list_for_each_entry(led_cdev, &tpt_trig->trig.led_cdevs, trig_list)
228 +               led_brightness_set(led_cdev, LED_OFF);
229 +       read_unlock(&tpt_trig->trig.leddev_list_lock);
230 +}
231 --- a/net/mac80211/led.h
232 +++ b/net/mac80211/led.h
233 @@ -12,14 +12,17 @@
234  #include "ieee80211_i.h"
235  
236  #ifdef CONFIG_MAC80211_LEDS
237 -extern void ieee80211_led_rx(struct ieee80211_local *local);
238 -extern void ieee80211_led_tx(struct ieee80211_local *local, int q);
239 -extern void ieee80211_led_assoc(struct ieee80211_local *local,
240 -                               bool associated);
241 -extern void ieee80211_led_radio(struct ieee80211_local *local,
242 -                               bool enabled);
243 -extern void ieee80211_led_init(struct ieee80211_local *local);
244 -extern void ieee80211_led_exit(struct ieee80211_local *local);
245 +void ieee80211_led_rx(struct ieee80211_local *local);
246 +void ieee80211_led_tx(struct ieee80211_local *local, int q);
247 +void ieee80211_led_assoc(struct ieee80211_local *local,
248 +                        bool associated);
249 +void ieee80211_led_radio(struct ieee80211_local *local,
250 +                        bool enabled);
251 +void ieee80211_led_names(struct ieee80211_local *local);
252 +void ieee80211_led_init(struct ieee80211_local *local);
253 +void ieee80211_led_exit(struct ieee80211_local *local);
254 +void ieee80211_start_tpt_led_trig(struct ieee80211_local *local);
255 +void ieee80211_stop_tpt_led_trig(struct ieee80211_local *local);
256  #else
257  static inline void ieee80211_led_rx(struct ieee80211_local *local)
258  {
259 @@ -35,10 +38,37 @@ static inline void ieee80211_led_radio(s
260                                        bool enabled)
261  {
262  }
263 +static inline void ieee80211_led_names(struct ieee80211_local *local)
264 +{
265 +}
266  static inline void ieee80211_led_init(struct ieee80211_local *local)
267  {
268  }
269  static inline void ieee80211_led_exit(struct ieee80211_local *local)
270  {
271  }
272 +static inline void ieee80211_start_tpt_led_trig(struct ieee80211_local *local)
273 +{
274 +}
275 +static inline void ieee80211_stop_tpt_led_trig(struct ieee80211_local *local)
276 +{
277 +}
278 +#endif
279 +
280 +static inline void
281 +ieee80211_tpt_led_trig_tx(struct ieee80211_local *local, __le16 fc, int bytes)
282 +{
283 +#ifdef CONFIG_MAC80211_LEDS
284 +       if (local->tpt_led_trigger && ieee80211_is_data(fc))
285 +               local->tpt_led_trigger->tx_bytes += bytes;
286 +#endif
287 +}
288 +
289 +static inline void
290 +ieee80211_tpt_led_trig_rx(struct ieee80211_local *local, __le16 fc, int bytes)
291 +{
292 +#ifdef CONFIG_MAC80211_LEDS
293 +       if (local->tpt_led_trigger && ieee80211_is_data(fc))
294 +               local->tpt_led_trigger->rx_bytes += bytes;
295  #endif
296 +}
297 --- a/net/mac80211/main.c
298 +++ b/net/mac80211/main.c
299 @@ -602,6 +602,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(
300         /* init dummy netdev for use w/ NAPI */
301         init_dummy_netdev(&local->napi_dev);
302  
303 +       ieee80211_led_names(local);
304 +
305         return local_to_hw(local);
306  }
307  EXPORT_SYMBOL(ieee80211_alloc_hw);
308 --- a/include/net/mac80211.h
309 +++ b/include/net/mac80211.h
310 @@ -1856,11 +1856,26 @@ struct ieee80211_hw *ieee80211_alloc_hw(
311   */
312  int ieee80211_register_hw(struct ieee80211_hw *hw);
313  
314 +/**
315 + * struct ieee80211_tpt_blink - throughput blink description
316 + * @throughput: throughput in Kbit/sec
317 + * @blink_time: blink time in milliseconds
318 + *     (full cycle, ie. one off + one on period)
319 + */
320 +struct ieee80211_tpt_blink {
321 +       int throughput;
322 +       int blink_time;
323 +};
324 +
325  #ifdef CONFIG_MAC80211_LEDS
326  extern char *__ieee80211_get_tx_led_name(struct ieee80211_hw *hw);
327  extern char *__ieee80211_get_rx_led_name(struct ieee80211_hw *hw);
328  extern char *__ieee80211_get_assoc_led_name(struct ieee80211_hw *hw);
329  extern char *__ieee80211_get_radio_led_name(struct ieee80211_hw *hw);
330 +extern char *__ieee80211_create_tpt_led_trigger(
331 +                               struct ieee80211_hw *hw,
332 +                               const struct ieee80211_tpt_blink *blink_table,
333 +                               unsigned int blink_table_len);
334  #endif
335  /**
336   * ieee80211_get_tx_led_name - get name of TX LED
337 @@ -1939,6 +1954,29 @@ static inline char *ieee80211_get_radio_
338  }
339  
340  /**
341 + * ieee80211_create_tpt_led_trigger - create throughput LED trigger
342 + * @hw: the hardware to create the trigger for
343 + * @blink_table: the blink table -- needs to be ordered by throughput
344 + * @blink_table_len: size of the blink table
345 + *
346 + * This function returns %NULL (in case of error, or if no LED
347 + * triggers are configured) or the name of the new trigger.
348 + * This function must be called before ieee80211_register_hw().
349 + */
350 +static inline char *
351 +ieee80211_create_tpt_led_trigger(struct ieee80211_hw *hw,
352 +                                const struct ieee80211_tpt_blink *blink_table,
353 +                                unsigned int blink_table_len)
354 +{
355 +#ifdef CONFIG_MAC80211_LEDS
356 +       return __ieee80211_create_tpt_led_trigger(hw, blink_table,
357 +                                                 blink_table_len);
358 +#else
359 +       return NULL;
360 +#endif
361 +}
362 +
363 +/**
364   * ieee80211_unregister_hw - Unregister a hardware device
365   *
366   * This function instructs mac80211 to free allocated resources
367 --- a/net/mac80211/ieee80211_i.h
368 +++ b/net/mac80211/ieee80211_i.h
369 @@ -23,6 +23,7 @@
370  #include <linux/types.h>
371  #include <linux/spinlock.h>
372  #include <linux/etherdevice.h>
373 +#include <linux/leds.h>
374  #include <net/ieee80211_radiotap.h>
375  #include <net/cfg80211.h>
376  #include <net/mac80211.h>
377 @@ -629,6 +630,19 @@ enum queue_stop_reason {
378         IEEE80211_QUEUE_STOP_REASON_SKB_ADD,
379  };
380  
381 +#ifdef CONFIG_MAC80211_LEDS
382 +struct tpt_led_trigger {
383 +       struct led_trigger trig;
384 +       char name[32];
385 +       const struct ieee80211_tpt_blink *blink_table;
386 +       unsigned int blink_table_len;
387 +       struct timer_list timer;
388 +       bool running;
389 +       unsigned long prev_traffic;
390 +       unsigned long tx_bytes, rx_bytes;
391 +};
392 +#endif
393 +
394  /**
395   * mac80211 scan flags - currently active scan mode
396   *
397 @@ -842,6 +856,7 @@ struct ieee80211_local {
398  #ifdef CONFIG_MAC80211_LEDS
399         int tx_led_counter, rx_led_counter;
400         struct led_trigger *tx_led, *rx_led, *assoc_led, *radio_led;
401 +       struct tpt_led_trigger *tpt_led_trigger;
402         char tx_led_name[32], rx_led_name[32],
403              assoc_led_name[32], radio_led_name[32];
404  #endif
405 --- a/net/mac80211/iface.c
406 +++ b/net/mac80211/iface.c
407 @@ -220,6 +220,7 @@ static int ieee80211_do_open(struct net_
408                 /* we're brought up, everything changes */
409                 hw_reconf_flags = ~0;
410                 ieee80211_led_radio(local, true);
411 +               ieee80211_start_tpt_led_trig(local);
412         }
413  
414         /*
415 --- a/net/mac80211/rx.c
416 +++ b/net/mac80211/rx.c
417 @@ -2888,6 +2888,9 @@ void ieee80211_rx(struct ieee80211_hw *h
418                 return;
419         }
420  
421 +       ieee80211_tpt_led_trig_rx(local,
422 +                       ((struct ieee80211_hdr *)skb->data)->frame_control,
423 +                       skb->len);
424         __ieee80211_rx_handle_packet(hw, skb);
425  
426         rcu_read_unlock();
427 --- a/net/mac80211/tx.c
428 +++ b/net/mac80211/tx.c
429 @@ -1293,6 +1293,7 @@ static int __ieee80211_tx(struct ieee802
430  
431         while (skb) {
432                 int q = skb_get_queue_mapping(skb);
433 +               __le16 fc;
434  
435                 spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
436                 ret = IEEE80211_TX_OK;
437 @@ -1335,6 +1336,7 @@ static int __ieee80211_tx(struct ieee802
438                 else
439                         info->control.sta = NULL;
440  
441 +               fc = ((struct ieee80211_hdr *)skb->data)->frame_control;
442                 ret = drv_tx(local, skb);
443                 if (WARN_ON(ret != NETDEV_TX_OK && skb->len != len)) {
444                         dev_kfree_skb(skb);
445 @@ -1345,6 +1347,7 @@ static int __ieee80211_tx(struct ieee802
446                         return IEEE80211_TX_AGAIN;
447                 }
448  
449 +               ieee80211_tpt_led_trig_tx(local, fc, len);
450                 *skbp = skb = next;
451                 ieee80211_led_tx(local, 1);
452                 fragm = true;
453 --- a/net/mac80211/util.c
454 +++ b/net/mac80211/util.c
455 @@ -1141,6 +1141,7 @@ u32 ieee80211_sta_get_rates(struct ieee8
456  void ieee80211_stop_device(struct ieee80211_local *local)
457  {
458         ieee80211_led_radio(local, false);
459 +       ieee80211_stop_tpt_led_trig(local);
460  
461         cancel_work_sync(&local->reconfig_filter);
462  
463 @@ -1175,6 +1176,7 @@ int ieee80211_reconfig(struct ieee80211_
464                 }
465  
466                 ieee80211_led_radio(local, true);
467 +               ieee80211_start_tpt_led_trig(local);
468         }
469  
470         /* add interfaces */