root/include/asm-i386/irq.h

/* [previous][next][first][last][top][bottom][index][help] */

INCLUDED FROM


   1 #ifndef _ASM_IRQ_H
   2 #define _ASM_IRQ_H
   3 
   4 /*
   5  *      linux/include/asm/irq.h
   6  *
   7  *      (C) 1992, 1993 Linus Torvalds
   8  *
   9  *      IRQ/IPI changes taken from work by Thomas Radke <tomsoft@informatik.tu-chemnitz.de>
  10  */
  11 
  12 #include <linux/linkage.h>
  13 #include <asm/segment.h>
  14 
  15 #define NR_IRQS 16
  16 
  17 #define TIMER_IRQ 0
  18 
  19 extern void disable_irq(unsigned int);
  20 extern void enable_irq(unsigned int);
  21 
  22 #define __STR(x) #x
  23 #define STR(x) __STR(x)
  24  
  25 #define SAVE_ALL \
  26         "cld\n\t" \
  27         "push %gs\n\t" \
  28         "push %fs\n\t" \
  29         "push %es\n\t" \
  30         "push %ds\n\t" \
  31         "pushl %eax\n\t" \
  32         "pushl %ebp\n\t" \
  33         "pushl %edi\n\t" \
  34         "pushl %esi\n\t" \
  35         "pushl %edx\n\t" \
  36         "pushl %ecx\n\t" \
  37         "pushl %ebx\n\t" \
  38         "movl $" STR(KERNEL_DS) ",%edx\n\t" \
  39         "mov %dx,%ds\n\t" \
  40         "mov %dx,%es\n\t" \
  41         "movl $" STR(USER_DS) ",%edx\n\t" \
  42         "mov %dx,%fs\n\t"   \
  43         "movl $0,%edx\n\t"  \
  44         "movl %edx,%db7\n\t"
  45 
  46 /*
  47  * SAVE_MOST/RESTORE_MOST is used for the faster version of IRQ handlers,
  48  * installed by using the SA_INTERRUPT flag. These kinds of IRQ's don't
  49  * call the routines that do signal handling etc on return, and can have
  50  * more relaxed register-saving etc. They are also atomic, and are thus
  51  * suited for small, fast interrupts like the serial lines or the harddisk
  52  * drivers, which don't actually need signal handling etc.
  53  *
  54  * Also note that we actually save only those registers that are used in
  55  * C subroutines (%eax, %edx and %ecx), so if you do something weird,
  56  * you're on your own. The only segments that are saved (not counting the
  57  * automatic stack and code segment handling) are %ds and %es, and they
  58  * point to kernel space. No messing around with %fs here.
  59  */
  60 #define SAVE_MOST \
  61         "cld\n\t" \
  62         "push %es\n\t" \
  63         "push %ds\n\t" \
  64         "pushl %eax\n\t" \
  65         "pushl %edx\n\t" \
  66         "pushl %ecx\n\t" \
  67         "movl $" STR(KERNEL_DS) ",%edx\n\t" \
  68         "mov %dx,%ds\n\t" \
  69         "mov %dx,%es\n\t"
  70 
  71 #define RESTORE_MOST \
  72         "popl %ecx\n\t" \
  73         "popl %edx\n\t" \
  74         "popl %eax\n\t" \
  75         "pop %ds\n\t" \
  76         "pop %es\n\t" \
  77         "iret"
  78 
  79 /*
  80  * The "inb" instructions are not needed, but seem to change the timings
  81  * a bit - without them it seems that the harddisk driver won't work on
  82  * all hardware. Arghh.
  83  */
  84 #define ACK_FIRST(mask) \
  85         "inb $0x21,%al\n\t" \
  86         "jmp 1f\n" \
  87         "1:\tjmp 1f\n" \
  88         "1:\torb $" #mask ","SYMBOL_NAME_STR(cache_21)"\n\t" \
  89         "movb "SYMBOL_NAME_STR(cache_21)",%al\n\t" \
  90         "outb %al,$0x21\n\t" \
  91         "jmp 1f\n" \
  92         "1:\tjmp 1f\n" \
  93         "1:\tmovb $0x20,%al\n\t" \
  94         "outb %al,$0x20\n\t"
  95 
  96 #define ACK_SECOND(mask) \
  97         "inb $0xA1,%al\n\t" \
  98         "jmp 1f\n" \
  99         "1:\tjmp 1f\n" \
 100         "1:\torb $" #mask ","SYMBOL_NAME_STR(cache_A1)"\n\t" \
 101         "movb "SYMBOL_NAME_STR(cache_A1)",%al\n\t" \
 102         "outb %al,$0xA1\n\t" \
 103         "jmp 1f\n" \
 104         "1:\tjmp 1f\n" \
 105         "1:\tmovb $0x20,%al\n\t" \
 106         "outb %al,$0xA0\n\t" \
 107         "jmp 1f\n" \
 108         "1:\tjmp 1f\n" \
 109         "1:\toutb %al,$0x20\n\t"
 110 
 111 #define UNBLK_FIRST(mask) \
 112         "inb $0x21,%al\n\t" \
 113         "jmp 1f\n" \
 114         "1:\tjmp 1f\n" \
 115         "1:\tandb $~(" #mask "),"SYMBOL_NAME_STR(cache_21)"\n\t" \
 116         "movb "SYMBOL_NAME_STR(cache_21)",%al\n\t" \
 117         "outb %al,$0x21\n\t"
 118 
 119 #define UNBLK_SECOND(mask) \
 120         "inb $0xA1,%al\n\t" \
 121         "jmp 1f\n" \
 122         "1:\tjmp 1f\n" \
 123         "1:\tandb $~(" #mask "),"SYMBOL_NAME_STR(cache_A1)"\n\t" \
 124         "movb "SYMBOL_NAME_STR(cache_A1)",%al\n\t" \
 125         "outb %al,$0xA1\n\t"
 126 
 127 #define IRQ_NAME2(nr) nr##_interrupt(void)
 128 #define IRQ_NAME(nr) IRQ_NAME2(IRQ##nr)
 129 #define FAST_IRQ_NAME(nr) IRQ_NAME2(fast_IRQ##nr)
 130 #define BAD_IRQ_NAME(nr) IRQ_NAME2(bad_IRQ##nr)
 131 
 132 #ifdef  __SMP__
 133 
 134 #ifndef __SMP_PROF__
 135 #define SMP_PROF_INT_SPINS 
 136 #define SMP_PROF_IPI_CNT 
 137 #else
 138 #define SMP_PROF_INT_SPINS "incl "SYMBOL_NAME_STR(smp_spins)"(,%eax,4)\n\t"
 139 #define SMP_PROF_IPI_CNT "incl "SYMBOL_NAME_STR(ipi_count)"\n\t" 
 140 #endif
 141 
 142 #define GET_PROCESSOR_ID \
 143         "movl "SYMBOL_NAME_STR(apic_reg)", %edx\n\t" \
 144         "movl 32(%edx), %eax\n\t" \
 145         "shrl $24,%eax\n\t" \
 146         "andb $0x0F,%al\n"
 147         
 148 #define ENTER_KERNEL \
 149         "pushl %eax\n\t" \
 150         "pushl %edx\n\t" \
 151         "pushfl\n\t" \
 152         "cli\n\t" \
 153         GET_PROCESSOR_ID \
 154         "btsl $" STR(SMP_FROM_INT) ","SYMBOL_NAME_STR(smp_proc_in_lock)"(,%eax,4)\n\t" \
 155         "1: " \
 156         "lock\n\t" \
 157         "btsl $0, "SYMBOL_NAME_STR(kernel_flag)"\n\t" \
 158         "jnc 3f\n\t" \
 159         "cmpb "SYMBOL_NAME_STR(active_kernel_processor)", %al\n\t" \
 160         "je 4f\n\t" \
 161         "2: " \
 162         SMP_PROF_INT_SPINS \
 163         "btl %al, "SYMBOL_NAME_STR(smp_invalidate_needed)"\n\t" \
 164         "jnc 5f\n\t" \
 165         "lock\n\t" \
 166         "btrl %al, "SYMBOL_NAME_STR(smp_invalidate_needed)"\n\t" \
 167         "jnc 5f\n\t" \
 168         "movl %cr3,%edx\n\t" \
 169         "movl %edx,%cr3\n" \
 170         "5: btl $0, "SYMBOL_NAME_STR(kernel_flag)"\n\t" \
 171         "jc 2b\n\t" \
 172         "jmp 1b\n\t" \
 173         "3: " \
 174         "movb %al, "SYMBOL_NAME_STR(active_kernel_processor)"\n\t" \
 175         "4: " \
 176         "incl "SYMBOL_NAME_STR(kernel_counter)"\n\t" \
 177         "popfl\n\t" \
 178         "popl %edx\n\t" \
 179         "popl %eax\n\t"
 180 
 181 #define LEAVE_KERNEL \
 182         GET_PROCESSOR_ID \
 183         "btrl $" STR(SMP_FROM_INT) ","SYMBOL_NAME_STR(smp_proc_in_lock)"(,%eax,4)\n\t" \
 184         "pushfl\n\t" \
 185         "cli\n\t" \
 186         "decl "SYMBOL_NAME_STR(kernel_counter)"\n\t" \
 187         "jnz 1f\n\t" \
 188         "movb $" STR (NO_PROC_ID) ", "SYMBOL_NAME_STR(active_kernel_processor)"\n\t" \
 189         "lock\n\t" \
 190         "btrl $0, "SYMBOL_NAME_STR(kernel_flag)"\n\t" \
 191         "1: " \
 192         "popfl\n\t"
 193         
 194         
 195 /*
 196  *      the syscall count inc is a gross hack because ret_from_syscall is used by both irq and
 197  *      syscall return paths (urghh).
 198  */
 199  
 200 #define BUILD_IRQ(chip,nr,mask) \
 201 asmlinkage void IRQ_NAME(nr); \
 202 asmlinkage void FAST_IRQ_NAME(nr); \
 203 asmlinkage void BAD_IRQ_NAME(nr); \
 204 __asm__( \
 205 "\n"__ALIGN_STR"\n" \
 206 SYMBOL_NAME_STR(IRQ) #nr "_interrupt:\n\t" \
 207         "pushl $-"#nr"-2\n\t" \
 208         SAVE_ALL \
 209         ENTER_KERNEL \
 210         ACK_##chip(mask) \
 211         "incl "SYMBOL_NAME_STR(intr_count)"\n\t"\
 212         "sti\n\t" \
 213         "movl %esp,%ebx\n\t" \
 214         "pushl %ebx\n\t" \
 215         "pushl $" #nr "\n\t" \
 216         "call "SYMBOL_NAME_STR(do_IRQ)"\n\t" \
 217         "addl $8,%esp\n\t" \
 218         "cli\n\t" \
 219         UNBLK_##chip(mask) \
 220         "decl "SYMBOL_NAME_STR(intr_count)"\n\t" \
 221         "incl "SYMBOL_NAME_STR(syscall_count)"\n\t" \
 222         "jmp ret_from_sys_call\n" \
 223 "\n"__ALIGN_STR"\n" \
 224 SYMBOL_NAME_STR(fast_IRQ) #nr "_interrupt:\n\t" \
 225         SAVE_MOST \
 226         ENTER_KERNEL \
 227         ACK_##chip(mask) \
 228         "incl "SYMBOL_NAME_STR(intr_count)"\n\t" \
 229         "pushl $" #nr "\n\t" \
 230         "call "SYMBOL_NAME_STR(do_fast_IRQ)"\n\t" \
 231         "addl $4,%esp\n\t" \
 232         "cli\n\t" \
 233         UNBLK_##chip(mask) \
 234         "decl "SYMBOL_NAME_STR(intr_count)"\n\t" \
 235         LEAVE_KERNEL \
 236         RESTORE_MOST \
 237 "\n"__ALIGN_STR"\n" \
 238 SYMBOL_NAME_STR(bad_IRQ) #nr "_interrupt:\n\t" \
 239         SAVE_MOST \
 240         ENTER_KERNEL \
 241         ACK_##chip(mask) \
 242         LEAVE_KERNEL \
 243         RESTORE_MOST);
 244         
 245  
 246 #define BUILD_TIMER_IRQ(chip,nr,mask) \
 247 asmlinkage void IRQ_NAME(nr); \
 248 asmlinkage void FAST_IRQ_NAME(nr); \
 249 asmlinkage void BAD_IRQ_NAME(nr); \
 250 __asm__( \
 251 "\n"__ALIGN_STR"\n" \
 252 SYMBOL_NAME_STR(fast_IRQ) #nr "_interrupt:\n\t" \
 253 SYMBOL_NAME_STR(bad_IRQ) #nr "_interrupt:\n\t" \
 254 SYMBOL_NAME_STR(IRQ) #nr "_interrupt:\n\t" \
 255         "pushl $-"#nr"-2\n\t" \
 256         SAVE_ALL \
 257         ENTER_KERNEL \
 258         ACK_##chip(mask) \
 259         "incl "SYMBOL_NAME_STR(intr_count)"\n\t"\
 260         "movl %esp,%ebx\n\t" \
 261         "pushl %ebx\n\t" \
 262         "pushl $" #nr "\n\t" \
 263         "call "SYMBOL_NAME_STR(do_IRQ)"\n\t" \
 264         "addl $8,%esp\n\t" \
 265         "cli\n\t" \
 266         UNBLK_##chip(mask) \
 267         "decl "SYMBOL_NAME_STR(intr_count)"\n\t" \
 268         "incl "SYMBOL_NAME_STR(syscall_count)"\n\t" \
 269         "jmp ret_from_sys_call\n");
 270 
 271         
 272 /*
 273  *      Message pass must be a fast IRQ..
 274  */
 275 
 276 #define BUILD_MSGIRQ(chip,nr,mask) \
 277 asmlinkage void IRQ_NAME(nr); \
 278 asmlinkage void FAST_IRQ_NAME(nr); \
 279 asmlinkage void BAD_IRQ_NAME(nr); \
 280 __asm__( \
 281 "\n"__ALIGN_STR"\n" \
 282 SYMBOL_NAME_STR(IRQ) #nr "_interrupt:\n\t" \
 283         "pushl $-"#nr"-2\n\t" \
 284         SAVE_ALL \
 285         ENTER_KERNEL \
 286         ACK_##chip(mask) \
 287         "incl "SYMBOL_NAME_STR(intr_count)"\n\t"\
 288         "sti\n\t" \
 289         "movl %esp,%ebx\n\t" \
 290         "pushl %ebx\n\t" \
 291         "pushl $" #nr "\n\t" \
 292         "call "SYMBOL_NAME_STR(do_IRQ)"\n\t" \
 293         "addl $8,%esp\n\t" \
 294         "cli\n\t" \
 295         UNBLK_##chip(mask) \
 296         GET_PROCESSOR_ID \
 297         "btrl $" STR(SMP_FROM_INT) ","SYMBOL_NAME_STR(smp_proc_in_lock)"(,%eax,4)\n\t" \
 298         "decl "SYMBOL_NAME_STR(intr_count)"\n\t" \
 299         "incl "SYMBOL_NAME_STR(syscall_count)"\n\t" \
 300         "jmp ret_from_sys_call\n" \
 301 "\n"__ALIGN_STR"\n" \
 302 SYMBOL_NAME_STR(fast_IRQ) #nr "_interrupt:\n\t" \
 303         SAVE_MOST \
 304         ACK_##chip(mask) \
 305         SMP_PROF_IPI_CNT \
 306         "pushl $" #nr "\n\t" \
 307         "call "SYMBOL_NAME_STR(do_fast_IRQ)"\n\t" \
 308         "addl $4,%esp\n\t" \
 309         "cli\n\t" \
 310         UNBLK_##chip(mask) \
 311         RESTORE_MOST \
 312 "\n"__ALIGN_STR"\n" \
 313 SYMBOL_NAME_STR(bad_IRQ) #nr "_interrupt:\n\t" \
 314         SAVE_MOST \
 315         ACK_##chip(mask) \
 316         RESTORE_MOST);
 317 
 318 #define BUILD_RESCHEDIRQ(nr) \
 319 asmlinkage void IRQ_NAME(nr); \
 320 __asm__( \
 321 "\n"__ALIGN_STR"\n" \
 322 SYMBOL_NAME_STR(IRQ) #nr "_interrupt:\n\t" \
 323         "pushl $-"#nr"-2\n\t" \
 324         SAVE_ALL \
 325         ENTER_KERNEL \
 326         "incl "SYMBOL_NAME_STR(intr_count)"\n\t"\
 327         "sti\n\t" \
 328         "movl %esp,%ebx\n\t" \
 329         "pushl %ebx\n\t" \
 330         "pushl $" #nr "\n\t" \
 331         "call "SYMBOL_NAME_STR(smp_reschedule_irq)"\n\t" \
 332         "addl $8,%esp\n\t" \
 333         "cli\n\t" \
 334         "decl "SYMBOL_NAME_STR(intr_count)"\n\t" \
 335         "incl "SYMBOL_NAME_STR(syscall_count)"\n\t" \
 336         "jmp ret_from_sys_call\n");
 337 #else
 338         
 339 #define BUILD_IRQ(chip,nr,mask) \
 340 asmlinkage void IRQ_NAME(nr); \
 341 asmlinkage void FAST_IRQ_NAME(nr); \
 342 asmlinkage void BAD_IRQ_NAME(nr); \
 343 __asm__( \
 344 "\n"__ALIGN_STR"\n" \
 345 SYMBOL_NAME_STR(IRQ) #nr "_interrupt:\n\t" \
 346         "pushl $-"#nr"-2\n\t" \
 347         SAVE_ALL \
 348         ACK_##chip(mask) \
 349         "incl "SYMBOL_NAME_STR(intr_count)"\n\t"\
 350         "sti\n\t" \
 351         "movl %esp,%ebx\n\t" \
 352         "pushl %ebx\n\t" \
 353         "pushl $" #nr "\n\t" \
 354         "call "SYMBOL_NAME_STR(do_IRQ)"\n\t" \
 355         "addl $8,%esp\n\t" \
 356         "cli\n\t" \
 357         UNBLK_##chip(mask) \
 358         "decl "SYMBOL_NAME_STR(intr_count)"\n\t" \
 359         "jmp ret_from_sys_call\n" \
 360 "\n"__ALIGN_STR"\n" \
 361 SYMBOL_NAME_STR(fast_IRQ) #nr "_interrupt:\n\t" \
 362         SAVE_MOST \
 363         ACK_##chip(mask) \
 364         "incl "SYMBOL_NAME_STR(intr_count)"\n\t" \
 365         "pushl $" #nr "\n\t" \
 366         "call "SYMBOL_NAME_STR(do_fast_IRQ)"\n\t" \
 367         "addl $4,%esp\n\t" \
 368         "cli\n\t" \
 369         UNBLK_##chip(mask) \
 370         "decl "SYMBOL_NAME_STR(intr_count)"\n\t" \
 371         RESTORE_MOST \
 372 "\n"__ALIGN_STR"\n" \
 373 SYMBOL_NAME_STR(bad_IRQ) #nr "_interrupt:\n\t" \
 374         SAVE_MOST \
 375         ACK_##chip(mask) \
 376         RESTORE_MOST);
 377         
 378 #define BUILD_TIMER_IRQ(chip,nr,mask) \
 379 asmlinkage void IRQ_NAME(nr); \
 380 asmlinkage void FAST_IRQ_NAME(nr); \
 381 asmlinkage void BAD_IRQ_NAME(nr); \
 382 __asm__( \
 383 "\n"__ALIGN_STR"\n" \
 384 SYMBOL_NAME_STR(fast_IRQ) #nr "_interrupt:\n\t" \
 385 SYMBOL_NAME_STR(bad_IRQ) #nr "_interrupt:\n\t" \
 386 SYMBOL_NAME_STR(IRQ) #nr "_interrupt:\n\t" \
 387         "pushl $-"#nr"-2\n\t" \
 388         SAVE_ALL \
 389         ACK_##chip(mask) \
 390         "incl "SYMBOL_NAME_STR(intr_count)"\n\t"\
 391         "movl %esp,%ebx\n\t" \
 392         "pushl %ebx\n\t" \
 393         "pushl $" #nr "\n\t" \
 394         "call "SYMBOL_NAME_STR(do_IRQ)"\n\t" \
 395         "addl $8,%esp\n\t" \
 396         "cli\n\t" \
 397         UNBLK_##chip(mask) \
 398         "decl "SYMBOL_NAME_STR(intr_count)"\n\t" \
 399         "jmp ret_from_sys_call\n");
 400 
 401 #endif
 402 #endif

/* [previous][next][first][last][top][bottom][index][help] */