[PATCH] SLB shadow buffer

Milton Miller miltonm at bga.com
Sat Aug 5 15:56:39 EST 2006


On Fri Aug  4 2006 12:53:19 AM CDT, Michael Neuling wrote:
> This adds a shadow buffer for the SLBs and regsiters it with PHYP.
> Only the bolted SLB entries (first 3) are saved.
> 
> Signed-off-by: Michael Neuling <mikey at neuling.org>
> 
> 
> Index: linux-2.6-ozlabs/arch/powerpc/kernel/entry_64.S
> ===================================================================
> --- linux-2.6-ozlabs.orig/arch/powerpc/kernel/entry_64.S
> +++ linux-2.6-ozlabs/arch/powerpc/kernel/entry_64.S
> @@ -323,6 +323,10 @@ _GLOBAL(ret_from_fork)
>   * The code which creates the new task context is in 'copy_thread'
>   * in arch/powerpc/kernel/process.c 
>   */
> +#define SHADOW_SLB_BOLTED_LAST_ESID \
> +		(SLBSHADOW_SAVEAREA + 0x10*(SLB_NUM_BOLTED-1))
> +#define SHADOW_SLB_BOLTED_LAST_VSID \
> +		(SLBSHADOW_SAVEAREA + 0x10*(SLB_NUM_BOLTED-1) + 8)

It's not because it's the last one but that it's the one with the stack.

>  	.align	7
>  _GLOBAL(_switch)
>  	mflr	r0
> @@ -375,6 +379,14 @@ BEGIN_FTR_SECTION
>  	ld	r7,KSP_VSID(r4)	/* Get new stack's VSID */
>  	oris	r0,r6,(SLB_ESID_V)@h
>  	ori	r0,r0,(SLB_NUM_BOLTED-1)@l
> +
> +	/* Update the last bolted SLB */
> +	ld	r9,PACA_SLBSHADOWPTR(r13)
> + 	li	r12,0
> +  	std     r12,SHADOW_SLB_BOLTED_LAST_ESID(r9) /* Clear ESID */
> +	std     r7,SHADOW_SLB_BOLTED_LAST_VSID(r9)  /* Save VSID */
> + 	std     r0,SHADOW_SLB_BOLTED_LAST_ESID(r9)  /* Save ESID */
> +

Tabs not spaces please

>  	slbie	r6
>  	slbie	r6		/* Workaround POWER5 < DD2.1 issue */
>  	slbmte	r7,r0
> Index: linux-2.6-ozlabs/arch/powerpc/kernel/paca.c
> ===================================================================
> --- linux-2.6-ozlabs.orig/arch/powerpc/kernel/paca.c
> +++ linux-2.6-ozlabs/arch/powerpc/kernel/paca.c
> @@ -17,6 +17,7 @@
>  #include <asm/lppaca.h>
>  #include <asm/iseries/it_lp_reg_save.h>
>  #include <asm/paca.h>
> +#include <asm/mmu.h>
>  
>  
>  /* This symbol is provided by the linker - let it fill in the paca
> @@ -45,6 +46,17 @@ struct lppaca lppaca[] = {
>  	},
>  };
>  
> +/*
> + * 3 persistent SLBs are registered here.  The buffer will be zero
> + * initially, hence will all be invaild until we actually write them.
> + */
> +struct slb_shadow_buffer slb_shadow_buffer[] = {
> +	[0 ... (NR_CPUS-1)] = {
> +		.persistent = SLB_NUM_BOLTED,
> +		.buffer_length = sizeof(struct slb_shadow_buffer),
> +	},
> +};

How about making this per-cpu and setting the paca pointer at runtime?
It would save NR_CPUS-1 cachelines of data.   Otherwise, put  in
cacheline_aligned will potentially save some space.

> +
>  /* The Paca is an array with one entry per processor.  Each contains an
>   * lppaca, which contains the information shared between the
>   * hypervisor and Linux.
> @@ -59,7 +71,8 @@ struct lppaca lppaca[] = {
>  	.lock_token = 0x8000,						    \
>  	.paca_index = (number),		/* Paca Index */		    \
>  	.kernel_toc = (unsigned long)(&__toc_start) + 0x8000UL,		    \
> -	.hw_cpu_id = 0xffff,
> +	.hw_cpu_id = 0xffff,						    \
> +	.slb_shadow_buffer_ptr = &slb_shadow_buffer[number]

Trailing , (yeah, still have to add the \ )

>  
>  #ifdef CONFIG_PPC_ISERIES
>  #define PACA_INIT_ISERIES(number)					    \
> Index: linux-2.6-ozlabs/arch/powerpc/mm/slb.c
> ===================================================================
> --- linux-2.6-ozlabs.orig/arch/powerpc/mm/slb.c
> +++ linux-2.6-ozlabs/arch/powerpc/mm/slb.c
> @@ -22,6 +22,8 @@
>  #include <asm/paca.h>
>  #include <asm/cputable.h>
>  #include <asm/cacheflush.h>
> +#include <asm/smp.h>
> +#include <linux/compiler.h>
>  
>  #ifdef DEBUG
>  #define DBG(fmt...) udbg_printf(fmt)
> @@ -50,9 +52,29 @@ static inline unsigned long mk_vsid_data
>  	return (get_kernel_vsid(ea) << SLB_VSID_SHIFT) | flags;
>  }
>  
> +static inline void slb_shadow_update(unsigned long esid, unsigned long vsid,
> +				     unsigned long entry)
> +{
> +	/* Clear the ESID first so the entry is not valid while we are
> +	 * updating it.  Then write the VSID before the real ESID. */

Multi-line comments get the  */ on it's own line

> +	get_slb_shadow_buffer()->save_area[2*entry] = 0;
> +	barrier();
> +	get_slb_shadow_buffer()->save_area[2*entry+1] =	vsid;
> +	barrier();
> +	get_slb_shadow_buffer()->save_area[2*entry] = esid;
> +
> +}

This 2* seems magic.  How about an array of structs?

> +
>  static inline void create_slbe(unsigned long ea, unsigned long flags,
>  			       unsigned long entry)

Should we rename to create_shadowed_slbe?

>  {
> +	/* Updating the shadow buffer before writing the SLB ensures
> +	 * we don't get a stale entry here if we get preempted by PHYP
> +	 * between these two statements. */

own line

> +	slb_shadow_update(mk_esid_data(ea, entry),
> +			  mk_vsid_data(ea, flags),
> +			  entry);

Do we need the third line?

> +
>  	asm volatile("slbmte  %0,%1" :
>  		     : "r" (mk_vsid_data(ea, flags)),
>  		       "r" (mk_esid_data(ea, entry))

Hopefully the compiler only calculates these once.

> @@ -77,6 +99,11 @@ void slb_flush_and_rebolt(void)
>  	if ((ksp_esid_data & ESID_MASK) == PAGE_OFFSET)
>  		ksp_esid_data &= ~SLB_ESID_V;
>  
> +	/* Only second entry may change here so only resave that */
> +	slb_shadow_update(ksp_esid_data,
> +			  mk_vsid_data(ksp_esid_data, lflags),
> +			  2);
> +

1) it's the third entry 2) it's the stack slot

>  	/* We need to do this all in asm, so we're sure we don't touch
>  	 * the stack between the slbia and rebolting it. */

own line

>  	asm volatile("isync\n"
> Index: linux-2.6-ozlabs/arch/powerpc/platforms/pseries/lpar.c
> ===================================================================
> --- linux-2.6-ozlabs.orig/arch/powerpc/platforms/pseries/lpar.c
> +++ linux-2.6-ozlabs/arch/powerpc/platforms/pseries/lpar.c
> @@ -254,18 +254,32 @@ out:
>  void vpa_init(int cpu)
>  {
>  	int hwcpu = get_hard_smp_processor_id(cpu);
> -	unsigned long vpa = __pa(&lppaca[cpu]);
> +	unsigned long vpa;

This is used for something  other than vpa, rename.

>  	long ret;
>  
>  	if (cpu_has_feature(CPU_FTR_ALTIVEC))
>  		lppaca[cpu].vmxregs_in_use = 1;
>  
> +	vpa = __pa(&lppaca[cpu]);
>  	ret = register_vpa(hwcpu, vpa);
>  
> -	if (ret)
> +	if (ret) {
>  		printk(KERN_ERR "WARNING: vpa_init: VPA registration for "
>  				"cpu %d (hw %d) of area %lx returns %ld\n",
>  				cpu, hwcpu, vpa, ret);
> +		return;
> +	}
> +	/* PAPR says this feature is SLB-Buffer but firmware never
> +	 * reports that.  All SPLPAR support SLB shadow buffer. */

own line

> +	vpa = __pa(&slb_shadow_buffer[cpu]);
> +	if (firmware_has_feature(FW_FEATURE_SPLPAR)) {
> +		ret = register_slb_shadow(hwcpu, vpa);
> +		if (ret)
> +			printk(KERN_ERR
> +			       "WARNING: vpa_init: SLB shadow buffer "
> +			       "registration for cpu %d (hw %d) of area %lx "
> +			       "returns %ld\n", cpu, hwcpu, vpa, ret);
> +	}
>  }
>  
>  long pSeries_lpar_hpte_insert(unsigned long hpte_group,
...
> Index: linux-2.6-ozlabs/arch/powerpc/platforms/pseries/setup.c
> ===================================================================
> --- linux-2.6-ozlabs.orig/arch/powerpc/platforms/pseries/setup.c
> +++ linux-2.6-ozlabs/arch/powerpc/platforms/pseries/setup.c
> @@ -234,8 +234,16 @@ static void pseries_kexec_cpu_down_xics(
>  {
>  	/* Don't risk a hypervisor call if we're crashing */
>  	if (firmware_has_feature(FW_FEATURE_SPLPAR) && !crash_shutdown) {
> -		unsigned long vpa = __pa(get_lppaca());
> +		unsigned long vpa;

Rename.

>  
> +		vpa = __pa(get_slb_shadow_buffer());
> +		if (unregister_slb_shadow(hard_smp_processor_id(), vpa))
> +			printk("SLB shadow buffer deregistration of "
> +			       "cpu %u (hw_cpu_id %d) failed\n",
> +			       smp_processor_id(),
> +			       hard_smp_processor_id());
> +
> +		vpa = __pa(get_lppaca());
>  		if (unregister_vpa(hard_smp_processor_id(), vpa)) {
>  			printk("VPA deregistration of cpu %u (hw_cpu_id %d) "
>  					"failed\n", smp_processor_id(),


Side comment: this seems like it should be in pseeries/lpar.c, that would
be a seperate cleanup.

> Index: linux-2.6-ozlabs/include/asm-powerpc/lppaca.h
> ===================================================================
> --- linux-2.6-ozlabs.orig/include/asm-powerpc/lppaca.h
> +++ linux-2.6-ozlabs/include/asm-powerpc/lppaca.h
> @@ -28,6 +28,7 @@
>  //
>  //----------------------------------------------------------------------------
>  #include <asm/types.h>
> +#include <asm/mmu.h>
>  
>  /* The Hypervisor barfs if the lppaca crosses a page boundary.  A 1k
>   * alignment is sufficient to prevent this */
> @@ -133,5 +134,19 @@ struct lppaca {
>  
>  extern struct lppaca lppaca[];
>  
> +/* SLB shadow buffer structure as defined in the PAPR.  The save_area
> + * contains adjacent ESID and VSID pairs for each shadowed SLB.  The
> + * ESID is stored in the lower 64bits, then the VSID.  NOTE: This
> + * structure is 0x40 bytes long (with 3 bolted SLBs), but PHYP
> + * complaints if we're not 0x80 (cache line?) aligned.  */

Own line

Less explaination needed with array of structs.

> +struct slb_shadow_buffer {
> +	u32	persistent;		// Number of persistent SLBs	x00-x03
> +	u32	buffer_length;		// Total shadow buffer length	x04-x07
> +	u64	reserved;		// Alignment			x08-x0f
> +	u64     save_area[SLB_NUM_BOLTED * 2];	//			x10-x40
> +} __attribute__((__aligned__(0x80)));
> +
> +extern struct slb_shadow_buffer slb_shadow_buffer[];
> +

Remove buffer from these names? They seem quite long for linux.
 
>  #endif /* __KERNEL__ */
>  #endif /* _ASM_POWERPC_LPPACA_H */
> Index: linux-2.6-ozlabs/include/asm-powerpc/paca.h
> ===================================================================
> --- linux-2.6-ozlabs.orig/include/asm-powerpc/paca.h
> +++ linux-2.6-ozlabs/include/asm-powerpc/paca.h
> @@ -23,6 +23,7 @@
>  register struct paca_struct *local_paca asm("r13");
>  #define get_paca()	local_paca
>  #define get_lppaca()	(get_paca()->lppaca_ptr)
> +#define get_slb_shadow_buffer()	(get_paca()->slb_shadow_buffer_ptr)
>  
>  struct task_struct;
>  
> @@ -98,6 +99,9 @@ struct paca_struct {
>  	u64 user_time;			/* accumulated usermode TB ticks */
>  	u64 system_time;		/* accumulated system TB ticks */
>  	u64 startpurr;			/* PURR/TB value snapshot */
> +
> +	/* Pointer to SLB shadow buffer */
> +	struct slb_shadow_buffer *slb_shadow_buffer_ptr;
>  };

With the long name the comment doesn't add much.

>  
>  extern struct paca_struct paca[];
> 



More information about the Linuxppc-dev mailing list