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/powerpc/powerpc/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) 2002 Benno Rice.
   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  * $FreeBSD$
   61  */
   62 
   63 #include "opt_isa.h"
   64 
   65 #include <sys/param.h>
   66 #include <sys/systm.h>
   67 #include <sys/kernel.h>
   68 #include <sys/queue.h>
   69 #include <sys/bus.h>
   70 #include <sys/cpuset.h>
   71 #include <sys/interrupt.h>
   72 #include <sys/ktr.h>
   73 #include <sys/lock.h>
   74 #include <sys/malloc.h>
   75 #include <sys/mutex.h>
   76 #include <sys/pcpu.h>
   77 #include <sys/smp.h>
   78 #include <sys/syslog.h>
   79 #include <sys/vmmeter.h>
   80 #include <sys/proc.h>
   81 
   82 #include <machine/frame.h>
   83 #include <machine/intr_machdep.h>
   84 #include <machine/md_var.h>
   85 #include <machine/smp.h>
   86 #include <machine/trap.h>
   87 
   88 #include "pic_if.h"
   89 
   90 #define MAX_STRAY_LOG   5
   91 
   92 static MALLOC_DEFINE(M_INTR, "intr", "interrupt handler data");
   93 
   94 struct powerpc_intr {
   95         struct intr_event *event;
   96         long    *cntp;
   97         u_int   irq;
   98         device_t pic;
   99         u_int   intline;
  100         u_int   vector;
  101         u_int   cntindex;
  102         cpuset_t cpu;
  103         enum intr_trigger trig;
  104         enum intr_polarity pol;
  105 };
  106 
  107 struct pic {
  108         device_t dev;
  109         uint32_t node;
  110         u_int   irqs;
  111         u_int   ipis;
  112         int     base;
  113 };
  114 
  115 static u_int intrcnt_index = 0;
  116 static struct mtx intr_table_lock;
  117 static struct powerpc_intr *powerpc_intrs[INTR_VECTORS];
  118 static struct pic piclist[MAX_PICS];
  119 static u_int nvectors;          /* Allocated vectors */
  120 static u_int npics;             /* PICs registered */
  121 #ifdef DEV_ISA
  122 static u_int nirqs = 16;        /* Allocated IRQS (ISA pre-allocated). */
  123 #else
  124 static u_int nirqs = 0;         /* Allocated IRQs. */
  125 #endif
  126 static u_int stray_count;
  127 
  128 device_t root_pic;
  129 
  130 #ifdef SMP
  131 static void *ipi_cookie;
  132 #endif
  133 
  134 static void
  135 intr_init(void *dummy __unused)
  136 {
  137 
  138         mtx_init(&intr_table_lock, "intr sources lock", NULL, MTX_DEF);
  139 }
  140 SYSINIT(intr_init, SI_SUB_INTR, SI_ORDER_FIRST, intr_init, NULL);
  141 
  142 #ifdef SMP
  143 static void
  144 smp_intr_init(void *dummy __unused)
  145 {
  146         struct powerpc_intr *i;
  147         int vector;
  148 
  149         for (vector = 0; vector < nvectors; vector++) {
  150                 i = powerpc_intrs[vector];
  151                 if (i != NULL && i->pic == root_pic)
  152                         PIC_BIND(i->pic, i->intline, i->cpu);
  153         }
  154 }
  155 SYSINIT(smp_intr_init, SI_SUB_SMP, SI_ORDER_ANY, smp_intr_init, NULL);
  156 #endif
  157 
  158 static void
  159 intrcnt_setname(const char *name, int index)
  160 {
  161 
  162         snprintf(intrnames + (MAXCOMLEN + 1) * index, MAXCOMLEN + 1, "%-*s",
  163             MAXCOMLEN, name);
  164 }
  165 
  166 void
  167 intrcnt_add(const char *name, u_long **countp)
  168 {
  169         int idx;
  170 
  171         idx = atomic_fetchadd_int(&intrcnt_index, 1);
  172         *countp = &intrcnt[idx];
  173         intrcnt_setname(name, idx);
  174 }
  175 
  176 static struct powerpc_intr *
  177 intr_lookup(u_int irq)
  178 {
  179         char intrname[8];
  180         struct powerpc_intr *i, *iscan;
  181         int vector;
  182 
  183         mtx_lock(&intr_table_lock);
  184         for (vector = 0; vector < nvectors; vector++) {
  185                 i = powerpc_intrs[vector];
  186                 if (i != NULL && i->irq == irq) {
  187                         mtx_unlock(&intr_table_lock);
  188                         return (i);
  189                 }
  190         }
  191 
  192         i = malloc(sizeof(*i), M_INTR, M_NOWAIT);
  193         if (i == NULL) {
  194                 mtx_unlock(&intr_table_lock);
  195                 return (NULL);
  196         }
  197 
  198         i->event = NULL;
  199         i->cntp = NULL;
  200         i->trig = INTR_TRIGGER_CONFORM;
  201         i->pol = INTR_POLARITY_CONFORM;
  202         i->irq = irq;
  203         i->pic = NULL;
  204         i->vector = -1;
  205 
  206 #ifdef SMP
  207         i->cpu = all_cpus;
  208 #else
  209         CPU_SETOF(0, &i->cpu);
  210 #endif
  211 
  212         for (vector = 0; vector < INTR_VECTORS && vector <= nvectors;
  213             vector++) {
  214                 iscan = powerpc_intrs[vector];
  215                 if (iscan != NULL && iscan->irq == irq)
  216                         break;
  217                 if (iscan == NULL && i->vector == -1)
  218                         i->vector = vector;
  219                 iscan = NULL;
  220         }
  221 
  222         if (iscan == NULL && i->vector != -1) {
  223                 powerpc_intrs[i->vector] = i;
  224                 i->cntindex = atomic_fetchadd_int(&intrcnt_index, 1);
  225                 i->cntp = &intrcnt[i->cntindex];
  226                 sprintf(intrname, "irq%u:", i->irq);
  227                 intrcnt_setname(intrname, i->cntindex);
  228                 nvectors++;
  229         }
  230         mtx_unlock(&intr_table_lock);
  231 
  232         if (iscan != NULL || i->vector == -1) {
  233                 free(i, M_INTR);
  234                 i = iscan;
  235         }
  236 
  237         return (i);
  238 }
  239 
  240 static int
  241 powerpc_map_irq(struct powerpc_intr *i)
  242 {
  243         struct pic *p;
  244         u_int cnt;
  245         int idx;
  246 
  247         for (idx = 0; idx < npics; idx++) {
  248                 p = &piclist[idx];
  249                 cnt = p->irqs + p->ipis;
  250                 if (i->irq >= p->base && i->irq < p->base + cnt)
  251                         break;
  252         }
  253         if (idx == npics)
  254                 return (EINVAL);
  255 
  256         i->intline = i->irq - p->base;
  257         i->pic = p->dev;
  258 
  259         /* Try a best guess if that failed */
  260         if (i->pic == NULL)
  261                 i->pic = root_pic;
  262 
  263         return (0);
  264 }
  265 
  266 static void
  267 powerpc_intr_eoi(void *arg)
  268 {
  269         struct powerpc_intr *i = arg;
  270 
  271         PIC_EOI(i->pic, i->intline);
  272 }
  273 
  274 static void
  275 powerpc_intr_pre_ithread(void *arg)
  276 {
  277         struct powerpc_intr *i = arg;
  278 
  279         PIC_MASK(i->pic, i->intline);
  280         PIC_EOI(i->pic, i->intline);
  281 }
  282 
  283 static void
  284 powerpc_intr_post_ithread(void *arg)
  285 {
  286         struct powerpc_intr *i = arg;
  287 
  288         PIC_UNMASK(i->pic, i->intline);
  289 }
  290 
  291 static int
  292 powerpc_assign_intr_cpu(void *arg, u_char cpu)
  293 {
  294 #ifdef SMP
  295         struct powerpc_intr *i = arg;
  296 
  297         if (cpu == NOCPU)
  298                 i->cpu = all_cpus;
  299         else
  300                 CPU_SETOF(cpu, &i->cpu);
  301 
  302         if (!cold && i->pic != NULL && i->pic == root_pic)
  303                 PIC_BIND(i->pic, i->intline, i->cpu);
  304 
  305         return (0);
  306 #else
  307         return (EOPNOTSUPP);
  308 #endif
  309 }
  310 
  311 void
  312 powerpc_register_pic(device_t dev, uint32_t node, u_int irqs, u_int ipis,
  313     u_int atpic)
  314 {
  315         struct pic *p;
  316         u_int irq;
  317         int idx;
  318 
  319         mtx_lock(&intr_table_lock);
  320 
  321         /* XXX see powerpc_get_irq(). */
  322         for (idx = 0; idx < npics; idx++) {
  323                 p = &piclist[idx];
  324                 if (p->node != node)
  325                         continue;
  326                 if (node != 0 || p->dev == dev)
  327                         break;
  328         }
  329         p = &piclist[idx];
  330 
  331         p->dev = dev;
  332         p->node = node;
  333         p->irqs = irqs;
  334         p->ipis = ipis;
  335         if (idx == npics) {
  336 #ifdef DEV_ISA
  337                 p->base = (atpic) ? 0 : nirqs;
  338 #else
  339                 p->base = nirqs;
  340 #endif
  341                 irq = p->base + irqs + ipis;
  342                 nirqs = MAX(nirqs, irq);
  343                 npics++;
  344         }
  345 
  346         mtx_unlock(&intr_table_lock);
  347 }
  348 
  349 u_int
  350 powerpc_get_irq(uint32_t node, u_int pin)
  351 {
  352         int idx;
  353 
  354         if (node == 0)
  355                 return (pin);
  356 
  357         mtx_lock(&intr_table_lock);
  358         for (idx = 0; idx < npics; idx++) {
  359                 if (piclist[idx].node == node) {
  360                         mtx_unlock(&intr_table_lock);
  361                         return (piclist[idx].base + pin);
  362                 }
  363         }
  364 
  365         /*
  366          * XXX we should never encounter an unregistered PIC, but that
  367          * can only be done when we properly support bus enumeration
  368          * using multiple passes. Until then, fake an entry and give it
  369          * some adhoc maximum number of IRQs and IPIs.
  370          */
  371         piclist[idx].dev = NULL;
  372         piclist[idx].node = node;
  373         piclist[idx].irqs = 124;
  374         piclist[idx].ipis = 4;
  375         piclist[idx].base = nirqs;
  376         nirqs += 128;
  377         npics++;
  378 
  379         mtx_unlock(&intr_table_lock);
  380 
  381         return (piclist[idx].base + pin);
  382 }
  383 
  384 int
  385 powerpc_enable_intr(void)
  386 {
  387         struct powerpc_intr *i;
  388         int error, vector;
  389 #ifdef SMP
  390         int n;
  391 #endif
  392 
  393         if (npics == 0)
  394                 panic("no PIC detected\n");
  395 
  396         if (root_pic == NULL)
  397                 root_pic = piclist[0].dev;
  398 
  399 #ifdef SMP
  400         /* Install an IPI handler. */
  401         if (mp_ncpus > 1) {
  402                 for (n = 0; n < npics; n++) {
  403                         if (piclist[n].dev != root_pic)
  404                                 continue;
  405 
  406                         KASSERT(piclist[n].ipis != 0,
  407                             ("%s: SMP root PIC does not supply any IPIs",
  408                             __func__));
  409                         error = powerpc_setup_intr("IPI",
  410                             MAP_IRQ(piclist[n].node, piclist[n].irqs),
  411                             powerpc_ipi_handler, NULL, NULL,
  412                             INTR_TYPE_MISC | INTR_EXCL, &ipi_cookie);
  413                         if (error) {
  414                                 printf("unable to setup IPI handler\n");
  415                                 return (error);
  416                         }
  417                 }
  418         }
  419 #endif
  420 
  421         for (vector = 0; vector < nvectors; vector++) {
  422                 i = powerpc_intrs[vector];
  423                 if (i == NULL)
  424                         continue;
  425 
  426                 error = powerpc_map_irq(i);
  427                 if (error)
  428                         continue;
  429 
  430                 if (i->trig != INTR_TRIGGER_CONFORM ||
  431                     i->pol != INTR_POLARITY_CONFORM)
  432                         PIC_CONFIG(i->pic, i->intline, i->trig, i->pol);
  433 
  434                 if (i->event != NULL)
  435                         PIC_ENABLE(i->pic, i->intline, vector);
  436         }
  437 
  438         return (0);
  439 }
  440 
  441 int
  442 powerpc_setup_intr(const char *name, u_int irq, driver_filter_t filter,
  443     driver_intr_t handler, void *arg, enum intr_type flags, void **cookiep)
  444 {
  445         struct powerpc_intr *i;
  446         int error, enable = 0;
  447 
  448         i = intr_lookup(irq);
  449         if (i == NULL)
  450                 return (ENOMEM);
  451 
  452         if (i->event == NULL) {
  453                 error = intr_event_create(&i->event, (void *)i, 0, irq,
  454                     powerpc_intr_pre_ithread, powerpc_intr_post_ithread,
  455                     powerpc_intr_eoi, powerpc_assign_intr_cpu, "irq%u:", irq);
  456                 if (error)
  457                         return (error);
  458 
  459                 enable = 1;
  460         }
  461 
  462         error = intr_event_add_handler(i->event, name, filter, handler, arg,
  463             intr_priority(flags), flags, cookiep);
  464 
  465         mtx_lock(&intr_table_lock);
  466         intrcnt_setname(i->event->ie_fullname, i->cntindex);
  467         mtx_unlock(&intr_table_lock);
  468 
  469         if (!cold) {
  470                 error = powerpc_map_irq(i);
  471 
  472                 if (!error && (i->trig != INTR_TRIGGER_CONFORM ||
  473                     i->pol != INTR_POLARITY_CONFORM))
  474                         PIC_CONFIG(i->pic, i->intline, i->trig, i->pol);
  475 
  476                 if (!error && i->pic == root_pic)
  477                         PIC_BIND(i->pic, i->intline, i->cpu);
  478 
  479                 if (!error && enable)
  480                         PIC_ENABLE(i->pic, i->intline, i->vector);
  481         }
  482         return (error);
  483 }
  484 
  485 int
  486 powerpc_teardown_intr(void *cookie)
  487 {
  488 
  489         return (intr_event_remove_handler(cookie));
  490 }
  491 
  492 #ifdef SMP
  493 int
  494 powerpc_bind_intr(u_int irq, u_char cpu)
  495 {
  496         struct powerpc_intr *i;
  497 
  498         i = intr_lookup(irq);
  499         if (i == NULL)
  500                 return (ENOMEM);
  501 
  502         return (intr_event_bind(i->event, cpu));
  503 }
  504 #endif
  505 
  506 int
  507 powerpc_config_intr(int irq, enum intr_trigger trig, enum intr_polarity pol)
  508 {
  509         struct powerpc_intr *i;
  510 
  511         i = intr_lookup(irq);
  512         if (i == NULL)
  513                 return (ENOMEM);
  514 
  515         i->trig = trig;
  516         i->pol = pol;
  517 
  518         if (!cold && i->pic != NULL)
  519                 PIC_CONFIG(i->pic, i->intline, trig, pol);
  520 
  521         return (0);
  522 }
  523 
  524 void
  525 powerpc_dispatch_intr(u_int vector, struct trapframe *tf)
  526 {
  527         struct powerpc_intr *i;
  528         struct intr_event *ie;
  529 
  530         i = powerpc_intrs[vector];
  531         if (i == NULL)
  532                 goto stray;
  533 
  534         (*i->cntp)++;
  535 
  536         ie = i->event;
  537         KASSERT(ie != NULL, ("%s: interrupt without an event", __func__));
  538 
  539         if (intr_event_handle(ie, tf) != 0) {
  540                 goto stray;
  541         }
  542         return;
  543 
  544 stray:
  545         stray_count++;
  546         if (stray_count <= MAX_STRAY_LOG) {
  547                 printf("stray irq %d\n", i ? i->irq : -1);
  548                 if (stray_count >= MAX_STRAY_LOG) {
  549                         printf("got %d stray interrupts, not logging anymore\n",
  550                             MAX_STRAY_LOG);
  551                 }
  552         }
  553         if (i != NULL)
  554                 PIC_MASK(i->pic, i->intline);
  555 }

Cache object: 5e95a976ccc9b042b14add8106081261


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