diff options
Diffstat (limited to 'drivers/acpi/processor_throttling.c')
| -rw-r--r-- | drivers/acpi/processor_throttling.c | 288 | 
1 files changed, 112 insertions, 176 deletions
diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c index ff3632717c5..84243c32e29 100644 --- a/drivers/acpi/processor_throttling.c +++ b/drivers/acpi/processor_throttling.c @@ -32,18 +32,11 @@  #include <linux/init.h>  #include <linux/sched.h>  #include <linux/cpufreq.h> -#ifdef CONFIG_ACPI_PROCFS -#include <linux/proc_fs.h> -#include <linux/seq_file.h> -#endif - +#include <linux/acpi.h> +#include <acpi/processor.h>  #include <asm/io.h>  #include <asm/uaccess.h> -#include <acpi/acpi_bus.h> -#include <acpi/acpi_drivers.h> -#include <acpi/processor.h> -  #define PREFIX "ACPI: "  #define ACPI_PROCESSOR_CLASS            "processor" @@ -63,6 +56,12 @@ struct throttling_tstate {  	int target_state;		/* target T-state */  }; +struct acpi_processor_throttling_arg { +	struct acpi_processor *pr; +	int target_state; +	bool force; +}; +  #define THROTTLING_PRECHANGE       (1)  #define THROTTLING_POSTCHANGE      (2) @@ -215,9 +214,10 @@ err_ret:   */  void acpi_processor_throttling_init(void)  { -	if (acpi_processor_update_tsd_coord()) +	if (acpi_processor_update_tsd_coord()) {  		ACPI_DEBUG_PRINT((ACPI_DB_INFO,  			"Assume no T-state coordination\n")); +	}  	return;  } @@ -370,6 +370,58 @@ int acpi_processor_tstate_has_changed(struct acpi_processor *pr)  }  /* + * This function is used to reevaluate whether the T-state is valid + * after one CPU is onlined/offlined. + * It is noted that it won't reevaluate the following properties for + * the T-state. + *	1. Control method. + *	2. the number of supported T-state + *	3. TSD domain + */ +void acpi_processor_reevaluate_tstate(struct acpi_processor *pr, +					unsigned long action) +{ +	int result = 0; + +	if (action == CPU_DEAD) { +		/* When one CPU is offline, the T-state throttling +		 * will be invalidated. +		 */ +		pr->flags.throttling = 0; +		return; +	} +	/* the following is to recheck whether the T-state is valid for +	 * the online CPU +	 */ +	if (!pr->throttling.state_count) { +		/* If the number of T-state is invalid, it is +		 * invalidated. +		 */ +		pr->flags.throttling = 0; +		return; +	} +	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) { +		result = acpi_processor_set_throttling(pr, 0, false); +		if (result) +			goto end; +	} + +end: +	if (result) +		pr->flags.throttling = 0; +} +/*   * _PTC - Processor Throttling Control (and status) register location   */  static int acpi_processor_get_throttling_control(struct acpi_processor *pr) @@ -662,20 +714,14 @@ static int acpi_processor_get_throttling_fadt(struct acpi_processor *pr)  }  #ifdef CONFIG_X86 -static int acpi_throttling_rdmsr(struct acpi_processor *pr, -					u64 *value) +static int acpi_throttling_rdmsr(u64 *value)  { -	struct cpuinfo_x86 *c;  	u64 msr_high, msr_low; -	unsigned int cpu;  	u64 msr = 0;  	int ret = -1; -	cpu = pr->id; -	c = &cpu_data(cpu); - -	if ((c->x86_vendor != X86_VENDOR_INTEL) || -		!cpu_has(c, X86_FEATURE_ACPI)) { +	if ((this_cpu_read(cpu_info.x86_vendor) != X86_VENDOR_INTEL) || +		!this_cpu_has(X86_FEATURE_ACPI)) {  		printk(KERN_ERR PREFIX  			"HARDWARE addr space,NOT supported yet\n");  	} else { @@ -690,18 +736,13 @@ static int acpi_throttling_rdmsr(struct acpi_processor *pr,  	return ret;  } -static int acpi_throttling_wrmsr(struct acpi_processor *pr, u64 value) +static int acpi_throttling_wrmsr(u64 value)  { -	struct cpuinfo_x86 *c; -	unsigned int cpu;  	int ret = -1;  	u64 msr; -	cpu = pr->id; -	c = &cpu_data(cpu); - -	if ((c->x86_vendor != X86_VENDOR_INTEL) || -		!cpu_has(c, X86_FEATURE_ACPI)) { +	if ((this_cpu_read(cpu_info.x86_vendor) != X86_VENDOR_INTEL) || +		!this_cpu_has(X86_FEATURE_ACPI)) {  		printk(KERN_ERR PREFIX  			"HARDWARE addr space,NOT supported yet\n");  	} else { @@ -713,15 +754,14 @@ static int acpi_throttling_wrmsr(struct acpi_processor *pr, u64 value)  	return ret;  }  #else -static int acpi_throttling_rdmsr(struct acpi_processor *pr, -				u64 *value) +static int acpi_throttling_rdmsr(u64 *value)  {  	printk(KERN_ERR PREFIX  		"HARDWARE addr space,NOT supported yet\n");  	return -1;  } -static int acpi_throttling_wrmsr(struct acpi_processor *pr, u64 value) +static int acpi_throttling_wrmsr(u64 value)  {  	printk(KERN_ERR PREFIX  		"HARDWARE addr space,NOT supported yet\n"); @@ -733,7 +773,7 @@ static int acpi_read_throttling_status(struct acpi_processor *pr,  					u64 *value)  {  	u32 bit_width, bit_offset; -	u64 ptc_value; +	u32 ptc_value;  	u64 ptc_mask;  	struct acpi_processor_throttling *throttling;  	int ret = -1; @@ -741,19 +781,18 @@ static int acpi_read_throttling_status(struct acpi_processor *pr,  	throttling = &pr->throttling;  	switch (throttling->status_register.space_id) {  	case ACPI_ADR_SPACE_SYSTEM_IO: -		ptc_value = 0;  		bit_width = throttling->status_register.bit_width;  		bit_offset = throttling->status_register.bit_offset;  		acpi_os_read_port((acpi_io_address) throttling->status_register. -				  address, (u32 *) &ptc_value, +				  address, &ptc_value,  				  (u32) (bit_width + bit_offset));  		ptc_mask = (1 << bit_width) - 1;  		*value = (u64) ((ptc_value >> bit_offset) & ptc_mask);  		ret = 0;  		break;  	case ACPI_ADR_SPACE_FIXED_HARDWARE: -		ret = acpi_throttling_rdmsr(pr, value); +		ret = acpi_throttling_rdmsr(value);  		break;  	default:  		printk(KERN_ERR PREFIX "Unknown addr space %d\n", @@ -786,7 +825,7 @@ static int acpi_write_throttling_state(struct acpi_processor *pr,  		ret = 0;  		break;  	case ACPI_ADR_SPACE_FIXED_HARDWARE: -		ret = acpi_throttling_wrmsr(pr, value); +		ret = acpi_throttling_wrmsr(value);  		break;  	default:  		printk(KERN_ERR PREFIX "Unknown addr space %d\n", @@ -876,7 +915,11 @@ static int acpi_processor_get_throttling(struct acpi_processor *pr)  	 */  	cpumask_copy(saved_mask, ¤t->cpus_allowed);  	/* FIXME: use work_on_cpu() */ -	set_cpus_allowed_ptr(current, cpumask_of(pr->id)); +	if (set_cpus_allowed_ptr(current, cpumask_of(pr->id))) { +		/* Can't migrate to the target pr->id CPU. Exit */ +		free_cpumask_var(saved_mask); +		return -ENODEV; +	}  	ret = pr->throttling.acpi_processor_get_throttling(pr);  	/* restore the previous state */  	set_cpus_allowed_ptr(current, saved_mask); @@ -1023,16 +1066,24 @@ static int acpi_processor_set_throttling_ptc(struct acpi_processor *pr,  	return 0;  } +static long acpi_processor_throttling_fn(void *data) +{ +	struct acpi_processor_throttling_arg *arg = data; +	struct acpi_processor *pr = arg->pr; + +	return pr->throttling.acpi_processor_set_throttling(pr, +			arg->target_state, arg->force); +} +  int acpi_processor_set_throttling(struct acpi_processor *pr,  						int state, bool force)  { -	cpumask_var_t saved_mask;  	int ret = 0;  	unsigned int i;  	struct acpi_processor *match_pr;  	struct acpi_processor_throttling *p_throttling; +	struct acpi_processor_throttling_arg arg;  	struct throttling_tstate t_state; -	cpumask_var_t online_throttling_cpus;  	if (!pr)  		return -EINVAL; @@ -1043,25 +1094,23 @@ int acpi_processor_set_throttling(struct acpi_processor *pr,  	if ((state < 0) || (state > (pr->throttling.state_count - 1)))  		return -EINVAL; -	if (!alloc_cpumask_var(&saved_mask, GFP_KERNEL)) -		return -ENOMEM; - -	if (!alloc_cpumask_var(&online_throttling_cpus, GFP_KERNEL)) { -		free_cpumask_var(saved_mask); -		return -ENOMEM; +	if (cpu_is_offline(pr->id)) { +		/* +		 * the cpu pointed by pr->id is offline. Unnecessary to change +		 * the throttling state any more. +		 */ +		return -ENODEV;  	} -	cpumask_copy(saved_mask, ¤t->cpus_allowed);  	t_state.target_state = state;  	p_throttling = &(pr->throttling); -	cpumask_and(online_throttling_cpus, cpu_online_mask, -		    p_throttling->shared_cpu_map); +  	/*  	 * The throttling notifier will be called for every  	 * affected cpu in order to get one proper T-state.  	 * The notifier event is THROTTLING_PRECHANGE.  	 */ -	for_each_cpu(i, online_throttling_cpus) { +	for_each_cpu_and(i, cpu_online_mask, p_throttling->shared_cpu_map) {  		t_state.cpu = i;  		acpi_processor_throttling_notifier(THROTTLING_PRECHANGE,  							&t_state); @@ -1073,17 +1122,18 @@ int acpi_processor_set_throttling(struct acpi_processor *pr,  	 * it can be called only for the cpu pointed by pr.  	 */  	if (p_throttling->shared_type == DOMAIN_COORD_TYPE_SW_ANY) { -		/* FIXME: use work_on_cpu() */ -		set_cpus_allowed_ptr(current, cpumask_of(pr->id)); -		ret = p_throttling->acpi_processor_set_throttling(pr, -						t_state.target_state, force); +		arg.pr = pr; +		arg.target_state = state; +		arg.force = force; +		ret = work_on_cpu(pr->id, acpi_processor_throttling_fn, &arg);  	} else {  		/*  		 * When the T-state coordination is SW_ALL or HW_ALL,  		 * it is necessary to set T-state for every affected  		 * cpus.  		 */ -		for_each_cpu(i, online_throttling_cpus) { +		for_each_cpu_and(i, cpu_online_mask, +		    p_throttling->shared_cpu_map) {  			match_pr = per_cpu(processors, i);  			/*  			 * If the pointer is invalid, we will report the @@ -1100,16 +1150,16 @@ int acpi_processor_set_throttling(struct acpi_processor *pr,  			 */  			if (!match_pr->flags.throttling) {  				ACPI_DEBUG_PRINT((ACPI_DB_INFO, -					"Throttling Controll is unsupported " +					"Throttling Control is unsupported "  					"on CPU %d\n", i));  				continue;  			} -			t_state.cpu = i; -			/* FIXME: use work_on_cpu() */ -			set_cpus_allowed_ptr(current, cpumask_of(i)); -			ret = match_pr->throttling. -				acpi_processor_set_throttling( -				match_pr, t_state.target_state, force); + +			arg.pr = match_pr; +			arg.target_state = state; +			arg.force = force; +			ret = work_on_cpu(pr->id, acpi_processor_throttling_fn, +				&arg);  		}  	}  	/* @@ -1118,16 +1168,12 @@ int acpi_processor_set_throttling(struct acpi_processor *pr,  	 * affected cpu to update the T-states.  	 * The notifier event is THROTTLING_POSTCHANGE  	 */ -	for_each_cpu(i, online_throttling_cpus) { +	for_each_cpu_and(i, cpu_online_mask, p_throttling->shared_cpu_map) {  		t_state.cpu = i;  		acpi_processor_throttling_notifier(THROTTLING_POSTCHANGE,  							&t_state);  	} -	/* restore the previous state */ -	/* FIXME: use work_on_cpu() */ -	set_cpus_allowed_ptr(current, saved_mask); -	free_cpumask_var(online_throttling_cpus); -	free_cpumask_var(saved_mask); +  	return ret;  } @@ -1216,113 +1262,3 @@ int acpi_processor_get_throttling_info(struct acpi_processor *pr)  	return result;  } -#ifdef CONFIG_ACPI_PROCFS -/* proc interface */ -static int acpi_processor_throttling_seq_show(struct seq_file *seq, -					      void *offset) -{ -	struct acpi_processor *pr = seq->private; -	int i = 0; -	int result = 0; - -	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" -		   "state available: T%d to T%d\n", -		   pr->throttling.state_count, pr->throttling.state, -		   pr->throttling_platform_limit, -		   pr->throttling.state_count - 1); - -	seq_puts(seq, "states:\n"); -	if (pr->throttling.acpi_processor_get_throttling == -			acpi_processor_get_throttling_fadt) { -		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)); -	} else { -		for (i = 0; i < pr->throttling.state_count; i++) -			seq_printf(seq, "   %cT%d:                  %02d%%\n", -				   (i == pr->throttling.state ? '*' : ' '), i, -				   (int)pr->throttling.states_tss[i]. -				   freqpercentage); -	} - -      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_t acpi_processor_write_throttling(struct file *file, -					       const char __user * buffer, -					       size_t count, loff_t * data) -{ -	int result = 0; -	struct seq_file *m = file->private_data; -	struct acpi_processor *pr = m->private; -	char state_string[5] = ""; -	char *charp = NULL; -	size_t state_val = 0; -	char tmpbuf[5] = ""; - -	if (!pr || (count > sizeof(state_string) - 1)) -		return -EINVAL; - -	if (copy_from_user(state_string, buffer, count)) -		return -EFAULT; - -	state_string[count] = '\0'; -	if ((count > 0) && (state_string[count-1] == '\n')) -		state_string[count-1] = '\0'; - -	charp = state_string; -	if ((state_string[0] == 't') || (state_string[0] == 'T')) -		charp++; - -	state_val = simple_strtoul(charp, NULL, 0); -	if (state_val >= pr->throttling.state_count) -		return -EINVAL; - -	snprintf(tmpbuf, 5, "%zu", state_val); - -	if (strcmp(tmpbuf, charp) != 0) -		return -EINVAL; - -	result = acpi_processor_set_throttling(pr, state_val, false); -	if (result) -		return result; - -	return count; -} - -const struct file_operations acpi_processor_throttling_fops = { -	.owner = THIS_MODULE, -	.open = acpi_processor_throttling_open_fs, -	.read = seq_read, -	.write = acpi_processor_write_throttling, -	.llseek = seq_lseek, -	.release = single_release, -}; -#endif  | 
