Messages in this thread Patch in this message | | | Date | Sun, 8 Aug 1999 13:30:01 -0600 | From | yodaiken@chelm ... | Subject | irq.c cleanup and another try. |
| |
Matthew Wilcox pointed out that the first patch I posted did what it was supposed to and also, for no apparent reason, added a copy of the i8259.c file to the linux directory. At this point, I can only suspect either sabatoge from Redmond or my advanced age . Here's a corrected version. (Back in the good old days, we never used diff. We just used ls -l and extrapolated).
-------------------------------------------------------------------
diff -u -r -N vanilla12/arch/i386/kernel/Makefile linux.new12/arch/i386/kernel/Makefile --- vanilla12/arch/i386/kernel/Makefile Sun Jul 11 10:48:05 1999 +++ linux.new12/arch/i386/kernel/Makefile Wed Aug 4 16:20:49 1999 @@ -14,7 +14,7 @@ O_TARGET := kernel.o O_OBJS := process.o signal.o entry.o traps.o irq.o vm86.o \ - ptrace.o ioport.o ldt.o setup.o time.o sys_i386.o + ptrace.o i8259.o ioport.o ldt.o setup.o time.o sys_i386.o OX_OBJS := i386_ksyms.o MX_OBJS := diff -u -r -N vanilla12/arch/i386/kernel/bios32.c linux.new12/arch/i386/kernel/bios32.c --- vanilla12/arch/i386/kernel/bios32.c Sat Apr 24 18:49:37 1999 +++ linux.new12/arch/i386/kernel/bios32.c Wed Aug 4 16:20:49 1999 @@ -93,7 +93,7 @@ #include <asm/smp.h> #include <asm/spinlock.h> -#include "irq.h" +#include <linux/irq.h> #undef DEBUG diff -u -r -N vanilla12/arch/i386/kernel/i8259.c linux.new12/arch/i386/kernel/i8259.c --- vanilla12/arch/i386/kernel/i8259.c Wed Dec 31 17:00:00 1969 +++ linux.new12/arch/i386/kernel/i8259.c Wed Aug 4 16:20:49 1999 @@ -0,0 +1,404 @@ +#include <linux/config.h> +#include <linux/ptrace.h> +#include <linux/errno.h> +#include <linux/kernel_stat.h> +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/ioport.h> +#include <linux/interrupt.h> +#include <linux/timex.h> +#include <linux/malloc.h> +#include <linux/random.h> +#include <linux/smp.h> +#include <linux/tasks.h> +#include <linux/smp_lock.h> +#include <linux/init.h> + +#include <asm/system.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/bitops.h> +#include <asm/smp.h> +#include <asm/pgtable.h> +#include <asm/delay.h> +#include <asm/desc.h> + +#include <linux/irq.h> + + +/* Intel specific no controller code + odd that no-controller should be architecture dependent + but see the ifdef __SMP__ + */ +static void enable_none(unsigned int irq) { } +static unsigned int startup_none(unsigned int irq) {return 0; } +static void disable_none(unsigned int irq) { } +static void ack_none(unsigned int irq){ +#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 +} + +/* startup is the same as "enable", shutdown is same as "disable" */ +#define shutdown_none disable_none +#define end_none enable_none + +struct hw_interrupt_type no_irq_type = { + "none", + startup_none, + shutdown_none, + enable_none, + disable_none, + ack_none, + end_none +}; + + +/* + * This is the 'legacy' 8259A Programmable Interrupt Controller, + * present in the majority of PC/AT boxes. + * plus some generic x86 specific things if generic specifics makes + * any sense at all. + * this file should become arch/i386/kernel/irq.c when the old irq.c + * moves to arch independent land + */ +/* + * This builds up the IRQ handler stubs using some ugly macros in irq.h + * + * These macros create the low-level assembly IRQ routines that save + * register context and call do_IRQ(). do_IRQ() then does all the + * operations that are needed to keep the AT (or SMP IOAPIC) + * interrupt-controller happy. + */ + + +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_16_IRQS(0x0) + +#ifdef CONFIG_X86_IO_APIC +/* + * 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_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 + * is no hardware IRQ pin equivalent for them, they are triggered + * through the ICC by us (IPIs) + */ +BUILD_SMP_INTERRUPT(reschedule_interrupt) +BUILD_SMP_INTERRUPT(invalidate_interrupt) +BUILD_SMP_INTERRUPT(stop_cpu_interrupt) +BUILD_SMP_INTERRUPT(call_function_interrupt) +BUILD_SMP_INTERRUPT(spurious_interrupt) + +/* + * every pentium local APIC has two 'local interrupts', with a + * soft-definable vector attached to both interrupts, one of + * which is a timer interrupt, the other one is error counter + * overflow. Linux uses the local APIC timer interrupt to get + * a much simpler SMP time architecture: + */ +BUILD_SMP_TIMER_INTERRUPT(apic_timer_interrupt) + +#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) = { + IRQLIST_16(0x0), + +#ifdef CONFIG_X86_IO_APIC + 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 + + + + +static void enable_8259A_irq(unsigned int irq); +void disable_8259A_irq(unsigned int irq); + +/* shutdown is same as "disable" */ +#define end_8259A_irq enable_8259A_irq +#define shutdown_8259A_irq disable_8259A_irq +static void mask_and_ack_8259A(unsigned int); +static unsigned int startup_8259A_irq(unsigned int irq){ + enable_8259A_irq(irq); + return 0; /* never anything pending */ +} + +static struct hw_interrupt_type i8259A_irq_type = { + "XT-PIC", + startup_8259A_irq, + shutdown_8259A_irq, + enable_8259A_irq, + disable_8259A_irq, + mask_and_ack_8259A, + end_8259A_irq +}; + +/* + * 8259A PIC functions to handle ISA devices: + */ + +/* + * This contains the irq mask for both 8259A irq controllers, + */ +static unsigned int cached_irq_mask = 0xffff; + +#define __byte(x,y) (((unsigned char *)&(y))[x]) +#define cached_21 (__byte(0,cached_irq_mask)) +#define cached_A1 (__byte(1,cached_irq_mask)) + +/* + * Not all IRQs can be routed through the IO-APIC, eg. on certain (older) + * boards the timer interrupt is not connected to any IO-APIC pin, it's + * 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 nothing because it's only used + * at IRQ setup time. + */ +unsigned long io_apic_irqs = 0; + +/* + * These have to be protected by the irq controller spinlock + * before being called. + */ +void disable_8259A_irq(unsigned int irq) +{ + unsigned int mask = 1 << irq; + cached_irq_mask |= mask; + if (irq & 8) { + outb(cached_A1,0xA1); + } else { + outb(cached_21,0x21); + } +} + +static void enable_8259A_irq(unsigned int irq) +{ + unsigned int mask = ~(1 << irq); + cached_irq_mask &= mask; + if (irq & 8) { + outb(cached_A1,0xA1); + } else { + outb(cached_21,0x21); + } +} + +int i8259A_irq_pending(unsigned int irq) +{ + unsigned int mask = 1<<irq; + + if (irq < 8) + return (inb(0x20) & mask); + return (inb(0xA0) & (mask >> 8)); +} + +void make_8259A_irq(unsigned int irq) +{ + disable_irq_nosync(irq); + io_apic_irqs &= ~(1<<irq); + irq_desc[irq].handler = &i8259A_irq_type; + enable_irq(irq); +} + +/* + * Careful! The 8259A is a fragile beast, it pretty + * much _has_ to be done exactly like this (mask it + * first, _then_ send the EOI, and the order of EOI + * to the two 8259s is important! + */ +static void mask_and_ack_8259A(unsigned int irq) +{ + cached_irq_mask |= 1 << irq; + if (irq & 8) { + inb(0xA1); /* DUMMY */ + outb(cached_A1,0xA1); + outb(0x62,0x20); /* Specific EOI to cascade */ + outb(0x20,0xA0); + } else { + inb(0x21); /* DUMMY */ + outb(cached_21,0x21); + outb(0x20,0x20); + } +} +#ifndef CONFIG_VISWS +/* + * Note that on a 486, we don't want to do a SIGFPE on an irq13 + * as the irq is unreliable, and exception 16 works correctly + * (ie as explained in the intel literature). On a 386, you + * can't use exception 16 due to bad IBM design, so we have to + * rely on the less exact irq13. + * + * Careful.. Not only is IRQ13 unreliable, but it is also + * leads to races. IBM designers who came up with it should + * be shot. + */ + +static void math_error_irq(int cpl, void *dev_id, struct pt_regs *regs) +{ + outb(0,0xF0); + if (ignore_irq13 || !boot_cpu_data.hard_math) + return; + math_error(); +} + +static struct irqaction irq13 = { math_error_irq, 0, 0, "fpu", NULL, NULL }; + +/* + * IRQ2 is cascade interrupt to second interrupt controller + */ + +static struct irqaction irq2 = { no_action, 0, 0, "cascade", NULL, NULL}; +#endif + + +void init_ISA_irqs (void) +{ + int i; + + for (i = 0; i < NR_IRQS; i++) { + irq_desc[i].status = IRQ_DISABLED; + irq_desc[i].action = 0; + irq_desc[i].depth = 0; + + if (i < 16) { + /* + * 16 old-style INTA-cycle interrupts: + */ + irq_desc[i].handler = &i8259A_irq_type; + } else { + /* + * 'high' PCI IRQs filled in on demand + */ + irq_desc[i].handler = &no_irq_type; + } + } +} + +__initfunc(void init_IRQ(void)) +{ + int i; + +#ifndef CONFIG_X86_VISWS_APIC + init_ISA_irqs(); +#else + init_VISWS_APIC_irqs(); +#endif + /* + * 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__ + + /* + IRQ0 must be given a fixed assignment and initialized + before init_IRQ_SMP. + */ + set_intr_gate(IRQ0_TRAP_VECTOR, interrupt[0]); + + /* + * The reschedule interrupt is a CPU-to-CPU reschedule-helper + * IPI, driven by wakeup. + */ + set_intr_gate(RESCHEDULE_VECTOR, reschedule_interrupt); + + /* IPI for invalidation */ + set_intr_gate(INVALIDATE_TLB_VECTOR, invalidate_interrupt); + + /* IPI for CPU halt */ + set_intr_gate(STOP_CPU_VECTOR, stop_cpu_interrupt); + + /* self generated IPI for local APIC timer */ + set_intr_gate(LOCAL_TIMER_VECTOR, apic_timer_interrupt); + + /* IPI for generic function call */ + set_intr_gate(CALL_FUNCTION_VECTOR, call_function_interrupt); + + /* IPI vector for APIC spurious interrupts */ + set_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt); +#endif + + /* + * Set the clock to 100 Hz, we already have a valid + * vector now: + */ + outb_p(0x34,0x43); /* binary, mode 2, LSB/MSB, ch 0 */ + outb_p(LATCH & 0xff , 0x40); /* LSB */ + outb(LATCH >> 8 , 0x40); /* MSB */ + +#ifndef CONFIG_VISWS + setup_irq(2, &irq2); + setup_irq(13, &irq13); +#endif +} + +#ifdef CONFIG_X86_IO_APIC +__initfunc(void init_IRQ_SMP(void)) +{ + int i; + for (i = 0; i < NR_IRQS ; i++) + if (IO_APIC_VECTOR(i) > 0) + set_intr_gate(IO_APIC_VECTOR(i), interrupt[i]); +} +#endif + diff -u -r -N vanilla12/arch/i386/kernel/io_apic.c linux.new12/arch/i386/kernel/io_apic.c --- vanilla12/arch/i386/kernel/io_apic.c Sun Jul 25 11:26:01 1999 +++ linux.new12/arch/i386/kernel/io_apic.c Wed Aug 4 16:20:49 1999 @@ -19,7 +19,7 @@ #include <linux/delay.h> #include <asm/io.h> -#include "irq.h" +#include <linux/irq.h> /* * volatile is justified in this case, IO-APIC register contents @@ -954,24 +954,13 @@ * better to do it this way as thus we do not have to be aware of * 'pending' interrupts in the IRQ path, except at this point. */ -static inline void self_IPI(unsigned int irq) -{ - irq_desc_t *desc = irq_desc + irq; - unsigned int status = desc->status; - - if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) { - desc->status = status | IRQ_REPLAY; - send_IPI_self(IO_APIC_VECTOR(irq)); - } -} - /* * Edge triggered needs to resend any interrupt - * that was delayed. + * that was delayed but this is now handled in the device + * independent code. */ static void enable_edge_ioapic_irq(unsigned int irq) { - self_IPI(irq); enable_IO_APIC_irq(irq); } @@ -984,129 +973,49 @@ * Starting up a edge-triggered IO-APIC interrupt is * nasty - we need to make sure that we get the edge. * If it is already asserted for some reason, we need - * to fake an edge by marking it IRQ_PENDING.. + * return 1 to indicate that is was pending. * * This is not complete - we should be able to fake * an edge even if it isn't on the 8259A... */ -static void startup_edge_ioapic_irq(unsigned int irq) +static unsigned int startup_edge_ioapic_irq(unsigned int irq) { + int was_pending = 0; if (irq < 16) { disable_8259A_irq(irq); if (i8259A_irq_pending(irq)) - irq_desc[irq].status |= IRQ_PENDING; + was_pending = 1; } enable_edge_ioapic_irq(irq); + return was_pending; } #define shutdown_edge_ioapic_irq disable_edge_ioapic_irq +void static ack_edge_ioapic_irq(unsigned int i){ +ack_APIC_irq(); +} +void static end_edge_ioapic_irq(unsigned int i){} + /* * Level triggered interrupts can just be masked, * and shutting down and starting up the interrupt - * is the same as enabling and disabling them. + * is the same as enabling and disabling them -- except + * with a startup need to return a "was pending" value. */ -#define startup_level_ioapic_irq unmask_IO_APIC_irq +static unsigned int startup_level_ioapic_irq(unsigned int irq){ + unmask_IO_APIC_irq(irq); + return 0; /* don't check for pending */ +} + #define shutdown_level_ioapic_irq mask_IO_APIC_irq #define enable_level_ioapic_irq unmask_IO_APIC_irq #define disable_level_ioapic_irq mask_IO_APIC_irq - -static void do_edge_ioapic_IRQ(unsigned int irq, struct pt_regs * regs) -{ - irq_desc_t *desc = irq_desc + irq; - struct irqaction * action; - unsigned int status; - - spin_lock(&irq_controller_lock); - - /* - * Edge triggered IRQs can be acknowledged immediately - * and do not need to be masked. - */ +#define end_level_ioapic_irq unmask_IO_APIC_irq +void static mask_and_ack_level_ioapic_irq(unsigned int i){ + mask_IO_APIC_irq(i); ack_APIC_irq(); - status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING); - status |= IRQ_PENDING; - - /* - * If the IRQ is disabled for whatever reason, we cannot - * use the action we have. - */ - action = NULL; - if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) { - action = desc->action; - status &= ~IRQ_PENDING; - status |= IRQ_INPROGRESS; - } - desc->status = status; - spin_unlock(&irq_controller_lock); - - /* - * If there is no IRQ handler or it was disabled, exit early. - */ - if (!action) - return; - - /* - * Edge triggered interrupts need to remember - * pending events. - */ - for (;;) { - handle_IRQ_event(irq, regs, action); - - spin_lock(&irq_controller_lock); - if (!(desc->status & IRQ_PENDING)) - break; - desc->status &= ~IRQ_PENDING; - spin_unlock(&irq_controller_lock); - } - desc->status &= ~IRQ_INPROGRESS; - spin_unlock(&irq_controller_lock); -} - -static void do_level_ioapic_IRQ(unsigned int irq, struct pt_regs * regs) -{ - irq_desc_t *desc = irq_desc + irq; - struct irqaction * action; - unsigned int status; - - spin_lock(&irq_controller_lock); - /* - * In the level triggered case we first disable the IRQ - * in the IO-APIC, then we 'early ACK' the IRQ, then we - * handle it and enable the IRQ when finished. - * - * disable has to happen before the ACK, to avoid IRQ storms. - * So this all has to be within the spinlock. - */ - mask_IO_APIC_irq(irq); - status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING); - - /* - * If the IRQ is disabled for whatever reason, we must - * not enter the IRQ action. - */ - action = NULL; - if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) { - action = desc->action; - status |= IRQ_INPROGRESS; - } - desc->status = status; - - ack_APIC_irq(); - spin_unlock(&irq_controller_lock); - - /* Exit early if we had no action or it was disabled */ - if (!action) - return; - - handle_IRQ_event(irq, regs, action); - - spin_lock(&irq_controller_lock); - desc->status &= ~IRQ_INPROGRESS; - if (!(desc->status & IRQ_DISABLED)) - unmask_IO_APIC_irq(irq); - spin_unlock(&irq_controller_lock); } /* @@ -1122,18 +1031,20 @@ "IO-APIC-edge", startup_edge_ioapic_irq, shutdown_edge_ioapic_irq, - do_edge_ioapic_IRQ, enable_edge_ioapic_irq, - disable_edge_ioapic_irq + disable_edge_ioapic_irq, + ack_edge_ioapic_irq, + end_edge_ioapic_irq }; static struct hw_interrupt_type ioapic_level_irq_type = { "IO-APIC-level", startup_level_ioapic_irq, shutdown_level_ioapic_irq, - do_level_ioapic_IRQ, enable_level_ioapic_irq, - disable_level_ioapic_irq + disable_level_ioapic_irq, + mask_and_ack_level_ioapic_irq, + end_level_ioapic_irq }; static inline void init_IO_APIC_traps(void) diff -u -r -N vanilla12/arch/i386/kernel/irq.c linux.new12/arch/i386/kernel/irq.c --- vanilla12/arch/i386/kernel/irq.c Thu Jul 15 16:50:47 1999 +++ linux.new12/arch/i386/kernel/irq.c Wed Aug 4 16:20:49 1999 @@ -1,3 +1,8 @@ +/* mostly architecture independent + some moved to i8259.c + the beautiful visws architecture code needs to be updated too. + and, finally, the BUILD_IRQ and SMP_BUILD macros in irq.h need fixed. + */ /* * linux/arch/i386/kernel/irq.c * @@ -32,14 +37,14 @@ #include <asm/system.h> #include <asm/io.h> -#include <asm/irq.h> #include <asm/bitops.h> #include <asm/smp.h> #include <asm/pgtable.h> #include <asm/delay.h> #include <asm/desc.h> +#include <asm/irq.h> +#include <linux/irq.h> -#include "irq.h" unsigned int local_bh_count[NR_CPUS]; unsigned int local_irq_count[NR_CPUS]; @@ -67,334 +72,18 @@ * system. We never hold this lock when we call the actual * IRQ handler. */ -spinlock_t irq_controller_lock; - -/* - * Dummy controller type for unused interrupts - */ -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) { } - -/* startup is the same as "enable", shutdown is same as "disable" */ -#define startup_none enable_none -#define shutdown_none disable_none - -struct hw_interrupt_type no_irq_type = { - "none", - startup_none, - shutdown_none, - do_none, - enable_none, - disable_none -}; - -/* - * This is the 'legacy' 8259A Programmable Interrupt Controller, - * present in the majority of PC/AT boxes. - */ - -static void do_8259A_IRQ(unsigned int irq, struct pt_regs * regs); -static void enable_8259A_irq(unsigned int irq); -void disable_8259A_irq(unsigned int irq); - -/* startup is the same as "enable", shutdown is same as "disable" */ -#define startup_8259A_irq enable_8259A_irq -#define shutdown_8259A_irq disable_8259A_irq - -static struct hw_interrupt_type i8259A_irq_type = { - "XT-PIC", - startup_8259A_irq, - shutdown_8259A_irq, - do_8259A_IRQ, - enable_8259A_irq, - disable_8259A_irq -}; - +spinlock_t irq_controller_lock ={0}; /* * Controller mappings for all interrupt sources: */ irq_desc_t irq_desc[NR_IRQS] = { [0 ... NR_IRQS-1] = { 0, &no_irq_type, }}; - -/* - * 8259A PIC functions to handle ISA devices: - */ - -/* - * This contains the irq mask for both 8259A irq controllers, - */ -static unsigned int cached_irq_mask = 0xffff; - -#define __byte(x,y) (((unsigned char *)&(y))[x]) -#define cached_21 (__byte(0,cached_irq_mask)) -#define cached_A1 (__byte(1,cached_irq_mask)) - -/* - * Not all IRQs can be routed through the IO-APIC, eg. on certain (older) - * boards the timer interrupt is not connected to any IO-APIC pin, it's - * 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 nothing because it's only used - * at IRQ setup time. - */ -unsigned long io_apic_irqs = 0; - -/* - * These have to be protected by the irq controller spinlock - * before being called. - */ -void disable_8259A_irq(unsigned int irq) -{ - unsigned int mask = 1 << irq; - cached_irq_mask |= mask; - if (irq & 8) { - outb(cached_A1,0xA1); - } else { - outb(cached_21,0x21); - } -} - -static void enable_8259A_irq(unsigned int irq) -{ - unsigned int mask = ~(1 << irq); - cached_irq_mask &= mask; - if (irq & 8) { - outb(cached_A1,0xA1); - } else { - outb(cached_21,0x21); - } -} - -int i8259A_irq_pending(unsigned int irq) -{ - unsigned int mask = 1<<irq; - - if (irq < 8) - return (inb(0x20) & mask); - return (inb(0xA0) & (mask >> 8)); -} - -void make_8259A_irq(unsigned int irq) -{ - disable_irq_nosync(irq); - io_apic_irqs &= ~(1<<irq); - irq_desc[irq].handler = &i8259A_irq_type; - enable_irq(irq); -} - -/* - * Careful! The 8259A is a fragile beast, it pretty - * much _has_ to be done exactly like this (mask it - * first, _then_ send the EOI, and the order of EOI - * to the two 8259s is important! - */ -static inline void mask_and_ack_8259A(unsigned int irq) -{ - cached_irq_mask |= 1 << irq; - if (irq & 8) { - inb(0xA1); /* DUMMY */ - outb(cached_A1,0xA1); - outb(0x62,0x20); /* Specific EOI to cascade */ - outb(0x20,0xA0); - } else { - inb(0x21); /* DUMMY */ - outb(cached_21,0x21); - outb(0x20,0x20); - } -} - -static void do_8259A_IRQ(unsigned int irq, struct pt_regs * regs) -{ - struct irqaction * action; - irq_desc_t *desc = irq_desc + irq; - - spin_lock(&irq_controller_lock); - { - unsigned int status; - mask_and_ack_8259A(irq); - status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING); - action = NULL; - if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) { - action = desc->action; - status |= IRQ_INPROGRESS; - } - desc->status = status; - } - spin_unlock(&irq_controller_lock); - - /* Exit early if we had no action or it was disabled */ - if (!action) - return; - - handle_IRQ_event(irq, regs, action); - - spin_lock(&irq_controller_lock); - { - unsigned int status = desc->status & ~IRQ_INPROGRESS; - desc->status = status; - if (!(status & IRQ_DISABLED)) - enable_8259A_irq(irq); - } - spin_unlock(&irq_controller_lock); -} - -/* - * This builds up the IRQ handler stubs using some ugly macros in irq.h - * - * These macros create the low-level assembly IRQ routines that save - * register context and call do_IRQ(). do_IRQ() then does all the - * operations that are needed to keep the AT (or SMP IOAPIC) - * interrupt-controller happy. - */ - - -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_16_IRQS(0x0) - -#ifdef CONFIG_X86_IO_APIC -/* - * 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_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 - * is no hardware IRQ pin equivalent for them, they are triggered - * through the ICC by us (IPIs) - */ -BUILD_SMP_INTERRUPT(reschedule_interrupt) -BUILD_SMP_INTERRUPT(invalidate_interrupt) -BUILD_SMP_INTERRUPT(stop_cpu_interrupt) -BUILD_SMP_INTERRUPT(call_function_interrupt) -BUILD_SMP_INTERRUPT(spurious_interrupt) - -/* - * every pentium local APIC has two 'local interrupts', with a - * soft-definable vector attached to both interrupts, one of - * which is a timer interrupt, the other one is error counter - * overflow. Linux uses the local APIC timer interrupt to get - * a much simpler SMP time architecture: - */ -BUILD_SMP_TIMER_INTERRUPT(apic_timer_interrupt) - -#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) = { - IRQLIST_16(0x0), - -#ifdef CONFIG_X86_IO_APIC - 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 - - /* * Special irq handlers. */ void no_action(int cpl, void *dev_id, struct pt_regs *regs) { } -#ifndef CONFIG_VISWS -/* - * Note that on a 486, we don't want to do a SIGFPE on an irq13 - * as the irq is unreliable, and exception 16 works correctly - * (ie as explained in the intel literature). On a 386, you - * can't use exception 16 due to bad IBM design, so we have to - * rely on the less exact irq13. - * - * Careful.. Not only is IRQ13 unreliable, but it is also - * leads to races. IBM designers who came up with it should - * be shot. - */ - -static void math_error_irq(int cpl, void *dev_id, struct pt_regs *regs) -{ - outb(0,0xF0); - if (ignore_irq13 || !boot_cpu_data.hard_math) - return; - math_error(); -} - -static struct irqaction irq13 = { math_error_irq, 0, 0, "fpu", NULL, NULL }; - -/* - * IRQ2 is cascade interrupt to second interrupt controller - */ - -static struct irqaction irq2 = { no_action, 0, 0, "cascade", NULL, NULL}; -#endif - /* * Generic, controller-independent functions: */ @@ -782,7 +471,15 @@ spin_lock_irqsave(&irq_controller_lock, flags); switch (irq_desc[irq].depth) { case 1: - irq_desc[irq].status &= ~IRQ_DISABLED; + { + unsigned int status; + irq_desc[irq].status &= ~IRQ_DISABLED; + status = irq_desc[irq].status; + if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) { + irq_desc[irq].status |= IRQ_REPLAY; + hw_resend_irq(irq_desc[irq].handler,irq); + } + } irq_desc[irq].handler->enable(irq); /* fall throught */ default: @@ -800,7 +497,7 @@ * SMP cross-CPU interrupts have their own specific * handlers). */ -asmlinkage void do_IRQ(struct pt_regs regs) +asmlinkage unsigned int do_IRQ(struct pt_regs regs) { /* * We ack quickly, we don't want the irq controller @@ -812,76 +509,81 @@ * 0 return value means that this irq is already being * handled by some other CPU. (or is disabled) */ - int irq = regs.orig_eax & 0xff; /* subtle, see irq.h */ + int irq = regs.orig_eax &0xff;/* high bits used in ret_from_ code */ int cpu = smp_processor_id(); + irq_desc_t *desc; + struct irqaction * action; + unsigned int status; kstat.irqs[cpu][irq]++; - irq_desc[irq].handler->handle(irq, ®s); + desc = irq_desc + irq; + spin_lock(&irq_controller_lock); + irq_desc[irq].handler->ack(irq); + /* + REPLAY is when Linux resends an IRQ that was dropped earlier + WAITING is used by probe to mark irqs that are being tested + */ + status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING); + status |= IRQ_PENDING; /* we _want_ to handle it */ /* - * This should be conditional: we should really get - * a return code from the irq handler to tell us - * whether the handler wants us to do software bottom - * half handling or not.. + * If the IRQ is disabled for whatever reason, we cannot + * use the action we have. */ - if (1) { - if (bh_active & bh_mask) - do_bottom_half(); + action = NULL; + if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) { + action = desc->action; + status &= ~IRQ_PENDING; /* we commit to handling */ + status |= IRQ_INPROGRESS; /* we are handling it */ } -} - -int setup_x86_irq(unsigned int irq, struct irqaction * new) -{ - int shared = 0; - struct irqaction *old, **p; - unsigned long flags; + desc->status = status; + spin_unlock(&irq_controller_lock); /* - * Some drivers like serial.c use request_irq() heavily, - * so we have to be careful not to interfere with a - * running system. + * If there is no IRQ handler or it was disabled, exit early. + Since we set PENDING, if another processor is handling + a different instance of this same irq, the other processor + will take care of it. */ - if (new->flags & SA_SAMPLE_RANDOM) { - /* - * This function might sleep, we want to call it first, - * outside of the atomic block. - * Yes, this might clear the entropy pool if the wrong - * driver is attempted to be loaded, without actually - * installing a new handler, but is this really a problem, - * only the sysadmin is able to do this. - */ - rand_initialize_irq(irq); - } + if (!action) + return 1; /* - * The following block of code has to be executed atomically + * Edge triggered interrupts need to remember + * pending events. + * This applies to any hw interrupts that allow a second + * instance of the same irq to arrive while we are in do_IRQ + * or in the handler. But the code here only handles the _second_ + * instance of the irq, not the third or fourth. So it is mostly + * useful for irq hardware that does not mask cleanly in an + * SMP environment. */ - spin_lock_irqsave(&irq_controller_lock,flags); - p = &irq_desc[irq].action; - if ((old = *p) != NULL) { - /* Can't share interrupts unless both agree to */ - if (!(old->flags & new->flags & SA_SHIRQ)) { - spin_unlock_irqrestore(&irq_controller_lock,flags); - return -EBUSY; - } - - /* add new interrupt at end of irq queue */ - do { - p = &old->next; - old = *p; - } while (old); - shared = 1; + for (;;) { + handle_IRQ_event(irq, ®s, action); + spin_lock(&irq_controller_lock); + + if (!(desc->status & IRQ_PENDING)) + break; + desc->status &= ~IRQ_PENDING; + spin_unlock(&irq_controller_lock); + } + desc->status &= ~IRQ_INPROGRESS; + if (!(desc->status & IRQ_DISABLED)){ + irq_desc[irq].handler->end(irq); } + spin_unlock(&irq_controller_lock); - *p = new; - - if (!shared) { - irq_desc[irq].depth = 0; - irq_desc[irq].status &= ~IRQ_DISABLED; - irq_desc[irq].handler->startup(irq); + /* + * This should be conditional: we should really get + * a return code from the irq handler to tell us + * whether the handler wants us to do software bottom + * half handling or not.. + */ + if (1) { + if (bh_active & bh_mask) + do_bottom_half(); } - spin_unlock_irqrestore(&irq_controller_lock,flags); - return 0; + return 1; } int request_irq(unsigned int irq, @@ -910,8 +612,7 @@ action->next = NULL; action->dev_id = dev_id; - retval = setup_x86_irq(irq, action); - + retval = setup_irq(irq, action); if (retval) kfree(action); return retval; @@ -936,13 +637,6 @@ irq_desc[irq].status |= IRQ_DISABLED; irq_desc[irq].handler->shutdown(irq); } - spin_unlock_irqrestore(&irq_controller_lock,flags); - - /* Wait to make sure it's not being used on another CPU */ - while (irq_desc[irq].status & IRQ_INPROGRESS) - barrier(); - kfree(action); - return; } printk("Trying to free free IRQ%d\n",irq); spin_unlock_irqrestore(&irq_controller_lock,flags); @@ -968,7 +662,8 @@ for (i = NR_IRQS-1; i > 0; i--) { if (!irq_desc[i].action) { irq_desc[i].status |= IRQ_AUTODETECT | IRQ_WAITING; - irq_desc[i].handler->startup(i); + if(irq_desc[i].handler->startup(i)) + irq_desc[i].status |= IRQ_PENDING; } } spin_unlock_irq(&irq_controller_lock); @@ -1031,100 +726,58 @@ return irq_found; } -void init_ISA_irqs (void) +/* this was setup_x86_irq but it seems pretty generic */ +int setup_irq(unsigned int irq, struct irqaction * new) { - int i; - - for (i = 0; i < NR_IRQS; i++) { - irq_desc[i].status = IRQ_DISABLED; - irq_desc[i].action = 0; - irq_desc[i].depth = 0; - - if (i < 16) { - /* - * 16 old-style INTA-cycle interrupts: - */ - irq_desc[i].handler = &i8259A_irq_type; - } else { - /* - * 'high' PCI IRQs filled in on demand - */ - irq_desc[i].handler = &no_irq_type; - } - } -} - -__initfunc(void init_IRQ(void)) -{ - int i; + int shared = 0; + struct irqaction *old, **p; + unsigned long flags; -#ifndef CONFIG_X86_VISWS_APIC - init_ISA_irqs(); -#else - init_VISWS_APIC_irqs(); -#endif /* - * Cover the whole vector space, no vector can escape - * us. (some of these will be overridden and become - * 'special' SMP interrupts) + * Some drivers like serial.c use request_irq() heavily, + * so we have to be careful not to interfere with a + * running system. */ - for (i = 0; i < NR_IRQS; i++) { - int vector = FIRST_EXTERNAL_VECTOR + i; - if (vector != SYSCALL_VECTOR) - set_intr_gate(vector, interrupt[i]); + if (new->flags & SA_SAMPLE_RANDOM) { + /* + * This function might sleep, we want to call it first, + * outside of the atomic block. + * Yes, this might clear the entropy pool if the wrong + * driver is attempted to be loaded, without actually + * installing a new handler, but is this really a problem, + * only the sysadmin is able to do this. + */ + rand_initialize_irq(irq); } -#ifdef __SMP__ - - /* - IRQ0 must be given a fixed assignment and initialized - before init_IRQ_SMP. - */ - set_intr_gate(IRQ0_TRAP_VECTOR, interrupt[0]); - /* - * The reschedule interrupt is a CPU-to-CPU reschedule-helper - * IPI, driven by wakeup. + * The following block of code has to be executed atomically */ - set_intr_gate(RESCHEDULE_VECTOR, reschedule_interrupt); - - /* IPI for invalidation */ - set_intr_gate(INVALIDATE_TLB_VECTOR, invalidate_interrupt); - - /* IPI for CPU halt */ - set_intr_gate(STOP_CPU_VECTOR, stop_cpu_interrupt); - - /* self generated IPI for local APIC timer */ - set_intr_gate(LOCAL_TIMER_VECTOR, apic_timer_interrupt); - - /* IPI for generic function call */ - set_intr_gate(CALL_FUNCTION_VECTOR, call_function_interrupt); + spin_lock_irqsave(&irq_controller_lock,flags); + p = &irq_desc[irq].action; + if ((old = *p) != NULL) { + /* Can't share interrupts unless both agree to */ + if (!(old->flags & new->flags & SA_SHIRQ)) { + spin_unlock_irqrestore(&irq_controller_lock,flags); + return -EBUSY; + } - /* IPI vector for APIC spurious interrupts */ - set_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt); -#endif + /* add new interrupt at end of irq queue */ + do { + p = &old->next; + old = *p; + } while (old); + shared = 1; + } - /* - * Set the clock to 100 Hz, we already have a valid - * vector now: - */ - outb_p(0x34,0x43); /* binary, mode 2, LSB/MSB, ch 0 */ - outb_p(LATCH & 0xff , 0x40); /* LSB */ - outb(LATCH >> 8 , 0x40); /* MSB */ - -#ifndef CONFIG_VISWS - setup_x86_irq(2, &irq2); - setup_x86_irq(13, &irq13); -#endif -} + *p = new; -#ifdef CONFIG_X86_IO_APIC -__initfunc(void init_IRQ_SMP(void)) -{ - int i; - for (i = 0; i < NR_IRQS ; i++) - if (IO_APIC_VECTOR(i) > 0) - set_intr_gate(IO_APIC_VECTOR(i), interrupt[i]); + if (!shared) { + irq_desc[irq].depth = 0; + irq_desc[irq].status &= ~IRQ_DISABLED; + irq_desc[irq].handler->startup(irq); + } + spin_unlock_irqrestore(&irq_controller_lock,flags); + return 0; } -#endif diff -u -r -N vanilla12/arch/i386/kernel/irq.h linux.new12/arch/i386/kernel/irq.h --- vanilla12/arch/i386/kernel/irq.h Wed Jul 28 14:58:07 1999 +++ linux.new12/arch/i386/kernel/irq.h Wed Aug 4 16:27:29 1999 @@ -1,253 +1,3 @@ -#ifndef __irq_h -#define __irq_h -#include <asm/irq.h> +DO NOT USE THIS FILE -/* - * Interrupt controller descriptor. This is all we need - * to describe about the low-level hardware. - */ -struct hw_interrupt_type { - const char * typename; - void (*startup)(unsigned int irq); - void (*shutdown)(unsigned int irq); - void (*handle)(unsigned int irq, struct pt_regs * regs); - void (*enable)(unsigned int irq); - void (*disable)(unsigned int irq); -}; - -extern struct hw_interrupt_type no_irq_type; - -/* - * IRQ line status. - */ -#define IRQ_INPROGRESS 1 /* IRQ handler active - do not enter! */ -#define IRQ_DISABLED 2 /* IRQ disabled - do not enter! */ -#define IRQ_PENDING 4 /* IRQ pending - replay on enable */ -#define IRQ_REPLAY 8 /* IRQ has been replayed but not acked yet */ -#define IRQ_AUTODETECT 16 /* IRQ is being autodetected */ -#define IRQ_WAITING 32 /* IRQ not yet seen - for autodetection */ - -/* - * This is the "IRQ descriptor", which contains various information - * about the irq, including what kind of hardware handling it has, - * whether it is disabled etc etc. - * - * Pad this out to 32 bytes for cache and indexing reasons. - */ -typedef struct { - unsigned int status; /* IRQ status - IRQ_INPROGRESS, IRQ_DISABLED */ - struct hw_interrupt_type *handler; /* handle/enable/disable functions */ - struct irqaction *action; /* IRQ action list */ - unsigned int depth; /* Disable depth for nested irq disables */ -} 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 are merged - * into a single vector (FUNCTION_VECTOR) to save vector space. - * TLB, reschedule and local APIC vectors are performance-critical.) - */ -#define RESCHEDULE_VECTOR 0x30 -#define INVALIDATE_TLB_VECTOR 0x31 -#define STOP_CPU_VECTOR 0x40 -#define LOCAL_TIMER_VECTOR 0x41 -#define CALL_FUNCTION_VECTOR 0x50 - -/* - * First APIC vector available to drivers: (vectors 0x51-0xfe) - */ -#define IRQ0_TRAP_VECTOR 0x51 - -/* - * This IRQ should never happen, but we print a message nevertheless. - */ -#define SPURIOUS_APIC_VECTOR 0xff - -extern irq_desc_t irq_desc[NR_IRQS]; -extern int irq_vector[NR_IRQS]; -#define IO_APIC_VECTOR(irq) irq_vector[irq] - -extern void init_IRQ_SMP(void); -extern int handle_IRQ_event(unsigned int, struct pt_regs *, struct irqaction *); -extern int setup_x86_irq(unsigned int, struct irqaction *); - -/* - * Various low-level irq details needed by irq.c, process.c, - * time.c, io_apic.c and smp.c - * - * Interrupt entry/exit code at both C and assembly level - */ - -extern void no_action(int cpl, void *dev_id, struct pt_regs *regs); -extern void mask_irq(unsigned int irq); -extern void unmask_irq(unsigned int irq); -extern void disable_8259A_irq(unsigned int irq); -extern int i8259A_irq_pending(unsigned int irq); -extern void ack_APIC_irq(void); -extern void FASTCALL(send_IPI_self(int vector)); -extern void init_VISWS_APIC_irqs(void); -extern void setup_IO_APIC(void); -extern int IO_APIC_get_PCI_irq_vector(int bus, int slot, int fn); -extern void make_8259A_irq(unsigned int irq); -extern void send_IPI(int dest, int vector); -extern void init_pic_mode(void); -extern void print_IO_APIC(void); - -extern unsigned long io_apic_irqs; - -extern char _stext, _etext; - -#define MAX_IRQ_SOURCES 128 -#define MAX_MP_BUSSES 32 -enum mp_bustype { - MP_BUS_ISA, - MP_BUS_EISA, - MP_BUS_PCI -}; -extern int mp_bus_id_to_type [MAX_MP_BUSSES]; -extern int mp_bus_id_to_pci_bus [MAX_MP_BUSSES]; - -extern spinlock_t irq_controller_lock; - -#ifdef __SMP__ - -#include <asm/atomic.h> - -static inline void irq_enter(int cpu, unsigned int irq) -{ - hardirq_enter(cpu); - while (test_bit(0,&global_irq_lock)) { - /* nothing */; - } -} - -static inline void irq_exit(int cpu, unsigned int irq) -{ - hardirq_exit(cpu); -} - -#define IO_APIC_IRQ(x) (((x) >= 16) || ((1<<(x)) & io_apic_irqs)) - -#else - -#define irq_enter(cpu, irq) (++local_irq_count[cpu]) -#define irq_exit(cpu, irq) (--local_irq_count[cpu]) - -#define IO_APIC_IRQ(x) (0) - -#endif - -#define __STR(x) #x -#define STR(x) __STR(x) - -#define SAVE_ALL \ - "cld\n\t" \ - "pushl %es\n\t" \ - "pushl %ds\n\t" \ - "pushl %eax\n\t" \ - "pushl %ebp\n\t" \ - "pushl %edi\n\t" \ - "pushl %esi\n\t" \ - "pushl %edx\n\t" \ - "pushl %ecx\n\t" \ - "pushl %ebx\n\t" \ - "movl $" STR(__KERNEL_DS) ",%edx\n\t" \ - "movl %dx,%ds\n\t" \ - "movl %dx,%es\n\t" - -#define IRQ_NAME2(nr) nr##_interrupt(void) -#define IRQ_NAME(nr) IRQ_NAME2(IRQ##nr) - -#define GET_CURRENT \ - "movl %esp, %ebx\n\t" \ - "andl $-8192, %ebx\n\t" - -#ifdef __SMP__ - -/* - * SMP has a few special interrupts for IPI messages - */ - -#define BUILD_SMP_INTERRUPT(x) \ -asmlinkage void x(void); \ -__asm__( \ -"\n"__ALIGN_STR"\n" \ -SYMBOL_NAME_STR(x) ":\n\t" \ - "pushl $-1\n\t" \ - SAVE_ALL \ - "call "SYMBOL_NAME_STR(smp_##x)"\n\t" \ - "jmp ret_from_intr\n"); - -#define BUILD_SMP_TIMER_INTERRUPT(x) \ -asmlinkage void x(struct pt_regs * regs); \ -__asm__( \ -"\n"__ALIGN_STR"\n" \ -SYMBOL_NAME_STR(x) ":\n\t" \ - "pushl $-1\n\t" \ - SAVE_ALL \ - "movl %esp,%eax\n\t" \ - "pushl %eax\n\t" \ - "call "SYMBOL_NAME_STR(smp_##x)"\n\t" \ - "addl $4,%esp\n\t" \ - "jmp ret_from_intr\n"); - -#endif /* __SMP__ */ - -#define BUILD_COMMON_IRQ() \ -__asm__( \ - "\n" __ALIGN_STR"\n" \ - "common_interrupt:\n\t" \ - SAVE_ALL \ - "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__( \ -"\n"__ALIGN_STR"\n" \ -SYMBOL_NAME_STR(IRQ) #nr "_interrupt:\n\t" \ - "pushl $"#nr"-256\n\t" \ - "jmp common_interrupt"); - -/* - * x86 profiling function, SMP safe. We might want to do this in - * assembly totally? - */ -static inline void x86_do_profile (unsigned long eip) -{ - if (prof_buffer) { - eip -= (unsigned long) &_stext; - eip >>= prof_shift; - /* - * Don't ignore out-of-bounds EIP values silently, - * put them into the last histogram slot, so if - * present, they will show up as a sharp peak. - */ - if (eip > prof_len-1) - eip = prof_len-1; - atomic_inc((atomic_t *)&prof_buffer[eip]); - } -} - -#endif diff -u -r -N vanilla12/arch/i386/kernel/mtrr.c linux.new12/arch/i386/kernel/mtrr.c --- vanilla12/arch/i386/kernel/mtrr.c Sun Jun 27 11:10:41 1999 +++ linux.new12/arch/i386/kernel/mtrr.c Wed Aug 4 16:20:49 1999 @@ -235,7 +235,7 @@ #include <asm/msr.h> #include <asm/hardirq.h> -#include "irq.h" +#include <linux/irq.h> #define MTRR_VERSION "1.35 (19990512)" diff -u -r -N vanilla12/arch/i386/kernel/process.c linux.new12/arch/i386/kernel/process.c --- vanilla12/arch/i386/kernel/process.c Mon Jul 26 00:15:13 1999 +++ linux.new12/arch/i386/kernel/process.c Wed Aug 4 16:20:49 1999 @@ -45,7 +45,7 @@ #include <asm/math_emu.h> #endif -#include "irq.h" +#include <linux/irq.h> spinlock_t semaphore_wake_lock = SPIN_LOCK_UNLOCKED; diff -u -r -N vanilla12/arch/i386/kernel/smp.c linux.new12/arch/i386/kernel/smp.c --- vanilla12/arch/i386/kernel/smp.c Wed Jul 28 11:45:39 1999 +++ linux.new12/arch/i386/kernel/smp.c Wed Aug 4 16:20:49 1999 @@ -42,7 +42,7 @@ #include <asm/mtrr.h> #include <asm/msr.h> -#include "irq.h" +#include <linux/irq.h> #define JIFFIE_TIMEOUT 100 diff -u -r -N vanilla12/arch/i386/kernel/time.c linux.new12/arch/i386/kernel/time.c --- vanilla12/arch/i386/kernel/time.c Thu Apr 29 12:53:41 1999 +++ linux.new12/arch/i386/kernel/time.c Wed Aug 4 16:20:49 1999 @@ -59,7 +59,7 @@ /* * for x86_do_profile() */ -#include "irq.h" +#include <linux/irq.h> unsigned long cpu_hz; /* Detected as we calibrate the TSC */ @@ -681,8 +681,8 @@ co_cpu_write(CO_CPU_CTRL, co_cpu_read(CO_CPU_CTRL) & ~CO_CTRL_TIMEMASK); /* Wire cpu IDT entry to s/w handler (and Cobalt APIC to IDT) */ - setup_x86_irq(CO_IRQ_TIMER, &irq0); + setup_irq(CO_IRQ_TIMER, &irq0); #else - setup_x86_irq(0, &irq0); + setup_irq(0, &irq0); #endif } diff -u -r -N vanilla12/arch/i386/kernel/traps.c linux.new12/arch/i386/kernel/traps.c --- vanilla12/arch/i386/kernel/traps.c Sun Jul 25 14:45:25 1999 +++ linux.new12/arch/i386/kernel/traps.c Wed Aug 4 16:20:49 1999 @@ -42,7 +42,7 @@ #include <asm/lithium.h> #endif -#include "irq.h" +#include <linux/irq.h> asmlinkage int system_call(void); asmlinkage void lcall7(void); diff -u -r -N vanilla12/include/asm-i386/hw_irq.h linux.new12/include/asm-i386/hw_irq.h --- vanilla12/include/asm-i386/hw_irq.h Wed Dec 31 17:00:00 1969 +++ linux.new12/include/asm-i386/hw_irq.h Wed Aug 4 16:36:14 1999 @@ -0,0 +1,213 @@ +#ifndef _ASM_HW_IRQ_H +#define _ASM_HW_IRQ_H + +/* + * linux/include/asm/hw_irq.h + * + * (C) 1992, 1993 Linus Torvalds, (C) 1997 Ingo Molnar + * + * moved some of the old arch/i386/kernel/irq.h to here. VY + * + * IRQ/IPI changes taken from work by Thomas Radke + * <tomsoft@informatik.tu-chemnitz.de> + */ + +#include <asm/irq.h> + +/* + * 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 are merged + * into a single vector (FUNCTION_VECTOR) to save vector space. + * TLB, reschedule and local APIC vectors are performance-critical.) + */ +#define RESCHEDULE_VECTOR 0x30 +#define INVALIDATE_TLB_VECTOR 0x31 +#define STOP_CPU_VECTOR 0x40 +#define LOCAL_TIMER_VECTOR 0x41 +#define CALL_FUNCTION_VECTOR 0x50 + +/* + * First APIC vector available to drivers: (vectors 0x51-0xfe) + */ +#define IRQ0_TRAP_VECTOR 0x51 + +/* + * This IRQ should never happen, but we print a message nevertheless. + */ +#define SPURIOUS_APIC_VECTOR 0xff + +extern int irq_vector[NR_IRQS]; +#define IO_APIC_VECTOR(irq) irq_vector[irq] + +extern void init_IRQ_SMP(void); + +/* + * Various low-level irq details needed by irq.c, process.c, + * time.c, io_apic.c and smp.c + * + * Interrupt entry/exit code at both C and assembly level + */ + +extern void no_action(int cpl, void *dev_id, struct pt_regs *regs); +extern void mask_irq(unsigned int irq); +extern void unmask_irq(unsigned int irq); +extern void disable_8259A_irq(unsigned int irq); +extern int i8259A_irq_pending(unsigned int irq); +extern void ack_APIC_irq(void); +extern void FASTCALL(send_IPI_self(int vector)); +extern void init_VISWS_APIC_irqs(void); +extern void setup_IO_APIC(void); +extern int IO_APIC_get_PCI_irq_vector(int bus, int slot, int fn); +extern void make_8259A_irq(unsigned int irq); +extern void send_IPI(int dest, int vector); +extern void init_pic_mode(void); +extern void print_IO_APIC(void); + +extern unsigned long io_apic_irqs; + +extern char _stext, _etext; + +#define MAX_IRQ_SOURCES 128 +#define MAX_MP_BUSSES 32 +enum mp_bustype { + MP_BUS_ISA, + MP_BUS_EISA, + MP_BUS_PCI +}; +extern int mp_bus_id_to_type [MAX_MP_BUSSES]; +extern int mp_bus_id_to_pci_bus [MAX_MP_BUSSES]; + + +#ifdef __SMP__ +#define IO_APIC_IRQ(x) (((x) >= 16) || ((1<<(x)) & io_apic_irqs)) + +#else + +#define IO_APIC_IRQ(x) (0) + +#endif + +#define __STR(x) #x +#define STR(x) __STR(x) + +#define SAVE_ALL \ + "cld\n\t" \ + "pushl %es\n\t" \ + "pushl %ds\n\t" \ + "pushl %eax\n\t" \ + "pushl %ebp\n\t" \ + "pushl %edi\n\t" \ + "pushl %esi\n\t" \ + "pushl %edx\n\t" \ + "pushl %ecx\n\t" \ + "pushl %ebx\n\t" \ + "movl $" STR(__KERNEL_DS) ",%edx\n\t" \ + "movl %dx,%ds\n\t" \ + "movl %dx,%es\n\t" + +#define IRQ_NAME2(nr) nr##_interrupt(void) +#define IRQ_NAME(nr) IRQ_NAME2(IRQ##nr) + +#define GET_CURRENT \ + "movl %esp, %ebx\n\t" \ + "andl $-8192, %ebx\n\t" + +#ifdef __SMP__ + +/* + * SMP has a few special interrupts for IPI messages + */ + +#define BUILD_SMP_INTERRUPT(x) \ +asmlinkage void x(void); \ +__asm__( \ +"\n"__ALIGN_STR"\n" \ +SYMBOL_NAME_STR(x) ":\n\t" \ + "pushl $-1\n\t" \ + SAVE_ALL \ + "call "SYMBOL_NAME_STR(smp_##x)"\n\t" \ + "jmp ret_from_intr\n"); + +#define BUILD_SMP_TIMER_INTERRUPT(x) \ +asmlinkage void x(struct pt_regs * regs); \ +__asm__( \ +"\n"__ALIGN_STR"\n" \ +SYMBOL_NAME_STR(x) ":\n\t" \ + "pushl $-1\n\t" \ + SAVE_ALL \ + "movl %esp,%eax\n\t" \ + "pushl %eax\n\t" \ + "call "SYMBOL_NAME_STR(smp_##x)"\n\t" \ + "addl $4,%esp\n\t" \ + "jmp ret_from_intr\n"); + +#endif /* __SMP__ */ + +#define BUILD_COMMON_IRQ() \ +__asm__( \ + "\n" __ALIGN_STR"\n" \ + "common_interrupt:\n\t" \ + SAVE_ALL \ + "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 ;) + * + * Subtle as a pigs ear. VY + */ + +#define BUILD_IRQ(nr) \ +asmlinkage void IRQ_NAME(nr); \ +__asm__( \ +"\n"__ALIGN_STR"\n" \ +SYMBOL_NAME_STR(IRQ) #nr "_interrupt:\n\t" \ + "pushl $"#nr"-256\n\t" \ + "jmp common_interrupt"); + +/* + * x86 profiling function, SMP safe. We might want to do this in + * assembly totally? + */ +static inline void x86_do_profile (unsigned long eip) +{ + if (prof_buffer && current->pid) { + eip -= (unsigned long) &_stext; + eip >>= prof_shift; + /* + * Don't ignore out-of-bounds EIP values silently, + * put them into the last histogram slot, so if + * present, they will show up as a sharp peak. + */ + if (eip > prof_len-1) + eip = prof_len-1; + atomic_inc((atomic_t *)&prof_buffer[eip]); + } +} + +#ifdef __SMP__ /*more of this file should probably be ifdefed SMP */ +static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i) { + send_IPI_self(IO_APIC_VECTOR(i)); +} +#else +static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i) {} +#endif + +#endif /* _ASM_HW_IRQ_H */ diff -u -r -N vanilla12/include/linux/irq.h linux.new12/include/linux/irq.h --- vanilla12/include/linux/irq.h Wed Dec 31 17:00:00 1969 +++ linux.new12/include/linux/irq.h Wed Aug 4 16:36:15 1999 @@ -0,0 +1,79 @@ +#ifndef __irq_h +#define __irq_h + +#include <asm/irq.h> +/* + * IRQ line status. + */ +#define IRQ_INPROGRESS 1 /* IRQ handler active - do not enter! */ +#define IRQ_DISABLED 2 /* IRQ disabled - do not enter! */ +#define IRQ_PENDING 4 /* IRQ pending - replay on enable */ +#define IRQ_REPLAY 8 /* IRQ has been replayed but not acked yet */ +#define IRQ_AUTODETECT 16 /* IRQ is being autodetected */ +#define IRQ_WAITING 32 /* IRQ not yet seen - for autodetection */ + +/* + * Interrupt controller descriptor. This is all we need + * to describe about the low-level hardware. + */ +struct hw_interrupt_type { + const char * typename; + unsigned int (*startup)(unsigned int irq); + void (*shutdown)(unsigned int irq); + void (*enable)(unsigned int irq); + void (*disable)(unsigned int irq); + void (*ack)(unsigned int irq); + void (*end)(unsigned int irq); +}; + +typedef struct hw_interrupt_type hw_irq_controller; + +/* + * This is the "IRQ descriptor", which contains various information + * about the irq, including what kind of hardware handling it has, + * whether it is disabled etc etc. + * + * Pad this out to 32 bytes for cache and indexing reasons. + */ +typedef struct { + unsigned int status; /* IRQ status + - IRQ_INPROGRESS, IRQ_DISABLED */ + hw_irq_controller *handler; /* never derefed in arch + independent code */ + struct irqaction *action; /* IRQ action list */ + unsigned int depth; /* Disable depth for nested irq disables */ +} irq_desc_t; + +#include <asm/hw_irq.h> /* the arch dependent stuff */ + +extern irq_desc_t irq_desc[NR_IRQS]; + +extern int handle_IRQ_event(unsigned int, struct pt_regs *, struct irqaction *); +extern spinlock_t irq_controller_lock; +extern int setup_irq(unsigned int , struct irqaction * ); + +#ifdef __SMP__ + +#include <asm/atomic.h> + +static inline void irq_enter(int cpu, unsigned int irq) +{ + hardirq_enter(cpu); + while (test_bit(0,&global_irq_lock)) { + /* nothing */; + } +} + +static inline void irq_exit(int cpu, unsigned int irq) +{ + hardirq_exit(cpu); +} +#else +#define irq_enter(cpu, irq) (++local_irq_count[cpu]) +#define irq_exit(cpu, irq) (--local_irq_count[cpu]) +#endif + +extern hw_irq_controller no_irq_type; /* needed in every arch ? */ + +#endif /* __asm_h */ + - 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/
| |