Messages in this thread Patch in this message | | | Date | Wed, 17 Feb 1999 07:15:04 +0100 (CET) | From | Ingo Molnar <> | Subject | Re: The "not quite valentines day release".. |
| |
this is smp-2.2.2-C1, which adds some more SMP fixes, against 2.2.2-pre4. It compiles/boots cleanly both under UP and SMP. Changes over pre4:
- io_apic.c now reports when we are out of vectors, instead of silently stomping on SYSCALL_VECTOR. Due to the way we allocate vectors, 0x80 is allocated as one of the last vectors, so stopping at 0x80 is basically equivalent to maxing out all vectors.
- 'centralized' some more irq-architecture things, mainly the vector allocation part: new constants in irq.h, corrected comments.
- NR_IRQS up to 224. This now reaches the architectural limit on Intel x86 CPUs.
- io_apic.c complains less about "unexpected IO-APIC"s.
- chunk @@ -1163,7 +1168,7 @@ in io_apic.c corrects a bug. unexpected but 'theoretically IO-APIC' vectors were registered and silently ignored. Now we have more chances to see real unexpected vectors.
- chunk @@ -1278,14 +1290,12 @@ corrects the initialization order, first do we allocate the vector, then do we fill out the handler type.
- we had a few places using _stext, _etext inconsistently.
- MP-BIOS-bug workaround for 'version 0 APICs'
- removed the 'long long' solution of determining wether a vector is IO-APIC or not, this matters only for 'ISA-space' vectors anyway.
- added orig_eax-trick explaining comments
- replaced the IRQ building macros by hierarchic ones
-- mingo
--- linux/include/asm-i386/irq.h.orig Tue Feb 16 20:56:03 1999 +++ linux/include/asm-i386/irq.h Tue Feb 16 20:51:04 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.orig Tue Feb 16 20:56:03 1999 +++ linux/arch/i386/kernel/io_apic.c Tue Feb 16 20:51:04 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 *)®_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.orig Tue Feb 16 20:56:03 1999 +++ linux/arch/i386/kernel/smp.c Tue Feb 16 20:57:31 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()); } /* @@ -2058,3 +2069,4 @@ } #undef APIC_DIVISOR + --- linux/arch/i386/kernel/irq.c.orig Tue Feb 16 20:56:03 1999 +++ linux/arch/i386/kernel/irq.c Tue Feb 16 20:58:48 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 __SMP__ + /* + * [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.orig Tue Feb 16 20:56:03 1999 +++ linux/arch/i386/kernel/irq.h Tue Feb 16 20:51:04 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.orig Tue Feb 16 20:56:03 1999 +++ linux/arch/i386/kernel/traps.c Tue Feb 16 20:51:04 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; esp = (unsigned long) (1+regs); ss = __KERNEL_DS; @@ -669,9 +670,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); @@ -693,7 +691,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);
| |