root/trunk/patches/2.6.22/82-leds-arm-cpu-activity.patch
| Revision 833, 17.8 kB (checked in by blaster8, 3 years ago) |
|---|
-
linux-2.6.22-rc1-arm/arch/arm/kernel/process.c
old new 25 25 #include <linux/kallsyms.h> 26 26 #include <linux/init.h> 27 27 #include <linux/cpu.h> 28 #include <linux/leds.h> 28 29 #include <linux/elfcore.h> 29 30 #include <linux/pm.h> 30 31 #include <linux/tick.h> … … 120 121 121 122 122 123 /* 124 * CPU activity indicator. 125 */ 126 void (*leds_idle)(int is_idle); 127 EXPORT_SYMBOL(leds_idle); 128 129 /* 123 130 * This is our default idle handler. We need to disable 124 131 * interrupts here to ensure we don't miss a wakeup call. 125 132 */ … … 160 167 if (!idle) 161 168 idle = default_idle; 162 169 leds_event(led_idle_start); 170 if (leds_idle) 171 leds_idle(1); 163 172 tick_nohz_stop_sched_tick(); 164 173 while (!need_resched()) 165 174 idle(); 175 if (leds_idle) 176 leds_idle(0); 166 177 leds_event(led_idle_end); 167 178 tick_nohz_restart_sched_tick(); 168 179 preempt_enable_no_resched(); -
linux-2.6.22-rc1-arm/drivers/leds/Kconfig
old new 128 128 load average. 129 129 If unsure, say Y. 130 130 131 config LEDS_TRIGGER_CPU_ACTIVITY 132 tristate "LED CPU activity trigger" 133 depends LEDS_TRIGGER_TIMER 134 help 135 This allows LEDs to be set to show cpu activity via sysfs. 136 The LED will blink when the cpu is active and stay steady 137 (on or off according to the trigger selected) when idle. 138 If unsure, say Y. 139 131 140 endmenu 132 141 -
linux-2.6.22-rc1-arm/drivers/leds/Makefile
old new 21 21 obj-$(CONFIG_LEDS_TRIGGER_TIMER) += ledtrig-timer.o 22 22 obj-$(CONFIG_LEDS_TRIGGER_IDE_DISK) += ledtrig-ide-disk.o 23 23 obj-$(CONFIG_LEDS_TRIGGER_HEARTBEAT) += ledtrig-heartbeat.o 24 obj-$(CONFIG_LEDS_TRIGGER_CPU_ACTIVITY) += ledtrig-cpu.o -
/dev/null
old new 1 /* 2 * LEDs CPU activity trigger 3 * 4 * Author: John Bowler <jbowler@acm.org> 5 * 6 * Copyright (c) 2006 John Bowler 7 * 8 * Permission is hereby granted, free of charge, to any 9 * person obtaining a copy of this software and associated 10 * documentation files (the "Software"), to deal in the 11 * Software without restriction, including without 12 * limitation the rights to use, copy, modify, merge, 13 * publish, distribute, sublicense, and/or sell copies of 14 * the Software, and to permit persons to whom the 15 * Software is furnished to do so, subject to the 16 * following conditions: 17 * 18 * The above copyright notice and this permission notice 19 * shall be included in all copies or substantial portions 20 * of the Software. 21 * 22 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 23 * ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 24 * TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 25 * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 26 * SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 27 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 29 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 30 * OTHER DEALINGS IN THE SOFTWARE. 31 * 32 */ 33 34 #include <linux/ctype.h> 35 #include <linux/kernel.h> 36 #include <linux/module.h> 37 #include <linux/init.h> 38 #include <linux/spinlock.h> 39 #include <linux/timer.h> 40 #include <linux/device.h> 41 42 #include <linux/leds.h> 43 #include "leds.h" 44 45 //#include <linux/list.h> 46 //#include <linux/sysdev.h> 47 48 49 /* 50 * To simplify this the LED state is given for each case of 51 * CPU state - idle or active. The LED can be: 52 * 53 * off 54 * flash - slow for idle, fast (flicker) for active 55 * on 56 * 57 * This gives two useless states - off/off and on/on 58 */ 59 typedef enum cpu_trigger_led_state { 60 cpu_led_off, 61 cpu_led_flash, 62 cpu_led_on, 63 cpu_led_invalid 64 } cpu_trigger_led_state; 65 66 static const char *const cpu_trigger_names[] = { 67 "off", 68 "flash", 69 "on", 70 "invalid" 71 }; 72 73 /* Forward declaration - this is called back when an LED property 74 * is changed. 75 */ 76 static void leds_cpu_trigger_state_change(void); 77 78 /* 79 * These constants define the actual mark/space of the flashing 80 * in jiffies. msecs_to_jiffies rounds up and is compile time 81 * evaluable for constant arguments. Writing the ?: stuff below 82 * this way ensures the compiler doesn't think it needs to 83 * compile in the math of msecs_to_jiffies. 84 * 85 * These values have been determined by experiment to work well 86 * for the ready/status LED on a LinkSys NSLU2 (light piped) and 87 * for the user LED on a Loft (Gateway Avila variant) board where 88 * the LED was directly visible. Light Output Varies Everywhere. 89 */ 90 #define LEDS_CPU_ACTIVE_MARK msecs_to_jiffies(40) 91 #define LEDS_CPU_IDLE_MARK msecs_to_jiffies(800) 92 #define LEDS_CPU_ACTIVE_SPACE msecs_to_jiffies(60) 93 #define LEDS_CPU_IDLE_SPACE msecs_to_jiffies(800) 94 95 96 /* 97 * Individual LEDs ------------------------------------------------------------ 98 */ 99 struct cpu_trigger_data { 100 cpu_trigger_led_state active; /* Behaviour when the CPU is active. */ 101 cpu_trigger_led_state idle; /* Behaviour when the CPU is idle. */ 102 }; 103 104 /* 105 * LED state change - called when the state of a single LED might 106 * have changed. Returns true if the LED is blinking. The argument 107 * is the blink state - the brightness of the blinking LED. 108 */ 109 static int leds_cpu_trigger_led_state_change(struct led_classdev *led, 110 int is_active, enum led_brightness brightness) 111 { 112 int is_blinking = 0; 113 114 struct cpu_trigger_data *data = led->trigger_data; 115 116 /* Find the new brightness for the LED, if the LED is 117 * set to flash then the brightness passed in is the 118 * required value. 119 */ 120 if (likely(data != 0)) 121 switch (is_active ? data->active : data->idle) { 122 case cpu_led_off: brightness = LED_OFF; break; 123 case cpu_led_flash: is_blinking = 1; break; 124 case cpu_led_on: brightness = LED_FULL; break; 125 } 126 else 127 brightness = is_active ? LED_FULL : LED_OFF; 128 129 led_set_brightness(led, brightness); 130 131 return is_blinking; 132 } 133 134 /* 135 * sysfs properties, the property is output at an list of the 136 * values with the current setting enclosed in [] 137 */ 138 static ssize_t leds_cpu_trigger_show_prop(struct class_device *dev, char *buf, 139 size_t where) 140 { 141 struct led_classdev *led = dev->class_data; 142 cpu_trigger_led_state item = cpu_led_invalid, i; 143 char *next; 144 145 if (likely(led->trigger_data != 0)) 146 item = *(const cpu_trigger_led_state*)( 147 led->trigger_data + where); 148 149 for (i=0, next=buf; i<cpu_led_invalid; ++i) { 150 const char *name = cpu_trigger_names[i]; 151 size_t len = strlen(name); 152 153 if (i == item) 154 *next++ = '['; 155 memcpy(next, name, len); 156 next += len; 157 if (i == item) 158 *next++ = ']'; 159 *next++ = ' '; 160 } 161 162 next[-1] = '\n'; 163 *next++ = 0; 164 165 return next - buf; 166 } 167 168 static ssize_t leds_cpu_trigger_show_active(struct class_device *dev, char *buf) 169 { 170 return leds_cpu_trigger_show_prop(dev, buf, 171 offsetof(struct cpu_trigger_data, active)); 172 } 173 174 static ssize_t leds_cpu_trigger_show_idle(struct class_device *dev, char *buf) 175 { 176 return leds_cpu_trigger_show_prop(dev, buf, 177 offsetof(struct cpu_trigger_data, idle)); 178 } 179 180 /* 181 * Any matching leading substring selects a property - so "onoffonoff" 182 * sets the property to off. 183 */ 184 static ssize_t leds_cpu_trigger_store_prop(struct class_device *dev, 185 const char *buf, size_t size, size_t where) 186 { 187 size_t rc = 0; 188 cpu_trigger_led_state value = 0/*sic*/; 189 struct led_classdev *led; 190 191 /* ignore space characters before the value. */ 192 while (rc < size && isspace(buf[rc])) 193 ++rc; 194 if (rc >= size) 195 return rc; 196 197 /* look for a simple match against the trigger name, case 198 * sensitive. 199 */ 200 do { 201 const char *name = cpu_trigger_names[value]; 202 size_t len = strlen(name); 203 if (len <= size && memcmp(buf+rc, name, len) == 0) { 204 rc = len; 205 break; 206 } 207 if (++value >= cpu_led_invalid) 208 return -EINVAL; 209 } while (1); 210 211 led = dev->class_data; 212 if (likely(led->trigger_data != 0)) 213 *(cpu_trigger_led_state*)( 214 led->trigger_data + where) = value; 215 216 return rc; 217 } 218 219 static ssize_t leds_cpu_trigger_store_active(struct class_device *dev, 220 const char *buf, size_t size) 221 { 222 ssize_t rc = leds_cpu_trigger_store_prop(dev, buf, size, 223 offsetof(struct cpu_trigger_data, active)); 224 /* 225 * At least one CPU must be active (otherwise who is doing this?) 226 * Call down into the global state below to cause an update 227 * to happen now. 228 */ 229 leds_cpu_trigger_state_change(); 230 return rc; 231 } 232 233 static ssize_t leds_cpu_trigger_store_idle(struct class_device *dev, 234 const char *buf, size_t size) 235 { 236 return leds_cpu_trigger_store_prop(dev, buf, size, 237 offsetof(struct cpu_trigger_data, idle)); 238 } 239 240 static CLASS_DEVICE_ATTR(active, 0644, leds_cpu_trigger_show_active, 241 leds_cpu_trigger_store_active); 242 243 static CLASS_DEVICE_ATTR(idle, 0644, leds_cpu_trigger_show_idle, 244 leds_cpu_trigger_store_idle); 245 246 /* 247 * Activate and deactivate are called on individual LEDs when the 248 * LED trigger property is changed. 249 */ 250 static void leds_cpu_trigger_activate(struct led_classdev *led) 251 { 252 /* 253 * The initial setting of the trigger is simple CPU activity 254 * with the LED off for idle and on for active. Consequently 255 * there is no need to mess with the global state initially, 256 * we know the CPU is active at this moment! 257 */ 258 struct cpu_trigger_data *data = kmalloc(sizeof *data, GFP_KERNEL); 259 if (unlikely(data == 0)) 260 return; 261 262 data->active = cpu_led_on; 263 data->idle = cpu_led_off; 264 led->trigger_data = data; 265 266 class_device_create_file(led->class_dev, &class_device_attr_active); 267 class_device_create_file(led->class_dev, &class_device_attr_idle); 268 269 led_set_brightness(led, LED_FULL); 270 } 271 272 static void leds_cpu_trigger_deactivate(struct led_classdev *led) 273 { 274 struct cpu_trigger_data *data = led->trigger_data; 275 if (likely(data != 0)) { 276 led_set_brightness(led, LED_OFF); 277 278 class_device_remove_file(led->class_dev, &class_device_attr_idle); 279 class_device_remove_file(led->class_dev, &class_device_attr_active); 280 281 led->trigger_data = 0; 282 kfree(data); 283 } 284 } 285 286 287 /* 288 * Global state -------------------------------------------------------------- 289 * 290 * This is global because the CPU state is global and we only need one timer to 291 * do this stuff. 292 */ 293 typedef struct leds_cpu_trigger_data { 294 struct led_trigger trigger; /* the lock in here protects everything */ 295 struct timer_list timer; 296 unsigned long last_active_time; /* record of last jiffies */ 297 unsigned long last_idle_time; /* record of last jiffies */ 298 int count_active; /* number of active CPUs */ 299 } leds_cpu_trigger_data; 300 301 /* 302 * Mark state - uses the current time (jiffies) to work out 303 * whether this is a mark or space. 304 */ 305 static int leds_cpu_trigger_mark(struct leds_cpu_trigger_data *data, 306 unsigned long now) { 307 if (data->count_active > 0) { 308 unsigned long elapsed = now - data->last_active_time; 309 elapsed %= LEDS_CPU_ACTIVE_SPACE + LEDS_CPU_ACTIVE_MARK; 310 data->last_active_time = now - elapsed; 311 return elapsed > LEDS_CPU_ACTIVE_SPACE; 312 } else { 313 unsigned long elapsed = now - data->last_idle_time; 314 elapsed %= LEDS_CPU_IDLE_SPACE + LEDS_CPU_IDLE_MARK; 315 data->last_idle_time = now - elapsed; 316 return elapsed > LEDS_CPU_IDLE_SPACE; 317 } 318 } 319 320 321 /* 322 * State change - given information about the nature of the 323 * (possible) state change call up to each LED to adjust its 324 * state. Returns true if any LED is blinking. The lock 325 * must be held (a read lock is adequate). 326 */ 327 static int leds_cpu_trigger_scan_leds(struct leds_cpu_trigger_data *data, 328 unsigned long now) 329 { 330 int blinking = 0; 331 const int active = data->count_active > 0; 332 const enum led_brightness brightness = 333 leds_cpu_trigger_mark(data, now) ? LED_FULL : LED_OFF; 334 struct list_head *entry; 335 336 list_for_each(entry, &data->trigger.led_cdevs) { 337 struct led_classdev *led = 338 list_entry(entry, struct led_classdev, trig_list); 339 340 blinking |= leds_cpu_trigger_led_state_change(led, 341 active, brightness); 342 } 343 344 return blinking; 345 } 346 347 /* 348 * Set the timer correctly according to the current state, the lock 349 * must be held for write. 350 */ 351 static void leds_cpu_trigger_set_timer(struct leds_cpu_trigger_data *state, 352 unsigned long now) 353 { 354 unsigned long next; 355 if (state->count_active > 0) { 356 next = state->last_active_time; 357 if (now - next > LEDS_CPU_ACTIVE_SPACE) 358 next += LEDS_CPU_ACTIVE_MARK; 359 next += LEDS_CPU_ACTIVE_SPACE; 360 } else { 361 next = state->last_idle_time; 362 if (now - next > LEDS_CPU_IDLE_SPACE) 363 next += LEDS_CPU_IDLE_MARK; 364 next += LEDS_CPU_IDLE_SPACE; 365 } 366 mod_timer(&state->timer, next); 367 } 368 369 /* 370 * The timer callback if the LED is currently flashing, the callback 371 * calls the state change function and, if that returns true, meaning 372 * that at least one LED is still blinking, the timer is restarted 373 * with the correct timeout. 374 */ 375 static void leds_cpu_trigger_timer_callback(unsigned long data) 376 { 377 struct leds_cpu_trigger_data *state = 378 (struct leds_cpu_trigger_data *)data; 379 380 write_lock(&state->trigger.leddev_list_lock); 381 { 382 unsigned long now = jiffies; 383 384 /* If at least one LED is set to flash; set the timer 385 * again (this won't reset the timer set within the 386 * idle loop). 387 */ 388 if (leds_cpu_trigger_scan_leds(state, now)) 389 leds_cpu_trigger_set_timer(state, now); 390 } 391 write_unlock(&state->trigger.leddev_list_lock); 392 } 393 394 395 /* 396 * There is one global control structure, one timer and one set 397 * of state for active CPUs shared across all the LEDs. Individual 398 * LEDs say how this state to be handled. It is currently *not* 399 * possible to show per-cpu activity on individual LEDs, the code 400 * maintains a count of active CPUs and the state is only 'idle' 401 * if all CPUs are idle. 402 */ 403 static struct leds_cpu_trigger_data leds_cpu_trigger = { 404 .trigger = { 405 .name = "cpu", 406 .activate = leds_cpu_trigger_activate, 407 .deactivate = leds_cpu_trigger_deactivate, 408 } , 409 .timer = TIMER_INITIALIZER(leds_cpu_trigger_timer_callback, 0, 410 (unsigned long)&leds_cpu_trigger), 411 .last_active_time = 0, 412 .last_idle_time = 0, 413 .count_active = 0, 414 }; 415 416 /* 417 * State change - callback from an individual LED on a property change which 418 * might require a redisplay. 419 */ 420 static void leds_cpu_trigger_state_change() { 421 write_lock(&leds_cpu_trigger.trigger.leddev_list_lock); 422 { 423 unsigned long now = jiffies; 424 425 if (leds_cpu_trigger_scan_leds(&leds_cpu_trigger, now) && 426 !timer_pending(&leds_cpu_trigger.timer)) 427 leds_cpu_trigger_set_timer(&leds_cpu_trigger, now); 428 } 429 write_unlock(&leds_cpu_trigger.trigger.leddev_list_lock); 430 } 431 432 /* 433 * Called from every CPU at the start and end of the idle loop. 434 * The active count is initially 0, even though CPUs are running, 435 * so the code below must check for the resultant underflow. 436 * 437 * If the idle behaviour is 'flash' then when the timer times out 438 * it will take the CPU out of idle, set the active state (which 439 * may also be flash), drop back into idle and reset the timer to 440 * the idle timeout... 441 */ 442 static void leds_cpu_trigger_idle(int is_idle) 443 { 444 write_lock(&leds_cpu_trigger.trigger.leddev_list_lock); 445 if ((is_idle && leds_cpu_trigger.count_active > 0 && 446 --leds_cpu_trigger.count_active == 0) || 447 (!is_idle && leds_cpu_trigger.count_active < num_online_cpus() && 448 ++leds_cpu_trigger.count_active == 1)) { 449 unsigned long now = jiffies; 450 451 /* State change - the system just became idle or active, 452 * call the del_timer first in an attempt to minimise 453 * getting a timer interrupt which will take us unnecessarily 454 * out of idle (this doesn't matter). 455 */ 456 del_timer(&leds_cpu_trigger.timer); 457 if (leds_cpu_trigger_scan_leds(&leds_cpu_trigger, now)) 458 leds_cpu_trigger_set_timer(&leds_cpu_trigger, now); 459 } 460 write_unlock(&leds_cpu_trigger.trigger.leddev_list_lock); 461 } 462 463 /* 464 * Module init and exit - register the trigger, then store 465 * the idle callback in the arch-specific global. For this 466 * module to link (into the kernel) or load (into a running 467 * kernel) the architecture must define the leds_idle global. 468 */ 469 static int __init leds_cpu_trigger_init(void) 470 { 471 int rc = led_trigger_register(&leds_cpu_trigger.trigger); 472 leds_idle = leds_cpu_trigger_idle; 473 return rc; 474 } 475 module_init(leds_cpu_trigger_init); 476 477 static void __exit leds_cpu_trigger_exit(void) 478 { 479 leds_idle = 0; 480 del_timer_sync(&leds_cpu_trigger.timer); 481 led_trigger_unregister(&leds_cpu_trigger.trigger); 482 } 483 module_exit(leds_cpu_trigger_exit); 484 485 MODULE_AUTHOR("John Bowler <jbowler@acm.org>"); 486 MODULE_DESCRIPTION("CPU activity LED trigger"); 487 MODULE_LICENSE("MIT"); -
linux-2.6.22-rc1-arm/include/linux/leds.h
old new 110 110 #define ledtrig_ide_activity() do {} while(0) 111 111 #endif 112 112 113 /* 114 * CPU activity indication. 115 */ 116 /* Idle callback - call with is_idle==1 at the start of the idle loop 117 * and with is_idle==0 at the end. This symbol must be defined by 118 * the arch core to be able to use LEDS_TRIGGER_CPU_ACTIVITY 119 */ 120 extern void (*leds_idle)(int is_idle); 121 113 122 #endif /* __LINUX_LEDS_H_INCLUDED */
Note: See TracBrowser for help on using the browser.
