11da177e4SLinus Torvalds /* sun4m_irq.c 21da177e4SLinus Torvalds * arch/sparc/kernel/sun4m_irq.c: 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * djhr: Hacked out of irq.c into a CPU dependent version. 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) 71da177e4SLinus Torvalds * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx) 81da177e4SLinus Torvalds * Copyright (C) 1995 Pete A. Zaitcev (zaitcev@yahoo.com) 91da177e4SLinus Torvalds * Copyright (C) 1996 Dave Redman (djhr@tadpole.co.uk) 101da177e4SLinus Torvalds */ 111da177e4SLinus Torvalds 121da177e4SLinus Torvalds #include <linux/errno.h> 131da177e4SLinus Torvalds #include <linux/linkage.h> 141da177e4SLinus Torvalds #include <linux/kernel_stat.h> 151da177e4SLinus Torvalds #include <linux/signal.h> 161da177e4SLinus Torvalds #include <linux/sched.h> 171da177e4SLinus Torvalds #include <linux/ptrace.h> 181da177e4SLinus Torvalds #include <linux/smp.h> 191da177e4SLinus Torvalds #include <linux/interrupt.h> 201da177e4SLinus Torvalds #include <linux/slab.h> 211da177e4SLinus Torvalds #include <linux/init.h> 221da177e4SLinus Torvalds #include <linux/ioport.h> 23454eeb2dSDavid S. Miller #include <linux/of.h> 24454eeb2dSDavid S. Miller #include <linux/of_device.h> 251da177e4SLinus Torvalds 261da177e4SLinus Torvalds #include <asm/ptrace.h> 271da177e4SLinus Torvalds #include <asm/processor.h> 281da177e4SLinus Torvalds #include <asm/system.h> 291da177e4SLinus Torvalds #include <asm/psr.h> 301da177e4SLinus Torvalds #include <asm/vaddrs.h> 311da177e4SLinus Torvalds #include <asm/timer.h> 321da177e4SLinus Torvalds #include <asm/openprom.h> 331da177e4SLinus Torvalds #include <asm/oplib.h> 341da177e4SLinus Torvalds #include <asm/traps.h> 351da177e4SLinus Torvalds #include <asm/pgalloc.h> 361da177e4SLinus Torvalds #include <asm/pgtable.h> 371da177e4SLinus Torvalds #include <asm/smp.h> 381da177e4SLinus Torvalds #include <asm/irq.h> 391da177e4SLinus Torvalds #include <asm/io.h> 401da177e4SLinus Torvalds #include <asm/cacheflush.h> 411da177e4SLinus Torvalds 4232231a66SAl Viro #include "irq.h" 4332231a66SAl Viro 4432231a66SAl Viro /* On the sun4m, just like the timers, we have both per-cpu and master 4532231a66SAl Viro * interrupt registers. 4632231a66SAl Viro */ 4732231a66SAl Viro 4832231a66SAl Viro /* These registers are used for sending/receiving irqs from/to 4932231a66SAl Viro * different cpu's. 5032231a66SAl Viro */ 5132231a66SAl Viro struct sun4m_intreg_percpu { 5232231a66SAl Viro unsigned int tbt; /* Interrupts still pending for this cpu. */ 5332231a66SAl Viro 5432231a66SAl Viro /* These next two registers are WRITE-ONLY and are only 5532231a66SAl Viro * "on bit" sensitive, "off bits" written have NO affect. 5632231a66SAl Viro */ 5732231a66SAl Viro unsigned int clear; /* Clear this cpus irqs here. */ 5832231a66SAl Viro unsigned int set; /* Set this cpus irqs here. */ 5932231a66SAl Viro unsigned char space[PAGE_SIZE - 12]; 6032231a66SAl Viro }; 6132231a66SAl Viro 6232231a66SAl Viro /* 6332231a66SAl Viro * djhr 6432231a66SAl Viro * Actually the clear and set fields in this struct are misleading.. 6532231a66SAl Viro * according to the SLAVIO manual (and the same applies for the SEC) 6632231a66SAl Viro * the clear field clears bits in the mask which will ENABLE that IRQ 6732231a66SAl Viro * the set field sets bits in the mask to DISABLE the IRQ. 6832231a66SAl Viro * 6932231a66SAl Viro * Also the undirected_xx address in the SLAVIO is defined as 7032231a66SAl Viro * RESERVED and write only.. 7132231a66SAl Viro * 7232231a66SAl Viro * DAVEM_NOTE: The SLAVIO only specifies behavior on uniprocessor 7332231a66SAl Viro * sun4m machines, for MP the layout makes more sense. 7432231a66SAl Viro */ 7532231a66SAl Viro struct sun4m_intregs { 7632231a66SAl Viro struct sun4m_intreg_percpu cpu_intregs[SUN4M_NCPUS]; 7732231a66SAl Viro unsigned int tbt; /* IRQ's that are still pending. */ 7832231a66SAl Viro unsigned int irqs; /* Master IRQ bits. */ 7932231a66SAl Viro 8032231a66SAl Viro /* Again, like the above, two these registers are WRITE-ONLY. */ 8132231a66SAl Viro unsigned int clear; /* Clear master IRQ's by setting bits here. */ 8232231a66SAl Viro unsigned int set; /* Set master IRQ's by setting bits here. */ 8332231a66SAl Viro 8432231a66SAl Viro /* This register is both READ and WRITE. */ 8532231a66SAl Viro unsigned int undirected_target; /* Which cpu gets undirected irqs. */ 8632231a66SAl Viro }; 8732231a66SAl Viro 881da177e4SLinus Torvalds static unsigned long dummy; 891da177e4SLinus Torvalds 901da177e4SLinus Torvalds struct sun4m_intregs *sun4m_interrupts; 911da177e4SLinus Torvalds unsigned long *irq_rcvreg = &dummy; 921da177e4SLinus Torvalds 9332231a66SAl Viro /* Dave Redman (djhr@tadpole.co.uk) 9432231a66SAl Viro * The sun4m interrupt registers. 9532231a66SAl Viro */ 9632231a66SAl Viro #define SUN4M_INT_ENABLE 0x80000000 9732231a66SAl Viro #define SUN4M_INT_E14 0x00000080 9832231a66SAl Viro #define SUN4M_INT_E10 0x00080000 9932231a66SAl Viro 10032231a66SAl Viro #define SUN4M_HARD_INT(x) (0x000000001 << (x)) 10132231a66SAl Viro #define SUN4M_SOFT_INT(x) (0x000010000 << (x)) 10232231a66SAl Viro 10332231a66SAl Viro #define SUN4M_INT_MASKALL 0x80000000 /* mask all interrupts */ 10432231a66SAl Viro #define SUN4M_INT_MODULE_ERR 0x40000000 /* module error */ 10532231a66SAl Viro #define SUN4M_INT_M2S_WRITE 0x20000000 /* write buffer error */ 10632231a66SAl Viro #define SUN4M_INT_ECC 0x10000000 /* ecc memory error */ 10732231a66SAl Viro #define SUN4M_INT_FLOPPY 0x00400000 /* floppy disk */ 10832231a66SAl Viro #define SUN4M_INT_MODULE 0x00200000 /* module interrupt */ 10932231a66SAl Viro #define SUN4M_INT_VIDEO 0x00100000 /* onboard video */ 11032231a66SAl Viro #define SUN4M_INT_REALTIME 0x00080000 /* system timer */ 11132231a66SAl Viro #define SUN4M_INT_SCSI 0x00040000 /* onboard scsi */ 11232231a66SAl Viro #define SUN4M_INT_AUDIO 0x00020000 /* audio/isdn */ 11332231a66SAl Viro #define SUN4M_INT_ETHERNET 0x00010000 /* onboard ethernet */ 11432231a66SAl Viro #define SUN4M_INT_SERIAL 0x00008000 /* serial ports */ 11532231a66SAl Viro #define SUN4M_INT_KBDMS 0x00004000 /* keyboard/mouse */ 11632231a66SAl Viro #define SUN4M_INT_SBUSBITS 0x00003F80 /* sbus int bits */ 11732231a66SAl Viro 11832231a66SAl Viro #define SUN4M_INT_SBUS(x) (1 << (x+7)) 11932231a66SAl Viro #define SUN4M_INT_VME(x) (1 << (x)) 12032231a66SAl Viro 1211da177e4SLinus Torvalds /* These tables only apply for interrupts greater than 15.. 1221da177e4SLinus Torvalds * 1231da177e4SLinus Torvalds * any intr value below 0x10 is considered to be a soft-int 1241da177e4SLinus Torvalds * this may be useful or it may not.. but that's how I've done it. 1251da177e4SLinus Torvalds * and it won't clash with what OBP is telling us about devices. 1261da177e4SLinus Torvalds * 1271da177e4SLinus Torvalds * take an encoded intr value and lookup if it's valid 1281da177e4SLinus Torvalds * then get the mask bits that match from irq_mask 1291da177e4SLinus Torvalds * 1301da177e4SLinus Torvalds * P3: Translation from irq 0x0d to mask 0x2000 is for MrCoffee. 1311da177e4SLinus Torvalds */ 1321da177e4SLinus Torvalds static unsigned char irq_xlate[32] = { 1331da177e4SLinus Torvalds /* 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f */ 1341da177e4SLinus Torvalds 0, 0, 0, 0, 1, 0, 2, 0, 3, 0, 4, 5, 6, 14, 0, 7, 1351da177e4SLinus Torvalds 0, 0, 8, 9, 0, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 0 1361da177e4SLinus Torvalds }; 1371da177e4SLinus Torvalds 1381da177e4SLinus Torvalds static unsigned long irq_mask[] = { 1391da177e4SLinus Torvalds 0, /* illegal index */ 1401da177e4SLinus Torvalds SUN4M_INT_SCSI, /* 1 irq 4 */ 1411da177e4SLinus Torvalds SUN4M_INT_ETHERNET, /* 2 irq 6 */ 1421da177e4SLinus Torvalds SUN4M_INT_VIDEO, /* 3 irq 8 */ 1431da177e4SLinus Torvalds SUN4M_INT_REALTIME, /* 4 irq 10 */ 1441da177e4SLinus Torvalds SUN4M_INT_FLOPPY, /* 5 irq 11 */ 1451da177e4SLinus Torvalds (SUN4M_INT_SERIAL | SUN4M_INT_KBDMS), /* 6 irq 12 */ 1461da177e4SLinus Torvalds SUN4M_INT_MODULE_ERR, /* 7 irq 15 */ 1471da177e4SLinus Torvalds SUN4M_INT_SBUS(0), /* 8 irq 2 */ 1481da177e4SLinus Torvalds SUN4M_INT_SBUS(1), /* 9 irq 3 */ 1491da177e4SLinus Torvalds SUN4M_INT_SBUS(2), /* 10 irq 5 */ 1501da177e4SLinus Torvalds SUN4M_INT_SBUS(3), /* 11 irq 7 */ 1511da177e4SLinus Torvalds SUN4M_INT_SBUS(4), /* 12 irq 9 */ 1521da177e4SLinus Torvalds SUN4M_INT_SBUS(5), /* 13 irq 11 */ 1531da177e4SLinus Torvalds SUN4M_INT_SBUS(6) /* 14 irq 13 */ 1541da177e4SLinus Torvalds }; 1551da177e4SLinus Torvalds 156c61c65cdSAdrian Bunk static unsigned long sun4m_get_irqmask(unsigned int irq) 1571da177e4SLinus Torvalds { 1581da177e4SLinus Torvalds unsigned long mask; 1591da177e4SLinus Torvalds 1601da177e4SLinus Torvalds if (irq > 0x20) { 1611da177e4SLinus Torvalds /* OBIO/SBUS interrupts */ 1621da177e4SLinus Torvalds irq &= 0x1f; 1631da177e4SLinus Torvalds mask = irq_mask[irq_xlate[irq]]; 1641da177e4SLinus Torvalds if (!mask) 1651da177e4SLinus Torvalds printk("sun4m_get_irqmask: IRQ%d has no valid mask!\n",irq); 1661da177e4SLinus Torvalds } else { 1671da177e4SLinus Torvalds /* Soft Interrupts will come here. 1681da177e4SLinus Torvalds * Currently there is no way to trigger them but I'm sure 1691da177e4SLinus Torvalds * something could be cooked up. 1701da177e4SLinus Torvalds */ 1711da177e4SLinus Torvalds irq &= 0xf; 1721da177e4SLinus Torvalds mask = SUN4M_SOFT_INT(irq); 1731da177e4SLinus Torvalds } 1741da177e4SLinus Torvalds return mask; 1751da177e4SLinus Torvalds } 1761da177e4SLinus Torvalds 1771da177e4SLinus Torvalds static void sun4m_disable_irq(unsigned int irq_nr) 1781da177e4SLinus Torvalds { 1791da177e4SLinus Torvalds unsigned long mask, flags; 1801da177e4SLinus Torvalds int cpu = smp_processor_id(); 1811da177e4SLinus Torvalds 1821da177e4SLinus Torvalds mask = sun4m_get_irqmask(irq_nr); 1831da177e4SLinus Torvalds local_irq_save(flags); 1841da177e4SLinus Torvalds if (irq_nr > 15) 1851da177e4SLinus Torvalds sun4m_interrupts->set = mask; 1861da177e4SLinus Torvalds else 1871da177e4SLinus Torvalds sun4m_interrupts->cpu_intregs[cpu].set = mask; 1881da177e4SLinus Torvalds local_irq_restore(flags); 1891da177e4SLinus Torvalds } 1901da177e4SLinus Torvalds 1911da177e4SLinus Torvalds static void sun4m_enable_irq(unsigned int irq_nr) 1921da177e4SLinus Torvalds { 1931da177e4SLinus Torvalds unsigned long mask, flags; 1941da177e4SLinus Torvalds int cpu = smp_processor_id(); 1951da177e4SLinus Torvalds 1961da177e4SLinus Torvalds /* Dreadful floppy hack. When we use 0x2b instead of 1971da177e4SLinus Torvalds * 0x0b the system blows (it starts to whistle!). 1981da177e4SLinus Torvalds * So we continue to use 0x0b. Fixme ASAP. --P3 1991da177e4SLinus Torvalds */ 2001da177e4SLinus Torvalds if (irq_nr != 0x0b) { 2011da177e4SLinus Torvalds mask = sun4m_get_irqmask(irq_nr); 2021da177e4SLinus Torvalds local_irq_save(flags); 2031da177e4SLinus Torvalds if (irq_nr > 15) 2041da177e4SLinus Torvalds sun4m_interrupts->clear = mask; 2051da177e4SLinus Torvalds else 2061da177e4SLinus Torvalds sun4m_interrupts->cpu_intregs[cpu].clear = mask; 2071da177e4SLinus Torvalds local_irq_restore(flags); 2081da177e4SLinus Torvalds } else { 2091da177e4SLinus Torvalds local_irq_save(flags); 2101da177e4SLinus Torvalds sun4m_interrupts->clear = SUN4M_INT_FLOPPY; 2111da177e4SLinus Torvalds local_irq_restore(flags); 2121da177e4SLinus Torvalds } 2131da177e4SLinus Torvalds } 2141da177e4SLinus Torvalds 2151da177e4SLinus Torvalds static unsigned long cpu_pil_to_imask[16] = { 2161da177e4SLinus Torvalds /*0*/ 0x00000000, 2171da177e4SLinus Torvalds /*1*/ 0x00000000, 2181da177e4SLinus Torvalds /*2*/ SUN4M_INT_SBUS(0) | SUN4M_INT_VME(0), 2191da177e4SLinus Torvalds /*3*/ SUN4M_INT_SBUS(1) | SUN4M_INT_VME(1), 2201da177e4SLinus Torvalds /*4*/ SUN4M_INT_SCSI, 2211da177e4SLinus Torvalds /*5*/ SUN4M_INT_SBUS(2) | SUN4M_INT_VME(2), 2221da177e4SLinus Torvalds /*6*/ SUN4M_INT_ETHERNET, 2231da177e4SLinus Torvalds /*7*/ SUN4M_INT_SBUS(3) | SUN4M_INT_VME(3), 2241da177e4SLinus Torvalds /*8*/ SUN4M_INT_VIDEO, 2251da177e4SLinus Torvalds /*9*/ SUN4M_INT_SBUS(4) | SUN4M_INT_VME(4) | SUN4M_INT_MODULE_ERR, 2261da177e4SLinus Torvalds /*10*/ SUN4M_INT_REALTIME, 2271da177e4SLinus Torvalds /*11*/ SUN4M_INT_SBUS(5) | SUN4M_INT_VME(5) | SUN4M_INT_FLOPPY, 2281da177e4SLinus Torvalds /*12*/ SUN4M_INT_SERIAL | SUN4M_INT_KBDMS, 2291da177e4SLinus Torvalds /*13*/ SUN4M_INT_AUDIO, 2301da177e4SLinus Torvalds /*14*/ SUN4M_INT_E14, 2311da177e4SLinus Torvalds /*15*/ 0x00000000 2321da177e4SLinus Torvalds }; 2331da177e4SLinus Torvalds 2341da177e4SLinus Torvalds /* We assume the caller has disabled local interrupts when these are called, 2351da177e4SLinus Torvalds * or else very bizarre behavior will result. 2361da177e4SLinus Torvalds */ 2371da177e4SLinus Torvalds static void sun4m_disable_pil_irq(unsigned int pil) 2381da177e4SLinus Torvalds { 2391da177e4SLinus Torvalds sun4m_interrupts->set = cpu_pil_to_imask[pil]; 2401da177e4SLinus Torvalds } 2411da177e4SLinus Torvalds 2421da177e4SLinus Torvalds static void sun4m_enable_pil_irq(unsigned int pil) 2431da177e4SLinus Torvalds { 2441da177e4SLinus Torvalds sun4m_interrupts->clear = cpu_pil_to_imask[pil]; 2451da177e4SLinus Torvalds } 2461da177e4SLinus Torvalds 2471da177e4SLinus Torvalds #ifdef CONFIG_SMP 2481da177e4SLinus Torvalds static void sun4m_send_ipi(int cpu, int level) 2491da177e4SLinus Torvalds { 2501da177e4SLinus Torvalds unsigned long mask; 2511da177e4SLinus Torvalds 2521da177e4SLinus Torvalds mask = sun4m_get_irqmask(level); 2531da177e4SLinus Torvalds sun4m_interrupts->cpu_intregs[cpu].set = mask; 2541da177e4SLinus Torvalds } 2551da177e4SLinus Torvalds 2561da177e4SLinus Torvalds static void sun4m_clear_ipi(int cpu, int level) 2571da177e4SLinus Torvalds { 2581da177e4SLinus Torvalds unsigned long mask; 2591da177e4SLinus Torvalds 2601da177e4SLinus Torvalds mask = sun4m_get_irqmask(level); 2611da177e4SLinus Torvalds sun4m_interrupts->cpu_intregs[cpu].clear = mask; 2621da177e4SLinus Torvalds } 2631da177e4SLinus Torvalds 2641da177e4SLinus Torvalds static void sun4m_set_udt(int cpu) 2651da177e4SLinus Torvalds { 2661da177e4SLinus Torvalds sun4m_interrupts->undirected_target = cpu; 2671da177e4SLinus Torvalds } 2681da177e4SLinus Torvalds #endif 2691da177e4SLinus Torvalds 270*9b2e43aeSDavid S. Miller struct sun4m_timer_percpu { 271*9b2e43aeSDavid S. Miller u32 l14_limit; 272*9b2e43aeSDavid S. Miller u32 l14_count; 273*9b2e43aeSDavid S. Miller u32 l14_limit_noclear; 274*9b2e43aeSDavid S. Miller u32 user_timer_start_stop; 275*9b2e43aeSDavid S. Miller }; 276*9b2e43aeSDavid S. Miller 277*9b2e43aeSDavid S. Miller static struct sun4m_timer_percpu __iomem *timers_percpu[SUN4M_NCPUS]; 278*9b2e43aeSDavid S. Miller 279*9b2e43aeSDavid S. Miller struct sun4m_timer_global { 280*9b2e43aeSDavid S. Miller u32 l10_limit; 281*9b2e43aeSDavid S. Miller u32 l10_count; 282*9b2e43aeSDavid S. Miller u32 l10_limit_noclear; 283*9b2e43aeSDavid S. Miller u32 reserved; 284*9b2e43aeSDavid S. Miller u32 timer_config; 285*9b2e43aeSDavid S. Miller }; 286*9b2e43aeSDavid S. Miller 287*9b2e43aeSDavid S. Miller static struct sun4m_timer_global __iomem *timers_global; 288*9b2e43aeSDavid S. Miller 2891da177e4SLinus Torvalds #define OBIO_INTR 0x20 2901da177e4SLinus Torvalds #define TIMER_IRQ (OBIO_INTR | 10) 2911da177e4SLinus Torvalds 2921da177e4SLinus Torvalds unsigned int lvl14_resolution = (((1000000/HZ) + 1) << 10); 2931da177e4SLinus Torvalds 2941da177e4SLinus Torvalds static void sun4m_clear_clock_irq(void) 2951da177e4SLinus Torvalds { 296*9b2e43aeSDavid S. Miller sbus_readl(&timers_global->l10_limit); 2971da177e4SLinus Torvalds } 2981da177e4SLinus Torvalds 2991da177e4SLinus Torvalds static void sun4m_clear_profile_irq(int cpu) 3001da177e4SLinus Torvalds { 301*9b2e43aeSDavid S. Miller sbus_readl(&timers_percpu[cpu]->l14_limit); 3021da177e4SLinus Torvalds } 3031da177e4SLinus Torvalds 3041da177e4SLinus Torvalds static void sun4m_load_profile_irq(int cpu, unsigned int limit) 3051da177e4SLinus Torvalds { 306*9b2e43aeSDavid S. Miller sbus_writel(limit, &timers_percpu[cpu]->l14_limit); 3071da177e4SLinus Torvalds } 3081da177e4SLinus Torvalds 30940220c1aSDavid Howells static void __init sun4m_init_timers(irq_handler_t counter_fn) 3101da177e4SLinus Torvalds { 311*9b2e43aeSDavid S. Miller struct device_node *dp = of_find_node_by_name(NULL, "counter"); 312*9b2e43aeSDavid S. Miller int i, err, len, num_cpu_timers; 313*9b2e43aeSDavid S. Miller const u32 *addr; 3141da177e4SLinus Torvalds 315*9b2e43aeSDavid S. Miller if (!dp) { 316*9b2e43aeSDavid S. Miller printk(KERN_ERR "sun4m_init_timers: No 'counter' node.\n"); 317*9b2e43aeSDavid S. Miller return; 3181da177e4SLinus Torvalds } 3191da177e4SLinus Torvalds 320*9b2e43aeSDavid S. Miller addr = of_get_property(dp, "address", &len); 321*9b2e43aeSDavid S. Miller if (!addr) { 322*9b2e43aeSDavid S. Miller printk(KERN_ERR "sun4m_init_timers: No 'address' prop.\n"); 323*9b2e43aeSDavid S. Miller return; 3241da177e4SLinus Torvalds } 3251da177e4SLinus Torvalds 326*9b2e43aeSDavid S. Miller num_cpu_timers = (len / sizeof(u32)) - 1; 327*9b2e43aeSDavid S. Miller for (i = 0; i < num_cpu_timers; i++) { 328*9b2e43aeSDavid S. Miller timers_percpu[i] = (void __iomem *) 329*9b2e43aeSDavid S. Miller (unsigned long) addr[i]; 3301da177e4SLinus Torvalds } 331*9b2e43aeSDavid S. Miller timers_global = (void __iomem *) 332*9b2e43aeSDavid S. Miller (unsigned long) addr[num_cpu_timers]; 333*9b2e43aeSDavid S. Miller 334*9b2e43aeSDavid S. Miller sbus_writel((((1000000/HZ) + 1) << 10), &timers_global->l10_limit); 335*9b2e43aeSDavid S. Miller 336*9b2e43aeSDavid S. Miller master_l10_counter = &timers_global->l10_count; 337*9b2e43aeSDavid S. Miller master_l10_limit = &timers_global->l10_limit; 338*9b2e43aeSDavid S. Miller 339*9b2e43aeSDavid S. Miller err = request_irq(TIMER_IRQ, counter_fn, 340*9b2e43aeSDavid S. Miller (IRQF_DISABLED | SA_STATIC_ALLOC), "timer", NULL); 341*9b2e43aeSDavid S. Miller if (err) { 342*9b2e43aeSDavid S. Miller printk(KERN_ERR "sun4m_init_timers: Register IRQ error %d.\n", 343*9b2e43aeSDavid S. Miller err); 344*9b2e43aeSDavid S. Miller return; 345*9b2e43aeSDavid S. Miller } 346*9b2e43aeSDavid S. Miller 347*9b2e43aeSDavid S. Miller for (i = 0; i < num_cpu_timers; i++) 348*9b2e43aeSDavid S. Miller sbus_writel(0, &timers_percpu[i]->l14_limit); 349*9b2e43aeSDavid S. Miller if (num_cpu_timers == 4) 350*9b2e43aeSDavid S. Miller sbus_writel(SUN4M_INT_E14, &sun4m_interrupts->set); 351*9b2e43aeSDavid S. Miller 3521da177e4SLinus Torvalds #ifdef CONFIG_SMP 3531da177e4SLinus Torvalds { 3541da177e4SLinus Torvalds unsigned long flags; 3551da177e4SLinus Torvalds extern unsigned long lvl14_save[4]; 3561da177e4SLinus Torvalds struct tt_entry *trap_table = &sparc_ttable[SP_TRAP_IRQ1 + (14 - 1)]; 3571da177e4SLinus Torvalds 3581da177e4SLinus Torvalds /* For SMP we use the level 14 ticker, however the bootup code 359d1a78c32SSimon Arlott * has copied the firmware's level 14 vector into the boot cpu's 3601da177e4SLinus Torvalds * trap table, we must fix this now or we get squashed. 3611da177e4SLinus Torvalds */ 3621da177e4SLinus Torvalds local_irq_save(flags); 3631da177e4SLinus Torvalds trap_table->inst_one = lvl14_save[0]; 3641da177e4SLinus Torvalds trap_table->inst_two = lvl14_save[1]; 3651da177e4SLinus Torvalds trap_table->inst_three = lvl14_save[2]; 3661da177e4SLinus Torvalds trap_table->inst_four = lvl14_save[3]; 3671da177e4SLinus Torvalds local_flush_cache_all(); 3681da177e4SLinus Torvalds local_irq_restore(flags); 3691da177e4SLinus Torvalds } 3701da177e4SLinus Torvalds #endif 3711da177e4SLinus Torvalds } 3721da177e4SLinus Torvalds 3731da177e4SLinus Torvalds void __init sun4m_init_IRQ(void) 3741da177e4SLinus Torvalds { 3751da177e4SLinus Torvalds int ie_node,i; 3761da177e4SLinus Torvalds struct linux_prom_registers int_regs[PROMREG_MAX]; 3771da177e4SLinus Torvalds int num_regs; 3781da177e4SLinus Torvalds struct resource r; 3791da177e4SLinus Torvalds int mid; 3801da177e4SLinus Torvalds 3811da177e4SLinus Torvalds local_irq_disable(); 3821da177e4SLinus Torvalds if((ie_node = prom_searchsiblings(prom_getchild(prom_root_node), "obio")) == 0 || 3831da177e4SLinus Torvalds (ie_node = prom_getchild (ie_node)) == 0 || 3841da177e4SLinus Torvalds (ie_node = prom_searchsiblings (ie_node, "interrupt")) == 0) { 3851da177e4SLinus Torvalds prom_printf("Cannot find /obio/interrupt node\n"); 3861da177e4SLinus Torvalds prom_halt(); 3871da177e4SLinus Torvalds } 3881da177e4SLinus Torvalds num_regs = prom_getproperty(ie_node, "reg", (char *) int_regs, 3891da177e4SLinus Torvalds sizeof(int_regs)); 3901da177e4SLinus Torvalds num_regs = (num_regs/sizeof(struct linux_prom_registers)); 3911da177e4SLinus Torvalds 3921da177e4SLinus Torvalds /* Apply the obio ranges to these registers. */ 3931da177e4SLinus Torvalds prom_apply_obio_ranges(int_regs, num_regs); 3941da177e4SLinus Torvalds 3951da177e4SLinus Torvalds int_regs[4].phys_addr = int_regs[num_regs-1].phys_addr; 3961da177e4SLinus Torvalds int_regs[4].reg_size = int_regs[num_regs-1].reg_size; 3971da177e4SLinus Torvalds int_regs[4].which_io = int_regs[num_regs-1].which_io; 3981da177e4SLinus Torvalds for(ie_node = 1; ie_node < 4; ie_node++) { 3991da177e4SLinus Torvalds int_regs[ie_node].phys_addr = int_regs[ie_node-1].phys_addr + PAGE_SIZE; 4001da177e4SLinus Torvalds int_regs[ie_node].reg_size = int_regs[ie_node-1].reg_size; 4011da177e4SLinus Torvalds int_regs[ie_node].which_io = int_regs[ie_node-1].which_io; 4021da177e4SLinus Torvalds } 4031da177e4SLinus Torvalds 4041da177e4SLinus Torvalds memset((char *)&r, 0, sizeof(struct resource)); 4051da177e4SLinus Torvalds /* Map the interrupt registers for all possible cpus. */ 4061da177e4SLinus Torvalds r.flags = int_regs[0].which_io; 4071da177e4SLinus Torvalds r.start = int_regs[0].phys_addr; 408454eeb2dSDavid S. Miller sun4m_interrupts = (struct sun4m_intregs *) of_ioremap(&r, 0, 4091da177e4SLinus Torvalds PAGE_SIZE*SUN4M_NCPUS, "interrupts_percpu"); 4101da177e4SLinus Torvalds 4111da177e4SLinus Torvalds /* Map the system interrupt control registers. */ 4121da177e4SLinus Torvalds r.flags = int_regs[4].which_io; 4131da177e4SLinus Torvalds r.start = int_regs[4].phys_addr; 414454eeb2dSDavid S. Miller of_ioremap(&r, 0, int_regs[4].reg_size, "interrupts_system"); 4151da177e4SLinus Torvalds 4161da177e4SLinus Torvalds sun4m_interrupts->set = ~SUN4M_INT_MASKALL; 4171da177e4SLinus Torvalds for (i = 0; !cpu_find_by_instance(i, NULL, &mid); i++) 4181da177e4SLinus Torvalds sun4m_interrupts->cpu_intregs[mid].clear = ~0x17fff; 4191da177e4SLinus Torvalds 4201da177e4SLinus Torvalds if (!cpu_find_by_instance(1, NULL, NULL)) { 4211da177e4SLinus Torvalds /* system wide interrupts go to cpu 0, this should always 4221da177e4SLinus Torvalds * be safe because it is guaranteed to be fitted or OBP doesn't 4231da177e4SLinus Torvalds * come up 4241da177e4SLinus Torvalds * 4251da177e4SLinus Torvalds * Not sure, but writing here on SLAVIO systems may puke 4261da177e4SLinus Torvalds * so I don't do it unless there is more than 1 cpu. 4271da177e4SLinus Torvalds */ 4281da177e4SLinus Torvalds irq_rcvreg = (unsigned long *) 4291da177e4SLinus Torvalds &sun4m_interrupts->undirected_target; 4301da177e4SLinus Torvalds sun4m_interrupts->undirected_target = 0; 4311da177e4SLinus Torvalds } 4321da177e4SLinus Torvalds BTFIXUPSET_CALL(enable_irq, sun4m_enable_irq, BTFIXUPCALL_NORM); 4331da177e4SLinus Torvalds BTFIXUPSET_CALL(disable_irq, sun4m_disable_irq, BTFIXUPCALL_NORM); 4341da177e4SLinus Torvalds BTFIXUPSET_CALL(enable_pil_irq, sun4m_enable_pil_irq, BTFIXUPCALL_NORM); 4351da177e4SLinus Torvalds BTFIXUPSET_CALL(disable_pil_irq, sun4m_disable_pil_irq, BTFIXUPCALL_NORM); 4361da177e4SLinus Torvalds BTFIXUPSET_CALL(clear_clock_irq, sun4m_clear_clock_irq, BTFIXUPCALL_NORM); 4371da177e4SLinus Torvalds BTFIXUPSET_CALL(clear_profile_irq, sun4m_clear_profile_irq, BTFIXUPCALL_NORM); 4381da177e4SLinus Torvalds BTFIXUPSET_CALL(load_profile_irq, sun4m_load_profile_irq, BTFIXUPCALL_NORM); 4391da177e4SLinus Torvalds sparc_init_timers = sun4m_init_timers; 4401da177e4SLinus Torvalds #ifdef CONFIG_SMP 4411da177e4SLinus Torvalds BTFIXUPSET_CALL(set_cpu_int, sun4m_send_ipi, BTFIXUPCALL_NORM); 4421da177e4SLinus Torvalds BTFIXUPSET_CALL(clear_cpu_int, sun4m_clear_ipi, BTFIXUPCALL_NORM); 4431da177e4SLinus Torvalds BTFIXUPSET_CALL(set_irq_udt, sun4m_set_udt, BTFIXUPCALL_NORM); 4441da177e4SLinus Torvalds #endif 4451da177e4SLinus Torvalds /* Cannot enable interrupts until OBP ticker is disabled. */ 4461da177e4SLinus Torvalds } 447