octeon_intr.c revision 1.1 1 1.1 hikaru /* $NetBSD: octeon_intr.c,v 1.1 2015/04/29 08:32:00 hikaru Exp $ */
2 1.1 hikaru /*
3 1.1 hikaru * Copyright 2001, 2002 Wasabi Systems, Inc.
4 1.1 hikaru * All rights reserved.
5 1.1 hikaru *
6 1.1 hikaru * Written by Jason R. Thorpe and Simon Burge for Wasabi Systems, Inc.
7 1.1 hikaru *
8 1.1 hikaru * Redistribution and use in source and binary forms, with or without
9 1.1 hikaru * modification, are permitted provided that the following conditions
10 1.1 hikaru * are met:
11 1.1 hikaru * 1. Redistributions of source code must retain the above copyright
12 1.1 hikaru * notice, this list of conditions and the following disclaimer.
13 1.1 hikaru * 2. Redistributions in binary form must reproduce the above copyright
14 1.1 hikaru * notice, this list of conditions and the following disclaimer in the
15 1.1 hikaru * documentation and/or other materials provided with the distribution.
16 1.1 hikaru * 3. All advertising materials mentioning features or use of this software
17 1.1 hikaru * must display the following acknowledgement:
18 1.1 hikaru * This product includes software developed for the NetBSD Project by
19 1.1 hikaru * Wasabi Systems, Inc.
20 1.1 hikaru * 4. The name of Wasabi Systems, Inc. may not be used to endorse
21 1.1 hikaru * or promote products derived from this software without specific prior
22 1.1 hikaru * written permission.
23 1.1 hikaru *
24 1.1 hikaru * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
25 1.1 hikaru * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
26 1.1 hikaru * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
27 1.1 hikaru * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
28 1.1 hikaru * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 1.1 hikaru * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30 1.1 hikaru * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31 1.1 hikaru * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32 1.1 hikaru * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 1.1 hikaru * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 1.1 hikaru * POSSIBILITY OF SUCH DAMAGE.
35 1.1 hikaru */
36 1.1 hikaru
37 1.1 hikaru /*
38 1.1 hikaru * Platform-specific interrupt support for the MIPS Malta.
39 1.1 hikaru */
40 1.1 hikaru
41 1.1 hikaru #include "opt_octeon.h"
42 1.1 hikaru #define __INTR_PRIVATE
43 1.1 hikaru
44 1.1 hikaru #include <sys/cdefs.h>
45 1.1 hikaru __KERNEL_RCSID(0, "$NetBSD: octeon_intr.c,v 1.1 2015/04/29 08:32:00 hikaru Exp $");
46 1.1 hikaru
47 1.1 hikaru #include <sys/param.h>
48 1.1 hikaru #include <sys/cpu.h>
49 1.1 hikaru #include <sys/systm.h>
50 1.1 hikaru #include <sys/device.h>
51 1.1 hikaru #include <sys/intr.h>
52 1.1 hikaru #include <sys/kernel.h>
53 1.1 hikaru #include <sys/malloc.h>
54 1.1 hikaru
55 1.1 hikaru #include <lib/libkern/libkern.h>
56 1.1 hikaru
57 1.1 hikaru #include <mips/locore.h>
58 1.1 hikaru
59 1.1 hikaru #include <mips/cavium/dev/octeon_ciureg.h>
60 1.1 hikaru #include <mips/cavium/octeonvar.h>
61 1.1 hikaru
62 1.1 hikaru /*
63 1.1 hikaru * This is a mask of bits to clear in the SR when we go to a
64 1.1 hikaru * given hardware interrupt priority level.
65 1.1 hikaru */
66 1.1 hikaru static const struct ipl_sr_map octeon_ipl_sr_map = {
67 1.1 hikaru .sr_bits = {
68 1.1 hikaru [IPL_NONE] = 0,
69 1.1 hikaru [IPL_SOFTCLOCK] = MIPS_SOFT_INT_MASK_0,
70 1.1 hikaru [IPL_SOFTNET] = MIPS_SOFT_INT_MASK,
71 1.1 hikaru [IPL_VM] = MIPS_SOFT_INT_MASK | MIPS_INT_MASK_0,
72 1.1 hikaru [IPL_SCHED] = MIPS_SOFT_INT_MASK | MIPS_INT_MASK_0
73 1.1 hikaru | MIPS_INT_MASK_5,
74 1.1 hikaru [IPL_DDB] = MIPS_INT_MASK,
75 1.1 hikaru [IPL_HIGH] = MIPS_INT_MASK,
76 1.1 hikaru },
77 1.1 hikaru };
78 1.1 hikaru
79 1.1 hikaru #define NIRQS 64
80 1.1 hikaru
81 1.1 hikaru const char *octeon_intrnames[NIRQS] = {
82 1.1 hikaru "workq 0",
83 1.1 hikaru "workq 1",
84 1.1 hikaru "workq 2",
85 1.1 hikaru "workq 3",
86 1.1 hikaru "workq 4",
87 1.1 hikaru "workq 5",
88 1.1 hikaru "workq 6",
89 1.1 hikaru "workq 7",
90 1.1 hikaru "workq 8",
91 1.1 hikaru "workq 9",
92 1.1 hikaru "workq 10",
93 1.1 hikaru "workq 11",
94 1.1 hikaru "workq 12",
95 1.1 hikaru "workq 13",
96 1.1 hikaru "workq 14",
97 1.1 hikaru "workq 15",
98 1.1 hikaru "gpio 0",
99 1.1 hikaru "gpio 1",
100 1.1 hikaru "gpio 2",
101 1.1 hikaru "gpio 3",
102 1.1 hikaru "gpio 4",
103 1.1 hikaru "gpio 5",
104 1.1 hikaru "gpio 6",
105 1.1 hikaru "gpio 7",
106 1.1 hikaru "gpio 8",
107 1.1 hikaru "gpio 9",
108 1.1 hikaru "gpio 10",
109 1.1 hikaru "gpio 11",
110 1.1 hikaru "gpio 12",
111 1.1 hikaru "gpio 13",
112 1.1 hikaru "gpio 14",
113 1.1 hikaru "gpio 15",
114 1.1 hikaru "mbox 0-15",
115 1.1 hikaru "mbox 16-31",
116 1.1 hikaru "uart 0",
117 1.1 hikaru "uart 1",
118 1.1 hikaru "pci inta",
119 1.1 hikaru "pci intb",
120 1.1 hikaru "pci intc",
121 1.1 hikaru "pci intd",
122 1.1 hikaru "pci msi 0-15",
123 1.1 hikaru "pci msi 16-31",
124 1.1 hikaru "pci msi 32-47",
125 1.1 hikaru "pci msi 48-63",
126 1.1 hikaru "wdog summary",
127 1.1 hikaru "twsi",
128 1.1 hikaru "rml",
129 1.1 hikaru "trace",
130 1.1 hikaru "gmx drop",
131 1.1 hikaru "reserved",
132 1.1 hikaru "ipd drop",
133 1.1 hikaru "reserved",
134 1.1 hikaru "timer 0",
135 1.1 hikaru "timer 1",
136 1.1 hikaru "timer 2",
137 1.1 hikaru "timer 3",
138 1.1 hikaru "usb",
139 1.1 hikaru "pcm/tdm",
140 1.1 hikaru "mpi/spi",
141 1.1 hikaru "reserved",
142 1.1 hikaru "reserved",
143 1.1 hikaru "reserved",
144 1.1 hikaru "reserved",
145 1.1 hikaru "reserved",
146 1.1 hikaru };
147 1.1 hikaru
148 1.1 hikaru struct octeon_intrhand {
149 1.1 hikaru LIST_ENTRY(octeon_intrhand) ih_q;
150 1.1 hikaru int (*ih_func)(void *);
151 1.1 hikaru void *ih_arg;
152 1.1 hikaru int ih_irq;
153 1.1 hikaru int ih_ipl;
154 1.1 hikaru int ih_intr;
155 1.1 hikaru };
156 1.1 hikaru
157 1.1 hikaru struct octeon_intrhead {
158 1.1 hikaru LIST_HEAD(, octeon_intrhand) intr_list;
159 1.1 hikaru int intr_refcnt;
160 1.1 hikaru };
161 1.1 hikaru
162 1.1 hikaru struct octeon_intrhead octeon_ciu_intrtab[NIRQS];
163 1.1 hikaru
164 1.1 hikaru struct octeon_cpuintr {
165 1.1 hikaru LIST_HEAD(, octeon_intrhand) cintr_list;
166 1.1 hikaru struct evcnt cintr_count;
167 1.1 hikaru };
168 1.1 hikaru
169 1.1 hikaru #define NINTRS 5 /* MIPS INT0 - INT4 */
170 1.1 hikaru
171 1.1 hikaru struct octeon_cpuintr octeon_cpuintrs[NINTRS];
172 1.1 hikaru const char *octeon_cpuintrnames[NINTRS] = {
173 1.1 hikaru "int 0 (IP2)",
174 1.1 hikaru "int 1 (IP3)",
175 1.1 hikaru "int 2 ",
176 1.1 hikaru "int 3 ",
177 1.1 hikaru "int 4 ",
178 1.1 hikaru };
179 1.1 hikaru
180 1.1 hikaru
181 1.1 hikaru /* temporary interrupt enable bits */
182 1.1 hikaru uint64_t int0_enable0;
183 1.1 hikaru uint64_t int1_enable0;
184 1.1 hikaru
185 1.1 hikaru
186 1.1 hikaru #if 0
187 1.1 hikaru /*
188 1.1 hikaru * NOTE: This routine must be called with interrupts disabled in the CPSR.
189 1.1 hikaru */
190 1.1 hikaru static void
191 1.1 hikaru octeon_intr_calculate_masks(void)
192 1.1 hikaru {
193 1.1 hikaru struct octeon_intrhand *ih;
194 1.1 hikaru int level, ipl, irq;
195 1.1 hikaru
196 1.1 hikaru /* First, figure out which IPLs each INT has. */
197 1.1 hikaru for (level = 0; level < NINTRS; level++) {
198 1.1 hikaru int levels = 0;
199 1.1 hikaru
200 1.1 hikaru for (irq = 0; irq < NIRQS; irq++)
201 1.1 hikaru LIST_FOREACH(ih, &octeon_intrtab[irq].intr_list, ih_q)
202 1.1 hikaru if (ih->ih_intr == level)
203 1.1 hikaru levels |= 1 << ih->ih_ipl;
204 1.1 hikaru octeon_cpuintrs[level].cintr_levels = levels;
205 1.1 hikaru }
206 1.1 hikaru
207 1.1 hikaru /* Next, figure out which INTs are used by each IPL. */
208 1.1 hikaru for (ipl = 0; ipl < _IPL_N; ipl++) {
209 1.1 hikaru int irqs = 0;
210 1.1 hikaru
211 1.1 hikaru for (level = 0; level < NINTRS; level++)
212 1.1 hikaru if (1 << ipl & octeon_cpuintrs[level].cintr_levels)
213 1.1 hikaru irqs |= MIPS_INT_MASK_0 << level;
214 1.1 hikaru ipl_sr_bits[ipl] = irqs;
215 1.1 hikaru }
216 1.1 hikaru
217 1.1 hikaru /*
218 1.1 hikaru * IPL_CLOCK should mask clock interrupt even if interrupt handler
219 1.1 hikaru * is not registered.
220 1.1 hikaru */
221 1.1 hikaru ipl_sr_bits[IPL_CLOCK] |= MIPS_INT_MASK_5;
222 1.1 hikaru
223 1.1 hikaru /*
224 1.1 hikaru * IPL_NONE is used for hardware interrupts that are never blocked,
225 1.1 hikaru * and do not block anything else.
226 1.1 hikaru */
227 1.1 hikaru ipl_sr_bits[IPL_NONE] = 0;
228 1.1 hikaru
229 1.1 hikaru /*
230 1.1 hikaru * Initialize the soft interrupt masks to block themselves.
231 1.1 hikaru */
232 1.1 hikaru ipl_sr_bits[IPL_SOFTCLOCK] |= SI_TO_SRBIT(SI_SOFTCLOCK);
233 1.1 hikaru ipl_sr_bits[IPL_SOFTNET] |= SI_TO_SRBIT(SI_SOFTNET);
234 1.1 hikaru ipl_sr_bits[IPL_SOFTSERIAL] |= SI_TO_SRBIT(SI_SOFTSERIAL);
235 1.1 hikaru
236 1.1 hikaru /*
237 1.1 hikaru * Enforce a heirarchy that gives "slow" device (or devices with
238 1.1 hikaru * limited input buffer space/"real-time" requirements) a better
239 1.1 hikaru * chance at not dropping data.
240 1.1 hikaru */
241 1.1 hikaru for (ipl = 1; ipl < _IPL_N; ipl++)
242 1.1 hikaru ipl_sr_bits[ipl] |= ipl_sr_bits[ipl - 1];
243 1.1 hikaru
244 1.1 hikaru /*
245 1.1 hikaru * splhigh() must block "everything".
246 1.1 hikaru */
247 1.1 hikaru ipl_sr_bits[IPL_HIGH] = MIPS_INT_MASK;
248 1.1 hikaru
249 1.1 hikaru /*
250 1.1 hikaru * Now compute which INTs must be blocked when servicing any
251 1.1 hikaru * given INT.
252 1.1 hikaru */
253 1.1 hikaru for (level = 0; level < NINTRS; level++) {
254 1.1 hikaru int irqs = (MIPS_INT_MASK_0 << level);
255 1.1 hikaru
256 1.1 hikaru for (irq = 0; irq < NIRQS; irq++)
257 1.1 hikaru LIST_FOREACH(ih, &octeon_intrtab[irq].intr_list, ih_q)
258 1.1 hikaru if (ih->ih_intr == level)
259 1.1 hikaru irqs |= ipl_sr_bits[ih->ih_ipl];
260 1.1 hikaru octeon_cpuintrs[level].cintr_mask = irqs;
261 1.1 hikaru }
262 1.1 hikaru
263 1.1 hikaru // for (ipl = 0; ipl < _IPL_N; ipl++)
264 1.1 hikaru // printf("debug: ipl_sr_bits[%.2d] = %.8x\n", ipl, ipl_sr_bits[ipl]);
265 1.1 hikaru }
266 1.1 hikaru #endif
267 1.1 hikaru
268 1.1 hikaru void
269 1.1 hikaru octeon_intr_init(void)
270 1.1 hikaru {
271 1.1 hikaru ipl_sr_map = octeon_ipl_sr_map;
272 1.1 hikaru
273 1.1 hikaru octeon_write_csr(CIU_INT0_EN0, 0);
274 1.1 hikaru octeon_write_csr(CIU_INT1_EN0, 0);
275 1.1 hikaru octeon_write_csr(CIU_INT32_EN0, 0);
276 1.1 hikaru octeon_write_csr(CIU_INT0_EN1, 0);
277 1.1 hikaru octeon_write_csr(CIU_INT1_EN1, 0);
278 1.1 hikaru octeon_write_csr(CIU_INT32_EN1, 0);
279 1.1 hikaru
280 1.1 hikaru for (size_t i = 0; i < NINTRS; i++) {
281 1.1 hikaru LIST_INIT(&octeon_cpuintrs[i].cintr_list);
282 1.1 hikaru evcnt_attach_dynamic(&octeon_cpuintrs[i].cintr_count,
283 1.1 hikaru EVCNT_TYPE_INTR, NULL, "mips", octeon_cpuintrnames[i]);
284 1.1 hikaru }
285 1.1 hikaru
286 1.1 hikaru for (size_t i = 0; i < NIRQS; i++) {
287 1.1 hikaru LIST_INIT(&octeon_ciu_intrtab[i].intr_list);
288 1.1 hikaru octeon_ciu_intrtab[i].intr_refcnt = 0;
289 1.1 hikaru }
290 1.1 hikaru }
291 1.1 hikaru
292 1.1 hikaru void
293 1.1 hikaru octeon_cal_timer(int corefreq)
294 1.1 hikaru {
295 1.1 hikaru /* Compute the number of cycles per second. */
296 1.1 hikaru curcpu()->ci_cpu_freq = corefreq;
297 1.1 hikaru
298 1.1 hikaru /* Compute the number of ticks for hz. */
299 1.1 hikaru curcpu()->ci_cycles_per_hz = (curcpu()->ci_cpu_freq + hz / 2) / hz;
300 1.1 hikaru
301 1.1 hikaru /* Compute the delay divisor and reciprical. */
302 1.1 hikaru curcpu()->ci_divisor_delay =
303 1.1 hikaru ((curcpu()->ci_cpu_freq + 500000) / 1000000);
304 1.1 hikaru #if 0
305 1.1 hikaru MIPS_SET_CI_RECIPRICAL(curcpu());
306 1.1 hikaru #endif
307 1.1 hikaru
308 1.1 hikaru mips3_cp0_count_write(0);
309 1.1 hikaru mips3_cp0_compare_write(0);
310 1.1 hikaru }
311 1.1 hikaru
312 1.1 hikaru void *
313 1.1 hikaru octeon_intr_establish(int irq, int req, int level,
314 1.1 hikaru int (*func)(void *), void *arg)
315 1.1 hikaru {
316 1.1 hikaru struct octeon_intrhand *ih;
317 1.1 hikaru u_int64_t irq_mask;
318 1.1 hikaru int s;
319 1.1 hikaru
320 1.1 hikaru if (irq >= NIRQS)
321 1.1 hikaru panic("octeon_intr_establish: bogus IRQ %d", irq);
322 1.1 hikaru if (req > 1)
323 1.1 hikaru panic("octeon_intr_establish: bogus request %d", req);
324 1.1 hikaru
325 1.1 hikaru ih = malloc(sizeof(*ih), M_DEVBUF, M_NOWAIT);
326 1.1 hikaru if (ih == NULL)
327 1.1 hikaru return (NULL);
328 1.1 hikaru
329 1.1 hikaru ih->ih_func = func;
330 1.1 hikaru ih->ih_arg = arg;
331 1.1 hikaru ih->ih_irq = irq;
332 1.1 hikaru ih->ih_ipl = level;
333 1.1 hikaru ih->ih_intr = req;
334 1.1 hikaru
335 1.1 hikaru s = splhigh();
336 1.1 hikaru
337 1.1 hikaru /*
338 1.1 hikaru * First, link it into the tables.
339 1.1 hikaru * XXX do we want a separate list (really, should only be one item, not
340 1.1 hikaru * a list anyway) per irq, not per CPU interrupt?
341 1.1 hikaru */
342 1.1 hikaru LIST_INSERT_HEAD(&octeon_ciu_intrtab[irq].intr_list, ih, ih_q);
343 1.1 hikaru
344 1.1 hikaru /*
345 1.1 hikaru * Now enable it.
346 1.1 hikaru */
347 1.1 hikaru if (octeon_ciu_intrtab[irq].intr_refcnt++ == 0) {
348 1.1 hikaru irq_mask = 1ULL << irq;
349 1.1 hikaru
350 1.1 hikaru switch (req) {
351 1.1 hikaru case 0:
352 1.1 hikaru int0_enable0 |= irq_mask;
353 1.1 hikaru octeon_write_csr(CIU_INT0_EN0, int0_enable0);
354 1.1 hikaru break;
355 1.1 hikaru
356 1.1 hikaru case 1:
357 1.1 hikaru int1_enable0 |= irq_mask;
358 1.1 hikaru octeon_write_csr(CIU_INT1_EN0, int1_enable0);
359 1.1 hikaru break;
360 1.1 hikaru }
361 1.1 hikaru }
362 1.1 hikaru splx(s);
363 1.1 hikaru
364 1.1 hikaru return (ih);
365 1.1 hikaru }
366 1.1 hikaru
367 1.1 hikaru void
368 1.1 hikaru octeon_intr_disestablish(void *cookie)
369 1.1 hikaru {
370 1.1 hikaru struct octeon_intrhand *ih = cookie;
371 1.1 hikaru u_int64_t irq_mask;
372 1.1 hikaru int irq, req, s;
373 1.1 hikaru
374 1.1 hikaru irq = ih->ih_irq;
375 1.1 hikaru req = ih->ih_intr;
376 1.1 hikaru
377 1.1 hikaru s = splhigh();
378 1.1 hikaru
379 1.1 hikaru /*
380 1.1 hikaru * First, remove it from the table.
381 1.1 hikaru */
382 1.1 hikaru LIST_REMOVE(ih, ih_q);
383 1.1 hikaru
384 1.1 hikaru /*
385 1.1 hikaru * Now, disable it, if there is nothing remaining on the
386 1.1 hikaru * list.
387 1.1 hikaru */
388 1.1 hikaru if (octeon_ciu_intrtab[irq].intr_refcnt-- == 1) {
389 1.1 hikaru irq &= 63; /* throw away high bit if set */
390 1.1 hikaru req &= 1; /* throw away high bit if set */
391 1.1 hikaru irq_mask = ~(1ULL << irq);
392 1.1 hikaru
393 1.1 hikaru switch (req) {
394 1.1 hikaru case 0:
395 1.1 hikaru int0_enable0 &= irq_mask;
396 1.1 hikaru octeon_write_csr(CIU_INT0_EN0, int0_enable0);
397 1.1 hikaru break;
398 1.1 hikaru
399 1.1 hikaru case 1:
400 1.1 hikaru int1_enable0 &= irq_mask;
401 1.1 hikaru octeon_write_csr(CIU_INT1_EN0, int1_enable0);
402 1.1 hikaru break;
403 1.1 hikaru }
404 1.1 hikaru }
405 1.1 hikaru free(ih, M_DEVBUF);
406 1.1 hikaru
407 1.1 hikaru splx(s);
408 1.1 hikaru }
409 1.1 hikaru
410 1.1 hikaru void
411 1.1 hikaru octeon_iointr(int ipl, vaddr_t pc, uint32_t ipending)
412 1.1 hikaru {
413 1.1 hikaru struct octeon_intrhand *ih;
414 1.1 hikaru int level, irq;
415 1.1 hikaru uint64_t hwpend = 0;
416 1.1 hikaru
417 1.1 hikaru asm (".set mips64; clz %0,%1; .set mips0" : "=r"(level) : "r"(ipending));
418 1.1 hikaru switch (level = 21 - level) {
419 1.1 hikaru case 0: // MIPS_INT_MASK_0
420 1.1 hikaru hwpend = octeon_read_csr(CIU_INT0_SUM0) & int0_enable0;
421 1.1 hikaru break;
422 1.1 hikaru
423 1.1 hikaru case 1: // MIPS_INT_MASK_1
424 1.1 hikaru hwpend = octeon_read_csr(CIU_INT1_SUM0) & int1_enable0;
425 1.1 hikaru break;
426 1.1 hikaru
427 1.1 hikaru default:
428 1.1 hikaru panic("octeon_iointr: illegal interrupt");
429 1.1 hikaru }
430 1.1 hikaru if ((irq = ffs64(hwpend) - 1) < 0)
431 1.1 hikaru return;
432 1.1 hikaru LIST_FOREACH(ih, &octeon_ciu_intrtab[irq].intr_list, ih_q) {
433 1.1 hikaru (*ih->ih_func)(ih->ih_arg);
434 1.1 hikaru }
435 1.1 hikaru }
436