diff options
author | Wey-Yi Guy <wey-yi.w.guy@intel.com> | 2011-01-21 18:26:39 -0500 |
---|---|---|
committer | Wey-Yi Guy <wey-yi.w.guy@intel.com> | 2011-01-21 18:26:39 -0500 |
commit | 5ed540aecc2aae92d5c97b9a9306a5bf88ad5574 (patch) | |
tree | 0b19e77d0f5ed9ac4d88ab733440d7ea6348ea4e /drivers/net/wireless/iwlwifi/iwl-led.c | |
parent | 4a4fdf2e0b9e3534f6ec4f3e7077470bd66924ab (diff) |
iwlwifi: use mac80211 throughput trigger
Instead of keeping track of LED blink speed
in the driver, use the new mac80211 trigger
and link it up with an LED classdev that we
now register. This also allows users more
flexibility in how they want to have the LED
blink or not.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-led.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-led.c | 201 |
1 files changed, 80 insertions, 121 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c index 46ccdf406e8e..074ad2275228 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-led.c | |||
@@ -48,31 +48,19 @@ module_param(led_mode, int, S_IRUGO); | |||
48 | MODULE_PARM_DESC(led_mode, "0=system default, " | 48 | MODULE_PARM_DESC(led_mode, "0=system default, " |
49 | "1=On(RF On)/Off(RF Off), 2=blinking"); | 49 | "1=On(RF On)/Off(RF Off), 2=blinking"); |
50 | 50 | ||
51 | static const struct { | 51 | static const struct ieee80211_tpt_blink iwl_blink[] = { |
52 | u16 tpt; /* Mb/s */ | 52 | { .throughput = 0 * 1024 - 1, .blink_time = 334 }, |
53 | u8 on_time; | 53 | { .throughput = 1 * 1024 - 1, .blink_time = 260 }, |
54 | u8 off_time; | 54 | { .throughput = 5 * 1024 - 1, .blink_time = 220 }, |
55 | } blink_tbl[] = | 55 | { .throughput = 10 * 1024 - 1, .blink_time = 190 }, |
56 | { | 56 | { .throughput = 20 * 1024 - 1, .blink_time = 170 }, |
57 | {300, 25, 25}, | 57 | { .throughput = 50 * 1024 - 1, .blink_time = 150 }, |
58 | {200, 40, 40}, | 58 | { .throughput = 70 * 1024 - 1, .blink_time = 130 }, |
59 | {100, 55, 55}, | 59 | { .throughput = 100 * 1024 - 1, .blink_time = 110 }, |
60 | {70, 65, 65}, | 60 | { .throughput = 200 * 1024 - 1, .blink_time = 80 }, |
61 | {50, 75, 75}, | 61 | { .throughput = 300 * 1024 - 1, .blink_time = 50 }, |
62 | {20, 85, 85}, | ||
63 | {10, 95, 95}, | ||
64 | {5, 110, 110}, | ||
65 | {1, 130, 130}, | ||
66 | {0, 167, 167}, | ||
67 | /* SOLID_ON */ | ||
68 | {-1, IWL_LED_SOLID, 0} | ||
69 | }; | 62 | }; |
70 | 63 | ||
71 | #define IWL_1MB_RATE (128 * 1024) | ||
72 | #define IWL_LED_THRESHOLD (16) | ||
73 | #define IWL_MAX_BLINK_TBL (ARRAY_SIZE(blink_tbl) - 1) /* exclude SOLID_ON */ | ||
74 | #define IWL_SOLID_BLINK_IDX (ARRAY_SIZE(blink_tbl) - 1) | ||
75 | |||
76 | /* | 64 | /* |
77 | * Adjust led blink rate to compensate on a MAC Clock difference on every HW | 65 | * Adjust led blink rate to compensate on a MAC Clock difference on every HW |
78 | * Led blink rate analysis showed an average deviation of 0% on 3945, | 66 | * Led blink rate analysis showed an average deviation of 0% on 3945, |
@@ -97,133 +85,104 @@ static inline u8 iwl_blink_compensation(struct iwl_priv *priv, | |||
97 | } | 85 | } |
98 | 86 | ||
99 | /* Set led pattern command */ | 87 | /* Set led pattern command */ |
100 | static int iwl_led_pattern(struct iwl_priv *priv, unsigned int idx) | 88 | static int iwl_led_cmd(struct iwl_priv *priv, |
89 | unsigned long on, | ||
90 | unsigned long off) | ||
101 | { | 91 | { |
102 | struct iwl_led_cmd led_cmd = { | 92 | struct iwl_led_cmd led_cmd = { |
103 | .id = IWL_LED_LINK, | 93 | .id = IWL_LED_LINK, |
104 | .interval = IWL_DEF_LED_INTRVL | 94 | .interval = IWL_DEF_LED_INTRVL |
105 | }; | 95 | }; |
96 | int ret; | ||
106 | 97 | ||
107 | BUG_ON(idx > IWL_MAX_BLINK_TBL); | 98 | if (!test_bit(STATUS_READY, &priv->status)) |
99 | return -EBUSY; | ||
108 | 100 | ||
109 | IWL_DEBUG_LED(priv, "Led blink time compensation= %u\n", | 101 | if (priv->blink_on == on && priv->blink_off == off) |
102 | return 0; | ||
103 | |||
104 | IWL_DEBUG_LED(priv, "Led blink time compensation=%u\n", | ||
110 | priv->cfg->base_params->led_compensation); | 105 | priv->cfg->base_params->led_compensation); |
111 | led_cmd.on = | 106 | led_cmd.on = iwl_blink_compensation(priv, on, |
112 | iwl_blink_compensation(priv, blink_tbl[idx].on_time, | ||
113 | priv->cfg->base_params->led_compensation); | 107 | priv->cfg->base_params->led_compensation); |
114 | led_cmd.off = | 108 | led_cmd.off = iwl_blink_compensation(priv, off, |
115 | iwl_blink_compensation(priv, blink_tbl[idx].off_time, | ||
116 | priv->cfg->base_params->led_compensation); | 109 | priv->cfg->base_params->led_compensation); |
117 | 110 | ||
118 | return priv->cfg->ops->led->cmd(priv, &led_cmd); | 111 | ret = priv->cfg->ops->led->cmd(priv, &led_cmd); |
112 | if (!ret) { | ||
113 | priv->blink_on = on; | ||
114 | priv->blink_off = off; | ||
115 | } | ||
116 | return ret; | ||
119 | } | 117 | } |
120 | 118 | ||
121 | int iwl_led_start(struct iwl_priv *priv) | 119 | static void iwl_led_brightness_set(struct led_classdev *led_cdev, |
120 | enum led_brightness brightness) | ||
122 | { | 121 | { |
123 | return priv->cfg->ops->led->on(priv); | 122 | struct iwl_priv *priv = container_of(led_cdev, struct iwl_priv, led); |
124 | } | 123 | unsigned long on = 0; |
125 | EXPORT_SYMBOL(iwl_led_start); | ||
126 | 124 | ||
127 | int iwl_led_associate(struct iwl_priv *priv) | 125 | if (brightness > 0) |
128 | { | 126 | on = IWL_LED_SOLID; |
129 | IWL_DEBUG_LED(priv, "Associated\n"); | ||
130 | if (priv->cfg->led_mode == IWL_LED_BLINK) | ||
131 | priv->allow_blinking = 1; | ||
132 | priv->last_blink_time = jiffies; | ||
133 | 127 | ||
134 | return 0; | 128 | iwl_led_cmd(priv, on, 0); |
135 | } | 129 | } |
136 | EXPORT_SYMBOL(iwl_led_associate); | ||
137 | 130 | ||
138 | int iwl_led_disassociate(struct iwl_priv *priv) | 131 | static int iwl_led_blink_set(struct led_classdev *led_cdev, |
132 | unsigned long *delay_on, | ||
133 | unsigned long *delay_off) | ||
139 | { | 134 | { |
140 | priv->allow_blinking = 0; | 135 | struct iwl_priv *priv = container_of(led_cdev, struct iwl_priv, led); |
141 | 136 | ||
142 | return 0; | 137 | return iwl_led_cmd(priv, *delay_on, *delay_off); |
143 | } | 138 | } |
144 | EXPORT_SYMBOL(iwl_led_disassociate); | ||
145 | 139 | ||
146 | /* | 140 | void iwl_leds_init(struct iwl_priv *priv) |
147 | * calculate blink rate according to last second Tx/Rx activities | ||
148 | */ | ||
149 | static int iwl_get_blink_rate(struct iwl_priv *priv) | ||
150 | { | ||
151 | int i; | ||
152 | /* count both tx and rx traffic to be able to | ||
153 | * handle traffic in either direction | ||
154 | */ | ||
155 | u64 current_tpt = priv->tx_stats.data_bytes + | ||
156 | priv->rx_stats.data_bytes; | ||
157 | s64 tpt = current_tpt - priv->led_tpt; | ||
158 | |||
159 | if (tpt < 0) /* wraparound */ | ||
160 | tpt = -tpt; | ||
161 | |||
162 | IWL_DEBUG_LED(priv, "tpt %lld current_tpt %llu\n", | ||
163 | (long long)tpt, | ||
164 | (unsigned long long)current_tpt); | ||
165 | priv->led_tpt = current_tpt; | ||
166 | |||
167 | if (!priv->allow_blinking) | ||
168 | i = IWL_MAX_BLINK_TBL; | ||
169 | else | ||
170 | for (i = 0; i < IWL_MAX_BLINK_TBL; i++) | ||
171 | if (tpt > (blink_tbl[i].tpt * IWL_1MB_RATE)) | ||
172 | break; | ||
173 | |||
174 | IWL_DEBUG_LED(priv, "LED BLINK IDX=%d\n", i); | ||
175 | return i; | ||
176 | } | ||
177 | |||
178 | /* | ||
179 | * this function called from handler. Since setting Led command can | ||
180 | * happen very frequent we postpone led command to be called from | ||
181 | * REPLY handler so we know ucode is up | ||
182 | */ | ||
183 | void iwl_leds_background(struct iwl_priv *priv) | ||
184 | { | 141 | { |
185 | u8 blink_idx; | 142 | int mode = led_mode; |
186 | 143 | int ret; | |
187 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) { | 144 | |
188 | priv->last_blink_time = 0; | 145 | if (mode == IWL_LED_DEFAULT) |
189 | return; | 146 | mode = priv->cfg->led_mode; |
190 | } | 147 | |
191 | if (iwl_is_rfkill(priv)) { | 148 | priv->led.name = kasprintf(GFP_KERNEL, "%s-led", |
192 | priv->last_blink_time = 0; | 149 | wiphy_name(priv->hw->wiphy)); |
193 | return; | 150 | priv->led.brightness_set = iwl_led_brightness_set; |
151 | priv->led.blink_set = iwl_led_blink_set; | ||
152 | priv->led.max_brightness = 1; | ||
153 | |||
154 | switch (mode) { | ||
155 | case IWL_LED_DEFAULT: | ||
156 | WARN_ON(1); | ||
157 | break; | ||
158 | case IWL_LED_BLINK: | ||
159 | priv->led.default_trigger = | ||
160 | ieee80211_create_tpt_led_trigger(priv->hw, | ||
161 | IEEE80211_TPT_LEDTRIG_FL_CONNECTED, | ||
162 | iwl_blink, ARRAY_SIZE(iwl_blink)); | ||
163 | break; | ||
164 | case IWL_LED_RF_STATE: | ||
165 | priv->led.default_trigger = | ||
166 | ieee80211_get_radio_led_name(priv->hw); | ||
167 | break; | ||
194 | } | 168 | } |
195 | 169 | ||
196 | if (!priv->allow_blinking) { | 170 | ret = led_classdev_register(&priv->pci_dev->dev, &priv->led); |
197 | priv->last_blink_time = 0; | 171 | if (ret) { |
198 | if (priv->last_blink_rate != IWL_SOLID_BLINK_IDX) { | 172 | kfree(priv->led.name); |
199 | priv->last_blink_rate = IWL_SOLID_BLINK_IDX; | ||
200 | iwl_led_pattern(priv, IWL_SOLID_BLINK_IDX); | ||
201 | } | ||
202 | return; | 173 | return; |
203 | } | 174 | } |
204 | if (!priv->last_blink_time || | ||
205 | !time_after(jiffies, priv->last_blink_time + | ||
206 | msecs_to_jiffies(1000))) | ||
207 | return; | ||
208 | |||
209 | blink_idx = iwl_get_blink_rate(priv); | ||
210 | 175 | ||
211 | /* call only if blink rate change */ | 176 | priv->led_registered = true; |
212 | if (blink_idx != priv->last_blink_rate) | ||
213 | iwl_led_pattern(priv, blink_idx); | ||
214 | |||
215 | priv->last_blink_time = jiffies; | ||
216 | priv->last_blink_rate = blink_idx; | ||
217 | } | 177 | } |
218 | EXPORT_SYMBOL(iwl_leds_background); | 178 | EXPORT_SYMBOL(iwl_leds_init); |
219 | 179 | ||
220 | void iwl_leds_init(struct iwl_priv *priv) | 180 | void iwl_leds_exit(struct iwl_priv *priv) |
221 | { | 181 | { |
222 | priv->last_blink_rate = 0; | 182 | if (!priv->led_registered) |
223 | priv->last_blink_time = 0; | 183 | return; |
224 | priv->allow_blinking = 0; | 184 | |
225 | if (led_mode != IWL_LED_DEFAULT && | 185 | led_classdev_unregister(&priv->led); |
226 | led_mode != priv->cfg->led_mode) | 186 | kfree(priv->led.name); |
227 | priv->cfg->led_mode = led_mode; | ||
228 | } | 187 | } |
229 | EXPORT_SYMBOL(iwl_leds_init); | 188 | EXPORT_SYMBOL(iwl_leds_exit); |