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. device_interrupt
  13. isa_device_interrupt
  14. cabriolet_and_eb66p_device_interrupt
  15. eb66_and_eb64p_device_interrupt
  16. srm_device_interrupt
  17. probe_irq_on
  18. probe_irq_off
  19. machine_check
  20. do_entInt
  21. 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 #if defined(CONFIG_ALPHA_CABRIOLET) || defined(CONFIG_ALPHA_EB66P)
  31   static unsigned char cache_804 = 0xef;
  32   static unsigned char cache_805 = 0xff;
  33   static unsigned char cache_806 = 0xff;
  34 #elif defined(CONFIG_ALPHA_EB66) || defined(CONFIG_ALPHA_EB64P)
  35   static unsigned char cache_26 = 0xdf;
  36   static unsigned char cache_27 = 0xff;
  37 #endif
  38 
  39 void disable_irq(unsigned int irq_nr)
     /* [previous][next][first][last][top][bottom][index][help] */
  40 {
  41         unsigned long flags;
  42         unsigned char mask;
  43 
  44         save_flags(flags);
  45         cli();
  46         mask = 1 << (irq_nr & 7);
  47 
  48         if (irq_nr < 8) {
  49                 cache_21 |= mask;
  50                 outb(cache_21,0x21);
  51         } else if (irq_nr < 16) {
  52                 cache_A1 |= mask;
  53                 outb(cache_A1,0xA1);
  54 #if defined(CONFIG_ALPHA_CABRIOLET) || defined(CONFIG_ALPHA_EB66P)
  55         } else if (irq_nr < 24) {
  56                 cache_804 |= mask;
  57                 outb(cache_804, 0x804);
  58         } else if (irq_nr < 32) {
  59                 cache_805 |= mask;
  60                 outb(cache_805, 0x805);
  61         } else {
  62                 cache_806 |= mask;
  63                 outb(cache_806, 0x806);
  64 #elif defined(CONFIG_ALPHA_EB66) || defined(CONFIG_ALPHA_EB64P) 
  65         } else if (irq_nr < 24) {
  66                 cache_26 |= mask;
  67                 outb(cache_26, 0x26);
  68         } else {
  69                 cache_27 |= mask;
  70                 outb(cache_27, 0x27);
  71 #endif
  72         }
  73         restore_flags(flags);
  74 }
  75 
  76 void enable_irq(unsigned int irq_nr)
     /* [previous][next][first][last][top][bottom][index][help] */
  77 {
  78         unsigned long flags;
  79         unsigned char mask;
  80 
  81         mask = ~(1 << (irq_nr & 7));
  82         save_flags(flags);
  83         cli();
  84 
  85         if (irq_nr < 8) {
  86                 cache_21 &= mask;
  87                 outb(cache_21,0x21);
  88         } else if (irq_nr < 16) {
  89                 cache_A1 &= mask;
  90                 outb(cache_A1,0xA1);
  91 #if defined(CONFIG_ALPHA_CABRIOLET) || defined(CONFIG_ALPHA_EB66P)
  92         } else if (irq_nr < 24) {
  93                 cache_804 &= mask;
  94                 outb(cache_804, 0x804);
  95         } else if (irq_nr < 32) {
  96                 cache_805 &= mask;
  97                 outb(cache_805, 0x805);
  98         } else {
  99                 cache_806 &= mask;
 100                 outb(cache_806, 0x806);
 101 #elif defined(CONFIG_ALPHA_EB66) || defined(CONFIG_ALPHA_EB64P)
 102         } else if (irq_nr < 24) {
 103                 cache_26 &= mask;
 104                 outb(cache_26, 0x26);
 105         } else {
 106                 cache_27 &= mask;
 107                 outb(cache_27, 0x27);
 108 #endif
 109         }
 110         restore_flags(flags);
 111 }
 112 
 113 /*
 114  * Initial irq handlers.
 115  */
 116 struct irqaction {
 117         void (*handler)(int, struct pt_regs *);
 118         unsigned long flags;
 119         unsigned long mask;
 120         const char *name;
 121 };
 122 
 123 static struct irqaction irq_action[NR_IRQS];
 124 
 125 int get_irq_list(char *buf)
     /* [previous][next][first][last][top][bottom][index][help] */
 126 {
 127         int i, len = 0;
 128         struct irqaction * action = irq_action;
 129 
 130         for (i = 0 ; i < NR_IRQS ; i++, action++) {
 131                 if (!action->handler)
 132                         continue;
 133                 len += sprintf(buf+len, "%2d: %8d %c %s\n",
 134                         i, kstat.interrupts[i],
 135                         (action->flags & SA_INTERRUPT) ? '+' : ' ',
 136                         action->name);
 137         }
 138         return len;
 139 }
 140 
 141 static inline void ack_irq(int irq)
     /* [previous][next][first][last][top][bottom][index][help] */
 142 {
 143         if (irq < 16) {
 144                 /* ACK the interrupt making it the lowest priority */
 145                 /*  First the slave .. */
 146                 if (irq > 7) {
 147                         outb(0xE0 | (irq - 8), 0xa0);
 148                         irq = 2;
 149                 }
 150                 /* .. then the master */
 151                 outb(0xE0 | irq, 0x20);
 152         }
 153 }
 154 
 155 static inline void mask_irq(int irq)
     /* [previous][next][first][last][top][bottom][index][help] */
 156 {
 157         unsigned char mask;
 158 
 159         mask = 1 << (irq & 7);
 160         if (irq < 8) {
 161                 cache_21 |= mask;
 162                 outb(cache_21, 0x21);
 163         } else if (irq < 16) {
 164                 cache_A1 |= mask;
 165                 outb(cache_A1, 0xA1);
 166 #if defined(CONFIG_ALPHA_CABRIOLET) || defined(CONFIG_ALPHA_EB66P)
 167         } else if (irq < 24) {
 168                 cache_804 |= mask;
 169                 outb(cache_804, 0x804);
 170         } else if (irq < 32) {
 171                 cache_805 |= mask;
 172                 outb(cache_805, 0x805);
 173         } else {
 174                 cache_806 |= mask;
 175                 outb(cache_806, 0x806);
 176 #elif defined(CONFIG_ALPHA_EB66) || defined(CONFIG_ALPHA_EB66P)
 177         } else if (irq < 24) {
 178                 cache_26 |= mask;
 179                 outb(cache_26, 0x26);
 180         } else {
 181                 cache_27 |= mask;
 182                 outb(cache_27, 0x27);
 183 #endif
 184         }
 185 }
 186 
 187 static inline void unmask_irq(unsigned long irq)
     /* [previous][next][first][last][top][bottom][index][help] */
 188 {
 189         unsigned char mask = ~(1 << (irq & 7));
 190 
 191         if (irq < 8) {
 192                 cache_21 &= mask;
 193                 outb(cache_21, 0x21);
 194         } else if (irq < 16) {
 195                 cache_A1 &= mask;
 196                 outb(cache_A1, 0xA1);
 197 #if defined(CONFIG_ALPHA_CABRIOLET) || defined(CONFIG_ALPHA_EB66P)
 198         } else if (irq < 24) {
 199                 cache_804 &= mask;
 200                 outb(cache_804, 0x804);
 201         } else if (irq < 32) {
 202                 cache_805 &= mask;
 203                 outb(cache_805, 0x805);
 204         } else {
 205                 cache_806 &= mask;
 206                 outb(cache_806, 0x806);
 207 #elif defined(CONFIG_ALPHA_EB66) || defined(CONFIG_ALPHA_EB66P)
 208         } else if (irq < 24) {
 209                 cache_26 &= mask;
 210                 outb(cache_26, 0x26);
 211         } else {
 212                 cache_27 &= mask;
 213                 outb(cache_27, 0x27);
 214 #endif
 215         }
 216 }
 217 
 218 int request_irq(unsigned int irq, void (*handler)(int, struct pt_regs *),
     /* [previous][next][first][last][top][bottom][index][help] */
 219         unsigned long irqflags, const char * devname)
 220 {
 221         struct irqaction * action;
 222         unsigned long flags;
 223 
 224         if (irq >= NR_IRQS)
 225                 return -EINVAL;
 226         action = irq + irq_action;
 227         if (action->handler)
 228                 return -EBUSY;
 229         if (!handler)
 230                 return -EINVAL;
 231         save_flags(flags);
 232         cli();
 233         action->handler = handler;
 234         action->flags = irqflags;
 235         action->mask = 0;
 236         action->name = devname;
 237         enable_irq(irq);
 238         if (irq >= 8 && irq < 16) {
 239                 enable_irq(2);  /* ensure cascade is enabled too */
 240         }
 241         restore_flags(flags);
 242         return 0;
 243 }
 244 
 245 void free_irq(unsigned int irq)
     /* [previous][next][first][last][top][bottom][index][help] */
 246 {
 247         struct irqaction * action = irq + irq_action;
 248         unsigned long flags;
 249 
 250         if (irq >= NR_IRQS) {
 251                 printk("Trying to free IRQ%d\n", irq);
 252                 return;
 253         }
 254         if (!action->handler) {
 255                 printk("Trying to free free IRQ%d\n", irq);
 256                 return;
 257         }
 258         save_flags(flags);
 259         cli();
 260         mask_irq(irq);
 261         action->handler = NULL;
 262         action->flags = 0;
 263         action->mask = 0;
 264         action->name = NULL;
 265         restore_flags(flags);
 266 }
 267 
 268 static inline void handle_nmi(struct pt_regs * regs)
     /* [previous][next][first][last][top][bottom][index][help] */
 269 {
 270         printk("Whee.. NMI received. Probable hardware error\n");
 271         printk("61=%02x, 461=%02x\n", inb(0x61), inb(0x461));
 272 }
 273 
 274 static void unexpected_irq(int irq, struct pt_regs * regs)
     /* [previous][next][first][last][top][bottom][index][help] */
 275 {
 276         int i;
 277 
 278         printk("IO device interrupt, irq = %d\n", irq);
 279         printk("PC = %016lx PS=%04lx\n", regs->pc, regs->ps);
 280         printk("Expecting: ");
 281         for (i = 0; i < 16; i++)
 282                 if (irq_action[i].handler)
 283                         printk("[%s:%d] ", irq_action[i].name, i);
 284         printk("\n");
 285         printk("64=%02x, 60=%02x, 3fa=%02x 2fa=%02x\n",
 286                 inb(0x64), inb(0x60), inb(0x3fa), inb(0x2fa));
 287         outb(0x0c, 0x3fc);
 288         outb(0x0c, 0x2fc);
 289         outb(0,0x61);
 290         outb(0,0x461);
 291 }
 292 
 293 static inline void handle_irq(int irq, struct pt_regs * regs)
     /* [previous][next][first][last][top][bottom][index][help] */
 294 {
 295         struct irqaction * action = irq + irq_action;
 296 
 297         kstat.interrupts[irq]++;
 298         if (!action->handler) {
 299                 unexpected_irq(irq, regs);
 300                 return;
 301         }
 302         action->handler(irq, regs);
 303 }
 304 
 305 static inline void device_interrupt(int irq, int ack, struct pt_regs * regs)
     /* [previous][next][first][last][top][bottom][index][help] */
 306 {
 307         struct irqaction * action;
 308 
 309         if ((unsigned) irq > NR_IRQS) {
 310                 printk("device_interrupt: unexpected interrupt %d\n", irq);
 311                 return;
 312         }
 313 
 314         kstat.interrupts[irq]++;
 315         action = irq_action + irq;
 316         /* quick interrupts get executed with no extra overhead */
 317         if (action->flags & SA_INTERRUPT) {
 318                 action->handler(irq, regs);
 319                 ack_irq(ack);
 320                 return;
 321         }
 322         /*
 323          * For normal interrupts, we mask it out, and then ACK it.
 324          * This way another (more timing-critical) interrupt can
 325          * come through while we're doing this one.
 326          *
 327          * Note! A irq without a handler gets masked and acked, but
 328          * never unmasked. The autoirq stuff depends on this (it looks
 329          * at the masks before and after doing the probing).
 330          */
 331         mask_irq(ack);
 332         ack_irq(ack);
 333         if (!action->handler)
 334                 return;
 335         action->handler(irq, regs);
 336         unmask_irq(ack);
 337 }
 338 
 339 /*
 340  * Handle ISA interrupt via the PICs.
 341  */
 342 static inline void isa_device_interrupt(unsigned long vector,
     /* [previous][next][first][last][top][bottom][index][help] */
 343                                         struct pt_regs * regs)
 344 {
 345         unsigned long pic;
 346         int j;
 347         /* 
 348          *  The first read of gives you *all* interrupting lines.
 349          *  Therefore, read the mask register and and out those lines
 350          *  not enabled.  Note that some documentation has 21 and a1 
 351          *  write only.  This is not true.
 352          */
 353         pic = inb(0x20) | (inb(0xA0) << 8);     /* read isr */
 354         pic &= ~((cache_A1 << 8) | cache_21);   /* apply mask */
 355         pic &= 0xFFFB;                          /* mask out cascade */
 356 
 357         while (pic) {
 358                 j = ffz(~pic);
 359                 pic &= pic - 1;
 360                 device_interrupt(j, j, regs);
 361         }
 362 }
 363 
 364 static inline void cabriolet_and_eb66p_device_interrupt(unsigned long vector,
     /* [previous][next][first][last][top][bottom][index][help] */
 365                                                         struct pt_regs * regs)
 366 {
 367         unsigned long pld;
 368         unsigned int i;
 369         unsigned long flags;
 370 
 371         save_flags(flags);
 372         cli();
 373 
 374         /* read the interrupt summary registers */
 375         pld = inb(0x804) | (inb(0x805) << 8) | (inb(0x806) << 16);
 376 
 377         /*
 378          * Now for every possible bit set, work through them and call
 379          * the appropriate interrupt handler.
 380          */
 381         while (pld) {
 382                 i = ffz(~pld);
 383                 pld &= pld - 1; /* clear least bit set */
 384                 if (i == 4) {
 385                         isa_device_interrupt(vector, regs);
 386                 } else {
 387                         device_interrupt(16 + i, 16 + i, regs);
 388                 }
 389         }
 390         restore_flags(flags);
 391 }
 392 
 393 static inline void eb66_and_eb64p_device_interrupt(unsigned long vector,
     /* [previous][next][first][last][top][bottom][index][help] */
 394                                                    struct pt_regs * regs)
 395 {
 396         unsigned long pld;
 397         unsigned int i;
 398         unsigned long flags;
 399 
 400         save_flags(flags);
 401         cli();
 402 
 403         /* read the interrupt summary registers */
 404         pld = inb(0x26) | (inb(0x27) << 8);
 405         /*
 406          * Now, for every possible bit set, work through
 407          * them and call the appropriate interrupt handler.
 408          */
 409         while (pld) {
 410                 i = ffz(~pld);
 411                 pld &= pld - 1; /* clear least bit set */
 412 
 413                 if (i == 5) {
 414                         isa_device_interrupt(vector, regs);
 415                 } else {
 416                         device_interrupt(16 + i, 16 + i, regs);
 417                 }
 418         }
 419         restore_flags(flags);
 420 }
 421 
 422 /*
 423  * Jensen is special: the vector is 0x8X0 for EISA interrupt X, and
 424  * 0x9X0 for the local motherboard interrupts..
 425  *
 426  *      0x660 - NMI
 427  *
 428  *      0x800 - IRQ0  interval timer (not used, as we use the RTC timer)
 429  *      0x810 - IRQ1  line printer (duh..)
 430  *      0x860 - IRQ6  floppy disk
 431  *      0x8E0 - IRQ14 SCSI controller
 432  *
 433  *      0x900 - COM1
 434  *      0x920 - COM2
 435  *      0x980 - keyboard
 436  *      0x990 - mouse
 437  *
 438  * PCI-based systems are more sane: they don't have the local
 439  * interrupts at all, and have only normal PCI interrupts from
 440  * devices.  Happily it's easy enough to do a sane mapping from the
 441  * Jensen..  Note that this means that we may have to do a hardware
 442  * "ack" to a different interrupt than we report to the rest of the
 443  * world.
 444  */
 445 static inline void srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
     /* [previous][next][first][last][top][bottom][index][help] */
 446 {
 447         int irq, ack;
 448 
 449         ack = irq = (vector - 0x800) >> 4;
 450 
 451 #ifdef CONFIG_ALPHA_JENSEN
 452         switch (vector) {
 453               case 0x660: handle_nmi(regs); return;
 454                 /* local device interrupts: */
 455               case 0x900: handle_irq(4, regs); return;  /* com1 -> irq 4 */
 456               case 0x920: handle_irq(3, regs); return;  /* com2 -> irq 3 */
 457               case 0x980: handle_irq(1, regs); return;  /* kbd -> irq 1 */
 458               case 0x990: handle_irq(9, regs); return;  /* mouse -> irq 9 */
 459               default:
 460                 if (vector > 0x900) {
 461                         printk("Unknown local interrupt %lx\n", vector);
 462                 }
 463         }
 464         /* irq1 is supposed to be the keyboard, silly Jensen (is this really needed??) */
 465         if (irq == 1)
 466                 irq = 7;
 467 #endif /* CONFIG_ALPHA_JENSEN */
 468 
 469         device_interrupt(irq, ack, regs);
 470 }
 471 
 472 #if NR_IRQS > 64
 473 #  error Number of irqs limited to 64 due to interrupt-probing.
 474 #endif
 475 
 476 /*
 477  * Start listening for interrupts..
 478  */
 479 unsigned long probe_irq_on(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 480 {
 481         unsigned long irqs = 0, irqmask;
 482         unsigned long delay;
 483         unsigned int i;
 484 
 485         for (i = NR_IRQS - 1; i > 0; i--) {
 486                 if (!irq_action[i].handler) {
 487                         enable_irq(i);
 488                         irqs |= (1 << i);
 489                 }
 490         }
 491 
 492         /* wait for spurious interrupts to mask themselves out again */
 493         for (delay = jiffies + HZ/10; delay > jiffies; )
 494                 /* about 100 ms delay */;
 495         
 496         /* now filter out any obviously spurious interrupts */
 497         irqmask = (((unsigned long)cache_A1)<<8) | (unsigned long) cache_21;
 498 #if defined(CONFIG_ALPHA_CABRIOLET) || defined(CONFIG_ALPHA_EB66P)
 499         irqmask |= ((((unsigned long)cache_804)<<16) |
 500                     (((unsigned long)cache_805)<<24) |
 501                     (((unsigned long)cache_806)<<24));
 502 #elif defined(CONFIG_ALPHA_EB66) || defined(CONFIG_ALPHA_EB64P)
 503         irqmask |= ((((unsigned long)cache_26)<<16) |
 504                     (((unsigned long)cache_27)<<24));
 505 #endif
 506         irqs &= ~irqmask;
 507         return irqs;
 508 }
 509 
 510 /*
 511  * Get the result of the IRQ probe.. A negative result means that
 512  * we have several candidates (but we return the lowest-numbered
 513  * one).
 514  */
 515 int probe_irq_off(unsigned long irqs)
     /* [previous][next][first][last][top][bottom][index][help] */
 516 {
 517         unsigned long irqmask;
 518         int i;
 519         
 520         irqmask = (((unsigned int)cache_A1)<<8) | (unsigned int)cache_21;
 521 #if defined(CONFIG_ALPHA_CABRIOLET) || defined(CONFIG_ALPHA_EB66P)
 522         irqmask |= ((((unsigned long)cache_804)<<16) |
 523                     (((unsigned long)cache_805)<<24) |
 524                     (((unsigned long)cache_806)<<24));
 525 #elif defined(CONFIG_ALPHA_EB66) || defined(CONFIG_ALPHA_EB64P)
 526         irqmask |= ((((unsigned long)cache_26)<<16) |
 527                     (((unsigned long)cache_27)<<24));
 528 #endif
 529         irqs &= irqmask;
 530         if (!irqs)
 531                 return 0;
 532         i = ffz(~irqs);
 533         if (irqs != (1UL << i))
 534                 i = -i;
 535         return i;
 536 }
 537 
 538 static void machine_check(unsigned long vector, unsigned long la, struct pt_regs * regs)
     /* [previous][next][first][last][top][bottom][index][help] */
 539 {
 540 #if defined(CONFIG_ALPHA_LCA)
 541         extern void lca_machine_check (unsigned long vector, unsigned long la,
 542                                        struct pt_regs *regs);
 543         lca_machine_check(vector, la, regs);
 544 #elif defined(CONFIG_ALPHA_APECS)
 545         extern void apecs_machine_check(unsigned long vector, unsigned long la,
 546                                         struct pt_regs * regs);
 547         apecs_machine_check(vector, la, regs);
 548 #else
 549         printk("Machine check\n");
 550 #endif
 551 }
 552 
 553 asmlinkage void do_entInt(unsigned long type, unsigned long vector, unsigned long la_ptr,
     /* [previous][next][first][last][top][bottom][index][help] */
 554         unsigned long a3, unsigned long a4, unsigned long a5,
 555         struct pt_regs regs)
 556 {
 557         switch (type) {
 558                 case 0:
 559                         printk("Interprocessor interrupt? You must be kidding\n");
 560                         break;
 561                 case 1:
 562                         /* timer interrupt.. */
 563                         handle_irq(0, &regs);
 564                         return;
 565                 case 2:
 566                         machine_check(vector, la_ptr, &regs);
 567                         break;
 568                 case 3:
 569 #if defined(CONFIG_ALPHA_JENSEN) || defined(CONFIG_ALPHA_NONAME)
 570                         srm_device_interrupt(vector, &regs);
 571 #elif defined(CONFIG_ALPHA_CABRIOLET) || defined(CONFIG_ALPHA_EB66P)
 572                         cabriolet_and_eb66p_device_interrupt(vector, &regs);
 573 #elif defined(CONFIG_ALPHA_EB66) || defined(CONFIG_ALPHA_EB64P)
 574                         eb66_and_eb64p_device_interrupt(vector, &regs);
 575 #endif
 576                         return;
 577                 case 4:
 578                         printk("Performance counter interrupt\n");
 579                         break;;
 580                 default:
 581                         printk("Hardware intr %ld %lx? Huh?\n", type, vector);
 582         }
 583         printk("PC = %016lx PS=%04lx\n", regs.pc, regs.ps);
 584 }
 585 
 586 extern asmlinkage void entInt(void);
 587 
 588 void init_IRQ(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 589 {
 590         wrent(entInt, 0);
 591         dma_outb(0, DMA1_RESET_REG);
 592         dma_outb(0, DMA2_RESET_REG);
 593         dma_outb(0, DMA1_CLR_MASK_REG);
 594         dma_outb(0, DMA2_CLR_MASK_REG);
 595 #if defined(CONFIG_ALPHA_CABRIOLET) || defined(CONFIG_ALPHA_EB66P)
 596         outb(cache_804, 0x804);
 597         outb(cache_805, 0x805);
 598         outb(cache_806, 0x806);
 599 #elif defined(CONFIG_ALPHA_EB66) || defined(CONFIG_ALPHA_EB64P)
 600         outb(cache_26, 0x26);
 601         outb(cache_27, 0x27);
 602 #endif
 603 }

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