iq80310_intr.c revision 1.3
1/* $NetBSD: iq80310_intr.c,v 1.3 2001/11/07 02:24:18 thorpej Exp $ */ 2 3/* 4 * Copyright (c) 2001 Wasabi Systems, Inc. 5 * All rights reserved. 6 * 7 * Written by Jason R. Thorpe for Wasabi Systems, Inc. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed for the NetBSD Project by 20 * Wasabi Systems, Inc. 21 * 4. The name of Wasabi Systems, Inc. may not be used to endorse 22 * or promote products derived from this software without specific prior 23 * written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 * POSSIBILITY OF SUCH DAMAGE. 36 */ 37 38/* 39 * Interrupt support for the Intel IQ80310. 40 */ 41 42#include <sys/param.h> 43#include <sys/systm.h> 44#include <sys/malloc.h> 45 46#include <machine/bus.h> 47#include <machine/intr.h> 48#include <machine/cpu.h> 49#include <machine/cpufunc.h> 50 51#include <evbarm/iq80310/iq80310reg.h> 52#include <evbarm/iq80310/iq80310var.h> 53#include <evbarm/iq80310/obiovar.h> 54 55irqhandler_t *irqhandlers[NIRQS]; 56 57int current_intr_depth; /* Depth of interrupt nesting */ 58u_int intr_claimed_mask; /* Interrupts that are claimed */ 59u_int intr_disabled_mask; /* Interrupts that are temporarily disabled */ 60u_int intr_current_mask; /* Interrupts currently allowable */ 61u_int spl_mask; 62u_int irqmasks[IPL_LEVELS]; 63u_int irqblock[NIRQS]; 64 65extern u_int soft_interrupts; /* Only so we can initialise it */ 66 67extern char *_intrnames; 68extern void set_spl_masks(void); 69 70/* Called only from assembler code. */ 71uint32_t iq80310_intstat_read(void); 72void stray_irqhandler(int); 73 74/* 75 * We have 8 interrupt source bits -- 5 in the XINT3 register, and 3 76 * in the XINT0 register (the upper 3). 77 */ 78#define IRQ_BITS 0xff 79 80void 81irq_init(void) 82{ 83 int loop; 84 85 /* Clear all the IRQ handlers and the IRQ block masks. */ 86 for (loop = 0; loop < NIRQS; ++loop) { 87 irqhandlers[loop] = NULL; 88 irqblock[loop] = 0; 89 } 90 91 /* 92 * Set up the irqmasks for the different interrupt priority 93 * levels. We will start with no bits set and these will be 94 * updated as handlers are installed at different IPLs. 95 */ 96 for (loop = 0; loop < IPL_LEVELS; ++loop) 97 irqmasks[loop] = 0; 98 99 current_intr_depth = 0; 100 intr_claimed_mask = 0x00000000; 101 intr_disabled_mask = 0x00000000; 102 intr_current_mask = 0x00000000; 103 spl_mask = 0x00000000; 104 soft_interrupts = 0x00000000; 105 106 set_spl_masks(); 107 irq_setmasks(); 108 109 /* Enable IRQs and FIQs. */ 110 enable_interrupts(I32_bit | F32_bit); 111} 112 113uint32_t 114iq80310_intstat_read(void) 115{ 116 uint32_t intstat; 117 118 intstat = CPLD_READ(IQ80310_XINT3_STATUS) & 0x1f; 119 if (1/*rev F or later board*/) 120 intstat |= (CPLD_READ(IQ80310_XINT0_STATUS) & 0x7) << 5; 121 122 return (intstat); 123} 124 125__inline void 126irq_setmasks_nointr(void) 127{ 128 u_int disabled; 129 130 /* 131 * The XINT_MASK register sets a bit to *disable*. 132 */ 133 disabled = (~(intr_current_mask & spl_mask)) & IRQ_BITS; 134 135 /* 136 * The PCI interrupts are all masked by a single 137 * bit in XINT3. 138 */ 139 if (disabled >> 5) 140 disabled |= XINT3_SINTD; 141 142 CPLD_WRITE(IQ80310_XINT_MASK, disabled & 0x1f); 143} 144 145void 146irq_setmasks(void) 147{ 148 u_int oldirqstate; 149 150 oldirqstate = disable_interrupts(I32_bit); 151 irq_setmasks_nointr(); 152 restore_interrupts(oldirqstate); 153} 154 155void 156enable_irq(int irq) 157{ 158 159 intr_claimed_mask |= (1U << irq); 160 intr_current_mask = intr_claimed_mask & ~intr_disabled_mask; 161 irq_setmasks_nointr(); 162} 163 164void 165disable_irq(int irq) 166{ 167 168 intr_claimed_mask &= ~(1U << irq); 169 intr_current_mask = intr_claimed_mask & ~intr_disabled_mask; 170 irq_setmasks_nointr(); 171} 172 173void 174stray_irqhandler(int irq) 175{ 176 177 panic("no handlers for IRQ %d\n", irq); 178} 179 180void * 181iq80310_intr_establish(int irq, int ipl, int (*func)(void *), void *arg) 182{ 183 irqhandler_t *ih, *ptr; 184 u_int oldirqstate; 185 int loop; 186 187 ih = malloc(sizeof(*ih), M_DEVBUF, M_NOWAIT); 188 if (ih == NULL) 189 return (NULL); 190 191 ih->ih_level = ipl; 192 ih->ih_name = NULL; 193 ih->ih_func = func; 194 ih->ih_arg = arg; 195 ih->ih_flags = 0; 196 ih->ih_num = irq; 197 198 oldirqstate = disable_interrupts(I32_bit); 199 200 /* Attach handler at top of chain */ 201 ih->ih_next = irqhandlers[irq]; 202 irqhandlers[irq] = ih; 203 204 /* Update the IRQ masks. */ 205 ptr = irqhandlers[irq]; 206 if (ptr) { 207 ipl = ptr->ih_level - 1; 208 while (ptr) { 209 if (ptr->ih_level - 1 < ipl) 210 ipl = ptr->ih_level - 1; 211 ptr = ptr->ih_next; 212 } 213 for (loop = 0; loop < IPL_LEVELS; ++loop) { 214 if (ipl >= loop) 215 irqmasks[loop] |= (1U << irq); 216 else 217 irqmasks[loop] &= ~(1U << irq); 218 } 219 } 220 221 /* splimp > spltty */ 222 irqmasks[IPL_NET] &= irqmasks[IPL_TTY]; 223 224 /* 225 * We now need to update the irqblock array. This array indicates 226 * what other interrupts should be blocked when a given interrupt 227 * is asserted. This basically emulates hardware interrupt 228 * priorities e.g. by blocking all other IPL_BIO interrupts when 229 * an IPL_BIO interrupt is asserted. For each interrupt, we find 230 * the highest IPL and set the block mask to the interrupt mask 231 * for that level. 232 */ 233 for (loop = 0; loop < NIRQS; ++loop) { 234 ptr = irqhandlers[loop]; 235 if (ptr) { 236 /* There is at least 1 handler so scan the chain */ 237 ipl = ptr->ih_level; 238 while (ptr) { 239 if (ptr->ih_level > ipl) 240 ipl = ptr->ih_level; 241 ptr = ptr->ih_next; 242 } 243 irqblock[loop] = ~irqmasks[ipl]; 244 } else { 245 /* No handlers, so nothing else needs to be blocked. */ 246 irqblock[loop] = 0; 247 } 248 } 249 250 enable_irq(irq); 251 set_spl_masks(); 252 253 restore_interrupts(oldirqstate); 254 255 return (ih); 256} 257 258void 259iq80310_intr_disestablish(void *cookie) 260{ 261 262 panic("iq80310_intr_disestablish"); 263} 264