fmn.c revision 331722
1/*-
2 * Copyright (c) 2003-2009 RMI Corporation
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of RMI Corporation, nor the names of its contributors,
14 *    may be used to endorse or promote products derived from this software
15 *    without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * RMI_BSD */
30#include <sys/cdefs.h>
31__FBSDID("$FreeBSD: stable/11/sys/mips/rmi/fmn.c 331722 2018-03-29 02:50:57Z eadler $");
32#include <sys/types.h>
33#include <sys/systm.h>
34#include <sys/param.h>
35#include <sys/lock.h>
36#include <sys/mutex.h>
37#include <sys/proc.h>
38#include <sys/limits.h>
39#include <sys/bus.h>
40#include <sys/sbuf.h>
41
42#include <sys/ktr.h>
43#include <sys/kernel.h>
44#include <sys/kthread.h>
45#include <sys/resourcevar.h>
46#include <sys/sched.h>
47#include <sys/unistd.h>
48#include <sys/sysctl.h>
49#include <sys/malloc.h>
50
51#include <machine/reg.h>
52#include <machine/cpu.h>
53#include <machine/hwfunc.h>
54#include <machine/mips_opcode.h>
55
56#include <machine/intr_machdep.h>
57#include <mips/rmi/interrupt.h>
58#include <mips/rmi/msgring.h>
59#include <mips/rmi/pic.h>
60#include <mips/rmi/board.h>
61
62#define MSGRNG_CC_INIT_CPU_DEST(dest, counter) \
63do { \
64     msgrng_write_cc(MSGRNG_CC_##dest##_REG, counter[dest][0], 0 ); \
65     msgrng_write_cc(MSGRNG_CC_##dest##_REG, counter[dest][1], 1 ); \
66     msgrng_write_cc(MSGRNG_CC_##dest##_REG, counter[dest][2], 2 ); \
67     msgrng_write_cc(MSGRNG_CC_##dest##_REG, counter[dest][3], 3 ); \
68     msgrng_write_cc(MSGRNG_CC_##dest##_REG, counter[dest][4], 4 ); \
69     msgrng_write_cc(MSGRNG_CC_##dest##_REG, counter[dest][5], 5 ); \
70     msgrng_write_cc(MSGRNG_CC_##dest##_REG, counter[dest][6], 6 ); \
71     msgrng_write_cc(MSGRNG_CC_##dest##_REG, counter[dest][7], 7 ); \
72} while(0)
73
74
75/*
76 * Keep track of our message ring handler threads, each core has a
77 * different message station. Ideally we will need to start a few
78 * message handling threads every core, and wake them up depending on
79 * load
80 */
81struct msgring_thread {
82	struct {
83		struct thread	*thread; /* msgring handler threads */
84		int	needed;		/* thread needs to wake up */
85	} threads[XLR_NTHREADS];
86	int	running;		/* number of threads running */
87	int	nthreads;		/* number of threads started */
88	struct mtx lock;		/* for changing running/active */
89};
90static struct msgring_thread msgring_threads[XLR_MAX_CORES];
91static struct proc *msgring_proc;	/* all threads are under a proc */
92
93/*
94 * The maximum number of software message handler threads to be started
95 * per core. Default is 3 per core
96 */
97static int	msgring_maxthreads = 3;
98TUNABLE_INT("hw.fmn.maxthreads", &msgring_maxthreads);
99
100/*
101 * The device drivers can register a handler for the messages sent
102 * from a station (corresponding to the device).
103 */
104struct tx_stn_handler {
105	msgring_handler action;
106	void *arg;
107};
108static struct tx_stn_handler msgmap[MSGRNG_NSTATIONS];
109static struct mtx	msgmap_lock;
110
111/*
112 * Initialize the messaging subsystem.
113 *
114 * Message Stations are shared among all threads in a cpu core, this
115 * has to be called once from every core which is online.
116 */
117void
118xlr_msgring_cpu_init(void)
119{
120	struct stn_cc *cc_config;
121	struct bucket_size *bucket_sizes;
122	uint32_t flags;
123	int id;
124
125	KASSERT(xlr_thr_id() == 0,
126		("xlr_msgring_cpu_init from non-zero thread"));
127	id = xlr_core_id();
128	bucket_sizes = xlr_board_info.bucket_sizes;
129	cc_config = xlr_board_info.credit_configs[id];
130
131	flags = msgrng_access_enable();
132
133	/*
134	 * FMN messages are received in 8 buckets per core, set up
135	 * the bucket sizes for each bucket
136	 */
137	msgrng_write_bucksize(0, bucket_sizes->bucket[id * 8 + 0]);
138	msgrng_write_bucksize(1, bucket_sizes->bucket[id * 8 + 1]);
139	msgrng_write_bucksize(2, bucket_sizes->bucket[id * 8 + 2]);
140	msgrng_write_bucksize(3, bucket_sizes->bucket[id * 8 + 3]);
141	msgrng_write_bucksize(4, bucket_sizes->bucket[id * 8 + 4]);
142	msgrng_write_bucksize(5, bucket_sizes->bucket[id * 8 + 5]);
143	msgrng_write_bucksize(6, bucket_sizes->bucket[id * 8 + 6]);
144	msgrng_write_bucksize(7, bucket_sizes->bucket[id * 8 + 7]);
145
146	/*
147	 * For sending FMN messages, we need credits on the destination
148	 * bucket.  Program the credits this core has on the 128 possible
149	 * destination buckets.
150	 * We cannot use a loop here, because the first argument has
151	 * to be a constant integer value.
152	 */
153	MSGRNG_CC_INIT_CPU_DEST(0,  cc_config->counters);
154	MSGRNG_CC_INIT_CPU_DEST(1,  cc_config->counters);
155	MSGRNG_CC_INIT_CPU_DEST(2,  cc_config->counters);
156	MSGRNG_CC_INIT_CPU_DEST(3,  cc_config->counters);
157	MSGRNG_CC_INIT_CPU_DEST(4,  cc_config->counters);
158	MSGRNG_CC_INIT_CPU_DEST(5,  cc_config->counters);
159	MSGRNG_CC_INIT_CPU_DEST(6,  cc_config->counters);
160	MSGRNG_CC_INIT_CPU_DEST(7,  cc_config->counters);
161	MSGRNG_CC_INIT_CPU_DEST(8,  cc_config->counters);
162	MSGRNG_CC_INIT_CPU_DEST(9,  cc_config->counters);
163	MSGRNG_CC_INIT_CPU_DEST(10, cc_config->counters);
164	MSGRNG_CC_INIT_CPU_DEST(11, cc_config->counters);
165	MSGRNG_CC_INIT_CPU_DEST(12, cc_config->counters);
166	MSGRNG_CC_INIT_CPU_DEST(13, cc_config->counters);
167	MSGRNG_CC_INIT_CPU_DEST(14, cc_config->counters);
168	MSGRNG_CC_INIT_CPU_DEST(15, cc_config->counters);
169	msgrng_restore(flags);
170}
171
172/*
173 * Boot time init, called only once
174 */
175void
176xlr_msgring_config(void)
177{
178	mtx_init(&msgmap_lock, "msgring", NULL, MTX_SPIN);
179
180	/* check value */
181	if (msgring_maxthreads < 0 || msgring_maxthreads > XLR_NTHREADS)
182		msgring_maxthreads = XLR_NTHREADS;
183}
184
185/*
186 * Drain out max_messages for the buckets set in the bucket mask.
187 * Use max_messages = 0 to drain out all messages.
188 */
189uint32_t
190xlr_msgring_handler(uint8_t bucket_mask, uint32_t max_messages)
191{
192	int bucket = 0;
193	int size = 0, code = 0, rx_stid = 0;
194	struct msgrng_msg msg;
195	struct tx_stn_handler *he;
196	unsigned int status = 0;
197	unsigned long mflags;
198	uint32_t n_msgs;
199	uint32_t msgbuckets;
200
201	n_msgs = 0;
202	mflags = msgrng_access_enable();
203	for (;;) {
204		msgbuckets = (~msgrng_read_status() >> 24) & bucket_mask;
205
206		/* all buckets empty, break */
207		if (msgbuckets == 0)
208			break;
209
210		for (bucket = 0; bucket < 8; bucket++) {
211			if ((msgbuckets & (1 << bucket)) == 0) /* empty */
212				continue;
213
214			status = message_receive(bucket, &size, &code,
215			    &rx_stid, &msg);
216			if (status != 0)
217				continue;
218			n_msgs++;
219			he = &msgmap[rx_stid];
220			if (he->action == NULL) {
221				printf("[%s]: No Handler for message from "
222				    "stn_id=%d, bucket=%d, size=%d, msg0=%jx\n",
223				    __func__, rx_stid, bucket, size,
224				    (uintmax_t)msg.msg0);
225			} else {
226				msgrng_restore(mflags);
227				(*he->action)(bucket, size, code, rx_stid,
228				    &msg, he->arg);
229				mflags = msgrng_access_enable();
230			}
231			if (max_messages > 0 && n_msgs >= max_messages)
232				goto done;
233		}
234	}
235
236done:
237	msgrng_restore(mflags);
238	return (n_msgs);
239}
240
241/*
242 * XLR COP2 supports watermark interrupts based on the number of
243 * messages pending in all the buckets in the core.  We increase
244 * the watermark until all the possible handler threads in the core
245 * are woken up.
246 */
247static void
248msgrng_setconfig(int running, int nthr)
249{
250	uint32_t config, mflags;
251	int watermark = 1;	/* non zero needed */
252	int wm_intr_value;
253
254	KASSERT(nthr >= 0 && nthr <= msgring_maxthreads,
255	    ("Bad value of nthr %d", nthr));
256	KASSERT(running <= nthr, ("Bad value of running %d", running));
257
258	if (running == nthr) {
259		wm_intr_value = 0;
260	} else {
261		switch (running) {
262		case 0: break;		/* keep default */
263		case 1:
264			watermark = 32; break;
265		case 2:
266			watermark = 48; break;
267		case 3:
268			watermark = 56; break;
269		}
270		wm_intr_value = 0x2;	/* set watermark enable interrupt */
271	}
272	mflags = msgrng_access_enable();
273	config = (watermark << 24) | (IRQ_MSGRING << 16) | (1 << 8) |
274		wm_intr_value;
275	/* clear pending interrupts, they will get re-raised if still valid */
276	write_c0_eirr64(1ULL << IRQ_MSGRING);
277	msgrng_write_config(config);
278	msgrng_restore(mflags);
279}
280
281/* Debug counters */
282static int msgring_nintr[XLR_MAX_CORES];
283static int msgring_badintr[XLR_MAX_CORES];
284static int msgring_wakeup_sleep[XLR_MAX_CORES * XLR_NTHREADS];
285static int msgring_wakeup_nosleep[XLR_MAX_CORES * XLR_NTHREADS];
286static int msgring_nmsgs[XLR_MAX_CORES * XLR_NTHREADS];
287
288static int
289msgring_process_fast_intr(void *arg)
290{
291	struct msgring_thread *mthd;
292	struct thread	*td;
293	uint32_t	mflags;
294	int		core, nt;
295
296	core = xlr_core_id();
297	mthd = &msgring_threads[core];
298	msgring_nintr[core]++;
299	mtx_lock_spin(&mthd->lock);
300	nt = mthd->running;
301	if(nt >= mthd->nthreads) {
302		msgring_badintr[core]++;
303		mtx_unlock_spin(&mthd->lock);
304		return (FILTER_HANDLED);
305	}
306
307	td = mthd->threads[nt].thread;
308	mflags = msgrng_access_enable();
309
310	/* default value with interrupts disabled */
311	msgrng_write_config((1 << 24) | (IRQ_MSGRING << 16) | (1 << 8));
312	/* clear pending interrupts */
313	write_c0_eirr64(1ULL << IRQ_MSGRING);
314	msgrng_restore(mflags);
315	mtx_unlock_spin(&mthd->lock);
316
317	/* wake up the target thread */
318	mthd->threads[nt].needed = 1;
319	thread_lock(td);
320	if (TD_AWAITING_INTR(td)) {
321		msgring_wakeup_sleep[core*4+nt]++;
322		TD_CLR_IWAIT(td);
323		sched_add(td, SRQ_INTR);
324	} else
325		msgring_wakeup_nosleep[core*4+nt]++;
326	thread_unlock(td);
327	return (FILTER_HANDLED);
328}
329
330static void
331msgring_process(void *arg)
332{
333	struct msgring_thread *mthd;
334	struct thread	*td;
335	int		hwtid, tid, core;
336	int		nmsgs;
337
338	hwtid = (intptr_t)arg;
339	core = hwtid / 4;
340	tid = hwtid % 4;
341	mthd = &msgring_threads[core];
342	td = mthd->threads[tid].thread;
343	KASSERT(curthread == td,
344	    ("Incorrect thread core %d, thread %d", core, hwtid));
345
346	/* First bind this thread to the right CPU */
347	thread_lock(td);
348	sched_bind(td, xlr_hwtid_to_cpuid[hwtid]);
349	thread_unlock(td);
350
351	mtx_lock_spin(&mthd->lock);
352	++mthd->nthreads; 		/* Active thread count */
353	mtx_unlock_spin(&mthd->lock);
354
355	/* start processing messages */
356	for(;;) {
357		mtx_lock_spin(&mthd->lock);
358		++mthd->running;
359		msgrng_setconfig(mthd->running, mthd->nthreads);
360		mtx_unlock_spin(&mthd->lock);
361
362		atomic_store_rel_int(&mthd->threads[tid].needed, 0);
363		nmsgs = xlr_msgring_handler(0xff, 0);
364		msgring_nmsgs[hwtid] += nmsgs;
365
366		mtx_lock_spin(&mthd->lock);
367		--mthd->running;
368		msgrng_setconfig(mthd->running, mthd->nthreads);
369		mtx_unlock_spin(&mthd->lock);
370
371		/* sleep */
372		thread_lock(td);
373		if (mthd->threads[tid].needed) {
374			thread_unlock(td);
375			continue;
376		}
377		sched_class(td, PRI_ITHD);
378		TD_SET_IWAIT(td);
379		mi_switch(SW_VOL, NULL);
380		thread_unlock(td);
381	}
382}
383
384static void
385create_msgring_thread(int hwtid)
386{
387	struct msgring_thread *mthd;
388	struct thread *td;
389	int	tid, core;
390	int	error;
391
392	core = hwtid / 4;
393	tid = hwtid % 4;
394	mthd = &msgring_threads[core];
395	if (tid == 0) {
396		mtx_init(&mthd->lock, "msgrngcore", NULL, MTX_SPIN);
397		mthd->running = mthd->nthreads = 0;
398	}
399	error = kproc_kthread_add(msgring_process, (void *)(uintptr_t)hwtid,
400	    &msgring_proc, &td, RFSTOPPED, 2, "msgrngproc",
401	    "msgthr%d", hwtid);
402	if (error)
403		panic("kproc_kthread_add() failed with %d", error);
404	mthd->threads[tid].thread = td;
405
406	thread_lock(td);
407	sched_class(td, PRI_ITHD);
408	sched_add(td, SRQ_INTR);
409	thread_unlock(td);
410	CTR2(KTR_INTR, "%s: created %s", __func__, td->td_name);
411}
412
413int
414register_msgring_handler(int startb, int endb, msgring_handler action,
415    void *arg)
416{
417	void	*cookie;
418	int	i;
419	static int msgring_int_enabled = 0;
420
421	KASSERT(startb >= 0 && startb <= endb && endb < MSGRNG_NSTATIONS,
422	    ("Invalid value for for bucket range %d,%d", startb, endb));
423
424	mtx_lock_spin(&msgmap_lock);
425	for (i = startb; i <= endb; i++) {
426		KASSERT(msgmap[i].action == NULL,
427		   ("Bucket %d already used [action %p]", i, msgmap[i].action));
428		msgmap[i].action = action;
429		msgmap[i].arg = arg;
430	}
431	mtx_unlock_spin(&msgmap_lock);
432
433	if (xlr_test_and_set(&msgring_int_enabled)) {
434		create_msgring_thread(0);
435		if (msgring_maxthreads > xlr_threads_per_core)
436			msgring_maxthreads = xlr_threads_per_core;
437		cpu_establish_hardintr("msgring", msgring_process_fast_intr,
438			NULL, NULL, IRQ_MSGRING,
439			INTR_TYPE_NET, &cookie);
440	}
441	return (0);
442}
443
444/*
445 * Start message ring processing threads on other CPUs, after SMP start
446 */
447static void
448start_msgring_threads(void *arg)
449{
450	int	hwt, tid;
451
452	for (hwt = 1; hwt < XLR_MAX_CORES * XLR_NTHREADS; hwt++) {
453		if ((xlr_hw_thread_mask & (1 << hwt)) == 0)
454			continue;
455		tid = hwt % XLR_NTHREADS;
456		if (tid >= msgring_maxthreads)
457			continue;
458		create_msgring_thread(hwt);
459	}
460}
461
462SYSINIT(start_msgring_threads, SI_SUB_SMP, SI_ORDER_MIDDLE,
463    start_msgring_threads, NULL);
464
465/*
466 * DEBUG support, XXX: static buffer, not locked
467 */
468static int
469sys_print_debug(SYSCTL_HANDLER_ARGS)
470{
471	struct sbuf sb;
472	int error, i;
473
474	sbuf_new_for_sysctl(&sb, NULL, 64, req);
475	sbuf_printf(&sb,
476	    "\nID      INTR   ER   WU-SLP   WU-ERR     MSGS\n");
477	for (i = 0; i < 32; i++) {
478		if ((xlr_hw_thread_mask & (1 << i)) == 0)
479			continue;
480		sbuf_printf(&sb, "%2d: %8d %4d %8d %8d %8d\n", i,
481		    msgring_nintr[i/4], msgring_badintr[i/4],
482		    msgring_wakeup_sleep[i], msgring_wakeup_nosleep[i],
483		    msgring_nmsgs[i]);
484	}
485	error = sbuf_finish(&sb);
486	sbuf_delete(&sb);
487	return (error);
488}
489
490SYSCTL_PROC(_debug, OID_AUTO, msgring, CTLTYPE_STRING | CTLFLAG_RD, 0, 0,
491    sys_print_debug, "A", "msgring debug info");
492