1211809Sjchandra/*-
2198160Srrs * Copyright (c) 2003-2009 RMI Corporation
3198160Srrs * All rights reserved.
4198160Srrs *
5198160Srrs * Redistribution and use in source and binary forms, with or without
6198160Srrs * modification, are permitted provided that the following conditions
7198160Srrs * are met:
8198160Srrs * 1. Redistributions of source code must retain the above copyright
9198160Srrs *    notice, this list of conditions and the following disclaimer.
10198160Srrs * 2. Redistributions in binary form must reproduce the above copyright
11198160Srrs *    notice, this list of conditions and the following disclaimer in the
12198160Srrs *    documentation and/or other materials provided with the distribution.
13198160Srrs * 3. Neither the name of RMI Corporation, nor the names of its contributors,
14198160Srrs *    may be used to endorse or promote products derived from this software
15198160Srrs *    without specific prior written permission.
16198160Srrs *
17198160Srrs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18198160Srrs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19198160Srrs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20198160Srrs * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21198160Srrs * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22198160Srrs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23198160Srrs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24198160Srrs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25198160Srrs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26198160Srrs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27198160Srrs * SUCH DAMAGE.
28198160Srrs *
29198160Srrs * RMI_BSD */
30203112Srrs#include <sys/cdefs.h>
31203112Srrs__FBSDID("$FreeBSD$");
32198160Srrs#include <sys/types.h>
33198160Srrs#include <sys/systm.h>
34198160Srrs#include <sys/param.h>
35198160Srrs#include <sys/lock.h>
36198160Srrs#include <sys/mutex.h>
37198160Srrs#include <sys/proc.h>
38198160Srrs#include <sys/limits.h>
39198160Srrs#include <sys/bus.h>
40280013Sian#include <sys/sbuf.h>
41198160Srrs
42208165Srrs#include <sys/ktr.h>
43208165Srrs#include <sys/kernel.h>
44208165Srrs#include <sys/kthread.h>
45208165Srrs#include <sys/resourcevar.h>
46208165Srrs#include <sys/sched.h>
47208165Srrs#include <sys/unistd.h>
48208165Srrs#include <sys/sysctl.h>
49208165Srrs#include <sys/malloc.h>
50208165Srrs
51198160Srrs#include <machine/reg.h>
52198160Srrs#include <machine/cpu.h>
53208165Srrs#include <machine/hwfunc.h>
54198160Srrs#include <machine/mips_opcode.h>
55198160Srrs
56198160Srrs#include <machine/intr_machdep.h>
57198607Srrs#include <mips/rmi/interrupt.h>
58198607Srrs#include <mips/rmi/msgring.h>
59198607Srrs#include <mips/rmi/pic.h>
60198607Srrs#include <mips/rmi/board.h>
61198160Srrs
62198160Srrs#define MSGRNG_CC_INIT_CPU_DEST(dest, counter) \
63198160Srrsdo { \
64198160Srrs     msgrng_write_cc(MSGRNG_CC_##dest##_REG, counter[dest][0], 0 ); \
65198160Srrs     msgrng_write_cc(MSGRNG_CC_##dest##_REG, counter[dest][1], 1 ); \
66198160Srrs     msgrng_write_cc(MSGRNG_CC_##dest##_REG, counter[dest][2], 2 ); \
67198160Srrs     msgrng_write_cc(MSGRNG_CC_##dest##_REG, counter[dest][3], 3 ); \
68198160Srrs     msgrng_write_cc(MSGRNG_CC_##dest##_REG, counter[dest][4], 4 ); \
69198160Srrs     msgrng_write_cc(MSGRNG_CC_##dest##_REG, counter[dest][5], 5 ); \
70198160Srrs     msgrng_write_cc(MSGRNG_CC_##dest##_REG, counter[dest][6], 6 ); \
71198160Srrs     msgrng_write_cc(MSGRNG_CC_##dest##_REG, counter[dest][7], 7 ); \
72198160Srrs} while(0)
73198160Srrs
74198160Srrs
75213377Sjchandra/*
76213377Sjchandra * Keep track of our message ring handler threads, each core has a
77213377Sjchandra * different message station. Ideally we will need to start a few
78213377Sjchandra * message handling threads every core, and wake them up depending on
79213377Sjchandra * load
80213377Sjchandra */
81213377Sjchandrastruct msgring_thread {
82213377Sjchandra	struct {
83213377Sjchandra		struct thread	*thread; /* msgring handler threads */
84213377Sjchandra		int	needed;		/* thread needs to wake up */
85213377Sjchandra	} threads[XLR_NTHREADS];
86213377Sjchandra	int	running;		/* number of threads running */
87213377Sjchandra	int	nthreads;		/* number of threads started */
88213377Sjchandra	struct mtx lock;		/* for changing running/active */
89213377Sjchandra};
90213377Sjchandrastatic struct msgring_thread msgring_threads[XLR_MAX_CORES];
91213377Sjchandrastatic struct proc *msgring_proc;	/* all threads are under a proc */
92198160Srrs
93213377Sjchandra/*
94213377Sjchandra * The maximum number of software message handler threads to be started
95213443Sjchandra * per core. Default is 3 per core
96213377Sjchandra */
97213443Sjchandrastatic int	msgring_maxthreads = 3;
98213377SjchandraTUNABLE_INT("hw.fmn.maxthreads", &msgring_maxthreads);
99213377Sjchandra
100213377Sjchandra/*
101218909Sbrucec * The device drivers can register a handler for the messages sent
102213377Sjchandra * from a station (corresponding to the device).
103213377Sjchandra */
104213377Sjchandrastruct tx_stn_handler {
105213377Sjchandra	msgring_handler action;
106213377Sjchandra	void *arg;
107213377Sjchandra};
108213377Sjchandrastatic struct tx_stn_handler msgmap[MSGRNG_NSTATIONS];
109213377Sjchandrastatic struct mtx	msgmap_lock;
110213377Sjchandra
111213377Sjchandra/*
112213377Sjchandra * Initialize the messaging subsystem.
113213377Sjchandra *
114213377Sjchandra * Message Stations are shared among all threads in a cpu core, this
115213377Sjchandra * has to be called once from every core which is online.
116213377Sjchandra */
117198625Srrsvoid
118198625Srrsxlr_msgring_cpu_init(void)
119198160Srrs{
120198160Srrs	struct stn_cc *cc_config;
121198160Srrs	struct bucket_size *bucket_sizes;
122213377Sjchandra	uint32_t flags;
123198160Srrs	int id;
124198160Srrs
125208165Srrs	KASSERT(xlr_thr_id() == 0,
126213377Sjchandra		("xlr_msgring_cpu_init from non-zero thread"));
127208165Srrs	id = xlr_core_id();
128198160Srrs	bucket_sizes = xlr_board_info.bucket_sizes;
129198160Srrs	cc_config = xlr_board_info.credit_configs[id];
130198160Srrs
131213377Sjchandra	flags = msgrng_access_enable();
132198625Srrs
133198625Srrs	/*
134213377Sjchandra	 * FMN messages are received in 8 buckets per core, set up
135213377Sjchandra	 * the bucket sizes for each bucket
136198160Srrs	 */
137198625Srrs	msgrng_write_bucksize(0, bucket_sizes->bucket[id * 8 + 0]);
138198625Srrs	msgrng_write_bucksize(1, bucket_sizes->bucket[id * 8 + 1]);
139198625Srrs	msgrng_write_bucksize(2, bucket_sizes->bucket[id * 8 + 2]);
140198625Srrs	msgrng_write_bucksize(3, bucket_sizes->bucket[id * 8 + 3]);
141198625Srrs	msgrng_write_bucksize(4, bucket_sizes->bucket[id * 8 + 4]);
142198625Srrs	msgrng_write_bucksize(5, bucket_sizes->bucket[id * 8 + 5]);
143198625Srrs	msgrng_write_bucksize(6, bucket_sizes->bucket[id * 8 + 6]);
144198625Srrs	msgrng_write_bucksize(7, bucket_sizes->bucket[id * 8 + 7]);
145198160Srrs
146213377Sjchandra	/*
147213377Sjchandra	 * For sending FMN messages, we need credits on the destination
148213377Sjchandra	 * bucket.  Program the credits this core has on the 128 possible
149213377Sjchandra	 * destination buckets.
150218909Sbrucec	 * We cannot use a loop here, because the first argument has
151213443Sjchandra	 * to be a constant integer value.
152213377Sjchandra	 */
153213377Sjchandra	MSGRNG_CC_INIT_CPU_DEST(0,  cc_config->counters);
154213377Sjchandra	MSGRNG_CC_INIT_CPU_DEST(1,  cc_config->counters);
155213377Sjchandra	MSGRNG_CC_INIT_CPU_DEST(2,  cc_config->counters);
156213377Sjchandra	MSGRNG_CC_INIT_CPU_DEST(3,  cc_config->counters);
157213377Sjchandra	MSGRNG_CC_INIT_CPU_DEST(4,  cc_config->counters);
158213377Sjchandra	MSGRNG_CC_INIT_CPU_DEST(5,  cc_config->counters);
159213377Sjchandra	MSGRNG_CC_INIT_CPU_DEST(6,  cc_config->counters);
160213377Sjchandra	MSGRNG_CC_INIT_CPU_DEST(7,  cc_config->counters);
161213377Sjchandra	MSGRNG_CC_INIT_CPU_DEST(8,  cc_config->counters);
162213377Sjchandra	MSGRNG_CC_INIT_CPU_DEST(9,  cc_config->counters);
163198160Srrs	MSGRNG_CC_INIT_CPU_DEST(10, cc_config->counters);
164198160Srrs	MSGRNG_CC_INIT_CPU_DEST(11, cc_config->counters);
165198160Srrs	MSGRNG_CC_INIT_CPU_DEST(12, cc_config->counters);
166198160Srrs	MSGRNG_CC_INIT_CPU_DEST(13, cc_config->counters);
167198160Srrs	MSGRNG_CC_INIT_CPU_DEST(14, cc_config->counters);
168198160Srrs	MSGRNG_CC_INIT_CPU_DEST(15, cc_config->counters);
169212321Sjchandra	msgrng_restore(flags);
170198160Srrs}
171198160Srrs
172213377Sjchandra/*
173213377Sjchandra * Boot time init, called only once
174213377Sjchandra */
175198625Srrsvoid
176198625Srrsxlr_msgring_config(void)
177198160Srrs{
178213377Sjchandra	mtx_init(&msgmap_lock, "msgring", NULL, MTX_SPIN);
179213377Sjchandra
180213377Sjchandra	/* check value */
181213377Sjchandra	if (msgring_maxthreads < 0 || msgring_maxthreads > XLR_NTHREADS)
182213377Sjchandra		msgring_maxthreads = XLR_NTHREADS;
183198160Srrs}
184198160Srrs
185212790Sjchandra/*
186212790Sjchandra * Drain out max_messages for the buckets set in the bucket mask.
187212790Sjchandra * Use max_messages = 0 to drain out all messages.
188212790Sjchandra */
189212790Sjchandrauint32_t
190212790Sjchandraxlr_msgring_handler(uint8_t bucket_mask, uint32_t max_messages)
191198160Srrs{
192198625Srrs	int bucket = 0;
193213377Sjchandra	int size = 0, code = 0, rx_stid = 0;
194198160Srrs	struct msgrng_msg msg;
195213377Sjchandra	struct tx_stn_handler *he;
196198625Srrs	unsigned int status = 0;
197212790Sjchandra	unsigned long mflags;
198213377Sjchandra	uint32_t n_msgs;
199213377Sjchandra	uint32_t msgbuckets;
200198160Srrs
201212790Sjchandra	n_msgs = 0;
202212321Sjchandra	mflags = msgrng_access_enable();
203198625Srrs	for (;;) {
204213377Sjchandra		msgbuckets = (~msgrng_read_status() >> 24) & bucket_mask;
205198160Srrs
206198625Srrs		/* all buckets empty, break */
207213377Sjchandra		if (msgbuckets == 0)
208198625Srrs			break;
209198160Srrs
210213377Sjchandra		for (bucket = 0; bucket < 8; bucket++) {
211213377Sjchandra			if ((msgbuckets & (1 << bucket)) == 0) /* empty */
212198625Srrs				continue;
213198625Srrs
214213377Sjchandra			status = message_receive(bucket, &size, &code,
215213377Sjchandra			    &rx_stid, &msg);
216213377Sjchandra			if (status != 0)
217198625Srrs				continue;
218212790Sjchandra			n_msgs++;
219213377Sjchandra			he = &msgmap[rx_stid];
220213377Sjchandra			if (he->action == NULL) {
221213377Sjchandra				printf("[%s]: No Handler for message from "
222213377Sjchandra				    "stn_id=%d, bucket=%d, size=%d, msg0=%jx\n",
223213377Sjchandra				    __func__, rx_stid, bucket, size,
224213377Sjchandra				    (uintmax_t)msg.msg0);
225198625Srrs			} else {
226212321Sjchandra				msgrng_restore(mflags);
227213377Sjchandra				(*he->action)(bucket, size, code, rx_stid,
228213377Sjchandra				    &msg, he->arg);
229212321Sjchandra				mflags = msgrng_access_enable();
230198625Srrs			}
231212790Sjchandra			if (max_messages > 0 && n_msgs >= max_messages)
232212790Sjchandra				goto done;
233198160Srrs		}
234198160Srrs	}
235212790Sjchandra
236212790Sjchandradone:
237212321Sjchandra	msgrng_restore(mflags);
238212790Sjchandra	return (n_msgs);
239198160Srrs}
240198160Srrs
241213377Sjchandra/*
242213377Sjchandra * XLR COP2 supports watermark interrupts based on the number of
243213377Sjchandra * messages pending in all the buckets in the core.  We increase
244213377Sjchandra * the watermark until all the possible handler threads in the core
245213377Sjchandra * are woken up.
246213377Sjchandra */
247213377Sjchandrastatic void
248213377Sjchandramsgrng_setconfig(int running, int nthr)
249198160Srrs{
250212321Sjchandra	uint32_t config, mflags;
251213377Sjchandra	int watermark = 1;	/* non zero needed */
252213377Sjchandra	int wm_intr_value;
253198160Srrs
254213377Sjchandra	KASSERT(nthr >= 0 && nthr <= msgring_maxthreads,
255213377Sjchandra	    ("Bad value of nthr %d", nthr));
256213377Sjchandra	KASSERT(running <= nthr, ("Bad value of running %d", running));
257198160Srrs
258213377Sjchandra	if (running == nthr) {
259213377Sjchandra		wm_intr_value = 0;
260213377Sjchandra	} else {
261213377Sjchandra		switch (running) {
262213377Sjchandra		case 0: break;		/* keep default */
263213377Sjchandra		case 1:
264213443Sjchandra			watermark = 32; break;
265213377Sjchandra		case 2:
266213443Sjchandra			watermark = 48; break;
267213377Sjchandra		case 3:
268213443Sjchandra			watermark = 56; break;
269213377Sjchandra		}
270213377Sjchandra		wm_intr_value = 0x2;	/* set watermark enable interrupt */
271213377Sjchandra	}
272212321Sjchandra	mflags = msgrng_access_enable();
273213377Sjchandra	config = (watermark << 24) | (IRQ_MSGRING << 16) | (1 << 8) |
274213377Sjchandra		wm_intr_value;
275213443Sjchandra	/* clear pending interrupts, they will get re-raised if still valid */
276213377Sjchandra	write_c0_eirr64(1ULL << IRQ_MSGRING);
277198160Srrs	msgrng_write_config(config);
278212321Sjchandra	msgrng_restore(mflags);
279198160Srrs}
280198160Srrs
281213443Sjchandra/* Debug counters */
282213443Sjchandrastatic int msgring_nintr[XLR_MAX_CORES];
283213443Sjchandrastatic int msgring_badintr[XLR_MAX_CORES];
284213443Sjchandrastatic int msgring_wakeup_sleep[XLR_MAX_CORES * XLR_NTHREADS];
285213443Sjchandrastatic int msgring_wakeup_nosleep[XLR_MAX_CORES * XLR_NTHREADS];
286213443Sjchandrastatic int msgring_nmsgs[XLR_MAX_CORES * XLR_NTHREADS];
287213443Sjchandra
288208165Srrsstatic int
289208165Srrsmsgring_process_fast_intr(void *arg)
290208165Srrs{
291213377Sjchandra	struct msgring_thread *mthd;
292213377Sjchandra	struct thread	*td;
293213377Sjchandra	uint32_t	mflags;
294213377Sjchandra	int		core, nt;
295198160Srrs
296213377Sjchandra	core = xlr_core_id();
297213377Sjchandra	mthd = &msgring_threads[core];
298213443Sjchandra	msgring_nintr[core]++;
299213377Sjchandra	mtx_lock_spin(&mthd->lock);
300213377Sjchandra	nt = mthd->running;
301213377Sjchandra	if(nt >= mthd->nthreads) {
302213443Sjchandra		msgring_badintr[core]++;
303213377Sjchandra		mtx_unlock_spin(&mthd->lock);
304213377Sjchandra		return (FILTER_HANDLED);
305213377Sjchandra	}
306213377Sjchandra
307213377Sjchandra	td = mthd->threads[nt].thread;
308213377Sjchandra	mflags = msgrng_access_enable();
309213377Sjchandra
310213377Sjchandra	/* default value with interrupts disabled */
311213377Sjchandra	msgrng_write_config((1 << 24) | (IRQ_MSGRING << 16) | (1 << 8));
312213443Sjchandra	/* clear pending interrupts */
313213443Sjchandra	write_c0_eirr64(1ULL << IRQ_MSGRING);
314213377Sjchandra	msgrng_restore(mflags);
315213377Sjchandra	mtx_unlock_spin(&mthd->lock);
316213377Sjchandra
317213377Sjchandra	/* wake up the target thread */
318213377Sjchandra	mthd->threads[nt].needed = 1;
319208165Srrs	thread_lock(td);
320208165Srrs	if (TD_AWAITING_INTR(td)) {
321213443Sjchandra		msgring_wakeup_sleep[core*4+nt]++;
322208165Srrs		TD_CLR_IWAIT(td);
323208165Srrs		sched_add(td, SRQ_INTR);
324213443Sjchandra	} else
325213443Sjchandra		msgring_wakeup_nosleep[core*4+nt]++;
326208165Srrs	thread_unlock(td);
327213377Sjchandra	return (FILTER_HANDLED);
328208165Srrs}
329208165Srrs
330208165Srrsstatic void
331208165Srrsmsgring_process(void *arg)
332208165Srrs{
333213377Sjchandra	struct msgring_thread *mthd;
334213377Sjchandra	struct thread	*td;
335213377Sjchandra	int		hwtid, tid, core;
336213377Sjchandra	int		nmsgs;
337208165Srrs
338213377Sjchandra	hwtid = (intptr_t)arg;
339213377Sjchandra	core = hwtid / 4;
340213377Sjchandra	tid = hwtid % 4;
341213377Sjchandra	mthd = &msgring_threads[core];
342213377Sjchandra	td = mthd->threads[tid].thread;
343213377Sjchandra	KASSERT(curthread == td,
344213377Sjchandra	    ("Incorrect thread core %d, thread %d", core, hwtid));
345208165Srrs
346208165Srrs	/* First bind this thread to the right CPU */
347208165Srrs	thread_lock(td);
348213377Sjchandra	sched_bind(td, xlr_hwtid_to_cpuid[hwtid]);
349208165Srrs	thread_unlock(td);
350208165Srrs
351213377Sjchandra	mtx_lock_spin(&mthd->lock);
352213443Sjchandra	++mthd->nthreads; 		/* Active thread count */
353213377Sjchandra	mtx_unlock_spin(&mthd->lock);
354213377Sjchandra
355213377Sjchandra	/* start processing messages */
356213377Sjchandra	for(;;) {
357213377Sjchandra		mtx_lock_spin(&mthd->lock);
358213377Sjchandra		++mthd->running;
359213377Sjchandra		msgrng_setconfig(mthd->running, mthd->nthreads);
360213377Sjchandra		mtx_unlock_spin(&mthd->lock);
361213377Sjchandra
362213377Sjchandra		atomic_store_rel_int(&mthd->threads[tid].needed, 0);
363213377Sjchandra		nmsgs = xlr_msgring_handler(0xff, 0);
364213443Sjchandra		msgring_nmsgs[hwtid] += nmsgs;
365213377Sjchandra
366213377Sjchandra		mtx_lock_spin(&mthd->lock);
367213377Sjchandra		--mthd->running;
368213377Sjchandra		msgrng_setconfig(mthd->running, mthd->nthreads);
369213377Sjchandra		mtx_unlock_spin(&mthd->lock);
370213377Sjchandra
371213377Sjchandra		/* sleep */
372213377Sjchandra		thread_lock(td);
373213377Sjchandra		if (mthd->threads[tid].needed) {
374208165Srrs			thread_unlock(td);
375213377Sjchandra			continue;
376208165Srrs		}
377213377Sjchandra		sched_class(td, PRI_ITHD);
378213377Sjchandra		TD_SET_IWAIT(td);
379213377Sjchandra		mi_switch(SW_VOL, NULL);
380213377Sjchandra		thread_unlock(td);
381208165Srrs	}
382208165Srrs}
383208165Srrs
384208165Srrsstatic void
385213377Sjchandracreate_msgring_thread(int hwtid)
386208165Srrs{
387213377Sjchandra	struct msgring_thread *mthd;
388208165Srrs	struct thread *td;
389213377Sjchandra	int	tid, core;
390213377Sjchandra	int	error;
391208165Srrs
392213377Sjchandra	core = hwtid / 4;
393213377Sjchandra	tid = hwtid % 4;
394213377Sjchandra	mthd = &msgring_threads[core];
395213377Sjchandra	if (tid == 0) {
396213377Sjchandra		mtx_init(&mthd->lock, "msgrngcore", NULL, MTX_SPIN);
397213377Sjchandra		mthd->running = mthd->nthreads = 0;
398213377Sjchandra	}
399213474Sjchandra	error = kproc_kthread_add(msgring_process, (void *)(uintptr_t)hwtid,
400213377Sjchandra	    &msgring_proc, &td, RFSTOPPED, 2, "msgrngproc",
401213377Sjchandra	    "msgthr%d", hwtid);
402208165Srrs	if (error)
403213377Sjchandra		panic("kproc_kthread_add() failed with %d", error);
404213377Sjchandra	mthd->threads[tid].thread = td;
405208165Srrs
406208165Srrs	thread_lock(td);
407208165Srrs	sched_class(td, PRI_ITHD);
408208165Srrs	sched_add(td, SRQ_INTR);
409208165Srrs	thread_unlock(td);
410210845Sjchandra	CTR2(KTR_INTR, "%s: created %s", __func__, td->td_name);
411208165Srrs}
412208165Srrs
413198625Srrsint
414213377Sjchandraregister_msgring_handler(int startb, int endb, msgring_handler action,
415213377Sjchandra    void *arg)
416198160Srrs{
417213377Sjchandra	void	*cookie;
418213377Sjchandra	int	i;
419213377Sjchandra	static int msgring_int_enabled = 0;
420198160Srrs
421213377Sjchandra	KASSERT(startb >= 0 && startb <= endb && endb < MSGRNG_NSTATIONS,
422213377Sjchandra	    ("Invalid value for for bucket range %d,%d", startb, endb));
423198160Srrs
424213377Sjchandra	mtx_lock_spin(&msgmap_lock);
425213377Sjchandra	for (i = startb; i <= endb; i++) {
426213377Sjchandra		KASSERT(msgmap[i].action == NULL,
427213377Sjchandra		   ("Bucket %d already used [action %p]", i, msgmap[i].action));
428213377Sjchandra		msgmap[i].action = action;
429213377Sjchandra		msgmap[i].arg = arg;
430213377Sjchandra	}
431213377Sjchandra	mtx_unlock_spin(&msgmap_lock);
432198625Srrs
433198160Srrs	if (xlr_test_and_set(&msgring_int_enabled)) {
434213377Sjchandra		create_msgring_thread(0);
435213377Sjchandra		if (msgring_maxthreads > xlr_threads_per_core)
436213377Sjchandra			msgring_maxthreads = xlr_threads_per_core;
437213377Sjchandra		cpu_establish_hardintr("msgring", msgring_process_fast_intr,
438203112Srrs			NULL, NULL, IRQ_MSGRING,
439217072Sjhb			INTR_TYPE_NET, &cookie);
440198160Srrs	}
441213377Sjchandra	return (0);
442198160Srrs}
443198160Srrs
444213443Sjchandra/*
445213443Sjchandra * Start message ring processing threads on other CPUs, after SMP start
446213443Sjchandra */
447208165Srrsstatic void
448208165Srrsstart_msgring_threads(void *arg)
449208165Srrs{
450213377Sjchandra	int	hwt, tid;
451208165Srrs
452213377Sjchandra	for (hwt = 1; hwt < XLR_MAX_CORES * XLR_NTHREADS; hwt++) {
453213377Sjchandra		if ((xlr_hw_thread_mask & (1 << hwt)) == 0)
454213377Sjchandra			continue;
455213377Sjchandra		tid = hwt % XLR_NTHREADS;
456213377Sjchandra		if (tid >= msgring_maxthreads)
457213377Sjchandra			continue;
458213377Sjchandra		create_msgring_thread(hwt);
459208369Sjchandra	}
460198160Srrs}
461208165Srrs
462213443SjchandraSYSINIT(start_msgring_threads, SI_SUB_SMP, SI_ORDER_MIDDLE,
463213443Sjchandra    start_msgring_threads, NULL);
464213443Sjchandra
465213443Sjchandra/*
466213443Sjchandra * DEBUG support, XXX: static buffer, not locked
467213443Sjchandra */
468213443Sjchandrastatic int
469213443Sjchandrasys_print_debug(SYSCTL_HANDLER_ARGS)
470213443Sjchandra{
471280013Sian	struct sbuf sb;
472280013Sian	int error, i;
473213443Sjchandra
474280013Sian	sbuf_new_for_sysctl(&sb, NULL, 64, req);
475280013Sian	sbuf_printf(&sb,
476213443Sjchandra	    "\nID      INTR   ER   WU-SLP   WU-ERR     MSGS\n");
477213443Sjchandra	for (i = 0; i < 32; i++) {
478213443Sjchandra		if ((xlr_hw_thread_mask & (1 << i)) == 0)
479213443Sjchandra			continue;
480280013Sian		sbuf_printf(&sb, "%2d: %8d %4d %8d %8d %8d\n", i,
481213443Sjchandra		    msgring_nintr[i/4], msgring_badintr[i/4],
482213443Sjchandra		    msgring_wakeup_sleep[i], msgring_wakeup_nosleep[i],
483213443Sjchandra		    msgring_nmsgs[i]);
484213443Sjchandra	}
485280013Sian	error = sbuf_finish(&sb);
486280013Sian	sbuf_delete(&sb);
487213443Sjchandra	return (error);
488213443Sjchandra}
489213443Sjchandra
490213443SjchandraSYSCTL_PROC(_debug, OID_AUTO, msgring, CTLTYPE_STRING | CTLFLAG_RD, 0, 0,
491213443Sjchandra    sys_print_debug, "A", "msgring debug info");
492