source: rtems-libbsd/freebsd/kern/kern_intr.c @ ee6b343

4.1155-freebsd-126-freebsd-12freebsd-9.3
Last change on this file since ee6b343 was ee6b343, checked in by Christian Mauderer <christian.mauderer@…>, on 05/10/12 at 13:06:10

Provide SWI(9) and TIMEOUT(9)

  • Property mode set to 100644
File size: 48.1 KB
Line 
1#include <freebsd/machine/rtems-bsd-config.h>
2
3/*-
4 * Copyright (c) 1997, Stefan Esser <se@freebsd.org>
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 unmodified, this list of conditions, and the following
12 *    disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <freebsd/sys/cdefs.h>
30__FBSDID("$FreeBSD$");
31
32
33#include <freebsd/local/opt_ddb.h>
34
35#include <freebsd/sys/param.h>
36#include <freebsd/sys/bus.h>
37#include <freebsd/sys/conf.h>
38#include <freebsd/sys/cpuset.h>
39#include <freebsd/sys/rtprio.h>
40#include <freebsd/sys/systm.h>
41#include <freebsd/sys/interrupt.h>
42#include <freebsd/sys/kernel.h>
43#include <freebsd/sys/kthread.h>
44#include <freebsd/sys/ktr.h>
45#include <freebsd/sys/limits.h>
46#include <freebsd/sys/lock.h>
47#include <freebsd/sys/malloc.h>
48#include <freebsd/sys/mutex.h>
49#include <freebsd/sys/priv.h>
50#include <freebsd/sys/proc.h>
51#include <freebsd/sys/random.h>
52#include <freebsd/sys/resourcevar.h>
53#include <freebsd/sys/sched.h>
54#include <freebsd/sys/smp.h>
55#include <freebsd/sys/sysctl.h>
56#include <freebsd/sys/syslog.h>
57#include <freebsd/sys/unistd.h>
58#include <freebsd/sys/vmmeter.h>
59#include <freebsd/machine/atomic.h>
60#include <freebsd/machine/cpu.h>
61#ifndef __rtems__
62#include <freebsd/machine/md_var.h>
63#include <freebsd/machine/stdarg.h>
64#else /* __rtems__ */
65  #ifdef INTR_FILTER
66    #error INTR_FILTER is currently not suppported with RTEMS
67  #endif
68  #define RTEMSBSD_SWI_WAKEUP_EVENT RTEMS_EVENT_31
69#endif /* __rtems__ */
70#ifdef DDB
71#include <freebsd/ddb/ddb.h>
72#include <freebsd/ddb/db_sym.h>
73#endif
74
75/*
76 * Describe an interrupt thread.  There is one of these per interrupt event.
77 */
78struct intr_thread {
79        struct intr_event *it_event;
80        struct thread *it_thread;       /* Kernel thread. */
81        int     it_flags;               /* (j) IT_* flags. */
82        int     it_need;                /* Needs service. */
83};
84
85/* Interrupt thread flags kept in it_flags */
86#define IT_DEAD         0x000001        /* Thread is waiting to exit. */
87
88struct  intr_entropy {
89        struct  thread *td;
90        uintptr_t event;
91};
92
93struct  intr_event *clk_intr_event;
94#ifndef __rtems__
95struct  intr_event *tty_intr_event;
96void    *vm_ih;
97#endif /* __rtems__ */
98struct proc *intrproc;
99
100static MALLOC_DEFINE(M_ITHREAD, "ithread", "Interrupt Threads");
101
102static int intr_storm_threshold = 1000;
103#ifndef __rtems__
104TUNABLE_INT("hw.intr_storm_threshold", &intr_storm_threshold);
105SYSCTL_INT(_hw, OID_AUTO, intr_storm_threshold, CTLFLAG_RW,
106    &intr_storm_threshold, 0,
107    "Number of consecutive interrupts before storm protection is enabled");
108#endif /* __rtems__ */
109static TAILQ_HEAD(, intr_event) event_list =
110    TAILQ_HEAD_INITIALIZER(event_list);
111static struct mtx event_lock;
112MTX_SYSINIT(intr_event_list, &event_lock, "intr event list", MTX_DEF);
113
114static void     intr_event_update(struct intr_event *ie);
115#ifdef INTR_FILTER
116static int      intr_event_schedule_thread(struct intr_event *ie,
117                    struct intr_thread *ithd);
118static int      intr_filter_loop(struct intr_event *ie,
119                    struct trapframe *frame, struct intr_thread **ithd);
120static struct intr_thread *ithread_create(const char *name,
121                              struct intr_handler *ih);
122#else
123static int      intr_event_schedule_thread(struct intr_event *ie);
124static struct intr_thread *ithread_create(const char *name);
125#endif
126#ifndef __rtems__
127static void     ithread_destroy(struct intr_thread *ithread);
128#endif /* __rtems__ */
129static void     ithread_execute_handlers(struct proc *p,
130                    struct intr_event *ie);
131#ifdef INTR_FILTER
132static void     priv_ithread_execute_handler(struct proc *p,
133                    struct intr_handler *ih);
134#endif
135static void     ithread_loop(void *);
136static void     ithread_update(struct intr_thread *ithd);
137#ifndef __rtems__
138static void     start_softintr(void *);
139
140/* Map an interrupt type to an ithread priority. */
141u_char
142intr_priority(enum intr_type flags)
143{
144        u_char pri;
145
146        flags &= (INTR_TYPE_TTY | INTR_TYPE_BIO | INTR_TYPE_NET |
147            INTR_TYPE_CAM | INTR_TYPE_MISC | INTR_TYPE_CLK | INTR_TYPE_AV);
148        switch (flags) {
149        case INTR_TYPE_TTY:
150                pri = PI_TTYLOW;
151                break;
152        case INTR_TYPE_BIO:
153                /*
154                 * XXX We need to refine this.  BSD/OS distinguishes
155                 * between tape and disk priorities.
156                 */
157                pri = PI_DISK;
158                break;
159        case INTR_TYPE_NET:
160                pri = PI_NET;
161                break;
162        case INTR_TYPE_CAM:
163                pri = PI_DISK;          /* XXX or PI_CAM? */
164                break;
165        case INTR_TYPE_AV:              /* Audio/video */
166                pri = PI_AV;
167                break;
168        case INTR_TYPE_CLK:
169                pri = PI_REALTIME;
170                break;
171        case INTR_TYPE_MISC:
172                pri = PI_DULL;          /* don't care */
173                break;
174        default:
175                /* We didn't specify an interrupt level. */
176                panic("intr_priority: no interrupt type in flags");
177        }
178
179        return pri;
180}
181
182#endif /* __rtems__ */
183/*
184 * Update an ithread based on the associated intr_event.
185 */
186static void
187ithread_update(struct intr_thread *ithd)
188{
189        struct intr_event *ie;
190        struct thread *td;
191        u_char pri;
192
193        ie = ithd->it_event;
194        td = ithd->it_thread;
195
196        /* Determine the overall priority of this event. */
197        if (TAILQ_EMPTY(&ie->ie_handlers))
198                pri = PRI_MAX_ITHD;
199        else
200                pri = TAILQ_FIRST(&ie->ie_handlers)->ih_pri;
201
202        /* Update name and priority. */
203        strlcpy(td->td_name, ie->ie_fullname, sizeof(td->td_name));
204        thread_lock(td);
205#ifndef __rtems__
206        sched_prio(td, pri);
207#else /* __rtems__ */
208#warning TODO: set thread priority
209#endif /* __rtems__ */
210        thread_unlock(td);
211}
212
213/*
214 * Regenerate the full name of an interrupt event and update its priority.
215 */
216static void
217intr_event_update(struct intr_event *ie)
218{
219        struct intr_handler *ih;
220        char *last;
221        int missed, space;
222
223        /* Start off with no entropy and just the name of the event. */
224        mtx_assert(&ie->ie_lock, MA_OWNED);
225        strlcpy(ie->ie_fullname, ie->ie_name, sizeof(ie->ie_fullname));
226        ie->ie_flags &= ~IE_ENTROPY;
227        missed = 0;
228        space = 1;
229
230        /* Run through all the handlers updating values. */
231        TAILQ_FOREACH(ih, &ie->ie_handlers, ih_next) {
232                if (strlen(ie->ie_fullname) + strlen(ih->ih_name) + 1 <
233                    sizeof(ie->ie_fullname)) {
234                        strcat(ie->ie_fullname, " ");
235                        strcat(ie->ie_fullname, ih->ih_name);
236                        space = 0;
237                } else
238                        missed++;
239                if (ih->ih_flags & IH_ENTROPY)
240                        ie->ie_flags |= IE_ENTROPY;
241        }
242
243        /*
244         * If the handler names were too long, add +'s to indicate missing
245         * names. If we run out of room and still have +'s to add, change
246         * the last character from a + to a *.
247         */
248        last = &ie->ie_fullname[sizeof(ie->ie_fullname) - 2];
249        while (missed-- > 0) {
250                if (strlen(ie->ie_fullname) + 1 == sizeof(ie->ie_fullname)) {
251                        if (*last == '+') {
252                                *last = '*';
253                                break;
254                        } else
255                                *last = '+';
256                } else if (space) {
257                        strcat(ie->ie_fullname, " +");
258                        space = 0;
259                } else
260                        strcat(ie->ie_fullname, "+");
261        }
262
263        /*
264         * If this event has an ithread, update it's priority and
265         * name.
266         */
267        if (ie->ie_thread != NULL)
268                ithread_update(ie->ie_thread);
269        CTR2(KTR_INTR, "%s: updated %s", __func__, ie->ie_fullname);
270}
271
272int
273intr_event_create(struct intr_event **event, void *source, int flags, int irq,
274    void (*pre_ithread)(void *), void (*post_ithread)(void *),
275    void (*post_filter)(void *), int (*assign_cpu)(void *, u_char),
276    const char *fmt, ...)
277{
278        struct intr_event *ie;
279        va_list ap;
280
281        /* The only valid flag during creation is IE_SOFT. */
282        if ((flags & ~IE_SOFT) != 0)
283                return (EINVAL);
284        ie = malloc(sizeof(struct intr_event), M_ITHREAD, M_WAITOK | M_ZERO);
285        ie->ie_source = source;
286        ie->ie_pre_ithread = pre_ithread;
287        ie->ie_post_ithread = post_ithread;
288        ie->ie_post_filter = post_filter;
289        ie->ie_assign_cpu = assign_cpu;
290        ie->ie_flags = flags;
291        ie->ie_irq = irq;
292        ie->ie_cpu = NOCPU;
293        TAILQ_INIT(&ie->ie_handlers);
294        mtx_init(&ie->ie_lock, "intr event", NULL, MTX_DEF);
295
296        va_start(ap, fmt);
297        vsnprintf(ie->ie_name, sizeof(ie->ie_name), fmt, ap);
298        va_end(ap);
299        strlcpy(ie->ie_fullname, ie->ie_name, sizeof(ie->ie_fullname));
300        mtx_lock(&event_lock);
301        TAILQ_INSERT_TAIL(&event_list, ie, ie_list);
302        mtx_unlock(&event_lock);
303        if (event != NULL)
304                *event = ie;
305        CTR2(KTR_INTR, "%s: created %s", __func__, ie->ie_name);
306        return (0);
307}
308
309#ifndef __rtems__
310/*
311 * Bind an interrupt event to the specified CPU.  Note that not all
312 * platforms support binding an interrupt to a CPU.  For those
313 * platforms this request will fail.  For supported platforms, any
314 * associated ithreads as well as the primary interrupt context will
315 * be bound to the specificed CPU.  Using a cpu id of NOCPU unbinds
316 * the interrupt event.
317 */
318int
319intr_event_bind(struct intr_event *ie, u_char cpu)
320{
321        cpuset_t mask;
322        lwpid_t id;
323        int error;
324
325        /* Need a CPU to bind to. */
326        if (cpu != NOCPU && CPU_ABSENT(cpu))
327                return (EINVAL);
328
329        if (ie->ie_assign_cpu == NULL)
330                return (EOPNOTSUPP);
331
332        error = priv_check(curthread, PRIV_SCHED_CPUSET_INTR);
333        if (error)
334                return (error);
335
336        /*
337         * If we have any ithreads try to set their mask first to verify
338         * permissions, etc.
339         */
340        mtx_lock(&ie->ie_lock);
341        if (ie->ie_thread != NULL) {
342                CPU_ZERO(&mask);
343                if (cpu == NOCPU)
344                        CPU_COPY(cpuset_root, &mask);
345                else
346                        CPU_SET(cpu, &mask);
347                id = ie->ie_thread->it_thread->td_tid;
348                mtx_unlock(&ie->ie_lock);
349                error = cpuset_setthread(id, &mask);
350                if (error)
351                        return (error);
352        } else
353                mtx_unlock(&ie->ie_lock);
354        error = ie->ie_assign_cpu(ie->ie_source, cpu);
355        if (error) {
356                mtx_lock(&ie->ie_lock);
357                if (ie->ie_thread != NULL) {
358                        CPU_ZERO(&mask);
359                        if (ie->ie_cpu == NOCPU)
360                                CPU_COPY(cpuset_root, &mask);
361                        else
362                                CPU_SET(cpu, &mask);
363                        id = ie->ie_thread->it_thread->td_tid;
364                        mtx_unlock(&ie->ie_lock);
365                        (void)cpuset_setthread(id, &mask);
366                } else
367                        mtx_unlock(&ie->ie_lock);
368                return (error);
369        }
370
371        mtx_lock(&ie->ie_lock);
372        ie->ie_cpu = cpu;
373        mtx_unlock(&ie->ie_lock);
374
375        return (error);
376}
377
378static struct intr_event *
379intr_lookup(int irq)
380{
381        struct intr_event *ie;
382
383        mtx_lock(&event_lock);
384        TAILQ_FOREACH(ie, &event_list, ie_list)
385                if (ie->ie_irq == irq &&
386                    (ie->ie_flags & IE_SOFT) == 0 &&
387                    TAILQ_FIRST(&ie->ie_handlers) != NULL)
388                        break;
389        mtx_unlock(&event_lock);
390        return (ie);
391}
392
393int
394intr_setaffinity(int irq, void *m)
395{
396        struct intr_event *ie;
397        cpuset_t *mask;
398        u_char cpu;
399        int n;
400
401        mask = m;
402        cpu = NOCPU;
403        /*
404         * If we're setting all cpus we can unbind.  Otherwise make sure
405         * only one cpu is in the set.
406         */
407        if (CPU_CMP(cpuset_root, mask)) {
408                for (n = 0; n < CPU_SETSIZE; n++) {
409                        if (!CPU_ISSET(n, mask))
410                                continue;
411                        if (cpu != NOCPU)
412                                return (EINVAL);
413                        cpu = (u_char)n;
414                }
415        }
416        ie = intr_lookup(irq);
417        if (ie == NULL)
418                return (ESRCH);
419        return (intr_event_bind(ie, cpu));
420}
421
422int
423intr_getaffinity(int irq, void *m)
424{
425        struct intr_event *ie;
426        cpuset_t *mask;
427
428        mask = m;
429        ie = intr_lookup(irq);
430        if (ie == NULL)
431                return (ESRCH);
432        CPU_ZERO(mask);
433        mtx_lock(&ie->ie_lock);
434        if (ie->ie_cpu == NOCPU)
435                CPU_COPY(cpuset_root, mask);
436        else
437                CPU_SET(ie->ie_cpu, mask);
438        mtx_unlock(&ie->ie_lock);
439        return (0);
440}
441
442int
443intr_event_destroy(struct intr_event *ie)
444{
445
446        mtx_lock(&event_lock);
447        mtx_lock(&ie->ie_lock);
448        if (!TAILQ_EMPTY(&ie->ie_handlers)) {
449                mtx_unlock(&ie->ie_lock);
450                mtx_unlock(&event_lock);
451                return (EBUSY);
452        }
453        TAILQ_REMOVE(&event_list, ie, ie_list);
454#ifndef notyet
455        if (ie->ie_thread != NULL) {
456                ithread_destroy(ie->ie_thread);
457                ie->ie_thread = NULL;
458        }
459#endif
460        mtx_unlock(&ie->ie_lock);
461        mtx_unlock(&event_lock);
462        mtx_destroy(&ie->ie_lock);
463        free(ie, M_ITHREAD);
464        return (0);
465}
466
467#endif /* __rtems__ */
468#ifndef INTR_FILTER
469static struct intr_thread *
470ithread_create(const char *name)
471{
472        struct intr_thread *ithd;
473        struct thread *td;
474        int error;
475
476        ithd = malloc(sizeof(struct intr_thread), M_ITHREAD, M_WAITOK | M_ZERO);
477
478        error = kproc_kthread_add(ithread_loop, ithd, &intrproc,
479                    &td, RFSTOPPED | RFHIGHPID,
480                    0, "intr", "%s", name);
481        if (error)
482                panic("kproc_create() failed with %d", error);
483        thread_lock(td);
484#ifndef __rtems__
485        sched_class(td, PRI_ITHD);
486        TD_SET_IWAIT(td);
487#endif /* __rtems__ */
488        thread_unlock(td);
489#ifndef __rtems__
490        td->td_pflags |= TDP_ITHREAD;
491#endif /* __rtems__ */
492        ithd->it_thread = td;
493        CTR2(KTR_INTR, "%s: created %s", __func__, name);
494        return (ithd);
495}
496#else
497#ifndef __rtems__
498static struct intr_thread *
499ithread_create(const char *name, struct intr_handler *ih)
500{
501        struct intr_thread *ithd;
502        struct thread *td;
503        int error;
504
505        ithd = malloc(sizeof(struct intr_thread), M_ITHREAD, M_WAITOK | M_ZERO);
506
507        error = kproc_kthread_add(ithread_loop, ih, &intrproc,
508                    &td, RFSTOPPED | RFHIGHPID,
509                    0, "intr", "%s", name);
510        if (error)
511                panic("kproc_create() failed with %d", error);
512        thread_lock(td);
513        sched_class(td, PRI_ITHD);
514        TD_SET_IWAIT(td);
515        thread_unlock(td);
516        td->td_pflags |= TDP_ITHREAD;
517        ithd->it_thread = td;
518        CTR2(KTR_INTR, "%s: created %s", __func__, name);
519        return (ithd);
520}
521#endif /* __rtems__ */
522#endif
523#ifndef __rtems__
524
525static void
526ithread_destroy(struct intr_thread *ithread)
527{
528        struct thread *td;
529
530        CTR2(KTR_INTR, "%s: killing %s", __func__, ithread->it_event->ie_name);
531        td = ithread->it_thread;
532        thread_lock(td);
533        ithread->it_flags |= IT_DEAD;
534        if (TD_AWAITING_INTR(td)) {
535                TD_CLR_IWAIT(td);
536                sched_add(td, SRQ_INTR);
537        }
538        thread_unlock(td);
539}
540
541#endif /* __rtems__ */
542#ifndef INTR_FILTER
543int
544intr_event_add_handler(struct intr_event *ie, const char *name,
545    driver_filter_t filter, driver_intr_t handler, void *arg, u_char pri,
546    enum intr_type flags, void **cookiep)
547{
548        struct intr_handler *ih, *temp_ih;
549        struct intr_thread *it;
550
551        if (ie == NULL || name == NULL || (handler == NULL && filter == NULL))
552                return (EINVAL);
553
554        /* Allocate and populate an interrupt handler structure. */
555        ih = malloc(sizeof(struct intr_handler), M_ITHREAD, M_WAITOK | M_ZERO);
556        ih->ih_filter = filter;
557        ih->ih_handler = handler;
558        ih->ih_argument = arg;
559        strlcpy(ih->ih_name, name, sizeof(ih->ih_name));
560        ih->ih_event = ie;
561        ih->ih_pri = pri;
562        if (flags & INTR_EXCL)
563                ih->ih_flags = IH_EXCLUSIVE;
564        if (flags & INTR_MPSAFE)
565                ih->ih_flags |= IH_MPSAFE;
566        if (flags & INTR_ENTROPY)
567                ih->ih_flags |= IH_ENTROPY;
568
569        /* We can only have one exclusive handler in a event. */
570        mtx_lock(&ie->ie_lock);
571        if (!TAILQ_EMPTY(&ie->ie_handlers)) {
572                if ((flags & INTR_EXCL) ||
573                    (TAILQ_FIRST(&ie->ie_handlers)->ih_flags & IH_EXCLUSIVE)) {
574                        mtx_unlock(&ie->ie_lock);
575                        free(ih, M_ITHREAD);
576                        return (EINVAL);
577                }
578        }
579
580        /* Add the new handler to the event in priority order. */
581        TAILQ_FOREACH(temp_ih, &ie->ie_handlers, ih_next) {
582                if (temp_ih->ih_pri > ih->ih_pri)
583                        break;
584        }
585        if (temp_ih == NULL)
586                TAILQ_INSERT_TAIL(&ie->ie_handlers, ih, ih_next);
587        else
588                TAILQ_INSERT_BEFORE(temp_ih, ih, ih_next);
589        intr_event_update(ie);
590
591        /* Create a thread if we need one. */
592        while (ie->ie_thread == NULL && handler != NULL) {
593                if (ie->ie_flags & IE_ADDING_THREAD)
594                        msleep(ie, &ie->ie_lock, 0, "ithread", 0);
595                else {
596                        ie->ie_flags |= IE_ADDING_THREAD;
597                        mtx_unlock(&ie->ie_lock);
598                        it = ithread_create("intr: newborn");
599                        mtx_lock(&ie->ie_lock);
600                        ie->ie_flags &= ~IE_ADDING_THREAD;
601                        ie->ie_thread = it;
602                        it->it_event = ie;
603                        ithread_update(it);
604                        wakeup(ie);
605                }
606        }
607        CTR3(KTR_INTR, "%s: added %s to %s", __func__, ih->ih_name,
608            ie->ie_name);
609        mtx_unlock(&ie->ie_lock);
610
611        if (cookiep != NULL)
612                *cookiep = ih;
613        return (0);
614}
615#else
616#ifndef __rtems__
617int
618intr_event_add_handler(struct intr_event *ie, const char *name,
619    driver_filter_t filter, driver_intr_t handler, void *arg, u_char pri,
620    enum intr_type flags, void **cookiep)
621{
622        struct intr_handler *ih, *temp_ih;
623        struct intr_thread *it;
624
625        if (ie == NULL || name == NULL || (handler == NULL && filter == NULL))
626                return (EINVAL);
627
628        /* Allocate and populate an interrupt handler structure. */
629        ih = malloc(sizeof(struct intr_handler), M_ITHREAD, M_WAITOK | M_ZERO);
630        ih->ih_filter = filter;
631        ih->ih_handler = handler;
632        ih->ih_argument = arg;
633        strlcpy(ih->ih_name, name, sizeof(ih->ih_name));
634        ih->ih_event = ie;
635        ih->ih_pri = pri;
636        if (flags & INTR_EXCL)
637                ih->ih_flags = IH_EXCLUSIVE;
638        if (flags & INTR_MPSAFE)
639                ih->ih_flags |= IH_MPSAFE;
640        if (flags & INTR_ENTROPY)
641                ih->ih_flags |= IH_ENTROPY;
642
643        /* We can only have one exclusive handler in a event. */
644        mtx_lock(&ie->ie_lock);
645        if (!TAILQ_EMPTY(&ie->ie_handlers)) {
646                if ((flags & INTR_EXCL) ||
647                    (TAILQ_FIRST(&ie->ie_handlers)->ih_flags & IH_EXCLUSIVE)) {
648                        mtx_unlock(&ie->ie_lock);
649                        free(ih, M_ITHREAD);
650                        return (EINVAL);
651                }
652        }
653
654        /* Add the new handler to the event in priority order. */
655        TAILQ_FOREACH(temp_ih, &ie->ie_handlers, ih_next) {
656                if (temp_ih->ih_pri > ih->ih_pri)
657                        break;
658        }
659        if (temp_ih == NULL)
660                TAILQ_INSERT_TAIL(&ie->ie_handlers, ih, ih_next);
661        else
662                TAILQ_INSERT_BEFORE(temp_ih, ih, ih_next);
663        intr_event_update(ie);
664
665        /* For filtered handlers, create a private ithread to run on. */
666        if (filter != NULL && handler != NULL) {
667                mtx_unlock(&ie->ie_lock);
668                it = ithread_create("intr: newborn", ih);               
669                mtx_lock(&ie->ie_lock);
670                it->it_event = ie;
671                ih->ih_thread = it;
672                ithread_update(it); // XXX - do we really need this?!?!?
673        } else { /* Create the global per-event thread if we need one. */
674                while (ie->ie_thread == NULL && handler != NULL) {
675                        if (ie->ie_flags & IE_ADDING_THREAD)
676                                msleep(ie, &ie->ie_lock, 0, "ithread", 0);
677                        else {
678                                ie->ie_flags |= IE_ADDING_THREAD;
679                                mtx_unlock(&ie->ie_lock);
680                                it = ithread_create("intr: newborn", ih);
681                                mtx_lock(&ie->ie_lock);
682                                ie->ie_flags &= ~IE_ADDING_THREAD;
683                                ie->ie_thread = it;
684                                it->it_event = ie;
685                                ithread_update(it);
686                                wakeup(ie);
687                        }
688                }
689        }
690        CTR3(KTR_INTR, "%s: added %s to %s", __func__, ih->ih_name,
691            ie->ie_name);
692        mtx_unlock(&ie->ie_lock);
693
694        if (cookiep != NULL)
695                *cookiep = ih;
696        return (0);
697}
698#endif /* __rtems__ */
699#endif
700
701#ifndef __rtems__
702/*
703 * Append a description preceded by a ':' to the name of the specified
704 * interrupt handler.
705 */
706int
707intr_event_describe_handler(struct intr_event *ie, void *cookie,
708    const char *descr)
709{
710        struct intr_handler *ih;
711        size_t space;
712        char *start;
713
714        mtx_lock(&ie->ie_lock);
715#ifdef INVARIANTS
716        TAILQ_FOREACH(ih, &ie->ie_handlers, ih_next) {
717                if (ih == cookie)
718                        break;
719        }
720        if (ih == NULL) {
721                mtx_unlock(&ie->ie_lock);
722                panic("handler %p not found in interrupt event %p", cookie, ie);
723        }
724#endif
725        ih = cookie;
726
727        /*
728         * Look for an existing description by checking for an
729         * existing ":".  This assumes device names do not include
730         * colons.  If one is found, prepare to insert the new
731         * description at that point.  If one is not found, find the
732         * end of the name to use as the insertion point.
733         */
734        start = index(ih->ih_name, ':');
735        if (start == NULL)
736                start = index(ih->ih_name, 0);
737
738        /*
739         * See if there is enough remaining room in the string for the
740         * description + ":".  The "- 1" leaves room for the trailing
741         * '\0'.  The "+ 1" accounts for the colon.
742         */
743        space = sizeof(ih->ih_name) - (start - ih->ih_name) - 1;
744        if (strlen(descr) + 1 > space) {
745                mtx_unlock(&ie->ie_lock);
746                return (ENOSPC);
747        }
748
749        /* Append a colon followed by the description. */
750        *start = ':';
751        strcpy(start + 1, descr);
752        intr_event_update(ie);
753        mtx_unlock(&ie->ie_lock);
754        return (0);
755}
756
757/*
758 * Return the ie_source field from the intr_event an intr_handler is
759 * associated with.
760 */
761void *
762intr_handler_source(void *cookie)
763{
764        struct intr_handler *ih;
765        struct intr_event *ie;
766
767        ih = (struct intr_handler *)cookie;
768        if (ih == NULL)
769                return (NULL);
770        ie = ih->ih_event;
771        KASSERT(ie != NULL,
772            ("interrupt handler \"%s\" has a NULL interrupt event",
773            ih->ih_name));
774        return (ie->ie_source);
775}
776
777#endif /* __rtems__ */
778#ifndef INTR_FILTER
779#ifndef __rtems__
780int
781intr_event_remove_handler(void *cookie)
782{
783        struct intr_handler *handler = (struct intr_handler *)cookie;
784        struct intr_event *ie;
785#ifdef INVARIANTS
786        struct intr_handler *ih;
787#endif
788#ifdef notyet
789        int dead;
790#endif
791
792        if (handler == NULL)
793                return (EINVAL);
794        ie = handler->ih_event;
795        KASSERT(ie != NULL,
796            ("interrupt handler \"%s\" has a NULL interrupt event",
797            handler->ih_name));
798        mtx_lock(&ie->ie_lock);
799        CTR3(KTR_INTR, "%s: removing %s from %s", __func__, handler->ih_name,
800            ie->ie_name);
801#ifdef INVARIANTS
802        TAILQ_FOREACH(ih, &ie->ie_handlers, ih_next)
803                if (ih == handler)
804                        goto ok;
805        mtx_unlock(&ie->ie_lock);
806        panic("interrupt handler \"%s\" not found in interrupt event \"%s\"",
807            ih->ih_name, ie->ie_name);
808ok:
809#endif
810        /*
811         * If there is no ithread, then just remove the handler and return.
812         * XXX: Note that an INTR_FAST handler might be running on another
813         * CPU!
814         */
815        if (ie->ie_thread == NULL) {
816                TAILQ_REMOVE(&ie->ie_handlers, handler, ih_next);
817                mtx_unlock(&ie->ie_lock);
818                free(handler, M_ITHREAD);
819                return (0);
820        }
821
822        /*
823         * If the interrupt thread is already running, then just mark this
824         * handler as being dead and let the ithread do the actual removal.
825         *
826         * During a cold boot while cold is set, msleep() does not sleep,
827         * so we have to remove the handler here rather than letting the
828         * thread do it.
829         */
830        thread_lock(ie->ie_thread->it_thread);
831        if (!TD_AWAITING_INTR(ie->ie_thread->it_thread) && !cold) {
832                handler->ih_flags |= IH_DEAD;
833
834                /*
835                 * Ensure that the thread will process the handler list
836                 * again and remove this handler if it has already passed
837                 * it on the list.
838                 */
839                ie->ie_thread->it_need = 1;
840        } else
841                TAILQ_REMOVE(&ie->ie_handlers, handler, ih_next);
842        thread_unlock(ie->ie_thread->it_thread);
843        while (handler->ih_flags & IH_DEAD)
844                msleep(handler, &ie->ie_lock, 0, "iev_rmh", 0);
845        intr_event_update(ie);
846#ifdef notyet
847        /*
848         * XXX: This could be bad in the case of ppbus(8).  Also, I think
849         * this could lead to races of stale data when servicing an
850         * interrupt.
851         */
852        dead = 1;
853        TAILQ_FOREACH(ih, &ie->ie_handlers, ih_next) {
854                if (!(ih->ih_flags & IH_FAST)) {
855                        dead = 0;
856                        break;
857                }
858        }
859        if (dead) {
860                ithread_destroy(ie->ie_thread);
861                ie->ie_thread = NULL;
862        }
863#endif
864        mtx_unlock(&ie->ie_lock);
865        free(handler, M_ITHREAD);
866        return (0);
867}
868
869#endif /* __rtems__ */
870static int
871intr_event_schedule_thread(struct intr_event *ie)
872{
873        struct intr_entropy entropy;
874        struct intr_thread *it;
875        struct thread *td;
876        struct thread *ctd;
877        struct proc *p;
878
879        /*
880         * If no ithread or no handlers, then we have a stray interrupt.
881         */
882        if (ie == NULL || TAILQ_EMPTY(&ie->ie_handlers) ||
883            ie->ie_thread == NULL)
884                return (EINVAL);
885
886        ctd = curthread;
887        it = ie->ie_thread;
888        td = it->it_thread;
889        p = td->td_proc;
890
891        /*
892         * If any of the handlers for this ithread claim to be good
893         * sources of entropy, then gather some.
894         */
895        if (harvest.interrupt && ie->ie_flags & IE_ENTROPY) {
896                CTR3(KTR_INTR, "%s: pid %d (%s) gathering entropy", __func__,
897                    p->p_pid, td->td_name);
898                entropy.event = (uintptr_t)ie;
899                entropy.td = ctd;
900                random_harvest(&entropy, sizeof(entropy), 2, 0,
901                    RANDOM_INTERRUPT);
902        }
903
904        KASSERT(p != NULL, ("ithread %s has no process", ie->ie_name));
905
906        /*
907         * Set it_need to tell the thread to keep running if it is already
908         * running.  Then, lock the thread and see if we actually need to
909         * put it on the runqueue.
910         */
911        it->it_need = 1;
912        thread_lock(td);
913#ifndef __rtems__
914        if (TD_AWAITING_INTR(td)) {
915                CTR3(KTR_INTR, "%s: schedule pid %d (%s)", __func__, p->p_pid,
916                    td->td_name);
917                TD_CLR_IWAIT(td);
918                sched_add(td, SRQ_INTR);
919        } else {
920                CTR5(KTR_INTR, "%s: pid %d (%s): it_need %d, state %d",
921                    __func__, p->p_pid, td->td_name, it->it_need, td->td_state);
922        }
923#else /* __rtems__ */
924        /* Send event to wake the thread up.
925         * TODO: eventually replace event by a better mechanism
926         */
927        rtems_status_code sc = rtems_event_send(td->td_id, RTEMSBSD_SWI_WAKEUP_EVENT);
928        BSD_ASSERT(sc == RTEMS_SUCCESSFUL);
929#endif /* __rtems__ */
930        thread_unlock(td);
931
932        return (0);
933}
934#else
935#ifndef __rtems__
936int
937intr_event_remove_handler(void *cookie)
938{
939        struct intr_handler *handler = (struct intr_handler *)cookie;
940        struct intr_event *ie;
941        struct intr_thread *it;
942#ifdef INVARIANTS
943        struct intr_handler *ih;
944#endif
945#ifdef notyet
946        int dead;
947#endif
948
949        if (handler == NULL)
950                return (EINVAL);
951        ie = handler->ih_event;
952        KASSERT(ie != NULL,
953            ("interrupt handler \"%s\" has a NULL interrupt event",
954            handler->ih_name));
955        mtx_lock(&ie->ie_lock);
956        CTR3(KTR_INTR, "%s: removing %s from %s", __func__, handler->ih_name,
957            ie->ie_name);
958#ifdef INVARIANTS
959        TAILQ_FOREACH(ih, &ie->ie_handlers, ih_next)
960                if (ih == handler)
961                        goto ok;
962        mtx_unlock(&ie->ie_lock);
963        panic("interrupt handler \"%s\" not found in interrupt event \"%s\"",
964            ih->ih_name, ie->ie_name);
965ok:
966#endif
967        /*
968         * If there are no ithreads (per event and per handler), then
969         * just remove the handler and return. 
970         * XXX: Note that an INTR_FAST handler might be running on another CPU!
971         */
972        if (ie->ie_thread == NULL && handler->ih_thread == NULL) {
973                TAILQ_REMOVE(&ie->ie_handlers, handler, ih_next);
974                mtx_unlock(&ie->ie_lock);
975                free(handler, M_ITHREAD);
976                return (0);
977        }
978
979        /* Private or global ithread? */
980        it = (handler->ih_thread) ? handler->ih_thread : ie->ie_thread;
981        /*
982         * If the interrupt thread is already running, then just mark this
983         * handler as being dead and let the ithread do the actual removal.
984         *
985         * During a cold boot while cold is set, msleep() does not sleep,
986         * so we have to remove the handler here rather than letting the
987         * thread do it.
988         */
989        thread_lock(it->it_thread);
990        if (!TD_AWAITING_INTR(it->it_thread) && !cold) {
991                handler->ih_flags |= IH_DEAD;
992
993                /*
994                 * Ensure that the thread will process the handler list
995                 * again and remove this handler if it has already passed
996                 * it on the list.
997                 */
998                it->it_need = 1;
999        } else
1000                TAILQ_REMOVE(&ie->ie_handlers, handler, ih_next);
1001        thread_unlock(it->it_thread);
1002        while (handler->ih_flags & IH_DEAD)
1003                msleep(handler, &ie->ie_lock, 0, "iev_rmh", 0);
1004        /*
1005         * At this point, the handler has been disconnected from the event,
1006         * so we can kill the private ithread if any.
1007         */
1008        if (handler->ih_thread) {
1009                ithread_destroy(handler->ih_thread);
1010                handler->ih_thread = NULL;
1011        }
1012        intr_event_update(ie);
1013#ifdef notyet
1014        /*
1015         * XXX: This could be bad in the case of ppbus(8).  Also, I think
1016         * this could lead to races of stale data when servicing an
1017         * interrupt.
1018         */
1019        dead = 1;
1020        TAILQ_FOREACH(ih, &ie->ie_handlers, ih_next) {
1021                if (handler != NULL) {
1022                        dead = 0;
1023                        break;
1024                }
1025        }
1026        if (dead) {
1027                ithread_destroy(ie->ie_thread);
1028                ie->ie_thread = NULL;
1029        }
1030#endif
1031        mtx_unlock(&ie->ie_lock);
1032        free(handler, M_ITHREAD);
1033        return (0);
1034}
1035
1036static int
1037intr_event_schedule_thread(struct intr_event *ie, struct intr_thread *it)
1038{
1039        struct intr_entropy entropy;
1040        struct thread *td;
1041        struct thread *ctd;
1042        struct proc *p;
1043
1044        /*
1045         * If no ithread or no handlers, then we have a stray interrupt.
1046         */
1047        if (ie == NULL || TAILQ_EMPTY(&ie->ie_handlers) || it == NULL)
1048                return (EINVAL);
1049
1050        ctd = curthread;
1051        td = it->it_thread;
1052        p = td->td_proc;
1053
1054        /*
1055         * If any of the handlers for this ithread claim to be good
1056         * sources of entropy, then gather some.
1057         */
1058        if (harvest.interrupt && ie->ie_flags & IE_ENTROPY) {
1059                CTR3(KTR_INTR, "%s: pid %d (%s) gathering entropy", __func__,
1060                    p->p_pid, td->td_name);
1061                entropy.event = (uintptr_t)ie;
1062                entropy.td = ctd;
1063                random_harvest(&entropy, sizeof(entropy), 2, 0,
1064                    RANDOM_INTERRUPT);
1065        }
1066
1067        KASSERT(p != NULL, ("ithread %s has no process", ie->ie_name));
1068
1069        /*
1070         * Set it_need to tell the thread to keep running if it is already
1071         * running.  Then, lock the thread and see if we actually need to
1072         * put it on the runqueue.
1073         */
1074        it->it_need = 1;
1075        thread_lock(td);
1076        if (TD_AWAITING_INTR(td)) {
1077                CTR3(KTR_INTR, "%s: schedule pid %d (%s)", __func__, p->p_pid,
1078                    td->td_name);
1079                TD_CLR_IWAIT(td);
1080                sched_add(td, SRQ_INTR);
1081        } else {
1082                CTR5(KTR_INTR, "%s: pid %d (%s): it_need %d, state %d",
1083                    __func__, p->p_pid, td->td_name, it->it_need, td->td_state);
1084        }
1085        thread_unlock(td);
1086
1087        return (0);
1088}
1089#endif /* __rtems__ */
1090#endif
1091
1092/*
1093 * Allow interrupt event binding for software interrupt handlers -- a no-op,
1094 * since interrupts are generated in software rather than being directed by
1095 * a PIC.
1096 */
1097static int
1098swi_assign_cpu(void *arg, u_char cpu)
1099{
1100
1101        return (0);
1102}
1103
1104/*
1105 * Add a software interrupt handler to a specified event.  If a given event
1106 * is not specified, then a new event is created.
1107 */
1108int
1109swi_add(struct intr_event **eventp, const char *name, driver_intr_t handler,
1110            void *arg, int pri, enum intr_type flags, void **cookiep)
1111{
1112        struct intr_event *ie;
1113        int error;
1114
1115        if (flags & INTR_ENTROPY)
1116                return (EINVAL);
1117
1118        ie = (eventp != NULL) ? *eventp : NULL;
1119
1120        if (ie != NULL) {
1121                if (!(ie->ie_flags & IE_SOFT))
1122                        return (EINVAL);
1123        } else {
1124                error = intr_event_create(&ie, NULL, IE_SOFT, 0,
1125                    NULL, NULL, NULL, swi_assign_cpu, "swi%d:", pri);
1126                if (error)
1127                        return (error);
1128                if (eventp != NULL)
1129                        *eventp = ie;
1130        }
1131        error = intr_event_add_handler(ie, name, NULL, handler, arg,
1132            (pri * RQ_PPQ) + PI_SOFT, flags, cookiep);
1133        if (error)
1134                return (error);
1135#ifndef __rtems__
1136        if (pri == SWI_CLOCK) {
1137                struct proc *p;
1138                p = ie->ie_thread->it_thread->td_proc;
1139                PROC_LOCK(p);
1140                p->p_flag |= P_NOLOAD;
1141                PROC_UNLOCK(p);
1142        }
1143#else /* __rtems__ */
1144        // Do _not_ ignore the thread in the load avarage
1145#endif /* __rtems__ */
1146        return (0);
1147}
1148
1149/*
1150 * Schedule a software interrupt thread.
1151 */
1152void
1153swi_sched(void *cookie, int flags)
1154{
1155        struct intr_handler *ih = (struct intr_handler *)cookie;
1156        struct intr_event *ie = ih->ih_event;
1157        int error;
1158
1159        CTR3(KTR_INTR, "swi_sched: %s %s need=%d", ie->ie_name, ih->ih_name,
1160            ih->ih_need);
1161
1162        /*
1163         * Set ih_need for this handler so that if the ithread is already
1164         * running it will execute this handler on the next pass.  Otherwise,
1165         * it will execute it the next time it runs.
1166         */
1167        atomic_store_rel_int(&ih->ih_need, 1);
1168
1169        if (!(flags & SWI_DELAY)) {
1170#ifndef __rtems__
1171                PCPU_INC(cnt.v_soft);
1172#endif /* __rtems__ */
1173#ifdef INTR_FILTER
1174                error = intr_event_schedule_thread(ie, ie->ie_thread);
1175#else
1176                error = intr_event_schedule_thread(ie);
1177#endif
1178                KASSERT(error == 0, ("stray software interrupt"));
1179        }
1180}
1181
1182#ifndef __rtems__
1183/*
1184 * Remove a software interrupt handler.  Currently this code does not
1185 * remove the associated interrupt event if it becomes empty.  Calling code
1186 * may do so manually via intr_event_destroy(), but that's not really
1187 * an optimal interface.
1188 */
1189int
1190swi_remove(void *cookie)
1191{
1192
1193        return (intr_event_remove_handler(cookie));
1194}
1195
1196#ifdef INTR_FILTER
1197static void
1198priv_ithread_execute_handler(struct proc *p, struct intr_handler *ih)
1199{
1200        struct intr_event *ie;
1201
1202        ie = ih->ih_event;
1203        /*
1204         * If this handler is marked for death, remove it from
1205         * the list of handlers and wake up the sleeper.
1206         */
1207        if (ih->ih_flags & IH_DEAD) {
1208                mtx_lock(&ie->ie_lock);
1209                TAILQ_REMOVE(&ie->ie_handlers, ih, ih_next);
1210                ih->ih_flags &= ~IH_DEAD;
1211                wakeup(ih);
1212                mtx_unlock(&ie->ie_lock);
1213                return;
1214        }
1215       
1216        /* Execute this handler. */
1217        CTR6(KTR_INTR, "%s: pid %d exec %p(%p) for %s flg=%x",
1218             __func__, p->p_pid, (void *)ih->ih_handler, ih->ih_argument,
1219             ih->ih_name, ih->ih_flags);
1220       
1221        if (!(ih->ih_flags & IH_MPSAFE))
1222                mtx_lock(&Giant);
1223        ih->ih_handler(ih->ih_argument);
1224        if (!(ih->ih_flags & IH_MPSAFE))
1225                mtx_unlock(&Giant);
1226}
1227#endif
1228
1229#endif /* __rtems__ */
1230/*
1231 * This is a public function for use by drivers that mux interrupt
1232 * handlers for child devices from their interrupt handler.
1233 */
1234void
1235intr_event_execute_handlers(struct proc *p, struct intr_event *ie)
1236{
1237        struct intr_handler *ih, *ihn;
1238
1239        TAILQ_FOREACH_SAFE(ih, &ie->ie_handlers, ih_next, ihn) {
1240                /*
1241                 * If this handler is marked for death, remove it from
1242                 * the list of handlers and wake up the sleeper.
1243                 */
1244                if (ih->ih_flags & IH_DEAD) {
1245                        mtx_lock(&ie->ie_lock);
1246                        TAILQ_REMOVE(&ie->ie_handlers, ih, ih_next);
1247                        ih->ih_flags &= ~IH_DEAD;
1248                        wakeup(ih);
1249                        mtx_unlock(&ie->ie_lock);
1250                        continue;
1251                }
1252
1253                /* Skip filter only handlers */
1254                if (ih->ih_handler == NULL)
1255                        continue;
1256
1257                /*
1258                 * For software interrupt threads, we only execute
1259                 * handlers that have their need flag set.  Hardware
1260                 * interrupt threads always invoke all of their handlers.
1261                 */
1262                if (ie->ie_flags & IE_SOFT) {
1263                        if (!ih->ih_need)
1264                                continue;
1265                        else
1266                                atomic_store_rel_int(&ih->ih_need, 0);
1267                }
1268
1269                /* Execute this handler. */
1270                CTR6(KTR_INTR, "%s: pid %d exec %p(%p) for %s flg=%x",
1271                    __func__, p->p_pid, (void *)ih->ih_handler,
1272                    ih->ih_argument, ih->ih_name, ih->ih_flags);
1273
1274                if (!(ih->ih_flags & IH_MPSAFE))
1275                        mtx_lock(&Giant);
1276                ih->ih_handler(ih->ih_argument);
1277                if (!(ih->ih_flags & IH_MPSAFE))
1278                        mtx_unlock(&Giant);
1279        }
1280}
1281
1282static void
1283ithread_execute_handlers(struct proc *p, struct intr_event *ie)
1284{
1285
1286#ifndef __rtems__
1287        /* Interrupt handlers should not sleep. */
1288        if (!(ie->ie_flags & IE_SOFT))
1289                THREAD_NO_SLEEPING();
1290        intr_event_execute_handlers(p, ie);
1291        if (!(ie->ie_flags & IE_SOFT))
1292                THREAD_SLEEPING_OK();
1293#else /* __rtems__ */
1294        /* We only have soft-threads, so the two queries are not necessary. */
1295        intr_event_execute_handlers(p, ie);
1296#endif /* __rtems__ */
1297
1298        /*
1299         * Interrupt storm handling:
1300         *
1301         * If this interrupt source is currently storming, then throttle
1302         * it to only fire the handler once  per clock tick.
1303         *
1304         * If this interrupt source is not currently storming, but the
1305         * number of back to back interrupts exceeds the storm threshold,
1306         * then enter storming mode.
1307         */
1308        if (intr_storm_threshold != 0 && ie->ie_count >= intr_storm_threshold &&
1309            !(ie->ie_flags & IE_SOFT)) {
1310#ifndef __rtems__
1311                /* Report the message only once every second. */
1312                if (ppsratecheck(&ie->ie_warntm, &ie->ie_warncnt, 1)) {
1313                        printf(
1314        "interrupt storm detected on \"%s\"; throttling interrupt source\n",
1315                            ie->ie_name);
1316                }
1317#endif /* __rtems__ */
1318                pause("istorm", 1);
1319        } else
1320                ie->ie_count++;
1321
1322        /*
1323         * Now that all the handlers have had a chance to run, reenable
1324         * the interrupt source.
1325         */
1326        if (ie->ie_post_ithread != NULL)
1327                ie->ie_post_ithread(ie->ie_source);
1328}
1329
1330#ifndef INTR_FILTER
1331/*
1332 * This is the main code for interrupt threads.
1333 */
1334static void
1335ithread_loop(void *arg)
1336{
1337        struct intr_thread *ithd;
1338        struct intr_event *ie;
1339        struct thread *td;
1340        struct proc *p;
1341
1342        td = curthread;
1343        p = td->td_proc;
1344        ithd = (struct intr_thread *)arg;
1345        KASSERT(ithd->it_thread == td,
1346            ("%s: ithread and proc linkage out of sync", __func__));
1347        ie = ithd->it_event;
1348        ie->ie_count = 0;
1349
1350        /*
1351         * As long as we have interrupts outstanding, go through the
1352         * list of handlers, giving each one a go at it.
1353         */
1354        for (;;) {
1355                /*
1356                 * If we are an orphaned thread, then just die.
1357                 */
1358                if (ithd->it_flags & IT_DEAD) {
1359                        CTR3(KTR_INTR, "%s: pid %d (%s) exiting", __func__,
1360                            p->p_pid, td->td_name);
1361                        free(ithd, M_ITHREAD);
1362                        kthread_exit();
1363                }
1364
1365                /*
1366                 * Service interrupts.  If another interrupt arrives while
1367                 * we are running, it will set it_need to note that we
1368                 * should make another pass.
1369                 */
1370                while (ithd->it_need) {
1371                        /*
1372                         * This might need a full read and write barrier
1373                         * to make sure that this write posts before any
1374                         * of the memory or device accesses in the
1375                         * handlers.
1376                         */
1377                        atomic_store_rel_int(&ithd->it_need, 0);
1378                        ithread_execute_handlers(p, ie);
1379                }
1380                WITNESS_WARN(WARN_PANIC, NULL, "suspending ithread");
1381                mtx_assert(&Giant, MA_NOTOWNED);
1382
1383                /*
1384                 * Processed all our interrupts.  Now get the sched
1385                 * lock.  This may take a while and it_need may get
1386                 * set again, so we have to check it again.
1387                 */
1388                thread_lock(td);
1389                if (!ithd->it_need && !(ithd->it_flags & IT_DEAD)) {
1390#ifndef __rtems__
1391                        TD_SET_IWAIT(td);
1392                        ie->ie_count = 0;
1393                        mi_switch(SW_VOL | SWT_IWAIT, NULL);
1394#else /* __rtems__ */
1395                        /* wait for wakeup event
1396                         * TODO: eventually replace event by a better mechanism
1397                         */
1398                        rtems_event_set event_out;
1399                        rtems_status_code sc = rtems_event_receive(
1400                                RTEMSBSD_SWI_WAKEUP_EVENT,
1401                                RTEMS_WAIT | RTEMS_EVENT_ALL,
1402                                RTEMS_NO_TIMEOUT,
1403                                &event_out);
1404                        BSD_ASSERT(sc == RTEMS_SUCCESSFUL);
1405#endif /* __rtems__ */
1406                }
1407                thread_unlock(td);
1408        }
1409}
1410#ifndef __rtems__
1411
1412/*
1413 * Main interrupt handling body.
1414 *
1415 * Input:
1416 * o ie:                        the event connected to this interrupt.
1417 * o frame:                     some archs (i.e. i386) pass a frame to some.
1418 *                              handlers as their main argument.
1419 * Return value:
1420 * o 0:                         everything ok.
1421 * o EINVAL:                    stray interrupt.
1422 */
1423int
1424intr_event_handle(struct intr_event *ie, struct trapframe *frame)
1425{
1426        struct intr_handler *ih;
1427        struct thread *td;
1428        int error, ret, thread;
1429
1430        td = curthread;
1431
1432        /* An interrupt with no event or handlers is a stray interrupt. */
1433        if (ie == NULL || TAILQ_EMPTY(&ie->ie_handlers))
1434                return (EINVAL);
1435
1436        /*
1437         * Execute fast interrupt handlers directly.
1438         * To support clock handlers, if a handler registers
1439         * with a NULL argument, then we pass it a pointer to
1440         * a trapframe as its argument.
1441         */
1442        td->td_intr_nesting_level++;
1443        thread = 0;
1444        ret = 0;
1445        critical_enter();
1446        TAILQ_FOREACH(ih, &ie->ie_handlers, ih_next) {
1447                if (ih->ih_filter == NULL) {
1448                        thread = 1;
1449                        continue;
1450                }
1451                CTR4(KTR_INTR, "%s: exec %p(%p) for %s", __func__,
1452                    ih->ih_filter, ih->ih_argument == NULL ? frame :
1453                    ih->ih_argument, ih->ih_name);
1454                if (ih->ih_argument == NULL)
1455                        ret = ih->ih_filter(frame);
1456                else
1457                        ret = ih->ih_filter(ih->ih_argument);
1458                KASSERT(ret == FILTER_STRAY ||
1459                    ((ret & (FILTER_SCHEDULE_THREAD | FILTER_HANDLED)) != 0 &&
1460                    (ret & ~(FILTER_SCHEDULE_THREAD | FILTER_HANDLED)) == 0),
1461                    ("%s: incorrect return value %#x from %s", __func__, ret,
1462                    ih->ih_name));
1463
1464                /*
1465                 * Wrapper handler special handling:
1466                 *
1467                 * in some particular cases (like pccard and pccbb),
1468                 * the _real_ device handler is wrapped in a couple of
1469                 * functions - a filter wrapper and an ithread wrapper.
1470                 * In this case (and just in this case), the filter wrapper
1471                 * could ask the system to schedule the ithread and mask
1472                 * the interrupt source if the wrapped handler is composed
1473                 * of just an ithread handler.
1474                 *
1475                 * TODO: write a generic wrapper to avoid people rolling
1476                 * their own
1477                 */
1478                if (!thread) {
1479                        if (ret == FILTER_SCHEDULE_THREAD)
1480                                thread = 1;
1481                }
1482        }
1483
1484        if (thread) {
1485                if (ie->ie_pre_ithread != NULL)
1486                        ie->ie_pre_ithread(ie->ie_source);
1487        } else {
1488                if (ie->ie_post_filter != NULL)
1489                        ie->ie_post_filter(ie->ie_source);
1490        }
1491       
1492        /* Schedule the ithread if needed. */
1493        if (thread) {
1494                error = intr_event_schedule_thread(ie);
1495#ifndef XEN             
1496                KASSERT(error == 0, ("bad stray interrupt"));
1497#else
1498                if (error != 0)
1499                        log(LOG_WARNING, "bad stray interrupt");
1500#endif         
1501        }
1502        critical_exit();
1503        td->td_intr_nesting_level--;
1504        return (0);
1505}
1506#endif /* __rtems__ */
1507#else
1508#ifndef __rtems__
1509/*
1510 * This is the main code for interrupt threads.
1511 */
1512static void
1513ithread_loop(void *arg)
1514{
1515        struct intr_thread *ithd;
1516        struct intr_handler *ih;
1517        struct intr_event *ie;
1518        struct thread *td;
1519        struct proc *p;
1520        int priv;
1521
1522        td = curthread;
1523        p = td->td_proc;
1524        ih = (struct intr_handler *)arg;
1525        priv = (ih->ih_thread != NULL) ? 1 : 0;
1526        ithd = (priv) ? ih->ih_thread : ih->ih_event->ie_thread;
1527        KASSERT(ithd->it_thread == td,
1528            ("%s: ithread and proc linkage out of sync", __func__));
1529        ie = ithd->it_event;
1530        ie->ie_count = 0;
1531
1532        /*
1533         * As long as we have interrupts outstanding, go through the
1534         * list of handlers, giving each one a go at it.
1535         */
1536        for (;;) {
1537                /*
1538                 * If we are an orphaned thread, then just die.
1539                 */
1540                if (ithd->it_flags & IT_DEAD) {
1541                        CTR3(KTR_INTR, "%s: pid %d (%s) exiting", __func__,
1542                            p->p_pid, td->td_name);
1543                        free(ithd, M_ITHREAD);
1544                        kthread_exit();
1545                }
1546
1547                /*
1548                 * Service interrupts.  If another interrupt arrives while
1549                 * we are running, it will set it_need to note that we
1550                 * should make another pass.
1551                 */
1552                while (ithd->it_need) {
1553                        /*
1554                         * This might need a full read and write barrier
1555                         * to make sure that this write posts before any
1556                         * of the memory or device accesses in the
1557                         * handlers.
1558                         */
1559                        atomic_store_rel_int(&ithd->it_need, 0);
1560                        if (priv)
1561                                priv_ithread_execute_handler(p, ih);
1562                        else
1563                                ithread_execute_handlers(p, ie);
1564                }
1565                WITNESS_WARN(WARN_PANIC, NULL, "suspending ithread");
1566                mtx_assert(&Giant, MA_NOTOWNED);
1567
1568                /*
1569                 * Processed all our interrupts.  Now get the sched
1570                 * lock.  This may take a while and it_need may get
1571                 * set again, so we have to check it again.
1572                 */
1573                thread_lock(td);
1574                if (!ithd->it_need && !(ithd->it_flags & IT_DEAD)) {
1575                        TD_SET_IWAIT(td);
1576                        ie->ie_count = 0;
1577                        mi_switch(SW_VOL | SWT_IWAIT, NULL);
1578                }
1579                thread_unlock(td);
1580        }
1581}
1582
1583/*
1584 * Main loop for interrupt filter.
1585 *
1586 * Some architectures (i386, amd64 and arm) require the optional frame
1587 * parameter, and use it as the main argument for fast handler execution
1588 * when ih_argument == NULL.
1589 *
1590 * Return value:
1591 * o FILTER_STRAY:              No filter recognized the event, and no
1592 *                              filter-less handler is registered on this
1593 *                              line.
1594 * o FILTER_HANDLED:            A filter claimed the event and served it.
1595 * o FILTER_SCHEDULE_THREAD:    No filter claimed the event, but there's at
1596 *                              least one filter-less handler on this line.
1597 * o FILTER_HANDLED |
1598 *   FILTER_SCHEDULE_THREAD:    A filter claimed the event, and asked for
1599 *                              scheduling the per-handler ithread.
1600 *
1601 * In case an ithread has to be scheduled, in *ithd there will be a
1602 * pointer to a struct intr_thread containing the thread to be
1603 * scheduled.
1604 */
1605
1606static int
1607intr_filter_loop(struct intr_event *ie, struct trapframe *frame,
1608                 struct intr_thread **ithd)
1609{
1610        struct intr_handler *ih;
1611        void *arg;
1612        int ret, thread_only;
1613
1614        ret = 0;
1615        thread_only = 0;
1616        TAILQ_FOREACH(ih, &ie->ie_handlers, ih_next) {
1617                /*
1618                 * Execute fast interrupt handlers directly.
1619                 * To support clock handlers, if a handler registers
1620                 * with a NULL argument, then we pass it a pointer to
1621                 * a trapframe as its argument.
1622                 */
1623                arg = ((ih->ih_argument == NULL) ? frame : ih->ih_argument);
1624               
1625                CTR5(KTR_INTR, "%s: exec %p/%p(%p) for %s", __func__,
1626                     ih->ih_filter, ih->ih_handler, arg, ih->ih_name);
1627
1628                if (ih->ih_filter != NULL)
1629                        ret = ih->ih_filter(arg);
1630                else {
1631                        thread_only = 1;
1632                        continue;
1633                }
1634                KASSERT(ret == FILTER_STRAY ||
1635                    ((ret & (FILTER_SCHEDULE_THREAD | FILTER_HANDLED)) != 0 &&
1636                    (ret & ~(FILTER_SCHEDULE_THREAD | FILTER_HANDLED)) == 0),
1637                    ("%s: incorrect return value %#x from %s", __func__, ret,
1638                    ih->ih_name));
1639                if (ret & FILTER_STRAY)
1640                        continue;
1641                else {
1642                        *ithd = ih->ih_thread;
1643                        return (ret);
1644                }
1645        }
1646
1647        /*
1648         * No filters handled the interrupt and we have at least
1649         * one handler without a filter.  In this case, we schedule
1650         * all of the filter-less handlers to run in the ithread.
1651         */     
1652        if (thread_only) {
1653                *ithd = ie->ie_thread;
1654                return (FILTER_SCHEDULE_THREAD);
1655        }
1656        return (FILTER_STRAY);
1657}
1658
1659/*
1660 * Main interrupt handling body.
1661 *
1662 * Input:
1663 * o ie:                        the event connected to this interrupt.
1664 * o frame:                     some archs (i.e. i386) pass a frame to some.
1665 *                              handlers as their main argument.
1666 * Return value:
1667 * o 0:                         everything ok.
1668 * o EINVAL:                    stray interrupt.
1669 */
1670int
1671intr_event_handle(struct intr_event *ie, struct trapframe *frame)
1672{
1673        struct intr_thread *ithd;
1674        struct thread *td;
1675        int thread;
1676
1677        ithd = NULL;
1678        td = curthread;
1679
1680        if (ie == NULL || TAILQ_EMPTY(&ie->ie_handlers))
1681                return (EINVAL);
1682
1683        td->td_intr_nesting_level++;
1684        thread = 0;
1685        critical_enter();
1686        thread = intr_filter_loop(ie, frame, &ithd);   
1687        if (thread & FILTER_HANDLED) {
1688                if (ie->ie_post_filter != NULL)
1689                        ie->ie_post_filter(ie->ie_source);
1690        } else {
1691                if (ie->ie_pre_ithread != NULL)
1692                        ie->ie_pre_ithread(ie->ie_source);
1693        }
1694        critical_exit();
1695       
1696        /* Interrupt storm logic */
1697        if (thread & FILTER_STRAY) {
1698                ie->ie_count++;
1699                if (ie->ie_count < intr_storm_threshold)
1700                        printf("Interrupt stray detection not present\n");
1701        }
1702
1703        /* Schedule an ithread if needed. */
1704        if (thread & FILTER_SCHEDULE_THREAD) {
1705                if (intr_event_schedule_thread(ie, ithd) != 0)
1706                        panic("%s: impossible stray interrupt", __func__);
1707        }
1708        td->td_intr_nesting_level--;
1709        return (0);
1710}
1711#endif /* __rtems__ */
1712#endif
1713#ifndef __rtems__
1714
1715#ifdef DDB
1716/*
1717 * Dump details about an interrupt handler
1718 */
1719static void
1720db_dump_intrhand(struct intr_handler *ih)
1721{
1722        int comma;
1723
1724        db_printf("\t%-10s ", ih->ih_name);
1725        switch (ih->ih_pri) {
1726        case PI_REALTIME:
1727                db_printf("CLK ");
1728                break;
1729        case PI_AV:
1730                db_printf("AV  ");
1731                break;
1732        case PI_TTYHIGH:
1733        case PI_TTYLOW:
1734                db_printf("TTY ");
1735                break;
1736        case PI_TAPE:
1737                db_printf("TAPE");
1738                break;
1739        case PI_NET:
1740                db_printf("NET ");
1741                break;
1742        case PI_DISK:
1743        case PI_DISKLOW:
1744                db_printf("DISK");
1745                break;
1746        case PI_DULL:
1747                db_printf("DULL");
1748                break;
1749        default:
1750                if (ih->ih_pri >= PI_SOFT)
1751                        db_printf("SWI ");
1752                else
1753                        db_printf("%4u", ih->ih_pri);
1754                break;
1755        }
1756        db_printf(" ");
1757        db_printsym((uintptr_t)ih->ih_handler, DB_STGY_PROC);
1758        db_printf("(%p)", ih->ih_argument);
1759        if (ih->ih_need ||
1760            (ih->ih_flags & (IH_EXCLUSIVE | IH_ENTROPY | IH_DEAD |
1761            IH_MPSAFE)) != 0) {
1762                db_printf(" {");
1763                comma = 0;
1764                if (ih->ih_flags & IH_EXCLUSIVE) {
1765                        if (comma)
1766                                db_printf(", ");
1767                        db_printf("EXCL");
1768                        comma = 1;
1769                }
1770                if (ih->ih_flags & IH_ENTROPY) {
1771                        if (comma)
1772                                db_printf(", ");
1773                        db_printf("ENTROPY");
1774                        comma = 1;
1775                }
1776                if (ih->ih_flags & IH_DEAD) {
1777                        if (comma)
1778                                db_printf(", ");
1779                        db_printf("DEAD");
1780                        comma = 1;
1781                }
1782                if (ih->ih_flags & IH_MPSAFE) {
1783                        if (comma)
1784                                db_printf(", ");
1785                        db_printf("MPSAFE");
1786                        comma = 1;
1787                }
1788                if (ih->ih_need) {
1789                        if (comma)
1790                                db_printf(", ");
1791                        db_printf("NEED");
1792                }
1793                db_printf("}");
1794        }
1795        db_printf("\n");
1796}
1797
1798/*
1799 * Dump details about a event.
1800 */
1801void
1802db_dump_intr_event(struct intr_event *ie, int handlers)
1803{
1804        struct intr_handler *ih;
1805        struct intr_thread *it;
1806        int comma;
1807
1808        db_printf("%s ", ie->ie_fullname);
1809        it = ie->ie_thread;
1810        if (it != NULL)
1811                db_printf("(pid %d)", it->it_thread->td_proc->p_pid);
1812        else
1813                db_printf("(no thread)");
1814        if ((ie->ie_flags & (IE_SOFT | IE_ENTROPY | IE_ADDING_THREAD)) != 0 ||
1815            (it != NULL && it->it_need)) {
1816                db_printf(" {");
1817                comma = 0;
1818                if (ie->ie_flags & IE_SOFT) {
1819                        db_printf("SOFT");
1820                        comma = 1;
1821                }
1822                if (ie->ie_flags & IE_ENTROPY) {
1823                        if (comma)
1824                                db_printf(", ");
1825                        db_printf("ENTROPY");
1826                        comma = 1;
1827                }
1828                if (ie->ie_flags & IE_ADDING_THREAD) {
1829                        if (comma)
1830                                db_printf(", ");
1831                        db_printf("ADDING_THREAD");
1832                        comma = 1;
1833                }
1834                if (it != NULL && it->it_need) {
1835                        if (comma)
1836                                db_printf(", ");
1837                        db_printf("NEED");
1838                }
1839                db_printf("}");
1840        }
1841        db_printf("\n");
1842
1843        if (handlers)
1844                TAILQ_FOREACH(ih, &ie->ie_handlers, ih_next)
1845                    db_dump_intrhand(ih);
1846}
1847
1848/*
1849 * Dump data about interrupt handlers
1850 */
1851DB_SHOW_COMMAND(intr, db_show_intr)
1852{
1853        struct intr_event *ie;
1854        int all, verbose;
1855
1856        verbose = index(modif, 'v') != NULL;
1857        all = index(modif, 'a') != NULL;
1858        TAILQ_FOREACH(ie, &event_list, ie_list) {
1859                if (!all && TAILQ_EMPTY(&ie->ie_handlers))
1860                        continue;
1861                db_dump_intr_event(ie, verbose);
1862                if (db_pager_quit)
1863                        break;
1864        }
1865}
1866#endif /* DDB */
1867
1868/*
1869 * Start standard software interrupt threads
1870 */
1871static void
1872start_softintr(void *dummy)
1873{
1874
1875        if (swi_add(NULL, "vm", swi_vm, NULL, SWI_VM, INTR_MPSAFE, &vm_ih))
1876                panic("died while creating vm swi ithread");
1877}
1878SYSINIT(start_softintr, SI_SUB_SOFTINTR, SI_ORDER_FIRST, start_softintr,
1879    NULL);
1880
1881/*
1882 * Sysctls used by systat and others: hw.intrnames and hw.intrcnt.
1883 * The data for this machine dependent, and the declarations are in machine
1884 * dependent code.  The layout of intrnames and intrcnt however is machine
1885 * independent.
1886 *
1887 * We do not know the length of intrcnt and intrnames at compile time, so
1888 * calculate things at run time.
1889 */
1890static int
1891sysctl_intrnames(SYSCTL_HANDLER_ARGS)
1892{
1893        return (sysctl_handle_opaque(oidp, intrnames, eintrnames - intrnames,
1894           req));
1895}
1896
1897SYSCTL_PROC(_hw, OID_AUTO, intrnames, CTLTYPE_OPAQUE | CTLFLAG_RD,
1898    NULL, 0, sysctl_intrnames, "", "Interrupt Names");
1899
1900static int
1901sysctl_intrcnt(SYSCTL_HANDLER_ARGS)
1902{
1903        return (sysctl_handle_opaque(oidp, intrcnt,
1904            (char *)eintrcnt - (char *)intrcnt, req));
1905}
1906
1907SYSCTL_PROC(_hw, OID_AUTO, intrcnt, CTLTYPE_OPAQUE | CTLFLAG_RD,
1908    NULL, 0, sysctl_intrcnt, "", "Interrupt Counts");
1909
1910#ifdef DDB
1911/*
1912 * DDB command to dump the interrupt statistics.
1913 */
1914DB_SHOW_COMMAND(intrcnt, db_show_intrcnt)
1915{
1916        u_long *i;
1917        char *cp;
1918
1919        cp = intrnames;
1920        for (i = intrcnt; i != eintrcnt && !db_pager_quit; i++) {
1921                if (*cp == '\0')
1922                        break;
1923                if (*i != 0)
1924                        db_printf("%s\t%lu\n", cp, *i);
1925                cp += strlen(cp) + 1;
1926        }
1927}
1928#endif
1929#endif /* __rtems__ */
Note: See TracBrowser for help on using the repository browser.