root/arch/ppc/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. handle_IRQ
  5. check_irq
  6. request_irq
  7. free_irq
  8. no_action
  9. probe_irq_on
  10. probe_irq_off
  11. init_IRQ
  12. PCI_irq

   1 /*
   2  *      linux/arch/ppc/kernel/irq.c
   3  *
   4  *      Copyright (C) 1992 Linus Torvalds
   5  *      Adapted from arch/i386 by Gary Thomas
   6  *
   7  * This file contains the code used by various IRQ handling routines:
   8  * asking for different IRQ's should be done through these routines
   9  * instead of just grabbing them. Thus setups with different IRQ numbers
  10  * shouldn't result in any weird surprises, and installing new handlers
  11  * should be easier.
  12  */
  13 
  14 /*
  15  * IRQ's are in fact implemented a bit like signal handlers for the kernel.
  16  * Naturally it's not a 1:1 relation, but there are similarities.
  17  */
  18 
  19 #include <linux/ptrace.h>
  20 #include <linux/errno.h>
  21 #include <linux/kernel_stat.h>
  22 #include <linux/signal.h>
  23 #include <linux/sched.h>
  24 #include <linux/ioport.h>
  25 #include <linux/interrupt.h>
  26 #include <linux/timex.h>
  27 
  28 #include <asm/system.h>
  29 #include <asm/io.h>
  30 #include <asm/irq.h>
  31 #include <asm/bitops.h>
  32 
  33 #define CR0_NE 32
  34 
  35 static unsigned char cache_21 = 0xff;
  36 static unsigned char cache_A1 = 0xff;
  37 
  38 void disable_irq(unsigned int irq_nr)
     /* [previous][next][first][last][top][bottom][index][help] */
  39 {
  40         unsigned char mask;
  41         int s = _disable_interrupts();
  42 
  43         mask = 1 << (irq_nr & 7);
  44         if (irq_nr < 8) {
  45                 cache_21 |= mask;
  46                 outb(cache_21,0x21);
  47                 _enable_interrupts(s);
  48                 return;
  49         }
  50         cache_A1 |= mask;
  51         outb(cache_A1,0xA1);
  52         _enable_interrupts(s);
  53 }
  54 
  55 void enable_irq(unsigned int irq_nr)
     /* [previous][next][first][last][top][bottom][index][help] */
  56 {
  57         unsigned char mask;
  58         int s = _disable_interrupts();
  59 
  60         mask = ~(1 << (irq_nr & 7));
  61         if (irq_nr < 8) {
  62                 cache_21 &= mask;
  63                 outb(cache_21,0x21);
  64                 _enable_interrupts(s);
  65                 return;
  66         }
  67         cache_A1 &= mask;
  68         outb(cache_A1,0xA1);
  69         _enable_interrupts(s);
  70 }
  71 
  72 /*
  73  * Irq handlers.
  74  */
  75 struct irqaction {
  76         void (*handler)(int, struct pt_regs *);
  77         unsigned long flags;
  78         unsigned long mask;
  79         const char *name;
  80         int notified;
  81 };
  82 
  83 static struct irqaction irq_action[16] = {
  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         { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
  90         { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
  91         { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL }
  92 };
  93 
  94 int get_irq_list(char *buf)
     /* [previous][next][first][last][top][bottom][index][help] */
  95 {
  96         int i, len = 0;
  97         struct irqaction * action = irq_action;
  98 
  99         for (i = 0 ; i < 16 ; i++, action++) {
 100                 if (!action->handler)
 101                         continue;
 102                 len += sprintf(buf+len, "%2d: %8d %c %s\n",
 103                         i, kstat.interrupts[i],
 104                         (action->flags & SA_INTERRUPT) ? '+' : ' ',
 105                         action->name);
 106         }
 107         return len;
 108 }
 109 
 110 asmlinkage void handle_IRQ(struct pt_regs *regs)
     /* [previous][next][first][last][top][bottom][index][help] */
 111 {
 112         int irq, s;
 113         struct irqaction *action;
 114         intr_count++;
 115         /* Figure out IRQ#, etc. */
 116         outb(0x0C, 0x20);  /* Poll interrupt controller */
 117         irq = inb(0x20);
 118         irq &= 0x07;  /* Caution! */
 119         if (irq == 2)
 120         { /* Cascaded interrupt -> IRQ8..IRQ15 */
 121                 outb(0x0C, 0xA0);
 122                 irq = inb(0xA0) & 0x07;
 123                 irq += 8;
 124         }
 125         /* Mask interrupt & Issue EOI to interrupt controller */
 126         if (irq > 7)
 127         {
 128                 outb(cache_A1 | (1<<(irq-7)), 0xA1);
 129                 outb(0x20, 0xA0);
 130                 /* Need to ack cascade controller as well */
 131                 outb(0x20, 0x20);
 132         } else
 133         {
 134                 outb(cache_21 | (1<<irq), 0x21);
 135                 outb(0x20, 0x20);
 136         }
 137         action = irq + irq_action;
 138         kstat.interrupts[irq]++;
 139         if (action->handler)
 140         {
 141                 action->handler(irq, regs);
 142         } else
 143         {
 144                 _printk("Bogus interrupt #%d\n", irq);
 145         }
 146         if (_disable_interrupts() && !action->notified)
 147         {
 148                 action->notified = 1;
 149                 printk("*** WARNING! %s handler [IRQ %d] turned interrupts on!\n", action->name, irq);
 150         }
 151         /* Re-enable interrupt */
 152         if (irq > 7)
 153         {
 154                 outb(cache_A1, 0xA1);
 155         } else
 156         {
 157                 outb(cache_21, 0x21);
 158         }
 159         intr_count--;
 160 }
 161 
 162 /*
 163  * This routine gets called when the SCSI times out on an operation.
 164  * I don't know why this happens, but every so often it does and it
 165  * seems to be a problem with the interrupt controller [state].  It
 166  * happens a lot when there is also network activity (both devices
 167  * are on the PCI bus with interrupts on the cascaded controller).
 168  * Re-initializing the interrupt controller [which might lose some
 169  * pending edge detected interrupts] seems to fix it.
 170  */
 171 void check_irq(void )
     /* [previous][next][first][last][top][bottom][index][help] */
 172 {
 173         int s = _disable_interrupts();
 174         unsigned char _a0, _a1, _20, _21;
 175         _a1 = inb(0xA1);
 176         _21 = inb(0x21);
 177         outb(0x0C, 0x20);  _20 = inb(0x20);     
 178         outb(0x0C, 0xA0);  _a0 = inb(0xA0);
 179 #if 0   
 180         printk("IRQ 0x20 = %x, 0x21 = %x/%x, 0xA0 = %x, 0xA1 = %x/%x\n",
 181                 _20, _21, cache_21, _a0, _a1, cache_A1);
 182 #endif          
 183         /* Reset interrupt controller - see if this fixes it! */
 184         /* Initialize interrupt controllers */
 185         outb(0x11, 0x20); /* Start init sequence */
 186         outb(0x40, 0x21); /* Vector base */
 187         outb(0x04, 0x21); /* Cascade (slave) on IRQ2 */
 188         outb(0x01, 0x21); /* Select 8086 mode */
 189         outb(0xFF, 0x21); /* Mask all */
 190         outb(0x00, 0x4D0); /* All edge triggered */
 191         outb(0x11, 0xA0); /* Start init sequence */
 192         outb(0x48, 0xA1); /* Vector base */
 193         outb(0x02, 0xA1); /* Cascade (slave) on IRQ2 */
 194         outb(0x01, 0xA1); /* Select 8086 mode */
 195         outb(0xFF, 0xA1); /* Mask all */
 196         outb(0xCF, 0x4D1); /* Trigger mode */
 197         outb(cache_A1, 0xA1);
 198         outb(cache_21, 0x21);
 199         enable_irq(2);  /* Enable cascade interrupt */
 200         _enable_interrupts(s);
 201 }
 202 
 203 #define SA_PROBE SA_ONESHOT
 204 
 205 int request_irq(unsigned int irq, void (*handler)(int, struct pt_regs *),
     /* [previous][next][first][last][top][bottom][index][help] */
 206         unsigned long irqflags, const char * devname)
 207 {
 208         struct irqaction * action;
 209         unsigned long flags;
 210 
 211 #if 0
 212 _printk("Request IRQ #%d, Handler: %x\n", irq, handler);
 213 cnpause();
 214 #endif
 215         if (irq > 15)
 216                 return -EINVAL;
 217         action = irq + irq_action;
 218         if (action->handler)
 219                 return -EBUSY;
 220         if (!handler)
 221                 return -EINVAL;
 222         save_flags(flags);
 223         cli();
 224         action->handler = handler;
 225         action->flags = irqflags;
 226         action->mask = 0;
 227         action->name = devname;
 228 #if 0   
 229         if (!(action->flags & SA_PROBE)) { /* SA_ONESHOT is used by probing */
 230                 if (action->flags & SA_INTERRUPT)
 231                         set_intr_gate(0x20+irq,fast_interrupt[irq]);
 232                 else
 233                         set_intr_gate(0x20+irq,interrupt[irq]);
 234         }
 235 #endif  
 236         if (irq < 8) {
 237                 cache_21 &= ~(1<<irq);
 238                 outb(cache_21,0x21);
 239         } else {
 240                 cache_21 &= ~(1<<2);
 241                 cache_A1 &= ~(1<<(irq-8));
 242                 outb(cache_21,0x21);
 243                 outb(cache_A1,0xA1);
 244         }
 245         restore_flags(flags);
 246         return 0;
 247 }
 248                 
 249 void free_irq(unsigned int irq)
     /* [previous][next][first][last][top][bottom][index][help] */
 250 {
 251         struct irqaction * action = irq + irq_action;
 252         unsigned long flags;
 253 
 254         if (irq > 15) {
 255                 printk("Trying to free IRQ%d\n",irq);
 256                 return;
 257         }
 258         if (!action->handler) {
 259                 printk("Trying to free free IRQ%d\n",irq);
 260                 return;
 261         }
 262         save_flags(flags);
 263         cli();
 264         if (irq < 8) {
 265                 cache_21 |= 1 << irq;
 266                 outb(cache_21,0x21);
 267         } else {
 268                 cache_A1 |= 1 << (irq-8);
 269                 outb(cache_A1,0xA1);
 270         }
 271 #if 0   
 272         set_intr_gate(0x20+irq,bad_interrupt[irq]);
 273 #endif  
 274         action->handler = NULL;
 275         action->flags = 0;
 276         action->mask = 0;
 277         action->name = NULL;
 278         restore_flags(flags);
 279 }
 280 
 281 static void no_action(int cpl, struct pt_regs * regs) { }
     /* [previous][next][first][last][top][bottom][index][help] */
 282 
 283 unsigned /*int*/ long probe_irq_on (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 284 {
 285         unsigned int i, irqs = 0, irqmask;
 286         unsigned long delay;
 287 
 288         /* first, snaffle up any unassigned irqs */
 289         for (i = 15; i > 0; i--) {
 290                 if (!request_irq(i, no_action, SA_PROBE, "probe")) {
 291                         enable_irq(i);
 292                         irqs |= (1 << i);
 293                 }
 294         }
 295 
 296         /* wait for spurious interrupts to mask themselves out again */
 297         for (delay = jiffies + 2; delay > jiffies; );   /* min 10ms delay */
 298 
 299         /* now filter out any obviously spurious interrupts */
 300         irqmask = (((unsigned int)cache_A1)<<8) | (unsigned int)cache_21;
 301         for (i = 15; i > 0; i--) {
 302                 if (irqs & (1 << i) & irqmask) {
 303                         irqs ^= (1 << i);
 304                         free_irq(i);
 305                 }
 306         }
 307 #ifdef DEBUG
 308         printk("probe_irq_on:  irqs=0x%04x irqmask=0x%04x\n", irqs, irqmask);
 309 #endif
 310         return irqs;
 311 }
 312 
 313 int probe_irq_off (unsigned /*int*/ long irqs)
     /* [previous][next][first][last][top][bottom][index][help] */
 314 {
 315         unsigned int i, irqmask;
 316 
 317         irqmask = (((unsigned int)cache_A1)<<8) | (unsigned int)cache_21;
 318         for (i = 15; i > 0; i--) {
 319                 if (irqs & (1 << i)) {
 320                         free_irq(i);
 321                 }
 322         }
 323 #ifdef DEBUG
 324         printk("probe_irq_off: irqs=0x%04x irqmask=0x%04x\n", irqs, irqmask);
 325 #endif
 326         irqs &= irqmask;
 327         if (!irqs)
 328                 return 0;
 329         i = ffz(~irqs);
 330         if (irqs != (irqs & (1 << i)))
 331                 i = -i;
 332         return i;
 333 }
 334 
 335 void init_IRQ(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 336 {
 337         unsigned long *vme2_ie  = (unsigned long *)0xFEFF006C;
 338         unsigned long *vme2_ic  = (unsigned long *)0xFEFF0074;
 339         unsigned long *vme2_il2 = (unsigned long *)0xFEFF007C;
 340         unsigned long *vme2_ioc = (unsigned long *)0xFEFF0088;
 341         unsigned char *vme2pci_ic = (unsigned char *)0x80802050;
 342         unsigned char *ibc_pirq = (unsigned char *)0x80800860;
 343         unsigned char *ibc_pcicon = (unsigned char *)0x80800840;
 344         int i;
 345 
 346         /* set the clock to 100 Hz */
 347         outb_p(0x34,0x43);              /* binary, mode 2, LSB/MSB, ch 0 */
 348         outb_p(LATCH & 0xff , 0x40);    /* LSB */
 349         outb(LATCH >> 8 , 0x40);        /* MSB */
 350         if (request_irq(2, no_action, SA_INTERRUPT, "cascade"))
 351                 printk("Unable to get IRQ2 for cascade\n");
 352         request_region(0x20,0x20,"pic1");
 353         request_region(0xa0,0x20,"pic2");
 354 #if 0   
 355         /* Enable SIG0 */
 356         *vme2_ie = (*vme2_ie & 0xFFFBFFFF) | 0x00040000;
 357         /* Clear any pending interrupts */
 358         *vme2_ic = 0xFFFFFFFF;
 359         /* SIG0 -> Level 5 */
 360         *vme2_il2 = (*vme2_il2 & 0xFFFFF0FF) | 0x00000500;
 361         /* Master interrupt enable */
 362         *vme2_ioc |= 0x00800000;
 363 #endif  
 364         /* Enable interrupts from VMECHIP */
 365         *vme2pci_ic |= 0x08;
 366         /* Route PCI interrupts */
 367         ibc_pirq[0] = 0x0A;  /* PIRQ0 -> ISA10 */
 368         ibc_pirq[1] = 0x0B;  /* PIRQ1 -> ISA11 */
 369         ibc_pirq[2] = 0x0E;  /* PIRQ2 -> ISA14 */
 370         ibc_pirq[3] = 0x0F;  /* PIRQ3 -> ISA15 */
 371         /* Enable PCI interrupts */
 372         *ibc_pcicon |= 0x20;
 373 } 
 374 
 375 PCI_irq(int irq)
     /* [previous][next][first][last][top][bottom][index][help] */
 376 {
 377         static short _irq[] = {10, 11, 14, 15};
 378         int res = _irq[(irq-1)&0x03];
 379 #if 0   
 380         _printk("PCI IRQ #%d = %d\n", irq, res);
 381 #endif  
 382         return (res);
 383 }

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