root/arch/sparc/kernel/irq.c

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

DEFINITIONS

This source file includes following definitions.
  1. irq_panic
  2. get_irq_list
  3. free_irq
  4. unexpected_irq
  5. handler_irq
  6. do_IRQ
  7. do_fast_IRQ
  8. request_fast_irq
  9. request_irq
  10. probe_irq_on
  11. probe_irq_off
  12. init_IRQ

   1 /*  $Id: irq.c,v 1.43 1996/04/17 12:37:45 zaitcev Exp $
   2  *  arch/sparc/kernel/irq.c:  Interrupt request handling routines. On the
   3  *                            Sparc the IRQ's are basically 'cast in stone'
   4  *                            and you are supposed to probe the prom's device
   5  *                            node trees to find out who's got which IRQ.
   6  *
   7  *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
   8  *  Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx)
   9  *  Copyright (C) 1995 Pete A. Zaitcev (zaitcev@ipmce.su)
  10  *  Copyright (C) 1996 Dave Redman (djhr@tadpole.co.uk)
  11  */
  12 
  13 #include <linux/config.h>
  14 #include <linux/ptrace.h>
  15 #include <linux/errno.h>
  16 #include <linux/linkage.h>
  17 #include <linux/kernel_stat.h>
  18 #include <linux/signal.h>
  19 #include <linux/sched.h>
  20 #include <linux/interrupt.h>
  21 #include <linux/malloc.h>
  22 
  23 #include <asm/ptrace.h>
  24 #include <asm/processor.h>
  25 #include <asm/system.h>
  26 #include <asm/psr.h>
  27 #include <asm/smp.h>
  28 #include <asm/vaddrs.h>
  29 #include <asm/timer.h>
  30 #include <asm/openprom.h>
  31 #include <asm/oplib.h>
  32 #include <asm/traps.h>
  33 #include <asm/irq.h>
  34 #include <asm/io.h>
  35 
  36 /*
  37  * Dave Redman (djhr@tadpole.co.uk)
  38  *
  39  * IRQ numbers.. These are no longer restricted to 15..
  40  *
  41  * this is done to enable SBUS cards and onboard IO to be masked
  42  * correctly. using the interrupt level isn't good enough.
  43  *
  44  * For example:
  45  *   A device interrupting at sbus level6 and the Floppy both come in
  46  *   at IRQ11, but enabling and disabling them requires writing to
  47  *   different bits in the SLAVIO/SEC.
  48  *
  49  * As a result of these changes sun4m machines could now support
  50  * directed CPU interrupts using the existing enable/disable irq code
  51  * with tweaks.
  52  *
  53  */
  54 
  55 static void irq_panic(void)
     /* [previous][next][first][last][top][bottom][index][help] */
  56 {
  57     extern char *cputypval;
  58     prom_printf("machine: %s doesn't have irq handlers defined!\n",cputypval);
  59     prom_halt();
  60 }
  61 
  62 void (*enable_irq)(unsigned int) = (void (*)(unsigned int)) irq_panic;
  63 void (*disable_irq)(unsigned int) = (void (*)(unsigned int)) irq_panic;
  64 void (*clear_clock_irq)( void ) = irq_panic;
  65 void (*clear_profile_irq)( void ) = irq_panic;
  66 void (*load_profile_irq)( unsigned int ) =  (void (*)(unsigned int)) irq_panic;
  67 void (*init_timers)( void (*)(int, void *,struct pt_regs *)) =
  68     (void (*)( void (*)(int, void *,struct pt_regs *))) irq_panic;
  69 
  70 #ifdef __SMP__
  71 void (*set_cpu_int)(int, int);
  72 void (*clear_cpu_int)(int, int);
  73 void (*set_irq_udt)(int);
  74 #endif
  75 
  76 /*
  77  * Dave Redman (djhr@tadpole.co.uk)
  78  *
  79  * There used to be extern calls and hard coded values here.. very sucky!
  80  * instead, because some of the devices attach very early, I do something
  81  * equally sucky but at least we'll never try to free statically allocated
  82  * space or call kmalloc before kmalloc_init :(.
  83  * 
  84  * In fact its the timer10 that attaches first.. then timer14
  85  * then kmalloc_init is called.. then the tty interrupts attach.
  86  * hmmm....
  87  *
  88  */
  89 #define MAX_STATIC_ALLOC        4
  90 static struct irqaction static_irqaction[MAX_STATIC_ALLOC];
  91 static int static_irq_count = 0;
  92 
  93 static struct irqaction *irq_action[NR_IRQS+1] = {
  94           NULL, NULL, NULL, NULL, NULL, NULL , NULL, NULL,
  95           NULL, NULL, NULL, NULL, NULL, NULL , NULL, NULL
  96 };
  97 
  98 int get_irq_list(char *buf)
     /* [previous][next][first][last][top][bottom][index][help] */
  99 {
 100         int i, len = 0;
 101         struct irqaction * action;
 102 
 103         for (i = 0 ; i < (NR_IRQS+1) ; i++) {
 104                 action = *(i + irq_action);
 105                 if (!action) 
 106                         continue;
 107                 len += sprintf(buf+len, "%2d: %8d %c %s",
 108                         i, kstat.interrupts[i],
 109                         (action->flags & SA_INTERRUPT) ? '+' : ' ',
 110                         action->name);
 111                 for (action=action->next; action; action = action->next) {
 112                         len += sprintf(buf+len, ",%s %s",
 113                                 (action->flags & SA_INTERRUPT) ? " +" : "",
 114                                 action->name);
 115                 }
 116                 len += sprintf(buf+len, "\n");
 117         }
 118         return len;
 119 }
 120 
 121 void free_irq(unsigned int irq, void *dev_id)
     /* [previous][next][first][last][top][bottom][index][help] */
 122 {
 123         struct irqaction * action;
 124         struct irqaction * tmp = NULL;
 125         unsigned long flags;
 126         unsigned int cpu_irq;
 127         
 128         cpu_irq = irq & NR_IRQS;
 129         action = *(cpu_irq + irq_action);
 130         if (cpu_irq > 14) {  /* 14 irq levels on the sparc */
 131                 printk("Trying to free bogus IRQ %d\n", irq);
 132                 return;
 133         }
 134         if (!action->handler) {
 135                 printk("Trying to free free IRQ%d\n",irq);
 136                 return;
 137         }
 138         if (dev_id) {
 139                 for (; action; action = action->next) {
 140                         if (action->dev_id == dev_id) break;
 141                         tmp = action;
 142                 }
 143                 if (!action) {
 144                         printk("Trying to free free shared IRQ%d\n",irq);
 145                         return;
 146                 }
 147         } else if (action->flags & SA_SHIRQ) {
 148                 printk("Trying to free shared IRQ%d with NULL device ID\n", irq);
 149                 return;
 150         }
 151         if (action->flags & SA_STATIC_ALLOC)
 152         {
 153             /* This interrupt is marked as specially allocated
 154              * so it is a bad idea to free it.
 155              */
 156             printk("Attempt to free statically allocated IRQ%d (%s)\n",
 157                    irq, action->name);
 158             return;
 159         }
 160         
 161         save_flags(flags); cli();
 162         if (action && tmp)
 163                 tmp->next = action->next;
 164         else
 165                 *(cpu_irq + irq_action) = action->next;
 166 
 167         kfree_s(action, sizeof(struct irqaction));
 168 
 169         if (!(*(cpu_irq + irq_action)))
 170                 disable_irq(irq);
 171 
 172         restore_flags(flags);
 173 }
 174 
 175 void unexpected_irq(int irq, void *dev_id, struct pt_regs * regs)
     /* [previous][next][first][last][top][bottom][index][help] */
 176 {
 177         int i;
 178         struct irqaction * action;
 179         unsigned int cpu_irq;
 180         
 181         cpu_irq = irq & NR_IRQS;
 182         action = *(cpu_irq + irq_action);
 183 
 184         printk("IO device interrupt, irq = %d\n", irq);
 185         printk("PC = %08lx NPC = %08lx FP=%08lx\n", regs->pc, 
 186                     regs->npc, regs->u_regs[14]);
 187         printk("Expecting: ");
 188         for (i = 0; i < 16; i++)
 189                 if (action->handler)
 190                         prom_printf("[%s:%d:0x%x] ", action->name, (int) i,
 191                                     (unsigned int) action->handler);
 192         printk("AIEEE\n");
 193         panic("bogus interrupt received");
 194 }
 195 
 196 void handler_irq(int irq, struct pt_regs * regs)
     /* [previous][next][first][last][top][bottom][index][help] */
 197 {
 198         struct irqaction * action;
 199         unsigned int cpu_irq;
 200         
 201         cpu_irq = irq & NR_IRQS;
 202         action = *(cpu_irq + irq_action);
 203         kstat.interrupts[cpu_irq]++;
 204 #if 0
 205         printk("I<%d,%d,%d>", smp_processor_id(), irq, smp_proc_in_lock[smp_processor_id()]);
 206 #endif
 207         while (action) {
 208                 if (!action->handler)
 209                         unexpected_irq(irq, action->dev_id, regs);
 210                 else
 211                         action->handler(irq, action->dev_id, regs);
 212                 action = action->next;
 213         }
 214 }
 215 
 216 /*
 217  * do_IRQ handles IRQ's that have been installed without the
 218  * SA_INTERRUPT flag: it uses the full signal-handling return
 219  * and runs with other interrupts enabled. All relatively slow
 220  * IRQ's should use this format: notably the keyboard/timer
 221  * routines.
 222  */
 223 asmlinkage void do_IRQ(int irq, struct pt_regs * regs)
     /* [previous][next][first][last][top][bottom][index][help] */
 224 {
 225         struct irqaction * action;
 226         unsigned int cpu_irq;
 227         
 228         cpu_irq = irq & NR_IRQS;
 229         action = *(cpu_irq + irq_action);
 230         kstat.interrupts[cpu_irq]++;
 231         while (action) {
 232                 action->handler(irq, action->dev_id, regs);
 233                 action = action->next;
 234         }
 235 }
 236 
 237 /*
 238  * do_fast_IRQ handles IRQ's that don't need the fancy interrupt return
 239  * stuff - the handler is also running with interrupts disabled unless
 240  * it explicitly enables them later.
 241  */
 242 asmlinkage void do_fast_IRQ(int irq)
     /* [previous][next][first][last][top][bottom][index][help] */
 243 {
 244         kstat.interrupts[irq&NR_IRQS]++;
 245         printk("Got FAST_IRQ number %04lx\n", (long unsigned int) irq);
 246         return;
 247 }
 248 
 249 /* Fast IRQ's on the Sparc can only have one routine attached to them,
 250  * thus no sharing possible.
 251  */
 252 int request_fast_irq(unsigned int irq,
     /* [previous][next][first][last][top][bottom][index][help] */
 253                      void (*handler)(int, void *, struct pt_regs *),
 254                      unsigned long irqflags, const char *devname)
 255 {
 256         struct irqaction *action;
 257         unsigned long flags;
 258         unsigned int cpu_irq;
 259         
 260         cpu_irq = irq & NR_IRQS;
 261         if(cpu_irq > 14)
 262                 return -EINVAL;
 263         if(!handler)
 264                 return -EINVAL;
 265         action = *(cpu_irq + irq_action);
 266         if(action) {
 267                 if(action->flags & SA_SHIRQ)
 268                         panic("Trying to register fast irq when already shared.\n");
 269                 if(irqflags & SA_SHIRQ)
 270                         panic("Trying to register fast irq as shared.\n");
 271 
 272                 /* Anyway, someone already owns it so cannot be made fast. */
 273                 return -EBUSY;
 274         }
 275 
 276         save_flags(flags); cli();
 277 
 278         /* If this is flagged as statically allocated then we use our
 279          * private struct which is never freed.
 280          */
 281         if (irqflags & SA_STATIC_ALLOC)
 282             if (static_irq_count < MAX_STATIC_ALLOC)
 283                 action = &static_irqaction[static_irq_count++];
 284             else
 285                 printk("Fast IRQ%d (%s) SA_STATIC_ALLOC failed using kmalloc\n",
 286                        irq, devname);
 287         
 288         if (action == NULL)
 289             action = (struct irqaction *)kmalloc(sizeof(struct irqaction),
 290                                                  GFP_KERNEL);
 291         
 292         if (!action) { 
 293                 restore_flags(flags);
 294                 return -ENOMEM;
 295         }
 296 
 297         /* Dork with trap table if we get this far. */
 298         sparc_ttable[SP_TRAP_IRQ1+(cpu_irq-1)].inst_one =
 299                 SPARC_BRANCH((unsigned long) handler,
 300                              (unsigned long) &sparc_ttable[SP_TRAP_IRQ1+(irq-1)].inst_one);
 301         sparc_ttable[SP_TRAP_IRQ1+(cpu_irq-1)].inst_two = SPARC_RD_PSR_L0;
 302         sparc_ttable[SP_TRAP_IRQ1+(cpu_irq-1)].inst_three = SPARC_NOP;
 303         sparc_ttable[SP_TRAP_IRQ1+(cpu_irq-1)].inst_four = SPARC_NOP;
 304 
 305         action->handler = handler;
 306         action->flags = irqflags;
 307         action->mask = 0;
 308         action->name = devname;
 309         action->dev_id = NULL;
 310 
 311         *(cpu_irq + irq_action) = action;
 312 
 313         enable_irq(irq);
 314         restore_flags(flags);
 315         return 0;
 316 }
 317 
 318 int request_irq(unsigned int irq,
     /* [previous][next][first][last][top][bottom][index][help] */
 319                 void (*handler)(int, void *, struct pt_regs *),
 320                 unsigned long irqflags, const char * devname, void *dev_id)
 321 {
 322         struct irqaction * action, *tmp = NULL;
 323         unsigned long flags;
 324         unsigned int cpu_irq;
 325         
 326         cpu_irq = irq & NR_IRQS;
 327         if(cpu_irq > 14)
 328                 return -EINVAL;
 329 
 330         if (!handler)
 331             return -EINVAL;
 332         action = *(cpu_irq + irq_action);
 333         if (action) {
 334                 if ((action->flags & SA_SHIRQ) && (irqflags & SA_SHIRQ)) {
 335                         for (tmp = action; tmp->next; tmp = tmp->next);
 336                 } else {
 337                         return -EBUSY;
 338                 }
 339                 if ((action->flags & SA_INTERRUPT) ^ (irqflags & SA_INTERRUPT)) {
 340                         printk("Attempt to mix fast and slow interrupts on IRQ%d denied\n", irq);
 341                         return -EBUSY;
 342                 }   
 343         }
 344 
 345         save_flags(flags); cli();
 346 
 347         /* If this is flagged as statically allocated then we use our
 348          * private struct which is never freed.
 349          */
 350         if (irqflags & SA_STATIC_ALLOC)
 351             if (static_irq_count < MAX_STATIC_ALLOC)
 352                 action = &static_irqaction[static_irq_count++];
 353             else
 354                 printk("Request for IRQ%d (%s) SA_STATIC_ALLOC failed using kmalloc\n",irq, devname);
 355         
 356         if (action == NULL)
 357             action = (struct irqaction *)kmalloc(sizeof(struct irqaction),
 358                                                  GFP_KERNEL);
 359         
 360         if (!action) { 
 361                 restore_flags(flags);
 362                 return -ENOMEM;
 363         }
 364 
 365         action->handler = handler;
 366         action->flags = irqflags;
 367         action->mask = 0;
 368         action->name = devname;
 369         action->next = NULL;
 370         action->dev_id = dev_id;
 371 
 372         if (tmp)
 373                 tmp->next = action;
 374         else
 375                 *(cpu_irq + irq_action) = action;
 376 
 377         enable_irq(irq);
 378         restore_flags(flags);
 379         return 0;
 380 }
 381 
 382 /* We really don't need these at all on the Sparc.  We only have
 383  * stubs here because they are exported to modules.
 384  */
 385 unsigned long probe_irq_on(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 386 {
 387   return 0;
 388 }
 389 
 390 int probe_irq_off(unsigned long mask)
     /* [previous][next][first][last][top][bottom][index][help] */
 391 {
 392   return 0;
 393 }
 394 
 395 /* djhr
 396  * This could probably be made indirect too and assigned in the CPU
 397  * bits of the code. That would be much nicer I think and would also
 398  * fit in with the idea of being able to tune your kernel for your machine
 399  * by removing unrequired machine and device support.
 400  *
 401  */
 402 
 403 void init_IRQ(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 404 {
 405         extern void sun4c_init_IRQ( void );
 406         extern void sun4m_init_IRQ( void );
 407 #if CONFIG_AP1000
 408         extern void ap_init_IRQ(void);
 409         ap_init_IRQ();
 410         return;
 411 #endif
 412     
 413         switch(sparc_cpu_model) {
 414         case sun4c:
 415                 sun4c_init_IRQ();
 416                 break;
 417 
 418         case sun4m:
 419                 sun4m_init_IRQ();
 420                 break;
 421 
 422         default:
 423                 prom_printf("Cannot initialize IRQ's on this Sun machine...");
 424                 break;
 425         }
 426 }

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