fmn.c revision 212321
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: head/sys/mips/rmi/fmn.c 212321 2010-09-08 16:34:08Z jchandra $");
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>
40198160Srrs
41208165Srrs#include <sys/ktr.h>
42208165Srrs#include <sys/kernel.h>
43208165Srrs#include <sys/kthread.h>
44208165Srrs#include <sys/proc.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/param.h>
57198160Srrs#include <machine/intr_machdep.h>
58198607Srrs#include <mips/rmi/interrupt.h>
59198607Srrs#include <mips/rmi/msgring.h>
60198607Srrs#include <mips/rmi/pic.h>
61198607Srrs#include <mips/rmi/board.h>
62198160Srrs
63198625Srrsvoid
64198625Srrsdisable_msgring_int(void *arg);
65198625Srrsvoid
66198625Srrsenable_msgring_int(void *arg);
67198625Srrs
68198160Srrs/* definitions */
69198160Srrsstruct tx_stn_handler {
70198625Srrs	void (*action) (int, int, int, int, struct msgrng_msg *, void *);
71198160Srrs	void *dev_id;
72198160Srrs};
73198160Srrs
74208165Srrsstruct msgring_ithread {
75208165Srrs	struct thread *i_thread;
76208165Srrs	u_int i_pending;
77208165Srrs	u_int i_flags;
78208165Srrs	int i_cpu;
79208369Sjchandra	int i_core;
80208165Srrs};
81208165Srrs
82208165Srrsstruct msgring_ithread *msgring_ithreads[MAXCPU];
83208165Srrs
84198160Srrs/* globals */
85198160Srrsstatic struct tx_stn_handler tx_stn_handlers[MAX_TX_STNS];
86198160Srrs
87198160Srrs#define MSGRNG_CC_INIT_CPU_DEST(dest, counter) \
88198160Srrsdo { \
89198160Srrs     msgrng_write_cc(MSGRNG_CC_##dest##_REG, counter[dest][0], 0 ); \
90198160Srrs     msgrng_write_cc(MSGRNG_CC_##dest##_REG, counter[dest][1], 1 ); \
91198160Srrs     msgrng_write_cc(MSGRNG_CC_##dest##_REG, counter[dest][2], 2 ); \
92198160Srrs     msgrng_write_cc(MSGRNG_CC_##dest##_REG, counter[dest][3], 3 ); \
93198160Srrs     msgrng_write_cc(MSGRNG_CC_##dest##_REG, counter[dest][4], 4 ); \
94198160Srrs     msgrng_write_cc(MSGRNG_CC_##dest##_REG, counter[dest][5], 5 ); \
95198160Srrs     msgrng_write_cc(MSGRNG_CC_##dest##_REG, counter[dest][6], 6 ); \
96198160Srrs     msgrng_write_cc(MSGRNG_CC_##dest##_REG, counter[dest][7], 7 ); \
97198160Srrs} while(0)
98198160Srrs
99198160Srrs
100198160Srrs/* make this a read/write spinlock */
101198160Srrsstatic struct mtx msgrng_lock;
102198160Srrsstatic int msgring_int_enabled;
103198625Srrsstatic int msgring_pop_num_buckets;
104198625Srrsstatic uint32_t msgring_pop_bucket_mask;
105198625Srrsstatic int msgring_int_type;
106198625Srrsstatic int msgring_watermark_count;
107198625Srrsstatic uint32_t msgring_thread_mask;
108198160Srrsuint32_t msgrng_msg_cycles = 0;
109198160Srrs
110198160Srrsvoid xlr_msgring_handler(struct trapframe *);
111198160Srrs
112198625Srrsvoid
113198625Srrsxlr_msgring_cpu_init(void)
114198160Srrs{
115198160Srrs	struct stn_cc *cc_config;
116198160Srrs	struct bucket_size *bucket_sizes;
117198160Srrs	int id;
118212321Sjchandra	uint32_t flags;
119198160Srrs
120208165Srrs	KASSERT(xlr_thr_id() == 0,
121208165Srrs		("xlr_msgring_cpu_init from non-zero thread\n"));
122198160Srrs
123208165Srrs	id = xlr_core_id();
124208165Srrs
125198160Srrs	bucket_sizes = xlr_board_info.bucket_sizes;
126198160Srrs	cc_config = xlr_board_info.credit_configs[id];
127198160Srrs
128198625Srrs
129198625Srrs	/*
130198625Srrs	 * Message Stations are shared among all threads in a cpu core
131198625Srrs	 * Assume, thread 0 on all cores are always active when more than 1
132198625Srrs	 * thread is active in a core
133198160Srrs	 */
134212321Sjchandra	flags = msgrng_access_enable();
135212321Sjchandra
136198625Srrs	msgrng_write_bucksize(0, bucket_sizes->bucket[id * 8 + 0]);
137198625Srrs	msgrng_write_bucksize(1, bucket_sizes->bucket[id * 8 + 1]);
138198625Srrs	msgrng_write_bucksize(2, bucket_sizes->bucket[id * 8 + 2]);
139198625Srrs	msgrng_write_bucksize(3, bucket_sizes->bucket[id * 8 + 3]);
140198625Srrs	msgrng_write_bucksize(4, bucket_sizes->bucket[id * 8 + 4]);
141198625Srrs	msgrng_write_bucksize(5, bucket_sizes->bucket[id * 8 + 5]);
142198625Srrs	msgrng_write_bucksize(6, bucket_sizes->bucket[id * 8 + 6]);
143198625Srrs	msgrng_write_bucksize(7, bucket_sizes->bucket[id * 8 + 7]);
144198160Srrs
145198160Srrs	MSGRNG_CC_INIT_CPU_DEST(0, cc_config->counters);
146198160Srrs	MSGRNG_CC_INIT_CPU_DEST(1, cc_config->counters);
147198160Srrs	MSGRNG_CC_INIT_CPU_DEST(2, cc_config->counters);
148198160Srrs	MSGRNG_CC_INIT_CPU_DEST(3, cc_config->counters);
149198160Srrs	MSGRNG_CC_INIT_CPU_DEST(4, cc_config->counters);
150198160Srrs	MSGRNG_CC_INIT_CPU_DEST(5, cc_config->counters);
151198160Srrs	MSGRNG_CC_INIT_CPU_DEST(6, cc_config->counters);
152198160Srrs	MSGRNG_CC_INIT_CPU_DEST(7, cc_config->counters);
153198160Srrs	MSGRNG_CC_INIT_CPU_DEST(8, cc_config->counters);
154198160Srrs	MSGRNG_CC_INIT_CPU_DEST(9, cc_config->counters);
155198160Srrs	MSGRNG_CC_INIT_CPU_DEST(10, cc_config->counters);
156198160Srrs	MSGRNG_CC_INIT_CPU_DEST(11, cc_config->counters);
157198160Srrs	MSGRNG_CC_INIT_CPU_DEST(12, cc_config->counters);
158198160Srrs	MSGRNG_CC_INIT_CPU_DEST(13, cc_config->counters);
159198160Srrs	MSGRNG_CC_INIT_CPU_DEST(14, cc_config->counters);
160198160Srrs	MSGRNG_CC_INIT_CPU_DEST(15, cc_config->counters);
161198160Srrs
162212321Sjchandra	msgrng_restore(flags);
163198160Srrs}
164198160Srrs
165198625Srrsvoid
166198625Srrsxlr_msgring_config(void)
167198160Srrs{
168211802Sjchandra	mtx_init(&msgrng_lock, "msgring", NULL, MTX_SPIN | MTX_RECURSE);
169198160Srrs	msgring_int_type = 0x02;
170198160Srrs	msgring_pop_num_buckets = 8;
171198160Srrs	msgring_pop_bucket_mask = 0xff;
172211802Sjchandra	msgring_int_enabled = 0;
173198160Srrs	msgring_watermark_count = 1;
174198160Srrs	msgring_thread_mask = 0x01;
175198160Srrs}
176198160Srrs
177198625Srrsvoid
178198625Srrsxlr_msgring_handler(struct trapframe *tf)
179198160Srrs{
180198160Srrs	unsigned long mflags;
181198625Srrs	int bucket = 0;
182198625Srrs	int size = 0, code = 0, rx_stid = 0, tx_stid = 0;
183198160Srrs	struct msgrng_msg msg;
184198160Srrs	unsigned int bucket_empty_bm = 0;
185198625Srrs	unsigned int status = 0;
186198160Srrs
187212321Sjchandra	mflags = msgrng_access_enable();
188198160Srrs
189198160Srrs	/* First Drain all the high priority messages */
190198625Srrs	for (;;) {
191198160Srrs		bucket_empty_bm = (msgrng_read_status() >> 24) & msgring_pop_bucket_mask;
192198160Srrs
193198625Srrs		/* all buckets empty, break */
194198625Srrs		if (bucket_empty_bm == msgring_pop_bucket_mask)
195198625Srrs			break;
196198160Srrs
197198625Srrs		for (bucket = 0; bucket < msgring_pop_num_buckets; bucket++) {
198198625Srrs			if ((bucket_empty_bm & (1 << bucket)) /* empty */ )
199198625Srrs				continue;
200198625Srrs
201198160Srrs			status = message_receive(bucket, &size, &code, &rx_stid, &msg);
202198625Srrs			if (status)
203198625Srrs				continue;
204198625Srrs
205198160Srrs			tx_stid = xlr_board_info.msgmap[rx_stid];
206198160Srrs
207198160Srrs			if (!tx_stn_handlers[tx_stid].action) {
208198160Srrs				printf("[%s]: No Handler for message from stn_id=%d, bucket=%d, "
209209808Sjchandra				    "size=%d, msg0=%jx, dropping message\n",
210209808Sjchandra				    __FUNCTION__, tx_stid, bucket, size, (uintmax_t)msg.msg0);
211198625Srrs			} else {
212198160Srrs				//printf("[%s]: rx_stid = %d\n", __FUNCTION__, rx_stid);
213212321Sjchandra				msgrng_restore(mflags);
214198625Srrs				(*tx_stn_handlers[tx_stid].action) (bucket, size, code, rx_stid,
215198625Srrs				    &msg, tx_stn_handlers[tx_stid].dev_id);
216212321Sjchandra				mflags = msgrng_access_enable();
217198625Srrs			}
218198160Srrs		}
219198160Srrs	}
220212321Sjchandra	msgrng_restore(mflags);
221198160Srrs}
222198160Srrs
223198625Srrsvoid
224198625Srrsenable_msgring_int(void *arg)
225198160Srrs{
226212321Sjchandra	uint32_t config, mflags;
227198160Srrs
228212321Sjchandra	config = (msgring_watermark_count << 24) | (IRQ_MSGRING << 16) |
229212321Sjchandra	    (msgring_thread_mask << 8) | msgring_int_type;
230212321Sjchandra	mflags = msgrng_access_enable();
231212321Sjchandra	msgrng_write_config(config);
232212321Sjchandra	msgrng_restore(mflags);
233198160Srrs}
234198160Srrs
235198625Srrsvoid
236198625Srrsdisable_msgring_int(void *arg)
237198160Srrs{
238212321Sjchandra	uint32_t config, mflags;
239198160Srrs
240212321Sjchandra	mflags = msgrng_access_enable();
241212321Sjchandra	config = msgrng_read_config() & ~0x3;
242198160Srrs	msgrng_write_config(config);
243212321Sjchandra	msgrng_restore(mflags);
244198160Srrs}
245198160Srrs
246208165Srrsstatic int
247208165Srrsmsgring_process_fast_intr(void *arg)
248208165Srrs{
249208369Sjchandra	int core = xlr_core_id();
250208165Srrs	volatile struct msgring_ithread *it;
251208165Srrs	struct thread *td;
252198160Srrs
253208165Srrs	/* wakeup an appropriate intr_thread for processing this interrupt */
254208369Sjchandra	it = (volatile struct msgring_ithread *)msgring_ithreads[core];
255208369Sjchandra	KASSERT(it != NULL, ("No interrupt thread on cpu %d", core));
256208165Srrs	td = it->i_thread;
257208165Srrs
258208165Srrs	/*
259208165Srrs	 * Interrupt thread will enable the interrupts after processing all
260208165Srrs	 * messages
261208165Srrs	 */
262208165Srrs	disable_msgring_int(NULL);
263208165Srrs	atomic_store_rel_int(&it->i_pending, 1);
264208165Srrs	thread_lock(td);
265208165Srrs	if (TD_AWAITING_INTR(td)) {
266208165Srrs		TD_CLR_IWAIT(td);
267208165Srrs		sched_add(td, SRQ_INTR);
268208165Srrs	}
269208165Srrs	thread_unlock(td);
270208165Srrs	return FILTER_HANDLED;
271208165Srrs}
272208165Srrs
273208165Srrsstatic void
274208165Srrsmsgring_process(void *arg)
275208165Srrs{
276208165Srrs	volatile struct msgring_ithread *ithd;
277208165Srrs	struct thread *td;
278208165Srrs	struct proc *p;
279208165Srrs
280208165Srrs	td = curthread;
281208165Srrs	p = td->td_proc;
282208165Srrs	ithd = (volatile struct msgring_ithread *)arg;
283208165Srrs	KASSERT(ithd->i_thread == td,
284208165Srrs	    ("%s:msg_ithread and proc linkage out of sync", __func__));
285208165Srrs
286208165Srrs	/* First bind this thread to the right CPU */
287208165Srrs	thread_lock(td);
288208369Sjchandra
289208165Srrs	sched_bind(td, ithd->i_cpu);
290208165Srrs	thread_unlock(td);
291208165Srrs
292208369Sjchandra	atomic_store_rel_ptr((volatile uintptr_t *)&msgring_ithreads[ithd->i_core],
293208165Srrs	     (uintptr_t)arg);
294208165Srrs	enable_msgring_int(NULL);
295208165Srrs
296208165Srrs	while (1) {
297208165Srrs		while (ithd->i_pending) {
298208165Srrs			/*
299208165Srrs			 * This might need a full read and write barrier to
300208165Srrs			 * make sure that this write posts before any of the
301208165Srrs			 * memory or device accesses in the handlers.
302208165Srrs			 */
303208165Srrs			xlr_msgring_handler(NULL);
304208165Srrs			atomic_store_rel_int(&ithd->i_pending, 0);
305208165Srrs			enable_msgring_int(NULL);
306208165Srrs		}
307208165Srrs		if (!ithd->i_pending) {
308208165Srrs			thread_lock(td);
309208165Srrs			if (ithd->i_pending) {
310208165Srrs			  thread_unlock(td);
311208165Srrs			  continue;
312208165Srrs			}
313208165Srrs			sched_class(td, PRI_ITHD);
314208165Srrs			TD_SET_IWAIT(td);
315208165Srrs			mi_switch(SW_VOL, NULL);
316208165Srrs			thread_unlock(td);
317208165Srrs		}
318208165Srrs	}
319208165Srrs
320208165Srrs}
321208165Srrs
322208165Srrsstatic void
323208369Sjchandracreate_msgring_thread(int core, int cpu)
324208165Srrs{
325208165Srrs	struct msgring_ithread *ithd;
326208165Srrs	struct thread *td;
327208165Srrs	struct proc *p;
328208165Srrs	int error;
329208165Srrs
330208165Srrs	/* Create kernel thread for message ring interrupt processing */
331208165Srrs	/* Currently create one task for thread 0 of each core */
332208165Srrs	ithd = malloc(sizeof(struct msgring_ithread),
333208165Srrs	    M_DEVBUF, M_WAITOK | M_ZERO);
334208165Srrs	error = kproc_create(msgring_process, (void *)ithd, &p,
335208165Srrs	    RFSTOPPED | RFHIGHPID, 2, "msg_intr%d", cpu);
336208165Srrs
337208165Srrs	if (error)
338208165Srrs		panic("kproc_create() failed with %d", error);
339208165Srrs	td = FIRST_THREAD_IN_PROC(p);	/* XXXKSE */
340208165Srrs
341208165Srrs	ithd->i_thread = td;
342208165Srrs	ithd->i_pending = 0;
343208165Srrs	ithd->i_cpu = cpu;
344208369Sjchandra	ithd->i_core = core;
345208165Srrs
346208165Srrs	thread_lock(td);
347208165Srrs	sched_class(td, PRI_ITHD);
348208165Srrs	sched_add(td, SRQ_INTR);
349208165Srrs	thread_unlock(td);
350210845Sjchandra	CTR2(KTR_INTR, "%s: created %s", __func__, td->td_name);
351208165Srrs}
352208165Srrs
353198625Srrsint
354198625Srrsregister_msgring_handler(int major,
355198625Srrs    void (*action) (int, int, int, int, struct msgrng_msg *, void *),
356198625Srrs    void *dev_id)
357198160Srrs{
358198625Srrs	void *cookie;		/* FIXME - use? */
359198160Srrs
360198625Srrs	if (major >= MAX_TX_STNS)
361198160Srrs		return 1;
362198160Srrs
363211811Sjchandra	mtx_lock_spin(&msgrng_lock);
364198160Srrs	tx_stn_handlers[major].action = action;
365198160Srrs	tx_stn_handlers[major].dev_id = dev_id;
366211811Sjchandra	mtx_unlock_spin(&msgrng_lock);
367198625Srrs
368198160Srrs	if (xlr_test_and_set(&msgring_int_enabled)) {
369208369Sjchandra		create_msgring_thread(0, 0);
370203112Srrs		cpu_establish_hardintr("msgring", (driver_filter_t *) msgring_process_fast_intr,
371203112Srrs			NULL, NULL, IRQ_MSGRING,
372203112Srrs			INTR_TYPE_NET | INTR_FAST, &cookie);
373198160Srrs	}
374198160Srrs	return 0;
375198160Srrs}
376198160Srrs
377208165Srrsstatic void
378208165Srrsstart_msgring_threads(void *arg)
379208165Srrs{
380208369Sjchandra	int core, cpu;
381208165Srrs
382208369Sjchandra	for (core = 1; core < XLR_MAX_CORES; core++) {
383208369Sjchandra		if ((xlr_hw_thread_mask >> (4 * core)) & 0xf) {
384208369Sjchandra			/* start one thread for an enabled core */
385208369Sjchandra			cpu = xlr_hwtid_to_cpuid[4 * core];
386208369Sjchandra			create_msgring_thread(core, cpu);
387208369Sjchandra		}
388208369Sjchandra	}
389198160Srrs}
390208165Srrs
391208165SrrsSYSINIT(start_msgring_threads, SI_SUB_SMP, SI_ORDER_MIDDLE, start_msgring_threads, NULL);
392