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