root/arch/alpha/kernel/irq.c

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

DEFINITIONS

This source file includes following definitions.
  1. disable_irq
  2. enable_irq
  3. get_irq_list
  4. ack_irq
  5. mask_irq
  6. unmask_irq
  7. request_irq
  8. free_irq
  9. handle_nmi
  10. unexpected_irq
  11. handle_irq
  12. local_device_interrupt
  13. device_interrupt
  14. probe_irq_on
  15. probe_irq_off
  16. machine_check
  17. do_entInt
  18. init_IRQ

   1 /*
   2  *      linux/arch/alpha/kernel/irq.c
   3  *
   4  *      Copyright (C) 1995 Linus Torvalds
   5  *
   6  * This file contains the code used by various IRQ handling routines:
   7  * asking for different IRQ's should be done through these routines
   8  * instead of just grabbing them. Thus setups with different IRQ numbers
   9  * shouldn't result in any weird surprises, and installing new handlers
  10  * should be easier.
  11  */
  12 
  13 #include <linux/config.h>
  14 #include <linux/ptrace.h>
  15 #include <linux/errno.h>
  16 #include <linux/kernel_stat.h>
  17 #include <linux/signal.h>
  18 #include <linux/sched.h>
  19 #include <linux/interrupt.h>
  20 
  21 #include <asm/system.h>
  22 #include <asm/io.h>
  23 #include <asm/irq.h>
  24 #include <asm/bitops.h>
  25 
  26 static unsigned char cache_21 = 0xff;
  27 static unsigned char cache_A1 = 0xff;
  28 
  29 void disable_irq(unsigned int irq_nr)
     /* [previous][next][first][last][top][bottom][index][help] */
  30 {
  31         unsigned long flags;
  32         unsigned char mask;
  33 
  34         mask = 1 << (irq_nr & 7);
  35         save_flags(flags);
  36         if (irq_nr < 8) {
  37                 cli();
  38                 cache_21 |= mask;
  39                 outb(cache_21,0x21);
  40                 restore_flags(flags);
  41                 return;
  42         }
  43         cli();
  44         cache_A1 |= mask;
  45         outb(cache_A1,0xA1);
  46         restore_flags(flags);
  47 }
  48 
  49 void enable_irq(unsigned int irq_nr)
     /* [previous][next][first][last][top][bottom][index][help] */
  50 {
  51         unsigned long flags;
  52         unsigned char mask;
  53 
  54         mask = ~(1 << (irq_nr & 7));
  55         save_flags(flags);
  56         if (irq_nr < 8) {
  57                 cli();
  58                 cache_21 &= mask;
  59                 outb(cache_21,0x21);
  60                 restore_flags(flags);
  61                 return;
  62         }
  63         cli();
  64         cache_A1 &= mask;
  65         outb(cache_A1,0xA1);
  66         restore_flags(flags);
  67 }
  68 
  69 /*
  70  * Initial irq handlers.
  71  */
  72 struct irqaction {
  73         void (*handler)(int, struct pt_regs *);
  74         unsigned long flags;
  75         unsigned long mask;
  76         const char *name;
  77 };
  78 
  79 static struct irqaction irq_action[16] = {
  80         { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
  81         { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
  82         { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
  83         { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
  84         { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
  85         { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
  86         { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
  87         { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL }
  88 };
  89 
  90 int get_irq_list(char *buf)
     /* [previous][next][first][last][top][bottom][index][help] */
  91 {
  92         int i, len = 0;
  93         struct irqaction * action = irq_action;
  94 
  95         for (i = 0 ; i < 16 ; i++, action++) {
  96                 if (!action->handler)
  97                         continue;
  98                 len += sprintf(buf+len, "%2d: %8d %c %s\n",
  99                         i, kstat.interrupts[i],
 100                         (action->flags & SA_INTERRUPT) ? '+' : ' ',
 101                         action->name);
 102         }
 103         return len;
 104 }
 105 
 106 static inline void ack_irq(int irq)
     /* [previous][next][first][last][top][bottom][index][help] */
 107 {
 108         /* ACK the interrupt making it the lowest priority */
 109         /*  First the slave .. */
 110         if (irq > 7) {
 111                 outb(0xE0 | (irq - 8), 0xa0);
 112                 irq = 2;
 113         }
 114         /* .. then the master */
 115         outb(0xE0 | irq, 0x20);
 116 }
 117 
 118 static inline void mask_irq(int irq)
     /* [previous][next][first][last][top][bottom][index][help] */
 119 {
 120         if (irq < 8) {
 121                 cache_21 |= 1 << irq;
 122                 outb(cache_21, 0x21);
 123         } else {
 124                 cache_A1 |= 1 << (irq - 8);
 125                 outb(cache_A1, 0xA1);
 126         }
 127 }
 128 
 129 static inline void unmask_irq(unsigned long irq)
     /* [previous][next][first][last][top][bottom][index][help] */
 130 {
 131         if (irq < 8) {
 132                 cache_21 &= ~(1 << irq);
 133                 outb(cache_21, 0x21);
 134         } else {
 135                 cache_A1 &= ~(1 << (irq - 8));
 136                 outb(cache_A1, 0xA1);
 137         }
 138 }
 139 
 140 int request_irq(unsigned int irq, void (*handler)(int, struct pt_regs *),
     /* [previous][next][first][last][top][bottom][index][help] */
 141         unsigned long irqflags, const char * devname)
 142 {
 143         struct irqaction * action;
 144         unsigned long flags;
 145 
 146         if (irq > 15)
 147                 return -EINVAL;
 148         action = irq + irq_action;
 149         if (action->handler)
 150                 return -EBUSY;
 151         if (!handler)
 152                 return -EINVAL;
 153         save_flags(flags);
 154         cli();
 155         action->handler = handler;
 156         action->flags = irqflags;
 157         action->mask = 0;
 158         action->name = devname;
 159         if (irq < 8 && irq) {
 160                 cache_21 &= ~(1<<irq);
 161                 outb(cache_21,0x21);
 162         } else {
 163                 cache_21 &= ~(1<<2);
 164                 cache_A1 &= ~(1<<(irq-8));
 165                 outb(cache_21,0x21);
 166                 outb(cache_A1,0xA1);
 167         }
 168         restore_flags(flags);
 169         return 0;
 170 }
 171 
 172 void free_irq(unsigned int irq)
     /* [previous][next][first][last][top][bottom][index][help] */
 173 {
 174         struct irqaction * action = irq + irq_action;
 175         unsigned long flags;
 176 
 177         if (irq > 15) {
 178                 printk("Trying to free IRQ%d\n", irq);
 179                 return;
 180         }
 181         if (!action->handler) {
 182                 printk("Trying to free free IRQ%d\n", irq);
 183                 return;
 184         }
 185         save_flags(flags);
 186         cli();
 187         mask_irq(irq);
 188         action->handler = NULL;
 189         action->flags = 0;
 190         action->mask = 0;
 191         action->name = NULL;
 192         restore_flags(flags);
 193 }
 194 
 195 static void handle_nmi(struct pt_regs * regs)
     /* [previous][next][first][last][top][bottom][index][help] */
 196 {
 197         printk("Whee.. NMI received. Probable hardware error\n");
 198         printk("61=%02x, 461=%02x\n", inb(0x61), inb(0x461));
 199 }
 200 
 201 static void unexpected_irq(int irq, struct pt_regs * regs)
     /* [previous][next][first][last][top][bottom][index][help] */
 202 {
 203         int i;
 204 
 205         printk("IO device interrupt, irq = %d\n", irq);
 206         printk("PC = %016lx PS=%04lx\n", regs->pc, regs->ps);
 207         printk("Expecting: ");
 208         for (i = 0; i < 16; i++)
 209                 if (irq_action[i].handler)
 210                         printk("[%s:%d] ", irq_action[i].name, i);
 211         printk("\n");
 212         printk("64=%02x, 60=%02x, 3fa=%02x 2fa=%02x\n",
 213                 inb(0x64), inb(0x60), inb(0x3fa), inb(0x2fa));
 214         outb(0x0c, 0x3fc);
 215         outb(0x0c, 0x2fc);
 216         outb(0,0x61);
 217         outb(0,0x461);
 218 }
 219 
 220 static inline void handle_irq(int irq, struct pt_regs * regs)
     /* [previous][next][first][last][top][bottom][index][help] */
 221 {
 222         struct irqaction * action = irq + irq_action;
 223 
 224         kstat.interrupts[irq]++;
 225         if (!action->handler) {
 226                 unexpected_irq(irq, regs);
 227                 return;
 228         }
 229         action->handler(irq, regs);
 230 }
 231 
 232 static void local_device_interrupt(unsigned long vector, struct pt_regs * regs)
     /* [previous][next][first][last][top][bottom][index][help] */
 233 {
 234         switch (vector) {
 235                 /* com1: map to irq 4 */
 236                 case 0x900:
 237                         handle_irq(4, regs);
 238                         return;
 239 
 240                 /* com2: map to irq 3 */
 241                 case 0x920:
 242                         handle_irq(3, regs);
 243                         return;
 244 
 245                 /* keyboard: map to irq 1 */
 246                 case 0x980:
 247                         handle_irq(1, regs);
 248                         return;
 249 
 250                 /* mouse: map to irq 12 */
 251                 case 0x990:
 252                         handle_irq(12, regs);
 253                         return;
 254                 default:
 255                         printk("Unknown local interrupt %lx\n", vector);
 256         }
 257 }
 258 
 259 /*
 260  * The vector is 0x8X0 for EISA interrupt X, and 0x9X0 for the local
 261  * motherboard interrupts.. This is for the Jensen.
 262  *
 263  *      0x660 - NMI
 264  *
 265  *      0x800 - IRQ0  interval timer (not used, as we use the RTC timer)
 266  *      0x810 - IRQ1  line printer (duh..)
 267  *      0x860 - IRQ6  floppy disk
 268  *      0x8E0 - IRQ14 SCSI controller
 269  *
 270  *      0x900 - COM1
 271  *      0x920 - COM2
 272  *      0x980 - keyboard
 273  *      0x990 - mouse
 274  *
 275  * The PCI version is more sane: it doesn't have the local interrupts at
 276  * all, and has only normal PCI interrupts from devices. Happily it's easy
 277  * enough to do a sane mapping from the Jensen.. Note that this means
 278  * that we may have to do a hardware "ack" to a different interrupt than
 279  * we report to the rest of the world..
 280  */
 281 static void device_interrupt(unsigned long vector, struct pt_regs * regs)
     /* [previous][next][first][last][top][bottom][index][help] */
 282 {
 283         int irq, ack;
 284         struct irqaction * action;
 285 
 286         if (vector == 0x660) {
 287                 handle_nmi(regs);
 288                 return;
 289         }
 290 
 291         ack = irq = (vector - 0x800) >> 4;
 292 #ifndef CONFIG_PCI
 293         if (vector >= 0x900) {
 294                 local_device_interrupt(vector, regs);
 295                 return;
 296         }
 297         /* irq1 is supposed to be the keyboard, silly Jensen */
 298         if (irq == 1)
 299                 irq = 7;
 300 #endif
 301         printk("%d%d", irq, ack);
 302         kstat.interrupts[irq]++;
 303         action = irq_action + irq;
 304         /* quick interrupts get executed with no extra overhead */
 305         if (action->flags & SA_INTERRUPT) {
 306                 action->handler(irq, regs);
 307                 ack_irq(ack);
 308                 return;
 309         }
 310         /*
 311          * For normal interrupts, we mask it out, and then ACK it.
 312          * This way another (more timing-critical) interrupt can
 313          * come through while we're doing this one.
 314          *
 315          * Note! A irq without a handler gets masked and acked, but
 316          * never unmasked. The autoirq stuff depends on this (it looks
 317          * at the masks before and after doing the probing).
 318          */
 319         mask_irq(ack);
 320         ack_irq(ack);
 321         if (!action->handler)
 322                 return;
 323         action->handler(irq, regs);
 324         unmask_irq(ack);
 325 }
 326 
 327 /*
 328  * Start listening for interrupts..
 329  */
 330 unsigned int probe_irq_on(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 331 {
 332         unsigned int i, irqs = 0, irqmask;
 333         unsigned long delay;
 334 
 335         for (i = 15; i > 0; i--) {
 336                 if (!irq_action[i].handler) {
 337                         enable_irq(i);
 338                         irqs |= (1 << i);
 339                 }
 340         }
 341 
 342         /* wait for spurious interrupts to mask themselves out again */
 343         for (delay = jiffies + HZ/10; delay > jiffies; )
 344                 /* about 100 ms delay */;
 345         
 346         /* now filter out any obviously spurious interrupts */
 347         irqmask = (((unsigned int)cache_A1)<<8) | (unsigned int) cache_21;
 348         irqs &= ~irqmask;
 349         return irqs;
 350 }
 351 
 352 /*
 353  * Get the result of the IRQ probe.. A negative result means that
 354  * we have several candidates (but we return the lowest-numbered
 355  * one).
 356  */
 357 int probe_irq_off(unsigned int irqs)
     /* [previous][next][first][last][top][bottom][index][help] */
 358 {
 359         unsigned int i, irqmask;
 360         
 361         irqmask = (((unsigned int)cache_A1)<<8) | (unsigned int)cache_21;
 362         irqs &= irqmask;
 363         if (!irqs)
 364                 return 0;
 365         i = ffz(~irqs);
 366         if (irqs != (1 << i))
 367                 i = -i;
 368         return i;
 369 }
 370 
 371 static void machine_check(unsigned long vector, unsigned long la_ptr, struct pt_regs * regs)
     /* [previous][next][first][last][top][bottom][index][help] */
 372 {
 373         printk("Machine check\n");
 374 }
 375 
 376 asmlinkage void do_entInt(unsigned long type, unsigned long vector,
     /* [previous][next][first][last][top][bottom][index][help] */
 377         unsigned long la_ptr, struct pt_regs *regs)
 378 {
 379         switch (type) {
 380                 case 0:
 381                         printk("Interprocessor interrupt? You must be kidding\n");
 382                         break;
 383                 case 1:
 384                         /* timer interrupt.. */
 385                         handle_irq(0, regs);
 386                         return;
 387                 case 2:
 388                         machine_check(vector, la_ptr, regs);
 389                         break;
 390                 case 3:
 391                         device_interrupt(vector, regs);
 392                         return;
 393                 case 4:
 394                         printk("Performance counter interrupt\n");
 395                         break;;
 396                 default:
 397                         printk("Hardware intr %ld %lx? Huh?\n", type, vector);
 398         }
 399         printk("PC = %016lx PS=%04lx\n", regs->pc, regs->ps);
 400 }
 401 
 402 extern asmlinkage void entInt(void);
 403 
 404 void init_IRQ(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 405 {
 406         wrent(entInt, 0);
 407 }

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