root/arch/sparc/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. free_irq
  5. unexpected_irq
  6. handler_irq
  7. do_IRQ
  8. do_fast_IRQ
  9. request_irq
  10. sun4c_init_IRQ
  11. sun4m_init_IRQ
  12. init_IRQ

   1 /*  arch/sparc/kernel/irq.c:  Interrupt request handling routines. On the
   2  *                            Sparc the IRQ's are basically 'cast in stone'
   3  *                            and you are supposed to probe the prom's device
   4  *                            node trees to find out who's got which IRQ.
   5  *
   6  *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
   7  *  Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx)
   8  *  Copyright (C) 1995 Pete A. Zaitcev (zaitcev@jamica.lab.ipmce.su)
   9  */
  10 
  11 /*
  12  * IRQ's are in fact implemented a bit like signal handlers for the kernel.
  13  * The same sigaction struct is used, and with similar semantics (ie there
  14  * is a SA_INTERRUPT flag etc). Naturally it's not a 1:1 relation, but there
  15  * are similarities.
  16  *
  17  * sa_handler(int irq_NR) is the default function called (0 if no).
  18  * sa_mask is horribly ugly (I won't even mention it)
  19  * sa_flags contains various info: SA_INTERRUPT etc
  20  * sa_restorer is the unused
  21  */
  22 
  23 #include <linux/config.h>
  24 #include <linux/ptrace.h>
  25 #include <linux/errno.h>
  26 #include <linux/linkage.h>
  27 #include <linux/kernel_stat.h>
  28 #include <linux/signal.h>
  29 #include <linux/sched.h>
  30 #include <linux/interrupt.h>
  31 
  32 #include <asm/ptrace.h>
  33 #include <asm/processor.h>
  34 #include <asm/system.h>
  35 #include <asm/psr.h>
  36 #include <asm/vaddrs.h>
  37 #include <asm/timer.h>
  38 #include <asm/openprom.h>
  39 #include <asm/oplib.h>
  40 #include <asm/irq.h>
  41 #include <asm/io.h>
  42 
  43 /* Pointer to the interrupt enable byte */
  44 /* XXX Ugh, this is so sun4c specific it's driving me nuts. XXX */
  45 unsigned char *interrupt_enable = 0;
  46 struct sun4m_intregs *sun4m_interrupts;
  47 
  48 /* XXX Needs to handle Sun4m semantics XXX */
  49 void
  50 disable_irq(unsigned int irq_nr)
     /* [previous][next][first][last][top][bottom][index][help] */
  51 {
  52         unsigned long flags;
  53         unsigned char current_mask, new_mask;
  54 
  55         if(sparc_cpu_model != sun4c) return;
  56 
  57         save_flags(flags);
  58         cli();
  59 
  60         current_mask = *interrupt_enable;
  61 
  62         switch(irq_nr) {
  63         case 1:
  64                 new_mask = ((current_mask) & (~(SUN4C_INT_E1)));
  65                 break;
  66         case 4:
  67                 new_mask = ((current_mask) & (~(SUN4C_INT_E4)));
  68                 break;
  69         case 6:
  70                 new_mask = ((current_mask) & (~(SUN4C_INT_E6)));
  71                 break;
  72         case 8:
  73                 new_mask = ((current_mask) & (~(SUN4C_INT_E8)));
  74                 break;
  75         case 10:
  76                 new_mask = ((current_mask) & (~(SUN4C_INT_E10)));
  77                 break;
  78         case 14:
  79                 new_mask = ((current_mask) & (~(SUN4C_INT_E14)));
  80                 break;
  81         default:
  82 #if 0 /* Actually this is safe, as the floppy driver needs this */
  83                 printk("AIEEE, Illegal interrupt disable requested irq=%d\n", 
  84                        (int) irq_nr);
  85                 prom_halt();
  86 #endif
  87                 break;
  88         };
  89   
  90         restore_flags(flags);
  91         return;
  92 }
  93 
  94 /* XXX Needs to handle sun4m semantics XXX */
  95 void
  96 enable_irq(unsigned int irq_nr)
     /* [previous][next][first][last][top][bottom][index][help] */
  97 {
  98         unsigned long flags;
  99         unsigned char current_mask, new_mask;
 100 
 101         if(sparc_cpu_model != sun4c) return;
 102 
 103         save_flags(flags);
 104         cli();
 105 
 106         current_mask = *interrupt_enable;
 107 
 108         switch(irq_nr) {
 109         case 1:
 110                 new_mask = ((current_mask) | SUN4C_INT_E1);
 111                 break;
 112         case 4:
 113                 new_mask = ((current_mask) | SUN4C_INT_E4);
 114                 break;
 115         case 6:
 116                 new_mask = ((current_mask) | SUN4C_INT_E6);
 117                 break;
 118         case 8:
 119                 new_mask = ((current_mask) | SUN4C_INT_E8);
 120                 break;
 121         case 10:
 122                 new_mask = ((current_mask) | SUN4C_INT_E10);
 123                 break;
 124         case 14:
 125                 new_mask = ((current_mask) | SUN4C_INT_E14);
 126                 break;
 127         default:
 128 #if 0  /* Floppy driver does this on sun4c's anyhow */
 129                 printk ("Interrupt does not need to enable IE\n");
 130                 return;
 131 #endif
 132                 restore_flags(flags);
 133                 return;
 134         };
 135 
 136         *interrupt_enable = new_mask;
 137 
 138         restore_flags(flags);
 139 
 140         return;
 141 }
 142 
 143 /*
 144  * Initial irq handlers.
 145  */
 146 struct irqaction {
 147         void (*handler)(int, struct pt_regs *);
 148         unsigned long flags;
 149         unsigned long mask;
 150         const char *name;
 151 };
 152 
 153 static struct irqaction irq_action[16] = {
 154   { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
 155   { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
 156   { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
 157   { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
 158   { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
 159   { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
 160   { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
 161   { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL }
 162 };
 163 
 164 
 165 int
 166 get_irq_list(char *buf)
     /* [previous][next][first][last][top][bottom][index][help] */
 167 {
 168         int i, len = 0;
 169         struct irqaction * action = irq_action;
 170 
 171         for (i = 0 ; i < 16 ; i++, action++) {
 172                 if (!action->handler)
 173                         continue;
 174                 len += sprintf(buf+len, "%2d: %8d %c %s\n",
 175                                i, kstat.interrupts[i],
 176                                (action->flags & SA_INTERRUPT) ? '+' : ' ',
 177                                action->name);
 178         }
 179         return len;
 180 }
 181 
 182 void
 183 free_irq(unsigned int irq)
     /* [previous][next][first][last][top][bottom][index][help] */
 184 {
 185         struct irqaction * action = irq + irq_action;
 186         unsigned long flags;
 187 
 188         if (irq > 14) {  /* 14 irq levels on the sparc */
 189                 printk("Trying to free bogus IRQ %d\n", irq);
 190                 return;
 191         }
 192         if (!action->handler) {
 193                 printk("Trying to free free IRQ%d\n", irq);
 194                 return;
 195         }
 196         save_flags(flags);
 197         cli();
 198         disable_irq(irq);
 199         action->handler = NULL;
 200         action->flags = 0;
 201         action->mask = 0;
 202         action->name = NULL;
 203         restore_flags(flags);
 204 }
 205 
 206 void
 207 unexpected_irq(int irq, struct pt_regs * regs)
     /* [previous][next][first][last][top][bottom][index][help] */
 208 {
 209         int i;
 210 
 211         printk("IO device interrupt, irq = %d\n", irq);
 212         printk("PC = %08lx NPC = %08lx FP=%08lx\n", regs->pc, 
 213                regs->npc, regs->u_regs[14]);
 214         printk("Expecting: ");
 215         for (i = 0; i < 16; i++)
 216                 if (irq_action[i].handler)
 217                         printk("[%s:%d:0x%x] ", irq_action[i].name, (int) i,
 218                                (unsigned int) irq_action[i].handler);
 219         printk("AIEEE\n");
 220         prom_halt();
 221 }
 222 
 223 void
 224 handler_irq(int irq, struct pt_regs * regs)
     /* [previous][next][first][last][top][bottom][index][help] */
 225 {
 226         struct irqaction * action = irq_action + irq;
 227 
 228         if (!action->handler) {
 229                 unexpected_irq(irq, regs);
 230                 return;
 231         }
 232         action->handler(irq, regs);
 233 }
 234 
 235 /*
 236  * do_IRQ handles IRQ's that have been installed without the
 237  * SA_INTERRUPT flag: it uses the full signal-handling return
 238  * and runs with other interrupts enabled. All relatively slow
 239  * IRQ's should use this format: notably the keyboard/timer
 240  * routines.
 241  */
 242 asmlinkage void
 243 do_IRQ(int irq, struct pt_regs * regs)
     /* [previous][next][first][last][top][bottom][index][help] */
 244 {
 245         struct irqaction *action = irq + irq_action;
 246 
 247         kstat.interrupts[irq]++;
 248         action->handler(irq, regs);
 249         return;
 250 }
 251 
 252 /*
 253  * do_fast_IRQ handles IRQ's that don't need the fancy interrupt return
 254  * stuff - the handler is also running with interrupts disabled unless
 255  * it explicitly enables them later.
 256  */
 257 asmlinkage void
 258 do_fast_IRQ(int irq)
     /* [previous][next][first][last][top][bottom][index][help] */
 259 {
 260         kstat.interrupts[irq]++;
 261         printk("Got FAST_IRQ number %04lx\n", (long unsigned int) irq);
 262         return;
 263 }
 264 
 265 extern void probe_clock(void);
 266                 
 267 int
 268 request_irq(unsigned int irq, void (*handler)(int, struct pt_regs *),
     /* [previous][next][first][last][top][bottom][index][help] */
 269             unsigned long irqflags, const char * devname)
 270 {
 271         struct irqaction *action;
 272         unsigned long flags;
 273 
 274         if(irq > 14)  /* Only levels 1-14 are valid on the Sparc. */
 275                 return -EINVAL;
 276 
 277         /* i386 keyboard interrupt request, just return */
 278         if(irq == 1) return 0;
 279 
 280         /* sched_init() requesting the timer IRQ */
 281         if(irq == 0) {
 282                 irq = 10;
 283         }
 284 
 285         action = irq + irq_action;
 286 
 287         if(action->handler)
 288                 return -EBUSY;
 289 
 290         if(!handler)
 291                 return -EINVAL;
 292 
 293         save_flags(flags);
 294 
 295         cli();
 296 
 297         action->handler = handler;
 298         action->flags = irqflags;
 299         action->mask = 0;
 300         action->name = devname;
 301 
 302         enable_irq(irq);
 303 
 304         /* Init the timer/clocks if necessary. */
 305         if(irq == 10) probe_clock();
 306 
 307         restore_flags(flags);
 308 
 309         return 0;
 310 }
 311 
 312 void
 313 sun4c_init_IRQ(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 314 {
 315         struct linux_prom_registers int_regs[2];
 316         int ie_node;
 317 
 318         ie_node = prom_searchsiblings (prom_getchild(prom_root_node),
 319                                        "interrupt-enable");
 320         if(ie_node == 0) {
 321                 printk("Cannot find /interrupt-enable node\n");
 322                 prom_halt();
 323         }
 324         /* Depending on the "address" property is bad news... */
 325         prom_getproperty(ie_node, "reg", (char *) int_regs, sizeof(int_regs));
 326         sparc_alloc_io(int_regs[0].phys_addr, (void *) INTREG_VADDR,
 327                        int_regs[0].reg_size, "sun4c_interrupts",
 328                        int_regs[0].which_io, 0x0);
 329 
 330         interrupt_enable = (char *) INTREG_VADDR;
 331 
 332         /* Default value, accept interrupts, but no one is actually active */
 333         /* We also turn on level14 interrupts so PROM can run the console. */
 334         *interrupt_enable = (SUN4C_INT_ENABLE | SUN4C_INT_E14);
 335         sti(); /* As of NOW, L1-A works.  Turn irq's on full-blast. */
 336         return;
 337 }
 338 
 339 void
 340 sun4m_init_IRQ(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 341 {
 342         int ie_node, i;
 343 
 344         struct linux_prom_registers int_regs[PROMREG_MAX];
 345         int num_regs;
 346 
 347         cli();
 348 
 349         if((ie_node = prom_searchsiblings(prom_getchild(prom_root_node), "obio")) == 0 ||
 350            (ie_node = prom_getchild (ie_node)) == 0 ||
 351            (ie_node = prom_searchsiblings (ie_node, "interrupt")) == 0)
 352         {
 353                 printk("Cannot find /obio/interrupt node\n");
 354                 prom_halt();
 355         }
 356         num_regs = prom_getproperty(ie_node, "reg", (char *) int_regs,
 357                                     sizeof(int_regs));
 358         num_regs = (num_regs/sizeof(struct linux_prom_registers));
 359 
 360         /* Apply the obio ranges to these registers. */
 361         prom_apply_obio_ranges(int_regs, num_regs);
 362 
 363         /* Map the interrupt registers for all possible cpus. */
 364         sparc_alloc_io(int_regs[0].phys_addr, (void *) INTREG_VADDR,
 365                        PAGE_SIZE*NCPUS, "interrupts_percpu",
 366                        int_regs[0].which_io, 0x0);
 367 
 368         /* Map the system interrupt control registers. */
 369         sparc_alloc_io(int_regs[num_regs-1].phys_addr,
 370                        (void *) INTREG_VADDR+(NCPUS*PAGE_SIZE),
 371                        int_regs[num_regs-1].reg_size, "interrupts_system",
 372                        int_regs[num_regs-1].which_io, 0x0);
 373 
 374         sun4m_interrupts = (struct sun4m_intregs *) INTREG_VADDR;
 375 
 376 #if 0
 377         printk("Interrupt register dump...\n");
 378 
 379         for(i=0; i<NCPUS; i++)
 380                 printk("cpu%d: tbt %08x\n", i,
 381                        sun4m_interrupts->cpu_intregs[i].tbt);
 382 
 383         printk("Master tbt %08x\n", sun4m_interrupts->tbt);
 384         printk("Master irqs %08x\n", sun4m_interrupts->irqs);
 385         printk("Master set %08x\n", sun4m_interrupts->set);
 386         printk("Master clear %08x\n", sun4m_interrupts->clear);
 387         printk("Undirected ints taken by: %08x\n",
 388                sun4m_interrupts->undirected_target);
 389 
 390         prom_halt();
 391 #endif
 392 
 393         sti();
 394 
 395         return;
 396 }
 397 
 398 void
 399 init_IRQ(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 400 {
 401         switch(sparc_cpu_model) {
 402         case sun4c:
 403                 sun4c_init_IRQ();
 404                 break;
 405         case sun4m:
 406                 sun4m_init_IRQ();
 407                 break;
 408         default:
 409                 printk("Cannot initialize IRQ's on this Sun machine...\n");
 410                 halt();
 411                 break;
 412         };
 413 
 414         return;
 415 }

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