The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/sparc64/sparc64/intr_machdep.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 1991 The Regents of the University of California.
    3  * All rights reserved.
    4  *
    5  * This code is derived from software contributed to Berkeley by
    6  * William Jolitz.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following 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  * 4. Neither the name of the University nor the names of its contributors
   17  *    may be used to endorse or promote products derived from this software
   18  *    without specific prior written permission.
   19  *
   20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   30  * SUCH DAMAGE.
   31  */
   32 /*-
   33  * Copyright (c) 2001 Jake Burkholder.
   34  * All rights reserved.
   35  *
   36  * Redistribution and use in source and binary forms, with or without
   37  * modification, are permitted provided that the following conditions
   38  * are met:
   39  * 1. Redistributions of source code must retain the above copyright
   40  *    notice, this list of conditions and the following disclaimer.
   41  * 2. Redistributions in binary form must reproduce the above copyright
   42  *    notice, this list of conditions and the following disclaimer in the
   43  *    documentation and/or other materials provided with the distribution.
   44  *
   45  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   46  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   47  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   48  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   49  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   50  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   51  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   52  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   53  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   54  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   55  * SUCH DAMAGE.
   56  *
   57  *      from: @(#)isa.c 7.2 (Berkeley) 5/13/91
   58  *      form: src/sys/i386/isa/intr_machdep.c,v 1.57 2001/07/20
   59  */
   60 
   61 #include <sys/cdefs.h>
   62 __FBSDID("$FreeBSD$");
   63 
   64 #include <sys/param.h>
   65 #include <sys/systm.h>
   66 #include <sys/queue.h>
   67 #include <sys/bus.h>
   68 #include <sys/errno.h>
   69 #include <sys/interrupt.h>
   70 #include <sys/ktr.h>
   71 #include <sys/lock.h>
   72 #include <sys/mutex.h>
   73 #include <sys/pcpu.h>
   74 #include <sys/proc.h>
   75 #include <sys/vmmeter.h>
   76 
   77 #include <machine/frame.h>
   78 #include <machine/intr_machdep.h>
   79 
   80 #define MAX_STRAY_LOG   5
   81 
   82 CTASSERT((1 << IV_SHIFT) == sizeof(struct intr_vector));
   83 
   84 ih_func_t *intr_handlers[PIL_MAX];
   85 uint16_t pil_countp[PIL_MAX];
   86 
   87 struct intr_vector intr_vectors[IV_MAX];
   88 uint16_t intr_countp[IV_MAX];
   89 static u_long intr_stray_count[IV_MAX];
   90 
   91 static const char *pil_names[] = {
   92         "stray",
   93         "low",          /* PIL_LOW */
   94         "ithrd",        /* PIL_ITHREAD */
   95         "rndzvs",       /* PIL_RENDEZVOUS */
   96         "ast",          /* PIL_AST */
   97         "stop",         /* PIL_STOP */
   98         "stray", "stray", "stray", "stray", "stray", "stray", "stray",
   99         "fast",         /* PIL_FAST */
  100         "tick",         /* PIL_TICK */
  101 };
  102 
  103 /* protect the intr_vectors table */
  104 static struct mtx intr_table_lock;
  105 
  106 static void intr_enable_eoi(void *);
  107 static void intr_execute_handlers(void *);
  108 static void intr_stray_level(struct trapframe *);
  109 static void intr_stray_vector(void *);
  110 static int intrcnt_setname(const char *, int);
  111 static void intrcnt_updatename(int, const char *, int);
  112 
  113 /*
  114  * not MPSAFE
  115  */
  116 static void
  117 intrcnt_updatename(int vec, const char *name, int ispil)
  118 {
  119         static int intrcnt_index, stray_pil_index, stray_vec_index;
  120         int name_index;
  121 
  122         if (intrnames[0] == '\0') {
  123                 /* for bitbucket */
  124                 if (bootverbose)
  125                         printf("initalizing intr_countp\n");
  126                 intrcnt_setname("???", intrcnt_index++);
  127 
  128                 stray_vec_index = intrcnt_index++;
  129                 intrcnt_setname("stray", stray_vec_index);
  130                 for (name_index = 0; name_index < IV_MAX; name_index++)
  131                         intr_countp[name_index] = stray_vec_index;
  132 
  133                 stray_pil_index = intrcnt_index++;
  134                 intrcnt_setname("pil", stray_pil_index);
  135                 for (name_index = 0; name_index < PIL_MAX; name_index++)
  136                         pil_countp[name_index] = stray_pil_index;
  137         }
  138 
  139         if (name == NULL)
  140                 name = "???";
  141 
  142         if (!ispil && intr_countp[vec] != stray_vec_index)
  143                 name_index = intr_countp[vec];
  144         else if (ispil && pil_countp[vec] != stray_pil_index)
  145                 name_index = pil_countp[vec];
  146         else
  147                 name_index = intrcnt_index++;
  148 
  149         if (intrcnt_setname(name, name_index))
  150                 name_index = 0;
  151 
  152         if (!ispil)
  153                 intr_countp[vec] = name_index;
  154         else
  155                 pil_countp[vec] = name_index;
  156 }
  157 
  158 static int
  159 intrcnt_setname(const char *name, int index)
  160 {
  161 
  162         if (intrnames + (MAXCOMLEN + 1) * index >= eintrnames)
  163                 return (E2BIG);
  164         snprintf(intrnames + (MAXCOMLEN + 1) * index, MAXCOMLEN + 1, "%-*s",
  165             MAXCOMLEN, name);
  166         return (0);
  167 }
  168 
  169 void
  170 intr_setup(int pri, ih_func_t *ihf, int vec, iv_func_t *ivf, void *iva)
  171 {
  172         char pilname[MAXCOMLEN + 1];
  173         u_long ps;
  174 
  175         ps = intr_disable();
  176         if (vec != -1) {
  177                 intr_vectors[vec].iv_func = ivf;
  178                 intr_vectors[vec].iv_arg = iva;
  179                 intr_vectors[vec].iv_pri = pri;
  180                 intr_vectors[vec].iv_vec = vec;
  181         }
  182         snprintf(pilname, MAXCOMLEN + 1, "pil%d: %s", pri, pil_names[pri]);
  183         intrcnt_updatename(pri, pilname, 1);
  184         intr_handlers[pri] = ihf;
  185         intr_restore(ps);
  186 }
  187 
  188 static void
  189 intr_stray_level(struct trapframe *tf)
  190 {
  191 
  192         printf("stray level interrupt %ld\n", tf->tf_level);
  193 }
  194 
  195 static void
  196 intr_stray_vector(void *cookie)
  197 {
  198         struct intr_vector *iv;
  199 
  200         iv = cookie;
  201         if (intr_stray_count[iv->iv_vec] < MAX_STRAY_LOG) {
  202                 printf("stray vector interrupt %d\n", iv->iv_vec);
  203                 intr_stray_count[iv->iv_vec]++;
  204                 if (intr_stray_count[iv->iv_vec] >= MAX_STRAY_LOG)
  205                         printf("got %d stray interrupt %d's: not logging "
  206                             "anymore\n", MAX_STRAY_LOG, iv->iv_vec);
  207         }
  208 }
  209 
  210 void
  211 intr_init1()
  212 {
  213         int i;
  214 
  215         /* Mark all interrupts as being stray. */
  216         for (i = 0; i < PIL_MAX; i++)
  217                 intr_handlers[i] = intr_stray_level;
  218         for (i = 0; i < IV_MAX; i++) {
  219                 intr_vectors[i].iv_func = intr_stray_vector;
  220                 intr_vectors[i].iv_arg = &intr_vectors[i];
  221                 intr_vectors[i].iv_pri = PIL_LOW;
  222                 intr_vectors[i].iv_vec = i;
  223                 intr_vectors[i].iv_refcnt = 0;
  224         }
  225         intr_handlers[PIL_LOW] = intr_fast;
  226 }
  227 
  228 void
  229 intr_init2()
  230 {
  231 
  232         mtx_init(&intr_table_lock, "intr table", NULL, MTX_SPIN);
  233 }
  234 
  235 static void
  236 intr_enable_eoi(void *arg)
  237 {
  238         struct intr_vector *iv;
  239         const struct intr_controller *ic;
  240 
  241         iv = arg;
  242         ic = iv->iv_ic;
  243         ic->ic_enable(iv);
  244         ic->ic_eoi(iv);
  245 }
  246 
  247 static void
  248 intr_execute_handlers(void *cookie)
  249 {
  250         struct intr_vector *iv;
  251 #ifndef INTR_FILTER
  252         struct intr_event *ie;
  253         struct intr_handler *ih;
  254         int error, thread, ret;
  255 #endif
  256 
  257         iv = cookie;
  258 #ifndef INTR_FILTER
  259         ie = iv->iv_event;
  260         if (iv->iv_ic == NULL || ie == NULL) {
  261                 intr_stray_vector(iv);
  262                 return;
  263         }
  264 
  265         /* Execute fast interrupt handlers directly. */
  266         ret = 0;
  267         thread = 0;
  268         critical_enter();
  269         TAILQ_FOREACH(ih, &ie->ie_handlers, ih_next) {
  270                 if (ih->ih_filter == NULL) {
  271                         thread = 1;
  272                         continue;
  273                 }
  274                 MPASS(ih->ih_filter != NULL && ih->ih_argument != NULL);
  275                 CTR3(KTR_INTR, "%s: executing handler %p(%p)", __func__,
  276                     ih->ih_filter, ih->ih_argument);
  277                 ret = ih->ih_filter(ih->ih_argument);
  278                 /*
  279                  * Wrapper handler special case: see
  280                  * i386/intr_machdep.c::intr_execute_handlers()
  281                  */
  282                 if (!thread) {
  283                         if (ret == FILTER_SCHEDULE_THREAD)
  284                                 thread = 1;
  285                 }
  286         }
  287         if (!thread)
  288                 intr_enable_eoi(iv);
  289 
  290         /* Schedule a heavyweight interrupt process. */
  291         if (thread)
  292                 error = intr_event_schedule_thread(ie);
  293         else if (TAILQ_EMPTY(&ie->ie_handlers))
  294                 error = EINVAL;
  295         else
  296                 error = 0;
  297         critical_exit();
  298         if (error == EINVAL)
  299 #else
  300         if (intr_event_handle(iv->iv_event, NULL) != 0)
  301 #endif
  302                 intr_stray_vector(iv);
  303 }
  304 
  305 int
  306 intr_controller_register(int vec, const struct intr_controller *ic,
  307     void *icarg)
  308 {
  309         struct intr_event *ie;
  310         struct intr_vector *iv;
  311         int error;
  312 
  313         iv = &intr_vectors[vec];
  314         mtx_lock_spin(&intr_table_lock);
  315         ie = iv->iv_event;
  316         mtx_unlock_spin(&intr_table_lock);
  317         if (ie != NULL)
  318                 return (EEXIST);
  319         /*
  320          * Testing shows that at least with the interrupt controllers of
  321          * Psycho and Schizo bridges enabling an interrupt doesn't cause
  322          * an outstanding interrupt to be issued to the CPU. Thus we can't
  323          * use a function doing disable+EOI for the "disable" pointer as
  324          * done on other architectures because this would lead to a lost
  325          * interrupt if it triggers while we are still processing the
  326          * previous one. Instead we use an enable+EOI approach because as
  327          * outlined in the Tomatillo documentation clearing an interrupt
  328          * in the interrupt controller causes it to be (re)issued to the
  329          * CPU as long as the source of a level sensitive interrupt is
  330          * not cleared.
  331          */
  332         error = intr_event_create(&ie, iv, 0, intr_enable_eoi,
  333 #ifdef INTR_FILTER
  334             ic->ic_eoi, ic->ic_disable, "vec%d:", vec);
  335 #else
  336             "vec%d:", vec);
  337 #endif
  338         if (error != 0)
  339                 return (error);
  340         mtx_lock_spin(&intr_table_lock);
  341         if (iv->iv_event != NULL) {
  342                 mtx_unlock_spin(&intr_table_lock);
  343                 intr_event_destroy(ie);
  344                 return (EEXIST);
  345         }
  346         iv->iv_ic = ic;
  347         iv->iv_icarg = icarg;
  348         iv->iv_event = ie;
  349         iv->iv_mid = PCPU_GET(mid);
  350         mtx_unlock_spin(&intr_table_lock);
  351         return (0);
  352 }
  353 
  354 int
  355 inthand_add(const char *name, int vec, driver_filter_t *filt,
  356     driver_intr_t *handler, void *arg, int flags, void **cookiep)
  357 {
  358         const struct intr_controller *ic;
  359         struct intr_event *ie;
  360         struct intr_handler *ih;
  361         struct intr_vector *iv;
  362         int error, fast;
  363 
  364         iv = &intr_vectors[vec];
  365         mtx_lock_spin(&intr_table_lock);
  366         ic = iv->iv_ic;
  367         ie = iv->iv_event;
  368         mtx_unlock_spin(&intr_table_lock);
  369         if (ic == NULL || ie == NULL)
  370                 return (EINVAL);
  371 
  372         error = intr_event_add_handler(ie, name, filt, handler, arg,
  373             intr_priority(flags), flags, cookiep);
  374         if (error != 0)
  375                 return (error);
  376 
  377         mtx_lock_spin(&intr_table_lock);
  378         /* Disable the interrupt while we fiddle with it. */
  379         ic->ic_disable(iv);
  380         iv->iv_refcnt++;
  381         if (iv->iv_refcnt == 1)
  382                 intr_setup(filt != NULL ? PIL_FAST : PIL_ITHREAD, intr_fast,
  383                     vec, intr_execute_handlers, iv);
  384         else if (filt != NULL) {
  385                 /*
  386                  * Check if we need to upgrade from PIL_ITHREAD to PIL_FAST.
  387                  * Given that apart from the on-board SCCs and UARTs shared
  388                  * interrupts are rather uncommon on sparc64 this sould be
  389                  * pretty rare in practice.
  390                  */
  391                 fast = 0;
  392                 TAILQ_FOREACH(ih, &ie->ie_handlers, ih_next) {
  393                         if (ih->ih_filter != NULL && ih->ih_filter != filt) {
  394                                 fast = 1;
  395                                 break;
  396                         }
  397                 }
  398                 if (fast == 0)
  399                         intr_setup(PIL_FAST, intr_fast, vec,
  400                             intr_execute_handlers, iv);
  401         }
  402         intr_stray_count[vec] = 0;
  403         intrcnt_updatename(vec, ie->ie_fullname, 0);
  404         /* Ensure the interrupt is cleared, it might have triggered before. */
  405         intr_enable_eoi(iv);
  406         mtx_unlock_spin(&intr_table_lock);
  407         return (0);
  408 }
  409 
  410 int
  411 inthand_remove(int vec, void *cookie)
  412 {
  413         struct intr_vector *iv;
  414         int error;
  415 
  416         error = intr_event_remove_handler(cookie);
  417         if (error == 0) {
  418                 /*
  419                  * XXX: maybe this should be done regardless of whether
  420                  * intr_event_remove_handler() succeeded?
  421                  */
  422                 iv = &intr_vectors[vec];
  423                 mtx_lock_spin(&intr_table_lock);
  424                 iv->iv_refcnt--;
  425                 if (iv->iv_refcnt == 0) {
  426                         /*
  427                          * Don't disable the interrupt for now, so that
  428                          * stray interrupts get detected...
  429                          */
  430                         intr_setup(PIL_LOW, intr_fast, vec,
  431                             intr_stray_vector, iv);
  432                 }
  433                 mtx_unlock_spin(&intr_table_lock);
  434         }
  435         return (error);
  436 }

Cache object: a290c50dcf750fee58ce7736486d61ea


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.