Home | History | Annotate | Line # | Download | only in arm32
intr.c revision 1.15
      1 /*	$NetBSD: intr.c,v 1.15 2007/02/18 07:13:18 matt Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1994-1998 Mark Brinicombe.
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. All advertising materials mentioning features or use of this software
     16  *    must display the following acknowledgement:
     17  *	This product includes software developed by Mark Brinicombe
     18  *	for the NetBSD Project.
     19  * 4. The name of the company nor the name of the author may be used to
     20  *    endorse or promote products derived from this software without specific
     21  *    prior written permission.
     22  *
     23  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     24  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     25  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     26  * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
     27  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     28  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     29  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     33  * SUCH DAMAGE.
     34  *
     35  * Soft interrupt and other generic interrupt functions.
     36  */
     37 
     38 #include <sys/cdefs.h>
     39 __KERNEL_RCSID(0, "$NetBSD: intr.c,v 1.15 2007/02/18 07:13:18 matt Exp $");
     40 
     41 #include "opt_irqstats.h"
     42 
     43 #include <sys/param.h>
     44 #include <sys/systm.h>
     45 #include <sys/syslog.h>
     46 #include <sys/malloc.h>
     47 #include <sys/conf.h>
     48 
     49 #include <uvm/uvm_extern.h>
     50 
     51 #include <machine/atomic.h>
     52 #include <machine/intr.h>
     53 #include <machine/cpu.h>
     54 
     55 #include <net/netisr.h>
     56 
     57 #include <arm/arm32/machdep.h>
     58 
     59 extern int current_spl_level;
     60 
     61 extern unsigned spl_mask;
     62 
     63 /* Generate soft interrupt counts if IRQSTATS is defined */
     64 /* Prototypes */
     65 static void clearsoftintr(u_int);
     66 
     67 u_int soft_interrupts = 0;
     68 
     69 #ifndef __HAVE_GENERIC_SOFT_INTERRUPTS
     70 #ifdef IRQSTATS
     71 extern u_int sintrcnt[];
     72 #define INC_SINTRCNT(x) ++sintrcnt[x]
     73 #else
     74 #define INC_SINTRCNT(x)
     75 #endif	/* IRQSTATS */
     76 #else
     77 #define INC_SINTRCNT(x)
     78 #endif  /* !__HAVE_GENERIC_SOFT_INTERRUPTS */
     79 
     80 #define	COUNT	uvmexp.softs;
     81 
     82 /* Prototypes */
     83 
     84 #include "com.h"
     85 #if NCOM > 0
     86 extern void comsoft(void);
     87 #endif	/* NCOM > 0 */
     88 
     89 #if NPLCOM > 0
     90 extern void plcomsoft(void);
     91 #endif	/* NPLCOM > 0 */
     92 
     93 /* Eventually these will become macros */
     94 
     95 #define	SI_SOFTMASK(si)	(1U << (si))
     96 
     97 static inline void
     98 clearsoftintr(u_int intrmask)
     99 {
    100 	atomic_clear_bit(&soft_interrupts, intrmask);
    101 }
    102 
    103 #ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
    104 void
    105 _setsoftintr(int si)
    106 {
    107 	atomic_set_bit(&soft_interrupts, SI_SOFTMASK(si));
    108 }
    109 #else /* __HAVE_GENERIC_SOFT_INTERRUPTS */
    110 #define	SI_SOFTNET	SOFTIRQ_NET
    111 #define	SI_SOFTCLOCK	SOFTIRQ_CLOCK
    112 #define	SI_SOFTSERIAL	SOFTIRQ_SERIAL
    113 void
    114 setsoftintr(u_int intrmask)
    115 {
    116 	atomic_set_bit(&soft_interrupts, intrmask);
    117 }
    118 
    119 void
    120 setsoftclock(void)
    121 {
    122 	atomic_set_bit(&soft_interrupts, SI_MASK(SI_SOFTCLOCK));
    123 }
    124 
    125 void
    126 setsoftnet(void)
    127 {
    128 	atomic_set_bit(&soft_interrupts, SI_MASK(SI_SOFTNET));
    129 }
    130 
    131 void
    132 setsoftserial(void)
    133 {
    134 	atomic_set_bit(&soft_interrupts, SI_MASK(SI_SOFTSERIAL));
    135 }
    136 
    137 static void
    138 softnet(void)
    139 {
    140 #define DONETISR(bit, fn) do {					\
    141 		if (netisr & (1 << bit)) {			\
    142 			atomic_clear_bit(&netisr, (1 << bit));	\
    143 			fn();					\
    144 		}						\
    145 } while (0)
    146 
    147 #include <net/netisr_dispatch.h>
    148 
    149 #undef DONETISR
    150 }
    151 #endif /* !__HAVE_GENERIC_SOFT_INTERRUPTS */
    152 
    153 /* Handle software interrupts */
    154 
    155 void
    156 dosoftints(void)
    157 {
    158 	u_int softints;
    159 	int s;
    160 
    161 	softints = soft_interrupts & spl_smasks[current_spl_level];
    162 	if (softints == 0) return;
    163 
    164 	/*
    165 	 * Serial software interrupts
    166 	 */
    167 	if (softints & SI_SOFTMASK(SI_SOFTSERIAL)) {
    168 		s = splsoftserial();
    169 		++COUNT;
    170 		INC_SINTRCNT(SI_SOFTSERIAL);
    171 		clearsoftintr(SI_SOFTMASK(SI_SOFTSERIAL));
    172 #ifndef __HAVE_GENERIC_SOFT_INTERRUPTS
    173 #if NCOM > 0
    174 		comsoft();
    175 #endif	/* NCOM > 0 */
    176 #if NPLCOM > 0
    177 		plcomsoft();
    178 #endif	/* NPLCOM > 0 */
    179 #else
    180 		softintr_dispatch(SI_SOFTSERIAL);
    181 #endif
    182 		(void)splx(s);
    183 	}
    184 
    185 	/*
    186 	 * Network software interrupts
    187 	 */
    188 	if (softints & SI_SOFTMASK(SI_SOFTNET)) {
    189 		s = splsoftnet();
    190 		++COUNT;
    191 		INC_SINTRCNT(SI_SOFTNET);
    192 		clearsoftintr(SI_SOFTMASK(SI_SOFTNET));
    193 #ifndef __HAVE_GENERIC_SOFT_INTERRUPTS
    194 		softnet();
    195 #else
    196 		softintr_dispatch(SI_SOFTNET);
    197 #endif
    198 		(void)splx(s);
    199 	}
    200 
    201 	/*
    202 	 * Software clock interrupts
    203 	 */
    204 	if (softints & SI_SOFTMASK(SI_SOFTCLOCK)) {
    205 		s = splsoftclock();
    206 		++COUNT;
    207 		INC_SINTRCNT(SI_SOFTCLOCK);
    208 		clearsoftintr(SI_SOFTMASK(SI_SOFTCLOCK));
    209 #ifndef __HAVE_GENERIC_SOFT_INTERRUPTS
    210 		softclock(NULL);
    211 #else
    212 		softintr_dispatch(SI_SOFTCLOCK);
    213 #endif
    214 		(void)splx(s);
    215 	}
    216 
    217 	/*
    218 	 * Misc software interrupts
    219 	 */
    220 #ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
    221 	if (softints & SI_SOFTMASK(SI_SOFT)) {
    222 		s = splsoft();
    223 		++COUNT;
    224 		clearsoftintr(SI_SOFTMASK(SI_SOFT));
    225 		softintr_dispatch(SI_SOFT);
    226 		(void)splx(s);
    227 	}
    228 #endif
    229 }
    230 
    231 int current_spl_level = _SPL_SERIAL;
    232 u_int spl_masks[_SPL_LEVELS + 1];
    233 u_int spl_smasks[_SPL_LEVELS];
    234 int safepri = _SPL_0;
    235 
    236 extern u_int irqmasks[];
    237 
    238 void
    239 set_spl_masks(void)
    240 {
    241 	int loop;
    242 
    243 	for (loop = 0; loop < _SPL_LEVELS; ++loop) {
    244 		spl_masks[loop] = 0xffffffff;
    245 		spl_smasks[loop] = 0;
    246 	}
    247 
    248 	spl_masks[_SPL_BIO]        = irqmasks[IPL_BIO];
    249 	spl_masks[_SPL_NET]        = irqmasks[IPL_NET];
    250 	spl_masks[_SPL_SOFTSERIAL] = irqmasks[IPL_TTY];
    251 	spl_masks[_SPL_TTY]        = irqmasks[IPL_TTY];
    252 	spl_masks[_SPL_VM]         = irqmasks[IPL_VM];
    253 	spl_masks[_SPL_AUDIO]      = irqmasks[IPL_AUDIO];
    254 	spl_masks[_SPL_CLOCK]      = irqmasks[IPL_CLOCK];
    255 #ifdef IPL_STATCLOCK
    256 	spl_masks[_SPL_STATCLOCK]  = irqmasks[IPL_STATCLOCK];
    257 #else
    258 	spl_masks[_SPL_STATCLOCK]  = irqmasks[IPL_CLOCK];
    259 #endif
    260 	spl_masks[_SPL_HIGH]       = irqmasks[IPL_HIGH];
    261 	spl_masks[_SPL_SERIAL]     = irqmasks[IPL_SERIAL];
    262 	spl_masks[_SPL_LEVELS]     = 0;
    263 
    264 	spl_smasks[_SPL_0] = 0xffffffff;
    265 	for (loop = 0; loop < _SPL_SOFTSERIAL; ++loop)
    266 		spl_smasks[loop] |= SI_SOFTMASK(SI_SOFTSERIAL);
    267 	for (loop = 0; loop < _SPL_SOFTNET; ++loop)
    268 		spl_smasks[loop] |= SI_SOFTMASK(SI_SOFTNET);
    269 	for (loop = 0; loop < _SPL_SOFTCLOCK; ++loop)
    270 		spl_smasks[loop] |= SI_SOFTMASK(SI_SOFTCLOCK);
    271 #ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
    272 	for (loop = 0; loop < _SPL_SOFT; ++loop)
    273 		spl_smasks[loop] |= SI_SOFTMASK(SI_SOFT);
    274 #endif
    275 }
    276 
    277 static const int ipl_to_spl_map[] = {
    278 	[IPL_NONE] = 1 + _SPL_0,
    279 #ifdef IPL_SOFT
    280 	[IPL_SOFT] = 1 + _SPL_SOFT,
    281 #endif /* IPL_SOFTCLOCK */
    282 #if defined(IPL_SOFTCLOCK)
    283 	[IPL_SOFTCLOCK] = 1 + _SPL_SOFTCLOCK,
    284 #endif /* defined(IPL_SOFTCLOCK) */
    285 #if defined(IPL_SOFTNET)
    286 	[IPL_SOFTNET] = 1 + _SPL_SOFTNET,
    287 #endif /* defined(IPL_SOFTNET) */
    288 	[IPL_BIO] = 1 + _SPL_BIO,
    289 	[IPL_NET] = 1 + _SPL_NET,
    290 #if defined(IPL_SOFTSERIAL)
    291 	[IPL_SOFTSERIAL] = 1 + _SPL_SOFTSERIAL,
    292 #endif /* defined(IPL_SOFTSERIAL) */
    293 	[IPL_TTY] = 1 + _SPL_TTY,
    294 	[IPL_VM] = 1 + _SPL_VM,
    295 	[IPL_AUDIO] = 1 + _SPL_AUDIO,
    296 	[IPL_CLOCK] = 1 + _SPL_CLOCK,
    297 	[IPL_STATCLOCK] = 1 + _SPL_STATCLOCK,
    298 	[IPL_HIGH] = 1 + _SPL_HIGH,
    299 	[IPL_SERIAL] = 1 + _SPL_SERIAL,
    300 };
    301 
    302 int
    303 ipl_to_spl(int ipl)
    304 {
    305 	KASSERT(ipl < __arraycount(ipl_to_spl_map));
    306 	KASSERT(ipl_to_spl_map[ipl]);
    307 
    308 	return ipl_to_spl_map[ipl] - 1;
    309 }
    310 
    311 #ifdef DIAGNOSTIC
    312 void
    313 dump_spl_masks(void)
    314 {
    315 	int loop;
    316 
    317 	for (loop = 0; loop < _SPL_LEVELS; ++loop) {
    318 		printf("spl_mask[%d]=%08x splsmask[%d]=%08x\n", loop,
    319 		    spl_masks[loop], loop, spl_smasks[loop]);
    320 	}
    321 }
    322 #endif
    323 
    324 /* End of intr.c */
    325