processor.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,497 行 · 第 1/5 页
C
2,497 行
step = (1000 / pr->throttling.state_count); for (i=0; i<pr->throttling.state_count; i++) { pr->throttling.states[i].performance = step * i; pr->throttling.states[i].power = step * i; } ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %d throttling states\n", pr->throttling.state_count)); pr->flags.throttling = 1; /* * Disable throttling (if enabled). We'll let subsequent policy (e.g. * thermal) decide to lower performance if it so chooses, but for now * we'll crank up the speed. */ result = acpi_processor_get_throttling(pr); if (result) goto end; if (pr->throttling.state) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Disabling throttling (was T%d)\n", pr->throttling.state)); result = acpi_processor_set_throttling(pr, 0); if (result) goto end; }end: if (result) pr->flags.throttling = 0; return_VALUE(result);}/* -------------------------------------------------------------------------- Limit Interface -------------------------------------------------------------------------- */static intacpi_processor_apply_limit ( struct acpi_processor* pr){ int result = 0; u16 px = 0; u16 tx = 0; ACPI_FUNCTION_TRACE("acpi_processor_apply_limit"); if (!pr) return_VALUE(-EINVAL); if (!pr->flags.limit) return_VALUE(-ENODEV); if (pr->flags.throttling) { if (pr->limit.user.tx > tx) tx = pr->limit.user.tx; if (pr->limit.thermal.tx > tx) tx = pr->limit.thermal.tx; result = acpi_processor_set_throttling(pr, tx); if (result) goto end; } pr->limit.state.px = px; pr->limit.state.tx = tx; ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Processor [%d] limit set to (P%d:T%d)\n", pr->id, pr->limit.state.px, pr->limit.state.tx));end: if (result) ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unable to set limit\n")); return_VALUE(result);}#ifdef CONFIG_CPU_FREQ/* If a passive cooling situation is detected, primarily CPUfreq is used, as it * offers (in most cases) voltage scaling in addition to frequency scaling, and * thus a cubic (instead of linear) reduction of energy. Also, we allow for * _any_ cpufreq driver and not only the acpi-cpufreq driver. */static unsigned int cpufreq_thermal_reduction_pctg[NR_CPUS];static unsigned int acpi_thermal_cpufreq_is_init = 0;static int cpu_has_cpufreq(unsigned int cpu){ struct cpufreq_policy policy; if (!acpi_thermal_cpufreq_is_init) return -ENODEV; if (!cpufreq_get_policy(&policy, cpu)) return -ENODEV; return 0;}static int acpi_thermal_cpufreq_increase(unsigned int cpu){ if (!cpu_has_cpufreq(cpu)) return -ENODEV; if (cpufreq_thermal_reduction_pctg[cpu] < 60) { cpufreq_thermal_reduction_pctg[cpu] += 20; cpufreq_update_policy(cpu); return 0; } return -ERANGE;}static int acpi_thermal_cpufreq_decrease(unsigned int cpu){ if (!cpu_has_cpufreq(cpu)) return -ENODEV; if (cpufreq_thermal_reduction_pctg[cpu] >= 20) { cpufreq_thermal_reduction_pctg[cpu] -= 20; cpufreq_update_policy(cpu); return 0; } return -ERANGE;}static int acpi_thermal_cpufreq_notifier( struct notifier_block *nb, unsigned long event, void *data){ struct cpufreq_policy *policy = data; unsigned long max_freq = 0; if (event != CPUFREQ_ADJUST) goto out; max_freq = (policy->cpuinfo.max_freq * (100 - cpufreq_thermal_reduction_pctg[policy->cpu])) / 100; cpufreq_verify_within_limits(policy, 0, max_freq); out: return 0;}static struct notifier_block acpi_thermal_cpufreq_notifier_block = { .notifier_call = acpi_thermal_cpufreq_notifier,};static void acpi_thermal_cpufreq_init(void) { int i; for (i=0; i<NR_CPUS; i++) cpufreq_thermal_reduction_pctg[i] = 0; i = cpufreq_register_notifier(&acpi_thermal_cpufreq_notifier_block, CPUFREQ_POLICY_NOTIFIER); if (!i) acpi_thermal_cpufreq_is_init = 1;}static void acpi_thermal_cpufreq_exit(void) { if (acpi_thermal_cpufreq_is_init) cpufreq_unregister_notifier(&acpi_thermal_cpufreq_notifier_block, CPUFREQ_POLICY_NOTIFIER); acpi_thermal_cpufreq_is_init = 0;}#else /* ! CONFIG_CPU_FREQ */static void acpi_thermal_cpufreq_init(void) { return; }static void acpi_thermal_cpufreq_exit(void) { return; }static int acpi_thermal_cpufreq_increase(unsigned int cpu) { return -ENODEV; }static int acpi_thermal_cpufreq_decrease(unsigned int cpu) { return -ENODEV; }#endifintacpi_processor_set_thermal_limit ( acpi_handle handle, int type){ int result = 0; struct acpi_processor *pr = NULL; struct acpi_device *device = NULL; int tx = 0; ACPI_FUNCTION_TRACE("acpi_processor_set_thermal_limit"); if ((type < ACPI_PROCESSOR_LIMIT_NONE) || (type > ACPI_PROCESSOR_LIMIT_DECREMENT)) return_VALUE(-EINVAL); result = acpi_bus_get_device(handle, &device); if (result) return_VALUE(result); pr = (struct acpi_processor *) acpi_driver_data(device); if (!pr) return_VALUE(-ENODEV); /* Thermal limits are always relative to the current Px/Tx state. */ if (pr->flags.throttling) pr->limit.thermal.tx = pr->throttling.state; /* * Our default policy is to only use throttling at the lowest * performance state. */ tx = pr->limit.thermal.tx; switch (type) { case ACPI_PROCESSOR_LIMIT_NONE: do { result = acpi_thermal_cpufreq_decrease(pr->id); } while (!result); tx = 0; break; case ACPI_PROCESSOR_LIMIT_INCREMENT: /* if going up: P-states first, T-states later */ result = acpi_thermal_cpufreq_increase(pr->id); if (!result) goto end; else if (result == -ERANGE) ACPI_DEBUG_PRINT((ACPI_DB_INFO, "At maximum performance state\n")); if (pr->flags.throttling) { if (tx == (pr->throttling.state_count - 1)) ACPI_DEBUG_PRINT((ACPI_DB_INFO, "At maximum throttling state\n")); else tx++; } break; case ACPI_PROCESSOR_LIMIT_DECREMENT: /* if going down: T-states first, P-states later */ if (pr->flags.throttling) { if (tx == 0) ACPI_DEBUG_PRINT((ACPI_DB_INFO, "At minimum throttling state\n")); else { tx--; goto end; } } result = acpi_thermal_cpufreq_decrease(pr->id); if (result == -ERANGE) ACPI_DEBUG_PRINT((ACPI_DB_INFO, "At minimum performance state\n")); break; }end: if (pr->flags.throttling) { pr->limit.thermal.px = 0; pr->limit.thermal.tx = tx; result = acpi_processor_apply_limit(pr); if (result) ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unable to set thermal limit\n")); ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Thermal limit now (P%d:T%d)\n", pr->limit.thermal.px, pr->limit.thermal.tx)); } else result = 0; return_VALUE(result);}static intacpi_processor_get_limit_info ( struct acpi_processor *pr){ ACPI_FUNCTION_TRACE("acpi_processor_get_limit_info"); if (!pr) return_VALUE(-EINVAL); if (pr->flags.throttling) pr->flags.limit = 1; return_VALUE(0);}/* -------------------------------------------------------------------------- FS Interface (/proc) -------------------------------------------------------------------------- */struct proc_dir_entry *acpi_processor_dir = NULL;static int acpi_processor_info_seq_show(struct seq_file *seq, void *offset){ struct acpi_processor *pr = (struct acpi_processor *)seq->private; ACPI_FUNCTION_TRACE("acpi_processor_info_seq_show"); if (!pr) goto end; seq_printf(seq, "processor id: %d\n" "acpi id: %d\n" "bus mastering control: %s\n" "power management: %s\n" "throttling control: %s\n" "limit interface: %s\n", pr->id, pr->acpi_id, pr->flags.bm_control ? "yes" : "no", pr->flags.power ? "yes" : "no", pr->flags.throttling ? "yes" : "no", pr->flags.limit ? "yes" : "no");end: return 0;}static int acpi_processor_info_open_fs(struct inode *inode, struct file *file){ return single_open(file, acpi_processor_info_seq_show, PDE(inode)->data);}static int acpi_processor_power_seq_show(struct seq_file *seq, void *offset){ struct acpi_processor *pr = (struct acpi_processor *)seq->private; int i = 0; ACPI_FUNCTION_TRACE("acpi_processor_power_seq_show"); if (!pr) goto end; seq_printf(seq, "active state: C%d\n" "default state: C%d\n" "bus master activity: %08x\n", pr->power.state, pr->power.default_state, pr->power.bm_activity); seq_puts(seq, "states:\n"); for (i = 1; i < ACPI_C_STATE_COUNT; i++) { seq_printf(seq, " %cC%d: ", (i == pr->power.state?'*':' '), i); if (!pr->power.states[i].valid) { seq_puts(seq, "<not supported>\n"); continue; } if (pr->power.states[i].promotion.state) seq_printf(seq, "promotion[C%d] ", pr->power.states[i].promotion.state); else seq_puts(seq, "promotion[--] "); if (pr->power.states[i].demotion.state) seq_printf(seq, "demotion[C%d] ", pr->power.states[i].demotion.state); else seq_puts(seq, "demotion[--] "); seq_printf(seq, "latency[%03d] usage[%08d]\n", pr->power.states[i].latency, pr->power.states[i].usage); }end: return 0;}static int acpi_processor_power_open_fs(struct inode *inode, struct file *file){ return single_open(file, acpi_processor_power_seq_show, PDE(inode)->data);}static int acpi_processor_throttling_seq_show(struct seq_file *seq, void *offset){ struct acpi_processor *pr = (struct acpi_processor *)seq->private; int i = 0; int result = 0; ACPI_FUNCTION_TRACE("acpi_processor_throttling_seq_show"); if (!pr) goto end; if (!(pr->throttling.state_count > 0)) { seq_puts(seq, "<not supported>\n"); goto end; } result = acpi_processor_get_throttling(pr); if (result) { seq_puts(seq, "Could not determine current throttling state.\n"); goto end; } seq_printf(seq, "state count: %d\n" "active state: T%d\n", pr->throttling.state_count, pr->throttling.state); seq_puts(seq, "states:\n"); for (i = 0; i < pr->throttling.state_count; i++) seq_printf(seq, " %cT%d: %02d%%\n", (i == pr->throttling.state?'*':' '), i, (pr->throttling.states[i].performance?pr->throttling.states[i].performance/10:0));end: return 0;}static int acpi_processor_throttling_open_fs(struct inode *inode, struct file *file){ return single_open(file, acpi_processor_throttling_seq_show, PDE(inode)->data);}static ssize_tacpi_processor_write_throttling ( struct file *file, const char __user *buffer, size_t count, loff_t *data){ int result = 0; struct seq_file *m = (struct seq_file *)file->private_data; struct acpi_processor *pr = (struct acpi_processor *)m->private; char state_string[12] = {'\0'}; ACPI_FUNCTION_TRACE("acpi_processor_write_throttling"); if (!pr || (count > sizeof(state_string) - 1)) return_VALUE(-EINVAL); if (copy_from_user(state_string, buffer, count)) return_VALUE(-EFAULT); state_string[count] = '\0'; result = acpi_processor_set_throttling(pr, simple_strtoul(state_string, NULL, 0)); if (result) return_VALUE(result); return_VALUE(count);}static int acpi_processor_limit_seq_show(struct seq_file *seq, void *offset){ struct acpi_processor *pr = (struct acpi_processor *)seq->private; ACPI_FUNCTION_TRACE("acpi_processor_limit_seq_show"); if (!pr) goto end; if (!pr->flags.limit) { seq_puts(seq, "<not supported>\n"); goto end; } seq_printf(seq, "active limit: P%d:T%d\n" "user limit: P%d:T%d\n" "thermal limit: P%d:T%d\n", pr->limit.state.px, pr->limit.state.tx, pr->limit.user.px, pr->limit.user.tx, pr->limit.thermal.px, pr->limit.thermal.tx);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?