From: Christoph Hellwig <hch@lst.de>

This code is the same for all architectures with the following invariants:

- arm gurantees irqs are disabled when calling irq_exit so it can call
  __do_softirq directly instead of do_softirq

- arm26 is totally broken for about half a year, I didn't care for it

- some architectures use softirq_pending(smp_processor_id()) instead of
  local_softirq_pending, but they always evaluate to the same

This patch moves the out of line irq_exit implementation from
kernel/irq/handle.c which depends on CONFIG_GENERIC_HARDIRQS to
kernel/softirq.c which is always compiled, tweaks it for the arm special
case and moves the irq_enter/irq_exit/nmi_enter/nmi_exit bits from
asm-*/hardirq.h to linux/hardirq.h

Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 25-akpm/arch/ia64/kernel/irq_ia64.c     |   15 ---------------
 25-akpm/include/asm-alpha/hardirq.h     |   10 ----------
 25-akpm/include/asm-arm/hardirq.h       |   12 +-----------
 25-akpm/include/asm-arm26/hardirq.h     |   13 -------------
 25-akpm/include/asm-cris/hardirq.h      |    9 ---------
 25-akpm/include/asm-h8300/hardirq.h     |    9 ---------
 25-akpm/include/asm-m32r/hardirq.h      |   12 ------------
 25-akpm/include/asm-m68k/hardirq.h      |    9 ---------
 25-akpm/include/asm-m68knommu/hardirq.h |    9 ---------
 25-akpm/include/asm-parisc/hardirq.h    |    9 ---------
 25-akpm/include/asm-s390/hardirq.h      |   16 +---------------
 25-akpm/include/asm-sh/hardirq.h        |   12 ------------
 25-akpm/include/asm-sparc/hardirq.h     |    9 ---------
 25-akpm/include/asm-sparc64/hardirq.h   |    9 ---------
 25-akpm/include/asm-v850/hardirq.h      |    9 ---------
 25-akpm/include/linux/hardirq.h         |    2 --
 25-akpm/kernel/irq/handle.c             |   11 -----------
 25-akpm/kernel/softirq.c                |   17 +++++++++++++++++
 18 files changed, 19 insertions(+), 173 deletions(-)

diff -puN arch/ia64/kernel/irq_ia64.c~move-irq_enter-and-irq_exit-to-common-code arch/ia64/kernel/irq_ia64.c
--- 25/arch/ia64/kernel/irq_ia64.c~move-irq_enter-and-irq_exit-to-common-code	Mon Nov 29 13:15:52 2004
+++ 25-akpm/arch/ia64/kernel/irq_ia64.c	Mon Nov 29 13:15:52 2004
@@ -60,21 +60,6 @@ __u8 isa_irq_to_vector_map[16] = {
 };
 EXPORT_SYMBOL(isa_irq_to_vector_map);
 
-static inline void
-irq_enter (void)
-{
-	preempt_count() += HARDIRQ_OFFSET;
-}
-
-static inline void
-irq_exit (void)
-{
-	preempt_count() -= IRQ_EXIT_OFFSET;
-	if (!in_interrupt() && local_softirq_pending())
-		do_softirq();
-	preempt_enable_no_resched();
-}
-
 int
 assign_irq_vector (int irq)
 {
diff -puN include/asm-alpha/hardirq.h~move-irq_enter-and-irq_exit-to-common-code include/asm-alpha/hardirq.h
--- 25/include/asm-alpha/hardirq.h~move-irq_enter-and-irq_exit-to-common-code	Mon Nov 29 13:15:52 2004
+++ 25-akpm/include/asm-alpha/hardirq.h	Mon Nov 29 13:15:52 2004
@@ -29,14 +29,4 @@ typedef struct {
 #error HARDIRQ_BITS is too low!
 #endif
 
-#define irq_enter()		(preempt_count() += HARDIRQ_OFFSET)
-#define irq_exit()						\
-do {								\
-		preempt_count() -= IRQ_EXIT_OFFSET;		\
-		if (!in_interrupt() &&				\
-		    softirq_pending(smp_processor_id()))	\
-			do_softirq();				\
-		preempt_enable_no_resched();			\
-} while (0)
-
 #endif /* _ALPHA_HARDIRQ_H */
diff -puN include/asm-arm26/hardirq.h~move-irq_enter-and-irq_exit-to-common-code include/asm-arm26/hardirq.h
--- 25/include/asm-arm26/hardirq.h~move-irq_enter-and-irq_exit-to-common-code	Mon Nov 29 13:15:52 2004
+++ 25-akpm/include/asm-arm26/hardirq.h	Mon Nov 29 13:15:52 2004
@@ -26,17 +26,4 @@ typedef struct {
 # error HARDIRQ_BITS is too low!
 #endif
 
-#define irq_enter()		(preempt_count() += HARDIRQ_OFFSET)
-
-#ifndef CONFIG_SMP
-#define irq_exit()							\
-	do {								\
-		preempt_count() -= HARDIRQ_OFFSET;			\
-		if (!in_interrupt() && softirq_pending(smp_processor_id())) \
-			__asm__("bl%? __do_softirq": : : "lr");/* out of line */\
-		preempt_enable_no_resched();				\
-	} while (0)
-
-#endif
-
 #endif /* __ASM_HARDIRQ_H */
diff -puN include/asm-arm/hardirq.h~move-irq_enter-and-irq_exit-to-common-code include/asm-arm/hardirq.h
--- 25/include/asm-arm/hardirq.h~move-irq_enter-and-irq_exit-to-common-code	Mon Nov 29 13:15:52 2004
+++ 25-akpm/include/asm-arm/hardirq.h	Mon Nov 29 13:15:52 2004
@@ -27,16 +27,6 @@ typedef struct {
 # error HARDIRQ_BITS is too low!
 #endif
 
-#define irq_enter()		(preempt_count() += HARDIRQ_OFFSET)
-
-extern asmlinkage void __do_softirq(void);
-
-#define irq_exit()							\
-	do {								\
-		preempt_count() -= IRQ_EXIT_OFFSET;			\
-		if (!in_interrupt() && local_softirq_pending())		\
-			__do_softirq();					\
-		preempt_enable_no_resched();				\
-	} while (0)
+#define __ARCH_IRQ_EXIT_IRQS_DISABLED	1
 
 #endif /* __ASM_HARDIRQ_H */
diff -puN include/asm-cris/hardirq.h~move-irq_enter-and-irq_exit-to-common-code include/asm-cris/hardirq.h
--- 25/include/asm-cris/hardirq.h~move-irq_enter-and-irq_exit-to-common-code	Mon Nov 29 13:15:52 2004
+++ 25-akpm/include/asm-cris/hardirq.h	Mon Nov 29 13:15:52 2004
@@ -28,13 +28,4 @@ typedef struct {
 # error HARDIRQ_BITS is too low!
 #endif
 
-#define irq_enter()		(preempt_count() += HARDIRQ_OFFSET)
-#define irq_exit()							\
-do {									\
-		preempt_count() -= IRQ_EXIT_OFFSET;			\
-		if (!in_interrupt() && softirq_pending(smp_processor_id())) \
-			do_softirq();					\
-		preempt_enable_no_resched();				\
-} while (0)
-
 #endif /* __ASM_HARDIRQ_H */
diff -puN include/asm-h8300/hardirq.h~move-irq_enter-and-irq_exit-to-common-code include/asm-h8300/hardirq.h
--- 25/include/asm-h8300/hardirq.h~move-irq_enter-and-irq_exit-to-common-code	Mon Nov 29 13:15:52 2004
+++ 25-akpm/include/asm-h8300/hardirq.h	Mon Nov 29 13:15:52 2004
@@ -26,13 +26,4 @@ typedef struct {
 # error HARDIRQ_BITS is too low!
 #endif
 
-#define irq_enter()		(preempt_count() += HARDIRQ_OFFSET)
-#define irq_exit()							\
-do {									\
-		preempt_count() -= IRQ_EXIT_OFFSET;			\
-		if (!in_interrupt() && softirq_pending(smp_processor_id())) \
-			do_softirq();					\
-		preempt_enable_no_resched();				\
-} while (0)
-
 #endif
diff -puN include/asm-m32r/hardirq.h~move-irq_enter-and-irq_exit-to-common-code include/asm-m32r/hardirq.h
--- 25/include/asm-m32r/hardirq.h~move-irq_enter-and-irq_exit-to-common-code	Mon Nov 29 13:15:52 2004
+++ 25-akpm/include/asm-m32r/hardirq.h	Mon Nov 29 13:15:52 2004
@@ -28,16 +28,4 @@ typedef struct {
 # error HARDIRQ_BITS is too low!
 #endif
 
-#define irq_enter()		(preempt_count() += HARDIRQ_OFFSET)
-#define nmi_enter()		(irq_enter())
-#define nmi_exit()		(preempt_count() -= HARDIRQ_OFFSET)
-
-#define irq_exit()							\
-do {									\
-		preempt_count() -= IRQ_EXIT_OFFSET;			\
-		if (!in_interrupt() && softirq_pending(smp_processor_id())) \
-			do_softirq();					\
-		preempt_enable_no_resched();				\
-} while (0)
-
 #endif /* __ASM_HARDIRQ_H */
diff -puN include/asm-m68k/hardirq.h~move-irq_enter-and-irq_exit-to-common-code include/asm-m68k/hardirq.h
--- 25/include/asm-m68k/hardirq.h~move-irq_enter-and-irq_exit-to-common-code	Mon Nov 29 13:15:52 2004
+++ 25-akpm/include/asm-m68k/hardirq.h	Mon Nov 29 13:15:52 2004
@@ -23,13 +23,4 @@ typedef struct {
 # error HARDIRQ_BITS is too low!
 #endif
 
-#define irq_enter()		(preempt_count() += HARDIRQ_OFFSET)
-#define irq_exit()							\
-do {									\
-		preempt_count() -= IRQ_EXIT_OFFSET;			\
-		if (!in_interrupt() && softirq_pending(smp_processor_id())) \
-			do_softirq();					\
-		preempt_enable_no_resched();				\
-} while (0)
-
 #endif
diff -puN include/asm-m68knommu/hardirq.h~move-irq_enter-and-irq_exit-to-common-code include/asm-m68knommu/hardirq.h
--- 25/include/asm-m68knommu/hardirq.h~move-irq_enter-and-irq_exit-to-common-code	Mon Nov 29 13:15:52 2004
+++ 25-akpm/include/asm-m68knommu/hardirq.h	Mon Nov 29 13:15:52 2004
@@ -24,13 +24,4 @@ typedef struct {
 # error HARDIRQ_BITS is too low!
 #endif
 
-#define irq_enter()		(preempt_count() += HARDIRQ_OFFSET)
-#define irq_exit()							\
-do {									\
-		preempt_count() -= IRQ_EXIT_OFFSET;			\
-		if (!in_interrupt() && softirq_pending(smp_processor_id())) \
-			do_softirq();					\
-		preempt_enable_no_resched();				\
-} while (0)
-
 #endif /* __M68K_HARDIRQ_H */
diff -puN include/asm-parisc/hardirq.h~move-irq_enter-and-irq_exit-to-common-code include/asm-parisc/hardirq.h
--- 25/include/asm-parisc/hardirq.h~move-irq_enter-and-irq_exit-to-common-code	Mon Nov 29 13:15:52 2004
+++ 25-akpm/include/asm-parisc/hardirq.h	Mon Nov 29 13:15:52 2004
@@ -38,13 +38,4 @@ typedef struct {
 # error HARDIRQ_BITS is too low!
 #endif
 
-#define irq_enter()		(preempt_count() += HARDIRQ_OFFSET)
-#define irq_exit()								\
-do {										\
-		preempt_count() -= IRQ_EXIT_OFFSET;				\
-		if (!in_interrupt() && softirq_pending(smp_processor_id()))	\
-			do_softirq();						\
-		preempt_enable_no_resched();					\
-} while (0)
-
 #endif /* _PARISC_HARDIRQ_H */
diff -puN include/asm-s390/hardirq.h~move-irq_enter-and-irq_exit-to-common-code include/asm-s390/hardirq.h
--- 25/include/asm-s390/hardirq.h~move-irq_enter-and-irq_exit-to-common-code	Mon Nov 29 13:15:52 2004
+++ 25-akpm/include/asm-s390/hardirq.h	Mon Nov 29 13:15:52 2004
@@ -37,24 +37,10 @@ softirq_pending(unsigned int cpu)
 }
 
 #define __ARCH_IRQ_STAT
+#define __ARCH_HAS_DO_SOFTIRQ
 
 #define HARDIRQ_BITS	8
 
 extern void account_ticks(struct pt_regs *);
 
-#define __ARCH_HAS_DO_SOFTIRQ
-
-#define irq_enter()							\
-do {									\
-	(preempt_count() += HARDIRQ_OFFSET);				\
-} while(0)
-#define irq_exit()							\
-do {									\
-	preempt_count() -= IRQ_EXIT_OFFSET;				\
-	if (!in_interrupt() && local_softirq_pending())			\
-		/* Use the async. stack for softirq */			\
-		do_softirq();						\
-	preempt_enable_no_resched();					\
-} while (0)
-
 #endif /* __ASM_HARDIRQ_H */
diff -puN include/asm-sh/hardirq.h~move-irq_enter-and-irq_exit-to-common-code include/asm-sh/hardirq.h
--- 25/include/asm-sh/hardirq.h~move-irq_enter-and-irq_exit-to-common-code	Mon Nov 29 13:15:52 2004
+++ 25-akpm/include/asm-sh/hardirq.h	Mon Nov 29 13:15:52 2004
@@ -23,16 +23,4 @@ typedef struct {
 # error HARDIRQ_BITS is too low!
 #endif
 
-#define nmi_enter()		(irq_enter())
-#define nmi_exit()		(preempt_count() -= HARDIRQ_OFFSET)
-
-#define irq_enter()		(preempt_count() += HARDIRQ_OFFSET)
-#define irq_exit()							\
-do {									\
-		preempt_count() -= IRQ_EXIT_OFFSET;			\
-		if (!in_interrupt() && softirq_pending(smp_processor_id())) \
-			do_softirq();					\
-		preempt_enable_no_resched();				\
-} while (0)
-
 #endif /* __ASM_SH_HARDIRQ_H */
diff -puN include/asm-sparc64/hardirq.h~move-irq_enter-and-irq_exit-to-common-code include/asm-sparc64/hardirq.h
--- 25/include/asm-sparc64/hardirq.h~move-irq_enter-and-irq_exit-to-common-code	Mon Nov 29 13:15:52 2004
+++ 25-akpm/include/asm-sparc64/hardirq.h	Mon Nov 29 13:15:52 2004
@@ -20,13 +20,4 @@ typedef struct {
 
 #define HARDIRQ_BITS	8
 
-#define irq_enter()		(preempt_count() += HARDIRQ_OFFSET)
-#define irq_exit()							\
-do {									\
-		preempt_count() -= IRQ_EXIT_OFFSET;			\
-		if (!in_interrupt() && softirq_pending(smp_processor_id())) \
-			do_softirq();					\
-		preempt_enable_no_resched();				\
-} while (0)
-
 #endif /* !(__SPARC64_HARDIRQ_H) */
diff -puN include/asm-sparc/hardirq.h~move-irq_enter-and-irq_exit-to-common-code include/asm-sparc/hardirq.h
--- 25/include/asm-sparc/hardirq.h~move-irq_enter-and-irq_exit-to-common-code	Mon Nov 29 13:15:52 2004
+++ 25-akpm/include/asm-sparc/hardirq.h	Mon Nov 29 13:15:52 2004
@@ -21,13 +21,4 @@ typedef struct {
 
 #define HARDIRQ_BITS    8
 
-#define irq_enter()             (preempt_count() += HARDIRQ_OFFSET)
-#define irq_exit()                                                      \
-do {                                                                    \
-                preempt_count() -= IRQ_EXIT_OFFSET;                     \
-                if (!in_interrupt() && softirq_pending(smp_processor_id())) \
-                        do_softirq();                                   \
-                preempt_enable_no_resched();                            \
-} while (0)
-
 #endif /* __SPARC_HARDIRQ_H */
diff -puN include/asm-v850/hardirq.h~move-irq_enter-and-irq_exit-to-common-code include/asm-v850/hardirq.h
--- 25/include/asm-v850/hardirq.h~move-irq_enter-and-irq_exit-to-common-code	Mon Nov 29 13:15:52 2004
+++ 25-akpm/include/asm-v850/hardirq.h	Mon Nov 29 13:15:52 2004
@@ -24,13 +24,4 @@ typedef struct {
 # error HARDIRQ_BITS is too low!
 #endif
 
-#define irq_enter()		(preempt_count() += HARDIRQ_OFFSET)
-#define irq_exit()							      \
-do {									      \
-	preempt_count() -= IRQ_EXIT_OFFSET;				      \
-	if (!in_interrupt() && softirq_pending(smp_processor_id()))	      \
-		do_softirq();						      \
-	preempt_enable_no_resched();					      \
-} while (0)
-
 #endif /* __V850_HARDIRQ_H__ */
diff -puN include/linux/hardirq.h~move-irq_enter-and-irq_exit-to-common-code include/linux/hardirq.h
--- 25/include/linux/hardirq.h~move-irq_enter-and-irq_exit-to-common-code	Mon Nov 29 13:15:52 2004
+++ 25-akpm/include/linux/hardirq.h	Mon Nov 29 13:15:52 2004
@@ -77,12 +77,10 @@ extern void synchronize_irq(unsigned int
 # define synchronize_irq(irq)	barrier()
 #endif
 
-#ifdef CONFIG_GENERIC_HARDIRQS
 #define nmi_enter()		(preempt_count() += HARDIRQ_OFFSET)
 #define nmi_exit()		(preempt_count() -= HARDIRQ_OFFSET)
 
 #define irq_enter()		(preempt_count() += HARDIRQ_OFFSET)
 extern void irq_exit(void);
-#endif
 
 #endif /* LINUX_HARDIRQ_H */
diff -puN kernel/irq/handle.c~move-irq_enter-and-irq_exit-to-common-code kernel/irq/handle.c
--- 25/kernel/irq/handle.c~move-irq_enter-and-irq_exit-to-common-code	Mon Nov 29 13:15:52 2004
+++ 25-akpm/kernel/irq/handle.c	Mon Nov 29 13:15:52 2004
@@ -73,17 +73,6 @@ irqreturn_t no_action(int cpl, void *dev
 }
 
 /*
- * Exit an interrupt context. Process softirqs if needed and possible:
- */
-void irq_exit(void)
-{
-	preempt_count() -= IRQ_EXIT_OFFSET;
-	if (!in_interrupt() && local_softirq_pending())
-		do_softirq();
-	preempt_enable_no_resched();
-}
-
-/*
  * Have got an event to handle:
  */
 fastcall int handle_IRQ_event(unsigned int irq, struct pt_regs *regs,
diff -puN kernel/softirq.c~move-irq_enter-and-irq_exit-to-common-code kernel/softirq.c
--- 25/kernel/softirq.c~move-irq_enter-and-irq_exit-to-common-code	Mon Nov 29 13:15:52 2004
+++ 25-akpm/kernel/softirq.c	Mon Nov 29 13:15:52 2004
@@ -152,6 +152,23 @@ void local_bh_enable(void)
 }
 EXPORT_SYMBOL(local_bh_enable);
 
+#ifdef __ARCH_IRQ_EXIT_IRQS_DISABLED
+# define invoke_softirq()	__do_softirq()
+#else
+# define invoke_softirq()	do_softirq()
+#endif
+
+/*
+ * Exit an interrupt context. Process softirqs if needed and possible:
+ */
+void irq_exit(void)
+{
+	preempt_count() -= IRQ_EXIT_OFFSET;
+	if (!in_interrupt() && local_softirq_pending())
+		invoke_softirq();
+	preempt_enable_no_resched();
+}
+
 /*
  * This function must run with irqs disabled!
  */
_