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

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