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

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