rmixl_fmn.c revision 1.1.2.10 1 /* $NetBSD: rmixl_fmn.c,v 1.1.2.10 2012/01/19 08:05:24 matt Exp $ */
2 /*-
3 * Copyright (c) 2010 The NetBSD Foundation, Inc.
4 * All rights reserved.
5 *
6 * This code is derived from software contributed to The NetBSD Foundation
7 * by Cliff Neighbors.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
19 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
22 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include "opt_ddb.h"
32 #include "opt_cputype.h"
33
34 #include <sys/cdefs.h>
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/cpu.h>
38 #include <sys/atomic.h>
39 #include <sys/intr.h>
40
41 #include <dev/pci/pcidevs.h>
42
43 #include <mips/cpuregs.h>
44
45 #include <mips/rmi/rmixlreg.h>
46 #include <mips/rmi/rmixlvar.h>
47 #include <mips/rmi/rmixl_intr.h>
48 #include <mips/rmi/rmixl_cpuvar.h>
49 #include <mips/rmi/rmixl_fmnvar.h>
50
51 #ifdef FMN_DEBUG
52 # define DPRINTF(x) do { printf x ; } while(0)
53 #else
54 # define DPRINTF(x)
55 #endif
56
57 #ifdef DIAGNOSTIC
58 # define DIAG_PRF(x) do { printf x ; } while(0)
59 #else
60 # define DIAG_PRF(x)
61 #endif
62
63 /*
64 * macros used because mtc2, mfc2, dmtc2, dmfc2 instructions
65 * must use literal values for rd and sel operands
66 * so let the compiler sort it out
67 */
68
69 /*
70 * read first 4 SELs for given RD
71 */
72 #define FMN_COP2_4SEL_READ(rd, sel, vp) \
73 do { \
74 uint32_t *rp = (vp); \
75 rp[0] = mips_mfc2(rd, sel+0); \
76 rp[1] = mips_mfc2(rd, sel+1); \
77 rp[2] = mips_mfc2(rd, sel+2); \
78 rp[3] = mips_mfc2(rd, sel+3); \
79 } while (0)
80
81 /*
82 * write v to first 4 SELs for given RD
83 */
84 #define FMN_COP2_4SEL_WRITE(rd, sel, v) \
85 do { \
86 mips_mtc2(rd, sel, v); \
87 mips_mtc2(rd, sel+1, v); \
88 mips_mtc2(rd, sel+2, v); \
89 mips_mtc2(rd, sel+3, v); \
90 } while (0)
91
92 #define FMN_COP2_8SEL_WRITE(rd, v) \
93 do { \
94 mips_mtc2(rd, 0, v); \
95 mips_mtc2(rd, 1, v); \
96 mips_mtc2(rd, 2, v); \
97 mips_mtc2(rd, 3, v); \
98 mips_mtc2(rd, 4, v); \
99 mips_mtc2(rd, 5, v); \
100 mips_mtc2(rd, 6, v); \
101 mips_mtc2(rd, 7, v); \
102 } while (0)
103
104
105 #define FMN_COP2_SEL_CASE_READ(rd, sel, v) \
106 case sel: \
107 v = mips_mfc2(rd, sel); \
108 break
109 #define FMN_COP2_SEL_CASE_WRITE(rd, sel, v) \
110 case sel: \
111 mips_mtc2(rd, sel, v); \
112 break
113 /*
114 * read/write a single arbitrary sel for the given rd
115 */
116 #define FMN_COP2_SEL_SWITCH_RW(rw, rd, sel, val) \
117 do { \
118 switch (sel) { \
119 FMN_COP2_SEL_CASE_ ## rw(rd, 0, val); \
120 FMN_COP2_SEL_CASE_ ## rw(rd, 1, val); \
121 FMN_COP2_SEL_CASE_ ## rw(rd, 2, val); \
122 FMN_COP2_SEL_CASE_ ## rw(rd, 3, val); \
123 FMN_COP2_SEL_CASE_ ## rw(rd, 4, val); \
124 FMN_COP2_SEL_CASE_ ## rw(rd, 5, val); \
125 FMN_COP2_SEL_CASE_ ## rw(rd, 6, val); \
126 FMN_COP2_SEL_CASE_ ## rw(rd, 7, val); \
127 default: \
128 panic("%s:%d: bad sel %d\n", \
129 __func__, __LINE__, sel); \
130 } \
131 } while (0)
132
133 #define FMN_COP2_RD_CASE_RW(rw, rd, sel, val) \
134 case rd: \
135 FMN_COP2_SEL_SWITCH_RW(rw, rd, sel, val); \
136 break
137 /*
138 * read/write a single arbitrary Credit Counter at (rd, sel)
139 * eg:
140 * FMN_COP2_RD_SWITCH_RW(READ, 16, 2, val)
141 * FMN_COP2_RD_SWITCH_RW(WRITE, 18, 0, val)
142 */
143 #define FMN_COP2_RD_SWITCH_RW(rw, rd, sel, val) \
144 do { \
145 switch(rd) { \
146 FMN_COP2_RD_CASE_RW(rw, 0, sel, val); \
147 FMN_COP2_RD_CASE_RW(rw, 1, sel, val); \
148 FMN_COP2_RD_CASE_RW(rw, 2, sel, val); \
149 FMN_COP2_RD_CASE_RW(rw, 3, sel, val); \
150 FMN_COP2_RD_CASE_RW(rw, 4, sel, val); \
151 FMN_COP2_RD_CASE_RW(rw, 5, sel, val); \
152 FMN_COP2_RD_CASE_RW(rw, 6, sel, val); \
153 FMN_COP2_RD_CASE_RW(rw, 7, sel, val); \
154 FMN_COP2_RD_CASE_RW(rw, 8, sel, val); \
155 FMN_COP2_RD_CASE_RW(rw, 9, sel, val); \
156 FMN_COP2_RD_CASE_RW(rw, 10, sel, val); \
157 FMN_COP2_RD_CASE_RW(rw, 11, sel, val); \
158 FMN_COP2_RD_CASE_RW(rw, 12, sel, val); \
159 FMN_COP2_RD_CASE_RW(rw, 13, sel, val); \
160 FMN_COP2_RD_CASE_RW(rw, 14, sel, val); \
161 FMN_COP2_RD_CASE_RW(rw, 15, sel, val); \
162 FMN_COP2_RD_CASE_RW(rw, 16, sel, val); \
163 FMN_COP2_RD_CASE_RW(rw, 17, sel, val); \
164 FMN_COP2_RD_CASE_RW(rw, 18, sel, val); \
165 FMN_COP2_RD_CASE_RW(rw, 19, sel, val); \
166 FMN_COP2_RD_CASE_RW(rw, 20, sel, val); \
167 FMN_COP2_RD_CASE_RW(rw, 21, sel, val); \
168 FMN_COP2_RD_CASE_RW(rw, 22, sel, val); \
169 FMN_COP2_RD_CASE_RW(rw, 23, sel, val); \
170 FMN_COP2_RD_CASE_RW(rw, 24, sel, val); \
171 FMN_COP2_RD_CASE_RW(rw, 25, sel, val); \
172 FMN_COP2_RD_CASE_RW(rw, 26, sel, val); \
173 FMN_COP2_RD_CASE_RW(rw, 27, sel, val); \
174 FMN_COP2_RD_CASE_RW(rw, 28, sel, val); \
175 FMN_COP2_RD_CASE_RW(rw, 29, sel, val); \
176 FMN_COP2_RD_CASE_RW(rw, 30, sel, val); \
177 FMN_COP2_RD_CASE_RW(rw, 31, sel, val); \
178 default: \
179 panic("%s:%d: bad regno %d\n", \
180 __func__, __LINE__, rd); \
181 } \
182 } while (0)
183
184
185 static int
186 fmn_stray_intr(void *v, rmixl_fmn_rxmsg_t *msg)
187 {
188 /* nothing */
189 return 0;
190 }
191
192 typedef uint8_t fmn_queue_id_t;
193
194 typedef struct fmn_station_info {
195 const char * si_name;
196 uint16_t si_qid_first;
197 uint16_t si_qid_last;
198 u_int si_buckets_max;
199 u_int si_bucket_size_dflt;
200 u_int si_credits_min;
201 u_int si_regbase;
202 } fmn_station_info_t;
203
204 typedef struct fmn_intrhand {
205 rmixl_fmn_intr_handler_t ih_func;
206 void * ih_arg;
207 } fmn_intrhand_t;
208
209 /*
210 * Global FMN stuff
211 */
212 typedef struct fmn_info {
213 const fmn_queue_id_t * fmn_qidtab;
214 const fmn_station_info_t * fmn_stinfo;
215 const char (*fmn_bucket_names)[12];
216 size_t fmn_intr_vec;
217 uint8_t fmn_nstid;
218 uint8_t fmn_nbucket; // or vc (XLP)
219 volatile uint32_t fmn_coremask;
220 volatile uint32_t fmn_nthread;
221
222 /*
223 * There are no per-CPU handlers.
224 */
225 volatile fmn_intrhand_t fmn_intrhand[RMIXL_FMN_NSTID];
226 } fmn_info_t;
227
228 static fmn_info_t fmn_info = {
229 .fmn_intrhand = {
230 [0 ... RMIXL_FMN_NSTID-1] = {
231 .ih_func = fmn_stray_intr,
232 .ih_arg = &fmn_info,
233 },
234 },
235 };
236
237 static char fmn_stid_ev_names[RMIXL_FMN_NSTID][32];
238
239 #if (MIPS64_XLR + MIPS64_XLS) > 0
240 static const char xlrxls_bucket_names[8][12] = {
241 "bucket 0", "bucket 1", "bucket 2", "bucket 3",
242 "bucket 4", "bucket 5", "bucket 6", "bucket 7",
243 };
244 #endif /* (MIPS64_XLR + MIPS64_XLS) > 0 */
245
246 #ifdef MIPS64_XLP
247 static const struct xlp_stid_map {
248 pcitag_t map_pcitag;
249 uint16_t map_product_id;
250 uint8_t map_stid;
251 } xlp_stid_map[] = {
252 #define MAP_ENTRY3(a,b,c) { \
253 .map_pcitag = RMIXLP_##a##_PCITAG, \
254 .map_product_id = PCI_PRODUCT_NETLOGIC_XLP_##b, \
255 .map_stid = RMIXLP_FMN_STID_##c }
256 #define MAP_ENTRY1(a) MAP_ENTRY3(a, a, a)
257 MAP_ENTRY3(PCIPORT0, PCIROOT, PCIE0),
258 MAP_ENTRY3(PCIPORT1, PCIROOT, PCIE1),
259 MAP_ENTRY3(PCIPORT2, PCIROOT, PCIE2),
260 MAP_ENTRY3(PCIPORT3, PCIROOT, PCIE3),
261 MAP_ENTRY1(NAE),
262 MAP_ENTRY1(NAE),
263 MAP_ENTRY1(NAE),
264 MAP_ENTRY1(NAE),
265 MAP_ENTRY1(POE),
266 MAP_ENTRY1(FMN),
267 MAP_ENTRY1(DMA),
268 MAP_ENTRY1(SAE),
269 MAP_ENTRY1(PKE),
270 MAP_ENTRY1(CDE),
271 MAP_ENTRY1(RXE),
272 MAP_ENTRY1(SRIO),
273 #undef MAP_ENTRY1
274 #undef MAP_ENTRY3
275 };
276
277 /* use this table for XLPxxx */
278 static fmn_queue_id_t xlp_xxx_qidtab[1024] = {
279 /* There are 4 VC queues per thread and are added dynamicly */
280 [ 128 ... 255] = RMIXLP_FMN_STID_POPQ,
281 /* I/O Push Queues start here and are determinted dynamicly */
282 };
283
284 /* use this table for XLPxxx */
285 static fmn_station_info_t xlp_xxx_stinfo[RMIXLP_FMN_NSTID] = {
286 [RMIXLP_FMN_STID_CPU] = { "cpu" },
287 [RMIXLP_FMN_STID_POPQ] = { "popq", 128, 255 },
288 [RMIXLP_FMN_STID_PCIE0] = { "pcie0" },
289 [RMIXLP_FMN_STID_PCIE1] = { "pcie1" },
290 [RMIXLP_FMN_STID_PCIE2] = { "pcie2" },
291 [RMIXLP_FMN_STID_PCIE3] = { "pcie3" },
292 [RMIXLP_FMN_STID_DMA] = { "dma" },
293 [RMIXLP_FMN_STID_PKE] = { "pke" },
294 [RMIXLP_FMN_STID_SAE] = { "sae" },
295 [RMIXLP_FMN_STID_CDE] = { "cde" },
296 [RMIXLP_FMN_STID_POE] = { "poe" },
297 [RMIXLP_FMN_STID_NAE] = { "nae" },
298 [RMIXLP_FMN_STID_NAE_FREEIN] = { "freein" },
299 [RMIXLP_FMN_STID_FMN] = { "fmn" },
300 [RMIXLP_FMN_STID_RXE] = { "rxe" },
301 [RMIXLP_FMN_STID_SRIO] = { "srio" },
302 };
303
304 static const char xlp_bucket_names[4][12] = {
305 "vc 0", "vc 1", "vc 2", "vc 3",
306 };
307
308 static void
309 fmn_init_xlp_claim_qids(const fmn_station_info_t * const si, size_t stid)
310 {
311 for (size_t qid = si->si_qid_first; qid <= si->si_qid_last; qid++) {
312 xlp_xxx_qidtab[qid++] = stid;
313 }
314 }
315 /*
316 * link to TX station ID table for RMI XLP type chip
317 */
318 static void
319 fmn_init_xlp(fmn_info_t *fmn)
320 {
321 fmn->fmn_nbucket = 4; // 4 VCs per thread
322 fmn->fmn_bucket_names = xlp_bucket_names;
323 fmn->fmn_nstid = RMIXLP_FMN_NSTID;
324 fmn->fmn_qidtab = xlp_xxx_qidtab;
325 fmn->fmn_stinfo = xlp_xxx_stinfo;
326
327 for (size_t i = 0; i < __arraycount(xlp_stid_map); i++) {
328 const struct xlp_stid_map * const map = &xlp_stid_map[i];
329 fmn_station_info_t * const si = &xlp_xxx_stinfo[map->map_stid];
330 pcireg_t id = rmixlp_read_4(map->map_pcitag, PCI_ID_REG);
331 if (PCI_PRODUCT(id) != map->map_product_id) {
332 continue;
333 }
334
335 pcireg_t statinfo = rmixlp_read_4(map->map_pcitag,
336 PCI_RMIXLP_STATID);
337 size_t qid_count = PCI_RMIXLP_STATID_COUNT(statinfo);
338 size_t qid_base = PCI_RMIXLP_STATID_BASE(statinfo);
339 if (qid_base < 256 && qid_count > 0) {
340 aprint_error("%s: pci device %#lx has "
341 "invalid station information (%#x); ignored\n",
342 __func__, map->map_pcitag, statinfo);
343 qid_count = 0;
344 }
345 if (qid_count == 0) {
346 si->si_qid_first = 1024;
347 si->si_qid_last = 1023;
348 continue;
349 }
350
351 si->si_qid_first = qid_base;
352 si->si_qid_last = qid_base + qid_count - 1;
353
354 fmn_init_xlp_claim_qids(si, map->map_stid);
355 }
356
357 /*
358 * Initialize the NAE Free-In FIFO qids (used for supply buffers
359 * for received packets). There is one qid per interface.
360 */
361 fmn_station_info_t * const si =
362 &xlp_xxx_stinfo[RMIXLP_FMN_STID_NAE_FREEIN];
363 if (RMIXLP_8XX_P) {
364 si->si_qid_first = 1000;
365 si->si_qid_last = 1019;
366 } else {
367 KASSERT(RMIXLP_3XX_P);
368 si->si_qid_first = 496;
369 si->si_qid_last = 504;
370 }
371 fmn_init_xlp_claim_qids(si, RMIXLP_FMN_STID_NAE_FREEIN);
372 }
373
374 static void
375 fmn_init_thread_xlp(fmn_info_t *fmn)
376 {
377 }
378 #endif /* MIPS64_XLP */
379
380 #ifdef MIPS64_XLS
381 /*
382 * index CPU-dependent table by (global) bucket ID to obtain logical Station ID
383 * see Table 12.1 in the XLS PRM
384 */
385 /* use this table for XLS6xx, XLS4xx */
386 static const fmn_queue_id_t xls_4xx_qidtab[] = {
387 [0 ... 7] = RMIXLS_FMN_STID_CORE0,
388 [8 ... 15] = RMIXLS_FMN_STID_CORE1,
389 [16 ... 23] = RMIXLS_FMN_STID_CORE2,
390 [24 ... 31] = RMIXLS_FMN_STID_CORE3,
391 [32 ... 63] = RMIXLS_FMN_STID_RESERVED,
392 [64 ... 71] = RMIXLS_FMN_STID_PCIE,
393 [72 ... 79] = RMIXLS_FMN_STID_RESERVED,
394 [80 ... 87] = RMIXLS_FMN_STID_GMAC_Q1,
395 [88 ... 95] = RMIXLS_FMN_STID_RESERVED,
396 [96 ... 103] = RMIXLS_FMN_STID_GMAC_Q0,
397 [104 ... 107] = RMIXLS_FMN_STID_DMA,
398 [108 ... 109] = RMIXLS_FMN_STID_CDE,
399 [110 ... 119] = RMIXLS_FMN_STID_RESERVED,
400 [120 ... 127] = RMIXLS_FMN_STID_SAE,
401 };
402
403 /* use this table for XLS6xx, XLS4xx */
404 static const fmn_station_info_t xls_4xx_stinfo[RMIXLS_FMN_NSTID] = {
405 [RMIXLS_FMN_STID_CORE0] = { "core0", 0, 7, 8, 32, 4, 0 },
406 [RMIXLS_FMN_STID_CORE1] = { "core1", 8, 15, 8, 32, 4, 0 },
407 [RMIXLS_FMN_STID_CORE2] = { "core2", 16, 23, 8, 32, 4, 0 },
408 [RMIXLS_FMN_STID_CORE3] = { "core3", 24, 31, 8, 32, 4, 0 },
409 [RMIXLS_FMN_STID_PCIE] = { "pcie", 64, 71, 8, 32, 0, RMIXL_IO_DEV_PCIE_BE },
410 [RMIXLS_FMN_STID_GMAC_Q0] = { "gmac_q0", 80, 87, 3, 32, 0, RMIXL_IO_DEV_GMAC_0 },
411 [RMIXLS_FMN_STID_GMAC_Q1] = { "gmac_q1", 96, 103, 3, 32, 0, RMIXL_IO_DEV_GMAC_4 },
412 [RMIXLS_FMN_STID_DMA] = { "dma", 104, 107, 4, 64, 0, RMIXL_IO_DEV_DMA },
413 [RMIXLS_FMN_STID_CDE] = { "cde", 108, 109, 4, 128, 0, RMIXL_IO_DEV_CDE },
414 [RMIXLS_FMN_STID_SAE] = { "sae", 120, 121, 2, 128, 0, RMIXL_IO_DEV_SAE },
415 };
416
417 /* use this table for XLS408Lite, XLS404Lite */
418 static const fmn_queue_id_t xls_4xx_lite_qidtab[] = {
419 [0 ... 7] = RMIXLS_FMN_STID_CORE0,
420 [8 ... 15] = RMIXLS_FMN_STID_CORE1,
421 [16 ... 23] = RMIXLS_FMN_STID_CORE2,
422 [24 ... 31] = RMIXLS_FMN_STID_CORE3,
423 [32 ... 79] = RMIXLS_FMN_STID_RESERVED,
424 [80 ... 87] = RMIXLS_FMN_STID_GMAC_Q1,
425 [88 ... 95] = RMIXLS_FMN_STID_RESERVED,
426 [96 ... 103] = RMIXLS_FMN_STID_GMAC_Q0,
427 [104 ... 107] = RMIXLS_FMN_STID_DMA,
428 [108 ... 109] = RMIXLS_FMN_STID_CDE,
429 [110 ... 115] = RMIXLS_FMN_STID_RESERVED,
430 [116 ... 119] = RMIXLS_FMN_STID_PCIE,
431 [120 ... 127] = RMIXLS_FMN_STID_SAE,
432 };
433
434 /* use this table for XLS4xxLite */
435 static const fmn_station_info_t xls_4xx_lite_stinfo[RMIXLS_FMN_NSTID] = {
436 [RMIXLS_FMN_STID_CORE0] = { "core0", 0, 7, 8, 32, 4, 0 },
437 [RMIXLS_FMN_STID_CORE1] = { "core1", 8, 15, 8, 32, 4, 0 },
438 [RMIXLS_FMN_STID_CORE2] = { "core2", 16, 23, 8, 32, 4, 0 },
439 [RMIXLS_FMN_STID_CORE3] = { "core3", 24, 31, 8, 32, 4, 0 },
440 [RMIXLS_FMN_STID_GMAC_Q0] = { "gmac_q0", 80, 87, 3, 32, 0, RMIXL_IO_DEV_GMAC_0 },
441 [RMIXLS_FMN_STID_GMAC_Q1] = { "gmac_q1", 96, 103, 3, 32, 0, RMIXL_IO_DEV_GMAC_4 },
442 [RMIXLS_FMN_STID_DMA] = { "dma", 104, 107, 4, 64, 0, RMIXL_IO_DEV_DMA },
443 [RMIXLS_FMN_STID_CDE] = { "cde", 108, 109, 4, 128, 0, RMIXL_IO_DEV_CDE },
444 [RMIXLS_FMN_STID_PCIE] = { "pcie", 116, 119, 4, 64, 0, RMIXL_IO_DEV_PCIE_BE },
445 [RMIXLS_FMN_STID_SAE] = { "sae", 120, 121, 2, 128, 0, RMIXL_IO_DEV_SAE },
446 };
447
448 /* use this table for XLS2xx */
449 static const fmn_queue_id_t xls_2xx_qidtab[] = {
450 [0 ... 7] = RMIXLS_FMN_STID_CORE0,
451 [8 ... 15] = RMIXLS_FMN_STID_CORE1,
452 [16 ... 23] = RMIXLS_FMN_STID_CORE2,
453 [24 ... 31] = RMIXLS_FMN_STID_CORE3,
454 [32 ... 63] = RMIXLS_FMN_STID_RESERVED,
455 [64 ... 71] = RMIXLS_FMN_STID_PCIE,
456 [72 ... 95] = RMIXLS_FMN_STID_RESERVED,
457 [96 ... 103] = RMIXLS_FMN_STID_GMAC_Q0,
458 [104 ... 107] = RMIXLS_FMN_STID_DMA,
459 [108 ... 119] = RMIXLS_FMN_STID_RESERVED,
460 [120 ... 127] = RMIXLS_FMN_STID_SAE,
461 };
462
463 /* use this table for XLS2xx */
464 static const fmn_station_info_t xls_2xx_stinfo[RMIXLS_FMN_NSTID] = {
465 [RMIXLS_FMN_STID_CORE0] = { "core0", 0, 7, 8, 32, 4, 0 },
466 [RMIXLS_FMN_STID_CORE1] = { "core1", 8, 15, 8, 32, 4, 0 },
467 [RMIXLS_FMN_STID_CORE2] = { "core2", 16, 23, 8, 32, 4, 0 },
468 [RMIXLS_FMN_STID_CORE3] = { "core3", 24, 31, 8, 32, 4, 0 },
469 [RMIXLS_FMN_STID_PCIE] = { "pcie", 64, 71, 8, 32, 0, RMIXL_IO_DEV_PCIE_BE },
470 [RMIXLS_FMN_STID_GMAC_Q0] = { "gmac_q0", 96, 103, 3, 32, 0, RMIXL_IO_DEV_GMAC_0 },
471 [RMIXLS_FMN_STID_DMA] = { "dma", 104, 107, 4, 64, 0, RMIXL_IO_DEV_DMA },
472 [RMIXLS_FMN_STID_SAE] = { "sae", 120, 121, 2, 128, 0, RMIXL_IO_DEV_SAE },
473 };
474
475 /* use this table for XLS1xx */
476 static const fmn_queue_id_t xls_1xx_qidtab[] = {
477 [0 ... 7] = RMIXLS_FMN_STID_CORE0,
478 [8 ... 15] = RMIXLS_FMN_STID_CORE1,
479 [16 ... 23] = RMIXLS_FMN_STID_CORE2,
480 [24 ... 31] = RMIXLS_FMN_STID_CORE3,
481 [32 ... 63] = RMIXLS_FMN_STID_RESERVED,
482 [64 ... 71] = RMIXLS_FMN_STID_PCIE,
483 [72 ... 95] = RMIXLS_FMN_STID_RESERVED,
484 [96 ... 101] = RMIXLS_FMN_STID_GMAC_Q0,
485 [102 ... 103] = RMIXLS_FMN_STID_RESERVED,
486 [104 ... 107] = RMIXLS_FMN_STID_DMA,
487 [108 ... 119] = RMIXLS_FMN_STID_RESERVED,
488 [120 ... 127] = RMIXLS_FMN_STID_SAE,
489 };
490
491 /* use this table for XLS1xx */
492 static const fmn_station_info_t xls_1xx_stinfo[RMIXLS_FMN_NSTID] = {
493 [RMIXLS_FMN_STID_CORE0] = { "core0", 0, 7, 8, 32, 4, 0 },
494 [RMIXLS_FMN_STID_CORE1] = { "core1", 8, 15, 8, 32, 4, 0 },
495 [RMIXLS_FMN_STID_CORE2] = { "core2", 16, 23, 8, 32, 4, 0 },
496 [RMIXLS_FMN_STID_CORE3] = { "core3", 24, 31, 8, 32, 4, 0 },
497 [RMIXLS_FMN_STID_PCIE] = { "pcie", 64, 67, 4, 32, 0, RMIXL_IO_DEV_PCIE_BE },
498 [RMIXLS_FMN_STID_GMAC_Q0] = { "gmac_q0", 96, 101, 3, 32, 0, RMIXL_IO_DEV_GMAC_0 },
499 [RMIXLS_FMN_STID_DMA] = { "dma", 104, 107, 4, 64, 0, RMIXL_IO_DEV_PCIE_BE },
500 [RMIXLS_FMN_STID_SAE] = { "sae", 120, 121, 2, 128, 0, RMIXL_IO_DEV_SAE },
501 };
502
503 static const struct xls_stid_map {
504 uint8_t map_impl;
505 const fmn_queue_id_t * map_qidtab;
506 const fmn_station_info_t * map_stinfo;
507 } xls_stid_map[] = {
508 { MIPS_XLS104, xls_1xx_qidtab, xls_1xx_stinfo },
509 { MIPS_XLS108, xls_1xx_qidtab, xls_1xx_stinfo },
510 { MIPS_XLS204, xls_2xx_qidtab, xls_2xx_stinfo },
511 { MIPS_XLS208, xls_2xx_qidtab, xls_2xx_stinfo },
512 { MIPS_XLS404, xls_4xx_qidtab, xls_4xx_stinfo },
513 { MIPS_XLS408, xls_4xx_qidtab, xls_4xx_stinfo },
514 { MIPS_XLS416, xls_4xx_qidtab, xls_4xx_stinfo },
515 { MIPS_XLS608, xls_4xx_qidtab, xls_4xx_stinfo },
516 { MIPS_XLS616, xls_4xx_qidtab, xls_4xx_stinfo },
517 { MIPS_XLS404LITE, xls_4xx_lite_qidtab, xls_4xx_lite_stinfo },
518 { MIPS_XLS408LITE, xls_4xx_lite_qidtab, xls_4xx_lite_stinfo },
519 };
520
521
522 /*
523 * link to TX station ID table for RMI XLS type chip
524 */
525 static void
526 fmn_init_xls(fmn_info_t *fmn)
527 {
528 const uint8_t impl = MIPS_PRID_IMPL(mips_options.mips_cpu_id);
529
530 for (size_t i = 0; i < __arraycount(xls_stid_map); i++) {
531 const struct xls_stid_map * const map = &xls_stid_map[i];
532 if (map->map_impl == impl) {
533 fmn->fmn_nbucket = 8; // 4 buckets per core
534 fmn->fmn_bucket_names = xlrxls_bucket_names;
535 fmn->fmn_nstid = RMIXLS_FMN_NSTID;
536 fmn->fmn_qidtab = map->map_qidtab;
537 fmn->fmn_stinfo = map->map_stinfo;
538 return;
539 }
540 }
541
542 panic("%s: unknown PRID IMPL %#x\n", __func__, impl);
543 }
544 #endif /* MIPS64_XLS */
545
546 #ifdef MIPS64_XLR
547 /* use this table for XLRxxx */
548 static const fmn_queue_id_t xlr_xxx_qidtab[] = {
549 [0 ... 7] = RMIXLR_FMN_STID_CORE0,
550 [8 ... 15] = RMIXLR_FMN_STID_CORE1,
551 [16 ... 23] = RMIXLR_FMN_STID_CORE2,
552 [24 ... 31] = RMIXLR_FMN_STID_CORE3,
553 [32 ... 39] = RMIXLR_FMN_STID_CORE4,
554 [40 ... 47] = RMIXLR_FMN_STID_CORE5,
555 [48 ... 55] = RMIXLR_FMN_STID_CORE6,
556 [56 ... 63] = RMIXLR_FMN_STID_CORE7,
557 [64 ... 79] = RMIXLR_FMN_STID_TXRX_0,
558 [80 ... 95] = RMIXLR_FMN_STID_TXRX_1,
559 [96 ... 103] = RMIXLR_FMN_STID_RGMII,
560 [104 ... 107] = RMIXLR_FMN_STID_DMA,
561 [108 ... 111] = RMIXLR_FMN_STID_RESERVED,
562 [112 ... 113] = RMIXLR_FMN_STID_FREE_0,
563 [114 ... 115] = RMIXLR_FMN_STID_FREE_0,
564 [116 ... 119] = RMIXLR_FMN_STID_RESERVED,
565 [120 ... 127] = RMIXLR_FMN_STID_SAE,
566 };
567
568 /*
569 * use this table for XLRxxx
570 * caution:
571 * - the XGMII/SPI4 stations si_regbase are 'special'
572 * - the RGMII station si_regbase is 'special'
573 */
574 static const fmn_station_info_t xlr_xxx_stinfo[RMIXLR_FMN_NSTID] = {
575 [RMIXLR_FMN_STID_CORE0] = { "core0", 0, 7, 8, 32, 4, 0 },
576 [RMIXLR_FMN_STID_CORE1] = { "core1", 8, 15, 8, 32, 4, 0 },
577 [RMIXLR_FMN_STID_CORE2] = { "core2", 16, 23, 8, 32, 4, 0 },
578 [RMIXLR_FMN_STID_CORE3] = { "core3", 24, 31, 8, 32, 4, 0 },
579 [RMIXLR_FMN_STID_CORE4] = { "core4", 32, 39, 8, 32, 4, 0 },
580 [RMIXLR_FMN_STID_CORE5] = { "core5", 40, 47, 8, 32, 4, 0 },
581 [RMIXLR_FMN_STID_CORE6] = { "core6", 48, 55, 8, 32, 4, 0 },
582 [RMIXLR_FMN_STID_CORE7] = { "core7", 56, 63, 8, 32, 4, 0 },
583 [RMIXLR_FMN_STID_TXRX_0] = { "txrx0", 64, 79, 1, 16, 0, RMIXL_IO_DEV_XGMAC_A },
584 [RMIXLR_FMN_STID_TXRX_1] = { "txrx1", 80, 95, 1, 16, 0, RMIXL_IO_DEV_XGMAC_B },
585 [RMIXLR_FMN_STID_RGMII] = { "rgmii", 96, 103, 8, 32, 0, RMIXL_IO_DEV_GMAC_A },
586 [RMIXLR_FMN_STID_DMA] = { "dma", 104, 107, 4, 64, 0, RMIXL_IO_DEV_DMA },
587 [RMIXLR_FMN_STID_FREE_0] = { "free0", 112, 113, 2, 128, 0, RMIXL_IO_DEV_XGMAC_A },
588 [RMIXLR_FMN_STID_FREE_1] = { "free1", 114, 115, 2, 128, 0, RMIXL_IO_DEV_XGMAC_B },
589 [RMIXLR_FMN_STID_SAE] = { "sae", 120, 124, 5, 32, 0, RMIXL_IO_DEV_SAE },
590 };
591
592 /*
593 * link to TX station ID table for RMI XLR type chip
594 */
595 static void
596 fmn_init_xlr(fmn_info_t *fmn)
597 {
598 fmn->fmn_nbucket = 8; // 4 buckets per core
599 fmn->fmn_bucket_names = xlrxls_bucket_names;
600 fmn->fmn_nstid = RMIXLR_FMN_NSTID;
601 fmn->fmn_qidtab = xlr_xxx_qidtab;
602 fmn->fmn_stinfo = xlr_xxx_stinfo;
603 }
604 #endif /* MIPS64_XLR */
605
606 #if (MIPS64_XLR + MIPS64_XLS) > 0
607 /*
608 * fmn_init_noncore_xlrxls
609 *
610 * initialize bucket sizes and (minimum) credits for non-core stations
611 * to ZERO. configured through memory write operations instead of CP2
612 */
613 static void
614 fmn_init_noncore_xlrxls(fmn_info_t *fmn)
615 {
616 for (const fmn_station_info_t *si = fmn->fmn_stinfo;
617 si < &fmn->fmn_stinfo[fmn->fmn_nstid];
618 si++) {
619 u_int regoff = si->si_regbase;
620 if (regoff != 0) {
621 regoff += RMIXL_FMN_BS_FIRST;
622 for (size_t bucket=0;
623 bucket < si->si_buckets_max;
624 bucket++) {
625 RMIXL_IOREG_WRITE(regoff, 0);
626 regoff += sizeof(uint32_t);
627 }
628 }
629 }
630 }
631
632 /*
633 * fmn_init_thread_xlrxls
634 *
635 * - configure FMN
636 * - initialize bucket sizes and (minimum) credits for a core
637 */
638 static void
639 fmn_init_thread_xlrxls(fmn_info_t *fmn)
640 {
641 const fmn_station_info_t *si = fmn->fmn_stinfo;
642 uint32_t sts1;
643 uint32_t cfg;
644
645 /*
646 * Let's see if we've initialized this core before.
647 */
648 const uint32_t new = __BIT(RMIXL_CPU_CORE(curcpu()->ci_cpuid));
649 for (;;) {
650 const uint32_t old = fmn->fmn_coremask;
651 if (old & new) {
652 fmn_init_noncore_xlrxls(fmn);
653 return;
654 }
655 if (old == atomic_cas_32(&fmn->fmn_coremask, old, old | new))
656 break;
657 }
658
659 const uint32_t cp0_status = rmixl_cp2_enable();
660
661 /* check/clear any pre-existing status1 error(s) */
662 sts1 = mips_mfc2(RMIXL_COP_2_MSG_STS, 1);
663 if ((sts1 & RMIXL_MSG_STS1_ERRS) != 0)
664 mips_mtc2(RMIXL_COP_2_MSG_STS, 1, sts1);
665
666 /* set up MsgConfig reg */
667 cfg = __SHIFTIN(1, RMIXL_MSG_CFG0_WM) /* watermark */
668 | __SHIFTIN(fmn->fmn_intr_vec, RMIXL_MSG_CFG0_IV)
669 /* irq */
670 | __SHIFTIN(1, RMIXL_MSG_CFG0_ITM) /* thread mask */
671 | RMIXL_MSG_CFG0_WIE /* watermark intr enb */
672 | RMIXL_MSG_CFG0_EIE; /* rx not empty intr enb */
673 mips_dmtc2(RMIXL_COP_2_MSG_CFG, 0, cfg);
674
675 /* disable trace mode, credit overrun intr, messaging errors intr */
676 mips_dmtc2(RMIXL_COP_2_MSG_CFG, 0, 0);
677
678 /* XXX using 4 buckets per core */
679 KASSERT(4 <= si->si_buckets_max);
680
681 /*
682 * initialize default sizes for core buckets
683 * zero sizes for unused buckets
684 */
685 KASSERT(si->si_buckets_max == 8);
686 uint32_t sz = si->si_bucket_size_dflt;
687 KASSERT((sz & ~RMIXL_MSG_BSZ_SIZE) == 0);
688 mips_mtc2(RMIXL_COP_2_MSG_BSZ, 0, sz);
689 mips_mtc2(RMIXL_COP_2_MSG_BSZ, 1, sz);
690 mips_mtc2(RMIXL_COP_2_MSG_BSZ, 2, sz);
691 mips_mtc2(RMIXL_COP_2_MSG_BSZ, 3, sz);
692 mips_mtc2(RMIXL_COP_2_MSG_BSZ, 4, 0);
693 mips_mtc2(RMIXL_COP_2_MSG_BSZ, 5, 0);
694 mips_mtc2(RMIXL_COP_2_MSG_BSZ, 6, 0);
695 mips_mtc2(RMIXL_COP_2_MSG_BSZ, 7, 0);
696
697 /*
698 * configure minimum credits for each core, 4 buckets
699 * zero all unused credit counters for this core
700 */
701 uint32_t cr = si->si_credits_min;
702
703 FMN_COP2_4SEL_WRITE(RMIXL_COP_2_CREDITS, 0, cr);
704 FMN_COP2_4SEL_WRITE(RMIXL_COP_2_CREDITS, 4, 0);
705 FMN_COP2_4SEL_WRITE(RMIXL_COP_2_CREDITS+1, 0, cr);
706 FMN_COP2_4SEL_WRITE(RMIXL_COP_2_CREDITS+1, 4, 0);
707 FMN_COP2_4SEL_WRITE(RMIXL_COP_2_CREDITS+2, 0, cr);
708 FMN_COP2_4SEL_WRITE(RMIXL_COP_2_CREDITS+2, 4, 0);
709 FMN_COP2_4SEL_WRITE(RMIXL_COP_2_CREDITS+3, 0, cr);
710 FMN_COP2_4SEL_WRITE(RMIXL_COP_2_CREDITS+3, 4, 0);
711
712 FMN_COP2_8SEL_WRITE(RMIXL_COP_2_CREDITS+4, 0);
713 FMN_COP2_8SEL_WRITE(RMIXL_COP_2_CREDITS+5, 0);
714 FMN_COP2_8SEL_WRITE(RMIXL_COP_2_CREDITS+6, 0);
715 FMN_COP2_8SEL_WRITE(RMIXL_COP_2_CREDITS+7, 0);
716 FMN_COP2_8SEL_WRITE(RMIXL_COP_2_CREDITS+8, 0);
717 FMN_COP2_8SEL_WRITE(RMIXL_COP_2_CREDITS+9, 0);
718 FMN_COP2_8SEL_WRITE(RMIXL_COP_2_CREDITS+10, 0);
719 FMN_COP2_8SEL_WRITE(RMIXL_COP_2_CREDITS+11, 0);
720 FMN_COP2_8SEL_WRITE(RMIXL_COP_2_CREDITS+12, 0);
721 FMN_COP2_8SEL_WRITE(RMIXL_COP_2_CREDITS+13, 0);
722 FMN_COP2_8SEL_WRITE(RMIXL_COP_2_CREDITS+14, 0);
723 FMN_COP2_8SEL_WRITE(RMIXL_COP_2_CREDITS+15, 0);
724
725 sts1 = mips_mfc2(RMIXL_COP_2_MSG_STS, 1);
726 KASSERT((sts1 & RMIXL_MSG_STS1_ERRS) == 0);
727
728 rmixl_cp2_restore(cp0_status);
729 }
730 #endif /* (MIPS64_XLR + MIPS64_XLS) > 0 */
731
732 #if (MIPS64_XLP) > 0
733 static void fmn_init_thread_xlp(fmn_info_t *);
734 #endif
735 static int fmn_intr(void *);
736 static void fmn_softint(void *);
737
738 #ifdef FMN_DEBUG
739 void rmixl_fmn_cp2_dump(void);
740 void rmixl_fmn_cc_dump(void);
741 #endif
742
743 /*
744 * This is called from cpu_configure before autoconf starts.
745 */
746 void
747 rmixl_fmn_init(void)
748 {
749 fmn_info_t * const fmn = &fmn_info;
750
751 /*
752 * do chip-dependent FMN initialization
753 */
754 switch(cpu_rmixl_chip_type(mips_options.mips_cpu)) {
755 #ifdef MIPS64_XLR
756 case CIDFL_RMI_TYPE_XLR:
757 fmn_init_xlr(fmn);
758 break;
759 #endif
760 #ifdef MIPS64_XLS
761 case CIDFL_RMI_TYPE_XLS:
762 fmn_init_xls(fmn);
763 break;
764 #endif
765 #ifdef MIPS64_XLP
766 case CIDFL_RMI_TYPE_XLP:
767 fmn_init_xlp(fmn);
768 break;
769 #endif
770 default:
771 panic("%s: RMI chip type %#x unknown", __func__,
772 cpu_rmixl_chip_type(mips_options.mips_cpu));
773 }
774 }
775
776 void
777 rmixl_fmn_cpu_attach(struct cpu_info *ci)
778 {
779 fmn_info_t * const fmn = &fmn_info;
780 struct cpu_softc * const sc = ci->ci_softc;
781
782 KASSERT(sc->sc_fmn_si == NULL);
783 sc->sc_fmn_si = softint_establish(SOFTINT_NET, fmn_softint, sc);
784
785 KASSERT(sc->sc_dev != NULL);
786
787 const char * const xname = device_xname(sc->sc_dev);
788 KASSERT(xname != NULL);
789
790 for (size_t i = 1; i < fmn_info.fmn_nstid; i++) {
791 evcnt_attach_dynamic(&sc->sc_fmn_stid_evcnts[i],
792 EVCNT_TYPE_MISC, NULL, xname, fmn_stid_ev_names[i]);
793 }
794
795 for (size_t i = 0; i < fmn_info.fmn_nbucket; i++) {
796 evcnt_attach_dynamic(&sc->sc_fmn_cpu_evcnts[i],
797 EVCNT_TYPE_MISC, NULL, xname, fmn->fmn_bucket_names[i]);
798 }
799 }
800
801 /*
802 * This must be done in the context of the thread itself.
803 */
804 void
805 rmixl_fmn_init_thread(void)
806 {
807 fmn_info_t * const fmn = &fmn_info;
808 struct cpu_info * const ci = curcpu();
809
810 KASSERT(fmn->fmn_stinfo[0].si_name == NULL);
811 for (size_t i = 1; i < fmn_info.fmn_nstid; i++) {
812 KASSERT(fmn->fmn_stinfo[i].si_name != NULL);
813 snprintf(fmn_stid_ev_names[i], sizeof(fmn_stid_ev_names[i]),
814 "fmn %s rx msgs", fmn->fmn_stinfo[i].si_name);
815 }
816
817 if (CPU_IS_PRIMARY(ci)) {
818 KASSERT(rmixl_intr_lock != NULL);
819 /*
820 * establish dispatcher for FMN interrupt
821 */
822 mutex_enter(rmixl_intr_lock);
823 fmn->fmn_intr_vec = rmixl_intr_get_vec(IPL_VM);
824 void * const ih = rmixl_vec_establish(fmn->fmn_intr_vec, NULL,
825 IPL_VM, fmn_intr, NULL, true);
826 if (ih == NULL)
827 panic("%s: rmixl_vec_establish failed", __func__);
828 mutex_exit(rmixl_intr_lock);
829 }
830 /*
831 * do chip-dependent per-core FMN initialization
832 */
833 switch(cpu_rmixl_chip_type(mips_options.mips_cpu)) {
834 #ifdef MIPS64_XLR
835 case CIDFL_RMI_TYPE_XLR:
836 fmn_init_thread_xlrxls(fmn);
837 break;
838 #endif
839 #ifdef MIPS64_XLS
840 case CIDFL_RMI_TYPE_XLS:
841 fmn_init_thread_xlrxls(fmn);
842 break;
843 #endif
844 #ifdef MIPS64_XLP
845 case CIDFL_RMI_TYPE_XLP:
846 fmn_init_thread_xlp(fmn);
847 break;
848 #endif
849 default:
850 panic("%s: RMI chip type %#x unknown", __func__,
851 cpu_rmixl_chip_type(mips_options.mips_cpu));
852 }
853 }
854
855 void *
856 rmixl_fmn_intr_establish(size_t txstid, rmixl_fmn_intr_handler_t func,
857 void *arg)
858 {
859 fmn_info_t * const fmn = &fmn_info;
860 volatile fmn_intrhand_t *ih = &fmn->fmn_intrhand[txstid];
861
862 if (atomic_cas_ptr(&ih->ih_arg, fmn, arg) == fmn) {
863 /*
864 * Now that the argument is updated, we can change func
865 */
866 membar_producer();
867 (void) atomic_swap_ptr(&ih->ih_func, func);
868 } else {
869 #ifdef DEBUG
870 panic("%s: intrhand[%zu] busy", __func__, txstid);
871 #endif
872 ih = NULL;
873 }
874
875 return __UNVOLATILE(ih);
876 }
877
878 void
879 rmixl_fmn_intr_disestablish(void *cookie)
880 {
881 fmn_info_t * const fmn = &fmn_info;
882 volatile fmn_intrhand_t * const ih = cookie;
883 rmixl_fmn_intr_handler_t func = ih->ih_func;
884
885 if (atomic_cas_ptr(&ih->ih_func, func, fmn_stray_intr) == func) {
886 /*
887 * Now that the old interrupt handler is no longer being
888 * called, we can swap out the argument.
889 */
890 membar_producer();
891 (void) atomic_swap_ptr(&ih->ih_arg, fmn);
892 #ifdef DEBUG
893 } else {
894 panic("%s: intrhand[%zd] not in use",
895 __func__, ih - fmn->fmn_intrhand);
896 #endif
897 }
898 }
899
900 void
901 rmixl_fmn_intr_poll(u_int bucket, rmixl_fmn_rxmsg_t *rxmsg)
902 {
903 uint32_t bit = 1 << bucket;
904 uint32_t cp0_status;
905
906 KASSERT(bucket < 8);
907
908 cp0_status = rmixl_cp2_enable();
909
910 for(;;) {
911 rmixl_msgwait(bit);
912 if (rmixl_fmn_msg_recv(bucket, rxmsg))
913 break;
914 DELAY(10); /* XXX */
915 }
916
917 rmixl_cp2_restore(cp0_status);
918 }
919
920 size_t
921 rmixl_fmn_qid_to_stid(size_t qid)
922 {
923 return fmn_info.fmn_qidtab[qid];
924 }
925
926 const char *
927 rmixl_fmn_stid_name(size_t stid)
928 {
929 KASSERT(stid != 0);
930 KASSERT(stid < fmn_info.fmn_nstid);
931 return fmn_info.fmn_stinfo[stid].si_name;
932 }
933
934 static int
935 fmn_intr(void *arg)
936 {
937 const bool is_xlp_p = cpu_rmixlp(mips_options.mips_cpu);
938 struct cpu_softc * const sc = curcpu()->ci_softc;
939
940 softint_schedule(sc->sc_fmn_si);
941 if (!is_xlp_p) {
942 /*
943 * On the XLR and XLS, we can only stop interrupts on a per
944 * core basis but then there are no per-thread resources so
945 * it doesn't really hurt.
946 */
947 const uint32_t cp0_status = rmixl_cp2_enable();
948 uint32_t msg_cfg = mips_mfc2(RMIXL_COP_2_MSG_CFG, 0);
949 msg_cfg &= ~(RMIXL_MSG_CFG0_EIE|RMIXL_MSG_CFG0_WIE);
950 mips_mtc2(RMIXL_COP_2_MSG_CFG, 0, msg_cfg);
951 rmixl_cp2_restore(cp0_status);
952 }
953 return 1;
954 }
955
956 static void
957 fmn_softint(void *arg)
958 {
959 const bool is_xlp_p = cpu_rmixlp(mips_options.mips_cpu);
960 fmn_info_t * const fmn = &fmn_info;
961 struct cpu_softc * const sc = curcpu()->ci_softc;
962 uint32_t mask = 0;
963 uint32_t processed = 0;
964
965 const uint32_t cp0_status = rmixl_cp2_enable();
966
967 for (;;) {
968 if (mask == 0) {
969 if (is_xlp_p) {
970 mask = __SHIFTOUT(
971 ~mips_mfc2(RMIXLP_COP_2_MSG_RX_STS,0),
972 RMIXLP_MSG_RX_STS_RXQVCE);
973 } else {
974 mask = __SHIFTOUT(
975 ~mips_mfc2(RMIXL_COP_2_MSG_STS,0),
976 RMIXL_MSG_STS0_RFBE);
977 }
978 if (mask == 0)
979 break;
980 }
981
982 DPRINTF(("%s: non-empty q-mask %#x\n", __func__, mask));
983
984 const u_int rxq = ffs(mask) - 1;
985 processed = (1 << rxq);
986
987 sc->sc_fmn_cpu_evcnts[rxq].ev_count++;
988
989 rmixl_fmn_rxmsg_t rxmsg;
990 if (!rmixl_fmn_msg_recv(rxq, &rxmsg))
991 continue;
992
993 const size_t txstid = fmn->fmn_qidtab[rxmsg.rxsid];
994 volatile fmn_intrhand_t * const ih = &fmn->fmn_intrhand[txstid];
995
996 membar_consumer(); // make sure arg is loaded before func
997 void * const ih_arg = ih->ih_arg;
998
999 membar_consumer(); // make sure arg is loaded before func
1000 rmixl_fmn_intr_handler_t ih_func = ih->ih_func;
1001
1002 if ((*ih_func)(ih_arg, &rxmsg) != 0)
1003 sc->sc_fmn_stid_evcnts[txstid].ev_count++;
1004 }
1005
1006 if (is_xlp_p) {
1007 /*
1008 * We need to set VC_PEND again so interrupts can get posted
1009 * for the VCs we processed. This register is global for all
1010 * threads on a core so only ACK the VCs we processed.
1011 */
1012 uint32_t msg_sts1 = mips_mfc2(RMIXLP_COP_2_MSG_STS1, 0);
1013 msg_sts1 |= __SHIFTOUT(processed, RMIXLP_MSG_STS1_VC_PEND);
1014 mips_mtc2(RMIXLP_COP_2_MSG_STS1, 0, msg_sts1);
1015 }
1016
1017 rmixl_cp2_restore(cp0_status);
1018 }
1019
1020 static bool
1021 rmixl_fmn_clear_to_send_p(void)
1022 {
1023 KASSERT(!cpu_rmixlp(mips_options.mips_cpu));
1024 uint32_t msg_sts;
1025 for (u_int try=16; try--; ) {
1026 msg_sts = mips_mfc2(RMIXL_COP_2_MSG_STS, 0);
1027 if ((msg_sts & (RMIXL_MSG_STS0_LPF|RMIXL_MSG_STS0_SPF|RMIXL_MSG_STS0_SMP)) == 0)
1028 return true;
1029 DELAY(10); /* XXX ??? */
1030 }
1031 DIAG_PRF(("%s: cpu%u: sts=%#x: can't send\n",
1032 __func__, cpu_number(), msg_sts));
1033 return false;
1034 }
1035
1036 bool
1037 rmixl_fmn_msg_send(u_int size, u_int code, u_int dest_id, u_int dest_vc,
1038 const rmixl_fmn_msg_t *msg)
1039 {
1040 const bool is_xlp_p = cpu_rmixlp(mips_options.mips_cpu);
1041 bool rv = false; /* assume failure */
1042
1043 KASSERT(1 <= size && size <= 4);
1044 KASSERT(code < 0x100);
1045 KASSERT(dest_id < (is_xlp_p ? 0x1000 : 0x80));
1046 KASSERT(dest_vc == 0 || (is_xlp_p && (dest_id & 0x380) == 0x80));
1047
1048 const uint32_t cp0_status = rmixl_cp2_enable();
1049
1050 switch (size) {
1051 case 1:
1052 mips_dmtc2(RMIXL_COP_2_TXBUF, 0, msg->data[0]);
1053 break;
1054 case 2:
1055 mips_dmtc2(RMIXL_COP_2_TXBUF, 0, msg->data[0]);
1056 mips_dmtc2(RMIXL_COP_2_TXBUF, 1, msg->data[1]);
1057 break;
1058 case 3:
1059 mips_dmtc2(RMIXL_COP_2_TXBUF, 0, msg->data[0]);
1060 mips_dmtc2(RMIXL_COP_2_TXBUF, 1, msg->data[1]);
1061 mips_dmtc2(RMIXL_COP_2_TXBUF, 2, msg->data[2]);
1062 break;
1063 case 4:
1064 mips_dmtc2(RMIXL_COP_2_TXBUF, 0, msg->data[0]);
1065 mips_dmtc2(RMIXL_COP_2_TXBUF, 1, msg->data[1]);
1066 mips_dmtc2(RMIXL_COP_2_TXBUF, 2, msg->data[2]);
1067 mips_dmtc2(RMIXL_COP_2_TXBUF, 3, msg->data[3]);
1068 break;
1069 default:
1070 DIAG_PRF(("%s: bad size %d", __func__, size));
1071 goto out;
1072 }
1073
1074 if (!is_xlp_p && !rmixl_fmn_clear_to_send_p()) {
1075 goto out;
1076 }
1077 uint32_t desc;
1078 if (is_xlp_p) {
1079 desc = RMIXLP_MSGSND_DESC(size, code, dest_id, dest_vc);
1080 } else {
1081 desc = RMIXL_MSGSND_DESC(size, code, dest_id);
1082 }
1083 DPRINTF(("%s: cpu%u, desc %#x\n", __func__, cpu_number(), desc));
1084 rv = -1; /* assume failure */
1085 for (size_t try=16; try--; ) {
1086 if (is_xlp_p) {
1087 if ((rv == rmixlp_msgsnd(desc)) != false)
1088 break;
1089 uint32_t tx_sts = mips_mfc2(RMIXLP_COP_2_MSG_TX_STS, 0);
1090 const uint32_t bad_tx_sts = RMIXLP_MSG_TX_STS_PS
1091 | RMIXLP_MSG_TX_STS_IQC | RMIXLP_MSG_TX_STS_OQC;
1092 KASSERT((tx_sts & bad_tx_sts) != 0);
1093 tx_sts &= ~bad_tx_sts;
1094 mips_mtc2(RMIXLP_COP_2_MSG_TX_STS, 0, tx_sts);
1095 } else {
1096 rmixl_msgsnd(desc);
1097
1098 uint32_t msg_sts0 = mips_mfc2(RMIXL_COP_2_MSG_STS, 0);
1099 uint32_t msg_sts1 = mips_mfc2(RMIXL_COP_2_MSG_STS, 1);
1100
1101 if ((msg_sts0 & RMIXL_MSG_STS0_SCF) == 0
1102 && (msg_sts1 & RMIXL_MSG_STS1_ERRS) == 0) {
1103 rv = 0;
1104 break;
1105 }
1106
1107 /* clear status1 error(s) */
1108 if ((msg_sts1 & RMIXL_MSG_STS1_ERRS) != 0) {
1109 msg_sts1 = mips_mfc2(RMIXL_COP_2_MSG_STS, 1);
1110 mips_mtc2(RMIXL_COP_2_MSG_STS, 1, msg_sts1);
1111 }
1112 DIAG_PRF(("%s: src=%ld, dst=%d, sts=%#x/%#x: send error, try %zu\n",
1113 __func__, curcpu()->ci_cpuid, dest_id, msg_sts0, msg_sts1, try));
1114 }
1115 DELAY(10);
1116 }
1117 out:
1118 rmixl_cp2_restore(cp0_status);
1119
1120 return rv;
1121 }
1122
1123 static int
1124 fmn_msgld_rmixlp(u_int rxq, rmixl_fmn_rxmsg_t *rxmsg)
1125 {
1126 bool rv = false;
1127 for (u_int try=16; !rv && try; try--) {
1128 rv = rmixlp_msgld(rxq);
1129 }
1130 if (!rv)
1131 return rv;
1132
1133 uint32_t msg_sts = mips_mfc2(RMIXLP_COP_2_MSG_RX_STS, 0);
1134 rxmsg->rxsid = __SHIFTOUT(msg_sts, RMIXLP_MSG_RX_STS_SID);
1135 rxmsg->code = __SHIFTOUT(msg_sts, RMIXLP_MSG_RX_STS_SC);
1136 rxmsg->size = __SHIFTOUT(msg_sts, RMIXLP_MSG_RX_STS_SM1) + 1;
1137 return true;
1138 }
1139
1140 static bool
1141 fmn_msgld_rmixl(u_int rxq, rmixl_fmn_rxmsg_t *rxmsg)
1142 {
1143 uint32_t msg_sts;
1144
1145 for (u_int try=16; try--; ) {
1146 msg_sts = mips_mfc2(RMIXL_COP_2_MSG_STS, 0);
1147 if ((msg_sts & RMIXL_MSG_STS0_LPF) == 0) {
1148 break;
1149 }
1150 }
1151 if (msg_sts & RMIXL_MSG_STS0_LPF) {
1152 DIAG_PRF(("%s: cpu%u, rxq=%d, sts=%#x: Load Pending Fail\n",
1153 __func__, cpu_number(), rxq, msg_sts));
1154 return false;
1155 }
1156 rmixl_msgld(rxq);
1157 msg_sts = mips_mfc2(RMIXL_COP_2_MSG_STS, 0);
1158 DPRINTF(("%s: cpu%u, rxq=%d, sts=%#x\n",
1159 __func__, cpu_number(), rxq, msg_sts));
1160 if (msg_sts & (RMIXL_MSG_STS0_LEF|RMIXL_MSG_STS0_LPF))
1161 return false;
1162
1163 rxmsg->rxsid = __SHIFTOUT(msg_sts, RMIXL_MSG_STS0_RMSID);
1164 rxmsg->code = __SHIFTOUT(msg_sts, RMIXL_MSG_STS0_RMSC);
1165 rxmsg->size = __SHIFTOUT(msg_sts, RMIXL_MSG_STS0_RMS) + 1;
1166 return true;
1167 }
1168
1169 /*
1170 * rmixl_fmn_msg_recv
1171 *
1172 * - assume cp2 access is already enabled
1173 */
1174 bool
1175 rmixl_fmn_msg_recv(u_int rxq, rmixl_fmn_rxmsg_t *rxmsg)
1176 {
1177 const bool is_xlp_p = cpu_rmixlp(mips_options.mips_cpu);
1178 bool rv = false;
1179
1180 KASSERT(!is_xlp_p || rxq < 4);
1181
1182 if (is_xlp_p) {
1183 rv = fmn_msgld_rmixlp(rxq, rxmsg);
1184 } else {
1185 rv = fmn_msgld_rmixl(rxq, rxmsg);
1186 }
1187 if (rv) {
1188 switch(rxmsg->size) {
1189 case 1:
1190 rxmsg->msg.data[0] = mips_dmfc2(RMIXL_COP_2_RXBUF, 0);
1191 break;
1192 case 2:
1193 rxmsg->msg.data[0] = mips_dmfc2(RMIXL_COP_2_RXBUF, 0);
1194 rxmsg->msg.data[1] = mips_dmfc2(RMIXL_COP_2_RXBUF, 1);
1195 break;
1196 case 3:
1197 rxmsg->msg.data[0] = mips_dmfc2(RMIXL_COP_2_RXBUF, 0);
1198 rxmsg->msg.data[1] = mips_dmfc2(RMIXL_COP_2_RXBUF, 1);
1199 rxmsg->msg.data[2] = mips_dmfc2(RMIXL_COP_2_RXBUF, 2);
1200 break;
1201 case 4:
1202 rxmsg->msg.data[0] = mips_dmfc2(RMIXL_COP_2_RXBUF, 0);
1203 rxmsg->msg.data[1] = mips_dmfc2(RMIXL_COP_2_RXBUF, 1);
1204 rxmsg->msg.data[2] = mips_dmfc2(RMIXL_COP_2_RXBUF, 2);
1205 rxmsg->msg.data[3] = mips_dmfc2(RMIXL_COP_2_RXBUF, 3);
1206 break;
1207 default:
1208 /* "impossible" due to bitfield width */
1209 panic("%s: bad size %d", __func__, rxmsg->size);
1210 }
1211 }
1212
1213 return rv;
1214 }
1215
1216 #ifdef FMN_DEBUG
1217 void
1218 rmixl_fmn_cp2_dump(void)
1219 {
1220 const bool is_xlp_p = cpu_rmixlp(mips_options.mips_cpu);
1221
1222 const uint32_t cp0_status = rmixl_cp2_enable();
1223
1224 COP2_PRINT_8(RMIXL_COP_2_TXBUF, 0);
1225 COP2_PRINT_8(RMIXL_COP_2_TXBUF, 1);
1226 COP2_PRINT_8(RMIXL_COP_2_TXBUF, 2);
1227 COP2_PRINT_8(RMIXL_COP_2_TXBUF, 3);
1228
1229 COP2_PRINT_8(RMIXL_COP_2_RXBUF, 0);
1230 COP2_PRINT_8(RMIXL_COP_2_RXBUF, 1);
1231 COP2_PRINT_8(RMIXL_COP_2_RXBUF, 2);
1232 COP2_PRINT_8(RMIXL_COP_2_RXBUF, 3);
1233
1234 if (is_xlp_p) {
1235 COP2_PRINT_4(RMIXLP_COP_2_MSG_TX_STS, 0);
1236 COP2_PRINT_4(RMIXLP_COP_2_MSG_RX_STS, 0);
1237 COP2_PRINT_4(RMIXLP_COP_2_MSG_STS1, 0);
1238 COP2_PRINT_4(RMIXLP_COP_2_MSG_CFG, 0);
1239 COP2_PRINT_4(RMIXLP_COP_2_MSG_ERR, 0);
1240 COP2_PRINT_4(RMIXLP_COP_2_MSG_ERR, 1);
1241 COP2_PRINT_4(RMIXLP_COP_2_MSG_ERR, 2);
1242 COP2_PRINT_4(RMIXLP_COP_2_MSG_ERR, 3);
1243 COP2_PRINT_8(RMIXLP_COP_2_CREDITS, 0);
1244 COP2_PRINT_4(RMIXLP_COP_2_CREDITS, 1);
1245 } else {
1246
1247 COP2_PRINT_4(RMIXL_COP_2_MSG_STS, 0);
1248 COP2_PRINT_4(RMIXL_COP_2_MSG_STS, 1);
1249
1250 COP2_PRINT_4(RMIXL_COP_2_MSG_CFG, 0);
1251 COP2_PRINT_4(RMIXL_COP_2_MSG_CFG, 1);
1252
1253 COP2_PRINT_4(RMIXL_COP_2_MSG_BSZ, 0);
1254 COP2_PRINT_4(RMIXL_COP_2_MSG_BSZ, 1);
1255 COP2_PRINT_4(RMIXL_COP_2_MSG_BSZ, 2);
1256 COP2_PRINT_4(RMIXL_COP_2_MSG_BSZ, 3);
1257 COP2_PRINT_4(RMIXL_COP_2_MSG_BSZ, 4);
1258 COP2_PRINT_4(RMIXL_COP_2_MSG_BSZ, 5);
1259 COP2_PRINT_4(RMIXL_COP_2_MSG_BSZ, 6);
1260 COP2_PRINT_4(RMIXL_COP_2_MSG_BSZ, 7);
1261
1262 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 0, 0);
1263 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 0, 1);
1264 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 0, 2);
1265 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 0, 3);
1266 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 0, 4);
1267 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 0, 5);
1268 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 0, 6);
1269 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 0, 7);
1270
1271 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 1, 0);
1272 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 1, 1);
1273 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 1, 2);
1274 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 1, 3);
1275 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 1, 4);
1276 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 1, 5);
1277 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 1, 6);
1278 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 1, 7);
1279
1280 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 2, 0);
1281 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 2, 1);
1282 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 2, 2);
1283 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 2, 3);
1284 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 2, 4);
1285 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 2, 5);
1286 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 2, 6);
1287 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 2, 7);
1288
1289 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 3, 0);
1290 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 3, 1);
1291 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 3, 2);
1292 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 3, 3);
1293 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 3, 4);
1294 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 3, 5);
1295 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 3, 6);
1296 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 3, 7);
1297
1298 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 4, 0);
1299 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 4, 1);
1300 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 4, 2);
1301 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 4, 3);
1302 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 4, 4);
1303 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 4, 5);
1304 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 4, 6);
1305 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 4, 7);
1306
1307 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 5, 0);
1308 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 5, 1);
1309 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 5, 2);
1310 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 5, 3);
1311 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 5, 4);
1312 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 5, 5);
1313 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 5, 6);
1314 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 5, 7);
1315
1316 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 6, 0);
1317 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 6, 1);
1318 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 6, 2);
1319 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 6, 3);
1320 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 6, 4);
1321 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 6, 5);
1322 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 6, 6);
1323 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 6, 7);
1324
1325 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 7, 0);
1326 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 7, 1);
1327 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 7, 2);
1328 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 7, 3);
1329 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 7, 4);
1330 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 7, 5);
1331 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 7, 6);
1332 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 7, 7);
1333
1334 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 8, 0);
1335 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 8, 1);
1336 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 8, 2);
1337 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 8, 3);
1338 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 8, 4);
1339 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 8, 5);
1340 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 8, 6);
1341 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 8, 7);
1342
1343 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 9, 0);
1344 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 9, 1);
1345 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 9, 2);
1346 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 9, 3);
1347 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 9, 4);
1348 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 9, 5);
1349 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 9, 6);
1350 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 9, 7);
1351
1352 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 10, 0);
1353 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 10, 1);
1354 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 10, 2);
1355 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 10, 3);
1356 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 10, 4);
1357 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 10, 5);
1358 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 10, 6);
1359 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 10, 7);
1360
1361 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 11, 0);
1362 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 11, 1);
1363 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 11, 2);
1364 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 11, 3);
1365 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 11, 4);
1366 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 11, 5);
1367 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 11, 6);
1368 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 11, 7);
1369
1370 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 12, 0);
1371 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 12, 1);
1372 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 12, 2);
1373 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 12, 3);
1374 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 12, 4);
1375 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 12, 5);
1376 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 12, 6);
1377 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 12, 7);
1378
1379 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 13, 0);
1380 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 13, 1);
1381 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 13, 2);
1382 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 13, 3);
1383 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 13, 4);
1384 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 13, 5);
1385 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 13, 6);
1386 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 13, 7);
1387
1388 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 14, 0);
1389 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 14, 1);
1390 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 14, 2);
1391 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 14, 3);
1392 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 14, 4);
1393 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 14, 5);
1394 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 14, 6);
1395 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 14, 7);
1396
1397 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 15, 0);
1398 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 15, 1);
1399 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 15, 2);
1400 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 15, 3);
1401 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 15, 4);
1402 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 15, 5);
1403 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 15, 6);
1404 COP2_PRINT_4(RMIXL_COP_2_CREDITS + 15, 7);
1405 }
1406
1407 rmixl_cp2_restore(cp0_status);
1408 }
1409
1410
1411 void
1412 rmixl_fmn_cc_dump(void)
1413 {
1414 const bool is_xlp_p = cpu_rmixlp(mips_options.mips_cpu);
1415
1416 if (is_xlp_p) {
1417 } else {
1418 uint32_t cc[4][8];
1419
1420 FMN_COP2_4SEL_READ(RMIXL_COP_2_CREDITS, 0, &cc[0][0]);
1421 FMN_COP2_4SEL_READ(RMIXL_COP_2_CREDITS, 4, &cc[0][4]);
1422 FMN_COP2_4SEL_READ(RMIXL_COP_2_CREDITS+1, 0, &cc[1][0]);
1423 FMN_COP2_4SEL_READ(RMIXL_COP_2_CREDITS+1, 4, &cc[1][4]);
1424 FMN_COP2_4SEL_READ(RMIXL_COP_2_CREDITS+2, 0, &cc[2][0]);
1425 FMN_COP2_4SEL_READ(RMIXL_COP_2_CREDITS+2, 4, &cc[2][4]);
1426 FMN_COP2_4SEL_READ(RMIXL_COP_2_CREDITS+3, 0, &cc[3][0]);
1427 FMN_COP2_4SEL_READ(RMIXL_COP_2_CREDITS+3, 4, &cc[3][4]);
1428
1429 printf("%s: cpu%u\n", __func__, cpu_number());
1430 for (size_t i=0; i < 4; i++) {
1431 for (size_t j=0; j < 8; j++)
1432 printf(" %#x,", cc[i][j]);
1433 printf("\n");
1434 }
1435 }
1436 }
1437 #endif /* FMN_DEBUG */
1438