diff options
| author | 2012-07-30 09:03:10 +0200 | |
|---|---|---|
| committer | 2012-07-30 09:03:10 +0200 | |
| commit | 72ea1f74fcdf874cca6d2c0962379523bbd99e2c (patch) | |
| tree | 4c67be6c73356086ff44ef1b8b1c9479702689ca /arch/powerpc/kernel | |
| parent | Merge branch 'upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/floppy into for-3.6/drivers (diff) | |
| parent | drbd: announce FLUSH/FUA capability to upper layers (diff) | |
| download | wireguard-linux-72ea1f74fcdf874cca6d2c0962379523bbd99e2c.tar.xz wireguard-linux-72ea1f74fcdf874cca6d2c0962379523bbd99e2c.zip  | |
Merge branch 'for-jens' of git://git.drbd.org/linux-drbd into for-3.6/drivers
Diffstat (limited to 'arch/powerpc/kernel')
| -rw-r--r-- | arch/powerpc/kernel/entry_64.S | 97 | ||||
| -rw-r--r-- | arch/powerpc/kernel/irq.c | 50 | ||||
| -rw-r--r-- | arch/powerpc/kernel/module_32.c | 11 | ||||
| -rw-r--r-- | arch/powerpc/kernel/prom_init.c | 4 | ||||
| -rw-r--r-- | arch/powerpc/kernel/time.c | 14 | 
5 files changed, 106 insertions, 70 deletions
diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S index ed1718feb9d9..5971c85df136 100644 --- a/arch/powerpc/kernel/entry_64.S +++ b/arch/powerpc/kernel/entry_64.S @@ -558,27 +558,54 @@ _GLOBAL(ret_from_except_lite)  	mtmsrd	r10,1		  /* Update machine state */  #endif /* CONFIG_PPC_BOOK3E */ -#ifdef CONFIG_PREEMPT  	clrrdi	r9,r1,THREAD_SHIFT	/* current_thread_info() */ -	li	r0,_TIF_NEED_RESCHED	/* bits to check */  	ld	r3,_MSR(r1)  	ld	r4,TI_FLAGS(r9) -	/* Move MSR_PR bit in r3 to _TIF_SIGPENDING position in r0 */ -	rlwimi	r0,r3,32+TIF_SIGPENDING-MSR_PR_LG,_TIF_SIGPENDING -	and.	r0,r4,r0	/* check NEED_RESCHED and maybe SIGPENDING */ -	bne	do_work - -#else /* !CONFIG_PREEMPT */ -	ld	r3,_MSR(r1)	/* Returning to user mode? */  	andi.	r3,r3,MSR_PR -	beq	restore		/* if not, just restore regs and return */ +	beq	resume_kernel  	/* Check current_thread_info()->flags */ +	andi.	r0,r4,_TIF_USER_WORK_MASK +	beq	restore + +	andi.	r0,r4,_TIF_NEED_RESCHED +	beq	1f +	bl	.restore_interrupts +	bl	.schedule +	b	.ret_from_except_lite + +1:	bl	.save_nvgprs +	bl	.restore_interrupts +	addi	r3,r1,STACK_FRAME_OVERHEAD +	bl	.do_notify_resume +	b	.ret_from_except + +resume_kernel: +#ifdef CONFIG_PREEMPT +	/* Check if we need to preempt */ +	andi.	r0,r4,_TIF_NEED_RESCHED +	beq+	restore +	/* Check that preempt_count() == 0 and interrupts are enabled */ +	lwz	r8,TI_PREEMPT(r9) +	cmpwi	cr1,r8,0 +	ld	r0,SOFTE(r1) +	cmpdi	r0,0 +	crandc	eq,cr1*4+eq,eq +	bne	restore + +	/* +	 * Here we are preempting the current task. We want to make +	 * sure we are soft-disabled first +	 */ +	SOFT_DISABLE_INTS(r3,r4) +1:	bl	.preempt_schedule_irq + +	/* Re-test flags and eventually loop */  	clrrdi	r9,r1,THREAD_SHIFT  	ld	r4,TI_FLAGS(r9) -	andi.	r0,r4,_TIF_USER_WORK_MASK -	bne	do_work -#endif /* !CONFIG_PREEMPT */ +	andi.	r0,r4,_TIF_NEED_RESCHED +	bne	1b +#endif /* CONFIG_PREEMPT */  	.globl	fast_exc_return_irq  fast_exc_return_irq: @@ -759,50 +786,6 @@ restore_check_irq_replay:  #endif /* CONFIG_PPC_BOOK3E */  1:	b	.ret_from_except /* What else to do here ? */ - - -3: -do_work: -#ifdef CONFIG_PREEMPT -	andi.	r0,r3,MSR_PR	/* Returning to user mode? */ -	bne	user_work -	/* Check that preempt_count() == 0 and interrupts are enabled */ -	lwz	r8,TI_PREEMPT(r9) -	cmpwi	cr1,r8,0 -	ld	r0,SOFTE(r1) -	cmpdi	r0,0 -	crandc	eq,cr1*4+eq,eq -	bne	restore - -	/* -	 * Here we are preempting the current task. We want to make -	 * sure we are soft-disabled first -	 */ -	SOFT_DISABLE_INTS(r3,r4) -1:	bl	.preempt_schedule_irq - -	/* Re-test flags and eventually loop */ -	clrrdi	r9,r1,THREAD_SHIFT -	ld	r4,TI_FLAGS(r9) -	andi.	r0,r4,_TIF_NEED_RESCHED -	bne	1b -	b	restore - -user_work: -#endif /* CONFIG_PREEMPT */ - -	andi.	r0,r4,_TIF_NEED_RESCHED -	beq	1f -	bl	.restore_interrupts -	bl	.schedule -	b	.ret_from_except_lite - -1:	bl	.save_nvgprs -	bl	.restore_interrupts -	addi	r3,r1,STACK_FRAME_OVERHEAD -	bl	.do_notify_resume -	b	.ret_from_except -  unrecov_restore:  	addi	r3,r1,STACK_FRAME_OVERHEAD  	bl	.unrecoverable_exception diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index 7835a5e1ea5f..1f017bb7a7ce 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -229,7 +229,7 @@ notrace void arch_local_irq_restore(unsigned long en)  	 */  	if (unlikely(irq_happened != PACA_IRQ_HARD_DIS))  		__hard_irq_disable(); -#ifdef CONFIG_TRACE_IRQFLAG +#ifdef CONFIG_TRACE_IRQFLAGS  	else {  		/*  		 * We should already be hard disabled here. We had bugs @@ -277,7 +277,7 @@ EXPORT_SYMBOL(arch_local_irq_restore);   * NOTE: This is called with interrupts hard disabled but not marked   * as such in paca->irq_happened, so we need to resync this.   */ -void restore_interrupts(void) +void notrace restore_interrupts(void)  {  	if (irqs_disabled()) {  		local_paca->irq_happened |= PACA_IRQ_HARD_DIS; @@ -286,6 +286,52 @@ void restore_interrupts(void)  		__hard_irq_enable();  } +/* + * This is a helper to use when about to go into idle low-power + * when the latter has the side effect of re-enabling interrupts + * (such as calling H_CEDE under pHyp). + * + * You call this function with interrupts soft-disabled (this is + * already the case when ppc_md.power_save is called). The function + * will return whether to enter power save or just return. + * + * In the former case, it will have notified lockdep of interrupts + * being re-enabled and generally sanitized the lazy irq state, + * and in the latter case it will leave with interrupts hard + * disabled and marked as such, so the local_irq_enable() call + * in cpu_idle() will properly re-enable everything. + */ +bool prep_irq_for_idle(void) +{ +	/* +	 * First we need to hard disable to ensure no interrupt +	 * occurs before we effectively enter the low power state +	 */ +	hard_irq_disable(); + +	/* +	 * If anything happened while we were soft-disabled, +	 * we return now and do not enter the low power state. +	 */ +	if (lazy_irq_pending()) +		return false; + +	/* Tell lockdep we are about to re-enable */ +	trace_hardirqs_on(); + +	/* +	 * Mark interrupts as soft-enabled and clear the +	 * PACA_IRQ_HARD_DIS from the pending mask since we +	 * are about to hard enable as well as a side effect +	 * of entering the low power state. +	 */ +	local_paca->irq_happened &= ~PACA_IRQ_HARD_DIS; +	local_paca->soft_enabled = 1; + +	/* Tell the caller to enter the low power state */ +	return true; +} +  #endif /* CONFIG_PPC64 */  int arch_show_interrupts(struct seq_file *p, int prec) diff --git a/arch/powerpc/kernel/module_32.c b/arch/powerpc/kernel/module_32.c index 0b6d79617d7b..2e3200ca485f 100644 --- a/arch/powerpc/kernel/module_32.c +++ b/arch/powerpc/kernel/module_32.c @@ -176,8 +176,8 @@ int module_frob_arch_sections(Elf32_Ehdr *hdr,  static inline int entry_matches(struct ppc_plt_entry *entry, Elf32_Addr val)  { -	if (entry->jump[0] == 0x3d600000 + ((val + 0x8000) >> 16) -	    && entry->jump[1] == 0x396b0000 + (val & 0xffff)) +	if (entry->jump[0] == 0x3d800000 + ((val + 0x8000) >> 16) +	    && entry->jump[1] == 0x398c0000 + (val & 0xffff))  		return 1;  	return 0;  } @@ -204,10 +204,9 @@ static uint32_t do_plt_call(void *location,  		entry++;  	} -	/* Stolen from Paul Mackerras as well... */ -	entry->jump[0] = 0x3d600000+((val+0x8000)>>16);	/* lis r11,sym@ha */ -	entry->jump[1] = 0x396b0000 + (val&0xffff);	/* addi r11,r11,sym@l*/ -	entry->jump[2] = 0x7d6903a6;			/* mtctr r11 */ +	entry->jump[0] = 0x3d800000+((val+0x8000)>>16); /* lis r12,sym@ha */ +	entry->jump[1] = 0x398c0000 + (val&0xffff);     /* addi r12,r12,sym@l*/ +	entry->jump[2] = 0x7d8903a6;                    /* mtctr r12 */  	entry->jump[3] = 0x4e800420;			/* bctr */  	DEBUGP("Initialized plt for 0x%x at %p\n", val, entry); diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index 1b488e5305c5..0794a3017b1b 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c @@ -1312,7 +1312,7 @@ static struct opal_secondary_data {  extern char opal_secondary_entry; -static void prom_query_opal(void) +static void __init prom_query_opal(void)  {  	long rc; @@ -1436,7 +1436,7 @@ static void __init prom_opal_hold_cpus(void)  	prom_debug("prom_opal_hold_cpus: end...\n");  } -static void prom_opal_takeover(void) +static void __init prom_opal_takeover(void)  {  	struct opal_secondary_data *data = &RELOC(opal_secondary_data);  	struct opal_takeover_args *args = &data->args; diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index 99a995c2a3f2..be171ee73bf8 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c @@ -475,6 +475,7 @@ void timer_interrupt(struct pt_regs * regs)  	struct pt_regs *old_regs;  	u64 *next_tb = &__get_cpu_var(decrementers_next_tb);  	struct clock_event_device *evt = &__get_cpu_var(decrementers); +	u64 now;  	/* Ensure a positive value is written to the decrementer, or else  	 * some CPUs will continue to take decrementer exceptions. @@ -509,9 +510,16 @@ void timer_interrupt(struct pt_regs * regs)  		irq_work_run();  	} -	*next_tb = ~(u64)0; -	if (evt->event_handler) -		evt->event_handler(evt); +	now = get_tb_or_rtc(); +	if (now >= *next_tb) { +		*next_tb = ~(u64)0; +		if (evt->event_handler) +			evt->event_handler(evt); +	} else { +		now = *next_tb - now; +		if (now <= DECREMENTER_MAX) +			set_dec((int)now); +	}  #ifdef CONFIG_PPC64  	/* collect purr register values often, for accurate calculations */  | 
