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 4469c010b2SDavid S. Miller struct sun4m_irq_percpu { 4569c010b2SDavid S. Miller u32 pending; 4669c010b2SDavid S. Miller u32 clear; 4769c010b2SDavid S. Miller u32 set; 4832231a66SAl Viro }; 4932231a66SAl Viro 5069c010b2SDavid S. Miller struct sun4m_irq_global { 5169c010b2SDavid S. Miller u32 pending; 5269c010b2SDavid S. Miller u32 mask; 5369c010b2SDavid S. Miller u32 mask_clear; 5469c010b2SDavid S. Miller u32 mask_set; 5569c010b2SDavid S. Miller u32 interrupt_target; 5632231a66SAl Viro }; 5732231a66SAl Viro 5869c010b2SDavid S. Miller /* Code in entry.S needs to get at these register mappings. */ 5969c010b2SDavid S. Miller struct sun4m_irq_percpu __iomem *sun4m_irq_percpu[SUN4M_NCPUS]; 6069c010b2SDavid S. Miller struct sun4m_irq_global __iomem *sun4m_irq_global; 6169c010b2SDavid S. Miller 621da177e4SLinus Torvalds static unsigned long dummy; 631da177e4SLinus Torvalds unsigned long *irq_rcvreg = &dummy; 641da177e4SLinus Torvalds 6532231a66SAl Viro /* Dave Redman (djhr@tadpole.co.uk) 6632231a66SAl Viro * The sun4m interrupt registers. 6732231a66SAl Viro */ 6832231a66SAl Viro #define SUN4M_INT_ENABLE 0x80000000 6932231a66SAl Viro #define SUN4M_INT_E14 0x00000080 7032231a66SAl Viro #define SUN4M_INT_E10 0x00080000 7132231a66SAl Viro 7232231a66SAl Viro #define SUN4M_HARD_INT(x) (0x000000001 << (x)) 7332231a66SAl Viro #define SUN4M_SOFT_INT(x) (0x000010000 << (x)) 7432231a66SAl Viro 7532231a66SAl Viro #define SUN4M_INT_MASKALL 0x80000000 /* mask all interrupts */ 7632231a66SAl Viro #define SUN4M_INT_MODULE_ERR 0x40000000 /* module error */ 7732231a66SAl Viro #define SUN4M_INT_M2S_WRITE 0x20000000 /* write buffer error */ 7832231a66SAl Viro #define SUN4M_INT_ECC 0x10000000 /* ecc memory error */ 7932231a66SAl Viro #define SUN4M_INT_FLOPPY 0x00400000 /* floppy disk */ 8032231a66SAl Viro #define SUN4M_INT_MODULE 0x00200000 /* module interrupt */ 8132231a66SAl Viro #define SUN4M_INT_VIDEO 0x00100000 /* onboard video */ 8232231a66SAl Viro #define SUN4M_INT_REALTIME 0x00080000 /* system timer */ 8332231a66SAl Viro #define SUN4M_INT_SCSI 0x00040000 /* onboard scsi */ 8432231a66SAl Viro #define SUN4M_INT_AUDIO 0x00020000 /* audio/isdn */ 8532231a66SAl Viro #define SUN4M_INT_ETHERNET 0x00010000 /* onboard ethernet */ 8632231a66SAl Viro #define SUN4M_INT_SERIAL 0x00008000 /* serial ports */ 8732231a66SAl Viro #define SUN4M_INT_KBDMS 0x00004000 /* keyboard/mouse */ 8832231a66SAl Viro #define SUN4M_INT_SBUSBITS 0x00003F80 /* sbus int bits */ 8932231a66SAl Viro 9032231a66SAl Viro #define SUN4M_INT_SBUS(x) (1 << (x+7)) 9132231a66SAl Viro #define SUN4M_INT_VME(x) (1 << (x)) 9232231a66SAl Viro 931da177e4SLinus Torvalds /* These tables only apply for interrupts greater than 15.. 941da177e4SLinus Torvalds * 951da177e4SLinus Torvalds * any intr value below 0x10 is considered to be a soft-int 961da177e4SLinus Torvalds * this may be useful or it may not.. but that's how I've done it. 971da177e4SLinus Torvalds * and it won't clash with what OBP is telling us about devices. 981da177e4SLinus Torvalds * 991da177e4SLinus Torvalds * take an encoded intr value and lookup if it's valid 1001da177e4SLinus Torvalds * then get the mask bits that match from irq_mask 1011da177e4SLinus Torvalds * 1021da177e4SLinus Torvalds * P3: Translation from irq 0x0d to mask 0x2000 is for MrCoffee. 1031da177e4SLinus Torvalds */ 1041da177e4SLinus Torvalds static unsigned char irq_xlate[32] = { 1051da177e4SLinus Torvalds /* 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f */ 1061da177e4SLinus Torvalds 0, 0, 0, 0, 1, 0, 2, 0, 3, 0, 4, 5, 6, 14, 0, 7, 1071da177e4SLinus Torvalds 0, 0, 8, 9, 0, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 0 1081da177e4SLinus Torvalds }; 1091da177e4SLinus Torvalds 1101da177e4SLinus Torvalds static unsigned long irq_mask[] = { 1111da177e4SLinus Torvalds 0, /* illegal index */ 1121da177e4SLinus Torvalds SUN4M_INT_SCSI, /* 1 irq 4 */ 1131da177e4SLinus Torvalds SUN4M_INT_ETHERNET, /* 2 irq 6 */ 1141da177e4SLinus Torvalds SUN4M_INT_VIDEO, /* 3 irq 8 */ 1151da177e4SLinus Torvalds SUN4M_INT_REALTIME, /* 4 irq 10 */ 1161da177e4SLinus Torvalds SUN4M_INT_FLOPPY, /* 5 irq 11 */ 1171da177e4SLinus Torvalds (SUN4M_INT_SERIAL | SUN4M_INT_KBDMS), /* 6 irq 12 */ 1181da177e4SLinus Torvalds SUN4M_INT_MODULE_ERR, /* 7 irq 15 */ 1191da177e4SLinus Torvalds SUN4M_INT_SBUS(0), /* 8 irq 2 */ 1201da177e4SLinus Torvalds SUN4M_INT_SBUS(1), /* 9 irq 3 */ 1211da177e4SLinus Torvalds SUN4M_INT_SBUS(2), /* 10 irq 5 */ 1221da177e4SLinus Torvalds SUN4M_INT_SBUS(3), /* 11 irq 7 */ 1231da177e4SLinus Torvalds SUN4M_INT_SBUS(4), /* 12 irq 9 */ 1241da177e4SLinus Torvalds SUN4M_INT_SBUS(5), /* 13 irq 11 */ 1251da177e4SLinus Torvalds SUN4M_INT_SBUS(6) /* 14 irq 13 */ 1261da177e4SLinus Torvalds }; 1271da177e4SLinus Torvalds 128c61c65cdSAdrian Bunk static unsigned long sun4m_get_irqmask(unsigned int irq) 1291da177e4SLinus Torvalds { 1301da177e4SLinus Torvalds unsigned long mask; 1311da177e4SLinus Torvalds 1321da177e4SLinus Torvalds if (irq > 0x20) { 1331da177e4SLinus Torvalds /* OBIO/SBUS interrupts */ 1341da177e4SLinus Torvalds irq &= 0x1f; 1351da177e4SLinus Torvalds mask = irq_mask[irq_xlate[irq]]; 1361da177e4SLinus Torvalds if (!mask) 1371da177e4SLinus Torvalds printk("sun4m_get_irqmask: IRQ%d has no valid mask!\n",irq); 1381da177e4SLinus Torvalds } else { 1391da177e4SLinus Torvalds /* Soft Interrupts will come here. 1401da177e4SLinus Torvalds * Currently there is no way to trigger them but I'm sure 1411da177e4SLinus Torvalds * something could be cooked up. 1421da177e4SLinus Torvalds */ 1431da177e4SLinus Torvalds irq &= 0xf; 1441da177e4SLinus Torvalds mask = SUN4M_SOFT_INT(irq); 1451da177e4SLinus Torvalds } 1461da177e4SLinus Torvalds return mask; 1471da177e4SLinus Torvalds } 1481da177e4SLinus Torvalds 1491da177e4SLinus Torvalds static void sun4m_disable_irq(unsigned int irq_nr) 1501da177e4SLinus Torvalds { 1511da177e4SLinus Torvalds unsigned long mask, flags; 1521da177e4SLinus Torvalds int cpu = smp_processor_id(); 1531da177e4SLinus Torvalds 1541da177e4SLinus Torvalds mask = sun4m_get_irqmask(irq_nr); 1551da177e4SLinus Torvalds local_irq_save(flags); 1561da177e4SLinus Torvalds if (irq_nr > 15) 15769c010b2SDavid S. Miller sbus_writel(mask, &sun4m_irq_global->mask_set); 1581da177e4SLinus Torvalds else 15969c010b2SDavid S. Miller sbus_writel(mask, &sun4m_irq_percpu[cpu]->set); 1601da177e4SLinus Torvalds local_irq_restore(flags); 1611da177e4SLinus Torvalds } 1621da177e4SLinus Torvalds 1631da177e4SLinus Torvalds static void sun4m_enable_irq(unsigned int irq_nr) 1641da177e4SLinus Torvalds { 1651da177e4SLinus Torvalds unsigned long mask, flags; 1661da177e4SLinus Torvalds int cpu = smp_processor_id(); 1671da177e4SLinus Torvalds 1681da177e4SLinus Torvalds /* Dreadful floppy hack. When we use 0x2b instead of 1691da177e4SLinus Torvalds * 0x0b the system blows (it starts to whistle!). 1701da177e4SLinus Torvalds * So we continue to use 0x0b. Fixme ASAP. --P3 1711da177e4SLinus Torvalds */ 1721da177e4SLinus Torvalds if (irq_nr != 0x0b) { 1731da177e4SLinus Torvalds mask = sun4m_get_irqmask(irq_nr); 1741da177e4SLinus Torvalds local_irq_save(flags); 1751da177e4SLinus Torvalds if (irq_nr > 15) 17669c010b2SDavid S. Miller sbus_writel(mask, &sun4m_irq_global->mask_clear); 1771da177e4SLinus Torvalds else 17869c010b2SDavid S. Miller sbus_writel(mask, &sun4m_irq_percpu[cpu]->clear); 1791da177e4SLinus Torvalds local_irq_restore(flags); 1801da177e4SLinus Torvalds } else { 1811da177e4SLinus Torvalds local_irq_save(flags); 18269c010b2SDavid S. Miller sbus_writel(SUN4M_INT_FLOPPY, &sun4m_irq_global->mask_clear); 1831da177e4SLinus Torvalds local_irq_restore(flags); 1841da177e4SLinus Torvalds } 1851da177e4SLinus Torvalds } 1861da177e4SLinus Torvalds 1871da177e4SLinus Torvalds static unsigned long cpu_pil_to_imask[16] = { 1881da177e4SLinus Torvalds /*0*/ 0x00000000, 1891da177e4SLinus Torvalds /*1*/ 0x00000000, 1901da177e4SLinus Torvalds /*2*/ SUN4M_INT_SBUS(0) | SUN4M_INT_VME(0), 1911da177e4SLinus Torvalds /*3*/ SUN4M_INT_SBUS(1) | SUN4M_INT_VME(1), 1921da177e4SLinus Torvalds /*4*/ SUN4M_INT_SCSI, 1931da177e4SLinus Torvalds /*5*/ SUN4M_INT_SBUS(2) | SUN4M_INT_VME(2), 1941da177e4SLinus Torvalds /*6*/ SUN4M_INT_ETHERNET, 1951da177e4SLinus Torvalds /*7*/ SUN4M_INT_SBUS(3) | SUN4M_INT_VME(3), 1961da177e4SLinus Torvalds /*8*/ SUN4M_INT_VIDEO, 1971da177e4SLinus Torvalds /*9*/ SUN4M_INT_SBUS(4) | SUN4M_INT_VME(4) | SUN4M_INT_MODULE_ERR, 1981da177e4SLinus Torvalds /*10*/ SUN4M_INT_REALTIME, 1991da177e4SLinus Torvalds /*11*/ SUN4M_INT_SBUS(5) | SUN4M_INT_VME(5) | SUN4M_INT_FLOPPY, 2001da177e4SLinus Torvalds /*12*/ SUN4M_INT_SERIAL | SUN4M_INT_KBDMS, 2011da177e4SLinus Torvalds /*13*/ SUN4M_INT_AUDIO, 2021da177e4SLinus Torvalds /*14*/ SUN4M_INT_E14, 2031da177e4SLinus Torvalds /*15*/ 0x00000000 2041da177e4SLinus Torvalds }; 2051da177e4SLinus Torvalds 2061da177e4SLinus Torvalds /* We assume the caller has disabled local interrupts when these are called, 2071da177e4SLinus Torvalds * or else very bizarre behavior will result. 2081da177e4SLinus Torvalds */ 2091da177e4SLinus Torvalds static void sun4m_disable_pil_irq(unsigned int pil) 2101da177e4SLinus Torvalds { 21169c010b2SDavid S. Miller sbus_writel(cpu_pil_to_imask[pil], &sun4m_irq_global->mask_set); 2121da177e4SLinus Torvalds } 2131da177e4SLinus Torvalds 2141da177e4SLinus Torvalds static void sun4m_enable_pil_irq(unsigned int pil) 2151da177e4SLinus Torvalds { 21669c010b2SDavid S. Miller sbus_writel(cpu_pil_to_imask[pil], &sun4m_irq_global->mask_clear); 2171da177e4SLinus Torvalds } 2181da177e4SLinus Torvalds 2191da177e4SLinus Torvalds #ifdef CONFIG_SMP 2201da177e4SLinus Torvalds static void sun4m_send_ipi(int cpu, int level) 2211da177e4SLinus Torvalds { 22269c010b2SDavid S. Miller unsigned long mask = sun4m_get_irqmask(level); 22369c010b2SDavid S. Miller sbus_writel(mask, &sun4m_irq_percpu[cpu]->set); 2241da177e4SLinus Torvalds } 2251da177e4SLinus Torvalds 2261da177e4SLinus Torvalds static void sun4m_clear_ipi(int cpu, int level) 2271da177e4SLinus Torvalds { 22869c010b2SDavid S. Miller unsigned long mask = sun4m_get_irqmask(level); 22969c010b2SDavid S. Miller sbus_writel(mask, &sun4m_irq_percpu[cpu]->clear); 2301da177e4SLinus Torvalds } 2311da177e4SLinus Torvalds 2321da177e4SLinus Torvalds static void sun4m_set_udt(int cpu) 2331da177e4SLinus Torvalds { 23469c010b2SDavid S. Miller sbus_writel(cpu, &sun4m_irq_global->interrupt_target); 2351da177e4SLinus Torvalds } 2361da177e4SLinus Torvalds #endif 2371da177e4SLinus Torvalds 2389b2e43aeSDavid S. Miller struct sun4m_timer_percpu { 2399b2e43aeSDavid S. Miller u32 l14_limit; 2409b2e43aeSDavid S. Miller u32 l14_count; 2419b2e43aeSDavid S. Miller u32 l14_limit_noclear; 2429b2e43aeSDavid S. Miller u32 user_timer_start_stop; 2439b2e43aeSDavid S. Miller }; 2449b2e43aeSDavid S. Miller 2459b2e43aeSDavid S. Miller static struct sun4m_timer_percpu __iomem *timers_percpu[SUN4M_NCPUS]; 2469b2e43aeSDavid S. Miller 2479b2e43aeSDavid S. Miller struct sun4m_timer_global { 2489b2e43aeSDavid S. Miller u32 l10_limit; 2499b2e43aeSDavid S. Miller u32 l10_count; 2509b2e43aeSDavid S. Miller u32 l10_limit_noclear; 2519b2e43aeSDavid S. Miller u32 reserved; 2529b2e43aeSDavid S. Miller u32 timer_config; 2539b2e43aeSDavid S. Miller }; 2549b2e43aeSDavid S. Miller 2559b2e43aeSDavid S. Miller static struct sun4m_timer_global __iomem *timers_global; 2569b2e43aeSDavid S. Miller 2571da177e4SLinus Torvalds #define OBIO_INTR 0x20 2581da177e4SLinus Torvalds #define TIMER_IRQ (OBIO_INTR | 10) 2591da177e4SLinus Torvalds 2601da177e4SLinus Torvalds unsigned int lvl14_resolution = (((1000000/HZ) + 1) << 10); 2611da177e4SLinus Torvalds 2621da177e4SLinus Torvalds static void sun4m_clear_clock_irq(void) 2631da177e4SLinus Torvalds { 2649b2e43aeSDavid S. Miller sbus_readl(&timers_global->l10_limit); 2651da177e4SLinus Torvalds } 2661da177e4SLinus Torvalds 267*1de937a5SDavid S. Miller /* Exported for sun4m_smp.c */ 268*1de937a5SDavid S. Miller void sun4m_clear_profile_irq(int cpu) 2691da177e4SLinus Torvalds { 2709b2e43aeSDavid S. Miller sbus_readl(&timers_percpu[cpu]->l14_limit); 2711da177e4SLinus Torvalds } 2721da177e4SLinus Torvalds 2731da177e4SLinus Torvalds static void sun4m_load_profile_irq(int cpu, unsigned int limit) 2741da177e4SLinus Torvalds { 2759b2e43aeSDavid S. Miller sbus_writel(limit, &timers_percpu[cpu]->l14_limit); 2761da177e4SLinus Torvalds } 2771da177e4SLinus Torvalds 27840220c1aSDavid Howells static void __init sun4m_init_timers(irq_handler_t counter_fn) 2791da177e4SLinus Torvalds { 2809b2e43aeSDavid S. Miller struct device_node *dp = of_find_node_by_name(NULL, "counter"); 2819b2e43aeSDavid S. Miller int i, err, len, num_cpu_timers; 2829b2e43aeSDavid S. Miller const u32 *addr; 2831da177e4SLinus Torvalds 2849b2e43aeSDavid S. Miller if (!dp) { 2859b2e43aeSDavid S. Miller printk(KERN_ERR "sun4m_init_timers: No 'counter' node.\n"); 2869b2e43aeSDavid S. Miller return; 2871da177e4SLinus Torvalds } 2881da177e4SLinus Torvalds 2899b2e43aeSDavid S. Miller addr = of_get_property(dp, "address", &len); 2909b2e43aeSDavid S. Miller if (!addr) { 2919b2e43aeSDavid S. Miller printk(KERN_ERR "sun4m_init_timers: No 'address' prop.\n"); 2929b2e43aeSDavid S. Miller return; 2931da177e4SLinus Torvalds } 2941da177e4SLinus Torvalds 2959b2e43aeSDavid S. Miller num_cpu_timers = (len / sizeof(u32)) - 1; 2969b2e43aeSDavid S. Miller for (i = 0; i < num_cpu_timers; i++) { 2979b2e43aeSDavid S. Miller timers_percpu[i] = (void __iomem *) 2989b2e43aeSDavid S. Miller (unsigned long) addr[i]; 2991da177e4SLinus Torvalds } 3009b2e43aeSDavid S. Miller timers_global = (void __iomem *) 3019b2e43aeSDavid S. Miller (unsigned long) addr[num_cpu_timers]; 3029b2e43aeSDavid S. Miller 3039b2e43aeSDavid S. Miller sbus_writel((((1000000/HZ) + 1) << 10), &timers_global->l10_limit); 3049b2e43aeSDavid S. Miller 3059b2e43aeSDavid S. Miller master_l10_counter = &timers_global->l10_count; 3069b2e43aeSDavid S. Miller master_l10_limit = &timers_global->l10_limit; 3079b2e43aeSDavid S. Miller 3089b2e43aeSDavid S. Miller err = request_irq(TIMER_IRQ, counter_fn, 3099b2e43aeSDavid S. Miller (IRQF_DISABLED | SA_STATIC_ALLOC), "timer", NULL); 3109b2e43aeSDavid S. Miller if (err) { 3119b2e43aeSDavid S. Miller printk(KERN_ERR "sun4m_init_timers: Register IRQ error %d.\n", 3129b2e43aeSDavid S. Miller err); 3139b2e43aeSDavid S. Miller return; 3149b2e43aeSDavid S. Miller } 3159b2e43aeSDavid S. Miller 3169b2e43aeSDavid S. Miller for (i = 0; i < num_cpu_timers; i++) 3179b2e43aeSDavid S. Miller sbus_writel(0, &timers_percpu[i]->l14_limit); 3189b2e43aeSDavid S. Miller if (num_cpu_timers == 4) 31969c010b2SDavid S. Miller sbus_writel(SUN4M_INT_E14, &sun4m_irq_global->mask_set); 3209b2e43aeSDavid S. Miller 3211da177e4SLinus Torvalds #ifdef CONFIG_SMP 3221da177e4SLinus Torvalds { 3231da177e4SLinus Torvalds unsigned long flags; 3241da177e4SLinus Torvalds extern unsigned long lvl14_save[4]; 3251da177e4SLinus Torvalds struct tt_entry *trap_table = &sparc_ttable[SP_TRAP_IRQ1 + (14 - 1)]; 3261da177e4SLinus Torvalds 3271da177e4SLinus Torvalds /* For SMP we use the level 14 ticker, however the bootup code 328d1a78c32SSimon Arlott * has copied the firmware's level 14 vector into the boot cpu's 3291da177e4SLinus Torvalds * trap table, we must fix this now or we get squashed. 3301da177e4SLinus Torvalds */ 3311da177e4SLinus Torvalds local_irq_save(flags); 3321da177e4SLinus Torvalds trap_table->inst_one = lvl14_save[0]; 3331da177e4SLinus Torvalds trap_table->inst_two = lvl14_save[1]; 3341da177e4SLinus Torvalds trap_table->inst_three = lvl14_save[2]; 3351da177e4SLinus Torvalds trap_table->inst_four = lvl14_save[3]; 3361da177e4SLinus Torvalds local_flush_cache_all(); 3371da177e4SLinus Torvalds local_irq_restore(flags); 3381da177e4SLinus Torvalds } 3391da177e4SLinus Torvalds #endif 3401da177e4SLinus Torvalds } 3411da177e4SLinus Torvalds 3421da177e4SLinus Torvalds void __init sun4m_init_IRQ(void) 3431da177e4SLinus Torvalds { 34469c010b2SDavid S. Miller struct device_node *dp = of_find_node_by_name(NULL, "interrupt"); 34569c010b2SDavid S. Miller int len, i, mid, num_cpu_iregs; 34669c010b2SDavid S. Miller const u32 *addr; 34769c010b2SDavid S. Miller 34869c010b2SDavid S. Miller if (!dp) { 34969c010b2SDavid S. Miller printk(KERN_ERR "sun4m_init_IRQ: No 'interrupt' node.\n"); 35069c010b2SDavid S. Miller return; 35169c010b2SDavid S. Miller } 35269c010b2SDavid S. Miller 35369c010b2SDavid S. Miller addr = of_get_property(dp, "address", &len); 35469c010b2SDavid S. Miller if (!addr) { 35569c010b2SDavid S. Miller printk(KERN_ERR "sun4m_init_IRQ: No 'address' prop.\n"); 35669c010b2SDavid S. Miller return; 35769c010b2SDavid S. Miller } 35869c010b2SDavid S. Miller 35969c010b2SDavid S. Miller num_cpu_iregs = (len / sizeof(u32)) - 1; 36069c010b2SDavid S. Miller for (i = 0; i < num_cpu_iregs; i++) { 36169c010b2SDavid S. Miller sun4m_irq_percpu[i] = (void __iomem *) 36269c010b2SDavid S. Miller (unsigned long) addr[i]; 36369c010b2SDavid S. Miller } 36469c010b2SDavid S. Miller sun4m_irq_global = (void __iomem *) 36569c010b2SDavid S. Miller (unsigned long) addr[num_cpu_iregs]; 3661da177e4SLinus Torvalds 3671da177e4SLinus Torvalds local_irq_disable(); 3681da177e4SLinus Torvalds 36969c010b2SDavid S. Miller sbus_writel(~SUN4M_INT_MASKALL, &sun4m_irq_global->mask_set); 3701da177e4SLinus Torvalds for (i = 0; !cpu_find_by_instance(i, NULL, &mid); i++) 37169c010b2SDavid S. Miller sbus_writel(~0x17fff, &sun4m_irq_percpu[mid]->clear); 3721da177e4SLinus Torvalds 37369c010b2SDavid S. Miller if (num_cpu_iregs == 4) { 37469c010b2SDavid S. Miller irq_rcvreg = (unsigned long *) &sun4m_irq_global->interrupt_target; 37569c010b2SDavid S. Miller sbus_writel(0, &sun4m_irq_global->interrupt_target); 3761da177e4SLinus Torvalds } 3771da177e4SLinus Torvalds BTFIXUPSET_CALL(enable_irq, sun4m_enable_irq, BTFIXUPCALL_NORM); 3781da177e4SLinus Torvalds BTFIXUPSET_CALL(disable_irq, sun4m_disable_irq, BTFIXUPCALL_NORM); 3791da177e4SLinus Torvalds BTFIXUPSET_CALL(enable_pil_irq, sun4m_enable_pil_irq, BTFIXUPCALL_NORM); 3801da177e4SLinus Torvalds BTFIXUPSET_CALL(disable_pil_irq, sun4m_disable_pil_irq, BTFIXUPCALL_NORM); 3811da177e4SLinus Torvalds BTFIXUPSET_CALL(clear_clock_irq, sun4m_clear_clock_irq, BTFIXUPCALL_NORM); 3821da177e4SLinus Torvalds BTFIXUPSET_CALL(clear_profile_irq, sun4m_clear_profile_irq, BTFIXUPCALL_NORM); 3831da177e4SLinus Torvalds BTFIXUPSET_CALL(load_profile_irq, sun4m_load_profile_irq, BTFIXUPCALL_NORM); 3841da177e4SLinus Torvalds sparc_init_timers = sun4m_init_timers; 3851da177e4SLinus Torvalds #ifdef CONFIG_SMP 3861da177e4SLinus Torvalds BTFIXUPSET_CALL(set_cpu_int, sun4m_send_ipi, BTFIXUPCALL_NORM); 3871da177e4SLinus Torvalds BTFIXUPSET_CALL(clear_cpu_int, sun4m_clear_ipi, BTFIXUPCALL_NORM); 3881da177e4SLinus Torvalds BTFIXUPSET_CALL(set_irq_udt, sun4m_set_udt, BTFIXUPCALL_NORM); 3891da177e4SLinus Torvalds #endif 39069c010b2SDavid S. Miller 3911da177e4SLinus Torvalds /* Cannot enable interrupts until OBP ticker is disabled. */ 3921da177e4SLinus Torvalds } 393