1 /* $NetBSD: shared_intr.c,v 1.19 2008/03/10 14:01:35 ad Exp $ */
4 * Copyright (c) 1996 Carnegie-Mellon University.
7 * Authors: Chris G. Demetriou
9 * Permission to use, copy, modify and distribute this software and
10 * its documentation is hereby granted, provided that both the copyright
11 * notice and this permission notice appear in all copies of the
12 * software, derivative works or modified versions, and any portions
13 * thereof, and that both notices appear in supporting documentation.
15 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
16 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
17 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
19 * Carnegie Mellon requests users of this software to return to
21 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
22 * School of Computer Science
23 * Carnegie Mellon University
24 * Pittsburgh PA 15213-3890
26 * any improvements or extensions that they make and grant Carnegie the
27 * rights to redistribute these changes.
31 * Common shared-interrupt-line functionality.
34 #include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
36 __KERNEL_RCSID(0, "$NetBSD: shared_intr.c,v 1.19 2008/03/10 14:01:35 ad Exp $");
38 #include <sys/param.h>
39 #include <sys/kernel.h>
40 #include <sys/systm.h>
41 #include <sys/malloc.h>
42 #include <sys/syslog.h>
43 #include <sys/queue.h>
44 #include <sys/atomic.h>
47 static const char *intr_typename(int);
50 intr_typename(int type
)
61 return ("edge-triggered");
63 return ("level-triggered");
65 panic("intr_typename: unknown type %d", type
);
68 struct alpha_shared_intr
*
69 alpha_shared_intr_alloc(unsigned int n
, unsigned int namesize
)
71 struct alpha_shared_intr
*intr
;
74 intr
= malloc(n
* sizeof (struct alpha_shared_intr
), M_DEVBUF
,
75 cold
? M_NOWAIT
: M_WAITOK
);
77 panic("alpha_shared_intr_alloc: couldn't malloc intr");
79 for (i
= 0; i
< n
; i
++) {
80 TAILQ_INIT(&intr
[i
].intr_q
);
81 intr
[i
].intr_sharetype
= IST_NONE
;
82 intr
[i
].intr_dfltsharetype
= IST_NONE
;
83 intr
[i
].intr_nstrays
= 0;
84 intr
[i
].intr_maxstrays
= 5;
85 intr
[i
].intr_private
= NULL
;
87 intr
[i
].intr_string
= malloc(namesize
, M_DEVBUF
,
88 cold
? M_NOWAIT
: M_WAITOK
);
89 if (intr
[i
].intr_string
== NULL
)
90 panic("alpha_shared_intr_alloc: couldn't "
91 "malloc intr string");
93 intr
[i
].intr_string
= NULL
;
100 alpha_shared_intr_dispatch(struct alpha_shared_intr
*intr
, unsigned int num
)
102 struct alpha_shared_intrhand
*ih
;
105 atomic_add_long(&intr
[num
].intr_evcnt
.ev_count
, 1);
107 ih
= intr
[num
].intr_q
.tqh_first
;
112 * The handler returns one of three values:
113 * 0: This interrupt wasn't for me.
114 * 1: This interrupt was for me.
115 * -1: This interrupt might have been for me, but I can't say
118 rv
= (*ih
->ih_fn
)(ih
->ih_arg
);
120 handled
= handled
|| (rv
!= 0);
121 ih
= ih
->ih_q
.tqe_next
;
128 alpha_shared_intr_establish(struct alpha_shared_intr
*intr
, unsigned int num
,
129 int type
, int level
, int (*fn
)(void *), void *arg
, const char *basename
)
131 struct alpha_shared_intrhand
*ih
;
133 if (intr
[num
].intr_sharetype
== IST_UNUSABLE
) {
134 printf("alpha_shared_intr_establish: %s %d: unusable\n",
139 /* no point in sleeping unless someone can free memory. */
140 ih
= malloc(sizeof *ih
, M_DEVBUF
, cold
? M_NOWAIT
: M_WAITOK
);
142 panic("alpha_shared_intr_establish: can't malloc intrhand");
145 if (type
== IST_NONE
)
146 panic("alpha_shared_intr_establish: bogus type");
149 switch (intr
[num
].intr_sharetype
) {
152 if (type
== intr
[num
].intr_sharetype
)
155 if (type
!= IST_NONE
) {
156 if (intr
[num
].intr_q
.tqh_first
== NULL
) {
157 printf("alpha_shared_intr_establish: %s %d: warning: using %s on %s\n",
158 basename
, num
, intr_typename(type
),
159 intr_typename(intr
[num
].intr_sharetype
));
160 type
= intr
[num
].intr_sharetype
;
162 panic("alpha_shared_intr_establish: %s %d: can't share %s with %s",
163 basename
, num
, intr_typename(type
),
164 intr_typename(intr
[num
].intr_sharetype
));
170 /* not currently used; safe */
174 ih
->ih_intrhead
= intr
;
177 ih
->ih_level
= level
;
180 intr
[num
].intr_sharetype
= type
;
181 TAILQ_INSERT_TAIL(&intr
[num
].intr_q
, ih
, ih_q
);
187 alpha_shared_intr_disestablish(struct alpha_shared_intr
*intr
, void *cookie
,
188 const char *basename
)
190 struct alpha_shared_intrhand
*ih
= cookie
;
191 unsigned int num
= ih
->ih_num
;
194 * Just remove it from the list and free the entry. We let
195 * the caller deal with resetting the share type, if appropriate.
197 TAILQ_REMOVE(&intr
[num
].intr_q
, ih
, ih_q
);
201 alpha_shared_intr_get_sharetype(struct alpha_shared_intr
*intr
,
205 return (intr
[num
].intr_sharetype
);
209 alpha_shared_intr_isactive(struct alpha_shared_intr
*intr
, unsigned int num
)
212 return (intr
[num
].intr_q
.tqh_first
!= NULL
);
216 alpha_shared_intr_firstactive(struct alpha_shared_intr
*intr
, unsigned int num
)
219 return (intr
[num
].intr_q
.tqh_first
!= NULL
&&
220 intr
[num
].intr_q
.tqh_first
->ih_q
.tqe_next
== NULL
);
224 alpha_shared_intr_set_dfltsharetype(struct alpha_shared_intr
*intr
,
225 unsigned int num
, int newdfltsharetype
)
229 if (alpha_shared_intr_isactive(intr
, num
))
230 panic("alpha_shared_intr_set_dfltsharetype on active intr");
233 intr
[num
].intr_dfltsharetype
= newdfltsharetype
;
234 intr
[num
].intr_sharetype
= intr
[num
].intr_dfltsharetype
;
238 alpha_shared_intr_set_maxstrays(struct alpha_shared_intr
*intr
,
239 unsigned int num
, int newmaxstrays
)
242 intr
[num
].intr_maxstrays
= newmaxstrays
;
243 intr
[num
].intr_nstrays
= 0;
248 alpha_shared_intr_reset_strays(struct alpha_shared_intr
*intr
,
253 * Don't bother blocking interrupts; this doesn't have to be
254 * precise, but it does need to be fast.
256 intr
[num
].intr_nstrays
= 0;
260 alpha_shared_intr_stray(struct alpha_shared_intr
*intr
, unsigned int num
,
261 const char *basename
)
264 intr
[num
].intr_nstrays
++;
266 if (intr
[num
].intr_maxstrays
== 0)
269 if (intr
[num
].intr_nstrays
<= intr
[num
].intr_maxstrays
)
270 log(LOG_ERR
, "stray %s %d%s\n", basename
, num
,
271 intr
[num
].intr_nstrays
>= intr
[num
].intr_maxstrays
?
272 "; stopped logging" : "");
276 alpha_shared_intr_set_private(struct alpha_shared_intr
*intr
,
277 unsigned int num
, void *v
)
280 intr
[num
].intr_private
= v
;
284 alpha_shared_intr_get_private(struct alpha_shared_intr
*intr
,
288 return (intr
[num
].intr_private
);
292 alpha_shared_intr_evcnt(struct alpha_shared_intr
*intr
,
296 return (&intr
[num
].intr_evcnt
);
300 alpha_shared_intr_string(struct alpha_shared_intr
*intr
,
304 return (intr
[num
].intr_string
);