intr.c revision 139735
1129198Scognet/*	$NetBSD: intr.c,v 1.12 2003/07/15 00:24:41 lukem Exp $	*/
2129198Scognet
3139735Simp/*-
4129198Scognet * Copyright (c) 2004 Olivier Houchard.
5129198Scognet * Copyright (c) 1994-1998 Mark Brinicombe.
6129198Scognet * All rights reserved.
7129198Scognet *
8129198Scognet * Redistribution and use in source and binary forms, with or without
9129198Scognet * modification, are permitted provided that the following conditions
10129198Scognet * are met:
11129198Scognet * 1. Redistributions of source code must retain the above copyright
12129198Scognet *    notice, this list of conditions and the following disclaimer.
13129198Scognet * 2. Redistributions in binary form must reproduce the above copyright
14129198Scognet *    notice, this list of conditions and the following disclaimer in the
15129198Scognet *    documentation and/or other materials provided with the distribution.
16129198Scognet * 3. All advertising materials mentioning features or use of this software
17129198Scognet *    must display the following acknowledgement:
18129198Scognet *	This product includes software developed by Mark Brinicombe
19129198Scognet *	for the NetBSD Project.
20129198Scognet * 4. The name of the company nor the name of the author may be used to
21129198Scognet *    endorse or promote products derived from this software without specific
22129198Scognet *    prior written permission.
23129198Scognet *
24129198Scognet * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
25129198Scognet * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26129198Scognet * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27129198Scognet * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
28129198Scognet * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29129198Scognet * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30129198Scognet * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31129198Scognet * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32129198Scognet * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33129198Scognet * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34129198Scognet * SUCH DAMAGE.
35129198Scognet *
36129198Scognet * Soft interrupt and other generic interrupt functions.
37129198Scognet */
38129198Scognet
39129198Scognet#include <sys/cdefs.h>
40129198Scognet__FBSDID("$FreeBSD: head/sys/arm/arm/intr.c 139735 2005-01-05 21:58:49Z imp $");
41129198Scognet#include <sys/param.h>
42129198Scognet#include <sys/systm.h>
43129198Scognet#include <sys/syslog.h>
44129198Scognet#include <sys/malloc.h>
45135650Scognet#include <sys/proc.h>
46129198Scognet#include <sys/bus.h>
47129198Scognet#include <sys/interrupt.h>
48129198Scognet#include <sys/conf.h>
49129198Scognet#include <machine/atomic.h>
50129198Scognet#include <machine/intr.h>
51129198Scognet#include <machine/cpu.h>
52129198Scognet
53137629Scognetstatic struct ithd *ithreads[NIRQ];
54137629Scognetstatic int intrcnt_tab[NIRQ];
55137629Scognetstatic int intrcnt_index = 0;
56137629Scognetstatic int last_printed = 0;
57135650Scognetstruct arm_intr {
58135650Scognet	driver_intr_t *handler;
59135650Scognet	void *arg;
60135650Scognet	void *cookiep;
61135650Scognet	int irq;
62135650Scognet};
63129198Scognet
64135650Scognetstatic void
65135650Scognetarm_intr_handler(void *arg)
66135650Scognet{
67135650Scognet	struct arm_intr *intr = (struct arm_intr *)arg;
68129198Scognet
69135650Scognet	intr->handler(intr->arg);
70135650Scognet	arm_unmask_irqs(1 << intr->irq);
71129198Scognet}
72129198Scognet
73135650Scognetvoid	arm_handler_execute(void *, int);
74135650Scognet
75137629Scognetvoid
76137629Scognetarm_setup_irqhandler(const char *name, void (*hand)(void*), void *arg,
77129198Scognet    int irq, int flags, void **cookiep)
78129198Scognet{
79129198Scognet	struct ithd *cur_ith;
80135650Scognet	struct arm_intr *intr = NULL;
81129198Scognet	int error;
82129198Scognet
83129198Scognet	if (irq < 0 || irq >= NIRQ)
84129198Scognet		return;
85135650Scognet	if (!(flags & INTR_FAST))
86135650Scognet		intr = malloc(sizeof(*intr), M_DEVBUF, M_WAITOK);
87129198Scognet	cur_ith = ithreads[irq];
88129198Scognet	if (cur_ith == NULL) {
89129198Scognet		error = ithread_create(&cur_ith, irq, 0, NULL, NULL, "intr%d:",
90129198Scognet		    irq);
91129198Scognet		if (error)
92129198Scognet			return;
93129198Scognet		ithreads[irq] = cur_ith;
94137629Scognet		last_printed +=
95137629Scognet		    snprintf(intrnames + last_printed,
96137629Scognet		    MAXCOMLEN + 1,
97137629Scognet		    "irq%d: %s", irq, name);
98137629Scognet		last_printed++;
99137629Scognet		intrcnt_tab[irq] = intrcnt_index;
100137629Scognet		intrcnt_index++;
101137629Scognet
102129198Scognet	}
103135650Scognet	if (!(flags & INTR_FAST)) {
104135650Scognet		intr->handler = hand;
105135650Scognet		intr->arg = arg;
106135650Scognet		intr->irq = irq;
107135650Scognet		intr->cookiep = *cookiep;
108135650Scognet		ithread_add_handler(cur_ith, name, arm_intr_handler, intr,
109135650Scognet		    ithread_priority(flags), flags, cookiep);
110135650Scognet	} else
111135650Scognet		ithread_add_handler(cur_ith, name, hand, arg,
112135650Scognet		    ithread_priority(flags), flags, cookiep);
113129198Scognet}
114129198Scognet
115129198Scognetvoid dosoftints(void);
116129198Scognetvoid
117129198Scognetdosoftints(void)
118129198Scognet{
119129198Scognet}
120129198Scognet
121129198Scognetvoid
122135650Scognetarm_handler_execute(void *frame, int irqnb)
123129198Scognet{
124129198Scognet	struct ithd *ithd;
125138857Scognet	int i;
126129198Scognet	struct intrhand *ih;
127135650Scognet	struct thread *td = curthread;
128129198Scognet
129135650Scognet	td->td_intr_nesting_level++;
130135650Scognet	if (irqnb == 0)
131135650Scognet		irqnb = arm_get_irqnb(frame);
132135650Scognet	arm_mask_irqs(irqnb);
133138857Scognet	enable_interrupts(I32_bit|F32_bit);
134135650Scognet	while (irqnb != 0) {
135135650Scognet		i = ffs(irqnb) - 1;
136137629Scognet		intrcnt[intrcnt_tab[i]]++;
137135650Scognet		irqnb &= ~(1U << i);
138135650Scognet		ithd = ithreads[i];
139135650Scognet		if (!ithd)
140135650Scognet			continue;
141135650Scognet		ih = TAILQ_FIRST(&ithd->it_handlers);
142135650Scognet		if (ih && ih->ih_flags & IH_FAST) {
143135650Scognet			TAILQ_FOREACH(ih, &ithd->it_handlers,
144135650Scognet			    ih_next) {
145135650Scognet				ih->ih_handler(ih->ih_argument ?
146135650Scognet				    ih->ih_argument : frame);
147129198Scognet			}
148135650Scognet			arm_unmask_irqs(1 << i);
149138022Scognet		} else if (ih)
150135650Scognet			ithread_schedule(ithd);
151135650Scognet		irqnb |= arm_get_irqnb(frame);
152135650Scognet	}
153135650Scognet	td->td_intr_nesting_level--;
154129198Scognet}
155