patch-2.1.35 linux/arch/i386/kernel/irq.h
Next file: linux/arch/i386/kernel/mca.c
Previous file: linux/arch/i386/kernel/irq.c
Back to the patch index
Back to the overall index
- Lines: 270
- Date:
Tue Apr 15 11:50:30 1997
- Orig file:
v2.1.34/linux/arch/i386/kernel/irq.h
- Orig date:
Wed Dec 31 16:00:00 1969
diff -u --recursive --new-file v2.1.34/linux/arch/i386/kernel/irq.h linux/arch/i386/kernel/irq.h
@@ -0,0 +1,269 @@
+#ifndef __irq_h
+#define __irq_h
+
+/*
+ * Various low-level irq details needed by irq.c and smp.c
+ *
+ * Interrupt entry/exit code at both C and assembly level
+ */
+
+#ifdef __SMP__
+
+#undef INIT_STUCK
+#define INIT_STUCK 200000000
+
+#undef STUCK
+#define STUCK \
+if (!--stuck) {printk("irq_enter stuck (irq=%d, cpu=%d, global=%d)\n",irq,cpu,global_irq_holder); stuck = INIT_STUCK;}
+
+static inline void irq_enter(int cpu, int irq)
+{
+ int stuck = INIT_STUCK;
+
+ hardirq_enter(cpu);
+ while (test_bit(0,&global_irq_lock)) {
+ if ((unsigned char) cpu == global_irq_holder) {
+ printk("BAD! Local interrupts enabled, global disabled\n");
+ break;
+ }
+ STUCK;
+ /* nothing */;
+ }
+}
+
+static inline void irq_exit(int cpu, int irq)
+{
+ __cli();
+ hardirq_exit(cpu);
+ release_irqlock(cpu);
+}
+
+#else
+
+#define irq_enter(cpu, irq) (++local_irq_count[cpu])
+#define irq_exit(cpu, irq) (--local_irq_count[cpu])
+
+#endif
+
+#define __STR(x) #x
+#define STR(x) __STR(x)
+
+#define SAVE_ALL \
+ "cld\n\t" \
+ "push %es\n\t" \
+ "push %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" \
+ "mov %dx,%ds\n\t" \
+ "mov %dx,%es\n\t"
+
+/*
+ * SAVE_MOST/RESTORE_MOST is used for the faster version of IRQ handlers,
+ * installed by using the SA_INTERRUPT flag. These kinds of IRQ's don't
+ * call the routines that do signal handling etc on return, and can have
+ * more relaxed register-saving etc. They are also atomic, and are thus
+ * suited for small, fast interrupts like the serial lines or the harddisk
+ * drivers, which don't actually need signal handling etc.
+ *
+ * Also note that we actually save only those registers that are used in
+ * C subroutines (%eax, %edx and %ecx), so if you do something weird,
+ * you're on your own. The only segments that are saved (not counting the
+ * automatic stack and code segment handling) are %ds and %es, and they
+ * point to kernel space. No messing around with %fs here.
+ */
+#define SAVE_MOST \
+ "cld\n\t" \
+ "push %es\n\t" \
+ "push %ds\n\t" \
+ "pushl %eax\n\t" \
+ "pushl %edx\n\t" \
+ "pushl %ecx\n\t" \
+ "movl $" STR(KERNEL_DS) ",%edx\n\t" \
+ "mov %dx,%ds\n\t" \
+ "mov %dx,%es\n\t"
+
+#define RESTORE_MOST \
+ "popl %ecx\n\t" \
+ "popl %edx\n\t" \
+ "popl %eax\n\t" \
+ "pop %ds\n\t" \
+ "pop %es\n\t" \
+ "iret"
+
+/*
+ * Some fast irq handlers might want to access saved registers (mostly
+ * cs or flags)
+ */
+
+struct fast_irq_regs {
+ long ecx;
+ long edx;
+ long eax;
+ int xds;
+ int xes;
+ long eip;
+ int xcs;
+ long eflags;
+ long esp;
+ int xss;
+};
+
+/*
+ * The "inb" instructions are not needed, but seem to change the timings
+ * a bit - without them it seems that the harddisk driver won't work on
+ * all hardware. Arghh.
+ */
+#define ACK_FIRST(mask,nr) \
+ "inb $0x21,%al\n\t" \
+ "jmp 1f\n" \
+ "1:\tjmp 1f\n" \
+ "1:\torb $" #mask ","SYMBOL_NAME_STR(cache_21)"\n\t" \
+ "movb "SYMBOL_NAME_STR(cache_21)",%al\n\t" \
+ "outb %al,$0x21\n\t" \
+ "jmp 1f\n" \
+ "1:\tjmp 1f\n" \
+ "1:\tmovb $0x20,%al\n\t" \
+ "outb %al,$0x20\n\t"
+
+#define ACK_SECOND(mask,nr) \
+ "inb $0xA1,%al\n\t" \
+ "jmp 1f\n" \
+ "1:\tjmp 1f\n" \
+ "1:\torb $" #mask ","SYMBOL_NAME_STR(cache_A1)"\n\t" \
+ "movb "SYMBOL_NAME_STR(cache_A1)",%al\n\t" \
+ "outb %al,$0xA1\n\t" \
+ "jmp 1f\n" \
+ "1:\tjmp 1f\n" \
+ "1:\tmovb $0x20,%al\n\t" \
+ "outb %al,$0xA0\n\t" \
+ "jmp 1f\n" \
+ "1:\tjmp 1f\n" \
+ "1:\toutb %al,$0x20\n\t"
+
+#define UNBLK_FIRST(mask) \
+ "inb $0x21,%al\n\t" \
+ "jmp 1f\n" \
+ "1:\tjmp 1f\n" \
+ "1:\tandb $~(" #mask "),"SYMBOL_NAME_STR(cache_21)"\n\t" \
+ "movb "SYMBOL_NAME_STR(cache_21)",%al\n\t" \
+ "outb %al,$0x21\n\t"
+
+#define UNBLK_SECOND(mask) \
+ "inb $0xA1,%al\n\t" \
+ "jmp 1f\n" \
+ "1:\tjmp 1f\n" \
+ "1:\tandb $~(" #mask "),"SYMBOL_NAME_STR(cache_A1)"\n\t" \
+ "movb "SYMBOL_NAME_STR(cache_A1)",%al\n\t" \
+ "outb %al,$0xA1\n\t"
+
+#define IRQ_NAME2(nr) nr##_interrupt(void)
+#define IRQ_NAME(nr) IRQ_NAME2(IRQ##nr)
+#define FAST_IRQ_NAME(nr) IRQ_NAME2(fast_IRQ##nr)
+#define BAD_IRQ_NAME(nr) IRQ_NAME2(bad_IRQ##nr)
+
+#ifdef __SMP__
+
+#define GET_CURRENT \
+ "movl "SYMBOL_NAME_STR(apic_reg)", %ebx\n\t" \
+ "movl 32(%ebx), %ebx\n\t" \
+ "shrl $22,%ebx\n\t" \
+ "andl $0x3C,%ebx\n\t" \
+ "movl " SYMBOL_NAME_STR(current_set) "(,%ebx),%ebx\n\t"
+
+#else
+
+#define GET_CURRENT \
+ "movl " SYMBOL_NAME_STR(current_set) ",%ebx\n\t"
+
+#endif
+
+#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_IRQ(chip,nr,mask) \
+asmlinkage void IRQ_NAME(nr); \
+asmlinkage void FAST_IRQ_NAME(nr); \
+asmlinkage void BAD_IRQ_NAME(nr); \
+__asm__( \
+"\n"__ALIGN_STR"\n" \
+SYMBOL_NAME_STR(IRQ) #nr "_interrupt:\n\t" \
+ "pushl $-"#nr"-2\n\t" \
+ SAVE_ALL \
+ ACK_##chip(mask,(nr&7)) \
+ "movl %esp,%eax\n\t" \
+ "pushl %eax\n\t" \
+ "pushl $" #nr "\n\t" \
+ "call "SYMBOL_NAME_STR(do_IRQ)"\n\t" \
+ "addl $8,%esp\n\t" \
+ UNBLK_##chip(mask) \
+ "jmp ret_from_intr\n" \
+"\n"__ALIGN_STR"\n" \
+SYMBOL_NAME_STR(fast_IRQ) #nr "_interrupt:\n\t" \
+ SAVE_MOST \
+ ACK_##chip(mask,(nr&7)) \
+ "pushl $" #nr "\n\t" \
+ "call "SYMBOL_NAME_STR(do_fast_IRQ)"\n\t" \
+ "addl $4,%esp\n\t" \
+ UNBLK_##chip(mask) \
+ RESTORE_MOST \
+"\n"__ALIGN_STR"\n" \
+SYMBOL_NAME_STR(bad_IRQ) #nr "_interrupt:\n\t" \
+ SAVE_MOST \
+ ACK_##chip(mask,(nr&7)) \
+ RESTORE_MOST);
+
+#define BUILD_TIMER_IRQ(chip,nr,mask) \
+asmlinkage void IRQ_NAME(nr); \
+asmlinkage void FAST_IRQ_NAME(nr); \
+asmlinkage void BAD_IRQ_NAME(nr); \
+__asm__( \
+"\n"__ALIGN_STR"\n" \
+SYMBOL_NAME_STR(fast_IRQ) #nr "_interrupt:\n\t" \
+SYMBOL_NAME_STR(bad_IRQ) #nr "_interrupt:\n\t" \
+SYMBOL_NAME_STR(IRQ) #nr "_interrupt:\n\t" \
+ "pushl $-"#nr"-2\n\t" \
+ SAVE_ALL \
+ ACK_##chip(mask,(nr&7)) \
+ "movl %esp,%eax\n\t" \
+ "pushl %eax\n\t" \
+ "pushl $" #nr "\n\t" \
+ "call "SYMBOL_NAME_STR(do_IRQ)"\n\t" \
+ "addl $8,%esp\n\t" \
+ UNBLK_##chip(mask) \
+ "jmp ret_from_intr\n");
+
+#endif
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov