root/arch/sparc/kernel/sun4m_irq.c

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

DEFINITIONS

This source file includes following definitions.
  1. sun4m_get_irqmask
  2. sun4m_disable_irq
  3. sun4m_enable_irq
  4. sun4m_send_ipi
  5. sun4m_clear_ipi
  6. sun4m_set_udt
  7. sun4m_clear_clock_irq
  8. sun4m_clear_profile_irq
  9. sun4m_load_profile_irq
  10. sun4m_lvl14_handler
  11. sun4m_init_timers
  12. sun4m_init_IRQ

   1 /*  sun4m_irq.c
   2  *  arch/sparc/kernel/sun4m_irq.c:
   3  *
   4  *  djhr: Hacked out of irq.c into a CPU dependent version.
   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@ipmce.su)
   9  *  Copyright (C) 1996 Dave Redman (djhr@tadpole.co.uk)
  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/smp.h>
  19 #include <linux/interrupt.h>
  20 #include <linux/malloc.h>
  21 
  22 #include <asm/ptrace.h>
  23 #include <asm/processor.h>
  24 #include <asm/system.h>
  25 #include <asm/psr.h>
  26 #include <asm/vaddrs.h>
  27 #include <asm/timer.h>
  28 #include <asm/openprom.h>
  29 #include <asm/oplib.h>
  30 #include <asm/traps.h>
  31 #include <asm/smp.h>
  32 #include <asm/irq.h>
  33 #include <asm/io.h>
  34 
  35 static unsigned long dummy;
  36 
  37 extern int linux_num_cpus;
  38 struct sun4m_intregs *sun4m_interrupts;
  39 unsigned long *irq_rcvreg = &dummy;
  40 
  41 /* These tables only apply for interrupts greater than 15..
  42  * 
  43  * any intr value below 0x10 is considered to be a soft-int
  44  * this may be useful or it may not.. but thats how I've done it.
  45  * and it won't clash with what OBP is telling us about devices.
  46  *
  47  * take an encoded intr value and lookup if its valid
  48  * then get the mask bits that match from irq_mask
  49  */
  50 static unsigned char irq_xlate[32] = {
  51     /*  0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  a,  b,  c,  d,  e,  f */
  52         0,  0,  0,  0,  1,  0,  2,  0,  3,  0,  4,  5,  6,  0,  0,  7,
  53         0,  0,  8,  9,  0, 10,  0, 11,  0, 12,  0, 13,  0, 14,  0,  0
  54 };
  55 
  56 static unsigned long irq_mask[] = {
  57         0,                                                /* illegal index */
  58         SUN4M_INT_SCSI,                                   /*  1 irq 4 */
  59         SUN4M_INT_ETHERNET,                               /*  2 irq 6 */
  60         SUN4M_INT_VIDEO,                                  /*  3 irq 8 */
  61         SUN4M_INT_REALTIME,                               /*  4 irq 10 */
  62         SUN4M_INT_FLOPPY,                                 /*  5 irq 11 */
  63         (SUN4M_INT_SERIAL | SUN4M_INT_KBDMS),             /*  6 irq 12 */
  64         SUN4M_INT_MODULE_ERR,                             /*  7 irq 15 */
  65         SUN4M_INT_SBUS(1),                                /*  8 irq 2 */
  66         SUN4M_INT_SBUS(2),                                /*  9 irq 3 */
  67         SUN4M_INT_SBUS(3),                                /* 10 irq 5 */
  68         SUN4M_INT_SBUS(4),                                /* 11 irq 7 */
  69         SUN4M_INT_SBUS(5),                                /* 12 irq 9 */
  70         SUN4M_INT_SBUS(6),                                /* 13 irq 11 */
  71         SUN4M_INT_SBUS(7)                                 /* 14 irq 13 */
  72 };
  73 
  74 inline unsigned long sun4m_get_irqmask(unsigned int irq)
     /* [previous][next][first][last][top][bottom][index][help] */
  75 {
  76         unsigned long mask;
  77     
  78         if (irq > 0x20) {
  79                 /* OBIO/SBUS interrupts */
  80                 irq &= 0x1f;
  81                 mask = irq_mask[irq_xlate[irq]];
  82                 if (!mask)
  83                         printk("sun4m_get_irqmask: IRQ%d has no valid mask!\n",irq);
  84         } else {
  85                 /* Soft Interrupts will come here
  86                  * Currently there is no way to trigger them but I'm sure something
  87                  * could be cooked up.
  88                  */
  89                 irq &= 0xf;
  90                 mask = SUN4M_SOFT_INT(irq);
  91         }
  92         return mask;
  93 }
  94 
  95 static void sun4m_disable_irq(unsigned int irq_nr)
     /* [previous][next][first][last][top][bottom][index][help] */
  96 {
  97         unsigned long mask, flags;
  98         int cpu = smp_processor_id();
  99 
 100         mask = sun4m_get_irqmask(irq_nr);
 101         save_flags(flags); cli();
 102         if (irq_nr > 15)
 103                 sun4m_interrupts->set = mask;
 104         else
 105                 sun4m_interrupts->cpu_intregs[cpu].set = mask;
 106         restore_flags(flags);    
 107 }
 108 
 109 static void sun4m_enable_irq(unsigned int irq_nr)
     /* [previous][next][first][last][top][bottom][index][help] */
 110 {
 111         unsigned long mask, flags;
 112         int cpu = smp_processor_id();
 113 
 114         /* Dreadful floppy hack. When we use 0x2b instead of
 115          * 0x0b the system blows (it starts to whistle!).
 116          * So we continue to use 0x0b. Fixme ASAP. --P3
 117          */
 118         if (irq_nr != 0x0b) {
 119                 mask = sun4m_get_irqmask(irq_nr);
 120                 save_flags(flags); cli();
 121                 if (irq_nr > 15)
 122                         sun4m_interrupts->clear = mask;
 123                 else
 124                         sun4m_interrupts->cpu_intregs[cpu].clear = mask;
 125                 restore_flags(flags);    
 126         } else {
 127                 save_flags(flags); cli();
 128                 sun4m_interrupts->clear = SUN4M_INT_FLOPPY;
 129                 restore_flags(flags);
 130         }
 131 }
 132 
 133 void sun4m_send_ipi(int cpu, int level)
     /* [previous][next][first][last][top][bottom][index][help] */
 134 {
 135         unsigned long mask;
 136 
 137         mask = sun4m_get_irqmask(level);
 138         sun4m_interrupts->cpu_intregs[cpu].set = mask;
 139 }
 140 
 141 void sun4m_clear_ipi(int cpu, int level)
     /* [previous][next][first][last][top][bottom][index][help] */
 142 {
 143         unsigned long mask;
 144 
 145         mask = sun4m_get_irqmask(level);
 146         sun4m_interrupts->cpu_intregs[cpu].clear = mask;
 147 }
 148 
 149 void sun4m_set_udt(int cpu)
     /* [previous][next][first][last][top][bottom][index][help] */
 150 {
 151         sun4m_interrupts->undirected_target = cpu;
 152 }
 153 
 154 #define OBIO_INTR       0x20
 155 #define TIMER_IRQ       (OBIO_INTR | 10)
 156 #define PROFILE_IRQ     (OBIO_INTR | 14)
 157 
 158 struct sun4m_timer_regs *sun4m_timers;
 159 unsigned int lvl14_resolution = (((1000000/HZ) + 1) << 10);
 160 
 161 static void sun4m_clear_clock_irq(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 162 {
 163         volatile unsigned int clear_intr;
 164         clear_intr = sun4m_timers->l10_timer_limit;
 165 }
 166 
 167 static void sun4m_clear_profile_irq(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 168 {
 169         volatile unsigned int clear;
 170     
 171         clear = sun4m_timers->cpu_timers[0].l14_timer_limit;
 172 }
 173 
 174 static void sun4m_load_profile_irq(unsigned int limit)
     /* [previous][next][first][last][top][bottom][index][help] */
 175 {
 176         sun4m_timers->cpu_timers[0].l14_timer_limit = limit;
 177 }
 178 
 179 static void sun4m_lvl14_handler(int irq, void *dev_id, struct pt_regs * regs)
     /* [previous][next][first][last][top][bottom][index][help] */
 180 {
 181         volatile unsigned int clear;
 182     
 183         printk("CPU[%d]: TOOK A LEVEL14!\n", smp_processor_id());
 184         /* we do nothing with this at present
 185          * this is purely to prevent OBP getting its mucky paws
 186          * in linux.
 187          */
 188         clear = sun4m_timers->cpu_timers[0].l14_timer_limit; /* clear interrupt */
 189     
 190         /* reload with value, this allows on the fly retuning of the level14
 191          * timer
 192          */
 193         sun4m_timers->cpu_timers[0].l14_timer_limit = lvl14_resolution;
 194 }
 195 
 196 static void sun4m_init_timers(void (*counter_fn)(int, void *, struct pt_regs *))
     /* [previous][next][first][last][top][bottom][index][help] */
 197 {
 198         int reg_count, irq, cpu;
 199         struct linux_prom_registers cnt_regs[PROMREG_MAX];
 200         int obio_node, cnt_node;
 201 
 202         cnt_node = 0;
 203         if((obio_node =
 204             prom_searchsiblings (prom_getchild(prom_root_node), "obio")) == 0 ||
 205            (obio_node = prom_getchild (obio_node)) == 0 ||
 206            (cnt_node = prom_searchsiblings (obio_node, "counter")) == 0) {
 207                 prom_printf("Cannot find /obio/counter node\n");
 208                 prom_halt();
 209         }
 210         reg_count = prom_getproperty(cnt_node, "reg",
 211                                      (void *) cnt_regs, sizeof(cnt_regs));
 212         reg_count = (reg_count/sizeof(struct linux_prom_registers));
 213     
 214         /* Apply the obio ranges to the timer registers. */
 215         prom_apply_obio_ranges(cnt_regs, reg_count);
 216     
 217         cnt_regs[4].phys_addr = cnt_regs[reg_count-1].phys_addr;
 218         cnt_regs[4].reg_size = cnt_regs[reg_count-1].reg_size;
 219         cnt_regs[4].which_io = cnt_regs[reg_count-1].which_io;
 220         for(obio_node = 1; obio_node < 4; obio_node++) {
 221                 cnt_regs[obio_node].phys_addr =
 222                         cnt_regs[obio_node-1].phys_addr + PAGE_SIZE;
 223                 cnt_regs[obio_node].reg_size = cnt_regs[obio_node-1].reg_size;
 224                 cnt_regs[obio_node].which_io = cnt_regs[obio_node-1].which_io;
 225         }
 226     
 227         /* Map the per-cpu Counter registers. */
 228         sun4m_timers = sparc_alloc_io(cnt_regs[0].phys_addr, 0,
 229                                       PAGE_SIZE*NCPUS, "counters_percpu",
 230                                       cnt_regs[0].which_io, 0x0);
 231     
 232         /* Map the system Counter register. */
 233         sparc_alloc_io(cnt_regs[4].phys_addr, 0,
 234                        cnt_regs[4].reg_size,
 235                        "counters_system",
 236                        cnt_regs[4].which_io, 0x0);
 237     
 238         sun4m_timers->l10_timer_limit =  (((1000000/HZ) + 1) << 10);
 239 
 240         irq = request_irq(TIMER_IRQ,
 241                           counter_fn,
 242                           (SA_INTERRUPT | SA_STATIC_ALLOC),
 243                           "timer", NULL);
 244         if (irq) {
 245                 prom_printf("time_init: unable to attach IRQ%d\n",TIMER_IRQ);
 246                 prom_halt();
 247         }
 248     
 249         /* Can't cope with multiple CPUS yet so no level14 tick events */
 250 #if 0
 251         if (linux_num_cpus > 1)
 252                 claim_ticker14(NULL, PROFILE_IRQ, 0);
 253         else
 254                 claim_ticker14(sun4m_lvl14_handler, PROFILE_IRQ, lvl14_resolution);
 255 #endif
 256         if(linux_num_cpus > 1) {
 257                 for(cpu = 0; cpu < 4; cpu++)
 258                         sun4m_timers->cpu_timers[cpu].l14_timer_limit = 0;
 259                 sun4m_interrupts->set = SUN4M_INT_E14;
 260         } else {
 261                 sun4m_timers->cpu_timers[0].l14_timer_limit = 0;
 262         }
 263 }
 264 
 265 void sun4m_init_IRQ(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 266 {
 267         int ie_node,i;
 268         struct linux_prom_registers int_regs[PROMREG_MAX];
 269         int num_regs;
 270     
 271         cli();
 272         if((ie_node = prom_searchsiblings(prom_getchild(prom_root_node), "obio")) == 0 ||
 273            (ie_node = prom_getchild (ie_node)) == 0 ||
 274            (ie_node = prom_searchsiblings (ie_node, "interrupt")) == 0) {
 275                 prom_printf("Cannot find /obio/interrupt node\n");
 276                 prom_halt();
 277         }
 278         num_regs = prom_getproperty(ie_node, "reg", (char *) int_regs,
 279                                     sizeof(int_regs));
 280         num_regs = (num_regs/sizeof(struct linux_prom_registers));
 281     
 282         /* Apply the obio ranges to these registers. */
 283         prom_apply_obio_ranges(int_regs, num_regs);
 284     
 285         int_regs[4].phys_addr = int_regs[num_regs-1].phys_addr;
 286         int_regs[4].reg_size = int_regs[num_regs-1].reg_size;
 287         int_regs[4].which_io = int_regs[num_regs-1].which_io;
 288         for(ie_node = 1; ie_node < 4; ie_node++) {
 289                 int_regs[ie_node].phys_addr = int_regs[ie_node-1].phys_addr + PAGE_SIZE;
 290                 int_regs[ie_node].reg_size = int_regs[ie_node-1].reg_size;
 291                 int_regs[ie_node].which_io = int_regs[ie_node-1].which_io;
 292         }
 293 
 294         /* Map the interrupt registers for all possible cpus. */
 295         sun4m_interrupts = sparc_alloc_io(int_regs[0].phys_addr, 0,
 296                                           PAGE_SIZE*NCPUS, "interrupts_percpu",
 297                                           int_regs[0].which_io, 0x0);
 298     
 299         /* Map the system interrupt control registers. */
 300         sparc_alloc_io(int_regs[4].phys_addr, 0,
 301                        int_regs[4].reg_size, "interrupts_system",
 302                        int_regs[4].which_io, 0x0);
 303     
 304         sun4m_interrupts->set = ~SUN4M_INT_MASKALL;
 305         for (i=0; i<linux_num_cpus; i++)
 306                 sun4m_interrupts->cpu_intregs[i].clear = ~0x17fff;
 307     
 308         if (linux_num_cpus > 1) {
 309                 /* system wide interrupts go to cpu 0, this should always
 310                  * be safe because it is guaranteed to be fitted or OBP doesn't
 311                  * come up
 312                  *
 313                  * Not sure, but writing here on SLAVIO systems may puke
 314                  * so I don't do it unless there is more than 1 cpu.
 315                  */
 316 #if 0
 317                 printk("Warning:"
 318                        "sun4m multiple CPU interrupt code requires work\n");
 319 #endif
 320                 irq_rcvreg = &sun4m_interrupts->undirected_target;
 321                 sun4m_interrupts->undirected_target = 0;
 322         }
 323         enable_irq = sun4m_enable_irq;
 324         disable_irq = sun4m_disable_irq;
 325         clear_clock_irq = sun4m_clear_clock_irq;
 326         clear_profile_irq = sun4m_clear_profile_irq;
 327         load_profile_irq = sun4m_load_profile_irq;
 328         init_timers = sun4m_init_timers;
 329 #ifdef __SMP__
 330         set_cpu_int = sun4m_send_ipi;
 331         clear_cpu_int = sun4m_clear_ipi;
 332         set_irq_udt = sun4m_set_udt;
 333 #endif
 334         sti();
 335 }

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