]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/mips/rmi/fmn.c
Partial merge of the SPDX changes
[FreeBSD/FreeBSD.git] / sys / mips / rmi / fmn.c
1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright (c) 2003-2009 RMI Corporation
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
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.
18  *
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
29  * SUCH DAMAGE.
30  *
31  * RMI_BSD */
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
34 #include <sys/types.h>
35 #include <sys/systm.h>
36 #include <sys/param.h>
37 #include <sys/lock.h>
38 #include <sys/mutex.h>
39 #include <sys/proc.h>
40 #include <sys/limits.h>
41 #include <sys/bus.h>
42 #include <sys/sbuf.h>
43
44 #include <sys/ktr.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>
52
53 #include <machine/reg.h>
54 #include <machine/cpu.h>
55 #include <machine/hwfunc.h>
56 #include <machine/mips_opcode.h>
57
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>
63
64 #define MSGRNG_CC_INIT_CPU_DEST(dest, counter) \
65 do { \
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 ); \
74 } while(0)
75
76
77 /*
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
81  * load
82  */
83 struct msgring_thread {
84         struct {
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 */
91 };
92 static struct msgring_thread msgring_threads[XLR_MAX_CORES];
93 static struct proc *msgring_proc;       /* all threads are under a proc */
94
95 /*
96  * The maximum number of software message handler threads to be started 
97  * per core. Default is 3 per core
98  */
99 static int      msgring_maxthreads = 3; 
100 TUNABLE_INT("hw.fmn.maxthreads", &msgring_maxthreads);
101
102 /* 
103  * The device drivers can register a handler for the messages sent
104  * from a station (corresponding to the device). 
105  */
106 struct tx_stn_handler {
107         msgring_handler action;
108         void *arg;
109 };
110 static struct tx_stn_handler msgmap[MSGRNG_NSTATIONS];
111 static struct mtx       msgmap_lock;
112
113 /*
114  * Initialize the messaging subsystem.
115  * 
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.
118  */
119 void 
120 xlr_msgring_cpu_init(void)
121 {
122         struct stn_cc *cc_config;
123         struct bucket_size *bucket_sizes;
124         uint32_t flags;
125         int id;
126
127         KASSERT(xlr_thr_id() == 0,
128                 ("xlr_msgring_cpu_init from non-zero thread"));
129         id = xlr_core_id();
130         bucket_sizes = xlr_board_info.bucket_sizes;
131         cc_config = xlr_board_info.credit_configs[id];
132
133         flags = msgrng_access_enable();
134
135         /*
136          * FMN messages are received in 8 buckets per core, set up
137          * the bucket sizes for each bucket
138          */
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]);
147
148         /* 
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.
154          */
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);
172 }
173
174 /*
175  * Boot time init, called only once
176  */
177 void 
178 xlr_msgring_config(void)
179 {
180         mtx_init(&msgmap_lock, "msgring", NULL, MTX_SPIN);
181         
182         /* check value */
183         if (msgring_maxthreads < 0 || msgring_maxthreads > XLR_NTHREADS)
184                 msgring_maxthreads = XLR_NTHREADS;
185 }
186
187 /*
188  * Drain out max_messages for the buckets set in the bucket mask. 
189  * Use max_messages = 0 to drain out all messages.
190  */
191 uint32_t
192 xlr_msgring_handler(uint8_t bucket_mask, uint32_t max_messages)
193 {
194         int bucket = 0;
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;
200         uint32_t n_msgs;
201         uint32_t msgbuckets;
202
203         n_msgs = 0;
204         mflags = msgrng_access_enable();
205         for (;;) {
206                 msgbuckets = (~msgrng_read_status() >> 24) & bucket_mask;
207
208                 /* all buckets empty, break */
209                 if (msgbuckets == 0)
210                         break;
211
212                 for (bucket = 0; bucket < 8; bucket++) {
213                         if ((msgbuckets & (1 << bucket)) == 0) /* empty */
214                                 continue;
215
216                         status = message_receive(bucket, &size, &code,
217                             &rx_stid, &msg);
218                         if (status != 0)
219                                 continue;
220                         n_msgs++;
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);
227                         } else {
228                                 msgrng_restore(mflags);
229                                 (*he->action)(bucket, size, code, rx_stid,
230                                     &msg, he->arg);
231                                 mflags = msgrng_access_enable();
232                         }
233                         if (max_messages > 0 && n_msgs >= max_messages)
234                                 goto done;
235                 }
236         }
237
238 done:
239         msgrng_restore(mflags);
240         return (n_msgs);
241 }
242
243 /* 
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
247  * are woken up.
248  */
249 static void
250 msgrng_setconfig(int running, int nthr)
251 {
252         uint32_t config, mflags;
253         int watermark = 1;      /* non zero needed */
254         int wm_intr_value;
255
256         KASSERT(nthr >= 0 && nthr <= msgring_maxthreads,
257             ("Bad value of nthr %d", nthr));
258         KASSERT(running <= nthr, ("Bad value of running %d", running));
259
260         if (running == nthr) {
261                 wm_intr_value = 0;
262         } else {
263                 switch (running) {
264                 case 0: break;          /* keep default */
265                 case 1:
266                         watermark = 32; break;
267                 case 2:
268                         watermark = 48; break;
269                 case 3: 
270                         watermark = 56; break;
271                 }
272                 wm_intr_value = 0x2;    /* set watermark enable interrupt */
273         }
274         mflags = msgrng_access_enable();
275         config = (watermark << 24) | (IRQ_MSGRING << 16) | (1 << 8) |
276                 wm_intr_value;
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);
281 }
282
283 /* Debug counters */
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];
289
290 static int
291 msgring_process_fast_intr(void *arg)
292 {
293         struct msgring_thread *mthd;
294         struct thread   *td;
295         uint32_t        mflags;
296         int             core, nt;
297
298         core = xlr_core_id();
299         mthd = &msgring_threads[core];
300         msgring_nintr[core]++;
301         mtx_lock_spin(&mthd->lock);
302         nt = mthd->running;
303         if(nt >= mthd->nthreads) {
304                 msgring_badintr[core]++;
305                 mtx_unlock_spin(&mthd->lock);
306                 return (FILTER_HANDLED);
307         }
308
309         td = mthd->threads[nt].thread;
310         mflags = msgrng_access_enable();
311
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);
318
319         /* wake up the target thread */
320         mthd->threads[nt].needed = 1;
321         thread_lock(td);
322         if (TD_AWAITING_INTR(td)) {
323                 msgring_wakeup_sleep[core*4+nt]++;
324                 TD_CLR_IWAIT(td);
325                 sched_add(td, SRQ_INTR);
326         } else
327                 msgring_wakeup_nosleep[core*4+nt]++;
328         thread_unlock(td);
329         return (FILTER_HANDLED);
330 }
331
332 static void
333 msgring_process(void *arg)
334 {
335         struct msgring_thread *mthd;
336         struct thread   *td;
337         int             hwtid, tid, core;
338         int             nmsgs;
339
340         hwtid = (intptr_t)arg;
341         core = hwtid / 4;
342         tid = hwtid % 4;
343         mthd = &msgring_threads[core];
344         td = mthd->threads[tid].thread;
345         KASSERT(curthread == td,
346             ("Incorrect thread core %d, thread %d", core, hwtid));
347
348         /* First bind this thread to the right CPU */
349         thread_lock(td);
350         sched_bind(td, xlr_hwtid_to_cpuid[hwtid]);
351         thread_unlock(td);
352
353         mtx_lock_spin(&mthd->lock);
354         ++mthd->nthreads;               /* Active thread count */
355         mtx_unlock_spin(&mthd->lock);
356
357         /* start processing messages */
358         for(;;) {
359                 mtx_lock_spin(&mthd->lock);
360                 ++mthd->running;
361                 msgrng_setconfig(mthd->running, mthd->nthreads);
362                 mtx_unlock_spin(&mthd->lock);
363
364                 atomic_store_rel_int(&mthd->threads[tid].needed, 0);
365                 nmsgs = xlr_msgring_handler(0xff, 0);
366                 msgring_nmsgs[hwtid] += nmsgs;
367
368                 mtx_lock_spin(&mthd->lock);
369                 --mthd->running;
370                 msgrng_setconfig(mthd->running, mthd->nthreads);
371                 mtx_unlock_spin(&mthd->lock);
372
373                 /* sleep */
374                 thread_lock(td);
375                 if (mthd->threads[tid].needed) {
376                         thread_unlock(td);
377                         continue;
378                 }
379                 sched_class(td, PRI_ITHD);
380                 TD_SET_IWAIT(td);
381                 mi_switch(SW_VOL, NULL);
382                 thread_unlock(td);
383         }
384 }
385
386 static void 
387 create_msgring_thread(int hwtid)
388 {
389         struct msgring_thread *mthd;
390         struct thread *td;
391         int     tid, core;
392         int     error;
393
394         core = hwtid / 4;
395         tid = hwtid % 4;
396         mthd = &msgring_threads[core];
397         if (tid == 0) {
398                 mtx_init(&mthd->lock, "msgrngcore", NULL, MTX_SPIN);
399                 mthd->running = mthd->nthreads = 0;
400         }
401         error = kproc_kthread_add(msgring_process, (void *)(uintptr_t)hwtid,
402             &msgring_proc, &td, RFSTOPPED, 2, "msgrngproc",
403             "msgthr%d", hwtid);
404         if (error)
405                 panic("kproc_kthread_add() failed with %d", error);
406         mthd->threads[tid].thread = td;
407
408         thread_lock(td);
409         sched_class(td, PRI_ITHD);
410         sched_add(td, SRQ_INTR);
411         thread_unlock(td);
412         CTR2(KTR_INTR, "%s: created %s", __func__, td->td_name);
413 }
414
415 int 
416 register_msgring_handler(int startb, int endb, msgring_handler action,
417     void *arg)
418 {
419         void    *cookie;
420         int     i;
421         static int msgring_int_enabled = 0;
422
423         KASSERT(startb >= 0 && startb <= endb && endb < MSGRNG_NSTATIONS,
424             ("Invalid value for for bucket range %d,%d", startb, endb));
425
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;
431                 msgmap[i].arg = arg;
432         }
433         mtx_unlock_spin(&msgmap_lock);
434
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);
442         }
443         return (0);
444 }
445
446 /*
447  * Start message ring processing threads on other CPUs, after SMP start
448  */
449 static void
450 start_msgring_threads(void *arg)
451 {
452         int     hwt, tid;
453
454         for (hwt = 1; hwt < XLR_MAX_CORES * XLR_NTHREADS; hwt++) {
455                 if ((xlr_hw_thread_mask & (1 << hwt)) == 0)
456                         continue;
457                 tid = hwt % XLR_NTHREADS;
458                 if (tid >= msgring_maxthreads)
459                         continue;
460                 create_msgring_thread(hwt);
461         }
462 }
463
464 SYSINIT(start_msgring_threads, SI_SUB_SMP, SI_ORDER_MIDDLE,
465     start_msgring_threads, NULL);
466
467 /*
468  * DEBUG support, XXX: static buffer, not locked 
469  */
470 static int
471 sys_print_debug(SYSCTL_HANDLER_ARGS)
472 {
473         struct sbuf sb;
474         int error, i;
475
476         sbuf_new_for_sysctl(&sb, NULL, 64, req);
477         sbuf_printf(&sb, 
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)
481                         continue;
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],
485                     msgring_nmsgs[i]);
486         } 
487         error = sbuf_finish(&sb);
488         sbuf_delete(&sb);
489         return (error);
490 }
491
492 SYSCTL_PROC(_debug, OID_AUTO, msgring, CTLTYPE_STRING | CTLFLAG_RD, 0, 0,
493     sys_print_debug, "A", "msgring debug info");