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/init.h> 21#include <linux/ioport.h> 22#include <linux/of.h> 23#include <linux/of_device.h> 24 25#include <asm/ptrace.h> 26#include <asm/processor.h> 27#include <asm/system.h> 28#include <asm/psr.h> 29#include <asm/vaddrs.h> 30#include <asm/timer.h> 31#include <asm/openprom.h> 32#include <asm/oplib.h> 33#include <asm/traps.h> 34#include <asm/pgalloc.h> 35#include <asm/pgtable.h> 36#include <asm/smp.h> 37#include <asm/irq.h> 38#include <asm/io.h> 39#include <asm/cacheflush.h> 40 41#include "irq.h" 42 43struct sun4m_irq_percpu { 44 u32 pending; 45 u32 clear; 46 u32 set; 47}; 48 49struct sun4m_irq_global { 50 u32 pending; 51 u32 mask; 52 u32 mask_clear; 53 u32 mask_set; 54 u32 interrupt_target; 55}; 56 57/* Code in entry.S needs to get at these register mappings. */ 58struct sun4m_irq_percpu __iomem *sun4m_irq_percpu[SUN4M_NCPUS]; 59struct sun4m_irq_global __iomem *sun4m_irq_global; 60 61/* Dave Redman (djhr@tadpole.co.uk) 62 * The sun4m interrupt registers. 63 */ 64#define SUN4M_INT_ENABLE 0x80000000 65#define SUN4M_INT_E14 0x00000080 66#define SUN4M_INT_E10 0x00080000 67 68#define SUN4M_HARD_INT(x) (0x000000001 << (x)) 69#define SUN4M_SOFT_INT(x) (0x000010000 << (x)) 70 71#define SUN4M_INT_MASKALL 0x80000000 /* mask all interrupts */ 72#define SUN4M_INT_MODULE_ERR 0x40000000 /* module error */ 73#define SUN4M_INT_M2S_WRITE_ERR 0x20000000 /* write buffer error */ 74#define SUN4M_INT_ECC_ERR 0x10000000 /* ecc memory error */ 75#define SUN4M_INT_VME_ERR 0x08000000 /* vme async error */ 76#define SUN4M_INT_FLOPPY 0x00400000 /* floppy disk */ 77#define SUN4M_INT_MODULE 0x00200000 /* module interrupt */ 78#define SUN4M_INT_VIDEO 0x00100000 /* onboard video */ 79#define SUN4M_INT_REALTIME 0x00080000 /* system timer */ 80#define SUN4M_INT_SCSI 0x00040000 /* onboard scsi */ 81#define SUN4M_INT_AUDIO 0x00020000 /* audio/isdn */ 82#define SUN4M_INT_ETHERNET 0x00010000 /* onboard ethernet */ 83#define SUN4M_INT_SERIAL 0x00008000 /* serial ports */ 84#define SUN4M_INT_KBDMS 0x00004000 /* keyboard/mouse */ 85#define SUN4M_INT_SBUSBITS 0x00003F80 /* sbus int bits */ 86#define SUN4M_INT_VMEBITS 0x0000007F /* vme int bits */ 87 88#define SUN4M_INT_ERROR (SUN4M_INT_MODULE_ERR | \ 89 SUN4M_INT_M2S_WRITE_ERR | \ 90 SUN4M_INT_ECC_ERR | \ 91 SUN4M_INT_VME_ERR) 92 93#define SUN4M_INT_SBUS(x) (1 << (x+7)) 94#define SUN4M_INT_VME(x) (1 << (x)) 95 96/* Interrupt levels used by OBP */ 97#define OBP_INT_LEVEL_SOFT 0x10 98#define OBP_INT_LEVEL_ONBOARD 0x20 99#define OBP_INT_LEVEL_SBUS 0x30 100#define OBP_INT_LEVEL_VME 0x40 101 102 103static unsigned long irq_mask[0x50] = { 104 /* SMP */ 105 0, SUN4M_SOFT_INT(1), 106 SUN4M_SOFT_INT(2), SUN4M_SOFT_INT(3), 107 SUN4M_SOFT_INT(4), SUN4M_SOFT_INT(5), 108 SUN4M_SOFT_INT(6), SUN4M_SOFT_INT(7), 109 SUN4M_SOFT_INT(8), SUN4M_SOFT_INT(9), 110 SUN4M_SOFT_INT(10), SUN4M_SOFT_INT(11), 111 SUN4M_SOFT_INT(12), SUN4M_SOFT_INT(13), 112 SUN4M_SOFT_INT(14), SUN4M_SOFT_INT(15), 113 /* soft */ 114 0, SUN4M_SOFT_INT(1), 115 SUN4M_SOFT_INT(2), SUN4M_SOFT_INT(3), 116 SUN4M_SOFT_INT(4), SUN4M_SOFT_INT(5), 117 SUN4M_SOFT_INT(6), SUN4M_SOFT_INT(7), 118 SUN4M_SOFT_INT(8), SUN4M_SOFT_INT(9), 119 SUN4M_SOFT_INT(10), SUN4M_SOFT_INT(11), 120 SUN4M_SOFT_INT(12), SUN4M_SOFT_INT(13), 121 SUN4M_SOFT_INT(14), SUN4M_SOFT_INT(15), 122 /* onboard */ 123 0, 0, 0, 0, 124 SUN4M_INT_SCSI, 0, SUN4M_INT_ETHERNET, 0, 125 SUN4M_INT_VIDEO, SUN4M_INT_MODULE, 126 SUN4M_INT_REALTIME, SUN4M_INT_FLOPPY, 127 (SUN4M_INT_SERIAL | SUN4M_INT_KBDMS), 128 SUN4M_INT_AUDIO, 0, SUN4M_INT_MODULE_ERR, 129 /* sbus */ 130 0, 0, SUN4M_INT_SBUS(0), SUN4M_INT_SBUS(1), 131 0, SUN4M_INT_SBUS(2), 0, SUN4M_INT_SBUS(3), 132 0, SUN4M_INT_SBUS(4), 0, SUN4M_INT_SBUS(5), 133 0, SUN4M_INT_SBUS(6), 0, 0, 134 /* vme */ 135 0, 0, SUN4M_INT_VME(0), SUN4M_INT_VME(1), 136 0, SUN4M_INT_VME(2), 0, SUN4M_INT_VME(3), 137 0, SUN4M_INT_VME(4), 0, SUN4M_INT_VME(5), 138 0, SUN4M_INT_VME(6), 0, 0 139}; 140 141static unsigned long sun4m_get_irqmask(unsigned int irq) 142{ 143 unsigned long mask; 144 145 if (irq < 0x50) 146 mask = irq_mask[irq]; 147 else 148 mask = 0; 149 150 if (!mask) 151 printk(KERN_ERR "sun4m_get_irqmask: IRQ%d has no valid mask!\n", 152 irq); 153 154 return mask; 155} 156 157static void sun4m_disable_irq(unsigned int irq_nr) 158{ 159 unsigned long mask, flags; 160 int cpu = smp_processor_id(); 161 162 mask = sun4m_get_irqmask(irq_nr); 163 local_irq_save(flags); 164 if (irq_nr > 15) 165 sbus_writel(mask, &sun4m_irq_global->mask_set); 166 else 167 sbus_writel(mask, &sun4m_irq_percpu[cpu]->set); 168 local_irq_restore(flags); 169} 170 171static void sun4m_enable_irq(unsigned int irq_nr) 172{ 173 unsigned long mask, flags; 174 int cpu = smp_processor_id(); 175 176 if (irq_nr != 0x0b) { 177 mask = sun4m_get_irqmask(irq_nr); 178 local_irq_save(flags); 179 if (irq_nr > 15) 180 sbus_writel(mask, &sun4m_irq_global->mask_clear); 181 else 182 sbus_writel(mask, &sun4m_irq_percpu[cpu]->clear); 183 local_irq_restore(flags); 184 } else { 185 local_irq_save(flags); 186 sbus_writel(SUN4M_INT_FLOPPY, &sun4m_irq_global->mask_clear); 187 local_irq_restore(flags); 188 } 189} 190 191static unsigned long cpu_pil_to_imask[16] = { 192/*0*/ 0x00000000, 193/*1*/ 0x00000000, 194/*2*/ SUN4M_INT_SBUS(0) | SUN4M_INT_VME(0), 195/*3*/ SUN4M_INT_SBUS(1) | SUN4M_INT_VME(1), 196/*4*/ SUN4M_INT_SCSI, 197/*5*/ SUN4M_INT_SBUS(2) | SUN4M_INT_VME(2), 198/*6*/ SUN4M_INT_ETHERNET, 199/*7*/ SUN4M_INT_SBUS(3) | SUN4M_INT_VME(3), 200/*8*/ SUN4M_INT_VIDEO, 201/*9*/ SUN4M_INT_SBUS(4) | SUN4M_INT_VME(4) | SUN4M_INT_MODULE_ERR, 202/*10*/ SUN4M_INT_REALTIME, 203/*11*/ SUN4M_INT_SBUS(5) | SUN4M_INT_VME(5) | SUN4M_INT_FLOPPY, 204/*12*/ SUN4M_INT_SERIAL | SUN4M_INT_KBDMS, 205/*13*/ SUN4M_INT_SBUS(6) | SUN4M_INT_VME(6) | SUN4M_INT_AUDIO, 206/*14*/ SUN4M_INT_E14, 207/*15*/ SUN4M_INT_ERROR 208}; 209 210/* We assume the caller has disabled local interrupts when these are called, 211 * or else very bizarre behavior will result. 212 */ 213static void sun4m_disable_pil_irq(unsigned int pil) 214{ 215 sbus_writel(cpu_pil_to_imask[pil], &sun4m_irq_global->mask_set); 216} 217 218static void sun4m_enable_pil_irq(unsigned int pil) 219{ 220 sbus_writel(cpu_pil_to_imask[pil], &sun4m_irq_global->mask_clear); 221} 222 223#ifdef CONFIG_SMP 224static void sun4m_send_ipi(int cpu, int level) 225{ 226 unsigned long mask = sun4m_get_irqmask(level); 227 sbus_writel(mask, &sun4m_irq_percpu[cpu]->set); 228} 229 230static void sun4m_clear_ipi(int cpu, int level) 231{ 232 unsigned long mask = sun4m_get_irqmask(level); 233 sbus_writel(mask, &sun4m_irq_percpu[cpu]->clear); 234} 235 236static void sun4m_set_udt(int cpu) 237{ 238 sbus_writel(cpu, &sun4m_irq_global->interrupt_target); 239} 240#endif 241 242struct sun4m_timer_percpu { 243 u32 l14_limit; 244 u32 l14_count; 245 u32 l14_limit_noclear; 246 u32 user_timer_start_stop; 247}; 248 249static struct sun4m_timer_percpu __iomem *timers_percpu[SUN4M_NCPUS]; 250 251struct sun4m_timer_global { 252 u32 l10_limit; 253 u32 l10_count; 254 u32 l10_limit_noclear; 255 u32 reserved; 256 u32 timer_config; 257}; 258 259static struct sun4m_timer_global __iomem *timers_global; 260 261#define TIMER_IRQ (OBP_INT_LEVEL_ONBOARD | 10) 262 263unsigned int lvl14_resolution = (((1000000/HZ) + 1) << 10); 264 265static void sun4m_clear_clock_irq(void) 266{ 267 sbus_readl(&timers_global->l10_limit); 268} 269 270void sun4m_nmi(struct pt_regs *regs) 271{ 272 unsigned long afsr, afar, si; 273 274 printk(KERN_ERR "Aieee: sun4m NMI received!\n"); 275 __asm__ __volatile__("mov 0x500, %%g1\n\t" 276 "lda [%%g1] 0x4, %0\n\t" 277 "mov 0x600, %%g1\n\t" 278 "lda [%%g1] 0x4, %1\n\t" : 279 "=r" (afsr), "=r" (afar)); 280 printk(KERN_ERR "afsr=%08lx afar=%08lx\n", afsr, afar); 281 si = sbus_readl(&sun4m_irq_global->pending); 282 printk(KERN_ERR "si=%08lx\n", si); 283 if (si & SUN4M_INT_MODULE_ERR) 284 printk(KERN_ERR "Module async error\n"); 285 if (si & SUN4M_INT_M2S_WRITE_ERR) 286 printk(KERN_ERR "MBus/SBus async error\n"); 287 if (si & SUN4M_INT_ECC_ERR) 288 printk(KERN_ERR "ECC memory error\n"); 289 if (si & SUN4M_INT_VME_ERR) 290 printk(KERN_ERR "VME async error\n"); 291 printk(KERN_ERR "you lose buddy boy...\n"); 292 show_regs(regs); 293 prom_halt(); 294} 295 296/* Exported for sun4m_smp.c */ 297void sun4m_clear_profile_irq(int cpu) 298{ 299 sbus_readl(&timers_percpu[cpu]->l14_limit); 300} 301 302static void sun4m_load_profile_irq(int cpu, unsigned int limit) 303{ 304 sbus_writel(limit, &timers_percpu[cpu]->l14_limit); 305} 306 307static void __init sun4m_init_timers(irq_handler_t counter_fn) 308{ 309 struct device_node *dp = of_find_node_by_name(NULL, "counter"); 310 int i, err, len, num_cpu_timers; 311 const u32 *addr; 312 313 if (!dp) { 314 printk(KERN_ERR "sun4m_init_timers: No 'counter' node.\n"); 315 return; 316 } 317 318 addr = of_get_property(dp, "address", &len); 319 of_node_put(dp); 320 if (!addr) { 321 printk(KERN_ERR "sun4m_init_timers: No 'address' prop.\n"); 322 return; 323 } 324 325 num_cpu_timers = (len / sizeof(u32)) - 1; 326 for (i = 0; i < num_cpu_timers; i++) { 327 timers_percpu[i] = (void __iomem *) 328 (unsigned long) addr[i]; 329 } 330 timers_global = (void __iomem *) 331 (unsigned long) addr[num_cpu_timers]; 332 333 sbus_writel((((1000000/HZ) + 1) << 10), &timers_global->l10_limit); 334 335 master_l10_counter = &timers_global->l10_count; 336 337 err = request_irq(TIMER_IRQ, counter_fn, 338 (IRQF_DISABLED | SA_STATIC_ALLOC), "timer", NULL); 339 if (err) { 340 printk(KERN_ERR "sun4m_init_timers: Register IRQ error %d.\n", 341 err); 342 return; 343 } 344 345 for (i = 0; i < num_cpu_timers; i++) 346 sbus_writel(0, &timers_percpu[i]->l14_limit); 347 if (num_cpu_timers == 4) 348 sbus_writel(SUN4M_INT_E14, &sun4m_irq_global->mask_set); 349 350#ifdef CONFIG_SMP 351 { 352 unsigned long flags; 353 extern unsigned long lvl14_save[4]; 354 struct tt_entry *trap_table = &sparc_ttable[SP_TRAP_IRQ1 + (14 - 1)]; 355 356 /* For SMP we use the level 14 ticker, however the bootup code 357 * has copied the firmware's level 14 vector into the boot cpu's 358 * trap table, we must fix this now or we get squashed. 359 */ 360 local_irq_save(flags); 361 trap_table->inst_one = lvl14_save[0]; 362 trap_table->inst_two = lvl14_save[1]; 363 trap_table->inst_three = lvl14_save[2]; 364 trap_table->inst_four = lvl14_save[3]; 365 local_flush_cache_all(); 366 local_irq_restore(flags); 367 } 368#endif 369} 370 371void __init sun4m_init_IRQ(void) 372{ 373 struct device_node *dp = of_find_node_by_name(NULL, "interrupt"); 374 int len, i, mid, num_cpu_iregs; 375 const u32 *addr; 376 377 if (!dp) { 378 printk(KERN_ERR "sun4m_init_IRQ: No 'interrupt' node.\n"); 379 return; 380 } 381 382 addr = of_get_property(dp, "address", &len); 383 of_node_put(dp); 384 if (!addr) { 385 printk(KERN_ERR "sun4m_init_IRQ: No 'address' prop.\n"); 386 return; 387 } 388 389 num_cpu_iregs = (len / sizeof(u32)) - 1; 390 for (i = 0; i < num_cpu_iregs; i++) { 391 sun4m_irq_percpu[i] = (void __iomem *) 392 (unsigned long) addr[i]; 393 } 394 sun4m_irq_global = (void __iomem *) 395 (unsigned long) addr[num_cpu_iregs]; 396 397 local_irq_disable(); 398 399 sbus_writel(~SUN4M_INT_MASKALL, &sun4m_irq_global->mask_set); 400 for (i = 0; !cpu_find_by_instance(i, NULL, &mid); i++) 401 sbus_writel(~0x17fff, &sun4m_irq_percpu[mid]->clear); 402 403 if (num_cpu_iregs == 4) 404 sbus_writel(0, &sun4m_irq_global->interrupt_target); 405 406 BTFIXUPSET_CALL(enable_irq, sun4m_enable_irq, BTFIXUPCALL_NORM); 407 BTFIXUPSET_CALL(disable_irq, sun4m_disable_irq, BTFIXUPCALL_NORM); 408 BTFIXUPSET_CALL(enable_pil_irq, sun4m_enable_pil_irq, BTFIXUPCALL_NORM); 409 BTFIXUPSET_CALL(disable_pil_irq, sun4m_disable_pil_irq, BTFIXUPCALL_NORM); 410 BTFIXUPSET_CALL(clear_clock_irq, sun4m_clear_clock_irq, BTFIXUPCALL_NORM); 411 BTFIXUPSET_CALL(load_profile_irq, sun4m_load_profile_irq, BTFIXUPCALL_NORM); 412 sparc_init_timers = sun4m_init_timers; 413#ifdef CONFIG_SMP 414 BTFIXUPSET_CALL(set_cpu_int, sun4m_send_ipi, BTFIXUPCALL_NORM); 415 BTFIXUPSET_CALL(clear_cpu_int, sun4m_clear_ipi, BTFIXUPCALL_NORM); 416 BTFIXUPSET_CALL(set_irq_udt, sun4m_set_udt, BTFIXUPCALL_NORM); 417#endif 418 419 /* Cannot enable interrupts until OBP ticker is disabled. */ 420} 421