Annotation of sys/arch/arm/xscale/i80321_intr.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: i80321_intr.c,v 1.11 2007/05/19 15:47:16 miod Exp $ */
2:
3: /*
4: * Copyright (c) 2006 Dale Rahn <drahn@openbsd.org>
5: *
6: * Permission to use, copy, modify, and distribute this software for any
7: * purpose with or without fee is hereby granted, provided that the above
8: * copyright notice and this permission notice appear in all copies.
9: *
10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17: */
18:
19: #include <sys/param.h>
20: #include <sys/systm.h>
21: #include <sys/malloc.h>
22: #include <sys/evcount.h>
23:
24: #include <uvm/uvm.h> /* uvmexp */
25:
26: #include <machine/intr.h>
27:
28: #include <arm/cpufunc.h>
29: #include <arm/xscale/i80321reg.h>
30: #include <arm/xscale/i80321var.h>
31:
32: /*
33: * autoconf glue
34: */
35: int i80321intc_match(struct device *, void *, void *);
36: void i80321intc_attach(struct device *, struct device *, void *);
37:
38: /* internal functions */
39: static void i80321intc_write_intctl(uint32_t mask);
40: void i80321intc_write_steer(uint32_t mask);
41: uint32_t i80321intc_read_intsrc(void);
42: void i80321intc_calc_mask(void);
43: void i80321intc_init(void);
44: void i80321intc_intr_init(void);
45: static void i80321intc_setipl(int new);
46: void i80321intc_do_pending(void);
47:
48: uint32_t i80321intc_imask[NIPL];
49: uint32_t i80321intc_smask[NIPL];
50:
51: #define SI_TO_IRQBIT(x) (1 << (x))
52:
53: __volatile int current_ipl_level;
54: __volatile int softint_pending;
55:
56: struct cfattach i80321intc_ca = {
57: sizeof(struct device), i80321intc_match, i80321intc_attach
58: };
59:
60: struct cfdriver i80321intc_cd = {
61: NULL, "i80321intc", DV_DULL
62: };
63:
64: int i80321intc_attached = 0;
65:
66: int
67: i80321intc_match(struct device *parent, void *v, void *aux)
68: {
69: if (i80321intc_attached == 0)
70: return 1;
71:
72: i80321intc_attached = 1;
73: return 0;
74: }
75:
76: void
77: i80321intc_attach(struct device *parent, struct device *self, void *args)
78: {
79: i80321intc_init();
80: }
81:
82: static inline void
83: i80321intc_write_intctl(uint32_t mask)
84: {
85: __asm__ volatile ("mcr p6, 0, %0, c0, c0, 0" : : "r" (mask));
86: }
87:
88: void
89: i80321intc_write_steer(uint32_t mask)
90: {
91: __asm__ volatile ("mcr p6, 0, %0, c4, c0, 0" : : "r" (mask));
92: }
93:
94: uint32_t
95: i80321intc_read_intsrc(void)
96: {
97: uint32_t mask;
98: __asm__ volatile ("mrc p6, 0, %0, c8, c0, 0" : "=r" (mask));
99: return mask;
100: }
101:
102: static inline void
103: i80321intc_setipl(int new)
104: {
105: int psw;
106:
107: psw = disable_interrupts(I32_bit);
108: current_ipl_level = new;
109: i80321intc_write_intctl(i80321intc_imask[new]);
110: restore_interrupts(psw);
111: }
112:
113:
114: struct intrq i80321_handler[NIRQ];
115:
116: /*
117: * Recompute the irq mask bits.
118: * Must be called with interrupts disabled.
119: */
120: void
121: i80321intc_calc_mask(void)
122: {
123: int irq;
124: struct intrhand *ih;
125: int i;
126:
127: for (irq = 0; irq < NIRQ; irq++) {
128: int i;
129: int max = IPL_NONE;
130: int min = IPL_HIGH;
131: TAILQ_FOREACH(ih, &i80321_handler[irq].iq_list, ih_list) {
132: if (ih->ih_ipl > max)
133: max = ih->ih_ipl;
134:
135: if (ih->ih_ipl < min)
136: min = ih->ih_ipl;
137: }
138:
139: i80321_handler[irq].iq_irq = max;
140:
141: if (max == IPL_NONE)
142: min = IPL_NONE; /* interrupt not enabled */
143: #if 0
144: printf("irq %d: min %x max %x\n", irq, min, max);
145: #endif
146:
147: /* Enable interrupts at lower levels */
148: for (i = 0; i < min; i++)
149: i80321intc_imask[i] |= (1 << irq);
150: /* Disable interrupts at upper levels */
151: for (;i <= IPL_HIGH; i++)
152: i80321intc_imask[i] &= ~(1 << irq);
153: }
154: /* initialize soft interrupt mask */
155: for (i = IPL_NONE; i <= IPL_HIGH; i++) {
156: i80321intc_smask[i] = 0;
157: if (i < IPL_SOFT)
158: i80321intc_smask[i] |= SI_TO_IRQBIT(SI_SOFT);
159: if (i < IPL_SOFTCLOCK)
160: i80321intc_smask[i] |= SI_TO_IRQBIT(SI_SOFTCLOCK);
161: if (i < IPL_SOFTNET)
162: i80321intc_smask[i] |= SI_TO_IRQBIT(SI_SOFTNET);
163: if (i < IPL_SOFTSERIAL)
164: i80321intc_smask[i] |= SI_TO_IRQBIT(SI_SOFTSERIAL);
165: #if 0
166: printf("mask[%d]: %x %x\n", i, i80321intc_smask[i],
167: i80321intc_imask[i]);
168: #endif
169: }
170:
171: i80321intc_setipl(current_ipl_level);
172: }
173:
174: void
175: i80321intc_do_pending(void)
176: {
177: static int processing = 0;
178: int oldirqstate, spl_save;
179:
180: oldirqstate = disable_interrupts(I32_bit);
181:
182: spl_save = current_ipl_level;
183:
184: if (processing == 1) {
185: restore_interrupts(oldirqstate);
186: return;
187: }
188:
189: #define DO_SOFTINT(si, ipl) \
190: if ((softint_pending & i80321intc_smask[current_ipl_level]) & \
191: SI_TO_IRQBIT(si)) { \
192: softint_pending &= ~SI_TO_IRQBIT(si); \
193: if (current_ipl_level < ipl) \
194: i80321intc_setipl(ipl); \
195: restore_interrupts(oldirqstate); \
196: softintr_dispatch(si); \
197: oldirqstate = disable_interrupts(I32_bit); \
198: i80321intc_setipl(spl_save); \
199: }
200:
201: do {
202: DO_SOFTINT(SI_SOFTSERIAL, IPL_SOFTSERIAL);
203: DO_SOFTINT(SI_SOFTNET, IPL_SOFTNET);
204: DO_SOFTINT(SI_SOFTCLOCK, IPL_SOFTCLOCK);
205: DO_SOFTINT(SI_SOFT, IPL_SOFT);
206: } while (softint_pending & i80321intc_smask[current_ipl_level]);
207:
208:
209: processing = 0;
210: restore_interrupts(oldirqstate);
211: }
212:
213: void
214: splx(int new)
215: {
216: i80321intc_setipl(new);
217:
218: if (softint_pending & i80321intc_smask[current_ipl_level])
219: i80321intc_do_pending();
220: }
221:
222: int
223: _spllower(int new)
224: {
225: int old = current_ipl_level;
226: splx(new);
227: return (old);
228: }
229:
230: int
231: _splraise(int new)
232: {
233: int old;
234: old = current_ipl_level;
235:
236: /*
237: * setipl must always be called because there is a race window
238: * where the variable is updated before the mask is set
239: * an interrupt occurs in that window without the mask always
240: * being set, the hardware might not get updated on the next
241: * splraise completely messing up spl protection.
242: */
243: if (old > new)
244: new = old;
245:
246: i80321intc_setipl(new);
247:
248: return (old);
249: }
250:
251: void
252: _setsoftintr(int si)
253: {
254: int oldirqstate;
255:
256: oldirqstate = disable_interrupts(I32_bit);
257: softint_pending |= SI_TO_IRQBIT(si);
258: restore_interrupts(oldirqstate);
259:
260: /* Process unmasked pending soft interrupts. */
261: if (softint_pending & i80321intc_smask[current_ipl_level])
262: i80321intc_do_pending();
263: }
264:
265: /*
266: * i80321_icu_init:
267: *
268: * Initialize the i80321 ICU. Called early in bootstrap
269: * to make sure the ICU is in a pristine state.
270: */
271: void
272: i80321intc_intr_init(void)
273: {
274: i80321intc_write_intctl(0);
275:
276: i80321intc_write_steer(0);
277: }
278:
279: /*
280: * i80321_intr_init:
281: *
282: * Initialize the rest of the interrupt subsystem, making it
283: * ready to handle interrupts from devices.
284: */
285: void
286: i80321intc_init(void)
287: {
288: struct intrq *iq;
289: int i;
290:
291: for (i = 0; i < NIRQ; i++) {
292: iq = &i80321_handler[i];
293: TAILQ_INIT(&iq->iq_list);
294: }
295:
296: i80321intc_calc_mask();
297:
298: /* Enable IRQs (don't yet use FIQs). */
299: enable_interrupts(I32_bit);
300: }
301:
302: void *
303: i80321_intr_establish(int irq, int ipl, int (*func)(void *), void *arg,
304: char *name)
305: {
306: struct intrq *iq;
307: struct intrhand *ih;
308: uint32_t oldirqstate;
309:
310: if (irq < 0 || irq > NIRQ)
311: panic("i80321_intr_establish: IRQ %d out of range", irq);
312:
313: ih = malloc(sizeof(*ih), M_DEVBUF, M_NOWAIT);
314: if (ih == NULL)
315: return (NULL);
316:
317: ih->ih_func = func;
318: ih->ih_arg = arg;
319: ih->ih_ipl = ipl;
320: ih->ih_name = name;
321: ih->ih_irq = irq;
322:
323: iq = &i80321_handler[irq];
324:
325: if (name != NULL)
326: evcount_attach(&ih->ih_count, name, (void *)&ih->ih_irq,
327: &evcount_intr);
328:
329: /* All IOP321 interrupts are level-triggered. */
330: iq->iq_ist = IST_LEVEL;
331:
332: oldirqstate = disable_interrupts(I32_bit);
333:
334: TAILQ_INSERT_TAIL(&iq->iq_list, ih, ih_list);
335:
336: i80321intc_calc_mask();
337:
338: restore_interrupts(oldirqstate);
339:
340: return (ih);
341: }
342:
343:
344: void
345: i80321_intr_disestablish(void *cookie)
346: {
347: struct intrhand *ih = cookie;
348: struct intrq *iq = &i80321_handler[ih->ih_irq];
349: int oldirqstate;
350:
351: oldirqstate = disable_interrupts(I32_bit);
352:
353: TAILQ_REMOVE(&iq->iq_list, ih, ih_list);
354: if (ih->ih_name != NULL)
355: evcount_detach(&ih->ih_count);
356:
357: i80321intc_calc_mask();
358:
359: restore_interrupts(oldirqstate);
360: }
361:
362: void
363: i80321_irq_handler(void *arg)
364: {
365: struct clockframe *frame = arg;
366: uint32_t hwpend;
367: int irq;
368: int saved_spl_level;
369: struct intrhand *ih;
370:
371: saved_spl_level = current_ipl_level;
372:
373: /* get pending IRQs */
374: hwpend = i80321intc_read_intsrc();
375:
376: while ((irq = find_first_bit(hwpend)) >= 0) {
377: /* XXX: Should we handle IRQs in priority order? */
378:
379: /* raise spl to stop interrupts of lower priorities */
380: if (saved_spl_level < i80321_handler[irq].iq_irq)
381: i80321intc_setipl(i80321_handler[irq].iq_irq);
382:
383: /* Enable interrupt */
384: enable_interrupts(I32_bit);
385: TAILQ_FOREACH(ih, &i80321_handler[irq].iq_list, ih_list) {
386: if ((ih->ih_func)( ih->ih_arg == 0
387: ? frame : ih->ih_arg))
388: ih->ih_count.ec_count++;
389: }
390: /* Disable interrupt */
391: disable_interrupts(I32_bit);
392: hwpend &= ~(1<<irq);
393: }
394: uvmexp.intrs++;
395:
396: /* restore spl to that was when this interrupt happen */
397: i80321intc_setipl(saved_spl_level);
398:
399: if(softint_pending & i80321intc_smask[current_ipl_level])
400: i80321intc_do_pending();
401: }
402:
403: #ifdef DIAGNOSTIC
404: void
405: i80321_splassert_check(int wantipl, const char *func)
406: {
407: int oldipl = current_ipl_level;
408:
409: if (oldipl < wantipl) {
410: splassert_fail(wantipl, oldipl, func);
411: /*
412: * If the splassert_ctl is set to not panic, raise the ipl
413: * in a feeble attempt to reduce damage.
414: */
415: i80321intc_setipl(wantipl);
416: }
417: }
418: #endif
CVSweb