beri_pic.c revision 257522
1/*-
2 * Copyright (c) 2013 SRI International
3 * All rights reserved.
4 *
5 * This software was developed by SRI International and the University of
6 * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
7 * ("CTSRD"), as part of the DARPA CRASH research programme.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31#include <sys/cdefs.h>
32__FBSDID("$FreeBSD: stable/10/sys/mips/beri/beri_pic.c 257522 2013-11-01 20:28:13Z brooks $");
33
34#include <sys/param.h>
35#include <sys/kernel.h>
36#include <sys/lock.h>
37#include <sys/malloc.h>
38#include <sys/module.h>
39#include <sys/mutex.h>
40#include <sys/systm.h>
41#include <sys/bus.h>
42
43#include <machine/bus.h>
44#include <machine/intr_machdep.h>
45
46#include <dev/ofw/ofw_bus.h>
47#include <dev/ofw/ofw_bus_subr.h>
48
49#include <dev/fdt/fdt_common.h>
50
51#include "fdt_ic_if.h"
52
53struct beripic_softc;
54
55static uint64_t	bp_read_cfg(struct beripic_softc *, int);
56static void	bp_write_cfg(struct beripic_softc *, int, uint64_t);
57static void	bp_detach_resources(device_t);
58static char	*bp_strconfig(uint64_t, char *, size_t);
59static void	bp_config_source(device_t, int, int, u_long, u_long);
60#ifdef __mips__
61static void	bp_set_counter_name(device_t, device_t, int);
62#endif
63
64static int	beripic_fdt_probe(device_t);
65static int	beripic_fdt_attach(device_t);
66
67static int	beripic_activate_intr(device_t, struct resource *);
68static struct resource *
69		beripic_alloc_intr(device_t, device_t, int *, u_long, u_int);
70static int	beripic_config_intr(device_t, int,  enum intr_trigger,
71		    enum intr_polarity);
72static int	beripic_release_intr(device_t, struct resource *);
73static int	beripic_setup_intr(device_t, device_t, struct resource *,
74		    int, driver_filter_t *, driver_intr_t *, void *, void **);
75static int	beripic_teardown_intr(device_t, device_t, struct resource *,
76		    void *);
77
78static int	beripic_filter(void *);
79static void	beripic_intr(void *);
80
81#define	BP_MAX_HARD_IRQS	6
82#define	BP_FIRST_SOFT		64
83
84struct beripic_softc {
85	device_t		bp_dev;
86	struct resource		*bp_cfg_res;
87	struct resource		*bp_read_res;
88	struct resource		*bp_set_res;
89	struct resource		*bp_clear_res;
90	int			bp_cfg_rid;
91	int			bp_read_rid;
92	int			bp_set_rid;
93	int			bp_clear_rid;
94	bus_space_tag_t		bp_cfg_bst;
95	bus_space_tag_t		bp_read_bst;
96	bus_space_tag_t		bp_set_bst;
97	bus_space_tag_t		bp_clear_bst;
98	bus_space_handle_t	bp_cfg_bsh;
99	bus_space_handle_t	bp_read_bsh;
100	bus_space_handle_t	bp_set_bsh;
101	bus_space_handle_t	bp_clear_bsh;
102
103	struct resource		*bp_irqs[BP_MAX_HARD_IRQS];
104	int			bp_irq_rids[BP_MAX_HARD_IRQS];
105	int			bp_nirqs;
106	int			bp_next_irq;
107	int			bp_next_tid;
108
109	int			bp_nthreads;
110
111	int			bp_nhard;
112	int			bp_nsoft;
113	int			bp_nsrcs;
114	struct rman		bp_src_rman;
115
116#ifdef __mips__
117	mips_intrcnt_t		*bp_counters;
118#endif
119
120	struct mtx		bp_cfgmtx;
121};
122
123struct beripic_intr_arg {
124	driver_filter_t		*filter;
125	driver_intr_t		*intr;
126	void			*arg;
127	struct resource		*irq;
128#ifdef __mips__
129	mips_intrcnt_t		counter;
130#endif
131};
132
133struct beripic_cookie {
134	struct beripic_intr_arg	*bpia;
135	struct resource		*hirq;
136	void			*cookie;
137};
138
139#define	BP_CFG_MASK_E		0x80000000ull
140#define	BP_CFG_SHIFT_E		31
141#define	BP_CFG_MASK_TID		0x7FFFFF00ull	/* Depends on CPU */
142#define	BP_CFG_SHIFT_TID	8
143#define	BP_CFG_MASK_IRQ		0x0000000Full
144#define BP_CFG_SHIFT_IRQ	0
145#define	BP_CFG_VALID		(BP_CFG_MASK_E|BP_CFG_MASK_TID|BP_CFG_MASK_IRQ)
146#define	BP_CFG_RESERVED		~BP_CFG_VALID
147
148#define	BP_CFG_ENABLED(cfg)	(((cfg) & BP_CFG_MASK_E) >> BP_CFG_SHIFT_E)
149#define	BP_CFG_TID(cfg)		(((cfg) & BP_CFG_MASK_TID) >> BP_CFG_SHIFT_TID)
150#define	BP_CFG_IRQ(cfg)		(((cfg) & BP_CFG_MASK_IRQ) >> BP_CFG_SHIFT_IRQ)
151
152MALLOC_DEFINE(M_BERIPIC, "beripic", "beripic memory");
153
154static uint64_t
155bp_read_cfg(struct beripic_softc *sc, int irq)
156{
157
158	KASSERT((irq >= 0 && irq < sc->bp_nsrcs),
159	    ("IRQ of of range %d (0-%d)", irq, sc->bp_nsrcs - 1));
160	return (bus_space_read_8(sc->bp_cfg_bst, sc->bp_cfg_bsh, irq * 8));
161}
162
163static void
164bp_write_cfg(struct beripic_softc *sc, int irq, uint64_t config)
165{
166
167	KASSERT((irq >= 0 && irq < sc->bp_nsrcs),
168	    ("IRQ of of range %d (0-%d)", irq, sc->bp_nsrcs - 1));
169	bus_space_write_8(sc->bp_cfg_bst, sc->bp_cfg_bsh, irq * 8, config);
170}
171
172static void
173bp_detach_resources(device_t dev)
174{
175	struct beripic_softc *sc;
176	int i;
177
178	sc = device_get_softc(dev);
179
180	if (sc->bp_cfg_res != NULL) {
181		bus_release_resource(dev, SYS_RES_MEMORY, sc->bp_cfg_rid,
182		    sc->bp_cfg_res);
183		sc->bp_cfg_res = NULL;
184	}
185	if (sc->bp_read_res != NULL) {
186		bus_release_resource(dev, SYS_RES_MEMORY, sc->bp_read_rid,
187		    sc->bp_read_res);
188		sc->bp_read_res = NULL;
189	}
190	if (sc->bp_set_res != NULL) {
191		bus_release_resource(dev, SYS_RES_MEMORY, sc->bp_set_rid,
192		    sc->bp_set_res);
193		sc->bp_set_res = NULL;
194	}
195	if (sc->bp_clear_res != NULL) {
196		bus_release_resource(dev, SYS_RES_MEMORY, sc->bp_clear_rid,
197		    sc->bp_clear_res);
198		sc->bp_clear_res = NULL;
199	}
200	for (i = sc->bp_nirqs - 1; i >= 0; i--) {
201		bus_release_resource(dev, SYS_RES_IRQ, sc->bp_irq_rids[i],
202		    sc->bp_irqs[i]);
203	}
204	sc->bp_nirqs = 0;
205}
206
207static char *
208bp_strconfig(uint64_t config, char *configstr, size_t len)
209{
210
211	if (snprintf(configstr, len, "%s tid: %llu hardintr %llu",
212	    BP_CFG_ENABLED(config) ? "enabled" : "disabled",
213	    BP_CFG_TID(config), BP_CFG_IRQ(config)) > len - 1)
214		return (NULL);
215	return (configstr);
216}
217
218static void
219bp_config_source(device_t ic, int src, int enable, u_long tid, u_long irq)
220{
221	struct beripic_softc *sc;
222	uint64_t config;
223
224	sc = device_get_softc(ic);
225
226	config = 0;
227	config |= enable << BP_CFG_SHIFT_E;
228	config |= tid << BP_CFG_SHIFT_TID;
229	config |= irq << BP_CFG_SHIFT_IRQ;
230
231	bp_write_cfg(sc, src, config);
232}
233
234#ifdef __mips__
235static void
236bp_set_counter_name(device_t ic, device_t child, int src)
237{
238	struct beripic_softc *sc;
239	char name[MAXCOMLEN + 1];
240
241	sc = device_get_softc(ic);
242
243	if (snprintf(name, sizeof(name), "bp%dsrc%d%s%s%s",
244	    device_get_unit(ic), src, src < sc->bp_nhard ? "" : "s",
245	    child == NULL ? "" : " ",
246	    child == NULL ? " " : device_get_nameunit(child)) >= sizeof(name))
247		name[sizeof(name) - 2] = '+';
248
249	mips_intrcnt_setname(sc->bp_counters[src], name);
250}
251#endif
252
253static int
254beripic_fdt_probe(device_t dev)
255{
256
257	if (!ofw_bus_is_compatible(dev, "sri-cambridge,beri-pic"))
258		return (ENXIO);
259
260	device_set_desc(dev, "BERI Programmable Interrupt Controller");
261	return (BUS_PROBE_DEFAULT);
262}
263
264static int
265beripic_fdt_attach(device_t dev)
266{
267	char configstr[64];
268	struct beripic_softc *sc;
269	struct fdt_ic *fic;
270	pcell_t nhard, nsoft;
271	phandle_t ph;
272	int error, i, src;
273	uint64_t config;
274
275	sc = device_get_softc(dev);
276	sc->bp_dev = dev;
277
278	mtx_init(&sc->bp_cfgmtx, "beripic config lock", NULL, MTX_DEF);
279
280	/*
281	 * FDT lists CONFIG, IP_READ, IP_SET, and IP_CLEAR registers as
282	 * seperate memory regions in that order.
283	 */
284	sc->bp_cfg_rid = 0;
285	sc->bp_cfg_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
286	    &sc->bp_cfg_rid, RF_ACTIVE);
287	if (sc->bp_cfg_res == NULL) {
288		device_printf(dev, "failed to map config memory");
289		error = ENXIO;
290		goto err;
291	}
292	if (bootverbose)
293		device_printf(sc->bp_dev, "config region at mem %p-%p\n",
294		    (void *)rman_get_start(sc->bp_cfg_res),
295		    (void *)(rman_get_start(sc->bp_cfg_res) +
296		    rman_get_size(sc->bp_cfg_res)));
297
298	sc->bp_read_rid = 1;
299	sc->bp_read_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
300	    &sc->bp_read_rid, RF_ACTIVE);
301	if (sc->bp_read_res == NULL) {
302		device_printf(dev, "failed to map IP read memory");
303		error = ENXIO;
304		goto err;
305	}
306	if (bootverbose)
307		device_printf(sc->bp_dev, "IP read region at mem %p-%p\n",
308		    (void *)rman_get_start(sc->bp_read_res),
309		    (void *)(rman_get_start(sc->bp_read_res) +
310		    rman_get_size(sc->bp_read_res)));
311
312	sc->bp_set_rid = 2;
313	sc->bp_set_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
314	    &sc->bp_set_rid, RF_ACTIVE);
315	if (sc->bp_set_res == NULL) {
316		device_printf(dev, "failed to map IP read memory");
317		error = ENXIO;
318		goto err;
319	}
320	if (bootverbose)
321		device_printf(sc->bp_dev, "IP set region at mem %p-%p\n",
322		    (void *)rman_get_start(sc->bp_set_res),
323		    (void *)(rman_get_start(sc->bp_set_res) +
324		    rman_get_size(sc->bp_set_res)));
325
326	sc->bp_clear_rid = 3;
327	sc->bp_clear_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
328	    &sc->bp_clear_rid, RF_ACTIVE);
329	if (sc->bp_clear_res == NULL) {
330		device_printf(dev, "failed to map IP read memory");
331		error = ENXIO;
332		goto err;
333	}
334	if (bootverbose)
335		device_printf(sc->bp_dev, "IP clear region at mem %p-%p\n",
336		    (void *)rman_get_start(sc->bp_clear_res),
337		    (void *)(rman_get_start(sc->bp_clear_res) +
338		    rman_get_size(sc->bp_clear_res)));
339
340	i = 0;
341	for (i = 0; i < BP_MAX_HARD_IRQS; i++) {
342		sc->bp_irq_rids[i] = i;
343		sc->bp_irqs[i] = bus_alloc_resource_any(dev, SYS_RES_IRQ,
344		    &sc->bp_irq_rids[i], RF_ACTIVE | RF_SHAREABLE);
345		if (sc->bp_irqs[i] == NULL)
346			break;
347	}
348	if (i == 0) {
349		device_printf(dev, "failed to allocate any parent IRQs!");
350		error = ENXIO;
351		goto err;
352	}
353	sc->bp_nirqs = i;
354
355	ph = ofw_bus_gen_get_node(device_get_parent(dev), dev);
356
357#ifndef SMP
358	sc->bp_nthreads = 1;
359#else
360	sc->bp_nthreads = 1;
361	/* XXX: get nthreads from cpu(s) somehow */
362#endif
363
364	if (OF_getprop(ph, "hard-interrupt-sources", &nhard, sizeof(nhard))
365	    <= 0) {
366		device_printf(dev, "failed to get number of hard sources");
367		error = ENXIO;
368		goto err;
369	}
370	if (OF_getprop(ph, "soft-interrupt-sources", &nsoft, sizeof(nsoft))
371	    <= 0) {
372		device_printf(dev, "failed to get number of soft sources");
373		error = ENXIO;
374		goto err;
375	}
376
377	sc->bp_nhard = nhard;
378	sc->bp_nsoft = nsoft;
379	sc->bp_nsrcs = sc->bp_nhard + sc->bp_nsoft;
380	/* XXX: should deal with gap between hard and soft */
381	KASSERT(sc->bp_nhard <= BP_FIRST_SOFT,
382	    ("too many hard sources"));
383	KASSERT(rman_get_size(sc->bp_cfg_res) / 8 == sc->bp_nsrcs,
384	    ("config space size does not match sources"));
385	KASSERT(sc->bp_nhard % 64 == 0,
386	    ("Non-multiple of 64 intr counts not supported"));
387	KASSERT(sc->bp_nsoft % 64 == 0,
388	    ("Non-multiple of 64 intr counts not supported"));
389	if (bootverbose)
390		device_printf(dev, "%d hard and %d soft sources\n",
391		    sc->bp_nhard, sc->bp_nsoft);
392
393#ifdef __mips__
394	sc->bp_counters = malloc(sizeof(*sc->bp_counters) * sc->bp_nsrcs,
395	    M_BERIPIC, M_WAITOK|M_ZERO);
396	for (i = 0; i < sc->bp_nsrcs; i++) {
397		sc->bp_counters[i] = mips_intrcnt_create("");
398		bp_set_counter_name(dev, NULL, i);
399	}
400#endif
401
402	sc->bp_src_rman.rm_start = 0;
403	sc->bp_src_rman.rm_end = sc->bp_nsrcs - 1;
404	sc->bp_src_rman.rm_type = RMAN_ARRAY;
405	sc->bp_src_rman.rm_descr = "Interrupt source";
406	if (rman_init(&(sc->bp_src_rman)) != 0 ||
407	    rman_manage_region(&(sc->bp_src_rman), 0, sc->bp_nsrcs - 1) != 0) {
408		device_printf(dev, "Failed to set up sources rman");
409		error = ENXIO;
410		goto err;
411	}
412
413	sc->bp_cfg_bst = rman_get_bustag(sc->bp_cfg_res);
414	sc->bp_cfg_bsh = rman_get_bushandle(sc->bp_cfg_res);
415	sc->bp_read_bst = rman_get_bustag(sc->bp_read_res);
416	sc->bp_read_bsh = rman_get_bushandle(sc->bp_read_res);
417	sc->bp_set_bst = rman_get_bustag(sc->bp_set_res);
418	sc->bp_set_bsh = rman_get_bushandle(sc->bp_set_res);
419	sc->bp_clear_bst = rman_get_bustag(sc->bp_clear_res);
420	sc->bp_clear_bsh = rman_get_bushandle(sc->bp_clear_res);
421
422	for (src = 0; src < sc->bp_nsrcs; src++) {
423		config = bp_read_cfg(sc, src);
424		if (config == 0)
425			continue;
426
427		if (bootverbose) {
428			device_printf(dev, "initial config: src %d: %s\n", src,
429			    bp_strconfig(config, configstr, sizeof(configstr)));
430			if (config & BP_CFG_RESERVED)
431				device_printf(dev,
432				    "reserved bits not 0: 0x%016jx\n",
433				    (uintmax_t) config);
434		}
435
436		bp_config_source(dev, src, 0, 0, 0);
437	}
438
439	fic = malloc(sizeof(*fic), M_BERIPIC, M_WAITOK|M_ZERO);
440	fic->iph = ph;
441	fic->dev = dev;
442	SLIST_INSERT_HEAD(&fdt_ic_list_head, fic, fdt_ics);
443
444	return (0);
445err:
446	bp_detach_resources(dev);
447
448	return (error);
449}
450
451static struct resource *
452beripic_alloc_intr(device_t ic, device_t child, int *rid, u_long irq,
453    u_int flags)
454{
455	struct beripic_softc *sc;
456	struct resource *rv;
457
458	sc = device_get_softc(ic);
459
460	rv = rman_reserve_resource(&(sc->bp_src_rman), irq, irq, 1, flags,
461	    child);
462	if (rv == NULL)
463		 printf("%s: could not reserve source interrupt for %s\n",
464		     __func__, device_get_nameunit(child));
465	rman_set_rid(rv, *rid);
466
467	if ((flags & RF_ACTIVE) &&
468	    beripic_activate_intr(ic, rv) != 0) {
469		printf("%s: could not activate interrupt\n", __func__);
470		rman_release_resource(rv);
471		return (NULL);
472	}
473
474	return (rv);
475}
476
477static int
478beripic_release_intr(device_t ic, struct resource *r)
479{
480
481	return (rman_release_resource(r));
482}
483
484static int
485beripic_activate_intr(device_t ic, struct resource *r)
486{
487
488	return (rman_activate_resource(r));
489}
490
491static int
492beripic_deactivate_intr(device_t ic, struct resource *r)
493{
494
495	return (rman_deactivate_resource(r));
496}
497
498static int
499beripic_config_intr(device_t dev, int irq, enum intr_trigger trig,
500   enum intr_polarity pol)
501{
502
503	if (trig != INTR_TRIGGER_CONFORM || pol != INTR_POLARITY_CONFORM)
504		return (EINVAL);
505
506	return (0);
507}
508
509static int
510beripic_setup_intr(device_t ic, device_t child, struct resource *irq,
511    int flags, driver_filter_t *filter, driver_intr_t *intr, void *arg,
512    void **cookiep)
513{
514	struct beripic_softc *sc;
515	struct beripic_intr_arg *bpia;
516	struct beripic_cookie *bpc;
517	int error;
518	u_long hirq, src, tid;
519
520	sc = device_get_softc(ic);
521
522	src = rman_get_start(irq);
523
524	KASSERT(src < sc->bp_nsrcs, ("source (%lu) out of range 0-%d",
525	     src, sc->bp_nsrcs - 1));
526
527	bpia = malloc(sizeof(*bpia), M_BERIPIC, M_WAITOK|M_ZERO);
528	bpia->filter = filter;
529	bpia->intr = intr;
530	bpia->arg = arg;
531	bpia->irq = irq;
532#ifdef __mips__
533	bpia->counter = sc->bp_counters[src];
534	bp_set_counter_name(ic, child, src);
535#endif
536
537	bpc = malloc(sizeof(*bpc), M_BERIPIC, M_WAITOK|M_ZERO);
538	bpc->bpia = bpia;
539
540	mtx_lock(&(sc->bp_cfgmtx));
541	bpc->hirq = sc->bp_irqs[sc->bp_next_irq];
542	hirq = rman_get_start(bpc->hirq);
543	tid = sc->bp_next_tid;
544
545	error = BUS_SETUP_INTR(device_get_parent(ic), ic, bpc->hirq, flags,
546	    beripic_filter, intr == NULL ? NULL : beripic_intr, bpia,
547	    &(bpc->cookie));
548	if (error != 0)
549		goto err;
550
551#ifdef NOTYET
552#ifdef SMP
553	/* XXX: bind ithread to cpu */
554	sc->bp_next_tid++;
555	if (sc->bp_next_tid >= sc->bp_nthreads)
556		sc->bp_next_tid = 0;
557#endif
558#endif
559	if (sc->bp_next_tid == 0) {
560		sc->bp_next_irq++;
561		if (sc->bp_next_irq >= sc->bp_nirqs)
562			sc->bp_next_irq = 0;
563	}
564	mtx_unlock(&(sc->bp_cfgmtx));
565
566	*cookiep = bpc;
567
568	bp_config_source(ic, rman_get_start(irq), 1, tid, hirq);
569
570	return (0);
571err:
572	free(bpc, M_BERIPIC);
573	free(bpia, M_BERIPIC);
574
575	return (error);
576}
577
578static int
579beripic_teardown_intr(device_t dev, device_t child, struct resource *irq,
580    void *cookie)
581{
582	struct beripic_cookie *bpc;
583	int error;
584
585	bpc = cookie;
586
587	bp_config_source(dev, rman_get_start(irq), 0, 0, 0);
588
589	free(bpc->bpia, M_BERIPIC);
590
591	error = BUS_TEARDOWN_INTR(device_get_parent(dev), dev, bpc->hirq,
592	    bpc->cookie);
593
594	free(bpc, M_BERIPIC);
595
596	return (error);
597}
598
599static int
600beripic_filter(void *arg)
601{
602	struct beripic_intr_arg *bpic;
603
604	bpic = arg;
605
606#ifdef __mips__
607	mips_intrcnt_inc(bpic->counter);
608#endif
609
610	/* XXX: Add a check that our source is high */
611
612	if (bpic->filter == NULL)
613		return (FILTER_SCHEDULE_THREAD);
614
615	return (bpic->filter(bpic->arg));
616}
617
618static void
619beripic_intr(void *arg)
620{
621	struct beripic_intr_arg *bpic;
622
623	bpic = arg;
624
625	KASSERT(bpic->intr != NULL,
626	    ("%s installed, but no child intr", __func__));
627
628	bpic->intr(bpic->arg);
629}
630
631#ifdef SMP
632static void
633beripic_setup_ipi(device_t ic, u_int tid, u_int ipi_irq)
634{
635
636	bp_config_source(ic, BP_FIRST_SOFT + tid, 1, tid, ipi_irq);
637}
638
639static void
640beripic_send_ipi(device_t ic, u_int tid)
641{
642	struct beripic_softc *sc;
643	uint64_t bit;
644
645	sc = device_get_softc(ic);
646
647	KASSERT(tid < sc->bp_nsoft, ("tid (%d) too large\n", tid));
648
649	bit = 1ULL << (tid % 64);
650	bus_space_write_8(sc->bp_set_bst, sc->bp_set_bsh,
651	    (BP_FIRST_SOFT / 8) + (tid / 64), bit);
652}
653
654static void
655beripic_clear_ipi(device_t ic, u_int tid)
656{
657	struct beripic_softc *sc;
658	uint64_t bit;
659
660	sc = device_get_softc(ic);
661
662	KASSERT(tid < sc->bp_nsoft, ("tid (%d) to large\n", tid));
663
664	bit = 1ULL << (tid % 64);
665	bus_space_write_8(sc->bp_clear_bst, sc->bp_clear_bsh,
666	    (BP_FIRST_SOFT / 8) + (tid / 64), bit);
667}
668#endif
669
670devclass_t	beripic_devclass;
671
672static device_method_t beripic_fdt_methods[] = {
673	/* Device interface */
674	DEVMETHOD(device_probe,		beripic_fdt_probe),
675	DEVMETHOD(device_attach,	beripic_fdt_attach),
676
677	DEVMETHOD(fdt_ic_activate_intr,	beripic_activate_intr),
678	DEVMETHOD(fdt_ic_alloc_intr,	beripic_alloc_intr),
679	DEVMETHOD(fdt_ic_config_intr,	beripic_config_intr),
680	DEVMETHOD(fdt_ic_deactivate_intr, beripic_deactivate_intr),
681	DEVMETHOD(fdt_ic_release_intr,	beripic_release_intr),
682	DEVMETHOD(fdt_ic_setup_intr,	beripic_setup_intr),
683	DEVMETHOD(fdt_ic_teardown_intr,	beripic_teardown_intr),
684
685#ifdef SMP
686	DEVMETHOD(fdt_ic_setup_ipi,	beripic_setup_ipi),
687	DEVMETHOD(fdt_ic_clear_ipi,	beripic_clear_ipi),
688	DEVMETHOD(fdt_ic_send_ipi,	beripic_send_ipi),
689#endif
690
691	{ 0, 0 },
692};
693
694static driver_t beripic_fdt_driver = {
695	"beripic",
696	beripic_fdt_methods,
697	sizeof(struct beripic_softc)
698};
699
700DRIVER_MODULE(beripic, simplebus, beripic_fdt_driver, beripic_devclass, 0, 0);
701