/* * First try at a PPC idled kernel thread * Should slow the CPU via ICTC when idle for too long */ #include #include #include #include #define CONFIG_APM_CPU_IDLE /* Instruction fetch interval expressed in processor clock cycles */ #define ICTC_CPU_SLOWED 4 #ifdef CONFIG_APM_CPU_IDLE static int clock_slowed; #endif static int exit_kapmd; static int kapmd_running; extern void _set_ICTC(int); static int apm_do_idle(void) { clock_slowed = 1; /* Set ICTC and make sure ICTC[E] is set */ _set_ICTC((ICTC_CPU_SLOWED << 1) | 1); return 1; } static void apm_do_busy(void) { if (clock_slowed) { /* Reset ICTC */ _set_ICTC(0); clock_slowed = 0; } } /* * This is the APM thread main loop. * * Check whether we're the only running process to * decide if we should just power down. * */ #define system_idle() (nr_running == 1) #define APM_CHECK_TIMEOUT (HZ) static void apm_mainloop(void) { int timeout = HZ; set_current_state(TASK_INTERRUPTIBLE); for (;;) { /* Nothing to do, just sleep for the timeout */ // timeout = 2*timeout; if (timeout > APM_CHECK_TIMEOUT) timeout = APM_CHECK_TIMEOUT; schedule_timeout(timeout); if (exit_kapmd) break; /* * Ok, check for idle (and mark us sleeping * so as not to count towards the load average).. */ set_current_state(TASK_INTERRUPTIBLE); if (!system_idle()) continue; if (apm_do_idle()) { while ((!exit_kapmd) && system_idle()) { apm_do_idle(); } apm_do_busy(); // timeout = 1; } } } static int ppc_idled(void *unused) { kapmd_running = 1; daemonize(); strcpy(current->comm, "k_ppc_idled"); sigfillset(¤t->blocked); current->tty = NULL; /* get rid of controlling tty */ printk(KERN_INFO "PPC idled kernel thread started.\n"); if (smp_num_cpus == 1) { apm_mainloop(); } kapmd_running = 0; return 0; } /* * Just start the APM thread. We do NOT want to do APM BIOS * calls from anything but the APM thread, if for no other reason * than the fact that we don't trust the APM BIOS. This way, * most common APM BIOS problems that lead to protection errors * etc will have at least some level of being contained... * * In short, if something bad happens, at least we have a choice * of just killing the apm thread.. */ static int __init apm_init(void) { kernel_thread(ppc_idled, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD); return 0; } static void __exit apm_exit(void) { exit_kapmd = 1; while (kapmd_running) schedule(); } module_init(apm_init); module_exit(apm_exit); EXPORT_NO_SYMBOLS;