ia64/xen-unstable

changeset 18581:a311996570f4

[IA64] Add cpufreq ia64 driver

For IA64 Platform, add cpufreq driver for ia64 cpu, implementing
cpufreq_driver->init()/ exit()/ verify()/ target()/ get()

Signed-off-by: Yu, Ke <ke.yu@intel.com>
Signed-off-by: Liu, Jinsong <jinsong.liu@intel.com>
author Isaku Yamahata <yamahata@valinux.co.jp>
date Fri Oct 10 11:17:24 2008 +0900 (2008-10-10)
parents e02974a95872
children 903a901ab372
files xen/arch/ia64/xen/cpufreq/cpufreq.c
line diff
     1.1 --- a/xen/arch/ia64/xen/cpufreq/cpufreq.c	Fri Oct 03 12:50:28 2008 +0900
     1.2 +++ b/xen/arch/ia64/xen/cpufreq/cpufreq.c	Fri Oct 10 11:17:24 2008 +0900
     1.3 @@ -1,8 +1,311 @@
     1.4 +/*
     1.5 + * arch/ia64/kernel/cpufreq/acpi-cpufreq.c
     1.6 + * This file provides the ACPI based P-state support. This
     1.7 + * module works with generic cpufreq infrastructure. Most of
     1.8 + * the code is based on i386 version
     1.9 + * (arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c)
    1.10 + *
    1.11 + * Copyright (C) 2005 Intel Corp
    1.12 + *      Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
    1.13 + *
    1.14 + * Sep 2008 - Liu Jinsong <jinsong.liu@intel.com>
    1.15 + *      porting IPF acpi-cpufreq.c from Linux 2.6.23 to Xen hypervisor
    1.16 + */
    1.17  
    1.18 +#include <xen/types.h>
    1.19  #include <xen/errno.h>
    1.20 +#include <xen/delay.h>
    1.21 +#include <xen/cpumask.h>
    1.22 +#include <xen/sched.h>
    1.23 +#include <xen/timer.h>
    1.24 +#include <xen/xmalloc.h>
    1.25 +#include <asm/bug.h>
    1.26 +#include <asm/io.h>
    1.27 +#include <asm/config.h>
    1.28 +#include <asm/processor.h>
    1.29 +#include <asm/percpu.h>
    1.30 +#include <asm/pal.h>
    1.31  #include <acpi/acpi.h>
    1.32 -#include <acpi/cpufreq/processor_perf.h>
    1.33 -#include <public/platform.h>
    1.34 +#include <acpi/cpufreq/cpufreq.h>
    1.35 +
    1.36 +static struct acpi_cpufreq_data *drv_data[NR_CPUS];
    1.37 +
    1.38 +static struct cpufreq_driver acpi_cpufreq_driver;
    1.39 +
    1.40 +static int
    1.41 +processor_get_pstate (u32 *value)
    1.42 +{
    1.43 +	u64 pstate_index = 0;
    1.44 +	s64 retval;
    1.45 +
    1.46 +	retval = ia64_pal_get_pstate(&pstate_index,
    1.47 +			PAL_GET_PSTATE_TYPE_INSTANT);
    1.48 +	*value = (u32) pstate_index;
    1.49 +
    1.50 +	if (retval)
    1.51 +		printk("Failed to get current freq\n");
    1.52 +
    1.53 +	return (int)retval;
    1.54 +}
    1.55 +
    1.56 +static unsigned int
    1.57 +extract_clock (unsigned value)
    1.58 +{
    1.59 +	unsigned long i;
    1.60 +	unsigned int cpu;
    1.61 +	struct processor_performance *perf;
    1.62 +
    1.63 +	cpu = smp_processor_id();
    1.64 +	perf = &processor_pminfo[cpu]->perf;
    1.65 +
    1.66 +	for (i = 0; i < perf->state_count; i++) {
    1.67 +		if (value == perf->states[i].status)
    1.68 +			return perf->states[i].core_frequency;
    1.69 +	}
    1.70 +	return perf->states[i-1].core_frequency;
    1.71 +}
    1.72 +
    1.73 +static void
    1.74 +processor_get_freq (void *data)
    1.75 +{
    1.76 +	unsigned int *freq = data;
    1.77 +	int ret = 0;
    1.78 +	u32 value = 0;
    1.79 +	unsigned int clock_freq;
    1.80 +
    1.81 +	ret = processor_get_pstate(&value);
    1.82 +	if (ret) {
    1.83 +		*freq = 0;
    1.84 +		return;
    1.85 +	}
    1.86 +
    1.87 +	clock_freq = extract_clock(value);
    1.88 +	*freq = (clock_freq*1000);
    1.89 +	return;
    1.90 +}
    1.91 +
    1.92 +static unsigned int
    1.93 +acpi_cpufreq_get (unsigned int cpu)
    1.94 +{
    1.95 +	unsigned int freq;
    1.96 +
    1.97 +	if (!cpu_online(cpu))
    1.98 +		return 0;
    1.99 +
   1.100 +	if (cpu == smp_processor_id())
   1.101 +		processor_get_freq((void*)&freq);
   1.102 +	else
   1.103 +		smp_call_function_single(cpu, processor_get_freq,
   1.104 +					 (void *)&freq, 0, 1);
   1.105 +
   1.106 +	return freq;
   1.107 +}
   1.108 +
   1.109 +static void
   1.110 +processor_set_pstate (void *data)
   1.111 +{
   1.112 +	u32 *value = data;
   1.113 +	s64 retval;
   1.114 +
   1.115 +	retval = ia64_pal_set_pstate((u64)*value);
   1.116 +
   1.117 +	if (retval)
   1.118 +		*value = 1;
   1.119 +	else
   1.120 +		*value = 0;
   1.121 +}
   1.122 +
   1.123 +static int
   1.124 +processor_set_freq (struct acpi_cpufreq_data *data,
   1.125 +		struct cpufreq_policy *policy, int state)
   1.126 +{
   1.127 +	u32 value = 0;
   1.128 +	unsigned int cpu = policy->cpu;
   1.129 +
   1.130 +	if (!cpu_online(cpu))
   1.131 +		return -ENODEV;
   1.132 +
   1.133 +	if (state == data->acpi_data->state) {
   1.134 +		if (unlikely(policy->resume)) {
   1.135 +			printk(KERN_INFO
   1.136 +			       "Called after resume, resetting to P%d\n",
   1.137 +			       state);
   1.138 +			policy->resume = 0;
   1.139 +		} else {
   1.140 +			printk(KERN_DEBUG"Already at target state (P%d)\n",
   1.141 +			       state);
   1.142 +			return 0;
   1.143 +		}
   1.144 +	}
   1.145 +
   1.146 +	value = (u32) data->acpi_data->states[state].control;
   1.147 +
   1.148 +	if (cpu == smp_processor_id())
   1.149 +		processor_set_pstate((void *)&value);
   1.150 +	else
   1.151 +		smp_call_function_single(cpu, processor_set_pstate,
   1.152 +				(void *)&value, 0, 1);
   1.153 +
   1.154 +	if (value) {
   1.155 +		printk(KERN_WARNING "Transition failed\n");
   1.156 +		return -ENODEV;
   1.157 +	}
   1.158 +
   1.159 +	cpufreq_statistic_update(cpu, data->acpi_data->state, state);
   1.160 +
   1.161 +	data->acpi_data->state = state;
   1.162 +
   1.163 +	return 0;
   1.164 +}
   1.165 +
   1.166 +static int
   1.167 +acpi_cpufreq_target (struct cpufreq_policy *policy,
   1.168 +		unsigned int target_freq, unsigned int relation)
   1.169 +{
   1.170 +	struct acpi_cpufreq_data *data = drv_data[policy->cpu];
   1.171 +	unsigned int next_state = 0;
   1.172 +	unsigned int result = 0;
   1.173 +
   1.174 +	result = cpufreq_frequency_table_target(policy,
   1.175 +			data->freq_table, target_freq, relation, &next_state);
   1.176 +	if (result)
   1.177 +		return (result);
   1.178 +
   1.179 +	result = processor_set_freq(data, policy, next_state);
   1.180 +
   1.181 +	return (result);
   1.182 +}
   1.183 +
   1.184 +static int
   1.185 +acpi_cpufreq_verify (struct cpufreq_policy *policy)
   1.186 +{
   1.187 +	struct acpi_cpufreq_data *data = drv_data[policy->cpu];
   1.188 +	struct processor_performance *perf =
   1.189 +		&processor_pminfo[policy->cpu]->perf;
   1.190 +
   1.191 +	if (!policy || !data)
   1.192 +		return -EINVAL;
   1.193 +
   1.194 +	cpufreq_verify_within_limits(policy, 0,
   1.195 +			perf->states[perf->platform_limit].core_frequency * 1000);
   1.196 +
   1.197 +	return cpufreq_frequency_table_verify(policy, data->freq_table);
   1.198 +}
   1.199 +
   1.200 +static int
   1.201 +acpi_cpufreq_cpu_init (struct cpufreq_policy *policy)
   1.202 +{
   1.203 +	unsigned int i;
   1.204 +	unsigned int cpu = policy->cpu;
   1.205 +	unsigned int result = 0;
   1.206 +	struct acpi_cpufreq_data *data;
   1.207 +
   1.208 +	data = xmalloc(struct acpi_cpufreq_data);
   1.209 +	if (!data)
   1.210 +		return -ENOMEM;
   1.211 +	memset(data, 0, sizeof(struct acpi_cpufreq_data));
   1.212 +
   1.213 +	drv_data[cpu] = data;
   1.214 +
   1.215 +	data->acpi_data = &processor_pminfo[cpu]->perf;
   1.216 +
   1.217 +	/* capability check */
   1.218 +	if (data->acpi_data->state_count <= 1) {
   1.219 +		printk(KERN_WARNING "P-States\n");
   1.220 +		result = -ENODEV;
   1.221 +		goto err_unreg;
   1.222 +	}
   1.223 +
   1.224 +	if ((data->acpi_data->control_register.space_id !=
   1.225 +				ACPI_ADR_SPACE_FIXED_HARDWARE) ||
   1.226 +			(data->acpi_data->status_register.space_id !=
   1.227 +			 ACPI_ADR_SPACE_FIXED_HARDWARE)) {
   1.228 +		result = -ENODEV;
   1.229 +		goto err_unreg;
   1.230 +	}
   1.231 +
   1.232 +	data->freq_table = xmalloc_array(struct cpufreq_frequency_table,
   1.233 +			(data->acpi_data->state_count + 1));
   1.234 +	if (!data->freq_table) {
   1.235 +		result = -ENOMEM;
   1.236 +		goto err_unreg;
   1.237 +	}
   1.238 +
   1.239 +	/* detect transition latency */
   1.240 +	policy->cpuinfo.transition_latency = 0;
   1.241 +	for (i=0; i<data->acpi_data->state_count; i++) {
   1.242 +		if ((data->acpi_data->states[i].transition_latency * 1000) >
   1.243 +				policy->cpuinfo.transition_latency) {
   1.244 +			policy->cpuinfo.transition_latency =
   1.245 +				data->acpi_data->states[i].transition_latency * 1000;
   1.246 +		}
   1.247 +	}
   1.248 +	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
   1.249 +
   1.250 +	policy->cur = acpi_cpufreq_get(policy->cpu);
   1.251 +	printk(KERN_INFO "Current freq of CPU %u is %u\n", cpu, policy->cur);
   1.252 +
   1.253 +	/* table init */
   1.254 +	for (i = 0; i <= data->acpi_data->state_count; i++) {
   1.255 +		data->freq_table[i].index = i;
   1.256 +		if (i < data->acpi_data->state_count) {
   1.257 +			data->freq_table[i].frequency =
   1.258 +				data->acpi_data->states[i].core_frequency * 1000;
   1.259 +		} else {
   1.260 +			data->freq_table[i].frequency = CPUFREQ_TABLE_END;
   1.261 +		}
   1.262 +	}
   1.263 +
   1.264 +	result = cpufreq_frequency_table_cpuinfo(policy, data->freq_table);
   1.265 +	if (result)
   1.266 +		goto err_freqfree;
   1.267 +
   1.268 +	data->acpi_data->state = 0;
   1.269 +	policy->resume = 1;
   1.270 +
   1.271 +	return result;
   1.272 +
   1.273 +err_freqfree:
   1.274 +	xfree(data->freq_table);
   1.275 +err_unreg:
   1.276 +	xfree(data);
   1.277 +	drv_data[cpu] = NULL;
   1.278 +
   1.279 +	return result;
   1.280 +}
   1.281 +
   1.282 +static int
   1.283 +acpi_cpufreq_cpu_exit (struct cpufreq_policy *policy)
   1.284 +{
   1.285 +	struct acpi_cpufreq_data *data = drv_data[policy->cpu];
   1.286 +
   1.287 +	if (data) {
   1.288 +		drv_data[policy->cpu] = NULL;
   1.289 +		xfree(data->freq_table);
   1.290 +		xfree(data);
   1.291 +	}
   1.292 +
   1.293 +	return 0;
   1.294 +}
   1.295 +
   1.296 +static struct cpufreq_driver acpi_cpufreq_driver = {
   1.297 +	.verify     = acpi_cpufreq_verify,
   1.298 +	.target     = acpi_cpufreq_target,
   1.299 +	.get        = acpi_cpufreq_get,
   1.300 +	.init       = acpi_cpufreq_cpu_init,
   1.301 +	.exit       = acpi_cpufreq_cpu_exit,
   1.302 +};
   1.303 +
   1.304 +static int __init cpufreq_driver_init(void)
   1.305 +{
   1.306 +	int ret = 0;
   1.307 +
   1.308 +	if (cpufreq_controller == FREQCTL_xen)
   1.309 +		ret = cpufreq_register_driver(&acpi_cpufreq_driver);
   1.310 +
   1.311 +	return ret;
   1.312 +}
   1.313 +__initcall(cpufreq_driver_init);
   1.314  
   1.315  int get_cpu_id(u8 acpi_id)
   1.316  {