xref: /openbmc/linux/arch/sparc/kernel/sun4m_irq.c (revision 9b2e43ae4e9609f80034dfe8de895045cac52d77)
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