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@yahoo.com) 9 * Copyright (C) 1996 Dave Redman (djhr@tadpole.co.uk) 10 */ 11 12 #include <linux/errno.h> 13 #include <linux/linkage.h> 14 #include <linux/kernel_stat.h> 15 #include <linux/signal.h> 16 #include <linux/sched.h> 17 #include <linux/ptrace.h> 18 #include <linux/smp.h> 19 #include <linux/interrupt.h> 20 #include <linux/slab.h> 21 #include <linux/init.h> 22 #include <linux/ioport.h> 23 24 #include <asm/ptrace.h> 25 #include <asm/processor.h> 26 #include <asm/system.h> 27 #include <asm/psr.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/pgalloc.h> 34 #include <asm/pgtable.h> 35 #include <asm/smp.h> 36 #include <asm/irq.h> 37 #include <asm/io.h> 38 #include <asm/sbus.h> 39 #include <asm/cacheflush.h> 40 41 static unsigned long dummy; 42 43 struct sun4m_intregs *sun4m_interrupts; 44 unsigned long *irq_rcvreg = &dummy; 45 46 /* These tables only apply for interrupts greater than 15.. 47 * 48 * any intr value below 0x10 is considered to be a soft-int 49 * this may be useful or it may not.. but that's how I've done it. 50 * and it won't clash with what OBP is telling us about devices. 51 * 52 * take an encoded intr value and lookup if it's valid 53 * then get the mask bits that match from irq_mask 54 * 55 * P3: Translation from irq 0x0d to mask 0x2000 is for MrCoffee. 56 */ 57 static unsigned char irq_xlate[32] = { 58 /* 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f */ 59 0, 0, 0, 0, 1, 0, 2, 0, 3, 0, 4, 5, 6, 14, 0, 7, 60 0, 0, 8, 9, 0, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 0 61 }; 62 63 static unsigned long irq_mask[] = { 64 0, /* illegal index */ 65 SUN4M_INT_SCSI, /* 1 irq 4 */ 66 SUN4M_INT_ETHERNET, /* 2 irq 6 */ 67 SUN4M_INT_VIDEO, /* 3 irq 8 */ 68 SUN4M_INT_REALTIME, /* 4 irq 10 */ 69 SUN4M_INT_FLOPPY, /* 5 irq 11 */ 70 (SUN4M_INT_SERIAL | SUN4M_INT_KBDMS), /* 6 irq 12 */ 71 SUN4M_INT_MODULE_ERR, /* 7 irq 15 */ 72 SUN4M_INT_SBUS(0), /* 8 irq 2 */ 73 SUN4M_INT_SBUS(1), /* 9 irq 3 */ 74 SUN4M_INT_SBUS(2), /* 10 irq 5 */ 75 SUN4M_INT_SBUS(3), /* 11 irq 7 */ 76 SUN4M_INT_SBUS(4), /* 12 irq 9 */ 77 SUN4M_INT_SBUS(5), /* 13 irq 11 */ 78 SUN4M_INT_SBUS(6) /* 14 irq 13 */ 79 }; 80 81 static int sun4m_pil_map[] = { 0, 2, 3, 5, 7, 9, 11, 13 }; 82 83 unsigned int sun4m_sbint_to_irq(struct sbus_dev *sdev, unsigned int sbint) 84 { 85 if (sbint >= sizeof(sun4m_pil_map)) { 86 printk(KERN_ERR "%s: bogus SBINT %d\n", sdev->prom_name, sbint); 87 BUG(); 88 } 89 return sun4m_pil_map[sbint] | 0x30; 90 } 91 92 inline unsigned long sun4m_get_irqmask(unsigned int irq) 93 { 94 unsigned long mask; 95 96 if (irq > 0x20) { 97 /* OBIO/SBUS interrupts */ 98 irq &= 0x1f; 99 mask = irq_mask[irq_xlate[irq]]; 100 if (!mask) 101 printk("sun4m_get_irqmask: IRQ%d has no valid mask!\n",irq); 102 } else { 103 /* Soft Interrupts will come here. 104 * Currently there is no way to trigger them but I'm sure 105 * something could be cooked up. 106 */ 107 irq &= 0xf; 108 mask = SUN4M_SOFT_INT(irq); 109 } 110 return mask; 111 } 112 113 static void sun4m_disable_irq(unsigned int irq_nr) 114 { 115 unsigned long mask, flags; 116 int cpu = smp_processor_id(); 117 118 mask = sun4m_get_irqmask(irq_nr); 119 local_irq_save(flags); 120 if (irq_nr > 15) 121 sun4m_interrupts->set = mask; 122 else 123 sun4m_interrupts->cpu_intregs[cpu].set = mask; 124 local_irq_restore(flags); 125 } 126 127 static void sun4m_enable_irq(unsigned int irq_nr) 128 { 129 unsigned long mask, flags; 130 int cpu = smp_processor_id(); 131 132 /* Dreadful floppy hack. When we use 0x2b instead of 133 * 0x0b the system blows (it starts to whistle!). 134 * So we continue to use 0x0b. Fixme ASAP. --P3 135 */ 136 if (irq_nr != 0x0b) { 137 mask = sun4m_get_irqmask(irq_nr); 138 local_irq_save(flags); 139 if (irq_nr > 15) 140 sun4m_interrupts->clear = mask; 141 else 142 sun4m_interrupts->cpu_intregs[cpu].clear = mask; 143 local_irq_restore(flags); 144 } else { 145 local_irq_save(flags); 146 sun4m_interrupts->clear = SUN4M_INT_FLOPPY; 147 local_irq_restore(flags); 148 } 149 } 150 151 static unsigned long cpu_pil_to_imask[16] = { 152 /*0*/ 0x00000000, 153 /*1*/ 0x00000000, 154 /*2*/ SUN4M_INT_SBUS(0) | SUN4M_INT_VME(0), 155 /*3*/ SUN4M_INT_SBUS(1) | SUN4M_INT_VME(1), 156 /*4*/ SUN4M_INT_SCSI, 157 /*5*/ SUN4M_INT_SBUS(2) | SUN4M_INT_VME(2), 158 /*6*/ SUN4M_INT_ETHERNET, 159 /*7*/ SUN4M_INT_SBUS(3) | SUN4M_INT_VME(3), 160 /*8*/ SUN4M_INT_VIDEO, 161 /*9*/ SUN4M_INT_SBUS(4) | SUN4M_INT_VME(4) | SUN4M_INT_MODULE_ERR, 162 /*10*/ SUN4M_INT_REALTIME, 163 /*11*/ SUN4M_INT_SBUS(5) | SUN4M_INT_VME(5) | SUN4M_INT_FLOPPY, 164 /*12*/ SUN4M_INT_SERIAL | SUN4M_INT_KBDMS, 165 /*13*/ SUN4M_INT_AUDIO, 166 /*14*/ SUN4M_INT_E14, 167 /*15*/ 0x00000000 168 }; 169 170 /* We assume the caller has disabled local interrupts when these are called, 171 * or else very bizarre behavior will result. 172 */ 173 static void sun4m_disable_pil_irq(unsigned int pil) 174 { 175 sun4m_interrupts->set = cpu_pil_to_imask[pil]; 176 } 177 178 static void sun4m_enable_pil_irq(unsigned int pil) 179 { 180 sun4m_interrupts->clear = cpu_pil_to_imask[pil]; 181 } 182 183 #ifdef CONFIG_SMP 184 static void sun4m_send_ipi(int cpu, int level) 185 { 186 unsigned long mask; 187 188 mask = sun4m_get_irqmask(level); 189 sun4m_interrupts->cpu_intregs[cpu].set = mask; 190 } 191 192 static void sun4m_clear_ipi(int cpu, int level) 193 { 194 unsigned long mask; 195 196 mask = sun4m_get_irqmask(level); 197 sun4m_interrupts->cpu_intregs[cpu].clear = mask; 198 } 199 200 static void sun4m_set_udt(int cpu) 201 { 202 sun4m_interrupts->undirected_target = cpu; 203 } 204 #endif 205 206 #define OBIO_INTR 0x20 207 #define TIMER_IRQ (OBIO_INTR | 10) 208 #define PROFILE_IRQ (OBIO_INTR | 14) 209 210 struct sun4m_timer_regs *sun4m_timers; 211 unsigned int lvl14_resolution = (((1000000/HZ) + 1) << 10); 212 213 static void sun4m_clear_clock_irq(void) 214 { 215 volatile unsigned int clear_intr; 216 clear_intr = sun4m_timers->l10_timer_limit; 217 } 218 219 static void sun4m_clear_profile_irq(int cpu) 220 { 221 volatile unsigned int clear; 222 223 clear = sun4m_timers->cpu_timers[cpu].l14_timer_limit; 224 } 225 226 static void sun4m_load_profile_irq(int cpu, unsigned int limit) 227 { 228 sun4m_timers->cpu_timers[cpu].l14_timer_limit = limit; 229 } 230 231 static void __init sun4m_init_timers(irq_handler_t counter_fn) 232 { 233 int reg_count, irq, cpu; 234 struct linux_prom_registers cnt_regs[PROMREG_MAX]; 235 int obio_node, cnt_node; 236 struct resource r; 237 238 cnt_node = 0; 239 if((obio_node = 240 prom_searchsiblings (prom_getchild(prom_root_node), "obio")) == 0 || 241 (obio_node = prom_getchild (obio_node)) == 0 || 242 (cnt_node = prom_searchsiblings (obio_node, "counter")) == 0) { 243 prom_printf("Cannot find /obio/counter node\n"); 244 prom_halt(); 245 } 246 reg_count = prom_getproperty(cnt_node, "reg", 247 (void *) cnt_regs, sizeof(cnt_regs)); 248 reg_count = (reg_count/sizeof(struct linux_prom_registers)); 249 250 /* Apply the obio ranges to the timer registers. */ 251 prom_apply_obio_ranges(cnt_regs, reg_count); 252 253 cnt_regs[4].phys_addr = cnt_regs[reg_count-1].phys_addr; 254 cnt_regs[4].reg_size = cnt_regs[reg_count-1].reg_size; 255 cnt_regs[4].which_io = cnt_regs[reg_count-1].which_io; 256 for(obio_node = 1; obio_node < 4; obio_node++) { 257 cnt_regs[obio_node].phys_addr = 258 cnt_regs[obio_node-1].phys_addr + PAGE_SIZE; 259 cnt_regs[obio_node].reg_size = cnt_regs[obio_node-1].reg_size; 260 cnt_regs[obio_node].which_io = cnt_regs[obio_node-1].which_io; 261 } 262 263 memset((char*)&r, 0, sizeof(struct resource)); 264 /* Map the per-cpu Counter registers. */ 265 r.flags = cnt_regs[0].which_io; 266 r.start = cnt_regs[0].phys_addr; 267 sun4m_timers = (struct sun4m_timer_regs *) sbus_ioremap(&r, 0, 268 PAGE_SIZE*SUN4M_NCPUS, "sun4m_cpu_cnt"); 269 /* Map the system Counter register. */ 270 /* XXX Here we expect consequent calls to yeld adjusent maps. */ 271 r.flags = cnt_regs[4].which_io; 272 r.start = cnt_regs[4].phys_addr; 273 sbus_ioremap(&r, 0, cnt_regs[4].reg_size, "sun4m_sys_cnt"); 274 275 sun4m_timers->l10_timer_limit = (((1000000/HZ) + 1) << 10); 276 master_l10_counter = &sun4m_timers->l10_cur_count; 277 master_l10_limit = &sun4m_timers->l10_timer_limit; 278 279 irq = request_irq(TIMER_IRQ, 280 counter_fn, 281 (IRQF_DISABLED | SA_STATIC_ALLOC), 282 "timer", NULL); 283 if (irq) { 284 prom_printf("time_init: unable to attach IRQ%d\n",TIMER_IRQ); 285 prom_halt(); 286 } 287 288 if (!cpu_find_by_instance(1, NULL, NULL)) { 289 for(cpu = 0; cpu < 4; cpu++) 290 sun4m_timers->cpu_timers[cpu].l14_timer_limit = 0; 291 sun4m_interrupts->set = SUN4M_INT_E14; 292 } else { 293 sun4m_timers->cpu_timers[0].l14_timer_limit = 0; 294 } 295 #ifdef CONFIG_SMP 296 { 297 unsigned long flags; 298 extern unsigned long lvl14_save[4]; 299 struct tt_entry *trap_table = &sparc_ttable[SP_TRAP_IRQ1 + (14 - 1)]; 300 301 /* For SMP we use the level 14 ticker, however the bootup code 302 * has copied the firmware's level 14 vector into the boot cpu's 303 * trap table, we must fix this now or we get squashed. 304 */ 305 local_irq_save(flags); 306 trap_table->inst_one = lvl14_save[0]; 307 trap_table->inst_two = lvl14_save[1]; 308 trap_table->inst_three = lvl14_save[2]; 309 trap_table->inst_four = lvl14_save[3]; 310 local_flush_cache_all(); 311 local_irq_restore(flags); 312 } 313 #endif 314 } 315 316 void __init sun4m_init_IRQ(void) 317 { 318 int ie_node,i; 319 struct linux_prom_registers int_regs[PROMREG_MAX]; 320 int num_regs; 321 struct resource r; 322 int mid; 323 324 local_irq_disable(); 325 if((ie_node = prom_searchsiblings(prom_getchild(prom_root_node), "obio")) == 0 || 326 (ie_node = prom_getchild (ie_node)) == 0 || 327 (ie_node = prom_searchsiblings (ie_node, "interrupt")) == 0) { 328 prom_printf("Cannot find /obio/interrupt node\n"); 329 prom_halt(); 330 } 331 num_regs = prom_getproperty(ie_node, "reg", (char *) int_regs, 332 sizeof(int_regs)); 333 num_regs = (num_regs/sizeof(struct linux_prom_registers)); 334 335 /* Apply the obio ranges to these registers. */ 336 prom_apply_obio_ranges(int_regs, num_regs); 337 338 int_regs[4].phys_addr = int_regs[num_regs-1].phys_addr; 339 int_regs[4].reg_size = int_regs[num_regs-1].reg_size; 340 int_regs[4].which_io = int_regs[num_regs-1].which_io; 341 for(ie_node = 1; ie_node < 4; ie_node++) { 342 int_regs[ie_node].phys_addr = int_regs[ie_node-1].phys_addr + PAGE_SIZE; 343 int_regs[ie_node].reg_size = int_regs[ie_node-1].reg_size; 344 int_regs[ie_node].which_io = int_regs[ie_node-1].which_io; 345 } 346 347 memset((char *)&r, 0, sizeof(struct resource)); 348 /* Map the interrupt registers for all possible cpus. */ 349 r.flags = int_regs[0].which_io; 350 r.start = int_regs[0].phys_addr; 351 sun4m_interrupts = (struct sun4m_intregs *) sbus_ioremap(&r, 0, 352 PAGE_SIZE*SUN4M_NCPUS, "interrupts_percpu"); 353 354 /* Map the system interrupt control registers. */ 355 r.flags = int_regs[4].which_io; 356 r.start = int_regs[4].phys_addr; 357 sbus_ioremap(&r, 0, int_regs[4].reg_size, "interrupts_system"); 358 359 sun4m_interrupts->set = ~SUN4M_INT_MASKALL; 360 for (i = 0; !cpu_find_by_instance(i, NULL, &mid); i++) 361 sun4m_interrupts->cpu_intregs[mid].clear = ~0x17fff; 362 363 if (!cpu_find_by_instance(1, NULL, NULL)) { 364 /* system wide interrupts go to cpu 0, this should always 365 * be safe because it is guaranteed to be fitted or OBP doesn't 366 * come up 367 * 368 * Not sure, but writing here on SLAVIO systems may puke 369 * so I don't do it unless there is more than 1 cpu. 370 */ 371 irq_rcvreg = (unsigned long *) 372 &sun4m_interrupts->undirected_target; 373 sun4m_interrupts->undirected_target = 0; 374 } 375 BTFIXUPSET_CALL(sbint_to_irq, sun4m_sbint_to_irq, BTFIXUPCALL_NORM); 376 BTFIXUPSET_CALL(enable_irq, sun4m_enable_irq, BTFIXUPCALL_NORM); 377 BTFIXUPSET_CALL(disable_irq, sun4m_disable_irq, BTFIXUPCALL_NORM); 378 BTFIXUPSET_CALL(enable_pil_irq, sun4m_enable_pil_irq, BTFIXUPCALL_NORM); 379 BTFIXUPSET_CALL(disable_pil_irq, sun4m_disable_pil_irq, BTFIXUPCALL_NORM); 380 BTFIXUPSET_CALL(clear_clock_irq, sun4m_clear_clock_irq, BTFIXUPCALL_NORM); 381 BTFIXUPSET_CALL(clear_profile_irq, sun4m_clear_profile_irq, BTFIXUPCALL_NORM); 382 BTFIXUPSET_CALL(load_profile_irq, sun4m_load_profile_irq, BTFIXUPCALL_NORM); 383 sparc_init_timers = sun4m_init_timers; 384 #ifdef CONFIG_SMP 385 BTFIXUPSET_CALL(set_cpu_int, sun4m_send_ipi, BTFIXUPCALL_NORM); 386 BTFIXUPSET_CALL(clear_cpu_int, sun4m_clear_ipi, BTFIXUPCALL_NORM); 387 BTFIXUPSET_CALL(set_irq_udt, sun4m_set_udt, BTFIXUPCALL_NORM); 388 #endif 389 /* Cannot enable interrupts until OBP ticker is disabled. */ 390 } 391