Re: The "not quite valentines day release"..

Ingo Molnar (mingo@chiara.csoma.elte.hu)
Wed, 17 Feb 1999 07:15:04 +0100 (CET)


This message is in MIME format. The first part should be readable text,
while the remaining parts are likely unreadable without MIME-aware tools.
Send mail to mime@docserver.cac.washington.edu for more info.

---1247997369-221944519-919201329=:4663
Content-Type: TEXT/PLAIN; CHARSET=US-ASCII
Content-ID: <Pine.LNX.3.96.990217070916.17263D@chiara.csoma.elte.hu>

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 *)&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.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);

---1247997369-221944519-919201329=:4663--

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/