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