Эх сурвалжийг харах

Merge branch 'parisc-for-3.10' of git://git.kernel.org/pub/scm/linux/kernel/git/deller/parisc-linux

Pull parisc update from Helge Deller:
 "The second round of parisc updates for 3.10 includes build fixes and
  enhancements to utilize irq stacks, fixes SMP races when updating PTE
  and TLB entries by proper locking and makes the search for the correct
  cross compiler more robust on Debian and Gentoo."

* 'parisc-for-3.10' of git://git.kernel.org/pub/scm/linux/kernel/git/deller/parisc-linux:
  parisc: make default cross compiler search more robust (v3)
  parisc: fix SMP races when updating PTE and TLB entries in entry.S
  parisc: implement irq stacks - part 2 (v2)
Linus Torvalds 12 жил өмнө
parent
commit
c83bb88589

+ 1 - 1
arch/parisc/Kconfig

@@ -245,7 +245,7 @@ config SMP
 
 
 config IRQSTACKS
 config IRQSTACKS
 	bool "Use separate kernel stacks when processing interrupts"
 	bool "Use separate kernel stacks when processing interrupts"
-	default n
+	default y
 	help
 	help
 	  If you say Y here the kernel will use separate kernel stacks
 	  If you say Y here the kernel will use separate kernel stacks
 	  for handling hard and soft interrupts.  This can help avoid
 	  for handling hard and soft interrupts.  This can help avoid

+ 9 - 12
arch/parisc/Makefile

@@ -23,24 +23,21 @@ NM		= sh $(srctree)/arch/parisc/nm
 CHECKFLAGS	+= -D__hppa__=1
 CHECKFLAGS	+= -D__hppa__=1
 LIBGCC		= $(shell $(CC) $(KBUILD_CFLAGS) -print-libgcc-file-name)
 LIBGCC		= $(shell $(CC) $(KBUILD_CFLAGS) -print-libgcc-file-name)
 
 
-MACHINE		:= $(shell uname -m)
-NATIVE		:= $(if $(filter parisc%,$(MACHINE)),1,0)
-
 ifdef CONFIG_64BIT
 ifdef CONFIG_64BIT
 UTS_MACHINE	:= parisc64
 UTS_MACHINE	:= parisc64
 CHECKFLAGS	+= -D__LP64__=1 -m64
 CHECKFLAGS	+= -D__LP64__=1 -m64
-WIDTH		:= 64
+CC_ARCHES	= hppa64
 else # 32-bit
 else # 32-bit
-WIDTH		:=
+CC_ARCHES	= hppa hppa2.0 hppa1.1
 endif
 endif
 
 
-# attempt to help out folks who are cross-compiling
-ifeq ($(NATIVE),1)
-CROSS_COMPILE	:= hppa$(WIDTH)-linux-
-else
- ifeq ($(CROSS_COMPILE),)
- CROSS_COMPILE	:= hppa$(WIDTH)-linux-gnu-
- endif
+ifneq ($(SUBARCH),$(UTS_MACHINE))
+	ifeq ($(CROSS_COMPILE),)
+		CC_SUFFIXES = linux linux-gnu unknown-linux-gnu
+		CROSS_COMPILE := $(call cc-cross-prefix, \
+			$(foreach a,$(CC_ARCHES), \
+			$(foreach s,$(CC_SUFFIXES),$(a)-$(s)-)))
+	endif
 endif
 endif
 
 
 OBJCOPY_FLAGS =-O binary -R .note -R .comment -S
 OBJCOPY_FLAGS =-O binary -R .note -R .comment -S

+ 9 - 0
arch/parisc/include/asm/hardirq.h

@@ -11,10 +11,18 @@
 #include <linux/threads.h>
 #include <linux/threads.h>
 #include <linux/irq.h>
 #include <linux/irq.h>
 
 
+#ifdef CONFIG_IRQSTACKS
+#define __ARCH_HAS_DO_SOFTIRQ
+#endif
+
 typedef struct {
 typedef struct {
 	unsigned int __softirq_pending;
 	unsigned int __softirq_pending;
 #ifdef CONFIG_DEBUG_STACKOVERFLOW
 #ifdef CONFIG_DEBUG_STACKOVERFLOW
 	unsigned int kernel_stack_usage;
 	unsigned int kernel_stack_usage;
+#ifdef CONFIG_IRQSTACKS
+	unsigned int irq_stack_usage;
+	unsigned int irq_stack_counter;
+#endif
 #endif
 #endif
 #ifdef CONFIG_SMP
 #ifdef CONFIG_SMP
 	unsigned int irq_resched_count;
 	unsigned int irq_resched_count;
@@ -28,6 +36,7 @@ DECLARE_PER_CPU_SHARED_ALIGNED(irq_cpustat_t, irq_stat);
 #define __ARCH_IRQ_STAT
 #define __ARCH_IRQ_STAT
 #define __IRQ_STAT(cpu, member) (irq_stat[cpu].member)
 #define __IRQ_STAT(cpu, member) (irq_stat[cpu].member)
 #define inc_irq_stat(member)	this_cpu_inc(irq_stat.member)
 #define inc_irq_stat(member)	this_cpu_inc(irq_stat.member)
+#define __inc_irq_stat(member)	__this_cpu_inc(irq_stat.member)
 #define local_softirq_pending()	this_cpu_read(irq_stat.__softirq_pending)
 #define local_softirq_pending()	this_cpu_read(irq_stat.__softirq_pending)
 
 
 #define __ARCH_SET_SOFTIRQ_PENDING
 #define __ARCH_SET_SOFTIRQ_PENDING

+ 3 - 0
arch/parisc/include/asm/processor.h

@@ -63,10 +63,13 @@
  */
  */
 #ifdef __KERNEL__
 #ifdef __KERNEL__
 
 
+#include <linux/spinlock_types.h>
+
 #define IRQ_STACK_SIZE      (4096 << 2) /* 16k irq stack size */
 #define IRQ_STACK_SIZE      (4096 << 2) /* 16k irq stack size */
 
 
 union irq_stack_union {
 union irq_stack_union {
 	unsigned long stack[IRQ_STACK_SIZE/sizeof(unsigned long)];
 	unsigned long stack[IRQ_STACK_SIZE/sizeof(unsigned long)];
+	raw_spinlock_t lock;
 };
 };
 
 
 DECLARE_PER_CPU(union irq_stack_union, irq_stack_union);
 DECLARE_PER_CPU(union irq_stack_union, irq_stack_union);

+ 83 - 72
arch/parisc/kernel/entry.S

@@ -452,9 +452,41 @@
 	L2_ptep		\pgd,\pte,\index,\va,\fault
 	L2_ptep		\pgd,\pte,\index,\va,\fault
 	.endm
 	.endm
 
 
+	/* Acquire pa_dbit_lock lock. */
+	.macro		dbit_lock	spc,tmp,tmp1
+#ifdef CONFIG_SMP
+	cmpib,COND(=),n	0,\spc,2f
+	load32		PA(pa_dbit_lock),\tmp
+1:	LDCW		0(\tmp),\tmp1
+	cmpib,COND(=)	0,\tmp1,1b
+	nop
+2:
+#endif
+	.endm
+
+	/* Release pa_dbit_lock lock without reloading lock address. */
+	.macro		dbit_unlock0	spc,tmp
+#ifdef CONFIG_SMP
+	or,COND(=)	%r0,\spc,%r0
+	stw             \spc,0(\tmp)
+#endif
+	.endm
+
+	/* Release pa_dbit_lock lock. */
+	.macro		dbit_unlock1	spc,tmp
+#ifdef CONFIG_SMP
+	load32		PA(pa_dbit_lock),\tmp
+	dbit_unlock0	\spc,\tmp
+#endif
+	.endm
+
 	/* Set the _PAGE_ACCESSED bit of the PTE.  Be clever and
 	/* Set the _PAGE_ACCESSED bit of the PTE.  Be clever and
 	 * don't needlessly dirty the cache line if it was already set */
 	 * don't needlessly dirty the cache line if it was already set */
-	.macro		update_ptep	ptep,pte,tmp,tmp1
+	.macro		update_ptep	spc,ptep,pte,tmp,tmp1
+#ifdef CONFIG_SMP
+	or,COND(=)	%r0,\spc,%r0
+	LDREG		0(\ptep),\pte
+#endif
 	ldi		_PAGE_ACCESSED,\tmp1
 	ldi		_PAGE_ACCESSED,\tmp1
 	or		\tmp1,\pte,\tmp
 	or		\tmp1,\pte,\tmp
 	and,COND(<>)	\tmp1,\pte,%r0
 	and,COND(<>)	\tmp1,\pte,%r0
@@ -463,7 +495,11 @@
 
 
 	/* Set the dirty bit (and accessed bit).  No need to be
 	/* Set the dirty bit (and accessed bit).  No need to be
 	 * clever, this is only used from the dirty fault */
 	 * clever, this is only used from the dirty fault */
-	.macro		update_dirty	ptep,pte,tmp
+	.macro		update_dirty	spc,ptep,pte,tmp
+#ifdef CONFIG_SMP
+	or,COND(=)	%r0,\spc,%r0
+	LDREG		0(\ptep),\pte
+#endif
 	ldi		_PAGE_ACCESSED|_PAGE_DIRTY,\tmp
 	ldi		_PAGE_ACCESSED|_PAGE_DIRTY,\tmp
 	or		\tmp,\pte,\pte
 	or		\tmp,\pte,\pte
 	STREG		\pte,0(\ptep)
 	STREG		\pte,0(\ptep)
@@ -1111,11 +1147,13 @@ dtlb_miss_20w:
 
 
 	L3_ptep		ptp,pte,t0,va,dtlb_check_alias_20w
 	L3_ptep		ptp,pte,t0,va,dtlb_check_alias_20w
 
 
-	update_ptep	ptp,pte,t0,t1
+	dbit_lock	spc,t0,t1
+	update_ptep	spc,ptp,pte,t0,t1
 
 
 	make_insert_tlb	spc,pte,prot
 	make_insert_tlb	spc,pte,prot
 	
 	
 	idtlbt          pte,prot
 	idtlbt          pte,prot
+	dbit_unlock1	spc,t0
 
 
 	rfir
 	rfir
 	nop
 	nop
@@ -1135,11 +1173,13 @@ nadtlb_miss_20w:
 
 
 	L3_ptep		ptp,pte,t0,va,nadtlb_check_alias_20w
 	L3_ptep		ptp,pte,t0,va,nadtlb_check_alias_20w
 
 
-	update_ptep	ptp,pte,t0,t1
+	dbit_lock	spc,t0,t1
+	update_ptep	spc,ptp,pte,t0,t1
 
 
 	make_insert_tlb	spc,pte,prot
 	make_insert_tlb	spc,pte,prot
 
 
 	idtlbt          pte,prot
 	idtlbt          pte,prot
+	dbit_unlock1	spc,t0
 
 
 	rfir
 	rfir
 	nop
 	nop
@@ -1161,7 +1201,8 @@ dtlb_miss_11:
 
 
 	L2_ptep		ptp,pte,t0,va,dtlb_check_alias_11
 	L2_ptep		ptp,pte,t0,va,dtlb_check_alias_11
 
 
-	update_ptep	ptp,pte,t0,t1
+	dbit_lock	spc,t0,t1
+	update_ptep	spc,ptp,pte,t0,t1
 
 
 	make_insert_tlb_11	spc,pte,prot
 	make_insert_tlb_11	spc,pte,prot
 
 
@@ -1172,6 +1213,7 @@ dtlb_miss_11:
 	idtlbp		prot,(%sr1,va)
 	idtlbp		prot,(%sr1,va)
 
 
 	mtsp		t0, %sr1	/* Restore sr1 */
 	mtsp		t0, %sr1	/* Restore sr1 */
+	dbit_unlock1	spc,t0
 
 
 	rfir
 	rfir
 	nop
 	nop
@@ -1192,7 +1234,8 @@ nadtlb_miss_11:
 
 
 	L2_ptep		ptp,pte,t0,va,nadtlb_check_alias_11
 	L2_ptep		ptp,pte,t0,va,nadtlb_check_alias_11
 
 
-	update_ptep	ptp,pte,t0,t1
+	dbit_lock	spc,t0,t1
+	update_ptep	spc,ptp,pte,t0,t1
 
 
 	make_insert_tlb_11	spc,pte,prot
 	make_insert_tlb_11	spc,pte,prot
 
 
@@ -1204,6 +1247,7 @@ nadtlb_miss_11:
 	idtlbp		prot,(%sr1,va)
 	idtlbp		prot,(%sr1,va)
 
 
 	mtsp		t0, %sr1	/* Restore sr1 */
 	mtsp		t0, %sr1	/* Restore sr1 */
+	dbit_unlock1	spc,t0
 
 
 	rfir
 	rfir
 	nop
 	nop
@@ -1224,13 +1268,15 @@ dtlb_miss_20:
 
 
 	L2_ptep		ptp,pte,t0,va,dtlb_check_alias_20
 	L2_ptep		ptp,pte,t0,va,dtlb_check_alias_20
 
 
-	update_ptep	ptp,pte,t0,t1
+	dbit_lock	spc,t0,t1
+	update_ptep	spc,ptp,pte,t0,t1
 
 
 	make_insert_tlb	spc,pte,prot
 	make_insert_tlb	spc,pte,prot
 
 
 	f_extend	pte,t0
 	f_extend	pte,t0
 
 
 	idtlbt          pte,prot
 	idtlbt          pte,prot
+	dbit_unlock1	spc,t0
 
 
 	rfir
 	rfir
 	nop
 	nop
@@ -1250,13 +1296,15 @@ nadtlb_miss_20:
 
 
 	L2_ptep		ptp,pte,t0,va,nadtlb_check_alias_20
 	L2_ptep		ptp,pte,t0,va,nadtlb_check_alias_20
 
 
-	update_ptep	ptp,pte,t0,t1
+	dbit_lock	spc,t0,t1
+	update_ptep	spc,ptp,pte,t0,t1
 
 
 	make_insert_tlb	spc,pte,prot
 	make_insert_tlb	spc,pte,prot
 
 
 	f_extend	pte,t0
 	f_extend	pte,t0
 	
 	
         idtlbt          pte,prot
         idtlbt          pte,prot
+	dbit_unlock1	spc,t0
 
 
 	rfir
 	rfir
 	nop
 	nop
@@ -1357,11 +1405,13 @@ itlb_miss_20w:
 
 
 	L3_ptep		ptp,pte,t0,va,itlb_fault
 	L3_ptep		ptp,pte,t0,va,itlb_fault
 
 
-	update_ptep	ptp,pte,t0,t1
+	dbit_lock	spc,t0,t1
+	update_ptep	spc,ptp,pte,t0,t1
 
 
 	make_insert_tlb	spc,pte,prot
 	make_insert_tlb	spc,pte,prot
 	
 	
 	iitlbt          pte,prot
 	iitlbt          pte,prot
+	dbit_unlock1	spc,t0
 
 
 	rfir
 	rfir
 	nop
 	nop
@@ -1379,11 +1429,13 @@ naitlb_miss_20w:
 
 
 	L3_ptep		ptp,pte,t0,va,naitlb_check_alias_20w
 	L3_ptep		ptp,pte,t0,va,naitlb_check_alias_20w
 
 
-	update_ptep	ptp,pte,t0,t1
+	dbit_lock	spc,t0,t1
+	update_ptep	spc,ptp,pte,t0,t1
 
 
 	make_insert_tlb	spc,pte,prot
 	make_insert_tlb	spc,pte,prot
 
 
 	iitlbt          pte,prot
 	iitlbt          pte,prot
+	dbit_unlock1	spc,t0
 
 
 	rfir
 	rfir
 	nop
 	nop
@@ -1405,7 +1457,8 @@ itlb_miss_11:
 
 
 	L2_ptep		ptp,pte,t0,va,itlb_fault
 	L2_ptep		ptp,pte,t0,va,itlb_fault
 
 
-	update_ptep	ptp,pte,t0,t1
+	dbit_lock	spc,t0,t1
+	update_ptep	spc,ptp,pte,t0,t1
 
 
 	make_insert_tlb_11	spc,pte,prot
 	make_insert_tlb_11	spc,pte,prot
 
 
@@ -1416,6 +1469,7 @@ itlb_miss_11:
 	iitlbp		prot,(%sr1,va)
 	iitlbp		prot,(%sr1,va)
 
 
 	mtsp		t0, %sr1	/* Restore sr1 */
 	mtsp		t0, %sr1	/* Restore sr1 */
+	dbit_unlock1	spc,t0
 
 
 	rfir
 	rfir
 	nop
 	nop
@@ -1427,7 +1481,8 @@ naitlb_miss_11:
 
 
 	L2_ptep		ptp,pte,t0,va,naitlb_check_alias_11
 	L2_ptep		ptp,pte,t0,va,naitlb_check_alias_11
 
 
-	update_ptep	ptp,pte,t0,t1
+	dbit_lock	spc,t0,t1
+	update_ptep	spc,ptp,pte,t0,t1
 
 
 	make_insert_tlb_11	spc,pte,prot
 	make_insert_tlb_11	spc,pte,prot
 
 
@@ -1438,6 +1493,7 @@ naitlb_miss_11:
 	iitlbp		prot,(%sr1,va)
 	iitlbp		prot,(%sr1,va)
 
 
 	mtsp		t0, %sr1	/* Restore sr1 */
 	mtsp		t0, %sr1	/* Restore sr1 */
+	dbit_unlock1	spc,t0
 
 
 	rfir
 	rfir
 	nop
 	nop
@@ -1459,13 +1515,15 @@ itlb_miss_20:
 
 
 	L2_ptep		ptp,pte,t0,va,itlb_fault
 	L2_ptep		ptp,pte,t0,va,itlb_fault
 
 
-	update_ptep	ptp,pte,t0,t1
+	dbit_lock	spc,t0,t1
+	update_ptep	spc,ptp,pte,t0,t1
 
 
 	make_insert_tlb	spc,pte,prot
 	make_insert_tlb	spc,pte,prot
 
 
 	f_extend	pte,t0	
 	f_extend	pte,t0	
 
 
 	iitlbt          pte,prot
 	iitlbt          pte,prot
+	dbit_unlock1	spc,t0
 
 
 	rfir
 	rfir
 	nop
 	nop
@@ -1477,13 +1535,15 @@ naitlb_miss_20:
 
 
 	L2_ptep		ptp,pte,t0,va,naitlb_check_alias_20
 	L2_ptep		ptp,pte,t0,va,naitlb_check_alias_20
 
 
-	update_ptep	ptp,pte,t0,t1
+	dbit_lock	spc,t0,t1
+	update_ptep	spc,ptp,pte,t0,t1
 
 
 	make_insert_tlb	spc,pte,prot
 	make_insert_tlb	spc,pte,prot
 
 
 	f_extend	pte,t0
 	f_extend	pte,t0
 
 
 	iitlbt          pte,prot
 	iitlbt          pte,prot
+	dbit_unlock1	spc,t0
 
 
 	rfir
 	rfir
 	nop
 	nop
@@ -1507,29 +1567,13 @@ dbit_trap_20w:
 
 
 	L3_ptep		ptp,pte,t0,va,dbit_fault
 	L3_ptep		ptp,pte,t0,va,dbit_fault
 
 
-#ifdef CONFIG_SMP
-	cmpib,COND(=),n        0,spc,dbit_nolock_20w
-	load32		PA(pa_dbit_lock),t0
-
-dbit_spin_20w:
-	LDCW		0(t0),t1
-	cmpib,COND(=)         0,t1,dbit_spin_20w
-	nop
-
-dbit_nolock_20w:
-#endif
-	update_dirty	ptp,pte,t1
+	dbit_lock	spc,t0,t1
+	update_dirty	spc,ptp,pte,t1
 
 
 	make_insert_tlb	spc,pte,prot
 	make_insert_tlb	spc,pte,prot
 		
 		
 	idtlbt          pte,prot
 	idtlbt          pte,prot
-#ifdef CONFIG_SMP
-	cmpib,COND(=),n        0,spc,dbit_nounlock_20w
-	ldi             1,t1
-	stw             t1,0(t0)
-
-dbit_nounlock_20w:
-#endif
+	dbit_unlock0	spc,t0
 
 
 	rfir
 	rfir
 	nop
 	nop
@@ -1543,18 +1587,8 @@ dbit_trap_11:
 
 
 	L2_ptep		ptp,pte,t0,va,dbit_fault
 	L2_ptep		ptp,pte,t0,va,dbit_fault
 
 
-#ifdef CONFIG_SMP
-	cmpib,COND(=),n        0,spc,dbit_nolock_11
-	load32		PA(pa_dbit_lock),t0
-
-dbit_spin_11:
-	LDCW		0(t0),t1
-	cmpib,=         0,t1,dbit_spin_11
-	nop
-
-dbit_nolock_11:
-#endif
-	update_dirty	ptp,pte,t1
+	dbit_lock	spc,t0,t1
+	update_dirty	spc,ptp,pte,t1
 
 
 	make_insert_tlb_11	spc,pte,prot
 	make_insert_tlb_11	spc,pte,prot
 
 
@@ -1565,13 +1599,7 @@ dbit_nolock_11:
 	idtlbp		prot,(%sr1,va)
 	idtlbp		prot,(%sr1,va)
 
 
 	mtsp            t1, %sr1     /* Restore sr1 */
 	mtsp            t1, %sr1     /* Restore sr1 */
-#ifdef CONFIG_SMP
-	cmpib,COND(=),n        0,spc,dbit_nounlock_11
-	ldi             1,t1
-	stw             t1,0(t0)
-
-dbit_nounlock_11:
-#endif
+	dbit_unlock0	spc,t0
 
 
 	rfir
 	rfir
 	nop
 	nop
@@ -1583,32 +1611,15 @@ dbit_trap_20:
 
 
 	L2_ptep		ptp,pte,t0,va,dbit_fault
 	L2_ptep		ptp,pte,t0,va,dbit_fault
 
 
-#ifdef CONFIG_SMP
-	cmpib,COND(=),n        0,spc,dbit_nolock_20
-	load32		PA(pa_dbit_lock),t0
-
-dbit_spin_20:
-	LDCW		0(t0),t1
-	cmpib,=         0,t1,dbit_spin_20
-	nop
-
-dbit_nolock_20:
-#endif
-	update_dirty	ptp,pte,t1
+	dbit_lock	spc,t0,t1
+	update_dirty	spc,ptp,pte,t1
 
 
 	make_insert_tlb	spc,pte,prot
 	make_insert_tlb	spc,pte,prot
 
 
 	f_extend	pte,t1
 	f_extend	pte,t1
 	
 	
         idtlbt          pte,prot
         idtlbt          pte,prot
-
-#ifdef CONFIG_SMP
-	cmpib,COND(=),n        0,spc,dbit_nounlock_20
-	ldi             1,t1
-	stw             t1,0(t0)
-
-dbit_nounlock_20:
-#endif
+	dbit_unlock0	spc,t0
 
 
 	rfir
 	rfir
 	nop
 	nop

+ 87 - 14
arch/parisc/kernel/irq.c

@@ -166,22 +166,32 @@ int arch_show_interrupts(struct seq_file *p, int prec)
 	seq_printf(p, "%*s: ", prec, "STK");
 	seq_printf(p, "%*s: ", prec, "STK");
 	for_each_online_cpu(j)
 	for_each_online_cpu(j)
 		seq_printf(p, "%10u ", irq_stats(j)->kernel_stack_usage);
 		seq_printf(p, "%10u ", irq_stats(j)->kernel_stack_usage);
-	seq_printf(p, "  Kernel stack usage\n");
+	seq_puts(p, "  Kernel stack usage\n");
+# ifdef CONFIG_IRQSTACKS
+	seq_printf(p, "%*s: ", prec, "IST");
+	for_each_online_cpu(j)
+		seq_printf(p, "%10u ", irq_stats(j)->irq_stack_usage);
+	seq_puts(p, "  Interrupt stack usage\n");
+	seq_printf(p, "%*s: ", prec, "ISC");
+	for_each_online_cpu(j)
+		seq_printf(p, "%10u ", irq_stats(j)->irq_stack_counter);
+	seq_puts(p, "  Interrupt stack usage counter\n");
+# endif
 #endif
 #endif
 #ifdef CONFIG_SMP
 #ifdef CONFIG_SMP
 	seq_printf(p, "%*s: ", prec, "RES");
 	seq_printf(p, "%*s: ", prec, "RES");
 	for_each_online_cpu(j)
 	for_each_online_cpu(j)
 		seq_printf(p, "%10u ", irq_stats(j)->irq_resched_count);
 		seq_printf(p, "%10u ", irq_stats(j)->irq_resched_count);
-	seq_printf(p, "  Rescheduling interrupts\n");
+	seq_puts(p, "  Rescheduling interrupts\n");
 	seq_printf(p, "%*s: ", prec, "CAL");
 	seq_printf(p, "%*s: ", prec, "CAL");
 	for_each_online_cpu(j)
 	for_each_online_cpu(j)
 		seq_printf(p, "%10u ", irq_stats(j)->irq_call_count);
 		seq_printf(p, "%10u ", irq_stats(j)->irq_call_count);
-	seq_printf(p, "  Function call interrupts\n");
+	seq_puts(p, "  Function call interrupts\n");
 #endif
 #endif
 	seq_printf(p, "%*s: ", prec, "TLB");
 	seq_printf(p, "%*s: ", prec, "TLB");
 	for_each_online_cpu(j)
 	for_each_online_cpu(j)
 		seq_printf(p, "%10u ", irq_stats(j)->irq_tlb_count);
 		seq_printf(p, "%10u ", irq_stats(j)->irq_tlb_count);
-	seq_printf(p, "  TLB shootdowns\n");
+	seq_puts(p, "  TLB shootdowns\n");
 	return 0;
 	return 0;
 }
 }
 
 
@@ -378,6 +388,7 @@ static inline void stack_overflow_check(struct pt_regs *regs)
 	unsigned long sp = regs->gr[30];
 	unsigned long sp = regs->gr[30];
 	unsigned long stack_usage;
 	unsigned long stack_usage;
 	unsigned int *last_usage;
 	unsigned int *last_usage;
+	int cpu = smp_processor_id();
 
 
 	/* if sr7 != 0, we interrupted a userspace process which we do not want
 	/* if sr7 != 0, we interrupted a userspace process which we do not want
 	 * to check for stack overflow. We will only check the kernel stack. */
 	 * to check for stack overflow. We will only check the kernel stack. */
@@ -386,7 +397,31 @@ static inline void stack_overflow_check(struct pt_regs *regs)
 
 
 	/* calculate kernel stack usage */
 	/* calculate kernel stack usage */
 	stack_usage = sp - stack_start;
 	stack_usage = sp - stack_start;
-	last_usage = &per_cpu(irq_stat.kernel_stack_usage, smp_processor_id());
+#ifdef CONFIG_IRQSTACKS
+	if (likely(stack_usage <= THREAD_SIZE))
+		goto check_kernel_stack; /* found kernel stack */
+
+	/* check irq stack usage */
+	stack_start = (unsigned long) &per_cpu(irq_stack_union, cpu).stack;
+	stack_usage = sp - stack_start;
+
+	last_usage = &per_cpu(irq_stat.irq_stack_usage, cpu);
+	if (unlikely(stack_usage > *last_usage))
+		*last_usage = stack_usage;
+
+	if (likely(stack_usage < (IRQ_STACK_SIZE - STACK_MARGIN)))
+		return;
+
+	pr_emerg("stackcheck: %s will most likely overflow irq stack "
+		 "(sp:%lx, stk bottom-top:%lx-%lx)\n",
+		current->comm, sp, stack_start, stack_start + IRQ_STACK_SIZE);
+	goto panic_check;
+
+check_kernel_stack:
+#endif
+
+	/* check kernel stack usage */
+	last_usage = &per_cpu(irq_stat.kernel_stack_usage, cpu);
 
 
 	if (unlikely(stack_usage > *last_usage))
 	if (unlikely(stack_usage > *last_usage))
 		*last_usage = stack_usage;
 		*last_usage = stack_usage;
@@ -398,31 +433,69 @@ static inline void stack_overflow_check(struct pt_regs *regs)
 		 "(sp:%lx, stk bottom-top:%lx-%lx)\n",
 		 "(sp:%lx, stk bottom-top:%lx-%lx)\n",
 		current->comm, sp, stack_start, stack_start + THREAD_SIZE);
 		current->comm, sp, stack_start, stack_start + THREAD_SIZE);
 
 
+#ifdef CONFIG_IRQSTACKS
+panic_check:
+#endif
 	if (sysctl_panic_on_stackoverflow)
 	if (sysctl_panic_on_stackoverflow)
 		panic("low stack detected by irq handler - check messages\n");
 		panic("low stack detected by irq handler - check messages\n");
 #endif
 #endif
 }
 }
 
 
 #ifdef CONFIG_IRQSTACKS
 #ifdef CONFIG_IRQSTACKS
-DEFINE_PER_CPU(union irq_stack_union, irq_stack_union);
+DEFINE_PER_CPU(union irq_stack_union, irq_stack_union) = {
+		.lock = __RAW_SPIN_LOCK_UNLOCKED((irq_stack_union).lock)
+	};
 
 
 static void execute_on_irq_stack(void *func, unsigned long param1)
 static void execute_on_irq_stack(void *func, unsigned long param1)
 {
 {
-	unsigned long *irq_stack_start;
+	union irq_stack_union *union_ptr;
 	unsigned long irq_stack;
 	unsigned long irq_stack;
-	int cpu = smp_processor_id();
+	raw_spinlock_t *irq_stack_in_use;
 
 
-	irq_stack_start = &per_cpu(irq_stack_union, cpu).stack[0];
-	irq_stack = (unsigned long) irq_stack_start;
-	irq_stack = ALIGN(irq_stack, 16); /* align for stack frame usage */
+	union_ptr = &per_cpu(irq_stack_union, smp_processor_id());
+	irq_stack = (unsigned long) &union_ptr->stack;
+	irq_stack = ALIGN(irq_stack + sizeof(irq_stack_union.lock),
+			 64); /* align for stack frame usage */
 
 
-	BUG_ON(*irq_stack_start); /* report bug if we were called recursive. */
-	*irq_stack_start = 1;
+	/* We may be called recursive. If we are already using the irq stack,
+	 * just continue to use it. Use spinlocks to serialize
+	 * the irq stack usage.
+	 */
+	irq_stack_in_use = &union_ptr->lock;
+	if (!raw_spin_trylock(irq_stack_in_use)) {
+		void (*direct_call)(unsigned long p1) = func;
+
+		/* We are using the IRQ stack already.
+		 * Do direct call on current stack. */
+		direct_call(param1);
+		return;
+	}
 
 
 	/* This is where we switch to the IRQ stack. */
 	/* This is where we switch to the IRQ stack. */
 	call_on_stack(param1, func, irq_stack);
 	call_on_stack(param1, func, irq_stack);
 
 
-	*irq_stack_start = 0;
+	__inc_irq_stat(irq_stack_counter);
+
+	/* free up irq stack usage. */
+	do_raw_spin_unlock(irq_stack_in_use);
+}
+
+asmlinkage void do_softirq(void)
+{
+	__u32 pending;
+	unsigned long flags;
+
+	if (in_interrupt())
+		return;
+
+	local_irq_save(flags);
+
+	pending = local_softirq_pending();
+
+	if (pending)
+		execute_on_irq_stack(__do_softirq, 0);
+
+	local_irq_restore(flags);
 }
 }
 #endif /* CONFIG_IRQSTACKS */
 #endif /* CONFIG_IRQSTACKS */
 
 

+ 2 - 2
arch/parisc/mm/init.c

@@ -1069,7 +1069,7 @@ void flush_tlb_all(void)
 {
 {
 	int do_recycle;
 	int do_recycle;
 
 
-	inc_irq_stat(irq_tlb_count);
+	__inc_irq_stat(irq_tlb_count);
 	do_recycle = 0;
 	do_recycle = 0;
 	spin_lock(&sid_lock);
 	spin_lock(&sid_lock);
 	if (dirty_space_ids > RECYCLE_THRESHOLD) {
 	if (dirty_space_ids > RECYCLE_THRESHOLD) {
@@ -1090,7 +1090,7 @@ void flush_tlb_all(void)
 #else
 #else
 void flush_tlb_all(void)
 void flush_tlb_all(void)
 {
 {
-	inc_irq_stat(irq_tlb_count);
+	__inc_irq_stat(irq_tlb_count);
 	spin_lock(&sid_lock);
 	spin_lock(&sid_lock);
 	flush_tlb_all_local(NULL);
 	flush_tlb_all_local(NULL);
 	recycle_sids();
 	recycle_sids();