[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH v11] xen/arm : emulation of arm's PSCI v0.2 standard
Arm based virtual machines dom0/guest will request power related functionality from xen through PSCI interface. This patch implements version 0.2 of PSCI standard specified by arm for 64bit and 32 bit arm machines. Signed-off-by: Parth Dixit <parth.dixit@xxxxxxxxxx> --- Changelog v11 - fixed arm32 bit compilation error for psci - corrected grammar in comments in psci_suspend - Removed coding details about individual function/macro from commit text Changelog v10 - added new comment in cpu_suspend to reflect - that current implementation performs standby Changelog v9 - removed context_id from cpu_suspend Changelog v8 - fixed error in cpu_suspend Changelog v7 - removed casting from functions in do_psci_trap - modified cpu_suspend to return success in case the call returns Changelog v6 - fixed indentation - removed casting from error codes - modified cpu_suspend to check power_state - ignoring context_id in case of standby - added comments for ignoring affinity - added macro for checking power_state Changelog v5 - removed PSCI_ARGS macro - preload error value for calls that do not return - added new macro for 32 bit arguments - casting return calls to appropriate types - added new function psci_mode_check - added error checks for PSCI v0.2 function id's Changelog v4 - added target_affinity_mask[] to local variable - removed AFF3 masking for 64 bit cpu - added do_common_cpu_on for PSCI v0.1 and v0.2 - moved cpu_on decision based on entry point - removed vpsci_ver introduced in v3 - removed psci tables - added new macro for selecting arguments - do_trap_psci is now switch case based instead of tables Changelog v3 - moved wfi helper to seperate patch - replaced new wfi function in traps.c - removed defining power_state variable using value directly - added new line between declaration - merged PSCI v0.1 and v0.2 cpu_on function to avoid duplication - removed spurious change - renamed PSCI return values to reflect v0.2 moved them to top - removed PSCI v0.1 version declaration for now, will introduce it when needed - removed hard tabs in the code lifted from linux - removed PSCI_0_1_MAX - did not retained copyright header from linux as most of functions are removed - added two function tables for PSCI v0.1 and PSCI v0.2 - added compatibility string to libxl_arm to expose new functionality - refactored affinity_info code - added table for masking function - removed definitions of unused PSCI v0.2 functions - removed function id's of unused PSCI v0.2 functions - renamed constant PSCI_0_2_TOS_MP ( multicore aware) as per spec tools/libxl/libxl_arm.c | 2 +- xen/arch/arm/domain_build.c | 5 +- xen/arch/arm/traps.c | 127 ++++++++++++++++++++++++++++----------- xen/arch/arm/vpsci.c | 130 ++++++++++++++++++++++++++++++++++++++-- xen/include/asm-arm/processor.h | 3 + xen/include/asm-arm/psci.h | 83 ++++++++++++++++++++++--- 6 files changed, 300 insertions(+), 50 deletions(-) diff --git a/tools/libxl/libxl_arm.c b/tools/libxl/libxl_arm.c index 4f0f0e2..e8bcd05 100644 --- a/tools/libxl/libxl_arm.c +++ b/tools/libxl/libxl_arm.c @@ -237,7 +237,7 @@ static int make_psci_node(libxl__gc *gc, void *fdt) res = fdt_begin_node(fdt, "psci"); if (res) return res; - res = fdt_property_compat(gc, fdt, 1, "arm,psci"); + res = fdt_property_compat(gc, fdt, 2, "arm,psci-0.2","arm,psci"); if (res) return res; res = fdt_property_string(fdt, "method", "hvc"); diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c index c424793..ebd4170 100644 --- a/xen/arch/arm/domain_build.c +++ b/xen/arch/arm/domain_build.c @@ -388,6 +388,9 @@ static int make_hypervisor_node(struct domain *d, static int make_psci_node(void *fdt, const struct dt_device_node *parent) { int res; + const char compat[] = + "arm,psci-0.2""\0" + "arm,psci"; DPRINT("Create PSCI node\n"); @@ -396,7 +399,7 @@ static int make_psci_node(void *fdt, const struct dt_device_node *parent) if ( res ) return res; - res = fdt_property_string(fdt, "compatible", "arm,psci"); + res = fdt_property(fdt, "compatible", compat, sizeof(compat)); if ( res ) return res; diff --git a/xen/arch/arm/traps.c b/xen/arch/arm/traps.c index 8102540..1b6c8b2 100644 --- a/xen/arch/arm/traps.c +++ b/xen/arch/arm/traps.c @@ -1030,24 +1030,6 @@ static arm_hypercall_t arm_hypercall_table[] = { HYPERCALL_ARM(vcpu_op, 3), }; -typedef int (*arm_psci_fn_t)(uint32_t, register_t); - -typedef struct { - arm_psci_fn_t fn; - int nr_args; -} arm_psci_t; - -#define PSCI(_name, _nr_args) \ - [ PSCI_ ## _name ] = { \ - .fn = (arm_psci_fn_t) &do_psci_ ## _name, \ - .nr_args = _nr_args, \ - } - -static arm_psci_t arm_psci_table[] = { - PSCI(cpu_off, 1), - PSCI(cpu_on, 2), -}; - #ifndef NDEBUG static void do_debug_trap(struct cpu_user_regs *regs, unsigned int code) { @@ -1080,33 +1062,108 @@ static void do_debug_trap(struct cpu_user_regs *regs, unsigned int code) #endif #ifdef CONFIG_ARM_64 -#define PSCI_OP_REG(r) (r)->x0 -#define PSCI_RESULT_REG(r) (r)->x0 -#define PSCI_ARGS(r) (r)->x1, (r)->x2 +#define PSCI_RESULT_REG(reg) (reg)->x0 +#define PSCI_ARG(reg,n) (reg)->x##n +#define PSCI_ARG32(reg,n) (uint32_t)( (reg)->x##n & 0x00000000FFFFFFFF ) #else -#define PSCI_OP_REG(r) (r)->r0 -#define PSCI_RESULT_REG(r) (r)->r0 -#define PSCI_ARGS(r) (r)->r1, (r)->r2 +#define PSCI_RESULT_REG(reg) (reg)->r0 +#define PSCI_ARG(reg,n) (reg)->r##n +#define PSCI_ARG32(reg,n) PSCI_ARG(reg,n) #endif -static void do_trap_psci(struct cpu_user_regs *regs) +/* helper function for checking arm mode 32/64 bit */ +static inline int psci_mode_check(struct domain *d, register_t fid) { - arm_psci_fn_t psci_call = NULL; + return !( is_64bit_domain(d)^( (fid & PSCI_0_2_64BIT) >> 30 ) ); +} - if ( PSCI_OP_REG(regs) >= ARRAY_SIZE(arm_psci_table) ) - { - domain_crash_synchronous(); - return; - } +static void do_trap_psci(struct cpu_user_regs *regs) +{ + register_t fid = PSCI_ARG(regs,0); - psci_call = arm_psci_table[PSCI_OP_REG(regs)].fn; - if ( psci_call == NULL ) + /* preloading in case psci_mode_check fails */ + PSCI_RESULT_REG(regs) = PSCI_INVALID_PARAMETERS; + switch( fid ) { + case PSCI_cpu_off: + { + uint32_t pstate = PSCI_ARG32(regs,1); + PSCI_RESULT_REG(regs) = do_psci_cpu_off(pstate); + } + break; + case PSCI_cpu_on: + { + uint32_t vcpuid = PSCI_ARG32(regs,1); + register_t epoint = PSCI_ARG(regs,2); + PSCI_RESULT_REG(regs) = do_psci_cpu_on(vcpuid, epoint); + } + break; + case PSCI_0_2_FN_PSCI_VERSION: + PSCI_RESULT_REG(regs) = do_psci_0_2_version(); + break; + case PSCI_0_2_FN_CPU_OFF: + PSCI_RESULT_REG(regs) = do_psci_0_2_cpu_off(); + break; + case PSCI_0_2_FN_MIGRATE_INFO_TYPE: + PSCI_RESULT_REG(regs) = do_psci_0_2_migrate_info_type(); + break; + case PSCI_0_2_FN_MIGRATE_INFO_UP_CPU: + case PSCI_0_2_FN64_MIGRATE_INFO_UP_CPU: + if ( psci_mode_check(current->domain, fid) ) + PSCI_RESULT_REG(regs) = do_psci_0_2_migrate_info_up_cpu(); + break; + case PSCI_0_2_FN_SYSTEM_OFF: + do_psci_0_2_system_off(); + PSCI_RESULT_REG(regs) = PSCI_INTERNAL_FAILURE; + break; + case PSCI_0_2_FN_SYSTEM_RESET: + do_psci_0_2_system_reset(); + PSCI_RESULT_REG(regs) = PSCI_INTERNAL_FAILURE; + break; + case PSCI_0_2_FN_CPU_ON: + case PSCI_0_2_FN64_CPU_ON: + if ( psci_mode_check(current->domain, fid) ) + { + register_t vcpuid = PSCI_ARG(regs,1); + register_t epoint = PSCI_ARG(regs,2); + register_t cid = PSCI_ARG(regs,3); + PSCI_RESULT_REG(regs) = + do_psci_0_2_cpu_on(vcpuid, epoint, cid); + } + break; + case PSCI_0_2_FN_CPU_SUSPEND: + case PSCI_0_2_FN64_CPU_SUSPEND: + if ( psci_mode_check(current->domain, fid) ) + { + uint32_t pstate = PSCI_ARG32(regs,1); + register_t epoint = PSCI_ARG(regs,2); + register_t cid = PSCI_ARG(regs,3); + PSCI_RESULT_REG(regs) = + do_psci_0_2_cpu_suspend(pstate, epoint, cid); + } + break; + case PSCI_0_2_FN_AFFINITY_INFO: + case PSCI_0_2_FN64_AFFINITY_INFO: + if ( psci_mode_check(current->domain, fid) ) + { + register_t taff = PSCI_ARG(regs,1); + uint32_t laff = PSCI_ARG32(regs,2); + PSCI_RESULT_REG(regs) = + do_psci_0_2_affinity_info(taff, laff); + } + break; + case PSCI_0_2_FN_MIGRATE: + case PSCI_0_2_FN64_MIGRATE: + if ( psci_mode_check(current->domain, fid) ) + { + uint32_t tcpu = PSCI_ARG32(regs,1); + PSCI_RESULT_REG(regs) = do_psci_0_2_migrate(tcpu); + } + break; + default: domain_crash_synchronous(); return; } - - PSCI_RESULT_REG(regs) = psci_call(PSCI_ARGS(regs)); } #ifdef CONFIG_ARM_64 diff --git a/xen/arch/arm/vpsci.c b/xen/arch/arm/vpsci.c index 1ceb8cb..c3d2df9 100644 --- a/xen/arch/arm/vpsci.c +++ b/xen/arch/arm/vpsci.c @@ -17,24 +17,37 @@ #include <asm/current.h> #include <asm/gic.h> #include <asm/psci.h> +#include <public/sched.h> +#include <asm-arm/event.h> -int do_psci_cpu_on(uint32_t vcpuid, register_t entry_point) +static int do_common_cpu_on(register_t target_cpu, register_t entry_point, + register_t context_id,int ver) { struct vcpu *v; struct domain *d = current->domain; struct vcpu_guest_context *ctxt; int rc; int is_thumb = entry_point & 1; + register_t vcpuid; + + if( ver == XEN_PSCI_V_0_2 ) + vcpuid = (target_cpu & MPIDR_HWID_MASK); + else + vcpuid = target_cpu; if ( (vcpuid < 0) || (vcpuid >= MAX_VIRT_CPUS) ) - return PSCI_EINVAL; + return PSCI_INVALID_PARAMETERS; if ( vcpuid >= d->max_vcpus || (v = d->vcpu[vcpuid]) == NULL ) - return PSCI_EINVAL; + return PSCI_INVALID_PARAMETERS; /* THUMB set is not allowed with 64-bit domain */ if ( is_64bit_domain(d) && is_thumb ) - return PSCI_EINVAL; + return PSCI_INVALID_PARAMETERS; + + if( ( ver == XEN_PSCI_V_0_2 ) && + ( !test_bit(_VPF_down, &v->pause_flags) ) ) + return PSCI_ALREADY_ON; if ( (ctxt = alloc_vcpu_guest_context()) == NULL ) return PSCI_DENIED; @@ -48,10 +61,18 @@ int do_psci_cpu_on(uint32_t vcpuid, register_t entry_point) ctxt->ttbr1 = 0; ctxt->ttbcr = 0; /* Defined Reset Value */ if ( is_32bit_domain(d) ) + { ctxt->user_regs.cpsr = PSR_GUEST32_INIT; + if( ver == XEN_PSCI_V_0_2 ) + ctxt->user_regs.r0_usr = context_id; + } #ifdef CONFIG_ARM_64 else + { ctxt->user_regs.cpsr = PSR_GUEST64_INIT; + if( ver == XEN_PSCI_V_0_2 ) + ctxt->user_regs.x0 = context_id; + } #endif /* Start the VCPU with THUMB set if it's requested by the kernel */ @@ -75,7 +96,12 @@ int do_psci_cpu_on(uint32_t vcpuid, register_t entry_point) return PSCI_SUCCESS; } -int do_psci_cpu_off(uint32_t power_state) +int32_t do_psci_cpu_on(uint32_t vcpuid, register_t entry_point) +{ + return do_common_cpu_on(vcpuid,entry_point,0,XEN_PSCI_V_0_1); +} + +int32_t do_psci_cpu_off(uint32_t power_state) { struct vcpu *v = current; if ( !test_and_set_bit(_VPF_down, &v->pause_flags) ) @@ -83,6 +109,100 @@ int do_psci_cpu_off(uint32_t power_state) return PSCI_SUCCESS; } +uint32_t do_psci_0_2_version(void) +{ + return XEN_PSCI_V_0_2; +} + +register_t do_psci_0_2_cpu_suspend(uint32_t power_state, register_t entry_point, + register_t context_id) +{ + struct vcpu *v = current; + + /* + * Power off requests are treated as performing standby + * as this simplifies Xen implementation. + */ + + vcpu_block_unless_event_pending(v); + return PSCI_SUCCESS; +} + +int32_t do_psci_0_2_cpu_off(void) +{ + return do_psci_cpu_off(0); +} + +int32_t do_psci_0_2_cpu_on(register_t target_cpu, register_t entry_point, + register_t context_id) +{ + return do_common_cpu_on(target_cpu,entry_point,context_id,XEN_PSCI_V_0_2); +} + +static const unsigned long target_affinity_mask[] = { + ( MPIDR_HWID_MASK & AFFINITY_MASK( 0 ) ), + ( MPIDR_HWID_MASK & AFFINITY_MASK( 1 ) ), + ( MPIDR_HWID_MASK & AFFINITY_MASK( 2 ) ) +#ifdef CONFIG_ARM_64 + ,( MPIDR_HWID_MASK & AFFINITY_MASK( 3 ) ) +#endif +}; + +int32_t do_psci_0_2_affinity_info(register_t target_affinity, + uint32_t lowest_affinity_level) +{ + struct domain *d = current->domain; + struct vcpu *v; + uint32_t vcpuid; + unsigned long tmask; + + if ( lowest_affinity_level < ARRAY_SIZE(target_affinity_mask) ) + { + tmask = target_affinity_mask[lowest_affinity_level]; + target_affinity &= tmask; + } + else + return PSCI_INVALID_PARAMETERS; + + for ( vcpuid = 0; vcpuid < d->max_vcpus; vcpuid++ ) + { + v = d->vcpu[vcpuid]; + + if ( ( ( v->arch.vmpidr & tmask ) == target_affinity ) + && ( !test_bit(_VPF_down, &v->pause_flags) ) ) + return PSCI_0_2_AFFINITY_LEVEL_ON; + } + + return PSCI_0_2_AFFINITY_LEVEL_OFF; +} + +int32_t do_psci_0_2_migrate(uint32_t target_cpu) +{ + return PSCI_NOT_SUPPORTED; +} + +uint32_t do_psci_0_2_migrate_info_type(void) +{ + return PSCI_0_2_TOS_MP_OR_NOT_PRESENT; +} + +register_t do_psci_0_2_migrate_info_up_cpu(void) +{ + return PSCI_NOT_SUPPORTED; +} + +void do_psci_0_2_system_off( void ) +{ + struct domain *d = current->domain; + domain_shutdown(d,SHUTDOWN_poweroff); +} + +void do_psci_0_2_system_reset(void) +{ + struct domain *d = current->domain; + domain_shutdown(d,SHUTDOWN_reboot); +} + /* * Local variables: * mode: C diff --git a/xen/include/asm-arm/processor.h b/xen/include/asm-arm/processor.h index 9267c1b..8a237c4 100644 --- a/xen/include/asm-arm/processor.h +++ b/xen/include/asm-arm/processor.h @@ -16,6 +16,9 @@ #define MPIDR_AFF0_MASK (_AC(0xff,U) << MPIDR_AFF0_SHIFT) #define MPIDR_HWID_MASK _AC(0xffffff,U) #define MPIDR_INVALID (~MPIDR_HWID_MASK) +#define MPIDR_LEVEL_BITS (8) +#define AFFINITY_MASK(level) ~((_AC(0x1,U) << ((level) * MPIDR_LEVEL_BITS)) - 1) + /* TTBCR Translation Table Base Control Register */ #define TTBCR_EAE _AC(0x80000000,U) diff --git a/xen/include/asm-arm/psci.h b/xen/include/asm-arm/psci.h index 189964b..9777c03 100644 --- a/xen/include/asm-arm/psci.h +++ b/xen/include/asm-arm/psci.h @@ -1,10 +1,16 @@ #ifndef __ASM_PSCI_H__ #define __ASM_PSCI_H__ -#define PSCI_SUCCESS 0 -#define PSCI_ENOSYS -1 -#define PSCI_EINVAL -2 -#define PSCI_DENIED -3 +/* PSCI return values (inclusive of all PSCI versions) */ +#define PSCI_SUCCESS 0 +#define PSCI_NOT_SUPPORTED -1 +#define PSCI_INVALID_PARAMETERS -2 +#define PSCI_DENIED -3 +#define PSCI_ALREADY_ON -4 +#define PSCI_ON_PENDING -5 +#define PSCI_INTERNAL_FAILURE -6 +#define PSCI_NOT_PRESENT -7 +#define PSCI_DISABLED -8 /* availability of PSCI on the host for SMP bringup */ extern bool_t psci_available; @@ -13,10 +19,71 @@ int psci_init(void); int call_psci_cpu_on(int cpu); /* functions to handle guest PSCI requests */ -int do_psci_cpu_on(uint32_t vcpuid, register_t entry_point); -int do_psci_cpu_off(uint32_t power_state); -int do_psci_cpu_suspend(uint32_t power_state, register_t entry_point); -int do_psci_migrate(uint32_t vcpuid); +int32_t do_psci_cpu_on(uint32_t vcpuid, register_t entry_point); +int32_t do_psci_cpu_off(uint32_t power_state); +int32_t do_psci_cpu_suspend(uint32_t power_state, register_t entry_point); +int32_t do_psci_migrate(uint32_t vcpuid); + +/* PSCI 0.2 functions to handle guest PSCI requests */ +uint32_t do_psci_0_2_version(void); +register_t do_psci_0_2_cpu_suspend(uint32_t power_state, register_t entry_point, + register_t context_id); +int32_t do_psci_0_2_cpu_off(void); +int32_t do_psci_0_2_cpu_on(register_t target_cpu, register_t entry_point, + register_t context_id); +int32_t do_psci_0_2_affinity_info(register_t target_affinity, + uint32_t lowest_affinity_level); +int32_t do_psci_0_2_migrate(uint32_t target_cpu); +uint32_t do_psci_0_2_migrate_info_type(void); +register_t do_psci_0_2_migrate_info_up_cpu(void); +void do_psci_0_2_system_off(void); +void do_psci_0_2_system_reset(void); + +/* PSCI version */ +#define XEN_PSCI_V_0_1 1 +#define XEN_PSCI_V_0_2 2 + +/* PSCI v0.2 interface */ +#define PSCI_0_2_FN_BASE 0x84000000 +#define PSCI_0_2_FN(n) (PSCI_0_2_FN_BASE + (n)) +#define PSCI_0_2_64BIT 0x40000000 +#define PSCI_0_2_FN64_BASE \ + (PSCI_0_2_FN_BASE + PSCI_0_2_64BIT) +#define PSCI_0_2_FN64(n) (PSCI_0_2_FN64_BASE + (n)) + +#define PSCI_0_2_FN_PSCI_VERSION PSCI_0_2_FN(0) +#define PSCI_0_2_FN_CPU_SUSPEND PSCI_0_2_FN(1) +#define PSCI_0_2_FN_CPU_OFF PSCI_0_2_FN(2) +#define PSCI_0_2_FN_CPU_ON PSCI_0_2_FN(3) +#define PSCI_0_2_FN_AFFINITY_INFO PSCI_0_2_FN(4) +#define PSCI_0_2_FN_MIGRATE PSCI_0_2_FN(5) +#define PSCI_0_2_FN_MIGRATE_INFO_TYPE PSCI_0_2_FN(6) +#define PSCI_0_2_FN_MIGRATE_INFO_UP_CPU PSCI_0_2_FN(7) +#define PSCI_0_2_FN_SYSTEM_OFF PSCI_0_2_FN(8) +#define PSCI_0_2_FN_SYSTEM_RESET PSCI_0_2_FN(9) + +#define PSCI_0_2_FN64_CPU_SUSPEND PSCI_0_2_FN64(1) +#define PSCI_0_2_FN64_CPU_ON PSCI_0_2_FN64(3) +#define PSCI_0_2_FN64_AFFINITY_INFO PSCI_0_2_FN64(4) +#define PSCI_0_2_FN64_MIGRATE PSCI_0_2_FN64(5) +#define PSCI_0_2_FN64_MIGRATE_INFO_UP_CPU PSCI_0_2_FN64(7) + +/* PSCI v0.2 affinity level state returned by AFFINITY_INFO */ +#define PSCI_0_2_AFFINITY_LEVEL_ON 0 +#define PSCI_0_2_AFFINITY_LEVEL_OFF 1 +#define PSCI_0_2_AFFINITY_LEVEL_ON_PENDING 2 + +/* PSCI v0.2 multicore support in Trusted OS returned by MIGRATE_INFO_TYPE */ +#define PSCI_0_2_TOS_UP_MIGRATE_CAPABLE 0 +#define PSCI_0_2_TOS_UP_NOT_MIGRATE_CAPABLE 1 +#define PSCI_0_2_TOS_MP_OR_NOT_PRESENT 2 + +/* PSCI v0.2 power state encoding for CPU_SUSPEND function */ +#define PSCI_0_2_POWER_STATE_ID_MASK 0xffff +#define PSCI_0_2_POWER_STATE_ID_SHIFT 0 +#define PSCI_0_2_POWER_STATE_TYPE_SHIFT 16 +#define PSCI_0_2_POWER_STATE_TYPE_MASK \ + (0x1 << PSCI_0_2_POWER_STATE_TYPE_SHIFT) #endif /* __ASM_PSCI_H__ */ -- 1.9.1 _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |