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/random.h>
  36 
  37 #include <asm/bitops.h>
  38 #include <asm/bootinfo.h>
  39 #include <asm/io.h>
  40 #include <asm/irq.h>
  41 #include <asm/jazz.h>
  42 #include <asm/mipsregs.h>
  43 #include <asm/system.h>
  44 
  45 unsigned char cache_21 = 0xff;
  46 unsigned char cache_A1 = 0xff;
  47 
  48 unsigned long spurious_count = 0;
  49 
  50 void disable_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 void enable_irq(unsigned int irq_nr)
     /* [previous][next][first][last][top][bottom][index][help] */
  71 {
  72         unsigned long flags;
  73         unsigned char mask;
  74 
  75         mask = ~(1 << (irq_nr & 7));
  76         save_flags(flags);
  77         if (irq_nr < 8) {
  78                 cli();
  79                 cache_21 &= mask;
  80                 outb(cache_21,0x21);
  81                 restore_flags(flags);
  82                 return;
  83         }
  84         cli();
  85         cache_A1 &= mask;
  86         outb(cache_A1,0xA1);
  87         restore_flags(flags);
  88 }
  89 
  90 /*
  91  * Pointers to the low-level handlers: first the general ones, then the
  92  * fast ones, then the bad ones.
  93  */
  94 extern void interrupt(void);
  95 extern void fast_interrupt(void);
  96 extern void bad_interrupt(void);
  97 
  98 /*
  99  * Initial irq handlers.
 100  */
 101 struct irqaction {
 102         void (*handler)(int, struct pt_regs *);
 103         unsigned long flags;
 104         unsigned long mask;
 105         const char *name;
 106 };
 107 
 108 static struct irqaction irq_action[16] = {
 109         { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
 110         { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
 111         { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
 112         { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
 113         { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
 114         { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
 115         { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
 116         { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL }
 117 };
 118 
 119 int get_irq_list(char *buf)
     /* [previous][next][first][last][top][bottom][index][help] */
 120 {
 121         int i, len = 0;
 122         struct irqaction * action = irq_action;
 123 
 124         for (i = 0 ; i < 16 ; i++, action++) {
 125                 if (!action->handler)
 126                         continue;
 127                 len += sprintf(buf+len, "%3d: %8d %c %s\n",
 128                         i, kstat.interrupts[i],
 129                         (action->flags & SA_INTERRUPT) ? '+' : ' ',
 130                         action->name);
 131         }
 132         return len;
 133 }
 134 
 135 /*
 136  * do_IRQ handles IRQ's that have been installed without the
 137  * SA_INTERRUPT flag: it uses the full signal-handling return
 138  * and runs with other interrupts enabled. All relatively slow
 139  * IRQ's should use this format: notably the keyboard/timer
 140  * routines.
 141  */
 142 asmlinkage void do_IRQ(int irq, struct pt_regs * regs)
     /* [previous][next][first][last][top][bottom][index][help] */
 143 {
 144         struct irqaction * action = irq + irq_action;
 145 
 146         kstat.interrupts[irq]++;
 147         if (action->flags & SA_SAMPLE_RANDOM)
 148                 add_interrupt_randomness(irq);
 149         action->handler(irq, regs);
 150 }
 151 
 152 /*
 153  * do_fast_IRQ handles IRQ's that don't need the fancy interrupt return
 154  * stuff - the handler is also running with interrupts disabled unless
 155  * it explicitly enables them later.
 156  */
 157 asmlinkage void do_fast_IRQ(int irq)
     /* [previous][next][first][last][top][bottom][index][help] */
 158 {
 159         struct irqaction * action = irq + irq_action;
 160 
 161         kstat.interrupts[irq]++;
 162         if (action->flags & SA_SAMPLE_RANDOM)
 163                 add_interrupt_randomness(irq);
 164         action->handler(irq, NULL);
 165 }
 166 
 167 #define SA_PROBE SA_ONESHOT
 168 
 169 int request_irq(unsigned int irq, void (*handler)(int, struct pt_regs *),
     /* [previous][next][first][last][top][bottom][index][help] */
 170         unsigned long irqflags, const char * devname)
 171 {
 172         struct irqaction * action;
 173         unsigned long flags;
 174 
 175         if (irq > 15)
 176                 return -EINVAL;
 177         action = irq + irq_action;
 178         if (action->handler)
 179                 return -EBUSY;
 180         if (!handler)
 181                 return -EINVAL;
 182         if (irqflags & SA_SAMPLE_RANDOM)
 183                 rand_initialize_irq(irq);
 184         save_flags(flags);
 185         cli();
 186         action->handler = handler;
 187         action->flags = irqflags;
 188         action->mask = 0;
 189         action->name = devname;
 190         if (!(action->flags & SA_PROBE)) { /* SA_ONESHOT is used by probing */
 191                 /*
 192                  * FIXME: Does the SA_INTERRUPT flag make any sense on MIPS???
 193                  */
 194                 if (action->flags & SA_INTERRUPT)
 195                         set_int_vector(irq,fast_interrupt);
 196                 else
 197                         set_int_vector(irq,interrupt);
 198         }
 199         if (irq < 8) {
 200                 cache_21 &= ~(1<<irq);
 201                 outb(cache_21,0x21);
 202         } else {
 203                 cache_21 &= ~(1<<2);
 204                 cache_A1 &= ~(1<<(irq-8));
 205                 outb(cache_21,0x21);
 206                 outb(cache_A1,0xA1);
 207         }
 208         restore_flags(flags);
 209         return 0;
 210 }
 211 
 212 void free_irq(unsigned int irq)
     /* [previous][next][first][last][top][bottom][index][help] */
 213 {
 214         struct irqaction * action = irq + irq_action;
 215         unsigned long flags;
 216 
 217         if (irq > 15) {
 218                 printk("Trying to free IRQ%d\n",irq);
 219                 return;
 220         }
 221         if (!action->handler) {
 222                 printk("Trying to free free IRQ%d\n",irq);
 223                 return;
 224         }
 225         save_flags(flags);
 226         cli();
 227         if (irq < 8) {
 228                 cache_21 |= 1 << irq;
 229                 outb(cache_21,0x21);
 230         } else {
 231                 cache_A1 |= 1 << (irq-8);
 232                 outb(cache_A1,0xA1);
 233         }
 234         set_int_vector(irq,bad_interrupt);
 235         action->handler = NULL;
 236         action->flags = 0;
 237         action->mask = 0;
 238         action->name = NULL;
 239         restore_flags(flags);
 240 }
 241 
 242 static void no_action(int cpl, struct pt_regs * regs) { }
     /* [previous][next][first][last][top][bottom][index][help] */
 243 
 244 unsigned long probe_irq_on (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 245 {
 246         unsigned int i, irqs = 0, irqmask;
 247         unsigned long delay;
 248 
 249         /* first, snaffle up any unassigned irqs */
 250         for (i = 15; i > 0; i--) {
 251                 if (!request_irq(i, no_action, SA_PROBE, "probe")) {
 252                         enable_irq(i);
 253                         irqs |= (1 << i);
 254                 }
 255         }
 256 
 257         /* wait for spurious interrupts to mask themselves out again */
 258         for (delay = jiffies + 2; delay > jiffies; );   /* min 10ms delay */
 259 
 260         /* now filter out any obviously spurious interrupts */
 261         irqmask = (((unsigned int)cache_A1)<<8) | (unsigned int)cache_21;
 262         for (i = 15; i > 0; i--) {
 263                 if (irqs & (1 << i) & irqmask) {
 264                         irqs ^= (1 << i);
 265                         free_irq(i);
 266                 }
 267         }
 268 #ifdef DEBUG
 269         printk("probe_irq_on:  irqs=0x%04x irqmask=0x%04x\n", irqs, irqmask);
 270 #endif
 271         return irqs;
 272 }
 273 
 274 int probe_irq_off (unsigned long irqs)
     /* [previous][next][first][last][top][bottom][index][help] */
 275 {
 276         unsigned int i, irqmask;
 277 
 278         irqmask = (((unsigned int)cache_A1)<<8) | (unsigned int)cache_21;
 279         for (i = 15; i > 0; i--) {
 280                 if (irqs & (1 << i)) {
 281                         free_irq(i);
 282                 }
 283         }
 284 #ifdef DEBUG
 285         printk("probe_irq_off: irqs=0x%04x irqmask=0x%04x\n", irqs, irqmask);
 286 #endif
 287         irqs &= irqmask;
 288         if (!irqs)
 289                 return 0;
 290         i = ffz(~irqs);
 291         if (irqs != (irqs & (1 << i)))
 292                 i = -i;
 293         return i;
 294 }
 295 
 296 void init_IRQ(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 297 {
 298         int i;
 299 
 300         switch (boot_info.machtype) {
 301                 case MACH_MIPS_MAGNUM_4000:
 302                 case MACH_ACER_PICA_61:
 303                         r4030_write_reg16(JAZZ_IO_IRQ_ENABLE,
 304                                           JAZZ_IE_ETHERNET |
 305                                           JAZZ_IE_SERIAL1  |
 306                                           JAZZ_IE_SERIAL2  |
 307                                           JAZZ_IE_PARALLEL |
 308                                           JAZZ_IE_FLOPPY);
 309                         r4030_read_reg16(JAZZ_IO_IRQ_SOURCE); /* clear pending IRQs */
 310                         set_cp0_status(ST0_IM, IE_IRQ4 | IE_IRQ1);
 311                         /* set the clock to 100 Hz */
 312                         r4030_write_reg32(JAZZ_TIMER_INTERVAL, 9);
 313                         break;
 314                 case MACH_DESKSTATION_TYNE:
 315                         /* set the clock to 100 Hz */
 316                         outb_p(0x34,0x43);              /* binary, mode 2, LSB/MSB, ch 0 */
 317                         outb_p(LATCH & 0xff , 0x40);    /* LSB */
 318                         outb(LATCH >> 8 , 0x40);        /* MSB */
 319 
 320                         if (request_irq(2, no_action, SA_INTERRUPT, "cascade"))
 321                                 printk("Unable to get IRQ2 for cascade\n");
 322                         break;
 323                 default:
 324                         panic("Unknown machtype in init_IRQ");
 325         }
 326 
 327         for (i = 0; i < 16 ; i++)
 328                 set_int_vector(i, bad_interrupt);
 329 
 330         /* initialize the bottom half routines. */
 331         for (i = 0; i < 32; i++) {
 332                 bh_base[i].routine = NULL;
 333                 bh_base[i].data = NULL;
 334         }
 335         bh_active = 0;
 336         intr_count = 0;
 337 }

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