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

4.1155-freebsd-126-freebsd-12freebsd-9.3
Last change on this file since d558a43 was d558a43, checked in by Jennifer Averett <jennifer.averett@…>, on 04/17/12 at 14:38:54

Added methods to resolve linker errors.

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