xref: /openbmc/linux/arch/sparc/kernel/sun4m_irq.c (revision 454eeb2dd7bd0418451ea33a606d0fa50aa36718)
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>
23*454eeb2dSDavid S. Miller #include <linux/of.h>
24*454eeb2dSDavid 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 
2701da177e4SLinus Torvalds #define OBIO_INTR	0x20
2711da177e4SLinus Torvalds #define TIMER_IRQ  	(OBIO_INTR | 10)
2721da177e4SLinus Torvalds #define PROFILE_IRQ	(OBIO_INTR | 14)
2731da177e4SLinus Torvalds 
274c61c65cdSAdrian Bunk static struct sun4m_timer_regs *sun4m_timers;
2751da177e4SLinus Torvalds unsigned int lvl14_resolution = (((1000000/HZ) + 1) << 10);
2761da177e4SLinus Torvalds 
2771da177e4SLinus Torvalds static void sun4m_clear_clock_irq(void)
2781da177e4SLinus Torvalds {
2791da177e4SLinus Torvalds 	volatile unsigned int clear_intr;
2801da177e4SLinus Torvalds 	clear_intr = sun4m_timers->l10_timer_limit;
2811da177e4SLinus Torvalds }
2821da177e4SLinus Torvalds 
2831da177e4SLinus Torvalds static void sun4m_clear_profile_irq(int cpu)
2841da177e4SLinus Torvalds {
2851da177e4SLinus Torvalds 	volatile unsigned int clear;
2861da177e4SLinus Torvalds 
2871da177e4SLinus Torvalds 	clear = sun4m_timers->cpu_timers[cpu].l14_timer_limit;
2881da177e4SLinus Torvalds }
2891da177e4SLinus Torvalds 
2901da177e4SLinus Torvalds static void sun4m_load_profile_irq(int cpu, unsigned int limit)
2911da177e4SLinus Torvalds {
2921da177e4SLinus Torvalds 	sun4m_timers->cpu_timers[cpu].l14_timer_limit = limit;
2931da177e4SLinus Torvalds }
2941da177e4SLinus Torvalds 
29540220c1aSDavid Howells static void __init sun4m_init_timers(irq_handler_t counter_fn)
2961da177e4SLinus Torvalds {
2971da177e4SLinus Torvalds 	int reg_count, irq, cpu;
2981da177e4SLinus Torvalds 	struct linux_prom_registers cnt_regs[PROMREG_MAX];
2991da177e4SLinus Torvalds 	int obio_node, cnt_node;
3001da177e4SLinus Torvalds 	struct resource r;
3011da177e4SLinus Torvalds 
3021da177e4SLinus Torvalds 	cnt_node = 0;
3031da177e4SLinus Torvalds 	if((obio_node =
3041da177e4SLinus Torvalds 	    prom_searchsiblings (prom_getchild(prom_root_node), "obio")) == 0 ||
3051da177e4SLinus Torvalds 	   (obio_node = prom_getchild (obio_node)) == 0 ||
3061da177e4SLinus Torvalds 	   (cnt_node = prom_searchsiblings (obio_node, "counter")) == 0) {
3071da177e4SLinus Torvalds 		prom_printf("Cannot find /obio/counter node\n");
3081da177e4SLinus Torvalds 		prom_halt();
3091da177e4SLinus Torvalds 	}
3101da177e4SLinus Torvalds 	reg_count = prom_getproperty(cnt_node, "reg",
3111da177e4SLinus Torvalds 				     (void *) cnt_regs, sizeof(cnt_regs));
3121da177e4SLinus Torvalds 	reg_count = (reg_count/sizeof(struct linux_prom_registers));
3131da177e4SLinus Torvalds 
3141da177e4SLinus Torvalds 	/* Apply the obio ranges to the timer registers. */
3151da177e4SLinus Torvalds 	prom_apply_obio_ranges(cnt_regs, reg_count);
3161da177e4SLinus Torvalds 
3171da177e4SLinus Torvalds 	cnt_regs[4].phys_addr = cnt_regs[reg_count-1].phys_addr;
3181da177e4SLinus Torvalds 	cnt_regs[4].reg_size = cnt_regs[reg_count-1].reg_size;
3191da177e4SLinus Torvalds 	cnt_regs[4].which_io = cnt_regs[reg_count-1].which_io;
3201da177e4SLinus Torvalds 	for(obio_node = 1; obio_node < 4; obio_node++) {
3211da177e4SLinus Torvalds 		cnt_regs[obio_node].phys_addr =
3221da177e4SLinus Torvalds 			cnt_regs[obio_node-1].phys_addr + PAGE_SIZE;
3231da177e4SLinus Torvalds 		cnt_regs[obio_node].reg_size = cnt_regs[obio_node-1].reg_size;
3241da177e4SLinus Torvalds 		cnt_regs[obio_node].which_io = cnt_regs[obio_node-1].which_io;
3251da177e4SLinus Torvalds 	}
3261da177e4SLinus Torvalds 
3271da177e4SLinus Torvalds 	memset((char*)&r, 0, sizeof(struct resource));
3281da177e4SLinus Torvalds 	/* Map the per-cpu Counter registers. */
3291da177e4SLinus Torvalds 	r.flags = cnt_regs[0].which_io;
3301da177e4SLinus Torvalds 	r.start = cnt_regs[0].phys_addr;
331*454eeb2dSDavid S. Miller 	sun4m_timers = (struct sun4m_timer_regs *) of_ioremap(&r, 0,
3321da177e4SLinus Torvalds 	    PAGE_SIZE*SUN4M_NCPUS, "sun4m_cpu_cnt");
3331da177e4SLinus Torvalds 	/* Map the system Counter register. */
3341da177e4SLinus Torvalds 	/* XXX Here we expect consequent calls to yeld adjusent maps. */
3351da177e4SLinus Torvalds 	r.flags = cnt_regs[4].which_io;
3361da177e4SLinus Torvalds 	r.start = cnt_regs[4].phys_addr;
337*454eeb2dSDavid S. Miller 	of_ioremap(&r, 0, cnt_regs[4].reg_size, "sun4m_sys_cnt");
3381da177e4SLinus Torvalds 
3391da177e4SLinus Torvalds 	sun4m_timers->l10_timer_limit =  (((1000000/HZ) + 1) << 10);
3401da177e4SLinus Torvalds 	master_l10_counter = &sun4m_timers->l10_cur_count;
3411da177e4SLinus Torvalds 	master_l10_limit = &sun4m_timers->l10_timer_limit;
3421da177e4SLinus Torvalds 
3431da177e4SLinus Torvalds 	irq = request_irq(TIMER_IRQ,
3441da177e4SLinus Torvalds 			  counter_fn,
34567413202SThomas Gleixner 			  (IRQF_DISABLED | SA_STATIC_ALLOC),
3461da177e4SLinus Torvalds 			  "timer", NULL);
3471da177e4SLinus Torvalds 	if (irq) {
3481da177e4SLinus Torvalds 		prom_printf("time_init: unable to attach IRQ%d\n",TIMER_IRQ);
3491da177e4SLinus Torvalds 		prom_halt();
3501da177e4SLinus Torvalds 	}
3511da177e4SLinus Torvalds 
3521da177e4SLinus Torvalds 	if (!cpu_find_by_instance(1, NULL, NULL)) {
3531da177e4SLinus Torvalds 		for(cpu = 0; cpu < 4; cpu++)
3541da177e4SLinus Torvalds 			sun4m_timers->cpu_timers[cpu].l14_timer_limit = 0;
3551da177e4SLinus Torvalds 		sun4m_interrupts->set = SUN4M_INT_E14;
3561da177e4SLinus Torvalds 	} else {
3571da177e4SLinus Torvalds 		sun4m_timers->cpu_timers[0].l14_timer_limit = 0;
3581da177e4SLinus Torvalds 	}
3591da177e4SLinus Torvalds #ifdef CONFIG_SMP
3601da177e4SLinus Torvalds 	{
3611da177e4SLinus Torvalds 		unsigned long flags;
3621da177e4SLinus Torvalds 		extern unsigned long lvl14_save[4];
3631da177e4SLinus Torvalds 		struct tt_entry *trap_table = &sparc_ttable[SP_TRAP_IRQ1 + (14 - 1)];
3641da177e4SLinus Torvalds 
3651da177e4SLinus Torvalds 		/* For SMP we use the level 14 ticker, however the bootup code
366d1a78c32SSimon Arlott 		 * has copied the firmware's level 14 vector into the boot cpu's
3671da177e4SLinus Torvalds 		 * trap table, we must fix this now or we get squashed.
3681da177e4SLinus Torvalds 		 */
3691da177e4SLinus Torvalds 		local_irq_save(flags);
3701da177e4SLinus Torvalds 		trap_table->inst_one = lvl14_save[0];
3711da177e4SLinus Torvalds 		trap_table->inst_two = lvl14_save[1];
3721da177e4SLinus Torvalds 		trap_table->inst_three = lvl14_save[2];
3731da177e4SLinus Torvalds 		trap_table->inst_four = lvl14_save[3];
3741da177e4SLinus Torvalds 		local_flush_cache_all();
3751da177e4SLinus Torvalds 		local_irq_restore(flags);
3761da177e4SLinus Torvalds 	}
3771da177e4SLinus Torvalds #endif
3781da177e4SLinus Torvalds }
3791da177e4SLinus Torvalds 
3801da177e4SLinus Torvalds void __init sun4m_init_IRQ(void)
3811da177e4SLinus Torvalds {
3821da177e4SLinus Torvalds 	int ie_node,i;
3831da177e4SLinus Torvalds 	struct linux_prom_registers int_regs[PROMREG_MAX];
3841da177e4SLinus Torvalds 	int num_regs;
3851da177e4SLinus Torvalds 	struct resource r;
3861da177e4SLinus Torvalds 	int mid;
3871da177e4SLinus Torvalds 
3881da177e4SLinus Torvalds 	local_irq_disable();
3891da177e4SLinus Torvalds 	if((ie_node = prom_searchsiblings(prom_getchild(prom_root_node), "obio")) == 0 ||
3901da177e4SLinus Torvalds 	   (ie_node = prom_getchild (ie_node)) == 0 ||
3911da177e4SLinus Torvalds 	   (ie_node = prom_searchsiblings (ie_node, "interrupt")) == 0) {
3921da177e4SLinus Torvalds 		prom_printf("Cannot find /obio/interrupt node\n");
3931da177e4SLinus Torvalds 		prom_halt();
3941da177e4SLinus Torvalds 	}
3951da177e4SLinus Torvalds 	num_regs = prom_getproperty(ie_node, "reg", (char *) int_regs,
3961da177e4SLinus Torvalds 				    sizeof(int_regs));
3971da177e4SLinus Torvalds 	num_regs = (num_regs/sizeof(struct linux_prom_registers));
3981da177e4SLinus Torvalds 
3991da177e4SLinus Torvalds 	/* Apply the obio ranges to these registers. */
4001da177e4SLinus Torvalds 	prom_apply_obio_ranges(int_regs, num_regs);
4011da177e4SLinus Torvalds 
4021da177e4SLinus Torvalds 	int_regs[4].phys_addr = int_regs[num_regs-1].phys_addr;
4031da177e4SLinus Torvalds 	int_regs[4].reg_size = int_regs[num_regs-1].reg_size;
4041da177e4SLinus Torvalds 	int_regs[4].which_io = int_regs[num_regs-1].which_io;
4051da177e4SLinus Torvalds 	for(ie_node = 1; ie_node < 4; ie_node++) {
4061da177e4SLinus Torvalds 		int_regs[ie_node].phys_addr = int_regs[ie_node-1].phys_addr + PAGE_SIZE;
4071da177e4SLinus Torvalds 		int_regs[ie_node].reg_size = int_regs[ie_node-1].reg_size;
4081da177e4SLinus Torvalds 		int_regs[ie_node].which_io = int_regs[ie_node-1].which_io;
4091da177e4SLinus Torvalds 	}
4101da177e4SLinus Torvalds 
4111da177e4SLinus Torvalds 	memset((char *)&r, 0, sizeof(struct resource));
4121da177e4SLinus Torvalds 	/* Map the interrupt registers for all possible cpus. */
4131da177e4SLinus Torvalds 	r.flags = int_regs[0].which_io;
4141da177e4SLinus Torvalds 	r.start = int_regs[0].phys_addr;
415*454eeb2dSDavid S. Miller 	sun4m_interrupts = (struct sun4m_intregs *) of_ioremap(&r, 0,
4161da177e4SLinus Torvalds 	    PAGE_SIZE*SUN4M_NCPUS, "interrupts_percpu");
4171da177e4SLinus Torvalds 
4181da177e4SLinus Torvalds 	/* Map the system interrupt control registers. */
4191da177e4SLinus Torvalds 	r.flags = int_regs[4].which_io;
4201da177e4SLinus Torvalds 	r.start = int_regs[4].phys_addr;
421*454eeb2dSDavid S. Miller 	of_ioremap(&r, 0, int_regs[4].reg_size, "interrupts_system");
4221da177e4SLinus Torvalds 
4231da177e4SLinus Torvalds 	sun4m_interrupts->set = ~SUN4M_INT_MASKALL;
4241da177e4SLinus Torvalds 	for (i = 0; !cpu_find_by_instance(i, NULL, &mid); i++)
4251da177e4SLinus Torvalds 		sun4m_interrupts->cpu_intregs[mid].clear = ~0x17fff;
4261da177e4SLinus Torvalds 
4271da177e4SLinus Torvalds 	if (!cpu_find_by_instance(1, NULL, NULL)) {
4281da177e4SLinus Torvalds 		/* system wide interrupts go to cpu 0, this should always
4291da177e4SLinus Torvalds 		 * be safe because it is guaranteed to be fitted or OBP doesn't
4301da177e4SLinus Torvalds 		 * come up
4311da177e4SLinus Torvalds 		 *
4321da177e4SLinus Torvalds 		 * Not sure, but writing here on SLAVIO systems may puke
4331da177e4SLinus Torvalds 		 * so I don't do it unless there is more than 1 cpu.
4341da177e4SLinus Torvalds 		 */
4351da177e4SLinus Torvalds 		irq_rcvreg = (unsigned long *)
4361da177e4SLinus Torvalds 				&sun4m_interrupts->undirected_target;
4371da177e4SLinus Torvalds 		sun4m_interrupts->undirected_target = 0;
4381da177e4SLinus Torvalds 	}
4391da177e4SLinus Torvalds 	BTFIXUPSET_CALL(enable_irq, sun4m_enable_irq, BTFIXUPCALL_NORM);
4401da177e4SLinus Torvalds 	BTFIXUPSET_CALL(disable_irq, sun4m_disable_irq, BTFIXUPCALL_NORM);
4411da177e4SLinus Torvalds 	BTFIXUPSET_CALL(enable_pil_irq, sun4m_enable_pil_irq, BTFIXUPCALL_NORM);
4421da177e4SLinus Torvalds 	BTFIXUPSET_CALL(disable_pil_irq, sun4m_disable_pil_irq, BTFIXUPCALL_NORM);
4431da177e4SLinus Torvalds 	BTFIXUPSET_CALL(clear_clock_irq, sun4m_clear_clock_irq, BTFIXUPCALL_NORM);
4441da177e4SLinus Torvalds 	BTFIXUPSET_CALL(clear_profile_irq, sun4m_clear_profile_irq, BTFIXUPCALL_NORM);
4451da177e4SLinus Torvalds 	BTFIXUPSET_CALL(load_profile_irq, sun4m_load_profile_irq, BTFIXUPCALL_NORM);
4461da177e4SLinus Torvalds 	sparc_init_timers = sun4m_init_timers;
4471da177e4SLinus Torvalds #ifdef CONFIG_SMP
4481da177e4SLinus Torvalds 	BTFIXUPSET_CALL(set_cpu_int, sun4m_send_ipi, BTFIXUPCALL_NORM);
4491da177e4SLinus Torvalds 	BTFIXUPSET_CALL(clear_cpu_int, sun4m_clear_ipi, BTFIXUPCALL_NORM);
4501da177e4SLinus Torvalds 	BTFIXUPSET_CALL(set_irq_udt, sun4m_set_udt, BTFIXUPCALL_NORM);
4511da177e4SLinus Torvalds #endif
4521da177e4SLinus Torvalds 	/* Cannot enable interrupts until OBP ticker is disabled. */
4531da177e4SLinus Torvalds }
454