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 + -
显示快捷键?