On 11 Feb 1999, Linus Torvalds wrote:

> which on the face of it looks sane, but you've now invalidated a really
> important rule: "orig_eax" _must_ be either a non-negative system call
> number, or negative for faults and interrupts. 

(oops, i missed that one completely.) The attached patch does this
correctly and adds a few comments, plus there are two other changes over
#1:

 - init_IO_APIC_traps() accidentally overwrote cascade and fpu, which
   changed the output of /proc/interrupts. Now it's the original again.

 - added ack_APIC() to the unexpected IRQ. an unacked IRQ will be retried
   by the IO-APIC a few times, or might hang the sender APIC completely.
   (i simulated unexpected APIC messages from other CPUs, and such unacked
   messages hung those CPU's APIC. This is why people with the problem
   saw hangs and IPI invalidate errors.)

(the unexpected IRQ phenomenon is still under investigation.) I've
compiled+booted this on UP too.

another issue: we could be a bit stricter wrt. 'spurious' device
interrupts now? During normal driver operation it's not acceptable to get
an interrupt delivered after the IRQ line is shutdown(). We have some
autodetection issues which at least in the ISA IRQ case makes it
legitimate to get IRQs on unallocated lines. Is this true for PCI drivers
too? This way we could catch a few driver bugs via printing a warning
message if an interrupt happens for an unallocated IRQ line.

-- mingo

--- linux/include/asm-i386/irq.h.orig2  Tue Feb  9 14:30:58 1999
+++ linux/include/asm-i386/irq.h        Thu Feb 11 19:17:36 1999
@@ -13,11 +13,15 @@
 #define TIMER_IRQ 0
 
 /*
- * 16 XT IRQ's, 8 potential APIC interrupt sources.
- * Right now the APIC is only used for SMP, but this
- * may change.
+ * 16 8259A IRQ's, 240 potential APIC interrupt sources.
+ * Right now the APIC is mostly only used for SMP.
+ * 256 vectors is an architectural limit. (we can have
+ * more than 256 devices theoretically, but they will
+ * have to use shared interrupts)
+ * Since vectors 0x00-0x1f are used/reserved for the CPU,
+ * the usable vector space is 0x20-0xff (224 vectors)
  */
-#define NR_IRQS 64
+#define NR_IRQS 224
 
 static __inline__ int irq_cannonicalize(int irq)
 {
--- linux/arch/i386/kernel/io_apic.c.orig2      Tue Feb  9 11:16:16 1999
+++ linux/arch/i386/kernel/io_apic.c    Thu Feb 11 20:41:22 1999
@@ -569,6 +569,9 @@
                printk("WARNING: ASSIGN_IRQ_VECTOR wrapped back to %02X\n",
                       current_vector);
        }
+       if (current_vector == SYSCALL_VECTOR)
+               panic("ran out of interrupt sources!");
+
        IO_APIC_VECTOR(irq) = current_vector;
        return current_vector;
 }
@@ -693,9 +696,11 @@
 
        printk(".... register #01: %08X\n", *(int *)&reg_01);
        printk(".......     : max redirection entries: %04X\n", reg_01.entries);
-       if (    (reg_01.entries != 0x0f) && /* ISA-only Neptune boards */
-               (reg_01.entries != 0x17) && /* ISA+PCI boards */
-               (reg_01.entries != 0x3F)    /* Xeon boards */
+       if (    (reg_01.entries != 0x0f) && /* older (Neptune) boards */
+               (reg_01.entries != 0x17) && /* typical ISA+PCI boards */
+               (reg_01.entries != 0x1b) && /* Compaq Proliant boards */
+               (reg_01.entries != 0x1f) && /* dual Xeon boards */
+               (reg_01.entries != 0x3F)    /* bigger Xeon boards */
        )
                UNEXPECTED_IO_APIC();
        if (reg_01.entries == 0x0f)
@@ -1163,7 +1168,7 @@
         * 0x80, because int 0x80 is hm, kind of importantish. ;)
         */
        for (i = 0; i < NR_IRQS ; i++) {
-               if (IO_APIC_IRQ(i)) {
+               if (IO_APIC_VECTOR(i) > 0) {
                        if (IO_APIC_irq_trigger(i))
                                irq_desc[i].handler = &ioapic_level_irq_type;
                        else
@@ -1173,8 +1178,15 @@
                         */
                        if (i < 16)
                                disable_8259A_irq(i);
-               }
+               } else
+                       /*
+                        * we have no business changing low ISA
+                        * IRQs.
+                        */
+                       if (IO_APIC_IRQ(i))
+                               irq_desc[i].handler = &no_irq_type;
        }
+       init_IRQ_SMP();
 }
 
 /*
@@ -1278,14 +1290,12 @@
                construct_default_ISA_mptable();
        }
 
-       init_IO_APIC_traps();
-
        /*
         * Set up the IO-APIC IRQ routing table by parsing the MP-BIOS
         * mptable:
         */
        setup_IO_APIC_irqs();
-       init_IRQ_SMP();
+       init_IO_APIC_traps();
        check_timer();
 
        print_IO_APIC();
--- linux/arch/i386/kernel/smp.c.orig2  Mon Feb  8 20:42:52 1999
+++ linux/arch/i386/kernel/smp.c        Thu Feb 11 19:18:59 1999
@@ -42,7 +42,7 @@
 
 #include "irq.h"
 
-extern unsigned long start_kernel, _etext;
+extern unsigned long start_kernel;
 extern void update_one_process( struct task_struct *p,
                                unsigned long ticks, unsigned long user,
                                unsigned long system, int cpu);
@@ -319,8 +319,17 @@
                                                printk("Processor #%d unused. (Max %d 
processors).\n",m->mpc_apicid, NR_CPUS);
                                        else
                                        {
+                                               int ver = m->mpc_apicver;
+
                                                cpu_present_map|=(1<<m->mpc_apicid);
-                                               
apic_version[m->mpc_apicid]=m->mpc_apicver;
+                                               /*
+                                                * Validate version
+                                                */
+                                               if (ver == 0x0) {
+                                                       printk("BIOS bug, APIC version 
+is 0 for CPU#%d! fixing up to 0x10. (tell your hw vendor)\n", m->mpc_apicid);
+                                                       ver = 0x10;
+                                               }
+                                               apic_version[m->mpc_apicid] = ver;
                                        }
                                }
                                mpt+=sizeof(*m);
@@ -1806,8 +1815,10 @@
  */
 asmlinkage void smp_spurious_interrupt(void)
 {
-       /* ack_APIC_irq();   see sw-dev-man vol 3, chapter 7.4.13.5 */
-       printk("spurious APIC interrupt, ayiee, should never happen.\n");
+       ack_APIC_irq();
+       /* see sw-dev-man vol 3, chapter 7.4.13.5 */
+       printk("spurious APIC interrupt on CPU#%d, should never happen.\n",
+                       smp_processor_id());
 }
 
 /*
--- linux/arch/i386/kernel/irq.c.orig2  Tue Feb  9 12:16:40 1999
+++ linux/arch/i386/kernel/irq.c        Thu Feb 11 20:10:43 1999
@@ -70,11 +70,34 @@
  */
 spinlock_t irq_controller_lock;
 
-
 /*
  * Dummy controller type for unused interrupts
  */
-static void do_none(unsigned int irq, struct pt_regs * regs) { }
+static void do_none(unsigned int irq, struct pt_regs * regs)
+{
+       /*
+        * we are careful. While for ISA irqs it's common to happen
+        * outside of any driver (think autodetection), this is not
+        * at all nice for PCI interrupts. So we are stricter and
+        * print a warning when such spurious interrupts happen.
+        * Spurious interrupts can confuse other drivers if the PCI
+        * IRQ line is shared.
+        *
+        * Such spurious interrupts are either driver bugs, or
+        * sometimes hw (chipset) bugs.
+        */
+       printk("unexpected IRQ vector %d on CPU#%d!\n",irq, smp_processor_id());
+
+#ifdef CONFIG_X86_IO_APIC
+       /*
+        * [currently unexpected vectors happen only on SMP and APIC.
+        *  if we want to have non-APIC and non-8259A controllers
+        *  in the future with unexpected vectors, this ack should
+        *  probably be made controller-specific.]
+        */
+       ack_APIC_irq();
+#endif
+}
 static void enable_none(unsigned int irq) { }
 static void disable_none(unsigned int irq) { }
 
@@ -82,7 +105,7 @@
 #define startup_none   enable_none
 #define shutdown_none  disable_none
 
-static struct hw_interrupt_type no_irq_type = {
+struct hw_interrupt_type no_irq_type = {
        "none",
        startup_none,
        shutdown_none,
@@ -141,10 +164,10 @@
  * fed to the CPU IRQ line directly.
  *
  * Any '1' bit in this mask means the IRQ is routed through the IO-APIC.
- * this 'mixed mode' IRQ handling costs us one more branch in do_IRQ,
- * but we have _much_ higher compatibility and robustness this way.
+ * this 'mixed mode' IRQ handling costs nothing because it's only used
+ * at IRQ setup time.
  */
-unsigned long long io_apic_irqs = 0;
+unsigned long io_apic_irqs = 0;
 
 /*
  * These have to be protected by the irq controller spinlock
@@ -254,32 +277,43 @@
 
 
 BUILD_COMMON_IRQ()
+
+#define BI(x,y) \
+       BUILD_IRQ(##x##y)
+
+#define BUILD_16_IRQS(x) \
+       BI(x,0) BI(x,1) BI(x,2) BI(x,3) \
+       BI(x,4) BI(x,5) BI(x,6) BI(x,7) \
+       BI(x,8) BI(x,9) BI(x,a) BI(x,b) \
+       BI(x,c) BI(x,d) BI(x,e) BI(x,f)
+
 /*
  * ISA PIC or low IO-APIC triggered (INTA-cycle or APIC) interrupts:
+ * (these are usually mapped to vectors 0x20-0x30)
  */
-BUILD_IRQ(0)  BUILD_IRQ(1)  BUILD_IRQ(2)  BUILD_IRQ(3)
-BUILD_IRQ(4)  BUILD_IRQ(5)  BUILD_IRQ(6)  BUILD_IRQ(7)
-BUILD_IRQ(8)  BUILD_IRQ(9)  BUILD_IRQ(10) BUILD_IRQ(11)
-BUILD_IRQ(12) BUILD_IRQ(13) BUILD_IRQ(14) BUILD_IRQ(15)
+BUILD_16_IRQS(0x0)
 
 #ifdef CONFIG_X86_IO_APIC
 /*
- * The IO-APIC gives us many more interrupt sources..
+ * The IO-APIC gives us many more interrupt sources. Most of these 
+ * are unused but an SMP system is supposed to have enough memory ...
+ * sometimes (mostly wrt. hw bugs) we get corrupted vectors all
+ * across the spectrum, so we really want to be prepared to get all
+ * of these. Plus, more powerful systems might have more than 64
+ * IO-APIC registers.
+ *
+ * (these are usually mapped into the 0x30-0xff vector range)
  */
-BUILD_IRQ(16) BUILD_IRQ(17) BUILD_IRQ(18) BUILD_IRQ(19)
-BUILD_IRQ(20) BUILD_IRQ(21) BUILD_IRQ(22) BUILD_IRQ(23)
-BUILD_IRQ(24) BUILD_IRQ(25) BUILD_IRQ(26) BUILD_IRQ(27)
-BUILD_IRQ(28) BUILD_IRQ(29) BUILD_IRQ(30) BUILD_IRQ(31)
-BUILD_IRQ(32) BUILD_IRQ(33) BUILD_IRQ(34) BUILD_IRQ(35)
-BUILD_IRQ(36) BUILD_IRQ(37) BUILD_IRQ(38) BUILD_IRQ(39)
-BUILD_IRQ(40) BUILD_IRQ(41) BUILD_IRQ(42) BUILD_IRQ(43)
-BUILD_IRQ(44) BUILD_IRQ(45) BUILD_IRQ(46) BUILD_IRQ(47)
-BUILD_IRQ(48) BUILD_IRQ(49) BUILD_IRQ(50) BUILD_IRQ(51)
-BUILD_IRQ(52) BUILD_IRQ(53) BUILD_IRQ(54) BUILD_IRQ(55)
-BUILD_IRQ(56) BUILD_IRQ(57) BUILD_IRQ(58) BUILD_IRQ(59)
-BUILD_IRQ(60) BUILD_IRQ(61) BUILD_IRQ(62) BUILD_IRQ(63)
+                   BUILD_16_IRQS(0x1) BUILD_16_IRQS(0x2) BUILD_16_IRQS(0x3)
+BUILD_16_IRQS(0x4) BUILD_16_IRQS(0x5) BUILD_16_IRQS(0x6) BUILD_16_IRQS(0x7)
+BUILD_16_IRQS(0x8) BUILD_16_IRQS(0x9) BUILD_16_IRQS(0xa) BUILD_16_IRQS(0xb)
+BUILD_16_IRQS(0xc) BUILD_16_IRQS(0xd)
 #endif
 
+#undef BUILD_16_IRQS
+#undef BI
+
+
 #ifdef __SMP__
 /*
  * The following vectors are part of the Linux architecture, there
@@ -303,37 +337,35 @@
 
 #endif
 
+#define IRQ(x,y) \
+       IRQ##x##y##_interrupt
+
+#define IRQLIST_16(x) \
+       IRQ(x,0), IRQ(x,1), IRQ(x,2), IRQ(x,3), \
+       IRQ(x,4), IRQ(x,5), IRQ(x,6), IRQ(x,7), \
+       IRQ(x,8), IRQ(x,9), IRQ(x,a), IRQ(x,b), \
+       IRQ(x,c), IRQ(x,d), IRQ(x,e), IRQ(x,f)
+
 static void (*interrupt[NR_IRQS])(void) = {
-       IRQ0_interrupt, IRQ1_interrupt, IRQ2_interrupt, IRQ3_interrupt,
-       IRQ4_interrupt, IRQ5_interrupt, IRQ6_interrupt, IRQ7_interrupt,
-       IRQ8_interrupt, IRQ9_interrupt, IRQ10_interrupt, IRQ11_interrupt,
-       IRQ12_interrupt, IRQ13_interrupt, IRQ14_interrupt, IRQ15_interrupt
+       IRQLIST_16(0x0),
+
 #ifdef CONFIG_X86_IO_APIC
-       ,IRQ16_interrupt, IRQ17_interrupt, IRQ18_interrupt, IRQ19_interrupt,
-       IRQ20_interrupt, IRQ21_interrupt, IRQ22_interrupt, IRQ23_interrupt,
-       IRQ24_interrupt, IRQ25_interrupt, IRQ26_interrupt, IRQ27_interrupt,
-       IRQ28_interrupt, IRQ29_interrupt,
-       IRQ30_interrupt, IRQ31_interrupt, IRQ32_interrupt, IRQ33_interrupt,
-       IRQ34_interrupt, IRQ35_interrupt, IRQ36_interrupt, IRQ37_interrupt,
-       IRQ38_interrupt, IRQ39_interrupt,
-       IRQ40_interrupt, IRQ41_interrupt, IRQ42_interrupt, IRQ43_interrupt,
-       IRQ44_interrupt, IRQ45_interrupt, IRQ46_interrupt, IRQ47_interrupt,
-       IRQ48_interrupt, IRQ49_interrupt,
-       IRQ50_interrupt, IRQ51_interrupt, IRQ52_interrupt, IRQ53_interrupt,
-       IRQ54_interrupt, IRQ55_interrupt, IRQ56_interrupt, IRQ57_interrupt,
-       IRQ58_interrupt, IRQ59_interrupt,
-       IRQ60_interrupt, IRQ61_interrupt, IRQ62_interrupt, IRQ63_interrupt
+                        IRQLIST_16(0x1), IRQLIST_16(0x2), IRQLIST_16(0x3),
+       IRQLIST_16(0x4), IRQLIST_16(0x5), IRQLIST_16(0x6), IRQLIST_16(0x7),
+       IRQLIST_16(0x8), IRQLIST_16(0x9), IRQLIST_16(0xa), IRQLIST_16(0xb),
+       IRQLIST_16(0xc), IRQLIST_16(0xd)
 #endif
 };
 
+#undef IRQ
+#undef IRQLIST_16
+
 
 /*
- * Initial irq handlers.
+ * Special irq handlers.
  */
 
-void no_action(int cpl, void *dev_id, struct pt_regs *regs)
-{
-}
+void no_action(int cpl, void *dev_id, struct pt_regs *regs) { }
 
 #ifndef CONFIG_VISWS
 /*
@@ -770,7 +802,7 @@
         * 0 return value means that this irq is already being
         * handled by some other CPU. (or is disabled)
         */
-       unsigned int irq = regs.orig_eax & 0xff;
+       int irq = regs.orig_eax & 0xff; /* subtle, see irq.h */
        int cpu = smp_processor_id();
 
        kstat.irqs[cpu][irq]++;
@@ -986,42 +1018,6 @@
        return irq_found;
 }
 
-/*
- * Silly, horrible hack
- */
-static char uglybuffer[10*256];
-
-__asm__("\n" __ALIGN_STR"\n"
-       "common_unexpected:\n\t"
-       SAVE_ALL
-       "pushl $ret_from_intr\n\t"
-       "jmp strange_interrupt");
-
-void strange_interrupt(int irqnum)
-{
-       printk("Unexpected interrupt %d\n", irqnum & 255);
-       for (;;);
-}
-
-extern int common_unexpected;
-__initfunc(void init_unexpected_irq(void))
-{
-       int i;
-       for (i = 0; i < 256; i++) {
-               char *code = uglybuffer + 10*i;
-               unsigned long jumpto = (unsigned long) &common_unexpected;
-
-               jumpto -= (unsigned long)(code+10);
-               code[0] = 0x68;         /* pushl */
-               *(int *)(code+1) = i - 512;
-               code[5] = 0xe9;         /* jmp */
-               *(int *)(code+6) = jumpto;
-
-               set_intr_gate(i,code);
-       }
-}
-
-
 void init_ISA_irqs (void)
 {
        int i;
@@ -1033,7 +1029,7 @@
 
                if (i < 16) {
                        /*
-                        * 16 old-style INTA-cycle interrupt gates:
+                        * 16 old-style INTA-cycle interrupts:
                         */
                        irq_desc[i].handler = &i8259A_irq_type;
                } else {
@@ -1054,9 +1050,16 @@
 #else
        init_VISWS_APIC_irqs();
 #endif
-
-       for (i = 0; i < 16; i++)
-               set_intr_gate(0x20+i,interrupt[i]);
+       /*
+        * Cover the whole vector space, no vector can escape
+        * us. (some of these will be overridden and become
+        * 'special' SMP interrupts)
+        */
+       for (i = 0; i < NR_IRQS; i++) {
+               int vector = FIRST_EXTERNAL_VECTOR + i;
+               if (vector != SYSCALL_VECTOR) 
+                       set_intr_gate(vector, interrupt[i]);
+       }
 
 #ifdef __SMP__ 
 
@@ -1067,13 +1070,9 @@
        set_intr_gate(IRQ0_TRAP_VECTOR, interrupt[0]);
 
        /*
-        * The reschedule interrupt slowly changes it's functionality,
-        * while so far it was a kind of broadcasted timer interrupt,
-        * in the future it should become a CPU-to-CPU rescheduling IPI,
-        * driven by schedule() ?
+        * The reschedule interrupt is a CPU-to-CPU reschedule-helper
+        * IPI, driven by wakeup.
         */
-
-       /* IPI for rescheduling */
        set_intr_gate(RESCHEDULE_VECTOR, reschedule_interrupt);
 
        /* IPI for invalidation */
--- linux/arch/i386/kernel/irq.h.orig2  Tue Feb  9 12:36:07 1999
+++ linux/arch/i386/kernel/irq.h        Thu Feb 11 20:19:29 1999
@@ -16,6 +16,7 @@
        void (*disable)(unsigned int irq);
 };
 
+extern struct hw_interrupt_type no_irq_type;
 
 /*
  * IRQ line status.
@@ -41,6 +42,18 @@
 } irq_desc_t;
 
 /*
+ * IDT vectors usable for external interrupt sources start
+ * at 0x20:
+ */
+#define FIRST_EXTERNAL_VECTOR  0x20
+
+#define SYSCALL_VECTOR         0x80
+
+/*
+ * Vectors 0x20-0x2f are used for ISA interrupts.
+ */
+
+/*
  * Special IRQ vectors used by the SMP architecture:
  *
  * (some of the following vectors are 'rare', they might be merged
@@ -54,7 +67,7 @@
 #define MTRR_CHANGE_VECTOR     0x50
 
 /*
- * First vector available to drivers: (vectors 0x51-0xfe)
+ * First APIC vector available to drivers: (vectors 0x51-0xfe)
  */
 #define IRQ0_TRAP_VECTOR       0x51
 
@@ -94,7 +107,9 @@
 extern void init_pic_mode(void);
 extern void print_IO_APIC(void);
 
-extern unsigned long long io_apic_irqs;
+extern unsigned long io_apic_irqs;
+
+extern char _stext, _etext;
 
 #define MAX_IRQ_SOURCES 128
 #define MAX_MP_BUSSES 32
@@ -126,7 +141,7 @@
        hardirq_exit(cpu);
 }
 
-#define IO_APIC_IRQ(x) ((1<<x) & io_apic_irqs)
+#define IO_APIC_IRQ(x) (((x) >= 16) || ((1<<(x)) & io_apic_irqs))
 
 #else
 
@@ -201,6 +216,13 @@
        "pushl $ret_from_intr\n\t" \
        "jmp "SYMBOL_NAME_STR(do_IRQ));
 
+/*
+ * subtle. orig_eax is used by the signal code to distinct between
+ * system calls and interrupted 'random user-space'. Thus we have
+ * to put a negative value into orig_eax here. (the problem is that
+ * both system calls and IRQs want to have small integer numbers in
+ * orig_eax, and the syscall code has won the optimization conflict ;)
+ */
 #define BUILD_IRQ(nr) \
 asmlinkage void IRQ_NAME(nr); \
 __asm__( \
@@ -216,7 +238,6 @@
 static inline void x86_do_profile (unsigned long eip)
 {
        if (prof_buffer && current->pid) {
-               extern int _stext;
                eip -= (unsigned long) &_stext;
                eip >>= prof_shift;
                /*
--- linux/arch/i386/kernel/traps.c.orig2        Tue Feb  9 15:05:55 1999
+++ linux/arch/i386/kernel/traps.c      Tue Feb  9 16:13:02 1999
@@ -42,6 +42,8 @@
 #include <asm/lithium.h>
 #endif
 
+#include "irq.h"
+
 asmlinkage int system_call(void);
 asmlinkage void lcall7(void);
 
@@ -125,7 +127,6 @@
        unsigned long esp;
        unsigned short ss;
        unsigned long *stack, addr, module_start, module_end;
-       extern char _stext, _etext;
 
         __cli();
         smp_send_stop();
@@ -676,9 +677,6 @@
 #endif
 void __init trap_init(void)
 {
-       /* Initially up all of the IDT to jump to unexpected */
-       init_unexpected_irq();
-
        if (readl(0x0FFFD9) == 'E' + ('I'<<8) + ('S'<<16) + ('A'<<24))
                EISA_bus = 1;
        set_call_gate(&default_ldt,lcall7);
@@ -700,7 +698,7 @@
        set_trap_gate(15,&spurious_interrupt_bug);
        set_trap_gate(16,&coprocessor_error);
        set_trap_gate(17,&alignment_check);
-       set_system_gate(0x80,&system_call);
+       set_system_gate(SYSCALL_VECTOR,&system_call);
 
        /* set up GDT task & ldt entries */
        set_tss_desc(0, &init_task.tss);


-
Linux SMP list: FIRST see FAQ at http://www.irisa.fr/prive/mentre/smp-faq/
To Unsubscribe: send "unsubscribe linux-smp" to [EMAIL PROTECTED]

Reply via email to