2 * SPDX-License-Identifier: BSD-3-Clause
4 * Copyright (c) 2003-2009 RMI Corporation
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of RMI Corporation, nor the names of its contributors,
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
34 #include <sys/types.h>
35 #include <sys/systm.h>
36 #include <sys/param.h>
38 #include <sys/mutex.h>
40 #include <sys/limits.h>
45 #include <sys/kernel.h>
46 #include <sys/kthread.h>
47 #include <sys/resourcevar.h>
48 #include <sys/sched.h>
49 #include <sys/unistd.h>
50 #include <sys/sysctl.h>
51 #include <sys/malloc.h>
53 #include <machine/reg.h>
54 #include <machine/cpu.h>
55 #include <machine/hwfunc.h>
56 #include <machine/mips_opcode.h>
58 #include <machine/intr_machdep.h>
59 #include <mips/rmi/interrupt.h>
60 #include <mips/rmi/msgring.h>
61 #include <mips/rmi/pic.h>
62 #include <mips/rmi/board.h>
64 #define MSGRNG_CC_INIT_CPU_DEST(dest, counter) \
66 msgrng_write_cc(MSGRNG_CC_##dest##_REG, counter[dest][0], 0 ); \
67 msgrng_write_cc(MSGRNG_CC_##dest##_REG, counter[dest][1], 1 ); \
68 msgrng_write_cc(MSGRNG_CC_##dest##_REG, counter[dest][2], 2 ); \
69 msgrng_write_cc(MSGRNG_CC_##dest##_REG, counter[dest][3], 3 ); \
70 msgrng_write_cc(MSGRNG_CC_##dest##_REG, counter[dest][4], 4 ); \
71 msgrng_write_cc(MSGRNG_CC_##dest##_REG, counter[dest][5], 5 ); \
72 msgrng_write_cc(MSGRNG_CC_##dest##_REG, counter[dest][6], 6 ); \
73 msgrng_write_cc(MSGRNG_CC_##dest##_REG, counter[dest][7], 7 ); \
78 * Keep track of our message ring handler threads, each core has a
79 * different message station. Ideally we will need to start a few
80 * message handling threads every core, and wake them up depending on
83 struct msgring_thread {
85 struct thread *thread; /* msgring handler threads */
86 int needed; /* thread needs to wake up */
87 } threads[XLR_NTHREADS];
88 int running; /* number of threads running */
89 int nthreads; /* number of threads started */
90 struct mtx lock; /* for changing running/active */
92 static struct msgring_thread msgring_threads[XLR_MAX_CORES];
93 static struct proc *msgring_proc; /* all threads are under a proc */
96 * The maximum number of software message handler threads to be started
97 * per core. Default is 3 per core
99 static int msgring_maxthreads = 3;
100 TUNABLE_INT("hw.fmn.maxthreads", &msgring_maxthreads);
103 * The device drivers can register a handler for the messages sent
104 * from a station (corresponding to the device).
106 struct tx_stn_handler {
107 msgring_handler action;
110 static struct tx_stn_handler msgmap[MSGRNG_NSTATIONS];
111 static struct mtx msgmap_lock;
114 * Initialize the messaging subsystem.
116 * Message Stations are shared among all threads in a cpu core, this
117 * has to be called once from every core which is online.
120 xlr_msgring_cpu_init(void)
122 struct stn_cc *cc_config;
123 struct bucket_size *bucket_sizes;
127 KASSERT(xlr_thr_id() == 0,
128 ("xlr_msgring_cpu_init from non-zero thread"));
130 bucket_sizes = xlr_board_info.bucket_sizes;
131 cc_config = xlr_board_info.credit_configs[id];
133 flags = msgrng_access_enable();
136 * FMN messages are received in 8 buckets per core, set up
137 * the bucket sizes for each bucket
139 msgrng_write_bucksize(0, bucket_sizes->bucket[id * 8 + 0]);
140 msgrng_write_bucksize(1, bucket_sizes->bucket[id * 8 + 1]);
141 msgrng_write_bucksize(2, bucket_sizes->bucket[id * 8 + 2]);
142 msgrng_write_bucksize(3, bucket_sizes->bucket[id * 8 + 3]);
143 msgrng_write_bucksize(4, bucket_sizes->bucket[id * 8 + 4]);
144 msgrng_write_bucksize(5, bucket_sizes->bucket[id * 8 + 5]);
145 msgrng_write_bucksize(6, bucket_sizes->bucket[id * 8 + 6]);
146 msgrng_write_bucksize(7, bucket_sizes->bucket[id * 8 + 7]);
149 * For sending FMN messages, we need credits on the destination
150 * bucket. Program the credits this core has on the 128 possible
151 * destination buckets.
152 * We cannot use a loop here, because the first argument has
153 * to be a constant integer value.
155 MSGRNG_CC_INIT_CPU_DEST(0, cc_config->counters);
156 MSGRNG_CC_INIT_CPU_DEST(1, cc_config->counters);
157 MSGRNG_CC_INIT_CPU_DEST(2, cc_config->counters);
158 MSGRNG_CC_INIT_CPU_DEST(3, cc_config->counters);
159 MSGRNG_CC_INIT_CPU_DEST(4, cc_config->counters);
160 MSGRNG_CC_INIT_CPU_DEST(5, cc_config->counters);
161 MSGRNG_CC_INIT_CPU_DEST(6, cc_config->counters);
162 MSGRNG_CC_INIT_CPU_DEST(7, cc_config->counters);
163 MSGRNG_CC_INIT_CPU_DEST(8, cc_config->counters);
164 MSGRNG_CC_INIT_CPU_DEST(9, cc_config->counters);
165 MSGRNG_CC_INIT_CPU_DEST(10, cc_config->counters);
166 MSGRNG_CC_INIT_CPU_DEST(11, cc_config->counters);
167 MSGRNG_CC_INIT_CPU_DEST(12, cc_config->counters);
168 MSGRNG_CC_INIT_CPU_DEST(13, cc_config->counters);
169 MSGRNG_CC_INIT_CPU_DEST(14, cc_config->counters);
170 MSGRNG_CC_INIT_CPU_DEST(15, cc_config->counters);
171 msgrng_restore(flags);
175 * Boot time init, called only once
178 xlr_msgring_config(void)
180 mtx_init(&msgmap_lock, "msgring", NULL, MTX_SPIN);
183 if (msgring_maxthreads < 0 || msgring_maxthreads > XLR_NTHREADS)
184 msgring_maxthreads = XLR_NTHREADS;
188 * Drain out max_messages for the buckets set in the bucket mask.
189 * Use max_messages = 0 to drain out all messages.
192 xlr_msgring_handler(uint8_t bucket_mask, uint32_t max_messages)
195 int size = 0, code = 0, rx_stid = 0;
196 struct msgrng_msg msg;
197 struct tx_stn_handler *he;
198 unsigned int status = 0;
199 unsigned long mflags;
204 mflags = msgrng_access_enable();
206 msgbuckets = (~msgrng_read_status() >> 24) & bucket_mask;
208 /* all buckets empty, break */
212 for (bucket = 0; bucket < 8; bucket++) {
213 if ((msgbuckets & (1 << bucket)) == 0) /* empty */
216 status = message_receive(bucket, &size, &code,
221 he = &msgmap[rx_stid];
222 if (he->action == NULL) {
223 printf("[%s]: No Handler for message from "
224 "stn_id=%d, bucket=%d, size=%d, msg0=%jx\n",
225 __func__, rx_stid, bucket, size,
226 (uintmax_t)msg.msg0);
228 msgrng_restore(mflags);
229 (*he->action)(bucket, size, code, rx_stid,
231 mflags = msgrng_access_enable();
233 if (max_messages > 0 && n_msgs >= max_messages)
239 msgrng_restore(mflags);
244 * XLR COP2 supports watermark interrupts based on the number of
245 * messages pending in all the buckets in the core. We increase
246 * the watermark until all the possible handler threads in the core
250 msgrng_setconfig(int running, int nthr)
252 uint32_t config, mflags;
253 int watermark = 1; /* non zero needed */
256 KASSERT(nthr >= 0 && nthr <= msgring_maxthreads,
257 ("Bad value of nthr %d", nthr));
258 KASSERT(running <= nthr, ("Bad value of running %d", running));
260 if (running == nthr) {
264 case 0: break; /* keep default */
266 watermark = 32; break;
268 watermark = 48; break;
270 watermark = 56; break;
272 wm_intr_value = 0x2; /* set watermark enable interrupt */
274 mflags = msgrng_access_enable();
275 config = (watermark << 24) | (IRQ_MSGRING << 16) | (1 << 8) |
277 /* clear pending interrupts, they will get re-raised if still valid */
278 write_c0_eirr64(1ULL << IRQ_MSGRING);
279 msgrng_write_config(config);
280 msgrng_restore(mflags);
284 static int msgring_nintr[XLR_MAX_CORES];
285 static int msgring_badintr[XLR_MAX_CORES];
286 static int msgring_wakeup_sleep[XLR_MAX_CORES * XLR_NTHREADS];
287 static int msgring_wakeup_nosleep[XLR_MAX_CORES * XLR_NTHREADS];
288 static int msgring_nmsgs[XLR_MAX_CORES * XLR_NTHREADS];
291 msgring_process_fast_intr(void *arg)
293 struct msgring_thread *mthd;
298 core = xlr_core_id();
299 mthd = &msgring_threads[core];
300 msgring_nintr[core]++;
301 mtx_lock_spin(&mthd->lock);
303 if(nt >= mthd->nthreads) {
304 msgring_badintr[core]++;
305 mtx_unlock_spin(&mthd->lock);
306 return (FILTER_HANDLED);
309 td = mthd->threads[nt].thread;
310 mflags = msgrng_access_enable();
312 /* default value with interrupts disabled */
313 msgrng_write_config((1 << 24) | (IRQ_MSGRING << 16) | (1 << 8));
314 /* clear pending interrupts */
315 write_c0_eirr64(1ULL << IRQ_MSGRING);
316 msgrng_restore(mflags);
317 mtx_unlock_spin(&mthd->lock);
319 /* wake up the target thread */
320 mthd->threads[nt].needed = 1;
322 if (TD_AWAITING_INTR(td)) {
323 msgring_wakeup_sleep[core*4+nt]++;
325 sched_add(td, SRQ_INTR);
327 msgring_wakeup_nosleep[core*4+nt]++;
329 return (FILTER_HANDLED);
333 msgring_process(void *arg)
335 struct msgring_thread *mthd;
337 int hwtid, tid, core;
340 hwtid = (intptr_t)arg;
343 mthd = &msgring_threads[core];
344 td = mthd->threads[tid].thread;
345 KASSERT(curthread == td,
346 ("Incorrect thread core %d, thread %d", core, hwtid));
348 /* First bind this thread to the right CPU */
350 sched_bind(td, xlr_hwtid_to_cpuid[hwtid]);
353 mtx_lock_spin(&mthd->lock);
354 ++mthd->nthreads; /* Active thread count */
355 mtx_unlock_spin(&mthd->lock);
357 /* start processing messages */
359 mtx_lock_spin(&mthd->lock);
361 msgrng_setconfig(mthd->running, mthd->nthreads);
362 mtx_unlock_spin(&mthd->lock);
364 atomic_store_rel_int(&mthd->threads[tid].needed, 0);
365 nmsgs = xlr_msgring_handler(0xff, 0);
366 msgring_nmsgs[hwtid] += nmsgs;
368 mtx_lock_spin(&mthd->lock);
370 msgrng_setconfig(mthd->running, mthd->nthreads);
371 mtx_unlock_spin(&mthd->lock);
375 if (mthd->threads[tid].needed) {
379 sched_class(td, PRI_ITHD);
381 mi_switch(SW_VOL, NULL);
387 create_msgring_thread(int hwtid)
389 struct msgring_thread *mthd;
396 mthd = &msgring_threads[core];
398 mtx_init(&mthd->lock, "msgrngcore", NULL, MTX_SPIN);
399 mthd->running = mthd->nthreads = 0;
401 error = kproc_kthread_add(msgring_process, (void *)(uintptr_t)hwtid,
402 &msgring_proc, &td, RFSTOPPED, 2, "msgrngproc",
405 panic("kproc_kthread_add() failed with %d", error);
406 mthd->threads[tid].thread = td;
409 sched_class(td, PRI_ITHD);
410 sched_add(td, SRQ_INTR);
412 CTR2(KTR_INTR, "%s: created %s", __func__, td->td_name);
416 register_msgring_handler(int startb, int endb, msgring_handler action,
421 static int msgring_int_enabled = 0;
423 KASSERT(startb >= 0 && startb <= endb && endb < MSGRNG_NSTATIONS,
424 ("Invalid value for for bucket range %d,%d", startb, endb));
426 mtx_lock_spin(&msgmap_lock);
427 for (i = startb; i <= endb; i++) {
428 KASSERT(msgmap[i].action == NULL,
429 ("Bucket %d already used [action %p]", i, msgmap[i].action));
430 msgmap[i].action = action;
433 mtx_unlock_spin(&msgmap_lock);
435 if (xlr_test_and_set(&msgring_int_enabled)) {
436 create_msgring_thread(0);
437 if (msgring_maxthreads > xlr_threads_per_core)
438 msgring_maxthreads = xlr_threads_per_core;
439 cpu_establish_hardintr("msgring", msgring_process_fast_intr,
440 NULL, NULL, IRQ_MSGRING,
441 INTR_TYPE_NET, &cookie);
447 * Start message ring processing threads on other CPUs, after SMP start
450 start_msgring_threads(void *arg)
454 for (hwt = 1; hwt < XLR_MAX_CORES * XLR_NTHREADS; hwt++) {
455 if ((xlr_hw_thread_mask & (1 << hwt)) == 0)
457 tid = hwt % XLR_NTHREADS;
458 if (tid >= msgring_maxthreads)
460 create_msgring_thread(hwt);
464 SYSINIT(start_msgring_threads, SI_SUB_SMP, SI_ORDER_MIDDLE,
465 start_msgring_threads, NULL);
468 * DEBUG support, XXX: static buffer, not locked
471 sys_print_debug(SYSCTL_HANDLER_ARGS)
476 sbuf_new_for_sysctl(&sb, NULL, 64, req);
478 "\nID INTR ER WU-SLP WU-ERR MSGS\n");
479 for (i = 0; i < 32; i++) {
480 if ((xlr_hw_thread_mask & (1 << i)) == 0)
482 sbuf_printf(&sb, "%2d: %8d %4d %8d %8d %8d\n", i,
483 msgring_nintr[i/4], msgring_badintr[i/4],
484 msgring_wakeup_sleep[i], msgring_wakeup_nosleep[i],
487 error = sbuf_finish(&sb);
492 SYSCTL_PROC(_debug, OID_AUTO, msgring, CTLTYPE_STRING | CTLFLAG_RD, 0, 0,
493 sys_print_debug, "A", "msgring debug info");