octeon_intr.c revision 1.3.2.2 1 1.3.2.2 skrll /* $NetBSD: octeon_intr.c,v 1.3.2.2 2015/06/06 14:40:01 skrll Exp $ */
2 1.3.2.2 skrll /*
3 1.3.2.2 skrll * Copyright 2001, 2002 Wasabi Systems, Inc.
4 1.3.2.2 skrll * All rights reserved.
5 1.3.2.2 skrll *
6 1.3.2.2 skrll * Written by Jason R. Thorpe and Simon Burge for Wasabi Systems, Inc.
7 1.3.2.2 skrll *
8 1.3.2.2 skrll * Redistribution and use in source and binary forms, with or without
9 1.3.2.2 skrll * modification, are permitted provided that the following conditions
10 1.3.2.2 skrll * are met:
11 1.3.2.2 skrll * 1. Redistributions of source code must retain the above copyright
12 1.3.2.2 skrll * notice, this list of conditions and the following disclaimer.
13 1.3.2.2 skrll * 2. Redistributions in binary form must reproduce the above copyright
14 1.3.2.2 skrll * notice, this list of conditions and the following disclaimer in the
15 1.3.2.2 skrll * documentation and/or other materials provided with the distribution.
16 1.3.2.2 skrll * 3. All advertising materials mentioning features or use of this software
17 1.3.2.2 skrll * must display the following acknowledgement:
18 1.3.2.2 skrll * This product includes software developed for the NetBSD Project by
19 1.3.2.2 skrll * Wasabi Systems, Inc.
20 1.3.2.2 skrll * 4. The name of Wasabi Systems, Inc. may not be used to endorse
21 1.3.2.2 skrll * or promote products derived from this software without specific prior
22 1.3.2.2 skrll * written permission.
23 1.3.2.2 skrll *
24 1.3.2.2 skrll * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
25 1.3.2.2 skrll * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
26 1.3.2.2 skrll * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
27 1.3.2.2 skrll * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
28 1.3.2.2 skrll * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 1.3.2.2 skrll * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30 1.3.2.2 skrll * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31 1.3.2.2 skrll * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32 1.3.2.2 skrll * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 1.3.2.2 skrll * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 1.3.2.2 skrll * POSSIBILITY OF SUCH DAMAGE.
35 1.3.2.2 skrll */
36 1.3.2.2 skrll
37 1.3.2.2 skrll /*
38 1.3.2.2 skrll * Platform-specific interrupt support for the MIPS Malta.
39 1.3.2.2 skrll */
40 1.3.2.2 skrll
41 1.3.2.2 skrll #include "opt_octeon.h"
42 1.3.2.2 skrll #define __INTR_PRIVATE
43 1.3.2.2 skrll
44 1.3.2.2 skrll #include <sys/cdefs.h>
45 1.3.2.2 skrll __KERNEL_RCSID(0, "$NetBSD: octeon_intr.c,v 1.3.2.2 2015/06/06 14:40:01 skrll Exp $");
46 1.3.2.2 skrll
47 1.3.2.2 skrll #include <sys/param.h>
48 1.3.2.2 skrll #include <sys/cpu.h>
49 1.3.2.2 skrll #include <sys/systm.h>
50 1.3.2.2 skrll #include <sys/device.h>
51 1.3.2.2 skrll #include <sys/intr.h>
52 1.3.2.2 skrll #include <sys/kernel.h>
53 1.3.2.2 skrll #include <sys/kmem.h>
54 1.3.2.2 skrll #include <sys/atomic.h>
55 1.3.2.2 skrll
56 1.3.2.2 skrll #include <lib/libkern/libkern.h>
57 1.3.2.2 skrll
58 1.3.2.2 skrll #include <mips/locore.h>
59 1.3.2.2 skrll
60 1.3.2.2 skrll #include <mips/cavium/dev/octeon_ciureg.h>
61 1.3.2.2 skrll #include <mips/cavium/octeonvar.h>
62 1.3.2.2 skrll
63 1.3.2.2 skrll /*
64 1.3.2.2 skrll * This is a mask of bits to clear in the SR when we go to a
65 1.3.2.2 skrll * given hardware interrupt priority level.
66 1.3.2.2 skrll */
67 1.3.2.2 skrll static const struct ipl_sr_map octeon_ipl_sr_map = {
68 1.3.2.2 skrll .sr_bits = {
69 1.3.2.2 skrll [IPL_NONE] = 0,
70 1.3.2.2 skrll [IPL_SOFTCLOCK] = MIPS_SOFT_INT_MASK_0,
71 1.3.2.2 skrll [IPL_SOFTNET] = MIPS_SOFT_INT_MASK,
72 1.3.2.2 skrll [IPL_VM] = MIPS_SOFT_INT_MASK | MIPS_INT_MASK_0,
73 1.3.2.2 skrll [IPL_SCHED] = MIPS_SOFT_INT_MASK | MIPS_INT_MASK_0
74 1.3.2.2 skrll | MIPS_INT_MASK_5,
75 1.3.2.2 skrll [IPL_DDB] = MIPS_SOFT_INT_MASK | MIPS_INT_MASK_0
76 1.3.2.2 skrll | MIPS_INT_MASK_1 | MIPS_INT_MASK_5,
77 1.3.2.2 skrll [IPL_HIGH] = MIPS_INT_MASK,
78 1.3.2.2 skrll },
79 1.3.2.2 skrll };
80 1.3.2.2 skrll
81 1.3.2.2 skrll const char * const octeon_intrnames[NIRQS] = {
82 1.3.2.2 skrll "workq 0",
83 1.3.2.2 skrll "workq 1",
84 1.3.2.2 skrll "workq 2",
85 1.3.2.2 skrll "workq 3",
86 1.3.2.2 skrll "workq 4",
87 1.3.2.2 skrll "workq 5",
88 1.3.2.2 skrll "workq 6",
89 1.3.2.2 skrll "workq 7",
90 1.3.2.2 skrll "workq 8",
91 1.3.2.2 skrll "workq 9",
92 1.3.2.2 skrll "workq 10",
93 1.3.2.2 skrll "workq 11",
94 1.3.2.2 skrll "workq 12",
95 1.3.2.2 skrll "workq 13",
96 1.3.2.2 skrll "workq 14",
97 1.3.2.2 skrll "workq 15",
98 1.3.2.2 skrll "gpio 0",
99 1.3.2.2 skrll "gpio 1",
100 1.3.2.2 skrll "gpio 2",
101 1.3.2.2 skrll "gpio 3",
102 1.3.2.2 skrll "gpio 4",
103 1.3.2.2 skrll "gpio 5",
104 1.3.2.2 skrll "gpio 6",
105 1.3.2.2 skrll "gpio 7",
106 1.3.2.2 skrll "gpio 8",
107 1.3.2.2 skrll "gpio 9",
108 1.3.2.2 skrll "gpio 10",
109 1.3.2.2 skrll "gpio 11",
110 1.3.2.2 skrll "gpio 12",
111 1.3.2.2 skrll "gpio 13",
112 1.3.2.2 skrll "gpio 14",
113 1.3.2.2 skrll "gpio 15",
114 1.3.2.2 skrll "mbox 0-15",
115 1.3.2.2 skrll "mbox 16-31",
116 1.3.2.2 skrll "uart 0",
117 1.3.2.2 skrll "uart 1",
118 1.3.2.2 skrll "pci inta",
119 1.3.2.2 skrll "pci intb",
120 1.3.2.2 skrll "pci intc",
121 1.3.2.2 skrll "pci intd",
122 1.3.2.2 skrll "pci msi 0-15",
123 1.3.2.2 skrll "pci msi 16-31",
124 1.3.2.2 skrll "pci msi 32-47",
125 1.3.2.2 skrll "pci msi 48-63",
126 1.3.2.2 skrll "wdog summary",
127 1.3.2.2 skrll "twsi",
128 1.3.2.2 skrll "rml",
129 1.3.2.2 skrll "trace",
130 1.3.2.2 skrll "gmx drop",
131 1.3.2.2 skrll "reserved",
132 1.3.2.2 skrll "ipd drop",
133 1.3.2.2 skrll "reserved",
134 1.3.2.2 skrll "timer 0",
135 1.3.2.2 skrll "timer 1",
136 1.3.2.2 skrll "timer 2",
137 1.3.2.2 skrll "timer 3",
138 1.3.2.2 skrll "usb",
139 1.3.2.2 skrll "pcm/tdm",
140 1.3.2.2 skrll "mpi/spi",
141 1.3.2.2 skrll "reserved",
142 1.3.2.2 skrll "reserved",
143 1.3.2.2 skrll "reserved",
144 1.3.2.2 skrll "reserved",
145 1.3.2.2 skrll "reserved",
146 1.3.2.2 skrll };
147 1.3.2.2 skrll
148 1.3.2.2 skrll struct octeon_intrhand {
149 1.3.2.2 skrll int (*ih_func)(void *);
150 1.3.2.2 skrll void *ih_arg;
151 1.3.2.2 skrll int ih_irq;
152 1.3.2.2 skrll int ih_ipl;
153 1.3.2.2 skrll };
154 1.3.2.2 skrll
155 1.3.2.2 skrll #ifdef MULTIPROCESSOR
156 1.3.2.2 skrll static int octeon_send_ipi(struct cpu_info *, int);
157 1.3.2.2 skrll static int octeon_ipi_intr(void *);
158 1.3.2.2 skrll
159 1.3.2.2 skrll struct octeon_intrhand ipi_intrhands[2] = {
160 1.3.2.2 skrll [0] = {
161 1.3.2.2 skrll .ih_func = octeon_ipi_intr,
162 1.3.2.2 skrll .ih_arg = (void *)(uintptr_t)__BITS(15,0),
163 1.3.2.2 skrll .ih_irq = _CIU_INT_MBOX_15_0_SHIFT,
164 1.3.2.2 skrll .ih_ipl = IPL_SCHED,
165 1.3.2.2 skrll },
166 1.3.2.2 skrll [1] = {
167 1.3.2.2 skrll .ih_func = octeon_ipi_intr,
168 1.3.2.2 skrll .ih_arg = (void *)(uintptr_t)__BITS(31,16),
169 1.3.2.2 skrll .ih_irq = _CIU_INT_MBOX_31_16_SHIFT,
170 1.3.2.2 skrll .ih_ipl = IPL_HIGH,
171 1.3.2.2 skrll },
172 1.3.2.2 skrll };
173 1.3.2.2 skrll #endif
174 1.3.2.2 skrll
175 1.3.2.2 skrll struct octeon_intrhand *octeon_ciu_intrs[NIRQS] = {
176 1.3.2.2 skrll #ifdef MULTIPROCESSOR
177 1.3.2.2 skrll [_CIU_INT_MBOX_15_0_SHIFT] = &ipi_intrhands[0],
178 1.3.2.2 skrll [_CIU_INT_MBOX_31_16_SHIFT] = &ipi_intrhands[1],
179 1.3.2.2 skrll #endif
180 1.3.2.2 skrll };
181 1.3.2.2 skrll
182 1.3.2.2 skrll kmutex_t octeon_intr_lock;
183 1.3.2.2 skrll
184 1.3.2.2 skrll #define X(a) MIPS_PHYS_TO_XKPHYS(OCTEON_CCA_NONE, (a))
185 1.3.2.2 skrll
186 1.3.2.2 skrll struct cpu_softc octeon_cpu0_softc = {
187 1.3.2.2 skrll .cpu_ci = &cpu_info_store,
188 1.3.2.2 skrll .cpu_int0_sum0 = X(CIU_INT0_SUM0),
189 1.3.2.2 skrll .cpu_int1_sum0 = X(CIU_INT1_SUM0),
190 1.3.2.2 skrll .cpu_int2_sum0 = X(CIU_INT4_SUM0),
191 1.3.2.2 skrll
192 1.3.2.2 skrll .cpu_int0_en0 = X(CIU_INT0_EN0),
193 1.3.2.2 skrll .cpu_int1_en0 = X(CIU_INT1_EN0),
194 1.3.2.2 skrll .cpu_int2_en0 = X(CIU_INT4_EN00),
195 1.3.2.2 skrll
196 1.3.2.2 skrll .cpu_int0_en1 = X(CIU_INT0_EN1),
197 1.3.2.2 skrll .cpu_int1_en1 = X(CIU_INT1_EN1),
198 1.3.2.2 skrll .cpu_int2_en1 = X(CIU_INT4_EN01),
199 1.3.2.2 skrll
200 1.3.2.2 skrll .cpu_int32_en = X(CIU_INT32_EN0),
201 1.3.2.2 skrll
202 1.3.2.2 skrll #ifdef MULTIPROCESSOR
203 1.3.2.2 skrll .cpu_mbox_set = X(CIU_MBOX_SET0),
204 1.3.2.2 skrll .cpu_mbox_clr = X(CIU_MBOX_CLR0),
205 1.3.2.2 skrll #endif
206 1.3.2.2 skrll };
207 1.3.2.2 skrll
208 1.3.2.2 skrll #ifdef MULTIPROCESSOR
209 1.3.2.2 skrll struct cpu_softc octeon_cpu1_softc = {
210 1.3.2.2 skrll .cpu_int0_sum0 = X(CIU_INT2_SUM0),
211 1.3.2.2 skrll .cpu_int1_sum0 = X(CIU_INT3_SUM0),
212 1.3.2.2 skrll .cpu_int2_sum0 = X(CIU_INT4_SUM1),
213 1.3.2.2 skrll
214 1.3.2.2 skrll .cpu_int0_en0 = X(CIU_INT2_EN0),
215 1.3.2.2 skrll .cpu_int1_en0 = X(CIU_INT3_EN0),
216 1.3.2.2 skrll .cpu_int2_en0 = X(CIU_INT4_EN10),
217 1.3.2.2 skrll
218 1.3.2.2 skrll .cpu_int0_en1 = X(CIU_INT2_EN1),
219 1.3.2.2 skrll .cpu_int1_en1 = X(CIU_INT3_EN1),
220 1.3.2.2 skrll .cpu_int2_en1 = X(CIU_INT4_EN11),
221 1.3.2.2 skrll
222 1.3.2.2 skrll .cpu_int32_en = X(CIU_INT32_EN1),
223 1.3.2.2 skrll
224 1.3.2.2 skrll .cpu_mbox_set = X(CIU_MBOX_SET1),
225 1.3.2.2 skrll .cpu_mbox_clr = X(CIU_MBOX_CLR1),
226 1.3.2.2 skrll };
227 1.3.2.2 skrll #endif
228 1.3.2.2 skrll
229 1.3.2.2 skrll #undef X
230 1.3.2.2 skrll
231 1.3.2.2 skrll void
232 1.3.2.2 skrll octeon_intr_init(struct cpu_info *ci)
233 1.3.2.2 skrll {
234 1.3.2.2 skrll const int cpunum = cpu_index(ci);
235 1.3.2.2 skrll const char * const xname = cpu_name(ci);
236 1.3.2.2 skrll struct cpu_softc *cpu;
237 1.3.2.2 skrll
238 1.3.2.2 skrll ipl_sr_map = octeon_ipl_sr_map;
239 1.3.2.2 skrll
240 1.3.2.2 skrll if (ci->ci_cpuid == 0) {
241 1.3.2.2 skrll mutex_init(&octeon_intr_lock, MUTEX_DEFAULT, IPL_HIGH);
242 1.3.2.2 skrll cpu = &octeon_cpu0_softc;
243 1.3.2.2 skrll #ifdef MULTIPROCESSOR
244 1.3.2.2 skrll mips_locoresw.lsw_send_ipi = octeon_send_ipi;
245 1.3.2.2 skrll #endif
246 1.3.2.2 skrll } else {
247 1.3.2.2 skrll KASSERT(cpunum == 1);
248 1.3.2.2 skrll #ifdef MULTIPROCESSOR
249 1.3.2.2 skrll cpu = &octeon_cpu1_softc;
250 1.3.2.2 skrll #else
251 1.3.2.2 skrll cpu = NULL;
252 1.3.2.2 skrll #endif
253 1.3.2.2 skrll }
254 1.3.2.2 skrll ci->ci_softc = cpu;
255 1.3.2.2 skrll
256 1.3.2.2 skrll #ifdef MULTIPROCESSOR
257 1.3.2.2 skrll // Enable the IPIs
258 1.3.2.2 skrll cpu->cpu_int0_enable0 |= __BIT(_CIU_INT_MBOX_15_0_SHIFT);
259 1.3.2.2 skrll cpu->cpu_int2_enable0 |= __BIT(_CIU_INT_MBOX_31_16_SHIFT);
260 1.3.2.2 skrll #endif
261 1.3.2.2 skrll
262 1.3.2.2 skrll mips64_sd_a64(cpu->cpu_int0_en0, cpu->cpu_int0_enable0);
263 1.3.2.2 skrll mips64_sd_a64(cpu->cpu_int1_en0, cpu->cpu_int1_enable0);
264 1.3.2.2 skrll mips64_sd_a64(cpu->cpu_int2_en0, cpu->cpu_int2_enable0);
265 1.3.2.2 skrll
266 1.3.2.2 skrll mips64_sd_a64(cpu->cpu_int32_en, 0);
267 1.3.2.2 skrll
268 1.3.2.2 skrll mips64_sd_a64(cpu->cpu_int0_en1, 0); // WDOG IPL2
269 1.3.2.2 skrll mips64_sd_a64(cpu->cpu_int1_en1, 0); // WDOG IPL3
270 1.3.2.2 skrll mips64_sd_a64(cpu->cpu_int2_en1, 0); // WDOG IPL4
271 1.3.2.2 skrll
272 1.3.2.2 skrll #ifdef MULTIPROCESSOR
273 1.3.2.2 skrll mips64_sd_a64(cpu->cpu_mbox_clr, __BITS(31,0));
274 1.3.2.2 skrll #endif
275 1.3.2.2 skrll
276 1.3.2.2 skrll for (size_t i = 0; i < NIRQS; i++) {
277 1.3.2.2 skrll evcnt_attach_dynamic(&cpu->cpu_intr_evs[i],
278 1.3.2.2 skrll EVCNT_TYPE_INTR, NULL, xname, octeon_intrnames[i]);
279 1.3.2.2 skrll }
280 1.3.2.2 skrll }
281 1.3.2.2 skrll
282 1.3.2.2 skrll void
283 1.3.2.2 skrll octeon_cal_timer(int corefreq)
284 1.3.2.2 skrll {
285 1.3.2.2 skrll /* Compute the number of cycles per second. */
286 1.3.2.2 skrll curcpu()->ci_cpu_freq = corefreq;
287 1.3.2.2 skrll
288 1.3.2.2 skrll /* Compute the number of ticks for hz. */
289 1.3.2.2 skrll curcpu()->ci_cycles_per_hz = (curcpu()->ci_cpu_freq + hz / 2) / hz;
290 1.3.2.2 skrll
291 1.3.2.2 skrll /* Compute the delay divisor and reciprical. */
292 1.3.2.2 skrll curcpu()->ci_divisor_delay =
293 1.3.2.2 skrll ((curcpu()->ci_cpu_freq + 500000) / 1000000);
294 1.3.2.2 skrll #if 0
295 1.3.2.2 skrll MIPS_SET_CI_RECIPRICAL(curcpu());
296 1.3.2.2 skrll #endif
297 1.3.2.2 skrll
298 1.3.2.2 skrll mips3_cp0_count_write(0);
299 1.3.2.2 skrll mips3_cp0_compare_write(0);
300 1.3.2.2 skrll }
301 1.3.2.2 skrll
302 1.3.2.2 skrll void *
303 1.3.2.2 skrll octeon_intr_establish(int irq, int ipl, int (*func)(void *), void *arg)
304 1.3.2.2 skrll {
305 1.3.2.2 skrll struct octeon_intrhand *ih;
306 1.3.2.2 skrll
307 1.3.2.2 skrll if (irq >= NIRQS)
308 1.3.2.2 skrll panic("octeon_intr_establish: bogus IRQ %d", irq);
309 1.3.2.2 skrll if (ipl < IPL_VM)
310 1.3.2.2 skrll panic("octeon_intr_establish: bogus IPL %d", ipl);
311 1.3.2.2 skrll
312 1.3.2.2 skrll ih = kmem_zalloc(sizeof(*ih), KM_NOSLEEP);
313 1.3.2.2 skrll if (ih == NULL)
314 1.3.2.2 skrll return (NULL);
315 1.3.2.2 skrll
316 1.3.2.2 skrll ih->ih_func = func;
317 1.3.2.2 skrll ih->ih_arg = arg;
318 1.3.2.2 skrll ih->ih_irq = irq;
319 1.3.2.2 skrll ih->ih_ipl = ipl;
320 1.3.2.2 skrll
321 1.3.2.2 skrll mutex_enter(&octeon_intr_lock);
322 1.3.2.2 skrll
323 1.3.2.2 skrll /*
324 1.3.2.2 skrll * First, make it known.
325 1.3.2.2 skrll */
326 1.3.2.2 skrll KASSERTMSG(octeon_ciu_intrs[irq] == NULL, "irq %d in use! (%p)",
327 1.3.2.2 skrll irq, octeon_ciu_intrs[irq]);
328 1.3.2.2 skrll
329 1.3.2.2 skrll octeon_ciu_intrs[irq] = ih;
330 1.3.2.2 skrll membar_producer();
331 1.3.2.2 skrll
332 1.3.2.2 skrll /*
333 1.3.2.2 skrll * Now enable it.
334 1.3.2.2 skrll */
335 1.3.2.2 skrll const uint64_t irq_mask = __BIT(irq);
336 1.3.2.2 skrll struct cpu_softc * const cpu0 = &octeon_cpu0_softc;
337 1.3.2.2 skrll #if MULTIPROCESSOR
338 1.3.2.2 skrll struct cpu_softc * const cpu1 = &octeon_cpu1_softc;
339 1.3.2.2 skrll #endif
340 1.3.2.2 skrll
341 1.3.2.2 skrll switch (ipl) {
342 1.3.2.2 skrll case IPL_VM:
343 1.3.2.2 skrll cpu0->cpu_int0_enable0 |= irq_mask;
344 1.3.2.2 skrll mips64_sd_a64(cpu0->cpu_int0_en0, cpu0->cpu_int0_enable0);
345 1.3.2.2 skrll break;
346 1.3.2.2 skrll
347 1.3.2.2 skrll case IPL_SCHED:
348 1.3.2.2 skrll cpu0->cpu_int1_enable0 |= irq_mask;
349 1.3.2.2 skrll mips64_sd_a64(cpu0->cpu_int1_en0, cpu0->cpu_int1_enable0);
350 1.3.2.2 skrll #ifdef MULTIPROCESSOR
351 1.3.2.2 skrll cpu1->cpu_int1_enable0 = cpu0->cpu_int1_enable0;
352 1.3.2.2 skrll mips64_sd_a64(cpu1->cpu_int1_en0, cpu1->cpu_int1_enable0);
353 1.3.2.2 skrll #endif
354 1.3.2.2 skrll break;
355 1.3.2.2 skrll
356 1.3.2.2 skrll case IPL_DDB:
357 1.3.2.2 skrll case IPL_HIGH:
358 1.3.2.2 skrll cpu0->cpu_int2_enable0 |= irq_mask;
359 1.3.2.2 skrll mips64_sd_a64(cpu0->cpu_int2_en0, cpu0->cpu_int2_enable0);
360 1.3.2.2 skrll #ifdef MULTIPROCESSOR
361 1.3.2.2 skrll cpu1->cpu_int2_enable0 = cpu0->cpu_int2_enable0;
362 1.3.2.2 skrll mips64_sd_a64(cpu1->cpu_int2_en0, cpu1->cpu_int2_enable0);
363 1.3.2.2 skrll #endif
364 1.3.2.2 skrll break;
365 1.3.2.2 skrll }
366 1.3.2.2 skrll
367 1.3.2.2 skrll mutex_exit(&octeon_intr_lock);
368 1.3.2.2 skrll
369 1.3.2.2 skrll return ih;
370 1.3.2.2 skrll }
371 1.3.2.2 skrll
372 1.3.2.2 skrll void
373 1.3.2.2 skrll octeon_intr_disestablish(void *cookie)
374 1.3.2.2 skrll {
375 1.3.2.2 skrll struct octeon_intrhand * const ih = cookie;
376 1.3.2.2 skrll const int irq = ih->ih_irq & (NIRQS-1);
377 1.3.2.2 skrll const int ipl = ih->ih_ipl;
378 1.3.2.2 skrll
379 1.3.2.2 skrll mutex_enter(&octeon_intr_lock);
380 1.3.2.2 skrll
381 1.3.2.2 skrll /*
382 1.3.2.2 skrll * First disable it.
383 1.3.2.2 skrll */
384 1.3.2.2 skrll const uint64_t irq_mask = ~__BIT(irq);
385 1.3.2.2 skrll struct cpu_softc * const cpu0 = &octeon_cpu0_softc;
386 1.3.2.2 skrll #if MULTIPROCESSOR
387 1.3.2.2 skrll struct cpu_softc * const cpu1 = &octeon_cpu1_softc;
388 1.3.2.2 skrll #endif
389 1.3.2.2 skrll
390 1.3.2.2 skrll switch (ipl) {
391 1.3.2.2 skrll case IPL_VM:
392 1.3.2.2 skrll cpu0->cpu_int0_enable0 &= ~irq_mask;
393 1.3.2.2 skrll mips64_sd_a64(cpu0->cpu_int0_en0, cpu0->cpu_int0_enable0);
394 1.3.2.2 skrll break;
395 1.3.2.2 skrll
396 1.3.2.2 skrll case IPL_SCHED:
397 1.3.2.2 skrll cpu0->cpu_int1_enable0 &= ~irq_mask;
398 1.3.2.2 skrll mips64_sd_a64(cpu0->cpu_int1_en0, cpu0->cpu_int1_enable0);
399 1.3.2.2 skrll #ifdef MULTIPROCESSOR
400 1.3.2.2 skrll cpu1->cpu_int1_enable0 = cpu0->cpu_int1_enable0;
401 1.3.2.2 skrll mips64_sd_a64(cpu1->cpu_int1_en0, cpu1->cpu_int1_enable0);
402 1.3.2.2 skrll #endif
403 1.3.2.2 skrll break;
404 1.3.2.2 skrll
405 1.3.2.2 skrll case IPL_DDB:
406 1.3.2.2 skrll case IPL_HIGH:
407 1.3.2.2 skrll cpu0->cpu_int2_enable0 &= ~irq_mask;
408 1.3.2.2 skrll mips64_sd_a64(cpu0->cpu_int2_en0, cpu0->cpu_int2_enable0);
409 1.3.2.2 skrll #ifdef MULTIPROCESSOR
410 1.3.2.2 skrll cpu1->cpu_int2_enable0 = cpu0->cpu_int2_enable0;
411 1.3.2.2 skrll mips64_sd_a64(cpu1->cpu_int2_en0, cpu1->cpu_int2_enable0);
412 1.3.2.2 skrll #endif
413 1.3.2.2 skrll break;
414 1.3.2.2 skrll }
415 1.3.2.2 skrll
416 1.3.2.2 skrll /*
417 1.3.2.2 skrll * Now remove it since we shouldn't get interrupts for it.
418 1.3.2.2 skrll */
419 1.3.2.2 skrll octeon_ciu_intrs[irq] = NULL;
420 1.3.2.2 skrll
421 1.3.2.2 skrll mutex_exit(&octeon_intr_lock);
422 1.3.2.2 skrll
423 1.3.2.2 skrll kmem_free(ih, sizeof(*ih));
424 1.3.2.2 skrll }
425 1.3.2.2 skrll
426 1.3.2.2 skrll void
427 1.3.2.2 skrll octeon_iointr(int ipl, vaddr_t pc, uint32_t ipending)
428 1.3.2.2 skrll {
429 1.3.2.2 skrll struct cpu_info * const ci = curcpu();
430 1.3.2.2 skrll struct cpu_softc * const cpu = ci->ci_softc;
431 1.3.2.2 skrll
432 1.3.2.2 skrll KASSERT((ipending & ~MIPS_INT_MASK) == 0);
433 1.3.2.2 skrll KASSERT(ipending & MIPS_HARD_INT_MASK);
434 1.3.2.2 skrll uint64_t hwpend = 0;
435 1.3.2.2 skrll
436 1.3.2.2 skrll if (ipending & MIPS_INT_MASK_2) {
437 1.3.2.2 skrll hwpend = mips64_ld_a64(cpu->cpu_int2_sum0)
438 1.3.2.2 skrll & cpu->cpu_int2_enable0;
439 1.3.2.2 skrll } else if (ipending & MIPS_INT_MASK_1) {
440 1.3.2.2 skrll hwpend = mips64_ld_a64(cpu->cpu_int1_sum0)
441 1.3.2.2 skrll & cpu->cpu_int1_enable0;
442 1.3.2.2 skrll } else if (ipending & MIPS_INT_MASK_0) {
443 1.3.2.2 skrll hwpend = mips64_ld_a64(cpu->cpu_int0_sum0)
444 1.3.2.2 skrll & cpu->cpu_int0_enable0;
445 1.3.2.2 skrll } else {
446 1.3.2.2 skrll panic("octeon_iointr: unexpected ipending %#x", ipending);
447 1.3.2.2 skrll }
448 1.3.2.2 skrll while (hwpend != 0) {
449 1.3.2.2 skrll const int irq = ffs64(hwpend) - 1;
450 1.3.2.2 skrll hwpend &= ~__BIT(irq);
451 1.3.2.2 skrll
452 1.3.2.2 skrll struct octeon_intrhand * const ih = octeon_ciu_intrs[irq];
453 1.3.2.2 skrll cpu->cpu_intr_evs[irq].ev_count++;
454 1.3.2.2 skrll if (__predict_true(ih != NULL)) {
455 1.3.2.2 skrll #ifdef MULTIPROCESSOR
456 1.3.2.2 skrll if (ipl == IPL_VM) {
457 1.3.2.2 skrll KERNEL_LOCK(1, NULL);
458 1.3.2.2 skrll #endif
459 1.3.2.2 skrll (*ih->ih_func)(ih->ih_arg);
460 1.3.2.2 skrll #ifdef MULTIPROCESSOR
461 1.3.2.2 skrll KERNEL_UNLOCK_ONE(NULL);
462 1.3.2.2 skrll } else {
463 1.3.2.2 skrll (*ih->ih_func)(ih->ih_arg);
464 1.3.2.2 skrll }
465 1.3.2.2 skrll #endif
466 1.3.2.2 skrll }
467 1.3.2.2 skrll }
468 1.3.2.2 skrll }
469 1.3.2.2 skrll
470 1.3.2.2 skrll #ifdef MULTIPROCESSOR
471 1.3.2.2 skrll __CTASSERT(NIPIS < 16);
472 1.3.2.2 skrll
473 1.3.2.2 skrll int
474 1.3.2.2 skrll octeon_ipi_intr(void *arg)
475 1.3.2.2 skrll {
476 1.3.2.2 skrll struct cpu_info * const ci = curcpu();
477 1.3.2.2 skrll struct cpu_softc * const cpu = ci->ci_softc;
478 1.3.2.2 skrll uint64_t ipi_mask = (uintptr_t) arg;
479 1.3.2.2 skrll
480 1.3.2.2 skrll ipi_mask &= mips64_ld_a64(cpu->cpu_mbox_set);
481 1.3.2.2 skrll mips64_sd_a64(cpu->cpu_mbox_clr, ipi_mask);
482 1.3.2.2 skrll
483 1.3.2.2 skrll ipi_mask |= (ipi_mask >> 16);
484 1.3.2.2 skrll ipi_mask &= __BITS(15,0);
485 1.3.2.2 skrll
486 1.3.2.2 skrll KASSERT(ci->ci_cpl >= IPL_SCHED);
487 1.3.2.2 skrll KASSERT(ipi_mask < __BIT(NIPIS));
488 1.3.2.2 skrll
489 1.3.2.2 skrll /* if the request is clear, it was previously processed */
490 1.3.2.2 skrll if ((ci->ci_request_ipis & ipi_mask) == 0)
491 1.3.2.2 skrll return 0;
492 1.3.2.2 skrll
493 1.3.2.2 skrll atomic_or_64(&ci->ci_active_ipis, ipi_mask);
494 1.3.2.2 skrll atomic_and_64(&ci->ci_request_ipis, ~ipi_mask);
495 1.3.2.2 skrll
496 1.3.2.2 skrll ipi_process(ci, ipi_mask);
497 1.3.2.2 skrll
498 1.3.2.2 skrll atomic_and_64(&ci->ci_active_ipis, ~ipi_mask);
499 1.3.2.2 skrll
500 1.3.2.2 skrll return 1;
501 1.3.2.2 skrll }
502 1.3.2.2 skrll
503 1.3.2.2 skrll int
504 1.3.2.2 skrll octeon_send_ipi(struct cpu_info *ci, int req)
505 1.3.2.2 skrll {
506 1.3.2.2 skrll
507 1.3.2.2 skrll KASSERT(req < NIPIS);
508 1.3.2.2 skrll if (ci == NULL) {
509 1.3.2.2 skrll // only deals with 2 CPUs
510 1.3.2.2 skrll ci = cpuid_infos[(cpu_number() == 0) ? 1 : 0];
511 1.3.2.2 skrll }
512 1.3.2.2 skrll
513 1.3.2.2 skrll struct cpu_softc * const cpu = ci->ci_softc;
514 1.3.2.2 skrll uint64_t ipi_mask = __BIT(req);
515 1.3.2.2 skrll
516 1.3.2.2 skrll if (req == IPI_SUSPEND) {
517 1.3.2.2 skrll ipi_mask <<= 16;
518 1.3.2.2 skrll }
519 1.3.2.2 skrll
520 1.3.2.2 skrll mips64_sd_a64(cpu->cpu_mbox_set, ipi_mask);
521 1.3.2.2 skrll return 0;
522 1.3.2.2 skrll }
523 1.3.2.2 skrll #endif /* MULTIPROCESSOR */
524