Subject: Re: WFI idle for ARM926EJ-S/ARM1026EJ-S
To: Todd Allan <todd_allan@picovex.com>
From: Jason Thorpe <thorpej@shagadelic.org>
List: port-arm
Date: 08/08/2006 09:43:55
On Aug 7, 2006, at 3:02 PM, Todd Allan wrote:

> The attached patch adds a powersave idle for ARM926EJS/ARM1026EJS,  
> comprised of a Wait For Interrupt operation as described in the ARM  
> ARM: write SBZ data to CP15 coprocessor register 7, CRm=c0, opcode2=0.

Note, this should be controllable by sysctl -- a couple of years ago,  
I discovered that using the powersave mode on Xscale, anyway, led to a  
huge performance drop in a server appliance application.

It should probably default to "powersave enabled", and let  
applications that need the extra performance tune for that.

>
> This should work on some other ARM processors as well, and the patch  
> implements it in a generic cpufunc, but some ARM implementations,  
> notably including XScale, do this differently.  The patch has only  
> been tested on a 926EJ-S; it enables WFI on the 926EJ-S and on the  
> 10EJ-S, the TRM for which indicates that it implements this  
> operation.  This patch applies on top of a patch from Scott Allan  
> previously sent 07/31/2006 in thread "Patch to add support for ARM9E".
>
> Any suggestions appreciated, thanks.
>
> Index: netbsd_quilt/src/sys/arch/arm/arm/cpufunc.c
> ===================================================================
> --- netbsd_quilt.orig/src/sys/arch/arm/arm/cpufunc.c
> +++ netbsd_quilt/src/sys/arch/arm/arm/cpufunc.c
> @@ -501,7 +501,7 @@ struct cpu_functions armv5_ec_cpufuncs =
>  	cpufunc_nullop,			/* flush_brnchtgt_C	*/
>  	(void *)cpufunc_nullop,		/* flush_brnchtgt_E	*/
>
> -	(void *)cpufunc_nullop,		/* sleep		*/
> +	cpufunc_sleep,			/* sleep		*/
>
>  	/* Soft functions */
>
> @@ -1108,6 +1108,10 @@ set_cpufuncs()
>  		cpu_reset_needs_v4_MMU_disable = 1;	/* V4 or higher */
>  		get_cachetype_cp15();
>  		pmap_pte_init_generic();
> +
> +		/* Use powersave on this CPU. */
> +		cpu_do_powersave = 1;
> +
>  		return 0;
>  	}
>  #endif /* CPU_ARM9E || CPU_ARM10 */
> Index: netbsd_quilt/src/sys/arch/arm/arm/cpufunc_asm.S
> ===================================================================
> --- netbsd_quilt.orig/src/sys/arch/arm/arm/cpufunc_asm.S
> +++ netbsd_quilt/src/sys/arch/arm/arm/cpufunc_asm.S
> @@ -148,3 +148,12 @@ ENTRY(get_pc_str_offset)
>  	ldr	r0, [sp]
>  	sub	r0, r0, r1
>  	ldmdb	fp, {fp, sp, pc}
> +
> +/*
> + * WFI low-power idle per ARM ARM.
> + */
> +
> +ENTRY(cpufunc_sleep)
> +	mov	r0, #0x0
> +	mcr p15, 0, r0, c7, c0, 4
> +	mov	pc, lr
> Index: netbsd_quilt/src/sys/arch/arm/include/cpufunc.h
> ===================================================================
> --- netbsd_quilt.orig/src/sys/arch/arm/include/cpufunc.h
> +++ netbsd_quilt/src/sys/arch/arm/include/cpufunc.h
> @@ -209,6 +209,7 @@ u_int	cpufunc_control		__P((u_int, u_int
>  void	cpufunc_domains		__P((u_int));
>  u_int	cpufunc_faultstatus	__P((void));
>  u_int	cpufunc_faultaddress	__P((void));
> +void	cpufunc_sleep		__P((int));
>
>  #ifdef CPU_ARM3
>  u_int	arm3_control		__P((u_int, u_int));

-- thorpej