root/arch/sparc/kernel/irq.c

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

DEFINITIONS

This source file includes following definitions.
  1. sun4c_disable_irq
  2. sun4m_disable_irq
  3. disable_irq
  4. sun4c_enable_irq
  5. sun4m_enable_irq
  6. enable_irq
  7. get_irq_list
  8. free_irq
  9. unexpected_irq
  10. handler_irq
  11. do_IRQ
  12. do_fast_IRQ
  13. request_fast_irq
  14. request_irq
  15. probe_irq_on
  16. probe_irq_off
  17. sun4c_init_IRQ
  18. sun4m_init_IRQ
  19. init_IRQ

   1 /*  $Id: irq.c,v 1.34 1996/02/20 07:45:04 davem 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@jamica.lab.ipmce.su)
  10  */
  11 
  12 #include <linux/ptrace.h>
  13 #include <linux/errno.h>
  14 #include <linux/linkage.h>
  15 #include <linux/kernel_stat.h>
  16 #include <linux/signal.h>
  17 #include <linux/sched.h>
  18 #include <linux/interrupt.h>
  19 #include <linux/malloc.h>
  20 
  21 #include <asm/ptrace.h>
  22 #include <asm/processor.h>
  23 #include <asm/system.h>
  24 #include <asm/psr.h>
  25 #include <asm/vaddrs.h>
  26 #include <asm/timer.h>
  27 #include <asm/openprom.h>
  28 #include <asm/oplib.h>
  29 #include <asm/traps.h>
  30 #include <asm/irq.h>
  31 #include <asm/io.h>
  32 
  33 /* Pointer to the interrupt enable byte */
  34 unsigned char *interrupt_enable = 0;
  35 struct sun4m_intregs *sun4m_interrupts;
  36 
  37 void sun4c_disable_irq(unsigned int irq_nr)
     /* [previous][next][first][last][top][bottom][index][help] */
  38 {
  39         unsigned long flags;
  40         unsigned char current_mask, new_mask;
  41 
  42         if(sparc_cpu_model != sun4c)
  43                 return;
  44         save_flags(flags); cli();
  45         current_mask = *interrupt_enable;
  46         switch(irq_nr) {
  47         case 1:
  48                 new_mask = ((current_mask) & (~(SUN4C_INT_E1)));
  49                 break;
  50         case 8:
  51                 new_mask = ((current_mask) & (~(SUN4C_INT_E8)));
  52                 break;
  53         case 10:
  54                 new_mask = ((current_mask) & (~(SUN4C_INT_E10)));
  55                 break;
  56         case 14:
  57                 new_mask = ((current_mask) & (~(SUN4C_INT_E14)));
  58                 break;
  59         default:
  60                 restore_flags(flags);
  61                 return;
  62         }
  63         *interrupt_enable = new_mask;
  64         restore_flags(flags);
  65 }
  66 
  67 void sun4m_disable_irq(unsigned int irq_nr)
     /* [previous][next][first][last][top][bottom][index][help] */
  68 {
  69 #if 0
  70         printk("IRQ routines not yet written for the sun4m\n");
  71         panic("disable_irq: Unsupported arch.");
  72 #endif
  73 }
  74 
  75 void disable_irq(unsigned int irq_nr)
     /* [previous][next][first][last][top][bottom][index][help] */
  76 {
  77         switch(sparc_cpu_model) {
  78         case sun4c:
  79                 sun4c_disable_irq(irq_nr);
  80                 break;
  81         case sun4m:
  82                 sun4m_disable_irq(irq_nr);
  83                 break;
  84         default:
  85                 panic("disable_irq: Unsupported arch.");
  86         }
  87 }
  88 
  89 void sun4c_enable_irq(unsigned int irq_nr)
     /* [previous][next][first][last][top][bottom][index][help] */
  90 {
  91         unsigned long flags;
  92         unsigned char current_mask, new_mask;
  93 
  94         if(sparc_cpu_model != sun4c)
  95                 return;
  96         save_flags(flags); cli();
  97         current_mask = *interrupt_enable;
  98         switch(irq_nr) {
  99         case 1:
 100                 new_mask = ((current_mask) | SUN4C_INT_E1);
 101                 break;
 102         case 8:
 103                 new_mask = ((current_mask) | SUN4C_INT_E8);
 104                 break;
 105         case 10:
 106                 new_mask = ((current_mask) | SUN4C_INT_E10);
 107                 break;
 108         case 14:
 109                 new_mask = ((current_mask) | SUN4C_INT_E14);
 110                 break;
 111         default:
 112                 restore_flags(flags);
 113                 return;
 114         }
 115         *interrupt_enable = new_mask;
 116         restore_flags(flags);
 117 }
 118 
 119 void sun4m_enable_irq(unsigned int irq_nr)
     /* [previous][next][first][last][top][bottom][index][help] */
 120 {
 121 #if 0
 122         printk("IRQ routines not written for the sun4m yet.\n");
 123         panic("IRQ unsupported arch.");
 124 #endif
 125 }
 126 
 127 void enable_irq(unsigned int irq_nr)
     /* [previous][next][first][last][top][bottom][index][help] */
 128 {
 129         switch(sparc_cpu_model) {
 130         case sun4c:
 131                 sun4c_enable_irq(irq_nr);
 132                 break;
 133         case sun4m:
 134                 sun4m_enable_irq(irq_nr);
 135                 break;
 136         default:
 137                 panic("IRQ unsupported arch.");
 138         }
 139 }
 140 
 141 /*
 142  * Initial irq handlers.
 143  */
 144 extern void timer_interrupt(int, void *, struct pt_regs *);
 145 extern void rs_interrupt(int, void *, struct pt_regs *);
 146 
 147 static struct irqaction timer_irq = {
 148         timer_interrupt,
 149         SA_INTERRUPT,
 150         0, "timer",
 151         NULL, NULL
 152 };
 153 
 154 static struct irqaction serial_irq = {
 155         rs_interrupt,
 156         SA_INTERRUPT,
 157         0, "zilog serial",
 158         NULL, NULL
 159 };
 160 
 161 static struct irqaction *irq_action[16] = {
 162           NULL, NULL, NULL, NULL, NULL, NULL , NULL, NULL,
 163           NULL, NULL, &timer_irq, NULL, &serial_irq, NULL , NULL, NULL
 164 };
 165 
 166 
 167 int get_irq_list(char *buf)
     /* [previous][next][first][last][top][bottom][index][help] */
 168 {
 169         int i, len = 0;
 170         struct irqaction * action;
 171 
 172         for (i = 0 ; i < 16 ; i++) {
 173                 action = *(i + irq_action);
 174                 if (!action) 
 175                         continue;
 176                 len += sprintf(buf+len, "%2d: %8d %c %s",
 177                         i, kstat.interrupts[i],
 178                         (action->flags & SA_INTERRUPT) ? '+' : ' ',
 179                         action->name);
 180                 for (action=action->next; action; action = action->next) {
 181                         len += sprintf(buf+len, ",%s %s",
 182                                 (action->flags & SA_INTERRUPT) ? " +" : "",
 183                                 action->name);
 184                 }
 185                 len += sprintf(buf+len, "\n");
 186         }
 187         return len;
 188 }
 189 
 190 void free_irq(unsigned int irq, void *dev_id)
     /* [previous][next][first][last][top][bottom][index][help] */
 191 {
 192         struct irqaction * action = *(irq + irq_action);
 193         struct irqaction * tmp = NULL;
 194         unsigned long flags;
 195 
 196         if (irq > 14) {  /* 14 irq levels on the sparc */
 197                 printk("Trying to free bogus IRQ %d\n", irq);
 198                 return;
 199         }
 200         if (!action->handler) {
 201                 printk("Trying to free free IRQ%d\n",irq);
 202                 return;
 203         }
 204         if (dev_id) {
 205                 for (; action; action = action->next) {
 206                         if (action->dev_id == dev_id) break;
 207                         tmp = action;
 208                 }
 209                 if (!action) {
 210                         printk("Trying to free free shared IRQ%d\n",irq);
 211                         return;
 212                 }
 213         } else if (action->flags & SA_SHIRQ) {
 214                 printk("Trying to free shared IRQ%d with NULL device ID\n", irq);
 215                 return;
 216         }
 217         save_flags(flags); cli();
 218         if (action && tmp)
 219                 tmp->next = action->next;
 220         else
 221                 *(irq + irq_action) = action->next;
 222 
 223         kfree_s(action, sizeof(struct irqaction));
 224 
 225         if (!(*(irq + irq_action)))
 226                 disable_irq(irq);
 227 
 228         restore_flags(flags);
 229 }
 230 
 231 void unexpected_irq(int irq, void *dev_id, struct pt_regs * regs)
     /* [previous][next][first][last][top][bottom][index][help] */
 232 {
 233         int i;
 234         struct irqaction * action = *(irq + irq_action);
 235 
 236         printk("IO device interrupt, irq = %d\n", irq);
 237         printk("PC = %08lx NPC = %08lx FP=%08lx\n", regs->pc, 
 238                     regs->npc, regs->u_regs[14]);
 239         printk("Expecting: ");
 240         for (i = 0; i < 16; i++)
 241                 if (action->handler)
 242                         prom_printf("[%s:%d:0x%x] ", action->name, (int) i,
 243                                     (unsigned int) action->handler);
 244         printk("AIEEE\n");
 245         panic("bogus interrupt received");
 246 }
 247 
 248 void handler_irq(int irq, struct pt_regs * regs)
     /* [previous][next][first][last][top][bottom][index][help] */
 249 {
 250         struct irqaction * action = *(irq + irq_action);
 251 
 252         kstat.interrupts[irq]++;
 253         while (action) {
 254                 if (!action->handler)
 255                         unexpected_irq(irq, action->dev_id, regs);
 256                 else
 257                         action->handler(irq, action->dev_id, regs);
 258                 action = action->next;
 259         }
 260 }
 261 
 262 /*
 263  * do_IRQ handles IRQ's that have been installed without the
 264  * SA_INTERRUPT flag: it uses the full signal-handling return
 265  * and runs with other interrupts enabled. All relatively slow
 266  * IRQ's should use this format: notably the keyboard/timer
 267  * routines.
 268  */
 269 asmlinkage void do_IRQ(int irq, struct pt_regs * regs)
     /* [previous][next][first][last][top][bottom][index][help] */
 270 {
 271         struct irqaction * action = *(irq + irq_action);
 272 
 273         kstat.interrupts[irq]++;
 274         while (action) {
 275                 action->handler(irq, action->dev_id, regs);
 276                 action = action->next;
 277         }
 278 }
 279 
 280 /*
 281  * do_fast_IRQ handles IRQ's that don't need the fancy interrupt return
 282  * stuff - the handler is also running with interrupts disabled unless
 283  * it explicitly enables them later.
 284  */
 285 asmlinkage void do_fast_IRQ(int irq)
     /* [previous][next][first][last][top][bottom][index][help] */
 286 {
 287         kstat.interrupts[irq]++;
 288         printk("Got FAST_IRQ number %04lx\n", (long unsigned int) irq);
 289         return;
 290 }
 291 
 292 /* Fast IRQ's on the Sparc can only have one routine attached to them,
 293  * thus no sharing possible.
 294  */
 295 int request_fast_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
     /* [previous][next][first][last][top][bottom][index][help] */
 296                      unsigned long irqflags, const char *devname)
 297 {
 298         struct irqaction *action;
 299         unsigned long flags;
 300 
 301         if(irq > 14)
 302                 return -EINVAL;
 303         if(!handler)
 304                 return -EINVAL;
 305         action = *(irq + irq_action);
 306         if(action) {
 307                 if(action->flags & SA_SHIRQ)
 308                         panic("Trying to register fast irq when already shared.\n");
 309                 if(irqflags & SA_SHIRQ)
 310                         panic("Trying to register fast irq as shared.\n");
 311 
 312                 /* Anyway, someone already owns it so cannot be made fast. */
 313                 return -EBUSY;
 314         }
 315 
 316         save_flags(flags); cli();
 317 
 318         action = (struct irqaction *)kmalloc(sizeof(struct irqaction), GFP_KERNEL);
 319 
 320         if (!action) { 
 321                 restore_flags(flags);
 322                 return -ENOMEM;
 323         }
 324 
 325         /* Dork with trap table if we get this far. */
 326         sparc_ttable[SP_TRAP_IRQ1+(irq-1)].inst_one =
 327                 SPARC_BRANCH((unsigned long) handler,
 328                              (unsigned long) &sparc_ttable[SP_TRAP_IRQ1+(irq-1)].inst_one);
 329         sparc_ttable[SP_TRAP_IRQ1+(irq-1)].inst_two = SPARC_RD_PSR_L0;
 330         sparc_ttable[SP_TRAP_IRQ1+(irq-1)].inst_three = SPARC_NOP;
 331         sparc_ttable[SP_TRAP_IRQ1+(irq-1)].inst_four = SPARC_NOP;
 332 
 333         action->handler = handler;
 334         action->flags = irqflags;
 335         action->mask = 0;
 336         action->name = devname;
 337         action->dev_id = NULL;
 338 
 339         *(irq + irq_action) = action;
 340 
 341         restore_flags(flags);
 342         return 0;
 343 }
 344 
 345 int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
     /* [previous][next][first][last][top][bottom][index][help] */
 346                 unsigned long irqflags, const char * devname, void *dev_id)
 347 {
 348         struct irqaction * action, *tmp = NULL;
 349         unsigned long flags;
 350 
 351         if(irq > 14)
 352                 return -EINVAL;
 353 
 354         if (!handler)
 355             return -EINVAL;
 356         action = *(irq + irq_action);
 357         if (action) {
 358                 if ((action->flags & SA_SHIRQ) && (irqflags & SA_SHIRQ)) {
 359                         for (tmp = action; tmp->next; tmp = tmp->next);
 360                 } else {
 361                         return -EBUSY;
 362                 }
 363                 if ((action->flags & SA_INTERRUPT) ^ (irqflags & SA_INTERRUPT)) {
 364                         printk("Attempt to mix fast and slow interrupts on IRQ%d denied\n", irq);
 365                         return -EBUSY;
 366                 }   
 367         }
 368 
 369         save_flags(flags); cli();
 370         action = (struct irqaction *)kmalloc(sizeof(struct irqaction), GFP_KERNEL);
 371 
 372         if (!action) { 
 373                 restore_flags(flags);
 374                 return -ENOMEM;
 375         }
 376 
 377         action->handler = handler;
 378         action->flags = irqflags;
 379         action->mask = 0;
 380         action->name = devname;
 381         action->next = NULL;
 382         action->dev_id = dev_id;
 383 
 384         if (tmp)
 385                 tmp->next = action;
 386         else
 387                 *(irq + irq_action) = action;
 388 
 389         enable_irq(irq);
 390         restore_flags(flags);
 391         return 0;
 392 }
 393 
 394 /* We really don't need these at all on the Sparc.  We only have
 395  * stubs here because they are exported to modules.
 396  */
 397 unsigned long probe_irq_on(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 398 {
 399   return 0;
 400 }
 401 
 402 int probe_irq_off(unsigned long mask)
     /* [previous][next][first][last][top][bottom][index][help] */
 403 {
 404   return 0;
 405 }
 406 
 407 void sun4c_init_IRQ(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 408 {
 409         struct linux_prom_registers int_regs[2];
 410         int ie_node;
 411 
 412         ie_node = prom_searchsiblings (prom_getchild(prom_root_node),
 413                                        "interrupt-enable");
 414         if(ie_node == 0)
 415                 panic("Cannot find /interrupt-enable node");
 416         /* Depending on the "address" property is bad news... */
 417         prom_getproperty(ie_node, "reg", (char *) int_regs, sizeof(int_regs));
 418         interrupt_enable = (char *) sparc_alloc_io(int_regs[0].phys_addr, 0,
 419                                                    int_regs[0].reg_size,
 420                                                    "sun4c_interrupts",
 421                                                    int_regs[0].which_io, 0x0);
 422         *interrupt_enable = (SUN4C_INT_ENABLE);
 423         sti();
 424 }
 425 
 426 void sun4m_init_IRQ(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 427 {
 428         int ie_node;
 429 
 430         struct linux_prom_registers int_regs[PROMREG_MAX];
 431         int num_regs;
 432 
 433         cli();
 434         if((ie_node = prom_searchsiblings(prom_getchild(prom_root_node), "obio")) == 0 ||
 435            (ie_node = prom_getchild (ie_node)) == 0 ||
 436            (ie_node = prom_searchsiblings (ie_node, "interrupt")) == 0)
 437                 panic("Cannot find /obio/interrupt node\n");
 438         num_regs = prom_getproperty(ie_node, "reg", (char *) int_regs,
 439                                     sizeof(int_regs));
 440         num_regs = (num_regs/sizeof(struct linux_prom_registers));
 441 
 442         /* Apply the obio ranges to these registers. */
 443         prom_apply_obio_ranges(int_regs, num_regs);
 444 
 445         /* Map the interrupt registers for all possible cpus. */
 446         sun4m_interrupts = sparc_alloc_io(int_regs[0].phys_addr, 0,
 447                                           PAGE_SIZE*NCPUS, "interrupts_percpu",
 448                                           int_regs[0].which_io, 0x0);
 449 
 450         /* Map the system interrupt control registers. */
 451         sparc_alloc_io(int_regs[num_regs-1].phys_addr, 0,
 452                        int_regs[num_regs-1].reg_size, "interrupts_system",
 453                        int_regs[num_regs-1].which_io, 0x0);
 454         sti();
 455 }
 456 
 457 void init_IRQ(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 458 {
 459         switch(sparc_cpu_model) {
 460         case sun4c:
 461                 sun4c_init_IRQ();
 462                 break;
 463         case sun4m:
 464                 sun4m_init_IRQ();
 465                 break;
 466         default:
 467                 prom_printf("Cannot initialize IRQ's on this Sun machine...");
 468                 break;
 469         }
 470 }

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