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/bus.h>
   67 #include <sys/errno.h>
   68 #include <sys/interrupt.h>
   69 #include <sys/kernel.h>
   70 #include <sys/lock.h>
   71 #include <sys/mutex.h>
   72 #include <sys/pcpu.h>
   73 #include <sys/proc.h>
   74 #include <sys/smp.h>
   75 #include <sys/sx.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 static uint16_t pil_stray_count[PIL_MAX];
   87 
   88 struct intr_vector intr_vectors[IV_MAX];
   89 uint16_t intr_countp[IV_MAX];
   90 static uint16_t intr_stray_count[IV_MAX];
   91 
   92 static const char *const pil_names[] = {
   93         "stray",
   94         "low",          /* PIL_LOW */
   95         "preempt",      /* PIL_PREEMPT */
   96         "ithrd",        /* PIL_ITHREAD */
   97         "rndzvs",       /* PIL_RENDEZVOUS */
   98         "ast",          /* PIL_AST */
   99         "stray", "stray", "stray", "stray", "stray",
  100         "filter",       /* PIL_FILTER */
  101         "bridge",       /* PIL_BRIDGE */
  102         "stop",         /* PIL_STOP */
  103         "tick",         /* PIL_TICK */
  104 };
  105 
  106 /* protect the intr_vectors table */
  107 static struct sx intr_table_lock;
  108 /* protect intrcnt_index */
  109 static struct mtx intrcnt_lock;
  110 
  111 #ifdef SMP
  112 static int assign_cpu;
  113 
  114 static void intr_assign_next_cpu(struct intr_vector *iv);
  115 static void intr_shuffle_irqs(void *arg __unused);
  116 #endif
  117 
  118 static int intr_assign_cpu(void *arg, u_char cpu);
  119 static void intr_execute_handlers(void *);
  120 static void intr_stray_level(struct trapframe *);
  121 static void intr_stray_vector(void *);
  122 static int intrcnt_setname(const char *, int);
  123 static void intrcnt_updatename(int, const char *, int);
  124 
  125 static void
  126 intrcnt_updatename(int vec, const char *name, int ispil)
  127 {
  128         static int intrcnt_index, stray_pil_index, stray_vec_index;
  129         int name_index;
  130 
  131         mtx_lock_spin(&intrcnt_lock);
  132         if (intrnames[0] == '\0') {
  133                 /* for bitbucket */
  134                 if (bootverbose)
  135                         printf("initalizing intr_countp\n");
  136                 intrcnt_setname("???", intrcnt_index++);
  137 
  138                 stray_vec_index = intrcnt_index++;
  139                 intrcnt_setname("stray", stray_vec_index);
  140                 for (name_index = 0; name_index < IV_MAX; name_index++)
  141                         intr_countp[name_index] = stray_vec_index;
  142 
  143                 stray_pil_index = intrcnt_index++;
  144                 intrcnt_setname("pil", stray_pil_index);
  145                 for (name_index = 0; name_index < PIL_MAX; name_index++)
  146                         pil_countp[name_index] = stray_pil_index;
  147         }
  148 
  149         if (name == NULL)
  150                 name = "???";
  151 
  152         if (!ispil && intr_countp[vec] != stray_vec_index)
  153                 name_index = intr_countp[vec];
  154         else if (ispil && pil_countp[vec] != stray_pil_index)
  155                 name_index = pil_countp[vec];
  156         else
  157                 name_index = intrcnt_index++;
  158 
  159         if (intrcnt_setname(name, name_index))
  160                 name_index = 0;
  161 
  162         if (!ispil)
  163                 intr_countp[vec] = name_index;
  164         else
  165                 pil_countp[vec] = name_index;
  166         mtx_unlock_spin(&intrcnt_lock);
  167 }
  168 
  169 static int
  170 intrcnt_setname(const char *name, int index)
  171 {
  172 
  173         if (intrnames + (MAXCOMLEN + 1) * index >= eintrnames)
  174                 return (E2BIG);
  175         snprintf(intrnames + (MAXCOMLEN + 1) * index, MAXCOMLEN + 1, "%-*s",
  176             MAXCOMLEN, name);
  177         return (0);
  178 }
  179 
  180 void
  181 intr_setup(int pri, ih_func_t *ihf, int vec, iv_func_t *ivf, void *iva)
  182 {
  183         char pilname[MAXCOMLEN + 1];
  184         register_t s;
  185 
  186         s = intr_disable();
  187         if (vec != -1) {
  188                 intr_vectors[vec].iv_func = ivf;
  189                 intr_vectors[vec].iv_arg = iva;
  190                 intr_vectors[vec].iv_pri = pri;
  191                 intr_vectors[vec].iv_vec = vec;
  192         }
  193         intr_handlers[pri] = ihf;
  194         intr_restore(s);
  195         snprintf(pilname, MAXCOMLEN + 1, "pil%d: %s", pri, pil_names[pri]);
  196         intrcnt_updatename(pri, pilname, 1);
  197 }
  198 
  199 static void
  200 intr_stray_level(struct trapframe *tf)
  201 {
  202         uint64_t level;
  203 
  204         level = tf->tf_level;
  205         if (pil_stray_count[level] < MAX_STRAY_LOG) {
  206                 printf("stray level interrupt %ld\n", level);
  207                 pil_stray_count[level]++;
  208                 if (pil_stray_count[level] >= MAX_STRAY_LOG)
  209                         printf("got %d stray level interrupt %ld's: not "
  210                             "logging anymore\n", MAX_STRAY_LOG, level);
  211         }
  212 }
  213 
  214 static void
  215 intr_stray_vector(void *cookie)
  216 {
  217         struct intr_vector *iv;
  218         u_int vec;
  219 
  220         iv = cookie;
  221         vec = iv->iv_vec;
  222         if (intr_stray_count[vec] < MAX_STRAY_LOG) {
  223                 printf("stray vector interrupt %d\n", vec);
  224                 intr_stray_count[vec]++;
  225                 if (intr_stray_count[vec] >= MAX_STRAY_LOG)
  226                         printf("got %d stray vector interrupt %d's: not "
  227                             "logging anymore\n", MAX_STRAY_LOG, vec);
  228         }
  229 }
  230 
  231 void
  232 intr_init1()
  233 {
  234         int i;
  235 
  236         /* Mark all interrupts as being stray. */
  237         for (i = 0; i < PIL_MAX; i++)
  238                 intr_handlers[i] = intr_stray_level;
  239         for (i = 0; i < IV_MAX; i++) {
  240                 intr_vectors[i].iv_func = intr_stray_vector;
  241                 intr_vectors[i].iv_arg = &intr_vectors[i];
  242                 intr_vectors[i].iv_pri = PIL_LOW;
  243                 intr_vectors[i].iv_vec = i;
  244                 intr_vectors[i].iv_refcnt = 0;
  245         }
  246         intr_handlers[PIL_LOW] = intr_fast;
  247 }
  248 
  249 void
  250 intr_init2()
  251 {
  252 
  253         sx_init(&intr_table_lock, "intr sources");
  254         mtx_init(&intrcnt_lock, "intrcnt", NULL, MTX_SPIN);
  255 }
  256 
  257 static int
  258 intr_assign_cpu(void *arg, u_char cpu)
  259 {
  260 #ifdef SMP
  261         struct pcpu *pc;
  262         struct intr_vector *iv;
  263 
  264         /*
  265          * Don't do anything during early boot.  We will pick up the
  266          * assignment once the APs are started.
  267          */
  268         if (assign_cpu && cpu != NOCPU) {
  269                 pc = pcpu_find(cpu);
  270                 if (pc == NULL)
  271                         return (EINVAL);
  272                 iv = arg;
  273                 sx_xlock(&intr_table_lock);
  274                 iv->iv_mid = pc->pc_mid;
  275                 iv->iv_ic->ic_assign(iv);
  276                 sx_xunlock(&intr_table_lock);
  277         }
  278         return (0);
  279 #else
  280         return (EOPNOTSUPP);
  281 #endif
  282 }
  283 
  284 static void
  285 intr_execute_handlers(void *cookie)
  286 {
  287         struct intr_vector *iv;
  288 
  289         iv = cookie;
  290         if (__predict_false(intr_event_handle(iv->iv_event, NULL) != 0))
  291                 intr_stray_vector(iv);
  292 }
  293 
  294 int
  295 intr_controller_register(int vec, const struct intr_controller *ic,
  296     void *icarg)
  297 {
  298         struct intr_event *ie;
  299         struct intr_vector *iv;
  300         int error;
  301 
  302         if (vec < 0 || vec >= IV_MAX)
  303                 return (EINVAL);
  304         sx_xlock(&intr_table_lock);
  305         iv = &intr_vectors[vec];
  306         ie = iv->iv_event;
  307         sx_xunlock(&intr_table_lock);
  308         if (ie != NULL)
  309                 return (EEXIST);
  310         error = intr_event_create(&ie, iv, 0, vec, NULL, ic->ic_clear,
  311             ic->ic_clear, intr_assign_cpu, "vec%d:", vec);
  312         if (error != 0)
  313                 return (error);
  314         sx_xlock(&intr_table_lock);
  315         if (iv->iv_event != NULL) {
  316                 sx_xunlock(&intr_table_lock);
  317                 intr_event_destroy(ie);
  318                 return (EEXIST);
  319         }
  320         iv->iv_ic = ic;
  321         iv->iv_icarg = icarg;
  322         iv->iv_event = ie;
  323         iv->iv_mid = PCPU_GET(mid);
  324         sx_xunlock(&intr_table_lock);
  325         return (0);
  326 }
  327 
  328 int
  329 inthand_add(const char *name, int vec, driver_filter_t *filt,
  330     driver_intr_t *handler, void *arg, int flags, void **cookiep)
  331 {
  332         const struct intr_controller *ic;
  333         struct intr_event *ie;
  334         struct intr_handler *ih;
  335         struct intr_vector *iv;
  336         int error, filter;
  337 
  338         if (vec < 0 || vec >= IV_MAX)
  339                 return (EINVAL);
  340         /*
  341          * INTR_BRIDGE filters/handlers are special purpose only, allowing
  342          * them to be shared just would complicate things unnecessarily.
  343          */
  344         if ((flags & INTR_BRIDGE) != 0 && (flags & INTR_EXCL) == 0)
  345                 return (EINVAL);
  346         sx_xlock(&intr_table_lock);
  347         iv = &intr_vectors[vec];
  348         ic = iv->iv_ic;
  349         ie = iv->iv_event;
  350         sx_xunlock(&intr_table_lock);
  351         if (ic == NULL || ie == NULL)
  352                 return (EINVAL);
  353         error = intr_event_add_handler(ie, name, filt, handler, arg,
  354             intr_priority(flags), flags, cookiep);
  355         if (error != 0)
  356                 return (error);
  357         sx_xlock(&intr_table_lock);
  358         /* Disable the interrupt while we fiddle with it. */
  359         ic->ic_disable(iv);
  360         iv->iv_refcnt++;
  361         if (iv->iv_refcnt == 1)
  362                 intr_setup((flags & INTR_BRIDGE) != 0 ? PIL_BRIDGE :
  363                     filt != NULL ? PIL_FILTER : PIL_ITHREAD, intr_fast,
  364                     vec, intr_execute_handlers, iv);
  365         else if (filt != NULL) {
  366                 /*
  367                  * Check if we need to upgrade from PIL_ITHREAD to PIL_FILTER.
  368                  * Given that apart from the on-board SCCs and UARTs shared
  369                  * interrupts are rather uncommon on sparc64 this sould be
  370                  * pretty rare in practice.
  371                  */
  372                 filter = 0;
  373                 TAILQ_FOREACH(ih, &ie->ie_handlers, ih_next) {
  374                         if (ih->ih_filter != NULL && ih->ih_filter != filt) {
  375                                 filter = 1;
  376                                 break;
  377                         }
  378                 }
  379                 if (filter == 0)
  380                         intr_setup(PIL_FILTER, intr_fast, vec,
  381                             intr_execute_handlers, iv);
  382         }
  383         intr_stray_count[vec] = 0;
  384         intrcnt_updatename(vec, ie->ie_fullname, 0);
  385 #ifdef SMP
  386         if (assign_cpu)
  387                 intr_assign_next_cpu(iv);
  388 #endif
  389         ic->ic_enable(iv);
  390         /* Ensure the interrupt is cleared, it might have triggered before. */
  391         if (ic->ic_clear != NULL)
  392                 ic->ic_clear(iv);
  393         sx_xunlock(&intr_table_lock);
  394         return (0);
  395 }
  396 
  397 int
  398 inthand_remove(int vec, void *cookie)
  399 {
  400         struct intr_vector *iv;
  401         int error;
  402 
  403         if (vec < 0 || vec >= IV_MAX)
  404                 return (EINVAL);
  405         error = intr_event_remove_handler(cookie);
  406         if (error == 0) {
  407                 /*
  408                  * XXX: maybe this should be done regardless of whether
  409                  * intr_event_remove_handler() succeeded?
  410                  */
  411                 sx_xlock(&intr_table_lock);
  412                 iv = &intr_vectors[vec];
  413                 iv->iv_refcnt--;
  414                 if (iv->iv_refcnt == 0) {
  415                         /*
  416                          * Don't disable the interrupt for now, so that
  417                          * stray interrupts get detected...
  418                          */
  419                         intr_setup(PIL_LOW, intr_fast, vec,
  420                             intr_stray_vector, iv);
  421                 }
  422                 sx_xunlock(&intr_table_lock);
  423         }
  424         return (error);
  425 }
  426 
  427 /* Add a description to an active interrupt handler. */
  428 int
  429 intr_describe(int vec, void *ih, const char *descr)
  430 {
  431         struct intr_vector *iv;
  432         int error;
  433 
  434         if (vec < 0 || vec >= IV_MAX)
  435                 return (EINVAL);
  436         sx_xlock(&intr_table_lock);
  437         iv = &intr_vectors[vec];
  438         if (iv == NULL) {
  439                 sx_xunlock(&intr_table_lock);
  440                 return (EINVAL);
  441         }
  442         error = intr_event_describe_handler(iv->iv_event, ih, descr);
  443         if (error) {
  444                 sx_xunlock(&intr_table_lock);
  445                 return (error);
  446         }
  447         intrcnt_updatename(vec, iv->iv_event->ie_fullname, 0);
  448         sx_xunlock(&intr_table_lock);
  449         return (error);
  450 }
  451 
  452 #ifdef SMP
  453 /*
  454  * Support for balancing interrupt sources across CPUs.  For now we just
  455  * allocate CPUs round-robin.
  456  */
  457 
  458 /* The BSP is always a valid target. */
  459 static cpumask_t intr_cpus = (1 << 0);
  460 static int current_cpu;
  461 
  462 static void
  463 intr_assign_next_cpu(struct intr_vector *iv)
  464 {
  465         struct pcpu *pc;
  466 
  467         sx_assert(&intr_table_lock, SA_XLOCKED);
  468 
  469         /*
  470          * Assign this source to a CPU in a round-robin fashion.
  471          */
  472         pc = pcpu_find(current_cpu);
  473         if (pc == NULL)
  474                 return;
  475         iv->iv_mid = pc->pc_mid;
  476         iv->iv_ic->ic_assign(iv);
  477         do {
  478                 current_cpu++;
  479                 if (current_cpu > mp_maxid)
  480                         current_cpu = 0;
  481         } while (!(intr_cpus & (1 << current_cpu)));
  482 }
  483 
  484 /* Attempt to bind the specified IRQ to the specified CPU. */
  485 int
  486 intr_bind(int vec, u_char cpu)
  487 {
  488         struct intr_vector *iv;
  489         int error;
  490 
  491         if (vec < 0 || vec >= IV_MAX)
  492                 return (EINVAL);
  493         sx_xlock(&intr_table_lock);
  494         iv = &intr_vectors[vec];
  495         if (iv == NULL) {
  496                 sx_xunlock(&intr_table_lock);
  497                 return (EINVAL);
  498         }
  499         error = intr_event_bind(iv->iv_event, cpu);
  500         sx_xunlock(&intr_table_lock);
  501         return (error);
  502 }
  503 
  504 /*
  505  * Add a CPU to our mask of valid CPUs that can be destinations of
  506  * interrupts.
  507  */
  508 void
  509 intr_add_cpu(u_int cpu)
  510 {
  511 
  512         if (cpu >= MAXCPU)
  513                 panic("%s: Invalid CPU ID", __func__);
  514         if (bootverbose)
  515                 printf("INTR: Adding CPU %d as a target\n", cpu);
  516 
  517         intr_cpus |= (1 << cpu);
  518 }
  519 
  520 /*
  521  * Distribute all the interrupt sources among the available CPUs once the
  522  * APs have been launched.
  523  */
  524 static void
  525 intr_shuffle_irqs(void *arg __unused)
  526 {
  527         struct pcpu *pc;
  528         struct intr_vector *iv;
  529         int i;
  530 
  531         /* Don't bother on UP. */
  532         if (mp_ncpus == 1)
  533                 return;
  534 
  535         sx_xlock(&intr_table_lock);
  536         assign_cpu = 1;
  537         for (i = 0; i < IV_MAX; i++) {
  538                 iv = &intr_vectors[i];
  539                 if (iv != NULL && iv->iv_refcnt > 0) {
  540                         /*
  541                          * If this event is already bound to a CPU,
  542                          * then assign the source to that CPU instead
  543                          * of picking one via round-robin.
  544                          */
  545                         if (iv->iv_event->ie_cpu != NOCPU &&
  546                             (pc = pcpu_find(iv->iv_event->ie_cpu)) != NULL) {
  547                                 iv->iv_mid = pc->pc_mid;
  548                                 iv->iv_ic->ic_assign(iv);
  549                         } else
  550                                 intr_assign_next_cpu(iv);
  551                 }
  552         }
  553         sx_xunlock(&intr_table_lock);
  554 }
  555 SYSINIT(intr_shuffle_irqs, SI_SUB_SMP, SI_ORDER_SECOND, intr_shuffle_irqs,
  556     NULL);
  557 #endif

Cache object: 8e2fe5124e662afe03d24dfbd790baf5


[ 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.