188278ca27a43ae503572b52ea2c171fbf45db5a2Adrian Bunk/*
2e54f8548ff5285f57125c08d8092eec38dd05e0dSam Ravnborg * SS1000/SC2000 interrupt handling.
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Heavily based on arch/sparc/kernel/irq.c.
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel_stat.h>
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/seq_file.h>
10e54f8548ff5285f57125c08d8092eec38dd05e0dSam Ravnborg
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/timer.h>
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/traps.h>
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/irq.h>
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h>
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/sbi.h>
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/cacheflush.h>
175fcafb7a23e35b2f1a5243f4dd536240f52c8cebDaniel Hellstrom#include <asm/setup.h>
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1981265fd93bc40c7c43fd36796571786ae3df00e0Sam Ravnborg#include "kernel.h"
2032231a66b4e1b649c346dc76b7d191f7e64a663aAl Viro#include "irq.h"
2132231a66b4e1b649c346dc76b7d191f7e64a663aAl Viro
22e54f8548ff5285f57125c08d8092eec38dd05e0dSam Ravnborg/* Sun4d interrupts fall roughly into two categories.  SBUS and
23e54f8548ff5285f57125c08d8092eec38dd05e0dSam Ravnborg * cpu local.  CPU local interrupts cover the timer interrupts
24e54f8548ff5285f57125c08d8092eec38dd05e0dSam Ravnborg * and whatnot, and we encode those as normal PILs between
25e54f8548ff5285f57125c08d8092eec38dd05e0dSam Ravnborg * 0 and 15.
266baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg * SBUS interrupts are encodes as a combination of board, level and slot.
27e54f8548ff5285f57125c08d8092eec38dd05e0dSam Ravnborg */
28e54f8548ff5285f57125c08d8092eec38dd05e0dSam Ravnborg
296baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborgstruct sun4d_handler_data {
306baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg	unsigned int cpuid;    /* target cpu */
316baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg	unsigned int real_irq; /* interrupt level */
326baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg};
336baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg
346baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg
356baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborgstatic unsigned int sun4d_encode_irq(int board, int lvl, int slot)
366baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg{
376baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg	return (board + 1) << 5 | (lvl << 2) | slot;
386baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg}
396baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg
40f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Millerstruct sun4d_timer_regs {
41f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Miller	u32	l10_timer_limit;
42f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Miller	u32	l10_cur_countx;
43f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Miller	u32	l10_limit_noclear;
44f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Miller	u32	ctrl;
45f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Miller	u32	l10_cur_count;
46f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Miller};
47f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Miller
48f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Millerstatic struct sun4d_timer_regs __iomem *sun4d_timers;
49f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Miller
506baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg#define SUN4D_TIMER_IRQ        10
51db1cdd146a0814b6f312fe1a7fa1ab87ac177b2aSam Ravnborg
52db1cdd146a0814b6f312fe1a7fa1ab87ac177b2aSam Ravnborg/* Specify which cpu handle interrupts from which board.
53db1cdd146a0814b6f312fe1a7fa1ab87ac177b2aSam Ravnborg * Index is board - value is cpu.
54db1cdd146a0814b6f312fe1a7fa1ab87ac177b2aSam Ravnborg */
55db1cdd146a0814b6f312fe1a7fa1ab87ac177b2aSam Ravnborgstatic unsigned char board_to_cpu[32];
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pil_to_sbus[] = {
58e54f8548ff5285f57125c08d8092eec38dd05e0dSam Ravnborg	0,
59e54f8548ff5285f57125c08d8092eec38dd05e0dSam Ravnborg	0,
60e54f8548ff5285f57125c08d8092eec38dd05e0dSam Ravnborg	1,
61e54f8548ff5285f57125c08d8092eec38dd05e0dSam Ravnborg	2,
62e54f8548ff5285f57125c08d8092eec38dd05e0dSam Ravnborg	0,
63e54f8548ff5285f57125c08d8092eec38dd05e0dSam Ravnborg	3,
64e54f8548ff5285f57125c08d8092eec38dd05e0dSam Ravnborg	0,
65e54f8548ff5285f57125c08d8092eec38dd05e0dSam Ravnborg	4,
66e54f8548ff5285f57125c08d8092eec38dd05e0dSam Ravnborg	0,
67e54f8548ff5285f57125c08d8092eec38dd05e0dSam Ravnborg	5,
68e54f8548ff5285f57125c08d8092eec38dd05e0dSam Ravnborg	0,
69e54f8548ff5285f57125c08d8092eec38dd05e0dSam Ravnborg	6,
70e54f8548ff5285f57125c08d8092eec38dd05e0dSam Ravnborg	0,
71e54f8548ff5285f57125c08d8092eec38dd05e0dSam Ravnborg	7,
72e54f8548ff5285f57125c08d8092eec38dd05e0dSam Ravnborg	0,
73e54f8548ff5285f57125c08d8092eec38dd05e0dSam Ravnborg	0,
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
76f8376e933c4e80663f6f66a5b5dd90390a0feba2David S. Miller/* Exported for sun4d_smp.c */
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsDEFINE_SPINLOCK(sun4d_imsk_lock);
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
796baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg/* SBUS interrupts are encoded integers including the board number
806baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg * (plus one), the SBUS level, and the SBUS slot number.  Sun4D
816baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg * IRQ dispatch is done by:
826baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg *
836baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg * 1) Reading the BW local interrupt table in order to get the bus
846baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg *    interrupt mask.
856baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg *
866baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg *    This table is indexed by SBUS interrupt level which can be
876baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg *    derived from the PIL we got interrupted on.
886baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg *
896baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg * 2) For each bus showing interrupt pending from #1, read the
906baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg *    SBI interrupt state register.  This will indicate which slots
916baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg *    have interrupts pending for that SBUS interrupt level.
926baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg *
936baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg * 3) Call the genreric IRQ support.
946baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg */
956baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborgstatic void sun4d_sbus_handler_irq(int sbusl)
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
976baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg	unsigned int bus_mask;
986baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg	unsigned int sbino, slot;
996baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg	unsigned int sbil;
1006baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg
1016baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg	bus_mask = bw_get_intr_mask(sbusl) & 0x3ffff;
1026baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg	bw_clear_intr_mask(sbusl, bus_mask);
1036baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg
1046baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg	sbil = (sbusl << 2);
1056baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg	/* Loop for each pending SBI */
106ea160584574e345495e75ee4a7d3a7dbcad9e16coftedal	for (sbino = 0; bus_mask; sbino++, bus_mask >>= 1) {
1076baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg		unsigned int idx, mask;
1086baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg
1096baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg		if (!(bus_mask & 1))
1106baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg			continue;
1116baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg		/* XXX This seems to ACK the irq twice.  acquire_sbi()
1126baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg		 * XXX uses swap, therefore this writes 0xf << sbil,
1136baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg		 * XXX then later release_sbi() will write the individual
1146baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg		 * XXX bits which were set again.
1156baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg		 */
1166baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg		mask = acquire_sbi(SBI2DEVID(sbino), 0xf << sbil);
1176baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg		mask &= (0xf << sbil);
1186baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg
1196baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg		/* Loop for each pending SBI slot */
1206baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg		slot = (1 << sbil);
121ea160584574e345495e75ee4a7d3a7dbcad9e16coftedal		for (idx = 0; mask != 0; idx++, slot <<= 1) {
1226baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg			unsigned int pil;
1236baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg			struct irq_bucket *p;
1246baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg
1256baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg			if (!(mask & slot))
1266baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg				continue;
1276baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg
1286baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg			mask &= ~slot;
129ea160584574e345495e75ee4a7d3a7dbcad9e16coftedal			pil = sun4d_encode_irq(sbino, sbusl, idx);
1306baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg
1316baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg			p = irq_map[pil];
1326baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg			while (p) {
1336baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg				struct irq_bucket *next;
1346baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg
1356baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg				next = p->next;
1366baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg				generic_handle_irq(p->irq);
1376baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg				p = next;
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
1396baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg			release_sbi(SBI2DEVID(sbino), slot);
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
144e54f8548ff5285f57125c08d8092eec38dd05e0dSam Ravnborgvoid sun4d_handler_irq(int pil, struct pt_regs *regs)
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1460d84438d98777b0f9425d39121c42f47a06878caAl Viro	struct pt_regs *old_regs;
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* SBUS IRQ level (1 - 7) */
148d4d1ec48c4b1568338931bf8e7833543b78ec9d5Sam Ravnborg	int sbusl = pil_to_sbus[pil];
149e54f8548ff5285f57125c08d8092eec38dd05e0dSam Ravnborg
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* FIXME: Is this necessary?? */
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cc_get_ipen();
152e54f8548ff5285f57125c08d8092eec38dd05e0dSam Ravnborg
153d4d1ec48c4b1568338931bf8e7833543b78ec9d5Sam Ravnborg	cc_set_iclr(1 << pil);
154e54f8548ff5285f57125c08d8092eec38dd05e0dSam Ravnborg
15555dd23eca666876e6028aa35d5e391cfced54871Daniel Hellstrom#ifdef CONFIG_SMP
15655dd23eca666876e6028aa35d5e391cfced54871Daniel Hellstrom	/*
15755dd23eca666876e6028aa35d5e391cfced54871Daniel Hellstrom	 * Check IPI data structures after IRQ has been cleared. Hard and Soft
15855dd23eca666876e6028aa35d5e391cfced54871Daniel Hellstrom	 * IRQ can happen at the same time, so both cases are always handled.
15955dd23eca666876e6028aa35d5e391cfced54871Daniel Hellstrom	 */
16055dd23eca666876e6028aa35d5e391cfced54871Daniel Hellstrom	if (pil == SUN4D_IPI_IRQ)
16155dd23eca666876e6028aa35d5e391cfced54871Daniel Hellstrom		sun4d_ipi_interrupt();
16255dd23eca666876e6028aa35d5e391cfced54871Daniel Hellstrom#endif
16355dd23eca666876e6028aa35d5e391cfced54871Daniel Hellstrom
1640d84438d98777b0f9425d39121c42f47a06878caAl Viro	old_regs = set_irq_regs(regs);
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	irq_enter();
1666baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg	if (sbusl == 0) {
1676baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg		/* cpu interrupt */
1686baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg		struct irq_bucket *p;
1696baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg
1706baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg		p = irq_map[pil];
1716baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg		while (p) {
1726baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg			struct irq_bucket *next;
1736baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg
1746baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg			next = p->next;
1756baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg			generic_handle_irq(p->irq);
1766baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg			p = next;
1776baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg		}
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
1796baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg		/* SBUS interrupt */
1806baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg		sun4d_sbus_handler_irq(sbusl);
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	irq_exit();
1830d84438d98777b0f9425d39121c42f47a06878caAl Viro	set_irq_regs(old_regs);
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1866baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg
1876baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborgstatic void sun4d_mask_irq(struct irq_data *data)
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1896baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg	struct sun4d_handler_data *handler_data = data->handler_data;
1906baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg	unsigned int real_irq;
1916baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg#ifdef CONFIG_SMP
1926baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg	int cpuid = handler_data->cpuid;
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
1946baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg#endif
1956baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg	real_irq = handler_data->real_irq;
1966baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg#ifdef CONFIG_SMP
1976baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg	spin_lock_irqsave(&sun4d_imsk_lock, flags);
1986baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg	cc_set_imsk_other(cpuid, cc_get_imsk_other(cpuid) | (1 << real_irq));
1996baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg	spin_unlock_irqrestore(&sun4d_imsk_lock, flags);
2006baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg#else
2016baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg	cc_set_imsk(cc_get_imsk() | (1 << real_irq));
2026baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg#endif
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2056baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborgstatic void sun4d_unmask_irq(struct irq_data *data)
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2076baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg	struct sun4d_handler_data *handler_data = data->handler_data;
2086baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg	unsigned int real_irq;
2096baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg#ifdef CONFIG_SMP
2106baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg	int cpuid = handler_data->cpuid;
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
2126baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg#endif
2136baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg	real_irq = handler_data->real_irq;
214e54f8548ff5285f57125c08d8092eec38dd05e0dSam Ravnborg
2156baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg#ifdef CONFIG_SMP
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&sun4d_imsk_lock, flags);
217ea160584574e345495e75ee4a7d3a7dbcad9e16coftedal	cc_set_imsk_other(cpuid, cc_get_imsk_other(cpuid) & ~(1 << real_irq));
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&sun4d_imsk_lock, flags);
2196baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg#else
220ea160584574e345495e75ee4a7d3a7dbcad9e16coftedal	cc_set_imsk(cc_get_imsk() & ~(1 << real_irq));
2216baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg#endif
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2246baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborgstatic unsigned int sun4d_startup_irq(struct irq_data *data)
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2266baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg	irq_link(data->irq);
2276baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg	sun4d_unmask_irq(data);
2286baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg	return 0;
2296baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg}
230f8376e933c4e80663f6f66a5b5dd90390a0feba2David S. Miller
2316baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborgstatic void sun4d_shutdown_irq(struct irq_data *data)
2326baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg{
2336baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg	sun4d_mask_irq(data);
2346baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg	irq_unlink(data->irq);
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2376baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborgstruct irq_chip sun4d_irq = {
2386baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg	.name		= "sun4d",
2396baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg	.irq_startup	= sun4d_startup_irq,
2406baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg	.irq_shutdown	= sun4d_shutdown_irq,
2416baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg	.irq_unmask	= sun4d_unmask_irq,
2426baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg	.irq_mask	= sun4d_mask_irq,
2436baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg};
2446baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_SMP
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void sun4d_set_cpu_int(int cpu, int level)
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sun4d_send_ipi(cpu, level);
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void sun4d_clear_ipi(int cpu, int level)
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void sun4d_set_udt(int cpu)
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Setup IRQ distribution scheme. */
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid __init sun4d_distribute_irqs(void)
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
26271d3721189c0f4fad105a81e052bddfb826b693bDavid S. Miller	struct device_node *dp;
26371d3721189c0f4fad105a81e052bddfb826b693bDavid S. Miller
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int cpuid = cpu_logical_map(1);
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cpuid == -1)
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cpuid = cpu_logical_map(0);
26871d3721189c0f4fad105a81e052bddfb826b693bDavid S. Miller	for_each_node_by_name(dp, "sbi") {
26971d3721189c0f4fad105a81e052bddfb826b693bDavid S. Miller		int devid = of_getintprop_default(dp, "device-id", 0);
27071d3721189c0f4fad105a81e052bddfb826b693bDavid S. Miller		int board = of_getintprop_default(dp, "board#", 0);
271db1cdd146a0814b6f312fe1a7fa1ab87ac177b2aSam Ravnborg		board_to_cpu[board] = cpuid;
27271d3721189c0f4fad105a81e052bddfb826b693bDavid S. Miller		set_sbi_tid(devid, cpuid << 3);
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
274e54f8548ff5285f57125c08d8092eec38dd05e0dSam Ravnborg	printk(KERN_ERR "All sbus IRQs directed to CPU%d\n", cpuid);
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
277e54f8548ff5285f57125c08d8092eec38dd05e0dSam Ravnborg
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void sun4d_clear_clock_irq(void)
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
280f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Miller	sbus_readl(&sun4d_timers->l10_timer_limit);
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void sun4d_load_profile_irq(int cpu, unsigned int limit)
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bw_set_prof_limit(cpu, limit);
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
288f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Millerstatic void __init sun4d_load_profile_irqs(void)
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
290f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Miller	int cpu = 0, mid;
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
292f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Miller	while (!cpu_find_by_instance(cpu, NULL, &mid)) {
293f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Miller		sun4d_load_profile_irq(mid >> 3, 0);
294f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Miller		cpu++;
295f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Miller	}
296f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Miller}
297f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Miller
2985fba17084e5d1b00bf24e17b2b580cfa7705e7beoftedalunsigned int _sun4d_build_device_irq(unsigned int real_irq,
2995fba17084e5d1b00bf24e17b2b580cfa7705e7beoftedal                                     unsigned int pil,
3005fba17084e5d1b00bf24e17b2b580cfa7705e7beoftedal                                     unsigned int board)
3015fba17084e5d1b00bf24e17b2b580cfa7705e7beoftedal{
3025fba17084e5d1b00bf24e17b2b580cfa7705e7beoftedal	struct sun4d_handler_data *handler_data;
3035fba17084e5d1b00bf24e17b2b580cfa7705e7beoftedal	unsigned int irq;
3045fba17084e5d1b00bf24e17b2b580cfa7705e7beoftedal
3055fba17084e5d1b00bf24e17b2b580cfa7705e7beoftedal	irq = irq_alloc(real_irq, pil);
3065fba17084e5d1b00bf24e17b2b580cfa7705e7beoftedal	if (irq == 0) {
3075fba17084e5d1b00bf24e17b2b580cfa7705e7beoftedal		prom_printf("IRQ: allocate for %d %d %d failed\n",
3085fba17084e5d1b00bf24e17b2b580cfa7705e7beoftedal			real_irq, pil, board);
3095fba17084e5d1b00bf24e17b2b580cfa7705e7beoftedal		goto err_out;
3105fba17084e5d1b00bf24e17b2b580cfa7705e7beoftedal	}
3115fba17084e5d1b00bf24e17b2b580cfa7705e7beoftedal
3125fba17084e5d1b00bf24e17b2b580cfa7705e7beoftedal	handler_data = irq_get_handler_data(irq);
3135fba17084e5d1b00bf24e17b2b580cfa7705e7beoftedal	if (unlikely(handler_data))
3145fba17084e5d1b00bf24e17b2b580cfa7705e7beoftedal		goto err_out;
3155fba17084e5d1b00bf24e17b2b580cfa7705e7beoftedal
3165fba17084e5d1b00bf24e17b2b580cfa7705e7beoftedal	handler_data = kzalloc(sizeof(struct sun4d_handler_data), GFP_ATOMIC);
3175fba17084e5d1b00bf24e17b2b580cfa7705e7beoftedal	if (unlikely(!handler_data)) {
3185fba17084e5d1b00bf24e17b2b580cfa7705e7beoftedal		prom_printf("IRQ: kzalloc(sun4d_handler_data) failed.\n");
3195fba17084e5d1b00bf24e17b2b580cfa7705e7beoftedal		prom_halt();
3205fba17084e5d1b00bf24e17b2b580cfa7705e7beoftedal	}
3215fba17084e5d1b00bf24e17b2b580cfa7705e7beoftedal	handler_data->cpuid    = board_to_cpu[board];
3225fba17084e5d1b00bf24e17b2b580cfa7705e7beoftedal	handler_data->real_irq = real_irq;
3235fba17084e5d1b00bf24e17b2b580cfa7705e7beoftedal	irq_set_chip_and_handler_name(irq, &sun4d_irq,
3245fba17084e5d1b00bf24e17b2b580cfa7705e7beoftedal	                              handle_level_irq, "level");
3255fba17084e5d1b00bf24e17b2b580cfa7705e7beoftedal	irq_set_handler_data(irq, handler_data);
3265fba17084e5d1b00bf24e17b2b580cfa7705e7beoftedal
3275fba17084e5d1b00bf24e17b2b580cfa7705e7beoftedalerr_out:
3285fba17084e5d1b00bf24e17b2b580cfa7705e7beoftedal	return irq;
3295fba17084e5d1b00bf24e17b2b580cfa7705e7beoftedal}
3305fba17084e5d1b00bf24e17b2b580cfa7705e7beoftedal
3315fba17084e5d1b00bf24e17b2b580cfa7705e7beoftedal
3325fba17084e5d1b00bf24e17b2b580cfa7705e7beoftedal
3331d05995b0880b23353741d5b2b826f7c2fd6a296Sam Ravnborgunsigned int sun4d_build_device_irq(struct platform_device *op,
3341d05995b0880b23353741d5b2b826f7c2fd6a296Sam Ravnborg                                    unsigned int real_irq)
3351d05995b0880b23353741d5b2b826f7c2fd6a296Sam Ravnborg{
3361d05995b0880b23353741d5b2b826f7c2fd6a296Sam Ravnborg	struct device_node *dp = op->dev.of_node;
3379eeb08986f41c0740306f6f56cf04e619e2fe525oftedal	struct device_node *board_parent, *bus = dp->parent;
3389eeb08986f41c0740306f6f56cf04e619e2fe525oftedal	char *bus_connection;
3391d05995b0880b23353741d5b2b826f7c2fd6a296Sam Ravnborg	const struct linux_prom_registers *regs;
3406baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg	unsigned int pil;
3416baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg	unsigned int irq;
3421d05995b0880b23353741d5b2b826f7c2fd6a296Sam Ravnborg	int board, slot;
3431d05995b0880b23353741d5b2b826f7c2fd6a296Sam Ravnborg	int sbusl;
3441d05995b0880b23353741d5b2b826f7c2fd6a296Sam Ravnborg
3455fba17084e5d1b00bf24e17b2b580cfa7705e7beoftedal	irq = real_irq;
3469eeb08986f41c0740306f6f56cf04e619e2fe525oftedal	while (bus) {
3479eeb08986f41c0740306f6f56cf04e619e2fe525oftedal		if (!strcmp(bus->name, "sbi")) {
3489eeb08986f41c0740306f6f56cf04e619e2fe525oftedal			bus_connection = "io-unit";
3491d05995b0880b23353741d5b2b826f7c2fd6a296Sam Ravnborg			break;
3509eeb08986f41c0740306f6f56cf04e619e2fe525oftedal		}
3519eeb08986f41c0740306f6f56cf04e619e2fe525oftedal
3529eeb08986f41c0740306f6f56cf04e619e2fe525oftedal		if (!strcmp(bus->name, "bootbus")) {
3539eeb08986f41c0740306f6f56cf04e619e2fe525oftedal			bus_connection = "cpu-unit";
3549eeb08986f41c0740306f6f56cf04e619e2fe525oftedal			break;
3559eeb08986f41c0740306f6f56cf04e619e2fe525oftedal		}
3561d05995b0880b23353741d5b2b826f7c2fd6a296Sam Ravnborg
3579eeb08986f41c0740306f6f56cf04e619e2fe525oftedal		bus = bus->parent;
3581d05995b0880b23353741d5b2b826f7c2fd6a296Sam Ravnborg	}
3599eeb08986f41c0740306f6f56cf04e619e2fe525oftedal	if (!bus)
3601d05995b0880b23353741d5b2b826f7c2fd6a296Sam Ravnborg		goto err_out;
3611d05995b0880b23353741d5b2b826f7c2fd6a296Sam Ravnborg
3621d05995b0880b23353741d5b2b826f7c2fd6a296Sam Ravnborg	regs = of_get_property(dp, "reg", NULL);
3631d05995b0880b23353741d5b2b826f7c2fd6a296Sam Ravnborg	if (!regs)
3641d05995b0880b23353741d5b2b826f7c2fd6a296Sam Ravnborg		goto err_out;
3651d05995b0880b23353741d5b2b826f7c2fd6a296Sam Ravnborg
3661d05995b0880b23353741d5b2b826f7c2fd6a296Sam Ravnborg	slot = regs->which_io;
3671d05995b0880b23353741d5b2b826f7c2fd6a296Sam Ravnborg
3681d05995b0880b23353741d5b2b826f7c2fd6a296Sam Ravnborg	/*
3699eeb08986f41c0740306f6f56cf04e619e2fe525oftedal	 * If Bus nodes parent is not io-unit/cpu-unit or the io-unit/cpu-unit
3709eeb08986f41c0740306f6f56cf04e619e2fe525oftedal	 * lacks a "board#" property, something is very wrong.
3711d05995b0880b23353741d5b2b826f7c2fd6a296Sam Ravnborg	 */
3729eeb08986f41c0740306f6f56cf04e619e2fe525oftedal	if (!bus->parent || strcmp(bus->parent->name, bus_connection)) {
3739eeb08986f41c0740306f6f56cf04e619e2fe525oftedal		printk(KERN_ERR "%s: Error, parent is not %s.\n",
3749eeb08986f41c0740306f6f56cf04e619e2fe525oftedal			bus->full_name, bus_connection);
3751d05995b0880b23353741d5b2b826f7c2fd6a296Sam Ravnborg		goto err_out;
3761d05995b0880b23353741d5b2b826f7c2fd6a296Sam Ravnborg	}
3779eeb08986f41c0740306f6f56cf04e619e2fe525oftedal	board_parent = bus->parent;
3789eeb08986f41c0740306f6f56cf04e619e2fe525oftedal	board = of_getintprop_default(board_parent, "board#", -1);
3791d05995b0880b23353741d5b2b826f7c2fd6a296Sam Ravnborg	if (board == -1) {
3809eeb08986f41c0740306f6f56cf04e619e2fe525oftedal		printk(KERN_ERR "%s: Error, lacks board# property.\n",
3819eeb08986f41c0740306f6f56cf04e619e2fe525oftedal			board_parent->full_name);
3821d05995b0880b23353741d5b2b826f7c2fd6a296Sam Ravnborg		goto err_out;
3831d05995b0880b23353741d5b2b826f7c2fd6a296Sam Ravnborg	}
3841d05995b0880b23353741d5b2b826f7c2fd6a296Sam Ravnborg
3851d05995b0880b23353741d5b2b826f7c2fd6a296Sam Ravnborg	sbusl = pil_to_sbus[real_irq];
3861d05995b0880b23353741d5b2b826f7c2fd6a296Sam Ravnborg	if (sbusl)
3876baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg		pil = sun4d_encode_irq(board, sbusl, slot);
3886baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg	else
3896baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg		pil = real_irq;
3906baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg
3915fba17084e5d1b00bf24e17b2b580cfa7705e7beoftedal	irq = _sun4d_build_device_irq(real_irq, pil, board);
3921d05995b0880b23353741d5b2b826f7c2fd6a296Sam Ravnborgerr_out:
3935fba17084e5d1b00bf24e17b2b580cfa7705e7beoftedal	return irq;
3941d05995b0880b23353741d5b2b826f7c2fd6a296Sam Ravnborg}
3951d05995b0880b23353741d5b2b826f7c2fd6a296Sam Ravnborg
3965fba17084e5d1b00bf24e17b2b580cfa7705e7beoftedalunsigned int sun4d_build_timer_irq(unsigned int board, unsigned int real_irq)
3975fba17084e5d1b00bf24e17b2b580cfa7705e7beoftedal{
3985fba17084e5d1b00bf24e17b2b580cfa7705e7beoftedal	return _sun4d_build_device_irq(real_irq, real_irq, board);
3995fba17084e5d1b00bf24e17b2b580cfa7705e7beoftedal}
4005fba17084e5d1b00bf24e17b2b580cfa7705e7beoftedal
4015fba17084e5d1b00bf24e17b2b580cfa7705e7beoftedal
402f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Millerstatic void __init sun4d_fixup_trap_table(void)
403f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Miller{
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_SMP
405f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Miller	unsigned long flags;
406f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Miller	struct tt_entry *trap_table = &sparc_ttable[SP_TRAP_IRQ1 + (14 - 1)];
407f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Miller
408f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Miller	/* Adjust so that we jump directly to smp4d_ticker */
409f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Miller	lvl14_save[2] += smp4d_ticker - real_irq_entry;
410f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Miller
411f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Miller	/* For SMP we use the level 14 ticker, however the bootup code
412f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Miller	 * has copied the firmware's level 14 vector into the boot cpu's
413f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Miller	 * trap table, we must fix this now or we get squashed.
414f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Miller	 */
415f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Miller	local_irq_save(flags);
416f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Miller	patchme_maybe_smp_msg[0] = 0x01000000; /* NOP out the branch */
417f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Miller	trap_table->inst_one = lvl14_save[0];
418f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Miller	trap_table->inst_two = lvl14_save[1];
419f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Miller	trap_table->inst_three = lvl14_save[2];
420f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Miller	trap_table->inst_four = lvl14_save[3];
421f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Miller	local_flush_cache_all();
422f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Miller	local_irq_restore(flags);
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
424f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Miller}
425f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Miller
426f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Millerstatic void __init sun4d_init_timers(irq_handler_t counter_fn)
427f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Miller{
428f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Miller	struct device_node *dp;
429f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Miller	struct resource res;
4306baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg	unsigned int irq;
431f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Miller	const u32 *reg;
432f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Miller	int err;
4335fba17084e5d1b00bf24e17b2b580cfa7705e7beoftedal	int board;
434f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Miller
435f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Miller	dp = of_find_node_by_name(NULL, "cpu-unit");
436f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Miller	if (!dp) {
437f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Miller		prom_printf("sun4d_init_timers: Unable to find cpu-unit\n");
438f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Miller		prom_halt();
439f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Miller	}
440f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Miller
441f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Miller	/* Which cpu-unit we use is arbitrary, we can view the bootbus timer
442f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Miller	 * registers via any cpu's mapping.  The first 'reg' property is the
443f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Miller	 * bootbus.
444f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Miller	 */
445f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Miller	reg = of_get_property(dp, "reg", NULL);
446f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Miller	if (!reg) {
447f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Miller		prom_printf("sun4d_init_timers: No reg property\n");
448f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Miller		prom_halt();
449f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Miller	}
450f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Miller
4515fba17084e5d1b00bf24e17b2b580cfa7705e7beoftedal	board = of_getintprop_default(dp, "board#", -1);
4525fba17084e5d1b00bf24e17b2b580cfa7705e7beoftedal	if (board == -1) {
4535fba17084e5d1b00bf24e17b2b580cfa7705e7beoftedal		prom_printf("sun4d_init_timers: No board# property on cpu-unit\n");
4545fba17084e5d1b00bf24e17b2b580cfa7705e7beoftedal		prom_halt();
4555fba17084e5d1b00bf24e17b2b580cfa7705e7beoftedal	}
4565fba17084e5d1b00bf24e17b2b580cfa7705e7beoftedal
4575fba17084e5d1b00bf24e17b2b580cfa7705e7beoftedal	of_node_put(dp);
4585fba17084e5d1b00bf24e17b2b580cfa7705e7beoftedal
459f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Miller	res.start = reg[1];
460f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Miller	res.end = reg[2] - 1;
461f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Miller	res.flags = reg[0] & 0xff;
462f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Miller	sun4d_timers = of_ioremap(&res, BW_TIMER_LIMIT,
463f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Miller				  sizeof(struct sun4d_timer_regs), "user timer");
464f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Miller	if (!sun4d_timers) {
465f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Miller		prom_printf("sun4d_init_timers: Can't map timer regs\n");
466f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Miller		prom_halt();
467f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Miller	}
468f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Miller
469f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Miller	sbus_writel((((1000000/HZ) + 1) << 10), &sun4d_timers->l10_timer_limit);
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	master_l10_counter = &sun4d_timers->l10_cur_count;
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4735fba17084e5d1b00bf24e17b2b580cfa7705e7beoftedal	irq = sun4d_build_timer_irq(board, SUN4D_TIMER_IRQ);
4746baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg	err = request_irq(irq, counter_fn, IRQF_TIMER, "timer", NULL);
475f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Miller	if (err) {
476e54f8548ff5285f57125c08d8092eec38dd05e0dSam Ravnborg		prom_printf("sun4d_init_timers: request_irq() failed with %d\n",
477e54f8548ff5285f57125c08d8092eec38dd05e0dSam Ravnborg		             err);
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		prom_halt();
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
480f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Miller	sun4d_load_profile_irqs();
481f5f1085720c4799dd1437f78e28e40c8dd557bbaDavid S. Miller	sun4d_fixup_trap_table();
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid __init sun4d_init_sbi_irq(void)
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
48671d3721189c0f4fad105a81e052bddfb826b693bDavid S. Miller	struct device_node *dp;
4875fcafb7a23e35b2f1a5243f4dd536240f52c8cebDaniel Hellstrom	int target_cpu;
488f8376e933c4e80663f6f66a5b5dd90390a0feba2David S. Miller
489f8376e933c4e80663f6f66a5b5dd90390a0feba2David S. Miller	target_cpu = boot_cpu_id;
49071d3721189c0f4fad105a81e052bddfb826b693bDavid S. Miller	for_each_node_by_name(dp, "sbi") {
49171d3721189c0f4fad105a81e052bddfb826b693bDavid S. Miller		int devid = of_getintprop_default(dp, "device-id", 0);
49271d3721189c0f4fad105a81e052bddfb826b693bDavid S. Miller		int board = of_getintprop_default(dp, "board#", 0);
49371d3721189c0f4fad105a81e052bddfb826b693bDavid S. Miller		unsigned int mask;
49471d3721189c0f4fad105a81e052bddfb826b693bDavid S. Miller
495f8376e933c4e80663f6f66a5b5dd90390a0feba2David S. Miller		set_sbi_tid(devid, target_cpu << 3);
496db1cdd146a0814b6f312fe1a7fa1ab87ac177b2aSam Ravnborg		board_to_cpu[board] = target_cpu;
497f8376e933c4e80663f6f66a5b5dd90390a0feba2David S. Miller
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Get rid of pending irqs from PROM */
49971d3721189c0f4fad105a81e052bddfb826b693bDavid S. Miller		mask = acquire_sbi(devid, 0xffffffff);
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (mask) {
501e54f8548ff5285f57125c08d8092eec38dd05e0dSam Ravnborg			printk(KERN_ERR "Clearing pending IRQs %08x on SBI %d\n",
502e54f8548ff5285f57125c08d8092eec38dd05e0dSam Ravnborg			       mask, board);
50371d3721189c0f4fad105a81e052bddfb826b693bDavid S. Miller			release_sbi(devid, mask);
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid __init sun4d_init_IRQ(void)
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	local_irq_disable();
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BTFIXUPSET_CALL(clear_clock_irq, sun4d_clear_clock_irq, BTFIXUPCALL_NORM);
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BTFIXUPSET_CALL(load_profile_irq, sun4d_load_profile_irq, BTFIXUPCALL_NORM);
514bbdc2661eabddd442240533a66b2290f77d89cccSam Ravnborg
5156baa9b20a68a88c2fd751cbe8d7652009379351bSam Ravnborg	sparc_irq_config.init_timers      = sun4d_init_timers;
5161d05995b0880b23353741d5b2b826f7c2fd6a296Sam Ravnborg	sparc_irq_config.build_device_irq = sun4d_build_device_irq;
517bbdc2661eabddd442240533a66b2290f77d89cccSam Ravnborg
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_SMP
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BTFIXUPSET_CALL(set_cpu_int, sun4d_set_cpu_int, BTFIXUPCALL_NORM);
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BTFIXUPSET_CALL(clear_cpu_int, sun4d_clear_ipi, BTFIXUPCALL_NOP);
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BTFIXUPSET_CALL(set_irq_udt, sun4d_set_udt, BTFIXUPCALL_NOP);
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Cannot enable interrupts until OBP ticker is disabled. */
5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
525