intr_machdep.c revision 198484
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$");
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 <machine/intrcnt.h>
48
49struct mips_intrhand mips_intr_handlers[XLR_MAX_INTR];
50
51static void
52mips_mask_hard_irq(void *source)
53{
54	uintptr_t irq = (uintptr_t)source;
55
56	write_c0_eimr64(read_c0_eimr64() & ~(1ULL<<irq));
57}
58
59static void
60mips_unmask_hard_irq(void *source)
61{
62	uintptr_t irq = (uintptr_t)source;
63
64	write_c0_eimr64(read_c0_eimr64() | (1ULL<<irq));
65}
66
67void
68cpu_establish_hardintr(const char *name, driver_filter_t *filt,
69		   void (*handler)(void*), void *arg, int irq, int flags, void **cookiep)
70{
71	struct mips_intrhand *mih;      /* descriptor for the IRQ */
72	struct intr_event *ie;          /* descriptor for the IRQ */
73	int errcode;
74
75	if (intr < 0 || intr > XLR_MAX_INTR)
76		panic("%s called for unknown hard intr %d", __func__, intr);
77
78	/* FIXME locking - not needed now, because we do this only on startup from
79	   CPU0 */
80	mih = &mips_intr_handlers[irq];
81	mih->cntp = &intrcnt[irq];
82	ie = mih->mih_event;
83	if (ie == NULL) {
84		errcode = intr_event_create(&event, (void *)(uintptr_t)irq, 0,
85		    irq, mips_mask_hard_irq, mips_unmask_hard_irq,
86		    NULL, NULL, "hard intr%d:", irq);
87
88		if (errcode) {
89			printf("Could not create event for intr %d\n", irq);
90			return;
91		}
92	}
93	intr_event_add_handler(event, name, filt, handler, arg,
94	    intr_priority(flags), flags, cookiep);
95	mih->mih_event = ie;
96	mips_unmask_hard_irq((void*)(uintptr_t)irq);
97}
98
99
100void
101cpu_establish_softintr(const char *name, driver_filter_t *filt,
102    void (*handler)(void*), void *arg, int irq, int flags,
103    void **cookiep)
104{
105  /* we don't separate them into soft/hard like other mips */
106  cpu_establish_hardintr(name, filt, handler, arg, intr, flags, cookiep);
107}
108
109void
110cpu_intr(struct trapframe *tf)
111{
112	struct mips_intrhand *mih;
113	struct intr_handler *ih;
114	struct intr_event *ie;
115	register_t eirr;
116	int i, thread, error;
117
118	critical_enter();
119	eirr = read_c0_eirr64();
120	if (eirr == 0) {
121		critical_exit();
122		return;
123	}
124
125	/* No need to clear the EIRR here. the handler is gonna
126	 * write to compare which clears eirr also
127	 */
128	if (eirr & (1 << IRQ_TIMER)) {
129		count_compare_clockhandler(tf);
130		critical_exit();
131		return;
132	}
133
134	/* FIXME sched pin >? LOCK>? */
135	for(i = sizeof(eirr)*8 - 1; i>=0; i--) {
136		if ((eirr & 1ULL<<i) == 0)
137			continue;
138#ifdef SMP
139		/* These are reserved interrupts */
140		if((i == IPI_AST) || (i == IPI_RENDEZVOUS) || (i == IPI_STOP)
141		   || (i == IPI_SMP_CALL_FUNCTION)) {
142			write_c0_eirr64(1ULL << i);
143			pic_ack(i);
144			smp_handle_ipi(tf, i);
145			pic_delayed_ack(i);
146			continue;
147		}
148#ifdef XLR_PERFMON
149		if (i == IPI_PERFMON) {
150			write_c0_eirr64(1ULL << i);
151			pic_ack(i);
152			xlr_perfmon_sampler(NULL);
153			pic_delayed_ack(i);
154			continue;
155		}
156#endif
157#endif
158		mih = &mips_intr_handlers[i];
159		atomic_add_long(mih->cntp, 1);
160		ie  = mih->mih_event;
161
162		write_c0_eirr64(1ULL << i);
163		if (!ie || TAILQ_EMPTY(&ie->ie_handlers)) {
164			printf("stray interrupt %d\n", i);
165			continue;
166		}
167
168		if (intr_event_handle(ie, tf) != 0) {
169			printf("stray %s interrupt %d\n",
170			    hard ? "hard" : "soft", i);
171		}
172
173	}
174	critical_exit();
175}
176