intr_machdep.c revision 211811
1/*-
2 * Copyright (c) 2006-2009 RMI Corporation
3 * Copyright (c) 2002-2004 Juli Mallett <jmallett@FreeBSD.org>
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions, and the following disclaimer,
11 *    without modification, immediately at the beginning of the file.
12 * 2. The name of the author may not be used to endorse or promote products
13 *    derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
19 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 */
28
29#include <sys/cdefs.h>
30__FBSDID("$FreeBSD: head/sys/mips/rmi/intr_machdep.c 211811 2010-08-25 11:49:48Z jchandra $");
31
32#include <sys/param.h>
33#include <sys/systm.h>
34#include <sys/bus.h>
35#include <sys/interrupt.h>
36#include <sys/kernel.h>
37
38#include <machine/cpu.h>
39#include <machine/cpufunc.h>
40#include <machine/cpuinfo.h>
41#include <machine/cpuregs.h>
42#include <machine/frame.h>
43#include <machine/intr_machdep.h>
44#include <machine/md_var.h>
45#include <machine/trap.h>
46#include <machine/hwfunc.h>
47#include <mips/rmi/xlrconfig.h>
48#include <mips/rmi/interrupt.h>
49#include <mips/rmi/clock.h>
50#include <mips/rmi/pic.h>
51
52/*#include <machine/intrcnt.h>*/
53static mips_intrcnt_t mips_intr_counters[XLR_MAX_INTR];
54static struct intr_event *mips_intr_events[XLR_MAX_INTR];
55static int intrcnt_index;
56
57void
58xlr_mask_hard_irq(void *source)
59{
60	uintptr_t irq = (uintptr_t) source;
61
62	write_c0_eimr64(read_c0_eimr64() & ~(1ULL << irq));
63}
64
65void
66xlr_unmask_hard_irq(void *source)
67{
68	uintptr_t irq = (uintptr_t) source;
69
70	write_c0_eimr64(read_c0_eimr64() | (1ULL << irq));
71}
72
73void
74xlr_cpu_establish_hardintr(const char *name, driver_filter_t * filt,
75    void (*handler) (void *), void *arg, int irq, int flags, void **cookiep,
76    void (*pre_ithread)(void *), void (*post_ithread)(void *),
77    void (*post_filter)(void *), int (*assign_cpu)(void *, u_char))
78{
79	struct intr_event *ie;	/* descriptor for the IRQ */
80	int errcode;
81
82	if (irq < 0 || irq > XLR_MAX_INTR)
83		panic("%s called for unknown hard intr %d", __func__, irq);
84
85	/*
86	 * FIXME locking - not needed now, because we do this only on
87	 * startup from CPU0
88	 */
89	ie = mips_intr_events[irq];
90	/* mih->cntp = &intrcnt[irq]; */
91	if (ie == NULL) {
92		errcode = intr_event_create(&ie, (void *)(uintptr_t) irq, 0,
93		    irq, pre_ithread, post_ithread, post_filter, assign_cpu,
94		    "hard intr%d:", irq);
95
96		if (errcode) {
97			printf("Could not create event for intr %d\n", irq);
98			return;
99		}
100		mips_intr_events[irq] = ie;
101	}
102
103	intr_event_add_handler(ie, name, filt, handler, arg,
104	    intr_priority(flags), flags, cookiep);
105	xlr_unmask_hard_irq((void *)(uintptr_t) irq);
106}
107
108void
109cpu_establish_hardintr(const char *name, driver_filter_t * filt,
110    void (*handler) (void *), void *arg, int irq, int flags, void **cookiep)
111{
112	xlr_cpu_establish_hardintr(name, filt, handler, arg, irq,
113		flags, cookiep, xlr_mask_hard_irq, xlr_unmask_hard_irq,
114		NULL, NULL);
115}
116
117void
118cpu_establish_softintr(const char *name, driver_filter_t * filt,
119    void (*handler) (void *), void *arg, int irq, int flags,
120    void **cookiep)
121{
122	/* we don't separate them into soft/hard like other mips */
123	xlr_cpu_establish_hardintr(name, filt, handler, arg, irq,
124		flags, cookiep, xlr_mask_hard_irq, xlr_unmask_hard_irq,
125		NULL, NULL);
126}
127
128void
129cpu_intr(struct trapframe *tf)
130{
131	struct intr_event *ie;
132	uint64_t eirr, eimr;
133	int i;
134
135	critical_enter();
136
137	/* find a list of enabled interrupts */
138	eirr = read_c0_eirr64();
139	eimr = read_c0_eimr64();
140	eirr &= eimr;
141
142	if (eirr == 0) {
143		critical_exit();
144		return;
145	}
146	/*
147	 * No need to clear the EIRR here as the handler writes to
148	 * compare which ACKs the interrupt.
149	 */
150	if (eirr & (1 << IRQ_TIMER)) {
151		intr_event_handle(mips_intr_events[IRQ_TIMER], tf);
152		critical_exit();
153		return;
154	}
155
156	/* FIXME sched pin >? LOCK>? */
157	for (i = sizeof(eirr) * 8 - 1; i >= 0; i--) {
158		if ((eirr & (1ULL << i)) == 0)
159			continue;
160
161		ie = mips_intr_events[i];
162		/* Don't account special IRQs */
163		switch (i) {
164		case IRQ_IPI:
165		case IRQ_MSGRING:
166			break;
167		default:
168			mips_intrcnt_inc(mips_intr_counters[i]);
169		}
170		write_c0_eirr64(1ULL << i);
171		pic_ack(i);
172		if (!ie || TAILQ_EMPTY(&ie->ie_handlers)) {
173			printf("stray interrupt %d\n", i);
174			continue;
175		}
176		if (intr_event_handle(ie, tf) != 0) {
177			printf("stray interrupt %d\n", i);
178		}
179		pic_delayed_ack(i);
180	}
181	critical_exit();
182}
183
184void
185mips_intrcnt_setname(mips_intrcnt_t counter, const char *name)
186{
187	int idx = counter - intrcnt;
188
189	KASSERT(counter != NULL, ("mips_intrcnt_setname: NULL counter"));
190
191	snprintf(intrnames + (MAXCOMLEN + 1) * idx,
192	    MAXCOMLEN + 1, "%-*s", MAXCOMLEN, name);
193}
194
195mips_intrcnt_t
196mips_intrcnt_create(const char* name)
197{
198	mips_intrcnt_t counter = &intrcnt[intrcnt_index++];
199
200	mips_intrcnt_setname(counter, name);
201	return counter;
202}
203
204void
205cpu_init_interrupts()
206{
207	int i;
208	char name[MAXCOMLEN + 1];
209
210	/*
211	 * Initialize all available vectors so spare IRQ
212	 * would show up in systat output
213	 */
214	for (i = 0; i < XLR_MAX_INTR; i++) {
215		snprintf(name, MAXCOMLEN + 1, "int%d:", i);
216		mips_intr_counters[i] = mips_intrcnt_create(name);
217	}
218}
219