ia64/linux-2.6.18-xen.hg

changeset 548:12bcbf80b8e4

xen: Basic framework of getting and notifying Px info

Setup basic framework for ACPI Px parse, get basic Px info,
transfer Px info to hypervisor through platform op hypercall.
Add external control for ACPI parse, add notify mechanism for
dynamic Px event (like ppc).

Signed-off-by: Tian Kevin <kevin.tian@intel.com>
Signed-off-by: Liu Jinsong <jinsong.liu@intel.com>
author Keir Fraser <keir.fraser@citrix.com>
date Wed May 14 13:51:50 2008 +0100 (2008-05-14)
parents e25f25110882
children d59a4aaf8615
files arch/i386/kernel/acpi/processor_extcntl_xen.c drivers/acpi/processor_extcntl.c drivers/acpi/processor_perflib.c include/acpi/processor.h include/xen/interface/platform.h
line diff
     1.1 --- a/arch/i386/kernel/acpi/processor_extcntl_xen.c	Wed May 14 09:32:31 2008 +0100
     1.2 +++ b/arch/i386/kernel/acpi/processor_extcntl_xen.c	Wed May 14 13:51:50 2008 +0100
     1.3 @@ -28,6 +28,7 @@
     1.4  #include <linux/pm.h>
     1.5  #include <linux/cpu.h>
     1.6  
     1.7 +#include <linux/cpufreq.h>
     1.8  #include <acpi/processor.h>
     1.9  #include <asm/hypercall.h>
    1.10  
    1.11 @@ -110,9 +111,101 @@ static int xen_cx_notifier(struct acpi_p
    1.12  	return ret;
    1.13  }
    1.14  
    1.15 +static void convert_pct_reg(struct xen_pct_register *xpct,
    1.16 +	struct acpi_pct_register *apct)
    1.17 +{
    1.18 +	xpct->descriptor = apct->descriptor;
    1.19 +	xpct->length     = apct->length;
    1.20 +	xpct->space_id   = apct->space_id;
    1.21 +	xpct->bit_width  = apct->bit_width;
    1.22 +	xpct->bit_offset = apct->bit_offset;
    1.23 +	xpct->reserved   = apct->reserved;
    1.24 +	xpct->address    = apct->address;
    1.25 +}
    1.26 +
    1.27 +static void convert_pss_states(struct xen_processor_px *xpss, 
    1.28 +	struct acpi_processor_px *apss, int state_count)
    1.29 +{
    1.30 +	int i;
    1.31 +	for(i=0; i<state_count; i++) {
    1.32 +		xpss->core_frequency     = apss->core_frequency;
    1.33 +		xpss->power              = apss->power;
    1.34 +		xpss->transition_latency = apss->transition_latency;
    1.35 +		xpss->bus_master_latency = apss->bus_master_latency;
    1.36 +		xpss->control            = apss->control;
    1.37 +		xpss->status             = apss->status;
    1.38 +		xpss++;
    1.39 +		apss++;
    1.40 +	}
    1.41 +}
    1.42 +
    1.43 +static void convert_psd_pack(struct xen_psd_package *xpsd,
    1.44 +	struct acpi_psd_package *apsd)
    1.45 +{
    1.46 +	xpsd->num_entries    = apsd->num_entries;
    1.47 +	xpsd->revision       = apsd->revision;
    1.48 +	xpsd->domain         = apsd->domain;
    1.49 +	xpsd->coord_type     = apsd->coord_type;
    1.50 +	xpsd->num_processors = apsd->num_processors;
    1.51 +}
    1.52 +
    1.53  static int xen_px_notifier(struct acpi_processor *pr, int action)
    1.54  {
    1.55 -	return -EINVAL;
    1.56 +	int ret;
    1.57 +	xen_platform_op_t op = {
    1.58 +		.cmd			= XENPF_set_processor_pminfo,
    1.59 +		.interface_version	= XENPF_INTERFACE_VERSION,
    1.60 +		.u.set_pminfo.id	= pr->acpi_id,
    1.61 +		.u.set_pminfo.type	= XEN_PM_PX,
    1.62 +	};
    1.63 +	struct xen_processor_performance *perf;
    1.64 +	struct xen_processor_px *states = NULL;
    1.65 +	struct acpi_processor_performance *px;
    1.66 +	struct acpi_psd_package *pdomain;
    1.67 +
    1.68 +	/* leave dynamic ppc handle in the future */
    1.69 +	if (action == PROCESSOR_PM_CHANGE)
    1.70 +		return 0;
    1.71 +
    1.72 +	perf = &op.u.set_pminfo.perf;
    1.73 +	px = pr->performance;
    1.74 +
    1.75 +	perf->flags = XEN_PX_PPC | 
    1.76 +		      XEN_PX_PCT | 
    1.77 +		      XEN_PX_PSS | 
    1.78 +		      XEN_PX_PSD;
    1.79 +
    1.80 +	/* ppc */
    1.81 +	perf->ppc = pr->performance_platform_limit;
    1.82 +
    1.83 +	/* pct */
    1.84 +	convert_pct_reg(&perf->control_register, &px->control_register);
    1.85 +	convert_pct_reg(&perf->status_register, &px->status_register);
    1.86 +
    1.87 +	/* pss */
    1.88 +	perf->state_count = px->state_count;
    1.89 +	states = kzalloc(px->state_count*sizeof(xen_processor_px_t),GFP_KERNEL);
    1.90 +	if (!states)
    1.91 +		return -ENOMEM;
    1.92 +	convert_pss_states(states, px->states, px->state_count);
    1.93 +	set_xen_guest_handle(perf->states, states);
    1.94 +
    1.95 +	/* psd */
    1.96 +	pdomain = &px->domain_info;
    1.97 +	convert_psd_pack(&perf->domain_info, pdomain);
    1.98 +	if (perf->domain_info.num_processors) {
    1.99 +		if (pdomain->coord_type == DOMAIN_COORD_TYPE_SW_ALL)
   1.100 +			perf->shared_type = CPUFREQ_SHARED_TYPE_ALL;
   1.101 +		else if (pdomain->coord_type == DOMAIN_COORD_TYPE_SW_ANY)
   1.102 +			perf->shared_type = CPUFREQ_SHARED_TYPE_ANY;
   1.103 +		else if (pdomain->coord_type == DOMAIN_COORD_TYPE_HW_ALL)
   1.104 +			perf->shared_type = CPUFREQ_SHARED_TYPE_HW;
   1.105 +	} else
   1.106 +		perf->shared_type = CPUFREQ_SHARED_TYPE_NONE;
   1.107 +
   1.108 +	ret = HYPERVISOR_platform_op(&op);
   1.109 +	kfree(states);
   1.110 +	return ret;
   1.111  }
   1.112  
   1.113  static int xen_tx_notifier(struct acpi_processor *pr, int action)
     2.1 --- a/drivers/acpi/processor_extcntl.c	Wed May 14 09:32:31 2008 +0100
     2.2 +++ b/drivers/acpi/processor_extcntl.c	Wed May 14 13:51:50 2008 +0100
     2.3 @@ -31,12 +31,50 @@
     2.4  #include <acpi/processor.h>
     2.5  
     2.6  static int processor_extcntl_parse_csd(struct acpi_processor *pr);
     2.7 +static int processor_extcntl_get_performance(struct acpi_processor *pr);
     2.8  /*
     2.9   * External processor control logic may register with its own set of
    2.10   * ops to get ACPI related notification. One example is like VMM.
    2.11   */
    2.12  struct processor_extcntl_ops *processor_extcntl_ops;
    2.13  
    2.14 +static int processor_notify_smm(void)
    2.15 +{
    2.16 +	acpi_status status;
    2.17 +	static int is_done = 0;
    2.18 +
    2.19 +	/* only need successfully notify BIOS once */
    2.20 +	/* avoid double notification which may lead to unexpected result */
    2.21 +	if (is_done)
    2.22 +		return 0;
    2.23 +
    2.24 +	/* Can't write pstate_cnt to smi_cmd if either value is zero */
    2.25 +	if ((!acpi_fadt.smi_cmd) || (!acpi_fadt.pstate_cnt)) {
    2.26 +		ACPI_DEBUG_PRINT((ACPI_DB_INFO,"No SMI port or pstate_cnt\n"));
    2.27 +		return 0;
    2.28 +	}
    2.29 +
    2.30 +	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
    2.31 +		"Writing pstate_cnt [0x%x] to smi_cmd [0x%x]\n",
    2.32 +		acpi_fadt.pstate_cnt, acpi_fadt.smi_cmd));
    2.33 +
    2.34 +	/* FADT v1 doesn't support pstate_cnt, many BIOS vendors use
    2.35 +	 * it anyway, so we need to support it... */
    2.36 +	if (acpi_fadt_is_v1) {
    2.37 +		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
    2.38 +			"Using v1.0 FADT reserved value for pstate_cnt\n"));
    2.39 +	}
    2.40 +
    2.41 +	status = acpi_os_write_port(acpi_fadt.smi_cmd,
    2.42 +				    (u32) acpi_fadt.pstate_cnt, 8);
    2.43 +	if (ACPI_FAILURE(status)) 
    2.44 +		return status;
    2.45 +
    2.46 +	is_done = 1;
    2.47 +
    2.48 +	return 0;
    2.49 +}
    2.50 +
    2.51  int processor_notify_external(struct acpi_processor *pr, int event, int type)
    2.52  {
    2.53  	int ret = -EINVAL;
    2.54 @@ -109,7 +147,12 @@ int processor_unregister_extcntl(struct 
    2.55  int processor_extcntl_init(struct acpi_processor *pr)
    2.56  {
    2.57  	/* parse cstate dependency information */
    2.58 -	processor_extcntl_parse_csd(pr);
    2.59 +	if (processor_pm_external())
    2.60 +		processor_extcntl_parse_csd(pr);
    2.61 +
    2.62 +	/* Initialize performance states */
    2.63 +	if (processor_pmperf_external())
    2.64 +		processor_extcntl_get_performance(pr);
    2.65  
    2.66  	return 0;
    2.67  }
    2.68 @@ -135,3 +178,71 @@ static int processor_extcntl_parse_csd(s
    2.69  
    2.70  	return 0;
    2.71  }
    2.72 +
    2.73 +/*
    2.74 + * Existing ACPI module does parse performance states at some point,
    2.75 + * when acpi-cpufreq driver is loaded which however is something
    2.76 + * we'd like to disable to avoid confliction with external control
    2.77 + * logic. So we have to collect raw performance information here 
    2.78 + * when ACPI processor object is found and started.
    2.79 + */
    2.80 +#ifdef CONFIG_CPU_FREQ
    2.81 +static int processor_extcntl_get_performance(struct acpi_processor *pr)
    2.82 +{
    2.83 +	int ret;
    2.84 +	struct acpi_processor_performance *perf;
    2.85 +	struct acpi_psd_package *pdomain;
    2.86 +
    2.87 +	if (pr->performance)
    2.88 +		return -EBUSY;
    2.89 +
    2.90 +	perf = kzalloc(sizeof(struct acpi_processor_performance), GFP_KERNEL);
    2.91 +	if (!perf)
    2.92 +		return -ENOMEM;
    2.93 +
    2.94 +	pr->performance = perf;
    2.95 +	/* Get basic performance state information */
    2.96 +	ret = acpi_processor_get_performance_info(pr);
    2.97 +	if (ret < 0)
    2.98 +		goto err_out;
    2.99 +
   2.100 +	/*
   2.101 +	 * Well, here we need retrieve performance dependency information
   2.102 +	 * from _PSD object. The reason why existing interface is not used
   2.103 +	 * is due to the reason that existing interface sticks to Linux cpu
   2.104 +	 * id to construct some bitmap, however we want to split ACPI 
   2.105 +	 * processor objects from Linux cpu id logic. For example, even
   2.106 +	 * when Linux is configured as UP, we still want to parse all ACPI
   2.107 +	 * processor objects to external logic. In this case, it's preferred
   2.108 +	 * to use ACPI ID instead.
   2.109 +	 */
   2.110 +	pr->performance->domain_info.num_processors = 0;
   2.111 +	ret = acpi_processor_get_psd(pr);
   2.112 +	if (ret < 0)
   2.113 +		goto err_out;
   2.114 +
   2.115 +	/* Some sanity check */
   2.116 +	pdomain = &pr->performance->domain_info;
   2.117 +	if ((pdomain->revision != ACPI_PSD_REV0_REVISION) ||
   2.118 +	    (pdomain->num_entries != ACPI_PSD_REV0_ENTRIES) ||
   2.119 +	    ((pdomain->coord_type != DOMAIN_COORD_TYPE_SW_ALL) &&
   2.120 +	     (pdomain->coord_type != DOMAIN_COORD_TYPE_SW_ANY) &&
   2.121 +	     (pdomain->coord_type != DOMAIN_COORD_TYPE_HW_ALL))) {
   2.122 +		ret = -EINVAL;
   2.123 +		goto err_out;
   2.124 +	}
   2.125 +
   2.126 +	/* Last step is to notify BIOS that external logic exists */
   2.127 +	processor_notify_smm();
   2.128 +
   2.129 +	processor_notify_external(pr, PROCESSOR_PM_INIT, PM_TYPE_PERF);
   2.130 +
   2.131 +	return 0;
   2.132 +err_out:
   2.133 +	pr->performance = NULL;
   2.134 +	kfree(perf);
   2.135 +	return ret;
   2.136 +}
   2.137 +#else
   2.138 +static int processor_extcntl_get_performance(struct acpi_processor *pr) { return 0; }
   2.139 +#endif
     3.1 --- a/drivers/acpi/processor_perflib.c	Wed May 14 09:32:31 2008 +0100
     3.2 +++ b/drivers/acpi/processor_perflib.c	Wed May 14 13:51:50 2008 +0100
     3.3 @@ -304,7 +304,11 @@ static int acpi_processor_get_performanc
     3.4  	return result;
     3.5  }
     3.6  
     3.7 +#ifndef CONFIG_PROCESSOR_EXTERNAL_CONTROL
     3.8  static int acpi_processor_get_performance_info(struct acpi_processor *pr)
     3.9 +#else
    3.10 +int acpi_processor_get_performance_info(struct acpi_processor *pr)
    3.11 +#endif
    3.12  {
    3.13  	int result = 0;
    3.14  	acpi_status status = AE_OK;
    3.15 @@ -543,7 +547,11 @@ static void acpi_cpufreq_remove_file(str
    3.16  }
    3.17  #endif				/* CONFIG_X86_ACPI_CPUFREQ_PROC_INTF */
    3.18  
    3.19 +#ifndef CONFIG_PROCESSOR_EXTERNAL_CONTROL
    3.20  static int acpi_processor_get_psd(struct acpi_processor	*pr)
    3.21 +#else
    3.22 +int acpi_processor_get_psd(struct acpi_processor *pr)
    3.23 +#endif
    3.24  {
    3.25  	int result = 0;
    3.26  	acpi_status status = AE_OK;
     4.1 --- a/include/acpi/processor.h	Wed May 14 09:32:31 2008 +0100
     4.2 +++ b/include/acpi/processor.h	Wed May 14 13:51:50 2008 +0100
     4.3 @@ -353,6 +353,8 @@ extern int processor_notify_external(str
     4.4  extern int processor_register_extcntl(struct processor_extcntl_ops *ops);
     4.5  extern int processor_unregister_extcntl(struct processor_extcntl_ops *ops);
     4.6  extern int processor_extcntl_init(struct acpi_processor *pr);
     4.7 +extern int acpi_processor_get_performance_info(struct acpi_processor *pr);
     4.8 +extern int acpi_processor_get_psd(struct acpi_processor *pr);
     4.9  #else
    4.10  static inline int processor_cntl_external(void) {return 0;}
    4.11  static inline int processor_pm_external(void) {return 0;}
     5.1 --- a/include/xen/interface/platform.h	Wed May 14 09:32:31 2008 +0100
     5.2 +++ b/include/xen/interface/platform.h	Wed May 14 13:51:50 2008 +0100
     5.3 @@ -211,6 +211,12 @@ DEFINE_XEN_GUEST_HANDLE(xenpf_getidletim
     5.4  #define XEN_PM_PX   1
     5.5  #define XEN_PM_TX   2
     5.6  
     5.7 +/* Px sub info type */
     5.8 +#define XEN_PX_PCT   1
     5.9 +#define XEN_PX_PSS   2
    5.10 +#define XEN_PX_PPC   4
    5.11 +#define XEN_PX_PSD   8
    5.12 +
    5.13  struct xen_power_register {
    5.14      uint32_t     space_id;
    5.15      uint32_t     bit_width;
    5.16 @@ -252,12 +258,55 @@ struct xen_processor_power {
    5.17      XEN_GUEST_HANDLE(xen_processor_cx_t) states; /* supported c states */
    5.18  };
    5.19  
    5.20 +struct xen_pct_register {
    5.21 +    uint8_t  descriptor;
    5.22 +    uint16_t length;
    5.23 +    uint8_t  space_id;
    5.24 +    uint8_t  bit_width;
    5.25 +    uint8_t  bit_offset;
    5.26 +    uint8_t  reserved;
    5.27 +    uint64_t address;
    5.28 +};
    5.29 +
    5.30 +struct xen_processor_px {
    5.31 +    uint64_t core_frequency; /* megahertz */
    5.32 +    uint64_t power;      /* milliWatts */
    5.33 +    uint64_t transition_latency; /* microseconds */
    5.34 +    uint64_t bus_master_latency; /* microseconds */
    5.35 +    uint64_t control;        /* control value */
    5.36 +    uint64_t status;     /* success indicator */
    5.37 +};
    5.38 +typedef struct xen_processor_px xen_processor_px_t;
    5.39 +DEFINE_XEN_GUEST_HANDLE(xen_processor_px_t);
    5.40 +
    5.41 +struct xen_psd_package {
    5.42 +    uint64_t num_entries;
    5.43 +    uint64_t revision;
    5.44 +    uint64_t domain;
    5.45 +    uint64_t coord_type;
    5.46 +    uint64_t num_processors;
    5.47 +};
    5.48 +
    5.49 +struct xen_processor_performance {
    5.50 +    uint32_t flags;     /* flag for Px sub info type */
    5.51 +    uint32_t ppc;       /* Platform limitation on freq usage */
    5.52 +    struct xen_pct_register control_register;
    5.53 +    struct xen_pct_register status_register;
    5.54 +    uint32_t state_count;     /* total available performance states */
    5.55 +    XEN_GUEST_HANDLE(xen_processor_px_t) states;
    5.56 +    struct xen_psd_package domain_info;
    5.57 +    uint32_t shared_type;     /* coordination type of this processor */
    5.58 +};
    5.59 +typedef struct xen_processor_performance xen_processor_performance_t;
    5.60 +DEFINE_XEN_GUEST_HANDLE(xen_processor_performance_t);
    5.61 +
    5.62  struct xenpf_set_processor_pminfo {
    5.63      /* IN variables */
    5.64      uint32_t id;    /* ACPI CPU ID */
    5.65 -    uint32_t type;  /* {XEN_PM_CX, ...} */
    5.66 +    uint32_t type;  /* {XEN_PM_CX, XEN_PM_PX} */
    5.67      union {
    5.68          struct xen_processor_power          power;/* Cx: _CST/_CSD */
    5.69 +        struct xen_processor_performance    perf; /* Px: _PPC/_PCT/_PSS/_PSD */
    5.70      };
    5.71  };
    5.72  typedef struct xenpf_set_processor_pminfo xenpf_set_processor_pminfo_t;