diff options
9 files changed, 1075 insertions, 45 deletions
diff --git a/package/mac80211/patches/008-led_default.patch b/package/mac80211/patches/008-led_default.patch index cdfe19b60..164be5bac 100644 --- a/package/mac80211/patches/008-led_default.patch +++ b/package/mac80211/patches/008-led_default.patch @@ -36,49 +36,6 @@ # Atheros CONFIG_ATH_COMMON=m ---- a/drivers/net/wireless/ath/ath9k/gpio.c -+++ b/drivers/net/wireless/ath/ath9k/gpio.c -@@ -54,6 +54,7 @@ static void ath_led_blink_work(struct wo - sc->sc_flags |= SC_OP_LED_ON; - } - -+#ifdef CONFIG_LEDS_CLASS - static void ath_led_brightness(struct led_classdev *led_cdev, - enum led_brightness brightness) - { -@@ -90,10 +91,12 @@ static void ath_led_brightness(struct le - break; - } - } -+#endif - - static int ath_register_led(struct ath_softc *sc, struct ath_led *led, - char *trigger) - { -+#ifdef CONFIG_LEDS_CLASS - int ret; - - led->sc = sc; -@@ -108,14 +111,19 @@ static int ath_register_led(struct ath_s - else - led->registered = 1; - return ret; -+#else -+ return 0; -+#endif - } - - static void ath_unregister_led(struct ath_led *led) - { -+#ifdef CONFIG_LEDS_CLASS - if (led->registered) { - led_classdev_unregister(&led->led_cdev); - led->registered = 0; - } -+#endif - } - - void ath_deinit_leds(struct ath_softc *sc) --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -822,6 +822,7 @@ static void ath9k_led_brightness_work(st diff --git a/package/mac80211/patches/401-ath9k-dont-register-leds-on-ar9100.patch b/package/mac80211/patches/401-ath9k-dont-register-leds-on-ar9100.patch index 330503d23..166c133a6 100644 --- a/package/mac80211/patches/401-ath9k-dont-register-leds-on-ar9100.patch +++ b/package/mac80211/patches/401-ath9k-dont-register-leds-on-ar9100.patch @@ -1,6 +1,6 @@ --- a/drivers/net/wireless/ath/ath9k/gpio.c +++ b/drivers/net/wireless/ath/ath9k/gpio.c -@@ -128,6 +128,9 @@ static void ath_unregister_led(struct at +@@ -120,6 +120,9 @@ static void ath_unregister_led(struct at void ath_deinit_leds(struct ath_softc *sc) { @@ -10,7 +10,7 @@ ath_unregister_led(&sc->assoc_led); sc->sc_flags &= ~SC_OP_LED_ASSOCIATED; ath_unregister_led(&sc->tx_led); -@@ -141,6 +144,9 @@ void ath_init_leds(struct ath_softc *sc) +@@ -133,6 +136,9 @@ void ath_init_leds(struct ath_softc *sc) char *trigger; int ret; diff --git a/package/mac80211/patches/402-ath9k_blink_default.patch b/package/mac80211/patches/402-ath9k_blink_default.patch new file mode 100644 index 000000000..8269e61c6 --- /dev/null +++ b/package/mac80211/patches/402-ath9k_blink_default.patch @@ -0,0 +1,11 @@ +--- a/drivers/net/wireless/ath/ath9k/init.c ++++ b/drivers/net/wireless/ath/ath9k/init.c +@@ -34,7 +34,7 @@ int modparam_nohwcrypt; + module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444); + MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption"); + +-int led_blink; ++int led_blink = 1; + module_param_named(blink, led_blink, int, 0444); + MODULE_PARM_DESC(blink, "Enable LED blink on activity"); + diff --git a/package/mac80211/patches/560-led_blink_backport.patch b/package/mac80211/patches/560-led_blink_backport.patch new file mode 100644 index 000000000..d22ec95cc --- /dev/null +++ b/package/mac80211/patches/560-led_blink_backport.patch @@ -0,0 +1,207 @@ +--- a/compat/compat-2.6.37.c ++++ b/compat/compat-2.6.37.c +@@ -152,3 +152,175 @@ int compat_genl_unregister_family(struct + } + EXPORT_SYMBOL(compat_genl_unregister_family); + ++#ifdef CONFIG_LEDS_CLASS ++ ++#undef led_brightness_set ++#undef led_classdev_unregister ++ ++spinlock_t led_lock; ++static LIST_HEAD(led_timers); ++ ++struct led_timer { ++ struct list_head list; ++ struct led_classdev *cdev; ++ struct timer_list blink_timer; ++ unsigned long blink_delay_on; ++ unsigned long blink_delay_off; ++ int blink_brightness; ++}; ++ ++static void led_brightness_set(struct led_classdev *led_cdev, ++ enum led_brightness brightness) ++{ ++ led_cdev->brightness = brightness; ++ led_cdev->brightness_set(led_cdev, brightness); ++} ++ ++static struct led_timer *led_get_timer(struct led_classdev *led_cdev) ++{ ++ struct led_timer *p; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&led_lock, flags); ++ list_for_each_entry(p, &led_timers, list) { ++ if (p->cdev == led_cdev) ++ goto found; ++ } ++ p = NULL; ++found: ++ spin_unlock_irqrestore(&led_lock, flags); ++ return p; ++} ++ ++static void led_stop_software_blink(struct led_timer *led) ++{ ++ del_timer_sync(&led->blink_timer); ++ led->blink_delay_on = 0; ++ led->blink_delay_off = 0; ++} ++ ++static void led_timer_function(unsigned long data) ++{ ++ struct led_timer *led = (struct led_timer *)data; ++ unsigned long brightness; ++ unsigned long delay; ++ ++ if (!led->blink_delay_on || !led->blink_delay_off) { ++ led->cdev->brightness_set(led->cdev, LED_OFF); ++ return; ++ } ++ ++ brightness = led->cdev->brightness; ++ if (!brightness) { ++ /* Time to switch the LED on. */ ++ brightness = led->blink_brightness; ++ delay = led->blink_delay_on; ++ } else { ++ /* Store the current brightness value to be able ++ * to restore it when the delay_off period is over. ++ */ ++ led->blink_brightness = brightness; ++ brightness = LED_OFF; ++ delay = led->blink_delay_off; ++ } ++ ++ led_brightness_set(led->cdev, brightness); ++ mod_timer(&led->blink_timer, jiffies + msecs_to_jiffies(delay)); ++} ++ ++static struct led_timer *led_new_timer(struct led_classdev *led_cdev) ++{ ++ struct led_timer *led; ++ unsigned long flags; ++ ++ led = kzalloc(sizeof(struct led_timer), GFP_ATOMIC); ++ if (!led) ++ return NULL; ++ ++ led->cdev = led_cdev; ++ init_timer(&led->blink_timer); ++ led->blink_timer.function = led_timer_function; ++ led->blink_timer.data = (unsigned long) led; ++ ++ spin_lock_irqsave(&led_lock, flags); ++ list_add(&led->list, &led_timers); ++ spin_unlock_irqrestore(&led_lock, flags); ++ ++ return led; ++} ++ ++void led_blink_set(struct led_classdev *led_cdev, ++ unsigned long *delay_on, ++ unsigned long *delay_off) ++{ ++ struct led_timer *led = led_get_timer(led_cdev); ++ int current_brightness; ++ ++ if (!led) { ++ led = led_new_timer(led_cdev); ++ if (!led) ++ return; ++ } ++ ++ /* blink with 1 Hz as default if nothing specified */ ++ if (!*delay_on && !*delay_off) ++ *delay_on = *delay_off = 500; ++ ++ if (led->blink_delay_on == *delay_on && ++ led->blink_delay_off == *delay_off) ++ return; ++ ++ current_brightness = led_cdev->brightness; ++ if (current_brightness) ++ led->blink_brightness = current_brightness; ++ if (!led->blink_brightness) ++ led->blink_brightness = led_cdev->max_brightness; ++ ++ led_stop_software_blink(led); ++ led->blink_delay_on = *delay_on; ++ led->blink_delay_off = *delay_off; ++ ++ /* never on - don't blink */ ++ if (!*delay_on) ++ return; ++ ++ /* never off - just set to brightness */ ++ if (!*delay_off) { ++ led_brightness_set(led_cdev, led->blink_brightness); ++ return; ++ } ++ ++ mod_timer(&led->blink_timer, jiffies + 1); ++} ++EXPORT_SYMBOL(led_blink_set); ++ ++void compat_led_brightness_set(struct led_classdev *led_cdev, ++ enum led_brightness brightness) ++{ ++ struct led_timer *led = led_get_timer(led_cdev); ++ ++ if (led) ++ led_stop_software_blink(led); ++ ++ return led_cdev->brightness_set(led_cdev, brightness); ++} ++EXPORT_SYMBOL(compat_led_brightness_set); ++ ++void compat_led_classdev_unregister(struct led_classdev *led_cdev) ++{ ++ struct led_timer *led = led_get_timer(led_cdev); ++ unsigned long flags; ++ ++ if (led) { ++ del_timer_sync(&led->blink_timer); ++ spin_lock_irqsave(&led_lock, flags); ++ list_del(&led->list); ++ spin_unlock_irqrestore(&led_lock, flags); ++ kfree(led); ++ } ++ ++ led_classdev_unregister(led_cdev); ++} ++EXPORT_SYMBOL(compat_led_classdev_unregister); ++ ++#endif +--- a/include/linux/compat-2.6.37.h ++++ b/include/linux/compat-2.6.37.h +@@ -6,6 +6,7 @@ + #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37)) + + #include <linux/skbuff.h> ++#include <linux/leds.h> + + #define SDIO_CLASS_BT_AMP 0x09 /* Type-A Bluetooth AMP interface */ + +@@ -93,6 +94,18 @@ int genl_unregister_family(struct genl_f + #define genl_register_mc_group(_fam, _grp) genl_register_mc_group(&(_fam)->family, _grp) + #define genl_unregister_mc_group(_fam, _grp) genl_unregister_mc_group(&(_fam)->family, _grp) + ++ ++extern void led_blink_set(struct led_classdev *led_cdev, ++ unsigned long *delay_on, ++ unsigned long *delay_off); ++ ++#define led_classdev_unregister compat_led_classdev_unregister ++extern void led_classdev_unregister(struct led_classdev *led_cdev); ++ ++#define led_brightness_set compat_led_brightness_set ++extern void led_brightness_set(struct led_classdev *led_cdev, ++ enum led_brightness brightness); ++ + #endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37)) */ + + #endif /* LINUX_26_37_COMPAT_H */ diff --git a/package/mac80211/patches/561-led_trigger_names.patch b/package/mac80211/patches/561-led_trigger_names.patch new file mode 100644 index 000000000..28108ecfb --- /dev/null +++ b/package/mac80211/patches/561-led_trigger_names.patch @@ -0,0 +1,146 @@ +From: Johannes Berg <johannes.berg@intel.com> +Subject: [PATCH] mac80211: make LED trigger names available early + +The throughput trigger will require doing LED +classdev/trigger handling before register_hw(), +so drivers should have access to the trigger +names before it. If trigger registration fails, +this will still make the trigger name available, +but that's not a big problem since the default +trigger will the simply not be found. + +Signed-off-by: Johannes Berg <johannes.berg@intel.com> +--- + net/mac80211/led.c | 36 ++++++++++++++++-------------------- + net/mac80211/led.h | 4 ++++ + net/mac80211/main.c | 2 ++ + 3 files changed, 22 insertions(+), 20 deletions(-) + +--- a/net/mac80211/led.c ++++ b/net/mac80211/led.c +@@ -54,12 +54,22 @@ void ieee80211_led_radio(struct ieee8021 + led_trigger_event(local->radio_led, LED_OFF); + } + ++void ieee80211_led_names(struct ieee80211_local *local) ++{ ++ snprintf(local->rx_led_name, sizeof(local->rx_led_name), ++ "%srx", wiphy_name(local->hw.wiphy)); ++ snprintf(local->tx_led_name, sizeof(local->tx_led_name), ++ "%stx", wiphy_name(local->hw.wiphy)); ++ snprintf(local->assoc_led_name, sizeof(local->assoc_led_name), ++ "%sassoc", wiphy_name(local->hw.wiphy)); ++ snprintf(local->radio_led_name, sizeof(local->radio_led_name), ++ "%sradio", wiphy_name(local->hw.wiphy)); ++} ++ + void ieee80211_led_init(struct ieee80211_local *local) + { + local->rx_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL); + if (local->rx_led) { +- snprintf(local->rx_led_name, sizeof(local->rx_led_name), +- "%srx", wiphy_name(local->hw.wiphy)); + local->rx_led->name = local->rx_led_name; + if (led_trigger_register(local->rx_led)) { + kfree(local->rx_led); +@@ -69,8 +79,6 @@ void ieee80211_led_init(struct ieee80211 + + local->tx_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL); + if (local->tx_led) { +- snprintf(local->tx_led_name, sizeof(local->tx_led_name), +- "%stx", wiphy_name(local->hw.wiphy)); + local->tx_led->name = local->tx_led_name; + if (led_trigger_register(local->tx_led)) { + kfree(local->tx_led); +@@ -80,8 +88,6 @@ void ieee80211_led_init(struct ieee80211 + + local->assoc_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL); + if (local->assoc_led) { +- snprintf(local->assoc_led_name, sizeof(local->assoc_led_name), +- "%sassoc", wiphy_name(local->hw.wiphy)); + local->assoc_led->name = local->assoc_led_name; + if (led_trigger_register(local->assoc_led)) { + kfree(local->assoc_led); +@@ -91,8 +97,6 @@ void ieee80211_led_init(struct ieee80211 + + local->radio_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL); + if (local->radio_led) { +- snprintf(local->radio_led_name, sizeof(local->radio_led_name), +- "%sradio", wiphy_name(local->hw.wiphy)); + local->radio_led->name = local->radio_led_name; + if (led_trigger_register(local->radio_led)) { + kfree(local->radio_led); +@@ -125,9 +129,7 @@ char *__ieee80211_get_radio_led_name(str + { + struct ieee80211_local *local = hw_to_local(hw); + +- if (local->radio_led) +- return local->radio_led_name; +- return NULL; ++ return local->radio_led_name; + } + EXPORT_SYMBOL(__ieee80211_get_radio_led_name); + +@@ -135,9 +137,7 @@ char *__ieee80211_get_assoc_led_name(str + { + struct ieee80211_local *local = hw_to_local(hw); + +- if (local->assoc_led) +- return local->assoc_led_name; +- return NULL; ++ return local->assoc_led_name; + } + EXPORT_SYMBOL(__ieee80211_get_assoc_led_name); + +@@ -145,9 +145,7 @@ char *__ieee80211_get_tx_led_name(struct + { + struct ieee80211_local *local = hw_to_local(hw); + +- if (local->tx_led) +- return local->tx_led_name; +- return NULL; ++ return local->tx_led_name; + } + EXPORT_SYMBOL(__ieee80211_get_tx_led_name); + +@@ -155,8 +153,6 @@ char *__ieee80211_get_rx_led_name(struct + { + struct ieee80211_local *local = hw_to_local(hw); + +- if (local->rx_led) +- return local->rx_led_name; +- return NULL; ++ return local->rx_led_name; + } + EXPORT_SYMBOL(__ieee80211_get_rx_led_name); +--- a/net/mac80211/led.h ++++ b/net/mac80211/led.h +@@ -18,6 +18,7 @@ extern void ieee80211_led_assoc(struct i + bool associated); + extern void ieee80211_led_radio(struct ieee80211_local *local, + bool enabled); ++extern void ieee80211_led_names(struct ieee80211_local *local); + extern void ieee80211_led_init(struct ieee80211_local *local); + extern void ieee80211_led_exit(struct ieee80211_local *local); + #else +@@ -35,6 +36,9 @@ static inline void ieee80211_led_radio(s + bool enabled) + { + } ++static inline void ieee80211_led_names(struct ieee80211_local *local) ++{ ++} + static inline void ieee80211_led_init(struct ieee80211_local *local) + { + } +--- a/net/mac80211/main.c ++++ b/net/mac80211/main.c +@@ -599,6 +599,8 @@ struct ieee80211_hw *ieee80211_alloc_hw( + /* init dummy netdev for use w/ NAPI */ + init_dummy_netdev(&local->napi_dev); + ++ ieee80211_led_names(local); ++ + return local_to_hw(local); + } + EXPORT_SYMBOL(ieee80211_alloc_hw); diff --git a/package/mac80211/patches/562-throughput_trigger.patch b/package/mac80211/patches/562-throughput_trigger.patch new file mode 100644 index 000000000..811054794 --- /dev/null +++ b/package/mac80211/patches/562-throughput_trigger.patch @@ -0,0 +1,373 @@ +Subject: mac80211: add throughput based LED blink trigger +From: Johannes Berg <johannes.berg@intel.com> + +iwlwifi and other drivers like to blink their LED +based on throughput. Implement this generically in +mac80211, based on a throughput table the driver +specifies. That way, drivers can set the blink +frequencies depending on their desired behaviour +and max throughput. + +All the drivers need to do is provide an LED class +device, best with blink hardware offload. + +Signed-off-by: Johannes Berg <johannes.berg@intel.com> +--- +v2: turn off LED when turning off radio + + include/net/mac80211.h | 42 +++++++++++++++ + net/mac80211/ieee80211_i.h | 14 +++++ + net/mac80211/iface.c | 1 + net/mac80211/led.c | 120 +++++++++++++++++++++++++++++++++++++++++++++ + net/mac80211/led.h | 44 +++++++++++++--- + net/mac80211/rx.c | 1 + net/mac80211/tx.c | 1 + net/mac80211/util.c | 2 + 8 files changed, 216 insertions(+), 9 deletions(-) + +--- a/include/net/mac80211.h ++++ b/include/net/mac80211.h +@@ -1849,11 +1849,27 @@ struct ieee80211_hw *ieee80211_alloc_hw( + */ + int ieee80211_register_hw(struct ieee80211_hw *hw); + ++/** ++ * struct ieee80211_tpt_blink - throughput blink description ++ * @throughput: throughput in Kbit/sec ++ * @blink_time: blink time in milliseconds ++ * (full cycle, ie. one off + one on period) ++ */ ++struct ieee80211_tpt_blink { ++ int throughput; ++ int blink_time; ++}; ++ + #ifdef CONFIG_MAC80211_LEDS + extern char *__ieee80211_get_tx_led_name(struct ieee80211_hw *hw); + extern char *__ieee80211_get_rx_led_name(struct ieee80211_hw *hw); + extern char *__ieee80211_get_assoc_led_name(struct ieee80211_hw *hw); + extern char *__ieee80211_get_radio_led_name(struct ieee80211_hw *hw); ++extern char *__ieee80211_create_tpt_led_trigger( ++ struct ieee80211_hw *hw, ++ unsigned long update_timeout, ++ const struct ieee80211_tpt_blink *blink_table, ++ unsigned int blink_table_len); + #endif + /** + * ieee80211_get_tx_led_name - get name of TX LED +@@ -1932,6 +1948,32 @@ static inline char *ieee80211_get_radio_ + } + + /** ++ * ieee80211_create_tpt_led_trigger - create throughput LED trigger ++ * @hw: the hardware to create the trigger for ++ * @update_timeout: the update timeout (in jiffies) ++ * @blink_table: the blink table -- needs to be ordered by throughput ++ * @blink_table_len: size of the blink table ++ * ++ * This function returns %NULL (in case of error, or if no LED ++ * triggers are configured) or the name of the new trigger. ++ * This function must be called before ieee80211_register_hw(). ++ */ ++static inline char * ++ieee80211_create_tpt_led_trigger(struct ieee80211_hw *hw, ++ unsigned long update_timeout, ++ const struct ieee80211_tpt_blink *blink_table, ++ unsigned int blink_table_len) ++{ ++#ifdef CONFIG_MAC80211_LEDS ++ return __ieee80211_create_tpt_led_trigger(hw, update_timeout, ++ blink_table, ++ blink_table_len); ++#else ++ return NULL; ++#endif ++} ++ ++/** + * ieee80211_unregister_hw - Unregister a hardware device + * + * This function instructs mac80211 to free allocated resources +--- a/net/mac80211/ieee80211_i.h ++++ b/net/mac80211/ieee80211_i.h +@@ -23,6 +23,7 @@ + #include <linux/types.h> + #include <linux/spinlock.h> + #include <linux/etherdevice.h> ++#include <linux/leds.h> + #include <net/ieee80211_radiotap.h> + #include <net/cfg80211.h> + #include <net/mac80211.h> +@@ -636,6 +637,18 @@ enum queue_stop_reason { + IEEE80211_QUEUE_STOP_REASON_SKB_ADD, + }; + ++struct tpt_led_trigger { ++ struct led_trigger trig; ++ char name[32]; ++ const struct ieee80211_tpt_blink *blink_table; ++ unsigned int blink_table_len; ++ unsigned long update_timeout; ++ struct timer_list timer; ++ bool running; ++ unsigned long prev_traffic; ++ unsigned long tx_bytes, rx_bytes; ++}; ++ + /** + * mac80211 scan flags - currently active scan mode + * +@@ -849,6 +862,7 @@ struct ieee80211_local { + #ifdef CONFIG_MAC80211_LEDS + int tx_led_counter, rx_led_counter; + struct led_trigger *tx_led, *rx_led, *assoc_led, *radio_led; ++ struct tpt_led_trigger *tpt_led_trigger; + char tx_led_name[32], rx_led_name[32], + assoc_led_name[32], radio_led_name[32]; + #endif +--- a/net/mac80211/led.c ++++ b/net/mac80211/led.c +@@ -103,6 +103,13 @@ void ieee80211_led_init(struct ieee80211 + local->radio_led = NULL; + } + } ++ ++ if (local->tpt_led_trigger) { ++ if (led_trigger_register(&local->tpt_led_trigger->trig)) { ++ kfree(local->tpt_led_trigger); ++ local->tpt_led_trigger = NULL; ++ } ++ } + } + + void ieee80211_led_exit(struct ieee80211_local *local) +@@ -123,6 +130,11 @@ void ieee80211_led_exit(struct ieee80211 + led_trigger_unregister(local->rx_led); + kfree(local->rx_led); + } ++ ++ if (local->tpt_led_trigger) { ++ led_trigger_unregister(&local->tpt_led_trigger->trig); ++ kfree(local->tpt_led_trigger); ++ } + } + + char *__ieee80211_get_radio_led_name(struct ieee80211_hw *hw) +@@ -156,3 +168,111 @@ char *__ieee80211_get_rx_led_name(struct + return local->rx_led_name; + } + EXPORT_SYMBOL(__ieee80211_get_rx_led_name); ++ ++static unsigned long tpt_trig_traffic(struct ieee80211_local *local, ++ struct tpt_led_trigger *tpt_trig) ++{ ++ unsigned long traffic, delta; ++ ++ traffic = tpt_trig->tx_bytes + tpt_trig->rx_bytes; ++ ++ delta = traffic - tpt_trig->prev_traffic; ++ tpt_trig->prev_traffic = traffic; ++ return delta / (1024 / 8); ++} ++ ++static void tpt_trig_timer(unsigned long data) ++{ ++ struct ieee80211_local *local = (void *)data; ++ struct tpt_led_trigger *tpt_trig = local->tpt_led_trigger; ++ struct led_classdev *led_cdev; ++ unsigned long on, off, tpt; ++ int i; ++ ++ if (!tpt_trig->running) ++ return; ++ ++ mod_timer(&tpt_trig->timer, jiffies + tpt_trig->update_timeout); ++ ++ tpt = tpt_trig_traffic(local, tpt_trig); ++ ++ /* default to just solid on */ ++ on = 1; ++ off = 0; ++ ++ for (i = tpt_trig->blink_table_len - 1; i >= 0; i--) { ++ if (tpt >= tpt_trig->blink_table[i].throughput) { ++ off = tpt_trig->blink_table[i].blink_time / 2; ++ on = tpt_trig->blink_table[i].blink_time - off; ++ break; ++ } ++ } ++ ++ read_lock(&tpt_trig->trig.leddev_list_lock); ++ list_for_each_entry(led_cdev, &tpt_trig->trig.led_cdevs, trig_list) ++ led_blink_set(led_cdev, &on, &off); ++ read_unlock(&tpt_trig->trig.leddev_list_lock); ++} ++ ++extern char *__ieee80211_create_tpt_led_trigger( ++ struct ieee80211_hw *hw, ++ unsigned long update_timeout, ++ const struct ieee80211_tpt_blink *blink_table, ++ unsigned int blink_table_len) ++{ ++ struct ieee80211_local *local = hw_to_local(hw); ++ struct tpt_led_trigger *tpt_trig; ++ ++ if (WARN_ON(local->tpt_led_trigger)) ++ return NULL; ++ ++ tpt_trig = kzalloc(sizeof(struct tpt_led_trigger), GFP_KERNEL); ++ if (!tpt_trig) ++ return NULL; ++ ++ snprintf(tpt_trig->name, sizeof(tpt_trig->name), ++ "%stpt", wiphy_name(local->hw.wiphy)); ++ ++ tpt_trig->trig.name = tpt_trig->name; ++ ++ tpt_trig->update_timeout = update_timeout; ++ tpt_trig->blink_table = blink_table; ++ tpt_trig->blink_table_len = blink_table_len; ++ ++ setup_timer(&tpt_trig->timer, tpt_trig_timer, (unsigned long)local); ++ ++ local->tpt_led_trigger = tpt_trig; ++ ++ return tpt_trig->name; ++} ++EXPORT_SYMBOL(__ieee80211_create_tpt_led_trigger); ++ ++void ieee80211_start_tpt_led_trig(struct ieee80211_local *local) ++{ ++ struct tpt_led_trigger *tpt_trig = local->tpt_led_trigger; ++ ++ if (!tpt_trig) ++ return; ++ ++ /* reset traffic */ ++ tpt_trig_traffic(local, tpt_trig); ++ tpt_trig->running = true; ++ mod_timer(&tpt_trig->timer, jiffies + tpt_trig->update_timeout); ++} ++ ++void ieee80211_stop_tpt_led_trig(struct ieee80211_local *local) ++{ ++ struct tpt_led_trigger *tpt_trig = local->tpt_led_trigger; ++ struct led_classdev *led_cdev; ++ ++ if (!tpt_trig) ++ return; ++ ++ tpt_trig->running = false; ++ del_timer_sync(&tpt_trig->timer); ++ ++ read_lock(&tpt_trig->trig.leddev_list_lock); ++ list_for_each_entry(led_cdev, &tpt_trig->trig.led_cdevs, trig_list) ++ led_brightness_set(led_cdev, LED_OFF); ++ read_unlock(&tpt_trig->trig.leddev_list_lock); ++} +--- a/net/mac80211/led.h ++++ b/net/mac80211/led.h +@@ -12,15 +12,17 @@ + #include "ieee80211_i.h" + + #ifdef CONFIG_MAC80211_LEDS +-extern void ieee80211_led_rx(struct ieee80211_local *local); +-extern void ieee80211_led_tx(struct ieee80211_local *local, int q); +-extern void ieee80211_led_assoc(struct ieee80211_local *local, +- bool associated); +-extern void ieee80211_led_radio(struct ieee80211_local *local, +- bool enabled); +-extern void ieee80211_led_names(struct ieee80211_local *local); +-extern void ieee80211_led_init(struct ieee80211_local *local); +-extern void ieee80211_led_exit(struct ieee80211_local *local); ++void ieee80211_led_rx(struct ieee80211_local *local); ++void ieee80211_led_tx(struct ieee80211_local *local, int q); ++void ieee80211_led_assoc(struct ieee80211_local *local, ++ bool associated); ++void ieee80211_led_radio(struct ieee80211_local *local, ++ bool enabled); ++void ieee80211_led_names(struct ieee80211_local *local); ++void ieee80211_led_init(struct ieee80211_local *local); ++void ieee80211_led_exit(struct ieee80211_local *local); ++void ieee80211_start_tpt_led_trig(struct ieee80211_local *local); ++void ieee80211_stop_tpt_led_trig(struct ieee80211_local *local); + #else + static inline void ieee80211_led_rx(struct ieee80211_local *local) + { +@@ -45,4 +47,28 @@ static inline void ieee80211_led_init(st + static inline void ieee80211_led_exit(struct ieee80211_local *local) + { + } ++static inline void ieee80211_start_tpt_led_trig(struct ieee80211_local *local) ++{ ++} ++static inline void ieee80211_stop_tpt_led_trig(struct ieee80211_local *local) ++{ ++} ++#endif ++ ++static inline void ++ieee80211_tpt_led_trig_tx(struct ieee80211_local *local, int bytes) ++{ ++#ifdef CONFIG_MAC80211_LEDS ++ if (local->tpt_led_trigger) ++ local->tpt_led_trigger->tx_bytes += bytes; + #endif ++} ++ ++static inline void ++ieee80211_tpt_led_trig_rx(struct ieee80211_local *local, int bytes) ++{ ++#ifdef CONFIG_MAC80211_LEDS ++ if (local->tpt_led_trigger) ++ local->tpt_led_trigger->rx_bytes += bytes; ++#endif ++} +--- a/net/mac80211/iface.c ++++ b/net/mac80211/iface.c +@@ -225,6 +225,7 @@ static int ieee80211_do_open(struct net_ + /* we're brought up, everything changes */ + hw_reconf_flags = ~0; + ieee80211_led_radio(local, true); ++ ieee80211_start_tpt_led_trig(local); + } + + /* +--- a/net/mac80211/util.c ++++ b/net/mac80211/util.c +@@ -1141,6 +1141,7 @@ u32 ieee80211_sta_get_rates(struct ieee8 + void ieee80211_stop_device(struct ieee80211_local *local) + { + ieee80211_led_radio(local, false); ++ ieee80211_stop_tpt_led_trig(local); + + cancel_work_sync(&local->reconfig_filter); + +@@ -1175,6 +1176,7 @@ int ieee80211_reconfig(struct ieee80211_ + } + + ieee80211_led_radio(local, true); ++ ieee80211_start_tpt_led_trig(local); + } + + /* add interfaces */ +--- a/net/mac80211/rx.c ++++ b/net/mac80211/rx.c +@@ -2873,6 +2873,7 @@ void ieee80211_rx(struct ieee80211_hw *h + return; + } + ++ ieee80211_tpt_led_trig_rx(local, skb->len); + __ieee80211_rx_handle_packet(hw, skb); + + rcu_read_unlock(); +--- a/net/mac80211/tx.c ++++ b/net/mac80211/tx.c +@@ -1344,6 +1344,7 @@ static int __ieee80211_tx(struct ieee802 + return IEEE80211_TX_AGAIN; + } + ++ ieee80211_tpt_led_trig_tx(local, len); + *skbp = skb = next; + ieee80211_led_tx(local, 1); + fragm = true; diff --git a/package/mac80211/patches/563-tpt_trigger_register_fix.patch b/package/mac80211/patches/563-tpt_trigger_register_fix.patch new file mode 100644 index 000000000..270a5558b --- /dev/null +++ b/package/mac80211/patches/563-tpt_trigger_register_fix.patch @@ -0,0 +1,29 @@ +--- a/net/mac80211/led.c ++++ b/net/mac80211/led.c +@@ -103,13 +103,6 @@ void ieee80211_led_init(struct ieee80211 + local->radio_led = NULL; + } + } +- +- if (local->tpt_led_trigger) { +- if (led_trigger_register(&local->tpt_led_trigger->trig)) { +- kfree(local->tpt_led_trigger); +- local->tpt_led_trigger = NULL; +- } +- } + } + + void ieee80211_led_exit(struct ieee80211_local *local) +@@ -243,6 +236,12 @@ extern char *__ieee80211_create_tpt_led_ + + local->tpt_led_trigger = tpt_trig; + ++ if (led_trigger_register(&local->tpt_led_trigger->trig)) { ++ kfree(local->tpt_led_trigger); ++ local->tpt_led_trigger = NULL; ++ return NULL; ++ } ++ + return tpt_trig->name; + } + EXPORT_SYMBOL(__ieee80211_create_tpt_led_trigger); diff --git a/package/mac80211/patches/564-tpt_trigger_idle_fix.patch b/package/mac80211/patches/564-tpt_trigger_idle_fix.patch new file mode 100644 index 000000000..3578bcf0c --- /dev/null +++ b/package/mac80211/patches/564-tpt_trigger_idle_fix.patch @@ -0,0 +1,29 @@ +--- a/net/mac80211/led.c ++++ b/net/mac80211/led.c +@@ -194,7 +194,7 @@ static void tpt_trig_timer(unsigned long + off = 0; + + for (i = tpt_trig->blink_table_len - 1; i >= 0; i--) { +- if (tpt >= tpt_trig->blink_table[i].throughput) { ++ if (tpt > tpt_trig->blink_table[i].throughput) { + off = tpt_trig->blink_table[i].blink_time / 2; + on = tpt_trig->blink_table[i].blink_time - off; + break; +--- a/net/mac80211/rx.c ++++ b/net/mac80211/rx.c +@@ -1877,6 +1877,7 @@ ieee80211_rx_h_data(struct ieee80211_rx_ + msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout)); + } + ++ ieee80211_tpt_led_trig_rx(local, rx->skb->len); + ieee80211_deliver_skb(rx); + + return RX_QUEUED; +@@ -2873,7 +2874,6 @@ void ieee80211_rx(struct ieee80211_hw *h + return; + } + +- ieee80211_tpt_led_trig_rx(local, skb->len); + __ieee80211_rx_handle_packet(hw, skb); + + rcu_read_unlock(); diff --git a/package/mac80211/patches/565-ath9k_cleanup_led_blink.patch b/package/mac80211/patches/565-ath9k_cleanup_led_blink.patch new file mode 100644 index 000000000..86aec433f --- /dev/null +++ b/package/mac80211/patches/565-ath9k_cleanup_led_blink.patch @@ -0,0 +1,278 @@ +--- a/drivers/net/wireless/ath/ath9k/ath9k.h ++++ b/drivers/net/wireless/ath/ath9k/ath9k.h +@@ -437,26 +437,20 @@ void ath9k_btcoex_timer_pause(struct ath + + #define ATH_LED_PIN_DEF 1 + #define ATH_LED_PIN_9287 8 +-#define ATH_LED_ON_DURATION_IDLE 350 /* in msecs */ +-#define ATH_LED_OFF_DURATION_IDLE 250 /* in msecs */ +- +-enum ath_led_type { +- ATH_LED_RADIO, +- ATH_LED_ASSOC, +- ATH_LED_TX, +- ATH_LED_RX +-}; +- +-struct ath_led { +- struct ath_softc *sc; +- struct led_classdev led_cdev; +- enum ath_led_type led_type; +- char name[32]; +- bool registered; +-}; + ++#ifdef CONFIG_MAC80211_LEDS + void ath_init_leds(struct ath_softc *sc); + void ath_deinit_leds(struct ath_softc *sc); ++#else ++static inline void ath_init_leds(struct ath_softc *sc) ++{ ++} ++ ++static inline void ath_deinit_leds(struct ath_softc *sc) ++{ ++} ++#endif ++ + + /* Antenna diversity/combining */ + #define ATH_ANT_RX_CURRENT_SHIFT 4 +@@ -606,15 +600,11 @@ struct ath_softc { + struct ath_beacon beacon; + struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS]; + +- struct ath_led radio_led; +- struct ath_led assoc_led; +- struct ath_led tx_led; +- struct ath_led rx_led; +- struct delayed_work ath_led_blink_work; +- int led_on_duration; +- int led_off_duration; +- int led_on_cnt; +- int led_off_cnt; ++#ifdef CONFIG_MAC80211_LEDS ++ bool led_registered; ++ char led_name[32]; ++ struct led_classdev led_cdev; ++#endif + + int beacon_interval; + +--- a/drivers/net/wireless/ath/ath9k/gpio.c ++++ b/drivers/net/wireless/ath/ath9k/gpio.c +@@ -20,115 +20,34 @@ + /* LED functions */ + /********************************/ + +-static void ath_led_blink_work(struct work_struct *work) +-{ +- struct ath_softc *sc = container_of(work, struct ath_softc, +- ath_led_blink_work.work); +- +- if (!(sc->sc_flags & SC_OP_LED_ASSOCIATED)) +- return; +- +- if ((sc->led_on_duration == ATH_LED_ON_DURATION_IDLE) || +- (sc->led_off_duration == ATH_LED_OFF_DURATION_IDLE)) +- ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 0); +- else +- ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, +- (sc->sc_flags & SC_OP_LED_ON) ? 1 : 0); +- +- ieee80211_queue_delayed_work(sc->hw, +- &sc->ath_led_blink_work, +- (sc->sc_flags & SC_OP_LED_ON) ? +- msecs_to_jiffies(sc->led_off_duration) : +- msecs_to_jiffies(sc->led_on_duration)); +- +- sc->led_on_duration = sc->led_on_cnt ? +- max((ATH_LED_ON_DURATION_IDLE - sc->led_on_cnt), 25) : +- ATH_LED_ON_DURATION_IDLE; +- sc->led_off_duration = sc->led_off_cnt ? +- max((ATH_LED_OFF_DURATION_IDLE - sc->led_off_cnt), 10) : +- ATH_LED_OFF_DURATION_IDLE; +- sc->led_on_cnt = sc->led_off_cnt = 0; +- if (sc->sc_flags & SC_OP_LED_ON) +- sc->sc_flags &= ~SC_OP_LED_ON; +- else +- sc->sc_flags |= SC_OP_LED_ON; +-} ++#ifdef CONFIG_MAC80211_LEDS ++static const struct ieee80211_tpt_blink ath9k_blink[] = { ++ { .throughput = 0 * 1024, .blink_time = 334 }, ++ { .throughput = 1 * 1024, .blink_time = 260 }, ++ { .throughput = 5 * 1024, .blink_time = 220 }, ++ { .throughput = 10 * 1024, .blink_time = 190 }, ++ { .throughput = 20 * 1024, .blink_time = 170 }, ++ { .throughput = 50 * 1024, .blink_time = 150 }, ++ { .throughput = 70 * 1024, .blink_time = 130 }, ++ { .throughput = 100 * 1024, .blink_time = 110 }, ++ { .throughput = 200 * 1024, .blink_time = 80 }, ++ { .throughput = 300 * 1024, .blink_time = 50 }, ++}; + + static void ath_led_brightness(struct led_classdev *led_cdev, + enum led_brightness brightness) + { +- struct ath_led *led = container_of(led_cdev, struct ath_led, led_cdev); +- struct ath_softc *sc = led->sc; +- +- switch (brightness) { +- case LED_OFF: +- if (led->led_type == ATH_LED_ASSOC || +- led->led_type == ATH_LED_RADIO) { +- ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, +- (led->led_type == ATH_LED_RADIO)); +- sc->sc_flags &= ~SC_OP_LED_ASSOCIATED; +- if (led->led_type == ATH_LED_RADIO) +- sc->sc_flags &= ~SC_OP_LED_ON; +- } else { +- sc->led_off_cnt++; +- } +- break; +- case LED_FULL: +- if (led->led_type == ATH_LED_ASSOC) { +- sc->sc_flags |= SC_OP_LED_ASSOCIATED; +- if (led_blink) +- ieee80211_queue_delayed_work(sc->hw, +- &sc->ath_led_blink_work, 0); +- } else if (led->led_type == ATH_LED_RADIO) { +- ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 0); +- sc->sc_flags |= SC_OP_LED_ON; +- } else { +- sc->led_on_cnt++; +- } +- break; +- default: +- break; +- } +-} +- +-static int ath_register_led(struct ath_softc *sc, struct ath_led *led, +- char *trigger) +-{ +- int ret; +- +- led->sc = sc; +- led->led_cdev.name = led->name; +- led->led_cdev.default_trigger = trigger; +- led->led_cdev.brightness_set = ath_led_brightness; +- +- ret = led_classdev_register(wiphy_dev(sc->hw->wiphy), &led->led_cdev); +- if (ret) +- ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL, +- "Failed to register led:%s", led->name); +- else +- led->registered = 1; +- return ret; +-} +- +-static void ath_unregister_led(struct ath_led *led) +-{ +- if (led->registered) { +- led_classdev_unregister(&led->led_cdev); +- led->registered = 0; +- } ++ struct ath_softc *sc = container_of(led_cdev, struct ath_softc, led_cdev); ++ ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, (brightness == LED_OFF)); + } + + void ath_deinit_leds(struct ath_softc *sc) + { +- if (AR_SREV_9100(sc->sc_ah)) ++ if (!sc->led_registered) + return; + +- ath_unregister_led(&sc->assoc_led); +- sc->sc_flags &= ~SC_OP_LED_ASSOCIATED; +- ath_unregister_led(&sc->tx_led); +- ath_unregister_led(&sc->rx_led); +- ath_unregister_led(&sc->radio_led); +- ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1); ++ ath_led_brightness(&sc->led_cdev, LED_OFF); ++ led_classdev_unregister(&sc->led_cdev); + } + + void ath_init_leds(struct ath_softc *sc) +@@ -152,48 +71,28 @@ void ath_init_leds(struct ath_softc *sc) + /* LED off, active low */ + ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1); + +- if (led_blink) +- INIT_DELAYED_WORK(&sc->ath_led_blink_work, ath_led_blink_work); ++ /* ++ * create the tpt trigger even if led_blink is disabled, so that ++ * user space can still make use of it ++ */ ++ trigger = ieee80211_create_tpt_led_trigger(sc->hw, HZ, ath9k_blink, ++ ARRAY_SIZE(ath9k_blink)); ++ if (!led_blink) ++ trigger = ieee80211_get_radio_led_name(sc->hw); ++ ++ snprintf(sc->led_name, sizeof(sc->led_name), ++ "ath9k-%s", wiphy_name(sc->hw->wiphy)); ++ sc->led_cdev.name = sc->led_name; ++ sc->led_cdev.default_trigger = trigger; ++ sc->led_cdev.brightness_set = ath_led_brightness; ++ ++ ret = led_classdev_register(wiphy_dev(sc->hw->wiphy), &sc->led_cdev); ++ if (ret < 0) ++ return; + +- trigger = ieee80211_get_radio_led_name(sc->hw); +- snprintf(sc->radio_led.name, sizeof(sc->radio_led.name), +- "ath9k-%s::radio", wiphy_name(sc->hw->wiphy)); +- ret = ath_register_led(sc, &sc->radio_led, trigger); +- sc->radio_led.led_type = ATH_LED_RADIO; +- if (ret) +- goto fail; +- +- trigger = ieee80211_get_assoc_led_name(sc->hw); +- snprintf(sc->assoc_led.name, sizeof(sc->assoc_led.name), +- "ath9k-%s::assoc", wiphy_name(sc->hw->wiphy)); +- ret = ath_register_led(sc, &sc->assoc_led, trigger); +- sc->assoc_led.led_type = ATH_LED_ASSOC; +- if (ret) +- goto fail; +- +- trigger = ieee80211_get_tx_led_name(sc->hw); +- snprintf(sc->tx_led.name, sizeof(sc->tx_led.name), +- "ath9k-%s::tx", wiphy_name(sc->hw->wiphy)); +- ret = ath_register_led(sc, &sc->tx_led, trigger); +- sc->tx_led.led_type = ATH_LED_TX; +- if (ret) +- goto fail; +- +- trigger = ieee80211_get_rx_led_name(sc->hw); +- snprintf(sc->rx_led.name, sizeof(sc->rx_led.name), +- "ath9k-%s::rx", wiphy_name(sc->hw->wiphy)); +- ret = ath_register_led(sc, &sc->rx_led, trigger); +- sc->rx_led.led_type = ATH_LED_RX; +- if (ret) +- goto fail; +- +- return; +- +-fail: +- if (led_blink) +- cancel_delayed_work_sync(&sc->ath_led_blink_work); +- ath_deinit_leds(sc); ++ sc->led_registered = true; + } ++#endif + + /*******************/ + /* Rfkill */ +--- a/drivers/net/wireless/ath/ath9k/main.c ++++ b/drivers/net/wireless/ath/ath9k/main.c +@@ -1276,9 +1276,6 @@ static void ath9k_stop(struct ieee80211_ + + aphy->state = ATH_WIPHY_INACTIVE; + +- if (led_blink) +- cancel_delayed_work_sync(&sc->ath_led_blink_work); +- + cancel_delayed_work_sync(&sc->tx_complete_work); + cancel_work_sync(&sc->paprd_work); + cancel_work_sync(&sc->hw_check_work); |