📄 dpm.c
字号:
/***************************************************************************** * destroy an operating point * Assumes dpm_sem is held and the opt is no longer needed *anywhere* *****************************************************************************/voiddestroy_opt(struct dpm_opt *opt){ list_del(&opt->list); kfree(opt->name); kfree(opt);}/***************************************************************************** * create a named class of operating points (to be used to map to an operating * state) *****************************************************************************/intdpm_create_class(const char *name, char **op_names, unsigned nops){ int i; struct dpm_class *cls; trace("in dpm_create_class for \"%s\"\n", name); dpm_lock(); /* ensure class is not empty */ if (nops == 0) { dpm_unlock(); return -EINVAL; } /* ensure name is unique */ list_find(cls, name, dpm_classes, struct dpm_class); if (cls) { dpm_unlock(); return -EEXIST; } /* get memory for class */ cls = (struct dpm_class *) kmalloc(sizeof (struct dpm_class), GFP_KERNEL); if (!cls) { dpm_unlock(); return -ENOMEM; } trace("%s @ 0x%08lx\n", name, (unsigned long)cls); memset(cls, 0, sizeof (struct dpm_class)); /* get memory for array of pointers to operating points */ cls->ops = (struct dpm_opt **) kmalloc(nops * sizeof (struct dpm_opt *), GFP_KERNEL); if (!cls->ops) { kfree(cls); dpm_unlock(); return -ENOMEM; } /* get memory for class name */ cls->name = (char *) kmalloc(strlen(name) + 1, GFP_KERNEL); if (!cls->name) { kfree(cls->ops); kfree(cls); dpm_unlock(); return -ENOMEM; } /* find named op points and put their pointers in the class */ for (i = 0; i < nops; ++i) { struct dpm_opt *opt; list_find(opt, op_names[i], dpm_opts, struct dpm_opt); if (!opt) { kfree(cls->name); kfree(cls->ops); kfree(cls); dpm_unlock(); return -ENOENT; } cls->ops[i] = opt; } strcpy(cls->name, name); cls->nops = nops; cls->opt = cls->ops[0]; /* add class to our list */ list_add(&cls->list, &dpm_classes); dpm_unlock(); return 0;}/***************************************************************************** * destroy a class * Assumes dpm_sem is held and the class is no longer needed *anywhere* *****************************************************************************/voiddestroy_class(struct dpm_class *cls){ list_del(&cls->list); kfree(cls->ops); kfree(cls->name); kfree(cls);}/********* * Fill out pointer with all classes for a policy */intdpm_get_classes_in_policy(char *name, char **class_names){ int i; struct dpm_policy *policy; list_find(policy, name, dpm_policies, struct dpm_policy); if (policy == NULL) { return -EEXIST; } for(i = 0; i < DPM_STATES; i++) { class_names[i] = policy->classes[i]->name; } return 0;}/********* * Fill out pointer with all currently installed policies */intdpm_get_all_policies(char **policies){ int i = 0; struct list_head * p; list_for_each(p, &dpm_policies) { policies[i++] = ((struct dpm_policy *) list_entry(p, struct dpm_policy, list))->name; } return i;}/***************************************************************************** * create power policy *****************************************************************************/intdpm_create_policy(const char *name, char **class_names){ int i; struct dpm_policy *policy; trace("in dpm_install_policy for \"%s\" policy\n", name); dpm_lock(); /* ensure unique name */ list_find(policy, name, dpm_policies, struct dpm_policy); if (policy) { dpm_unlock(); return -EEXIST; } /* get memory for policy */ policy = (struct dpm_policy *) kmalloc(sizeof (struct dpm_policy), GFP_KERNEL); if (!policy) { dpm_unlock(); return -ENOMEM; } trace("%s @ 0x%08lx\n", name, (unsigned long)policy); memset(policy, 0, sizeof (struct dpm_policy)); /* get memory for policy name */ policy->name = (char *) kmalloc(strlen(name) + 1, GFP_KERNEL); if (!policy->name) { kfree(policy); dpm_unlock(); return -ENOMEM; } /* initialize the policy */ for (i = 0; i < DPM_STATES; ++i) { if (!class_names[i]) { kfree(policy->name); kfree(policy); dpm_unlock(); return -EINVAL; } list_find(policy->classes[i],class_names[i], dpm_classes, struct dpm_class); if(!policy->classes[i]) { kfree(policy->name); kfree(policy); dpm_unlock(); return -ENOENT; } } strcpy(policy->name, name); /* add policy to our list */ list_add(&policy->list, &dpm_policies); trace("installed \"%s\" policy\n", name); dpm_unlock(); return 0;}/***************************************************************************** * destroy a power policy * Assumes dpm_sem is held and the policy is no longer needed *anywhere* *****************************************************************************/voiddestroy_policy(struct dpm_policy *policy){ list_del(&policy->list); kfree(policy->name); kfree(policy);}/***************************************************************************** * uninstall power policy *****************************************************************************/intdpm_destroy_policy(const char *name){ struct dpm_policy *policy; trace("processing destroy request for \"%s\"\n", name); dpm_lock(); /* find the named policy */ list_find(policy, name, dpm_policies, struct dpm_policy); if (!policy) { dpm_unlock(); return -ENOENT; } /* can't uninstall active policy */ if (policy == dpm_active_policy) { dpm_unlock(); return -EBUSY; } /* remove the policy */ destroy_policy(policy); dpm_unlock(); trace("destroyed \"%s\" policy\n", name); return 0;}/* * set active power policy */intdpm_set_policy(const char *name){ int i, j; struct dpm_policy *new_p; struct dpm_class *cls; trace("in dpm_set_policy for \"%s\" policy\n", name); dpm_lock(); list_find(new_p, name, dpm_policies, struct dpm_policy); if (!new_p) { dpm_trace(DPM_TRACE_SET_POLICY, name, -ENOENT); dpm_unlock(); return -ENOENT; /* invalid name */ } if (new_p == dpm_active_policy) { dpm_trace(DPM_TRACE_SET_POLICY, name, 0); trace("\"%s\" policy already activated\n", name); dpm_unlock(); return 0; } /* find best unconstrained operating point for each operating state */ for (i = 0; i < DPM_STATES; ++i) { cls = new_p->classes[i]; cls->opt = 0; for (j = 0; j < cls->nops; ++j) { if (!cls->ops[j]->constrained) { cls->opt = cls->ops[j]; break; } } if (!cls->opt) { dpm_trace(DPM_TRACE_SET_POLICY, name, -EPERM); dpm_unlock(); return -EPERM; } }#ifdef CONFIG_DPM_STATS if (dpm_active_policy) dpm_update_stats(&new_p->stats, &dpm_active_policy->stats); else { new_p->stats.start_time = dpm_md_time(); new_p->stats.end_time = 0; new_p->stats.count++; }#endif dpm_active_policy = new_p; dpm_enabled = 1; /* Start the policy synchronously */ mb(); dpm_trace(DPM_TRACE_SET_POLICY, name, 0); dpm_set_opt_sync(); dpm_unlock(); return 0;}/***************************************************************************** * set a task state *****************************************************************************/intdpm_set_task_state(pid_t pid, dpm_state_t task_state){ struct task_struct *p; if (task_state == -(DPM_TASK_STATE_LIMIT + 1)) task_state = DPM_NO_STATE; else if (abs(task_state) > DPM_TASK_STATE_LIMIT) { dpm_trace(DPM_TRACE_SET_TASK_STATE, pid, task_state, -EINVAL); return -EINVAL; } else task_state += DPM_TASK_STATE; read_lock(&tasklist_lock); if (pid == 0) p = current; else p = find_task_by_pid(pid); if (!p) { read_unlock(&tasklist_lock); dpm_trace(DPM_TRACE_SET_TASK_STATE, pid, task_state, -ENOENT); return -ENOENT; } p->dpm_state = task_state; read_unlock(&tasklist_lock); dpm_trace(DPM_TRACE_SET_TASK_STATE, pid, task_state, 0); if (pid == 0) dpm_set_os(p->dpm_state); return 0;}/***************************************************************************** * set a raw op state *****************************************************************************/intdpm_set_op_state(const char *name){ int op_state; for (op_state = 0; op_state < DPM_STATES; op_state++) if (strcmp(dpm_state_names[op_state], name) == 0) { dpm_set_os(op_state); return 0; } return -ENOENT;}/***************************************************************************** * get a task state *****************************************************************************/intdpm_get_task_state(pid_t pid, dpm_state_t * task_state){ struct task_struct *p; read_lock(&tasklist_lock); if (pid == 0) p = current; else p = find_task_by_pid(pid); if (!p) { read_unlock(&tasklist_lock); return -ENOENT; } if (p->dpm_state == DPM_NO_STATE) *task_state = -(DPM_TASK_STATE_LIMIT + 1); else *task_state = p->dpm_state - DPM_TASK_STATE; read_unlock(&tasklist_lock); return 0;}/***************************************************************************** * terminate the DPM *****************************************************************************/intdpm_terminate(void){ trace("in dpm_terminate\n"); if (!dpm_initialized) return 0; dpm_lock(); dpm_initialized = 0; dpm_enabled = 0; dpm_active_opt = NULL; /* destroy all entities */ while (!list_empty(&dpm_policies)) destroy_policy(list_entry (dpm_policies.next, struct dpm_policy, list)); while (!list_empty(&dpm_classes)) destroy_class(list_entry(dpm_classes.next, struct dpm_class, list)); while (!list_empty(&dpm_opts)) destroy_opt(list_entry(dpm_opts.next, struct dpm_opt, list)); mb(); dpm_unlock(); trace("DPM is now terminated\n"); return 0;}EXPORT_SYMBOL(dpm_init);EXPORT_SYMBOL(dpm_terminate);EXPORT_SYMBOL(dpm_disable);EXPORT_SYMBOL(dpm_enable);EXPORT_SYMBOL(dpm_create_opt);EXPORT_SYMBOL(dpm_create_class);EXPORT_SYMBOL(dpm_create_policy);EXPORT_SYMBOL(dpm_destroy_policy);EXPORT_SYMBOL(dpm_set_policy);/* ?? Needed in kernel mode ?? EXPORT_SYMBOL(dpm_get_policy);*/EXPORT_SYMBOL(dpm_set_task_state);EXPORT_SYMBOL(dpm_get_task_state);extern void *sys_call_table[];/* until we get a permanent syscall number */#ifdef __NR_SYSCALL_BASEstatic int sys_dpm_nr = __NR_sys_dpm - __NR_SYSCALL_BASE;#elsestatic int sys_dpm_nr = __NR_sys_dpm;#endif/**************************************************************************** * install dynamic power policy support ****************************************************************************/intdpm_init_module(void){ extern asmlinkage long sys_ni_syscall(void); /* ensure syscall slot is available */ if (sys_call_table[sys_dpm_nr] != sys_ni_syscall) { printk("DPM syscall already taken, system call #%d disabled.\n", sys_dpm_nr); sys_call_table[sys_dpm_nr] = sys_ni_syscall; } else { /* install our syscall */ sys_call_table[sys_dpm_nr] = sys_dpm; }#ifdef CONFIG_PROC_FS { void dpm_proc_init(void); dpm_proc_init(); }#endif dpm_md_init(); trace("DPM is now installed\n"); return 0;}/**************************************************************************** * remove dynamic power policy support ****************************************************************************/voiddpm_exit_module(void){ /* disable power management policy system */ dpm_terminate(); dpm_md_cleanup(); /* uninstall our syscall */ sys_call_table[sys_dpm_nr] = sys_call_table[0];#ifdef CONFIG_PROC_FS { void dpm_proc_cleanup(void); dpm_proc_cleanup(); }#endif trace("DPM module is now unloaded\n");}/**************************************************************************** * LTT ****************************************************************************/#ifdef CONFIG_TRACEvoiddpm_ltt_trace_init(){ int k; for (k = 0; k < DPM_STATES; k++) { TRACE_DEFINE_NAME(TRACE_EV_DEFINE_NAME_DPM_STATE, k, 0, dpm_state_names[k]); }}#endif#ifdef MODULEmodule_init(dpm_init_module);module_exit(dpm_exit_module);#else__initcall(dpm_init_module);#endif/* * Local variables: * c-basic-offset: 8 * End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -