root/arch/mips/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. do_IRQ
  5. do_fast_IRQ
  6. request_irq
  7. free_irq
  8. no_action
  9. probe_irq_on
  10. probe_irq_off
  11. init_IRQ

   1 /*
   2  *      linux/arch/mips/kernel/irq.c
   3  *
   4  *      Copyright (C) 1992 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 /*
  14  * IRQ's are in fact implemented a bit like signal handlers for the kernel.
  15  * Naturally it's not a 1:1 relation, but there are similarities.
  16  */
  17 
  18 /*
  19  * Mips support by Ralf Baechle and Andreas Busse
  20  *
  21  * The Deskstation Tyne is almost completely like an IBM compatible PC with
  22  * another type of microprocessor. Therefore this code is almost completely
  23  * the same. More work needs to be done to support Acer PICA and other
  24  * machines.
  25  */
  26 
  27 #include <linux/ptrace.h>
  28 #include <linux/errno.h>
  29 #include <linux/kernel_stat.h>
  30 #include <linux/signal.h>
  31 #include <linux/sched.h>
  32 #include <linux/types.h>
  33 #include <linux/interrupt.h>
  34 #include <linux/timex.h>
  35 #include <linux/malloc.h>
  36 #include <linux/random.h>
  37 
  38 #include <asm/bitops.h>
  39 #include <asm/bootinfo.h>
  40 #include <asm/io.h>
  41 #include <asm/irq.h>
  42 #include <asm/jazz.h>
  43 #include <asm/mipsregs.h>
  44 #include <asm/system.h>
  45 
  46 #define TIMER_IRQ 0                     /* Keep this in sync with time.c */
  47 
  48 unsigned char cache_21 = 0xff;
  49 unsigned char cache_A1 = 0xff;
  50 
  51 unsigned long spurious_count = 0;
  52 
  53 void disable_irq(unsigned int irq_nr)
     /* [previous][next][first][last][top][bottom][index][help] */
  54 {
  55         unsigned long flags;
  56         unsigned char mask;
  57 
  58         mask = 1 << (irq_nr & 7);
  59         save_flags(flags);
  60         if (irq_nr < 8) {
  61                 cli();
  62                 cache_21 |= mask;
  63                 outb(cache_21,0x21);
  64                 restore_flags(flags);
  65                 return;
  66         }
  67         cli();
  68         cache_A1 |= mask;
  69         outb(cache_A1,0xA1);
  70         restore_flags(flags);
  71 }
  72 
  73 void enable_irq(unsigned int irq_nr)
     /* [previous][next][first][last][top][bottom][index][help] */
  74 {
  75         unsigned long flags;
  76         unsigned char mask;
  77 
  78         mask = ~(1 << (irq_nr & 7));
  79         save_flags(flags);
  80         if (irq_nr < 8) {
  81                 cli();
  82                 cache_21 &= mask;
  83                 outb(cache_21,0x21);
  84                 restore_flags(flags);
  85                 return;
  86         }
  87         cli();
  88         cache_A1 &= mask;
  89         outb(cache_A1,0xA1);
  90         restore_flags(flags);
  91 }
  92 
  93 /*
  94  * Pointers to the low-level handlers: first the general ones, then the
  95  * fast ones, then the bad ones.
  96  */
  97 extern void interrupt(void);
  98 extern void fast_interrupt(void);
  99 extern void bad_interrupt(void);
 100 
 101 /*
 102  * Initial irq handlers.
 103  */
 104 static struct irqaction timer_irq = { NULL, 0, 0, NULL, NULL, NULL};
 105 static struct irqaction cascade_irq = { NULL, 0, 0, NULL, NULL, NULL};
 106 static struct irqaction math_irq = { NULL, 0, 0, NULL, NULL, NULL};
 107 
 108 static struct irqaction *irq_action[16] = {
 109           NULL, NULL, NULL, NULL, NULL, NULL , NULL, NULL,
 110           NULL, NULL, NULL, NULL, NULL, NULL , NULL, NULL
 111 };
 112 
 113 int get_irq_list(char *buf)
     /* [previous][next][first][last][top][bottom][index][help] */
 114 {
 115         int i, len = 0;
 116         struct irqaction * action;
 117 
 118         for (i = 0 ; i < 16 ; i++) {
 119                 action = *(i + irq_action);
 120                 if (!action) 
 121                         continue;
 122                 len += sprintf(buf+len, "%2d: %8d %c %s",
 123                         i, kstat.interrupts[i],
 124                         (action->flags & SA_INTERRUPT) ? '+' : ' ',
 125                         action->name);
 126                 for (action=action->next; action; action = action->next) {
 127                         len += sprintf(buf+len, ",%s %s",
 128                                 (action->flags & SA_INTERRUPT) ? " +" : "",
 129                                 action->name);
 130                 }
 131                 len += sprintf(buf+len, "\n");
 132         }
 133         return len;
 134 }
 135 
 136 /*
 137  * do_IRQ handles IRQ's that have been installed without the
 138  * SA_INTERRUPT flag: it uses the full signal-handling return
 139  * and runs with other interrupts enabled. All relatively slow
 140  * IRQ's should use this format: notably the keyboard/timer
 141  * routines.
 142  */
 143 asmlinkage void do_IRQ(int irq, struct pt_regs * regs)
     /* [previous][next][first][last][top][bottom][index][help] */
 144 {
 145         struct irqaction * action = *(irq + irq_action);
 146 
 147         kstat.interrupts[irq]++;
 148         if (action->flags & SA_SAMPLE_RANDOM)
 149                 add_interrupt_randomness(irq);
 150         while (action) {
 151             action->handler(irq, action->dev_id, regs);
 152             action = action->next;
 153         }
 154 }
 155 
 156 /*
 157  * do_fast_IRQ handles IRQ's that don't need the fancy interrupt return
 158  * stuff - the handler is also running with interrupts disabled unless
 159  * it explicitly enables them later.
 160  */
 161 asmlinkage void do_fast_IRQ(int irq)
     /* [previous][next][first][last][top][bottom][index][help] */
 162 {
 163         struct irqaction * action = *(irq + irq_action);
 164 
 165         kstat.interrupts[irq]++;
 166         if (action->flags & SA_SAMPLE_RANDOM)
 167                 add_interrupt_randomness(irq);
 168         while (action) {
 169             action->handler(irq, action->dev_id, NULL);
 170             action = action->next;
 171         }
 172 }
 173 
 174 #define SA_PROBE SA_ONESHOT
 175 
 176 int request_irq(unsigned int irq, 
     /* [previous][next][first][last][top][bottom][index][help] */
 177                 void (*handler)(int, void *, struct pt_regs *),
 178                 unsigned long irqflags, 
 179                 const char * devname,
 180                 void *dev_id)
 181 {
 182         struct irqaction * action, *tmp = NULL;
 183         unsigned long flags;
 184 
 185         if (irq > 15)
 186                 return -EINVAL;
 187         if (!handler)
 188             return -EINVAL;
 189         action = *(irq + irq_action);
 190         if (action) {
 191             if ((action->flags & SA_SHIRQ) && (irqflags & SA_SHIRQ)) {
 192                 for (tmp = action; tmp->next; tmp = tmp->next);
 193             } else {
 194                 return -EBUSY;
 195             }
 196             if ((action->flags & SA_INTERRUPT) ^ (irqflags & SA_INTERRUPT)) {
 197               printk("Attempt to mix fast and slow interrupts on IRQ%d denied\n", irq);
 198               return -EBUSY;
 199             }   
 200         }
 201         if (irqflags & SA_SAMPLE_RANDOM)
 202                 rand_initialize_irq(irq);
 203         save_flags(flags);
 204         cli();
 205         if (irq == 2)
 206             action = &cascade_irq;
 207         else if (irq == 13)
 208           action = &math_irq;
 209         else if (irq == TIMER_IRQ)
 210           action = &timer_irq;
 211         else
 212           action = (struct irqaction *)kmalloc(sizeof(struct irqaction), GFP_KERNEL);
 213 
 214         if (!action) { 
 215             restore_flags(flags);
 216             return -ENOMEM;
 217         }
 218 
 219         action->handler = handler;
 220         action->flags = irqflags;
 221         action->mask = 0;
 222         action->name = devname;
 223         action->next = NULL;
 224         action->dev_id = dev_id;
 225 
 226         if (tmp) {
 227             tmp->next = action;
 228         } else {
 229             *(irq + irq_action) = action;
 230             if (!(action->flags & SA_PROBE)) {/* SA_ONESHOT used by probing */
 231                 /*
 232                  * FIXME: Does the SA_INTERRUPT flag make any sense on MIPS???
 233                  */
 234                 if (action->flags & SA_INTERRUPT)
 235                         set_int_vector(irq,fast_interrupt);
 236                 else
 237                         set_int_vector(irq,interrupt);
 238             }
 239             if (irq < 8) {
 240                 cache_21 &= ~(1<<irq);
 241                 outb(cache_21,0x21);
 242             } else {
 243                 cache_21 &= ~(1<<2);
 244                 cache_A1 &= ~(1<<(irq-8));
 245                 outb(cache_21,0x21);
 246                 outb(cache_A1,0xA1);
 247             }
 248         }
 249         restore_flags(flags);
 250         return 0;
 251 }
 252 
 253 void free_irq(unsigned int irq, void *dev_id)
     /* [previous][next][first][last][top][bottom][index][help] */
 254 {
 255         struct irqaction * action = *(irq + irq_action);
 256         struct irqaction * tmp = NULL;
 257         unsigned long flags;
 258 
 259         if (irq > 15) {
 260                 printk("Trying to free IRQ%d\n",irq);
 261                 return;
 262         }
 263         if (!action->handler) {
 264                 printk("Trying to free free IRQ%d\n",irq);
 265                 return;
 266         }
 267         if (dev_id) {
 268             for (; action; action = action->next) {
 269                 if (action->dev_id == dev_id) break;
 270                 tmp = action;
 271             }
 272             if (!action) {
 273                 printk("Trying to free free shared IRQ%d\n",irq);
 274                 return;
 275             }
 276         } else if (action->flags & SA_SHIRQ) {
 277             printk("Trying to free shared IRQ%d with NULL device ID\n", irq);
 278             return;
 279         }
 280         save_flags(flags);
 281         cli();
 282         if (action && tmp) {
 283             tmp->next = action->next;
 284         } else {
 285             *(irq + irq_action) = action->next;
 286         }
 287 
 288         if ((irq == 2) || (irq == 13) | (irq == TIMER_IRQ))
 289           memset(action, 0, sizeof(struct irqaction));
 290         else 
 291           kfree_s(action, sizeof(struct irqaction));
 292         
 293         if (!(*(irq + irq_action))) {
 294             if (irq < 8) {
 295                 cache_21 |= 1 << irq;
 296                 outb(cache_21,0x21);
 297             } else {
 298                 cache_A1 |= 1 << (irq-8);
 299                 outb(cache_A1,0xA1);
 300             }
 301             set_int_vector(irq,bad_interrupt);
 302         }
 303         restore_flags(flags);
 304 }
 305 
 306 static void no_action(int cpl, void *dev_id, struct pt_regs * regs) { }
     /* [previous][next][first][last][top][bottom][index][help] */
 307 
 308 unsigned long probe_irq_on (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 309 {
 310         unsigned int i, irqs = 0, irqmask;
 311         unsigned long delay;
 312 
 313         /* first, snaffle up any unassigned irqs */
 314         for (i = 15; i > 0; i--) {
 315                 if (!request_irq(i, no_action, SA_PROBE, "probe", NULL)) {
 316                         enable_irq(i);
 317                         irqs |= (1 << i);
 318                 }
 319         }
 320 
 321         /* wait for spurious interrupts to mask themselves out again */
 322         for (delay = jiffies + 2; delay > jiffies; );   /* min 10ms delay */
 323 
 324         /* now filter out any obviously spurious interrupts */
 325         irqmask = (((unsigned int)cache_A1)<<8) | (unsigned int)cache_21;
 326         for (i = 15; i > 0; i--) {
 327                 if (irqs & (1 << i) & irqmask) {
 328                         irqs ^= (1 << i);
 329                         free_irq(i, NULL);
 330                 }
 331         }
 332 #ifdef DEBUG
 333         printk("probe_irq_on:  irqs=0x%04x irqmask=0x%04x\n", irqs, irqmask);
 334 #endif
 335         return irqs;
 336 }
 337 
 338 int probe_irq_off (unsigned long irqs)
     /* [previous][next][first][last][top][bottom][index][help] */
 339 {
 340         unsigned int i, irqmask;
 341 
 342         irqmask = (((unsigned int)cache_A1)<<8) | (unsigned int)cache_21;
 343         for (i = 15; i > 0; i--) {
 344                 if (irqs & (1 << i)) {
 345                         free_irq(i, NULL);
 346                 }
 347         }
 348 #ifdef DEBUG
 349         printk("probe_irq_off: irqs=0x%04x irqmask=0x%04x\n", irqs, irqmask);
 350 #endif
 351         irqs &= irqmask;
 352         if (!irqs)
 353                 return 0;
 354         i = ffz(~irqs);
 355         if (irqs != (irqs & (1 << i)))
 356                 i = -i;
 357         return i;
 358 }
 359 
 360 void init_IRQ(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 361 {
 362         int i;
 363 
 364         switch (boot_info.machtype) {
 365                 case MACH_MIPS_MAGNUM_4000:
 366                 case MACH_ACER_PICA_61:
 367                         r4030_write_reg16(JAZZ_IO_IRQ_ENABLE,
 368                                           JAZZ_IE_ETHERNET |
 369                                           JAZZ_IE_SERIAL1  |
 370                                           JAZZ_IE_SERIAL2  |
 371                                           JAZZ_IE_PARALLEL |
 372                                           JAZZ_IE_FLOPPY);
 373                         r4030_read_reg16(JAZZ_IO_IRQ_SOURCE); /* clear pending IRQs */
 374                         set_cp0_status(ST0_IM, IE_IRQ4 | IE_IRQ1);
 375                         /* set the clock to 100 Hz */
 376                         r4030_write_reg32(JAZZ_TIMER_INTERVAL, 9);
 377                         break;
 378                 case MACH_DESKSTATION_TYNE:
 379                         /* set the clock to 100 Hz */
 380                         outb_p(0x34,0x43);              /* binary, mode 2, LSB/MSB, ch 0 */
 381                         outb_p(LATCH & 0xff , 0x40);    /* LSB */
 382                         outb(LATCH >> 8 , 0x40);        /* MSB */
 383 
 384                         if (request_irq(2, no_action, SA_INTERRUPT, "cascade", NULL))
 385                                 printk("Unable to get IRQ2 for cascade\n");
 386                         break;
 387                 default:
 388                         panic("Unknown machtype in init_IRQ");
 389         }
 390 
 391         for (i = 0; i < 16 ; i++)
 392                 set_int_vector(i, bad_interrupt);
 393 
 394         /* initialize the bottom half routines. */
 395         for (i = 0; i < 32; i++) {
 396                 bh_base[i].routine = NULL;
 397                 bh_base[i].data = NULL;
 398         }
 399         bh_active = 0;
 400         intr_count = 0;
 401 }

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