forked from mirrors/linux
		
	arm: kernel: Add SMC structure parameter
This patch adds a quirk parameter to the arm_smccc_(smc/hvc) calls. The quirk structure allows for specialized SMC operations due to SoC specific requirements. The current arm_smccc_(smc/hvc) is renamed and macros are used instead to specify the standard arm_smccc_(smc/hvc) or the arm_smccc_(smc/hvc)_quirk function. This patch and partial implementation was suggested by Will Deacon. Signed-off-by: Andy Gross <andy.gross@linaro.org> Reviewed-by: Will Deacon <will.deacon@arm.com> Signed-off-by: Will Deacon <will.deacon@arm.com>
This commit is contained in:
		
							parent
							
								
									757b435aaa
								
							
						
					
					
						commit
						680a0873e1
					
				
					 6 changed files with 57 additions and 26 deletions
				
			
		| 
						 | 
					@ -178,6 +178,6 @@ EXPORT_SYMBOL(__pv_offset);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_HAVE_ARM_SMCCC
 | 
					#ifdef CONFIG_HAVE_ARM_SMCCC
 | 
				
			||||||
EXPORT_SYMBOL(arm_smccc_smc);
 | 
					EXPORT_SYMBOL(__arm_smccc_smc);
 | 
				
			||||||
EXPORT_SYMBOL(arm_smccc_hvc);
 | 
					EXPORT_SYMBOL(__arm_smccc_hvc);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -46,17 +46,19 @@ UNWIND(	.fnend)
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * void smccc_smc(unsigned long a0, unsigned long a1, unsigned long a2,
 | 
					 * void smccc_smc(unsigned long a0, unsigned long a1, unsigned long a2,
 | 
				
			||||||
 *		  unsigned long a3, unsigned long a4, unsigned long a5,
 | 
					 *		  unsigned long a3, unsigned long a4, unsigned long a5,
 | 
				
			||||||
 *		  unsigned long a6, unsigned long a7, struct arm_smccc_res *res)
 | 
					 *		  unsigned long a6, unsigned long a7, struct arm_smccc_res *res,
 | 
				
			||||||
 | 
					 *		  struct arm_smccc_quirk *quirk)
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
ENTRY(arm_smccc_smc)
 | 
					ENTRY(__arm_smccc_smc)
 | 
				
			||||||
	SMCCC SMCCC_SMC
 | 
						SMCCC SMCCC_SMC
 | 
				
			||||||
ENDPROC(arm_smccc_smc)
 | 
					ENDPROC(__arm_smccc_smc)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * void smccc_hvc(unsigned long a0, unsigned long a1, unsigned long a2,
 | 
					 * void smccc_hvc(unsigned long a0, unsigned long a1, unsigned long a2,
 | 
				
			||||||
 *		  unsigned long a3, unsigned long a4, unsigned long a5,
 | 
					 *		  unsigned long a3, unsigned long a4, unsigned long a5,
 | 
				
			||||||
 *		  unsigned long a6, unsigned long a7, struct arm_smccc_res *res)
 | 
					 *		  unsigned long a6, unsigned long a7, struct arm_smccc_res *res,
 | 
				
			||||||
 | 
					 *		  struct arm_smccc_quirk *quirk)
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
ENTRY(arm_smccc_hvc)
 | 
					ENTRY(__arm_smccc_hvc)
 | 
				
			||||||
	SMCCC SMCCC_HVC
 | 
						SMCCC SMCCC_HVC
 | 
				
			||||||
ENDPROC(arm_smccc_hvc)
 | 
					ENDPROC(__arm_smccc_hvc)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -73,5 +73,5 @@ NOKPROBE_SYMBOL(_mcount);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* arm-smccc */
 | 
						/* arm-smccc */
 | 
				
			||||||
EXPORT_SYMBOL(arm_smccc_smc);
 | 
					EXPORT_SYMBOL(__arm_smccc_smc);
 | 
				
			||||||
EXPORT_SYMBOL(arm_smccc_hvc);
 | 
					EXPORT_SYMBOL(__arm_smccc_hvc);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -145,6 +145,9 @@ int main(void)
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
  DEFINE(ARM_SMCCC_RES_X0_OFFS,		offsetof(struct arm_smccc_res, a0));
 | 
					  DEFINE(ARM_SMCCC_RES_X0_OFFS,		offsetof(struct arm_smccc_res, a0));
 | 
				
			||||||
  DEFINE(ARM_SMCCC_RES_X2_OFFS,		offsetof(struct arm_smccc_res, a2));
 | 
					  DEFINE(ARM_SMCCC_RES_X2_OFFS,		offsetof(struct arm_smccc_res, a2));
 | 
				
			||||||
 | 
					  DEFINE(ARM_SMCCC_QUIRK_ID_OFFS,	offsetof(struct arm_smccc_quirk, id));
 | 
				
			||||||
 | 
					  DEFINE(ARM_SMCCC_QUIRK_STATE_OFFS,	offsetof(struct arm_smccc_quirk, state));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  BLANK();
 | 
					  BLANK();
 | 
				
			||||||
  DEFINE(HIBERN_PBE_ORIG,	offsetof(struct pbe, orig_address));
 | 
					  DEFINE(HIBERN_PBE_ORIG,	offsetof(struct pbe, orig_address));
 | 
				
			||||||
  DEFINE(HIBERN_PBE_ADDR,	offsetof(struct pbe, address));
 | 
					  DEFINE(HIBERN_PBE_ADDR,	offsetof(struct pbe, address));
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -27,17 +27,19 @@
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * void arm_smccc_smc(unsigned long a0, unsigned long a1, unsigned long a2,
 | 
					 * void arm_smccc_smc(unsigned long a0, unsigned long a1, unsigned long a2,
 | 
				
			||||||
 *		  unsigned long a3, unsigned long a4, unsigned long a5,
 | 
					 *		  unsigned long a3, unsigned long a4, unsigned long a5,
 | 
				
			||||||
 *		  unsigned long a6, unsigned long a7, struct arm_smccc_res *res)
 | 
					 *		  unsigned long a6, unsigned long a7, struct arm_smccc_res *res,
 | 
				
			||||||
 | 
					 *		  struct arm_smccc_quirk *quirk)
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
ENTRY(arm_smccc_smc)
 | 
					ENTRY(__arm_smccc_smc)
 | 
				
			||||||
	SMCCC	smc
 | 
						SMCCC	smc
 | 
				
			||||||
ENDPROC(arm_smccc_smc)
 | 
					ENDPROC(__arm_smccc_smc)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * void arm_smccc_hvc(unsigned long a0, unsigned long a1, unsigned long a2,
 | 
					 * void arm_smccc_hvc(unsigned long a0, unsigned long a1, unsigned long a2,
 | 
				
			||||||
 *		  unsigned long a3, unsigned long a4, unsigned long a5,
 | 
					 *		  unsigned long a3, unsigned long a4, unsigned long a5,
 | 
				
			||||||
 *		  unsigned long a6, unsigned long a7, struct arm_smccc_res *res)
 | 
					 *		  unsigned long a6, unsigned long a7, struct arm_smccc_res *res,
 | 
				
			||||||
 | 
					 *		  struct arm_smccc_quirk *quirk)
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
ENTRY(arm_smccc_hvc)
 | 
					ENTRY(__arm_smccc_hvc)
 | 
				
			||||||
	SMCCC	hvc
 | 
						SMCCC	hvc
 | 
				
			||||||
ENDPROC(arm_smccc_hvc)
 | 
					ENDPROC(__arm_smccc_hvc)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -72,33 +72,57 @@ struct arm_smccc_res {
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * arm_smccc_smc() - make SMC calls
 | 
					 * struct arm_smccc_quirk - Contains quirk information
 | 
				
			||||||
 | 
					 * @id: quirk identification
 | 
				
			||||||
 | 
					 * @state: quirk specific information
 | 
				
			||||||
 | 
					 * @a6: Qualcomm quirk entry for returning post-smc call contents of a6
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct arm_smccc_quirk {
 | 
				
			||||||
 | 
						int	id;
 | 
				
			||||||
 | 
						union {
 | 
				
			||||||
 | 
							unsigned long a6;
 | 
				
			||||||
 | 
						} state;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * __arm_smccc_smc() - make SMC calls
 | 
				
			||||||
 * @a0-a7: arguments passed in registers 0 to 7
 | 
					 * @a0-a7: arguments passed in registers 0 to 7
 | 
				
			||||||
 * @res: result values from registers 0 to 3
 | 
					 * @res: result values from registers 0 to 3
 | 
				
			||||||
 | 
					 * @quirk: points to an arm_smccc_quirk, or NULL when no quirks are required.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * This function is used to make SMC calls following SMC Calling Convention.
 | 
					 * This function is used to make SMC calls following SMC Calling Convention.
 | 
				
			||||||
 * The content of the supplied param are copied to registers 0 to 7 prior
 | 
					 * The content of the supplied param are copied to registers 0 to 7 prior
 | 
				
			||||||
 * to the SMC instruction. The return values are updated with the content
 | 
					 * to the SMC instruction. The return values are updated with the content
 | 
				
			||||||
 * from register 0 to 3 on return from the SMC instruction.
 | 
					 * from register 0 to 3 on return from the SMC instruction.  An optional
 | 
				
			||||||
 | 
					 * quirk structure provides vendor specific behavior.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
asmlinkage void arm_smccc_smc(unsigned long a0, unsigned long a1,
 | 
					asmlinkage void __arm_smccc_smc(unsigned long a0, unsigned long a1,
 | 
				
			||||||
			unsigned long a2, unsigned long a3, unsigned long a4,
 | 
								unsigned long a2, unsigned long a3, unsigned long a4,
 | 
				
			||||||
			unsigned long a5, unsigned long a6, unsigned long a7,
 | 
								unsigned long a5, unsigned long a6, unsigned long a7,
 | 
				
			||||||
			struct arm_smccc_res *res);
 | 
								struct arm_smccc_res *res, struct arm_smccc_quirk *quirk);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * arm_smccc_hvc() - make HVC calls
 | 
					 * __arm_smccc_hvc() - make HVC calls
 | 
				
			||||||
 * @a0-a7: arguments passed in registers 0 to 7
 | 
					 * @a0-a7: arguments passed in registers 0 to 7
 | 
				
			||||||
 * @res: result values from registers 0 to 3
 | 
					 * @res: result values from registers 0 to 3
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * This function is used to make HVC calls following SMC Calling
 | 
					 * This function is used to make HVC calls following SMC Calling
 | 
				
			||||||
 * Convention.  The content of the supplied param are copied to registers 0
 | 
					 * Convention.  The content of the supplied param are copied to registers 0
 | 
				
			||||||
 * to 7 prior to the HVC instruction. The return values are updated with
 | 
					 * to 7 prior to the HVC instruction. The return values are updated with
 | 
				
			||||||
 * the content from register 0 to 3 on return from the HVC instruction.
 | 
					 * the content from register 0 to 3 on return from the HVC instruction.  An
 | 
				
			||||||
 | 
					 * optional quirk structure provides vendor specific behavior.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
asmlinkage void arm_smccc_hvc(unsigned long a0, unsigned long a1,
 | 
					asmlinkage void __arm_smccc_hvc(unsigned long a0, unsigned long a1,
 | 
				
			||||||
			unsigned long a2, unsigned long a3, unsigned long a4,
 | 
								unsigned long a2, unsigned long a3, unsigned long a4,
 | 
				
			||||||
			unsigned long a5, unsigned long a6, unsigned long a7,
 | 
								unsigned long a5, unsigned long a6, unsigned long a7,
 | 
				
			||||||
			struct arm_smccc_res *res);
 | 
								struct arm_smccc_res *res, struct arm_smccc_quirk *quirk);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define arm_smccc_smc(...) __arm_smccc_smc(__VA_ARGS__, NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define arm_smccc_smc_quirk(...) __arm_smccc_smc(__VA_ARGS__)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define arm_smccc_hvc(...) __arm_smccc_hvc(__VA_ARGS__, NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define arm_smccc_hvc_quirk(...) __arm_smccc_hvc(__VA_ARGS__)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /*__LINUX_ARM_SMCCC_H*/
 | 
					#endif /*__LINUX_ARM_SMCCC_H*/
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue