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