1210311Sjmallett/*-
2210311Sjmallett * Copyright (c) 2010 Juli Mallett <jmallett@FreeBSD.org>
3210311Sjmallett * All rights reserved.
4210311Sjmallett *
5210311Sjmallett * Redistribution and use in source and binary forms, with or without
6210311Sjmallett * modification, are permitted provided that the following conditions
7210311Sjmallett * are met:
8210311Sjmallett * 1. Redistributions of source code must retain the above copyright
9210311Sjmallett *    notice, this list of conditions and the following disclaimer.
10210311Sjmallett * 2. Redistributions in binary form must reproduce the above copyright
11210311Sjmallett *    notice, this list of conditions and the following disclaimer in the
12210311Sjmallett *    documentation and/or other materials provided with the distribution.
13210311Sjmallett *
14210311Sjmallett * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15210311Sjmallett * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16210311Sjmallett * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17210311Sjmallett * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18210311Sjmallett * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19210311Sjmallett * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20210311Sjmallett * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21210311Sjmallett * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22210311Sjmallett * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23210311Sjmallett * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24210311Sjmallett * SUCH DAMAGE.
25210311Sjmallett *
26210311Sjmallett * $FreeBSD$
27210311Sjmallett */
28210311Sjmallett
29210311Sjmallett#include <sys/cdefs.h>
30210311Sjmallett__FBSDID("$FreeBSD$");
31210311Sjmallett
32210311Sjmallett#include <sys/param.h>
33210311Sjmallett#include <sys/systm.h>
34210311Sjmallett#include <sys/bus.h>
35210311Sjmallett#include <sys/interrupt.h>
36210311Sjmallett#include <sys/kernel.h>
37210311Sjmallett#include <sys/module.h>
38210311Sjmallett#include <sys/rman.h>
39210311Sjmallett#include <sys/malloc.h>
40216092Sjmallett#include <sys/smp.h>
41210311Sjmallett
42210311Sjmallett#include <machine/bus.h>
43210311Sjmallett#include <machine/intr_machdep.h>
44210311Sjmallett
45210311Sjmallett#include <contrib/octeon-sdk/cvmx.h>
46232812Sjmallett#include <mips/cavium/octeon_irq.h>
47210311Sjmallett
48210311Sjmallett/*
49210311Sjmallett * This bus sits between devices/buses and nexus and handles CIU interrupts
50210311Sjmallett * and passes everything else through.  It should really be a nexus subclass
51210311Sjmallett * or something, but for now this will be sufficient.
52210311Sjmallett */
53210311Sjmallett
54210311Sjmallett#define	CIU_IRQ_HARD		(0)
55210311Sjmallett
56232812Sjmallett#define	CIU_IRQ_EN0_BEGIN	OCTEON_IRQ_WORKQ0
57232812Sjmallett#define	CIU_IRQ_EN0_END		OCTEON_IRQ_BOOTDMA
58210311Sjmallett#define	CIU_IRQ_EN0_COUNT	((CIU_IRQ_EN0_END - CIU_IRQ_EN0_BEGIN) + 1)
59210311Sjmallett
60232812Sjmallett#define	CIU_IRQ_EN1_BEGIN	OCTEON_IRQ_WDOG0
61232812Sjmallett#define	CIU_IRQ_EN1_END		OCTEON_IRQ_DFM
62210311Sjmallett#define	CIU_IRQ_EN1_COUNT	((CIU_IRQ_EN1_END - CIU_IRQ_EN1_BEGIN) + 1)
63210311Sjmallett
64210311Sjmallettstruct ciu_softc {
65210311Sjmallett	struct rman irq_rman;
66210311Sjmallett	struct resource *ciu_irq;
67210311Sjmallett};
68210311Sjmallett
69210311Sjmallettstatic mips_intrcnt_t ciu_en0_intrcnt[CIU_IRQ_EN0_COUNT];
70210311Sjmallettstatic mips_intrcnt_t ciu_en1_intrcnt[CIU_IRQ_EN1_COUNT];
71210311Sjmallett
72210311Sjmallettstatic struct intr_event *ciu_en0_intr_events[CIU_IRQ_EN0_COUNT];
73210311Sjmallettstatic struct intr_event *ciu_en1_intr_events[CIU_IRQ_EN1_COUNT];
74210311Sjmallett
75210311Sjmallettstatic int		ciu_probe(device_t);
76210311Sjmallettstatic int		ciu_attach(device_t);
77210311Sjmallettstatic struct resource	*ciu_alloc_resource(device_t, device_t, int, int *,
78210311Sjmallett					    u_long, u_long, u_long, u_int);
79210311Sjmallettstatic int		ciu_setup_intr(device_t, device_t, struct resource *,
80210311Sjmallett				       int, driver_filter_t *, driver_intr_t *,
81210311Sjmallett				       void *, void **);
82213090Sjmallettstatic int		ciu_teardown_intr(device_t, device_t,
83213090Sjmallett					  struct resource *, void *);
84216092Sjmallettstatic int		ciu_bind_intr(device_t, device_t, struct resource *,
85216092Sjmallett				      int);
86216092Sjmallettstatic int		ciu_describe_intr(device_t, device_t,
87216092Sjmallett					  struct resource *, void *,
88216092Sjmallett					  const char *);
89210311Sjmallettstatic void		ciu_hinted_child(device_t, const char *, int);
90210311Sjmallett
91210311Sjmallettstatic void		ciu_en0_intr_mask(void *);
92210311Sjmallettstatic void		ciu_en0_intr_unmask(void *);
93216092Sjmallett#ifdef SMP
94216092Sjmallettstatic int		ciu_en0_intr_bind(void *, u_char);
95216092Sjmallett#endif
96210311Sjmallett
97210311Sjmallettstatic void		ciu_en1_intr_mask(void *);
98210311Sjmallettstatic void		ciu_en1_intr_unmask(void *);
99216092Sjmallett#ifdef SMP
100216092Sjmallettstatic int		ciu_en1_intr_bind(void *, u_char);
101216092Sjmallett#endif
102210311Sjmallett
103210311Sjmallettstatic int		ciu_intr(void *);
104210311Sjmallett
105210311Sjmallettstatic int
106210311Sjmallettciu_probe(device_t dev)
107210311Sjmallett{
108210311Sjmallett	if (device_get_unit(dev) != 0)
109210311Sjmallett		return (ENXIO);
110210311Sjmallett
111210311Sjmallett	device_set_desc(dev, "Cavium Octeon Central Interrupt Unit");
112265999Sian	return (BUS_PROBE_NOWILDCARD);
113210311Sjmallett}
114210311Sjmallett
115210311Sjmallettstatic int
116210311Sjmallettciu_attach(device_t dev)
117210311Sjmallett{
118210311Sjmallett	char name[MAXCOMLEN + 1];
119210311Sjmallett	struct ciu_softc *sc;
120210311Sjmallett	unsigned i;
121210311Sjmallett	int error;
122210311Sjmallett	int rid;
123210311Sjmallett
124210311Sjmallett	sc = device_get_softc(dev);
125210311Sjmallett
126210311Sjmallett	rid = 0;
127210311Sjmallett	sc->ciu_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, CIU_IRQ_HARD,
128210311Sjmallett					 CIU_IRQ_HARD, 1, RF_ACTIVE);
129210311Sjmallett	if (sc->ciu_irq == NULL) {
130210311Sjmallett		device_printf(dev, "could not allocate irq%d\n", CIU_IRQ_HARD);
131210311Sjmallett		return (ENXIO);
132210311Sjmallett	}
133210311Sjmallett
134210311Sjmallett	error = bus_setup_intr(dev, sc->ciu_irq, INTR_TYPE_MISC, ciu_intr,
135210311Sjmallett			       NULL, sc, NULL);
136210311Sjmallett	if (error != 0) {
137210311Sjmallett		device_printf(dev, "bus_setup_intr failed: %d\n", error);
138210311Sjmallett		return (error);
139210311Sjmallett	}
140210311Sjmallett
141210311Sjmallett	sc->irq_rman.rm_type = RMAN_ARRAY;
142210311Sjmallett	sc->irq_rman.rm_descr = "CIU IRQ";
143210311Sjmallett
144210311Sjmallett	error = rman_init(&sc->irq_rman);
145210311Sjmallett	if (error != 0)
146210311Sjmallett		return (error);
147210311Sjmallett
148210311Sjmallett	/*
149210311Sjmallett	 * We have two contiguous IRQ regions, use a single rman.
150210311Sjmallett	 */
151210311Sjmallett	error = rman_manage_region(&sc->irq_rman, CIU_IRQ_EN0_BEGIN,
152210311Sjmallett				   CIU_IRQ_EN1_END);
153210311Sjmallett	if (error != 0)
154210311Sjmallett		return (error);
155210311Sjmallett
156210311Sjmallett	for (i = 0; i < CIU_IRQ_EN0_COUNT; i++) {
157210311Sjmallett		snprintf(name, sizeof name, "int%d:", i + CIU_IRQ_EN0_BEGIN);
158210311Sjmallett		ciu_en0_intrcnt[i] = mips_intrcnt_create(name);
159210311Sjmallett	}
160210311Sjmallett
161210311Sjmallett	for (i = 0; i < CIU_IRQ_EN1_COUNT; i++) {
162210311Sjmallett		snprintf(name, sizeof name, "int%d:", i + CIU_IRQ_EN1_BEGIN);
163210311Sjmallett		ciu_en1_intrcnt[i] = mips_intrcnt_create(name);
164210311Sjmallett	}
165210311Sjmallett
166210311Sjmallett	bus_generic_probe(dev);
167210311Sjmallett	bus_generic_attach(dev);
168210311Sjmallett
169210311Sjmallett	return (0);
170210311Sjmallett}
171210311Sjmallett
172210311Sjmallettstatic struct resource *
173210311Sjmallettciu_alloc_resource(device_t bus, device_t child, int type, int *rid,
174210311Sjmallett		   u_long start, u_long end, u_long count, u_int flags)
175210311Sjmallett{
176210311Sjmallett	struct resource *res;
177210311Sjmallett	struct ciu_softc *sc;
178210311Sjmallett
179210311Sjmallett	sc = device_get_softc(bus);
180210311Sjmallett
181210311Sjmallett	switch (type) {
182210311Sjmallett	case SYS_RES_IRQ:
183210311Sjmallett		break;
184210311Sjmallett	default:
185210311Sjmallett		return (bus_alloc_resource(device_get_parent(bus), type, rid,
186210311Sjmallett					   start, end, count, flags));
187210311Sjmallett	}
188210311Sjmallett
189210311Sjmallett	/*
190210311Sjmallett	 * One interrupt at a time for now.
191210311Sjmallett	 */
192210311Sjmallett	if (start != end)
193210311Sjmallett		return (NULL);
194210311Sjmallett
195210311Sjmallett	res = rman_reserve_resource(&sc->irq_rman, start, end, count, flags,
196210311Sjmallett				    child);
197210311Sjmallett	if (res != NULL)
198210311Sjmallett		return (res);
199210311Sjmallett
200210311Sjmallett	return (NULL);
201210311Sjmallett}
202210311Sjmallett
203210311Sjmallettstatic int
204210311Sjmallettciu_setup_intr(device_t bus, device_t child, struct resource *res, int flags,
205210311Sjmallett	       driver_filter_t *filter, driver_intr_t *intr, void *arg,
206210311Sjmallett	       void **cookiep)
207210311Sjmallett{
208210311Sjmallett	struct intr_event *event, **eventp;
209210311Sjmallett	void (*mask_func)(void *);
210210311Sjmallett	void (*unmask_func)(void *);
211216092Sjmallett	int (*bind_func)(void *, u_char);
212210311Sjmallett	mips_intrcnt_t intrcnt;
213210311Sjmallett	int error;
214210311Sjmallett	int irq;
215210311Sjmallett
216210311Sjmallett	irq = rman_get_start(res);
217210311Sjmallett	if (irq <= CIU_IRQ_EN0_END) {
218210311Sjmallett		eventp = &ciu_en0_intr_events[irq - CIU_IRQ_EN0_BEGIN];
219210311Sjmallett		intrcnt = ciu_en0_intrcnt[irq - CIU_IRQ_EN0_BEGIN];
220210311Sjmallett		mask_func = ciu_en0_intr_mask;
221210311Sjmallett		unmask_func = ciu_en0_intr_unmask;
222216092Sjmallett#ifdef SMP
223216092Sjmallett		bind_func = ciu_en0_intr_bind;
224216092Sjmallett#endif
225210311Sjmallett	} else {
226210311Sjmallett		eventp = &ciu_en1_intr_events[irq - CIU_IRQ_EN1_BEGIN];
227210311Sjmallett		intrcnt = ciu_en1_intrcnt[irq - CIU_IRQ_EN1_BEGIN];
228210311Sjmallett		mask_func = ciu_en1_intr_mask;
229210311Sjmallett		unmask_func = ciu_en1_intr_unmask;
230216092Sjmallett#ifdef SMP
231216092Sjmallett		bind_func = ciu_en1_intr_bind;
232216092Sjmallett#endif
233210311Sjmallett	}
234216092Sjmallett#if !defined(SMP)
235216092Sjmallett	bind_func = NULL;
236216092Sjmallett#endif
237210311Sjmallett
238210311Sjmallett	if ((event = *eventp) == NULL) {
239210311Sjmallett		error = intr_event_create(eventp, (void *)(uintptr_t)irq, 0,
240216092Sjmallett		    irq, mask_func, unmask_func, NULL, bind_func, "int%d", irq);
241210311Sjmallett		if (error != 0)
242210311Sjmallett			return (error);
243210311Sjmallett
244210311Sjmallett		event = *eventp;
245210311Sjmallett
246210311Sjmallett		unmask_func((void *)(uintptr_t)irq);
247210311Sjmallett	}
248210311Sjmallett
249210311Sjmallett	intr_event_add_handler(event, device_get_nameunit(child),
250210311Sjmallett	    filter, intr, arg, intr_priority(flags), flags, cookiep);
251210311Sjmallett
252210311Sjmallett	mips_intrcnt_setname(intrcnt, event->ie_fullname);
253210311Sjmallett
254210311Sjmallett	return (0);
255210311Sjmallett}
256210311Sjmallett
257213090Sjmallettstatic int
258213090Sjmallettciu_teardown_intr(device_t bus, device_t child, struct resource *res,
259213090Sjmallett		  void *cookie)
260213090Sjmallett{
261213090Sjmallett	int error;
262213090Sjmallett
263213090Sjmallett	error = intr_event_remove_handler(cookie);
264213090Sjmallett	if (error != 0)
265213090Sjmallett		return (error);
266213090Sjmallett
267213090Sjmallett	return (0);
268213090Sjmallett}
269213090Sjmallett
270216092Sjmallett#ifdef SMP
271216092Sjmallettstatic int
272216092Sjmallettciu_bind_intr(device_t bus, device_t child, struct resource *res, int cpu)
273216092Sjmallett{
274216092Sjmallett	struct intr_event *event;
275216092Sjmallett	int irq;
276216092Sjmallett
277216092Sjmallett	irq = rman_get_start(res);
278216092Sjmallett	if (irq <= CIU_IRQ_EN0_END)
279216092Sjmallett		event = ciu_en0_intr_events[irq - CIU_IRQ_EN0_BEGIN];
280216092Sjmallett	else
281216092Sjmallett		event = ciu_en1_intr_events[irq - CIU_IRQ_EN1_BEGIN];
282216092Sjmallett
283216092Sjmallett	return (intr_event_bind(event, cpu));
284216092Sjmallett}
285216092Sjmallett#endif
286216092Sjmallett
287216092Sjmallettstatic int
288216092Sjmallettciu_describe_intr(device_t bus, device_t child, struct resource *res,
289216092Sjmallett		  void *cookie, const char *descr)
290216092Sjmallett{
291216092Sjmallett	struct intr_event *event;
292216092Sjmallett	mips_intrcnt_t intrcnt;
293216092Sjmallett	int error;
294216092Sjmallett	int irq;
295216092Sjmallett
296216092Sjmallett	irq = rman_get_start(res);
297216092Sjmallett	if (irq <= CIU_IRQ_EN0_END) {
298216092Sjmallett		event = ciu_en0_intr_events[irq - CIU_IRQ_EN0_BEGIN];
299216092Sjmallett		intrcnt = ciu_en0_intrcnt[irq - CIU_IRQ_EN0_BEGIN];
300216092Sjmallett	} else {
301216092Sjmallett		event = ciu_en1_intr_events[irq - CIU_IRQ_EN1_BEGIN];
302216092Sjmallett		intrcnt = ciu_en1_intrcnt[irq - CIU_IRQ_EN1_BEGIN];
303216092Sjmallett	}
304216092Sjmallett
305216092Sjmallett	error = intr_event_describe_handler(event, cookie, descr);
306216092Sjmallett	if (error != 0)
307216092Sjmallett		return (error);
308216092Sjmallett
309216092Sjmallett	mips_intrcnt_setname(intrcnt, event->ie_fullname);
310216092Sjmallett
311216092Sjmallett	return (0);
312216092Sjmallett}
313216092Sjmallett
314210311Sjmallettstatic void
315210311Sjmallettciu_hinted_child(device_t bus, const char *dname, int dunit)
316210311Sjmallett{
317210311Sjmallett	BUS_ADD_CHILD(bus, 0, dname, dunit);
318210311Sjmallett}
319210311Sjmallett
320210311Sjmallettstatic void
321210311Sjmallettciu_en0_intr_mask(void *arg)
322210311Sjmallett{
323210311Sjmallett	uint64_t mask;
324210311Sjmallett	int irq;
325210311Sjmallett
326210311Sjmallett	irq = (uintptr_t)arg;
327210311Sjmallett	mask = cvmx_read_csr(CVMX_CIU_INTX_EN0(cvmx_get_core_num()*2));
328210311Sjmallett	mask &= ~(1ull << (irq - CIU_IRQ_EN0_BEGIN));
329210311Sjmallett	cvmx_write_csr(CVMX_CIU_INTX_EN0(cvmx_get_core_num()*2), mask);
330210311Sjmallett}
331210311Sjmallett
332210311Sjmallettstatic void
333210311Sjmallettciu_en0_intr_unmask(void *arg)
334210311Sjmallett{
335210311Sjmallett	uint64_t mask;
336210311Sjmallett	int irq;
337210311Sjmallett
338210311Sjmallett	irq = (uintptr_t)arg;
339210311Sjmallett	mask = cvmx_read_csr(CVMX_CIU_INTX_EN0(cvmx_get_core_num()*2));
340210311Sjmallett	mask |= 1ull << (irq - CIU_IRQ_EN0_BEGIN);
341210311Sjmallett	cvmx_write_csr(CVMX_CIU_INTX_EN0(cvmx_get_core_num()*2), mask);
342210311Sjmallett}
343210311Sjmallett
344216092Sjmallett#ifdef SMP
345216092Sjmallettstatic int
346216092Sjmallettciu_en0_intr_bind(void *arg, u_char target)
347216092Sjmallett{
348216092Sjmallett	uint64_t mask;
349216092Sjmallett	int core;
350216092Sjmallett	int irq;
351216092Sjmallett
352216092Sjmallett	irq = (uintptr_t)arg;
353216092Sjmallett	CPU_FOREACH(core) {
354216092Sjmallett		mask = cvmx_read_csr(CVMX_CIU_INTX_EN0(core*2));
355216092Sjmallett		if (core == target)
356216092Sjmallett			mask |= 1ull << (irq - CIU_IRQ_EN0_BEGIN);
357216092Sjmallett		else
358216092Sjmallett			mask &= ~(1ull << (irq - CIU_IRQ_EN0_BEGIN));
359216092Sjmallett		cvmx_write_csr(CVMX_CIU_INTX_EN0(core*2), mask);
360216092Sjmallett	}
361216092Sjmallett
362216092Sjmallett	return (0);
363216092Sjmallett}
364216092Sjmallett#endif
365216092Sjmallett
366210311Sjmallettstatic void
367210311Sjmallettciu_en1_intr_mask(void *arg)
368210311Sjmallett{
369210311Sjmallett	uint64_t mask;
370210311Sjmallett	int irq;
371210311Sjmallett
372210311Sjmallett	irq = (uintptr_t)arg;
373210311Sjmallett	mask = cvmx_read_csr(CVMX_CIU_INTX_EN1(cvmx_get_core_num()*2));
374210311Sjmallett	mask &= ~(1ull << (irq - CIU_IRQ_EN1_BEGIN));
375210311Sjmallett	cvmx_write_csr(CVMX_CIU_INTX_EN1(cvmx_get_core_num()*2), mask);
376210311Sjmallett}
377210311Sjmallett
378210311Sjmallettstatic void
379210311Sjmallettciu_en1_intr_unmask(void *arg)
380210311Sjmallett{
381210311Sjmallett	uint64_t mask;
382210311Sjmallett	int irq;
383210311Sjmallett
384210311Sjmallett	irq = (uintptr_t)arg;
385210311Sjmallett	mask = cvmx_read_csr(CVMX_CIU_INTX_EN1(cvmx_get_core_num()*2));
386210311Sjmallett	mask |= 1ull << (irq - CIU_IRQ_EN1_BEGIN);
387210311Sjmallett	cvmx_write_csr(CVMX_CIU_INTX_EN1(cvmx_get_core_num()*2), mask);
388210311Sjmallett}
389210311Sjmallett
390216092Sjmallett#ifdef SMP
391210311Sjmallettstatic int
392216092Sjmallettciu_en1_intr_bind(void *arg, u_char target)
393216092Sjmallett{
394216092Sjmallett	uint64_t mask;
395216092Sjmallett	int core;
396216092Sjmallett	int irq;
397216092Sjmallett
398216092Sjmallett	irq = (uintptr_t)arg;
399216092Sjmallett	CPU_FOREACH(core) {
400216092Sjmallett		mask = cvmx_read_csr(CVMX_CIU_INTX_EN1(core*2));
401216092Sjmallett		if (core == target)
402216092Sjmallett			mask |= 1ull << (irq - CIU_IRQ_EN1_BEGIN);
403216092Sjmallett		else
404216092Sjmallett			mask &= ~(1ull << (irq - CIU_IRQ_EN1_BEGIN));
405216092Sjmallett		cvmx_write_csr(CVMX_CIU_INTX_EN1(core*2), mask);
406216092Sjmallett	}
407216092Sjmallett
408216092Sjmallett	return (0);
409216092Sjmallett}
410216092Sjmallett#endif
411216092Sjmallett
412216092Sjmallettstatic int
413210311Sjmallettciu_intr(void *arg)
414210311Sjmallett{
415210311Sjmallett	struct ciu_softc *sc;
416210311Sjmallett	uint64_t en0_sum, en1_sum;
417210311Sjmallett	uint64_t en0_mask, en1_mask;
418210311Sjmallett	int irq_index;
419210311Sjmallett	int error;
420210311Sjmallett
421210311Sjmallett	sc = arg;
422210311Sjmallett	(void)sc;
423210311Sjmallett
424210311Sjmallett	en0_sum = cvmx_read_csr(CVMX_CIU_INTX_SUM0(cvmx_get_core_num()*2));
425210311Sjmallett	en1_sum = cvmx_read_csr(CVMX_CIU_INT_SUM1);
426210311Sjmallett
427210311Sjmallett	en0_mask = cvmx_read_csr(CVMX_CIU_INTX_EN0(cvmx_get_core_num()*2));
428210311Sjmallett	en1_mask = cvmx_read_csr(CVMX_CIU_INTX_EN1(cvmx_get_core_num()*2));
429210311Sjmallett
430210311Sjmallett	en0_sum &= en0_mask;
431210311Sjmallett	en1_sum &= en1_mask;
432210311Sjmallett
433210311Sjmallett	if (en0_sum == 0 && en1_sum == 0)
434210311Sjmallett		return (FILTER_STRAY);
435210311Sjmallett
436210311Sjmallett	irq_index = 0;
437210311Sjmallett	for (irq_index = 0; en0_sum != 0; irq_index++, en0_sum >>= 1) {
438210311Sjmallett		if ((en0_sum & 1) == 0)
439210311Sjmallett			continue;
440210311Sjmallett
441210311Sjmallett		mips_intrcnt_inc(ciu_en0_intrcnt[irq_index]);
442210311Sjmallett
443210311Sjmallett		error = intr_event_handle(ciu_en0_intr_events[irq_index], NULL);
444210311Sjmallett		if (error != 0)
445210311Sjmallett			printf("%s: stray en0 irq%d\n", __func__, irq_index);
446210311Sjmallett	}
447210311Sjmallett
448210311Sjmallett	irq_index = 0;
449210311Sjmallett	for (irq_index = 0; en1_sum != 0; irq_index++, en1_sum >>= 1) {
450210311Sjmallett		if ((en1_sum & 1) == 0)
451210311Sjmallett			continue;
452210311Sjmallett
453210311Sjmallett		mips_intrcnt_inc(ciu_en1_intrcnt[irq_index]);
454210311Sjmallett
455210311Sjmallett		error = intr_event_handle(ciu_en1_intr_events[irq_index], NULL);
456210311Sjmallett		if (error != 0)
457210311Sjmallett			printf("%s: stray en1 irq%d\n", __func__, irq_index);
458210311Sjmallett	}
459210311Sjmallett
460210311Sjmallett	return (FILTER_HANDLED);
461210311Sjmallett}
462210311Sjmallett
463210311Sjmallettstatic device_method_t ciu_methods[] = {
464210311Sjmallett	DEVMETHOD(device_probe,		ciu_probe),
465210311Sjmallett	DEVMETHOD(device_attach,	ciu_attach),
466210311Sjmallett
467210311Sjmallett	DEVMETHOD(bus_alloc_resource,	ciu_alloc_resource),
468210311Sjmallett	DEVMETHOD(bus_activate_resource,bus_generic_activate_resource),
469210311Sjmallett	DEVMETHOD(bus_setup_intr,	ciu_setup_intr),
470213090Sjmallett	DEVMETHOD(bus_teardown_intr,	ciu_teardown_intr),
471216092Sjmallett#ifdef SMP
472216092Sjmallett	DEVMETHOD(bus_bind_intr,	ciu_bind_intr),
473216092Sjmallett#endif
474216092Sjmallett	DEVMETHOD(bus_describe_intr,	ciu_describe_intr),
475210311Sjmallett
476210311Sjmallett	DEVMETHOD(bus_add_child,	bus_generic_add_child),
477210311Sjmallett	DEVMETHOD(bus_hinted_child,	ciu_hinted_child),
478210311Sjmallett
479210311Sjmallett	{ 0, 0 }
480210311Sjmallett};
481210311Sjmallett
482210311Sjmallettstatic driver_t ciu_driver = {
483210311Sjmallett	"ciu",
484210311Sjmallett	ciu_methods,
485210311Sjmallett	sizeof(struct ciu_softc),
486210311Sjmallett};
487210311Sjmallettstatic devclass_t ciu_devclass;
488210311SjmallettDRIVER_MODULE(ciu, nexus, ciu_driver, ciu_devclass, 0, 0);
489