xref: /netbsd/sys/arch/newsmips/dev/hb.c (revision 6550d01e)
1 /*	$NetBSD: hb.c,v 1.18 2008/04/09 15:40:30 tsutsui Exp $	*/
2 
3 #include <sys/cdefs.h>
4 __KERNEL_RCSID(0, "$NetBSD: hb.c,v 1.18 2008/04/09 15:40:30 tsutsui Exp $");
5 
6 #include <sys/param.h>
7 #include <sys/systm.h>
8 #include <sys/device.h>
9 #include <sys/malloc.h>
10 
11 #include <machine/autoconf.h>
12 #include <machine/intr.h>
13 
14 #include <newsmips/dev/hbvar.h>
15 
16 #include "ioconf.h"
17 
18 static int	hb_match(device_t, cfdata_t, void *);
19 static void	hb_attach(device_t, device_t, void *);
20 static int	hb_search(device_t, cfdata_t, const int *, void *);
21 static int	hb_print(void *, const char *);
22 
23 CFATTACH_DECL_NEW(hb, 0,
24     hb_match, hb_attach, NULL, NULL);
25 
26 #define NLEVEL	4
27 static struct newsmips_intr hbintr_tab[NLEVEL];
28 
29 static int
30 hb_match(device_t parent, cfdata_t cf, void *aux)
31 {
32 	struct confargs *ca = aux;
33 
34 	if (strcmp(ca->ca_name, hb_cd.cd_name) != 0)
35 		return 0;
36 
37 	return 1;
38 }
39 
40 static void
41 hb_attach(device_t parent, device_t self, void *aux)
42 {
43 	struct hb_attach_args ha;
44 	struct newsmips_intr *ip;
45 	int i;
46 
47 	aprint_normal("\n");
48 
49 	memset(&ha, 0, sizeof(ha));
50 	for (i = 0; i < NLEVEL; i++) {
51 		ip = &hbintr_tab[i];
52 		LIST_INIT(&ip->intr_q);
53 	}
54 
55 	config_search_ia(hb_search, self, "hb", &ha);
56 }
57 
58 static int
59 hb_search(device_t parent, cfdata_t cf, const int *ldesc, void *aux)
60 {
61 	struct hb_attach_args *ha = aux;
62 
63 	ha->ha_name = cf->cf_name;
64 	ha->ha_addr = cf->cf_addr;
65 	ha->ha_level = cf->cf_level;
66 
67 	if (config_match(parent, cf, ha) > 0)
68 		config_attach(parent, cf, ha, hb_print);
69 
70 	return 0;
71 }
72 
73 /*
74  * Print out the confargs.  The (parent) name is non-NULL
75  * when there was no match found by config_found().
76  */
77 static int
78 hb_print(void *args, const char *name)
79 {
80 	struct hb_attach_args *ha = args;
81 
82 	/* Be quiet about empty HB locations. */
83 	if (name)
84 		return QUIET;
85 
86 	if (ha->ha_addr != -1)
87 		aprint_normal(" addr 0x%x", ha->ha_addr);
88 
89 	return UNCONF;
90 }
91 
92 void *
93 hb_intr_establish(int level, int mask, int priority, int (*func)(void *),
94     void *arg)
95 {
96 	struct newsmips_intr *ip;
97 	struct newsmips_intrhand *ih, *curih;
98 
99 	ip = &hbintr_tab[level];
100 
101 	ih = malloc(sizeof(*ih), M_DEVBUF, M_NOWAIT);
102 	if (ih == NULL)
103 		panic("%s: malloc failed", __func__);
104 
105 	ih->ih_func = func;
106 	ih->ih_arg = arg;
107 	ih->ih_level = level;
108 	ih->ih_mask = mask;
109 	ih->ih_priority = priority;
110 
111 	if (LIST_EMPTY(&ip->intr_q)) {
112 		LIST_INSERT_HEAD(&ip->intr_q, ih, ih_q);
113 		goto done;
114 	}
115 
116 	for (curih = LIST_FIRST(&ip->intr_q);
117 	    LIST_NEXT(curih, ih_q) != NULL;
118 	    curih = LIST_NEXT(curih, ih_q)) {
119 		if (ih->ih_priority > curih->ih_priority) {
120 			LIST_INSERT_BEFORE(curih, ih, ih_q);
121 			goto done;
122 		}
123 	}
124 
125 	LIST_INSERT_AFTER(curih, ih, ih_q);
126 
127  done:
128 	return ih;
129 }
130 
131 void
132 hb_intr_dispatch(int level, int stat)
133 {
134 	struct newsmips_intr *ip;
135 	struct newsmips_intrhand *ih;
136 
137 	ip = &hbintr_tab[level];
138 
139 	LIST_FOREACH(ih, &ip->intr_q, ih_q) {
140 		if (ih->ih_mask & stat)
141 			(*ih->ih_func)(ih->ih_arg);
142 	}
143 }
144