fmn.c revision 211809
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 211809 2010-08-25 09:53:00Z 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;
118198160Srrs	unsigned long 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
128198160Srrs	msgrng_flags_save(flags);
129198625Srrs
130198625Srrs	/*
131198625Srrs	 * Message Stations are shared among all threads in a cpu core
132198625Srrs	 * Assume, thread 0 on all cores are always active when more than 1
133198625Srrs	 * thread is active in a core
134198160Srrs	 */
135198625Srrs	msgrng_write_bucksize(0, bucket_sizes->bucket[id * 8 + 0]);
136198625Srrs	msgrng_write_bucksize(1, bucket_sizes->bucket[id * 8 + 1]);
137198625Srrs	msgrng_write_bucksize(2, bucket_sizes->bucket[id * 8 + 2]);
138198625Srrs	msgrng_write_bucksize(3, bucket_sizes->bucket[id * 8 + 3]);
139198625Srrs	msgrng_write_bucksize(4, bucket_sizes->bucket[id * 8 + 4]);
140198625Srrs	msgrng_write_bucksize(5, bucket_sizes->bucket[id * 8 + 5]);
141198625Srrs	msgrng_write_bucksize(6, bucket_sizes->bucket[id * 8 + 6]);
142198625Srrs	msgrng_write_bucksize(7, bucket_sizes->bucket[id * 8 + 7]);
143198160Srrs
144198160Srrs	MSGRNG_CC_INIT_CPU_DEST(0, cc_config->counters);
145198160Srrs	MSGRNG_CC_INIT_CPU_DEST(1, cc_config->counters);
146198160Srrs	MSGRNG_CC_INIT_CPU_DEST(2, cc_config->counters);
147198160Srrs	MSGRNG_CC_INIT_CPU_DEST(3, cc_config->counters);
148198160Srrs	MSGRNG_CC_INIT_CPU_DEST(4, cc_config->counters);
149198160Srrs	MSGRNG_CC_INIT_CPU_DEST(5, cc_config->counters);
150198160Srrs	MSGRNG_CC_INIT_CPU_DEST(6, cc_config->counters);
151198160Srrs	MSGRNG_CC_INIT_CPU_DEST(7, cc_config->counters);
152198160Srrs	MSGRNG_CC_INIT_CPU_DEST(8, cc_config->counters);
153198160Srrs	MSGRNG_CC_INIT_CPU_DEST(9, cc_config->counters);
154198160Srrs	MSGRNG_CC_INIT_CPU_DEST(10, cc_config->counters);
155198160Srrs	MSGRNG_CC_INIT_CPU_DEST(11, cc_config->counters);
156198160Srrs	MSGRNG_CC_INIT_CPU_DEST(12, cc_config->counters);
157198160Srrs	MSGRNG_CC_INIT_CPU_DEST(13, cc_config->counters);
158198160Srrs	MSGRNG_CC_INIT_CPU_DEST(14, cc_config->counters);
159198160Srrs	MSGRNG_CC_INIT_CPU_DEST(15, cc_config->counters);
160198160Srrs
161198160Srrs	msgrng_flags_restore(flags);
162198160Srrs}
163198160Srrs
164198625Srrsvoid
165198625Srrsxlr_msgring_config(void)
166198160Srrs{
167211802Sjchandra	mtx_init(&msgrng_lock, "msgring", NULL, MTX_SPIN | MTX_RECURSE);
168198160Srrs	msgring_int_type = 0x02;
169198160Srrs	msgring_pop_num_buckets = 8;
170198160Srrs	msgring_pop_bucket_mask = 0xff;
171211802Sjchandra	msgring_int_enabled = 0;
172198160Srrs	msgring_watermark_count = 1;
173198160Srrs	msgring_thread_mask = 0x01;
174198160Srrs}
175198160Srrs
176198625Srrsvoid
177198625Srrsxlr_msgring_handler(struct trapframe *tf)
178198160Srrs{
179198160Srrs	unsigned long mflags;
180198625Srrs	int bucket = 0;
181198625Srrs	int size = 0, code = 0, rx_stid = 0, tx_stid = 0;
182198160Srrs	struct msgrng_msg msg;
183198160Srrs	unsigned int bucket_empty_bm = 0;
184198625Srrs	unsigned int status = 0;
185198160Srrs
186198160Srrs	/* TODO: not necessary to disable preemption */
187198160Srrs	msgrng_flags_save(mflags);
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);
213198160Srrs				msgrng_flags_restore(mflags);
214198625Srrs				(*tx_stn_handlers[tx_stid].action) (bucket, size, code, rx_stid,
215198625Srrs				    &msg, tx_stn_handlers[tx_stid].dev_id);
216198160Srrs				msgrng_flags_save(mflags);
217198625Srrs			}
218198160Srrs		}
219198160Srrs	}
220198160Srrs	msgrng_flags_restore(mflags);
221198160Srrs}
222198160Srrs
223198625Srrsvoid
224198625Srrsenable_msgring_int(void *arg)
225198160Srrs{
226198625Srrs	unsigned long mflags = 0;
227198160Srrs
228198160Srrs	msgrng_access_save(&msgrng_lock, mflags);
229198160Srrs	/* enable the message ring interrupts */
230198625Srrs	msgrng_write_config((msgring_watermark_count << 24) | (IRQ_MSGRING << 16)
231198625Srrs	    | (msgring_thread_mask << 8) | msgring_int_type);
232198625Srrs	msgrng_access_restore(&msgrng_lock, mflags);
233198160Srrs}
234198160Srrs
235198625Srrsvoid
236198625Srrsdisable_msgring_int(void *arg)
237198160Srrs{
238198625Srrs	unsigned long mflags = 0;
239198160Srrs	uint32_t config;
240198160Srrs
241198160Srrs	msgrng_access_save(&msgrng_lock, mflags);
242198160Srrs	config = msgrng_read_config();
243198160Srrs	config &= ~0x3;
244198160Srrs	msgrng_write_config(config);
245198625Srrs	msgrng_access_restore(&msgrng_lock, mflags);
246198160Srrs}
247198160Srrs
248208165Srrsstatic int
249208165Srrsmsgring_process_fast_intr(void *arg)
250208165Srrs{
251208369Sjchandra	int core = xlr_core_id();
252208165Srrs	volatile struct msgring_ithread *it;
253208165Srrs	struct thread *td;
254198160Srrs
255208165Srrs	/* wakeup an appropriate intr_thread for processing this interrupt */
256208369Sjchandra	it = (volatile struct msgring_ithread *)msgring_ithreads[core];
257208369Sjchandra	KASSERT(it != NULL, ("No interrupt thread on cpu %d", core));
258208165Srrs	td = it->i_thread;
259208165Srrs
260208165Srrs	/*
261208165Srrs	 * Interrupt thread will enable the interrupts after processing all
262208165Srrs	 * messages
263208165Srrs	 */
264208165Srrs	disable_msgring_int(NULL);
265208165Srrs	atomic_store_rel_int(&it->i_pending, 1);
266208165Srrs	thread_lock(td);
267208165Srrs	if (TD_AWAITING_INTR(td)) {
268208165Srrs		TD_CLR_IWAIT(td);
269208165Srrs		sched_add(td, SRQ_INTR);
270208165Srrs	}
271208165Srrs	thread_unlock(td);
272208165Srrs	return FILTER_HANDLED;
273208165Srrs}
274208165Srrs
275208165Srrsstatic void
276208165Srrsmsgring_process(void *arg)
277208165Srrs{
278208165Srrs	volatile struct msgring_ithread *ithd;
279208165Srrs	struct thread *td;
280208165Srrs	struct proc *p;
281208165Srrs
282208165Srrs	td = curthread;
283208165Srrs	p = td->td_proc;
284208165Srrs	ithd = (volatile struct msgring_ithread *)arg;
285208165Srrs	KASSERT(ithd->i_thread == td,
286208165Srrs	    ("%s:msg_ithread and proc linkage out of sync", __func__));
287208165Srrs
288208165Srrs	/* First bind this thread to the right CPU */
289208165Srrs	thread_lock(td);
290208369Sjchandra
291208165Srrs	sched_bind(td, ithd->i_cpu);
292208165Srrs	thread_unlock(td);
293208165Srrs
294208369Sjchandra	atomic_store_rel_ptr((volatile uintptr_t *)&msgring_ithreads[ithd->i_core],
295208165Srrs	     (uintptr_t)arg);
296208165Srrs	enable_msgring_int(NULL);
297208165Srrs
298208165Srrs	while (1) {
299208165Srrs		while (ithd->i_pending) {
300208165Srrs			/*
301208165Srrs			 * This might need a full read and write barrier to
302208165Srrs			 * make sure that this write posts before any of the
303208165Srrs			 * memory or device accesses in the handlers.
304208165Srrs			 */
305208165Srrs			xlr_msgring_handler(NULL);
306208165Srrs			atomic_store_rel_int(&ithd->i_pending, 0);
307208165Srrs			enable_msgring_int(NULL);
308208165Srrs		}
309208165Srrs		if (!ithd->i_pending) {
310208165Srrs			thread_lock(td);
311208165Srrs			if (ithd->i_pending) {
312208165Srrs			  thread_unlock(td);
313208165Srrs			  continue;
314208165Srrs			}
315208165Srrs			sched_class(td, PRI_ITHD);
316208165Srrs			TD_SET_IWAIT(td);
317208165Srrs			mi_switch(SW_VOL, NULL);
318208165Srrs			thread_unlock(td);
319208165Srrs		}
320208165Srrs	}
321208165Srrs
322208165Srrs}
323208165Srrs
324208165Srrsstatic void
325208369Sjchandracreate_msgring_thread(int core, int cpu)
326208165Srrs{
327208165Srrs	struct msgring_ithread *ithd;
328208165Srrs	struct thread *td;
329208165Srrs	struct proc *p;
330208165Srrs	int error;
331208165Srrs
332208165Srrs	/* Create kernel thread for message ring interrupt processing */
333208165Srrs	/* Currently create one task for thread 0 of each core */
334208165Srrs	ithd = malloc(sizeof(struct msgring_ithread),
335208165Srrs	    M_DEVBUF, M_WAITOK | M_ZERO);
336208165Srrs	error = kproc_create(msgring_process, (void *)ithd, &p,
337208165Srrs	    RFSTOPPED | RFHIGHPID, 2, "msg_intr%d", cpu);
338208165Srrs
339208165Srrs	if (error)
340208165Srrs		panic("kproc_create() failed with %d", error);
341208165Srrs	td = FIRST_THREAD_IN_PROC(p);	/* XXXKSE */
342208165Srrs
343208165Srrs	ithd->i_thread = td;
344208165Srrs	ithd->i_pending = 0;
345208165Srrs	ithd->i_cpu = cpu;
346208369Sjchandra	ithd->i_core = core;
347208165Srrs
348208165Srrs	thread_lock(td);
349208165Srrs	sched_class(td, PRI_ITHD);
350208165Srrs	sched_add(td, SRQ_INTR);
351208165Srrs	thread_unlock(td);
352210845Sjchandra	CTR2(KTR_INTR, "%s: created %s", __func__, td->td_name);
353208165Srrs}
354208165Srrs
355198625Srrsint
356198625Srrsregister_msgring_handler(int major,
357198625Srrs    void (*action) (int, int, int, int, struct msgrng_msg *, void *),
358198625Srrs    void *dev_id)
359198160Srrs{
360198625Srrs	void *cookie;		/* FIXME - use? */
361198160Srrs
362198625Srrs	if (major >= MAX_TX_STNS)
363198160Srrs		return 1;
364198160Srrs
365198160Srrs	//dbg_msg("major=%d, action=%p, dev_id=%p\n", major, action, dev_id);
366198160Srrs
367198956Srrs	if (rmi_spin_mutex_safe)
368198956Srrs	  mtx_lock_spin(&msgrng_lock);
369198160Srrs	tx_stn_handlers[major].action = action;
370198160Srrs	tx_stn_handlers[major].dev_id = dev_id;
371198956Srrs	if (rmi_spin_mutex_safe)
372198956Srrs	  mtx_unlock_spin(&msgrng_lock);
373198625Srrs
374198160Srrs	if (xlr_test_and_set(&msgring_int_enabled)) {
375208369Sjchandra		create_msgring_thread(0, 0);
376203112Srrs		cpu_establish_hardintr("msgring", (driver_filter_t *) msgring_process_fast_intr,
377203112Srrs			NULL, NULL, IRQ_MSGRING,
378203112Srrs			INTR_TYPE_NET | INTR_FAST, &cookie);
379198160Srrs	}
380198160Srrs	return 0;
381198160Srrs}
382198160Srrs
383208165Srrsstatic void
384208165Srrsstart_msgring_threads(void *arg)
385208165Srrs{
386208369Sjchandra	int core, cpu;
387208165Srrs
388208369Sjchandra	for (core = 1; core < XLR_MAX_CORES; core++) {
389208369Sjchandra		if ((xlr_hw_thread_mask >> (4 * core)) & 0xf) {
390208369Sjchandra			/* start one thread for an enabled core */
391208369Sjchandra			cpu = xlr_hwtid_to_cpuid[4 * core];
392208369Sjchandra			create_msgring_thread(core, cpu);
393208369Sjchandra		}
394208369Sjchandra	}
395198160Srrs}
396208165Srrs
397208165SrrsSYSINIT(start_msgring_threads, SI_SUB_SMP, SI_ORDER_MIDDLE, start_msgring_threads, NULL);
398