diff options
Diffstat (limited to 'include/linux/arm-smccc.h')
| -rw-r--r-- | include/linux/arm-smccc.h | 75 | 
1 files changed, 75 insertions, 0 deletions
diff --git a/include/linux/arm-smccc.h b/include/linux/arm-smccc.h index 080012a6f025..59494df0f55b 100644 --- a/include/linux/arm-smccc.h +++ b/include/linux/arm-smccc.h @@ -45,6 +45,7 @@  #define ARM_SMCCC_OWNER_SIP		2  #define ARM_SMCCC_OWNER_OEM		3  #define ARM_SMCCC_OWNER_STANDARD	4 +#define ARM_SMCCC_OWNER_STANDARD_HYP	5  #define ARM_SMCCC_OWNER_TRUSTED_APP	48  #define ARM_SMCCC_OWNER_TRUSTED_APP_END	49  #define ARM_SMCCC_OWNER_TRUSTED_OS	50 @@ -80,6 +81,22 @@  #include <linux/linkage.h>  #include <linux/types.h> + +enum arm_smccc_conduit { +	SMCCC_CONDUIT_NONE, +	SMCCC_CONDUIT_SMC, +	SMCCC_CONDUIT_HVC, +}; + +/** + * arm_smccc_1_1_get_conduit() + * + * Returns the conduit to be used for SMCCCv1.1 or later. + * + * When SMCCCv1.1 is not present, returns SMCCC_CONDUIT_NONE. + */ +enum arm_smccc_conduit arm_smccc_1_1_get_conduit(void); +  /**   * struct arm_smccc_res - Result from SMC/HVC call   * @a0-a3 result values from registers 0 to 3 @@ -302,5 +319,63 @@ asmlinkage void __arm_smccc_hvc(unsigned long a0, unsigned long a1,  #define SMCCC_RET_NOT_SUPPORTED			-1  #define SMCCC_RET_NOT_REQUIRED			-2 +/* + * Like arm_smccc_1_1* but always returns SMCCC_RET_NOT_SUPPORTED. + * Used when the SMCCC conduit is not defined. The empty asm statement + * avoids compiler warnings about unused variables. + */ +#define __fail_smccc_1_1(...)						\ +	do {								\ +		__declare_args(__count_args(__VA_ARGS__), __VA_ARGS__);	\ +		asm ("" __constraints(__count_args(__VA_ARGS__)));	\ +		if (___res)						\ +			___res->a0 = SMCCC_RET_NOT_SUPPORTED;		\ +	} while (0) + +/* + * arm_smccc_1_1_invoke() - make an SMCCC v1.1 compliant call + * + * This is a variadic macro taking one to eight source arguments, and + * an optional return structure. + * + * @a0-a7: arguments passed in registers 0 to 7 + * @res: result values from registers 0 to 3 + * + * This macro will make either an HVC call or an SMC call depending on the + * current SMCCC conduit. If no valid conduit is available then -1 + * (SMCCC_RET_NOT_SUPPORTED) is returned in @res.a0 (if supplied). + * + * The return value also provides the conduit that was used. + */ +#define arm_smccc_1_1_invoke(...) ({					\ +		int method = arm_smccc_1_1_get_conduit();		\ +		switch (method) {					\ +		case SMCCC_CONDUIT_HVC:					\ +			arm_smccc_1_1_hvc(__VA_ARGS__);			\ +			break;						\ +		case SMCCC_CONDUIT_SMC:					\ +			arm_smccc_1_1_smc(__VA_ARGS__);			\ +			break;						\ +		default:						\ +			__fail_smccc_1_1(__VA_ARGS__);			\ +			method = SMCCC_CONDUIT_NONE;			\ +			break;						\ +		}							\ +		method;							\ +	}) + +/* Paravirtualised time calls (defined by ARM DEN0057A) */ +#define ARM_SMCCC_HV_PV_TIME_FEATURES				\ +	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,			\ +			   ARM_SMCCC_SMC_64,			\ +			   ARM_SMCCC_OWNER_STANDARD_HYP,	\ +			   0x20) + +#define ARM_SMCCC_HV_PV_TIME_ST					\ +	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,			\ +			   ARM_SMCCC_SMC_64,			\ +			   ARM_SMCCC_OWNER_STANDARD_HYP,	\ +			   0x21) +  #endif /*__ASSEMBLY__*/  #endif /*__LINUX_ARM_SMCCC_H*/  |