1 /*-
2 * Copyright 2003-2011 Netlogic Microsystems (Netlogic). All rights
3 * reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in
13 * the documentation and/or other materials provided with the
14 * distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY Netlogic Microsystems ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 * THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * NETLOGIC_BSD */
29
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/bus.h>
36 #include <sys/interrupt.h>
37 #include <sys/kernel.h>
38
39 #include <machine/cpu.h>
40 #include <machine/cpufunc.h>
41 #include <machine/cpuinfo.h>
42 #include <machine/cpuregs.h>
43 #include <machine/frame.h>
44 #include <machine/intr_machdep.h>
45 #include <machine/md_var.h>
46 #include <machine/trap.h>
47 #include <machine/hwfunc.h>
48
49 #include <mips/nlm/hal/haldefs.h>
50 #include <mips/nlm/hal/iomap.h>
51 #include <mips/nlm/hal/mips-extns.h>
52 #include <mips/nlm/interrupt.h>
53 #include <mips/nlm/hal/pic.h>
54 #include <mips/nlm/xlp.h>
55
56 struct xlp_intrsrc {
57 void (*busack)(int); /* Additional ack */
58 struct intr_event *ie; /* event corresponding to intr */
59 int irq;
60 };
61
62 static struct xlp_intrsrc xlp_interrupts[XLR_MAX_INTR];
63 static mips_intrcnt_t mips_intr_counters[XLR_MAX_INTR];
64 static int intrcnt_index;
65
66 void
67 xlp_enable_irq(int irq)
68 {
69 uint64_t eimr;
70
71 eimr = nlm_read_c0_eimr();
72 nlm_write_c0_eimr(eimr | (1ULL << irq));
73 }
74
75 void
76 cpu_establish_softintr(const char *name, driver_filter_t * filt,
77 void (*handler) (void *), void *arg, int irq, int flags,
78 void **cookiep)
79 {
80
81 panic("Soft interrupts unsupported!\n");
82 }
83
84 void
85 cpu_establish_hardintr(const char *name, driver_filter_t * filt,
86 void (*handler) (void *), void *arg, int irq, int flags,
87 void **cookiep)
88 {
89
90 xlp_establish_intr(name, filt, handler, arg, irq, flags,
91 cookiep, NULL);
92 }
93
94 static void
95 xlp_post_filter(void *source)
96 {
97 struct xlp_intrsrc *src = source;
98
99 if (src->busack)
100 src->busack(src->irq);
101 nlm_pic_ack(xlp_pic_base, xlp_irq_to_irt(src->irq));
102 }
103
104 static void
105 xlp_pre_ithread(void *source)
106 {
107 struct xlp_intrsrc *src = source;
108
109 if (src->busack)
110 src->busack(src->irq);
111 }
112
113 static void
114 xlp_post_ithread(void *source)
115 {
116 struct xlp_intrsrc *src = source;
117
118 nlm_pic_ack(xlp_pic_base, xlp_irq_to_irt(src->irq));
119 }
120
121 void
122 xlp_establish_intr(const char *name, driver_filter_t filt,
123 driver_intr_t handler, void *arg, int irq, int flags,
124 void **cookiep, void (*busack)(int))
125 {
126 struct intr_event *ie; /* descriptor for the IRQ */
127 struct xlp_intrsrc *src = NULL;
128 int errcode;
129
130 if (irq < 0 || irq > XLR_MAX_INTR)
131 panic("%s called for unknown hard intr %d", __func__, irq);
132
133 /*
134 * FIXME locking - not needed now, because we do this only on
135 * startup from CPU0
136 */
137 src = &xlp_interrupts[irq];
138 ie = src->ie;
139 if (ie == NULL) {
140 /*
141 * PIC based interrupts need ack in PIC, and some SoC
142 * components need additional acks (e.g. PCI)
143 */
144 if (xlp_irq_is_picintr(irq))
145 errcode = intr_event_create(&ie, src, 0, irq,
146 xlp_pre_ithread, xlp_post_ithread, xlp_post_filter,
147 NULL, "hard intr%d:", irq);
148 else {
149 if (filt == NULL)
150 panic("Not supported - non filter percpu intr");
151 errcode = intr_event_create(&ie, src, 0, irq,
152 NULL, NULL, NULL, NULL, "hard intr%d:", irq);
153 }
154 if (errcode) {
155 printf("Could not create event for intr %d\n", irq);
156 return;
157 }
158 src->irq = irq;
159 src->busack = busack;
160 src->ie = ie;
161 }
162 intr_event_add_handler(ie, name, filt, handler, arg,
163 intr_priority(flags), flags, cookiep);
164 xlp_enable_irq(irq);
165 }
166
167 void
168 cpu_intr(struct trapframe *tf)
169 {
170 struct intr_event *ie;
171 uint64_t eirr, eimr;
172 int i;
173
174 critical_enter();
175
176 /* find a list of enabled interrupts */
177 eirr = nlm_read_c0_eirr();
178 eimr = nlm_read_c0_eimr();
179 eirr &= eimr;
180
181 if (eirr == 0) {
182 critical_exit();
183 return;
184 }
185 /*
186 * No need to clear the EIRR here as the handler writes to
187 * compare which ACKs the interrupt.
188 */
189 if (eirr & (1 << IRQ_TIMER)) {
190 intr_event_handle(xlp_interrupts[IRQ_TIMER].ie, tf);
191 critical_exit();
192 return;
193 }
194
195 /* FIXME sched pin >? LOCK>? */
196 for (i = sizeof(eirr) * 8 - 1; i >= 0; i--) {
197 if ((eirr & (1ULL << i)) == 0)
198 continue;
199
200 ie = xlp_interrupts[i].ie;
201 /* Don't account special IRQs */
202 switch (i) {
203 case IRQ_IPI:
204 case IRQ_MSGRING:
205 break;
206 default:
207 mips_intrcnt_inc(mips_intr_counters[i]);
208 }
209
210 /* Ack the IRQ on the CPU */
211 nlm_write_c0_eirr(1ULL << i);
212 if (intr_event_handle(ie, tf) != 0) {
213 printf("stray interrupt %d\n", i);
214 }
215 }
216 critical_exit();
217 }
218
219 void
220 mips_intrcnt_setname(mips_intrcnt_t counter, const char *name)
221 {
222 int idx = counter - intrcnt;
223
224 KASSERT(counter != NULL, ("mips_intrcnt_setname: NULL counter"));
225
226 snprintf(intrnames + (MAXCOMLEN + 1) * idx,
227 MAXCOMLEN + 1, "%-*s", MAXCOMLEN, name);
228 }
229
230 mips_intrcnt_t
231 mips_intrcnt_create(const char* name)
232 {
233 mips_intrcnt_t counter = &intrcnt[intrcnt_index++];
234
235 mips_intrcnt_setname(counter, name);
236 return counter;
237 }
238
239 void
240 cpu_init_interrupts()
241 {
242 int i;
243 char name[MAXCOMLEN + 1];
244
245 /*
246 * Initialize all available vectors so spare IRQ
247 * would show up in systat output
248 */
249 for (i = 0; i < XLR_MAX_INTR; i++) {
250 snprintf(name, MAXCOMLEN + 1, "int%d:", i);
251 mips_intr_counters[i] = mips_intrcnt_create(name);
252 }
253 }
Cache object: 2190febc81ac0da0f2ae3fa1d31a8992
|