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/openpic.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) 2002 Benno Rice.
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR
   15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   17  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   18  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
   19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
   20  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
   21  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
   22  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
   23  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   24  *
   25  * $FreeBSD: releng/5.2/sys/powerpc/powerpc/openpic.c 122841 2003-11-17 06:10:15Z peter $
   26  */
   27 
   28 #include <sys/param.h>
   29 #include <sys/systm.h>
   30 #include <sys/bus.h>
   31 #include <sys/conf.h>
   32 #include <sys/kernel.h>
   33 
   34 #include <dev/ofw/openfirm.h>
   35 #include <dev/ofw/ofw_pci.h>
   36 
   37 #include <dev/pci/pcivar.h>
   38 #include <dev/pci/pcireg.h>
   39 
   40 #include <machine/bus.h>
   41 #include <machine/intr.h>
   42 #include <machine/intr_machdep.h>
   43 #include <machine/md_var.h>
   44 #include <machine/nexusvar.h>
   45 #include <machine/pio.h>
   46 #include <machine/resource.h>
   47 
   48 #include <vm/vm.h>
   49 #include <vm/pmap.h>
   50 
   51 #include <sys/rman.h>
   52 
   53 #include <machine/openpicreg.h>
   54 #include <machine/openpicvar.h>
   55 
   56 #include "pic_if.h"
   57 
   58 /*
   59  * Device interface.
   60  */
   61 static int              openpic_probe(device_t);
   62 static int              openpic_attach(device_t);
   63 
   64 /*
   65  * PIC interface.
   66  */
   67 static struct resource  *openpic_allocate_intr(device_t, device_t, int *,
   68                             u_long, u_int);
   69 static int              openpic_setup_intr(device_t, device_t,
   70                             struct resource *, int, driver_intr_t, void *,
   71                             void **);
   72 static int              openpic_teardown_intr(device_t, device_t,
   73                             struct resource *, void *);
   74 static int              openpic_release_intr(device_t dev, device_t, int,
   75                             struct resource *res);
   76 
   77 /*
   78  * Local routines
   79  */
   80 static u_int            openpic_read(struct openpic_softc *, int);
   81 static void             openpic_write(struct openpic_softc *, int, u_int);
   82 static int              openpic_read_irq(struct openpic_softc *, int);
   83 static void             openpic_eoi(struct openpic_softc *, int);
   84 static void             openpic_enable_irq(struct openpic_softc *, int, int);
   85 static void             openpic_disable_irq(struct openpic_softc *, int);
   86 static void             openpic_set_priority(struct openpic_softc *, int, int);
   87 static void             openpic_intr(void);
   88 static void             irq_enable(uintptr_t);
   89 static void             irq_disable(uintptr_t);
   90 
   91 /*
   92  * Driver methods.
   93  */
   94 static device_method_t  openpic_methods[] = {
   95         /* Device interface */
   96         DEVMETHOD(device_probe,         openpic_probe),
   97         DEVMETHOD(device_attach,        openpic_attach),
   98 
   99         /* PIC interface */
  100         DEVMETHOD(pic_allocate_intr,    openpic_allocate_intr),
  101         DEVMETHOD(pic_setup_intr,       openpic_setup_intr),
  102         DEVMETHOD(pic_teardown_intr,    openpic_teardown_intr),
  103         DEVMETHOD(pic_release_intr,     openpic_release_intr),
  104 
  105         { 0, 0 }
  106 };
  107 
  108 static driver_t openpic_driver = {
  109         "openpic",
  110         openpic_methods,
  111         sizeof(struct openpic_softc)
  112 };
  113 
  114 static devclass_t       openpic_devclass;
  115 
  116 DRIVER_MODULE(openpic, nexus, openpic_driver, openpic_devclass, 0, 0);
  117 
  118 static struct   openpic_softc *softc;   /* XXX This limits us to one openpic */
  119 
  120 /*
  121  * Device interface
  122  */
  123 
  124 static int
  125 openpic_probe(device_t dev)
  126 {
  127         struct          openpic_softc *sc;
  128         phandle_t       node, parent;
  129         char            *type;
  130         char            *compat;
  131         u_int32_t       reg[5], val;
  132         vm_offset_t     macio_base;
  133         vm_offset_t     opic_base;
  134         
  135         sc = device_get_softc(dev);
  136         node = nexus_get_node(dev);
  137         type = nexus_get_device_type(dev);
  138         compat = nexus_get_compatible(dev);
  139 
  140         if (type == NULL)
  141                 return (ENXIO);
  142 
  143         if (strcmp(type, "open-pic") != 0)
  144                 return (ENXIO);
  145 
  146         if (strcmp(compat, "psim,open-pic") == 0) {
  147                 sc->sc_psim = 1;
  148 
  149                 if (OF_getprop(node, "reg", reg, sizeof(reg)) < 8)
  150                         return (ENXIO);
  151 
  152                 opic_base = reg[1];
  153         } else {
  154                 parent = OF_parent(node);
  155                 if (OF_getprop(parent, "assigned-addresses", 
  156                                reg, sizeof(reg)) < 20)
  157                         return (ENXIO);
  158                 
  159                 macio_base = (vm_offset_t)reg[2];
  160                 
  161                 if (OF_getprop(node, "reg", reg, sizeof(reg)) < 8)
  162                         return (ENXIO);
  163 
  164                 opic_base = macio_base + reg[0];
  165         }
  166 
  167         sc->sc_base = (vm_offset_t)pmap_mapdev(opic_base, OPENPIC_SIZE);
  168 
  169         val = openpic_read(sc, OPENPIC_FEATURE);
  170         switch (val & OPENPIC_FEATURE_VERSION_MASK) {
  171         case 1:
  172                 sc->sc_version = "1.0";
  173                 break;
  174         case 2:
  175                 sc->sc_version = "1.2";
  176                 break;
  177         case 3:
  178                 sc->sc_version = "1.3";
  179                 break;
  180         default:
  181                 sc->sc_version = "unknown";
  182                 break;
  183         }
  184 
  185         sc->sc_ncpu = ((val & OPENPIC_FEATURE_LAST_CPU_MASK) >>
  186             OPENPIC_FEATURE_LAST_CPU_SHIFT) + 1;
  187         sc->sc_nirq = ((val & OPENPIC_FEATURE_LAST_IRQ_MASK) >>
  188             OPENPIC_FEATURE_LAST_IRQ_SHIFT) + 1;
  189 
  190         /*
  191          * PSIM seems to report 1 too many IRQs
  192          */
  193         if (sc->sc_psim)
  194                 sc->sc_nirq--;
  195 
  196         device_set_desc(dev, "OpenPIC interrupt controller");
  197         return (0);
  198 }
  199 
  200 static int
  201 openpic_attach(device_t dev)
  202 {
  203         struct          openpic_softc *sc;
  204         u_int32_t       irq, x;
  205 
  206         sc = device_get_softc(dev);
  207         softc = sc;
  208 
  209         device_printf(dev,
  210             "Version %s, supports %d CPUs and %d irqs\n",
  211             sc->sc_version, sc->sc_ncpu, sc->sc_nirq);
  212 
  213         sc->sc_rman.rm_type = RMAN_ARRAY;
  214         sc->sc_rman.rm_descr = device_get_nameunit(dev);
  215 
  216         if (rman_init(&sc->sc_rman) != 0 ||
  217             rman_manage_region(&sc->sc_rman, 0, sc->sc_nirq - 1) != 0) {
  218                 device_printf(dev, "could not set up resource management");
  219                 return (ENXIO);
  220         }
  221 
  222         /* disable all interrupts */
  223         for (irq = 0; irq < sc->sc_nirq; irq++)
  224                 openpic_write(sc, OPENPIC_SRC_VECTOR(irq), OPENPIC_IMASK);
  225 
  226         openpic_set_priority(sc, 0, 15);
  227 
  228         /* we don't need 8259 passthrough mode */
  229         x = openpic_read(sc, OPENPIC_CONFIG);
  230         x |= OPENPIC_CONFIG_8259_PASSTHRU_DISABLE;
  231         openpic_write(sc, OPENPIC_CONFIG, x);
  232 
  233         /* send all interrupts to cpu 0 */
  234         for (irq = 0; irq < sc->sc_nirq; irq++)
  235                 openpic_write(sc, OPENPIC_IDEST(irq), 1 << 0);
  236 
  237         for (irq = 0; irq < sc->sc_nirq; irq++) {
  238                 x = irq;
  239                 x |= OPENPIC_IMASK;
  240                 x |= OPENPIC_POLARITY_POSITIVE;
  241                 x |= OPENPIC_SENSE_LEVEL;
  242                 x |= 8 << OPENPIC_PRIORITY_SHIFT;
  243                 openpic_write(sc, OPENPIC_SRC_VECTOR(irq), x);
  244         }
  245 
  246         /* XXX IPI */
  247         /* XXX set spurious intr vector */
  248 
  249         openpic_set_priority(sc, 0, 0);
  250 
  251         /* clear all pending interrupts */
  252         for (irq = 0; irq < sc->sc_nirq; irq++) {
  253                 openpic_read_irq(sc, 0);
  254                 openpic_eoi(sc, 0);
  255         }
  256 
  257         for (irq = 0; irq < sc->sc_nirq; irq++)
  258                 openpic_disable_irq(sc, irq);
  259 
  260         intr_init(openpic_intr, sc->sc_nirq, irq_enable, irq_disable);
  261 
  262         return (0);
  263 }
  264 
  265 /*
  266  * PIC interface
  267  */
  268 
  269 static struct resource *
  270 openpic_allocate_intr(device_t dev, device_t child, int *rid, u_long intr,
  271     u_int flags)
  272 {
  273         struct  openpic_softc *sc;
  274         struct  resource *rv;
  275         int     needactivate;
  276 
  277         sc = device_get_softc(dev);
  278         needactivate = flags & RF_ACTIVE;
  279         flags &= ~RF_ACTIVE;
  280 
  281         rv = rman_reserve_resource(&sc->sc_rman, intr, intr, 1, flags, child);
  282         if (rv == NULL) {
  283                 device_printf(dev, "interrupt reservation failed for %s\n",
  284                     device_get_nameunit(child));
  285                 return (NULL);
  286         }
  287 
  288         if (needactivate) {
  289                 if (bus_activate_resource(child, SYS_RES_IRQ, *rid, rv) != 0) {
  290                         device_printf(dev,
  291                             "resource activation failed for %s\n",
  292                             device_get_nameunit(child));
  293                         rman_release_resource(rv);
  294                         return (NULL);
  295                 }
  296         }
  297 
  298         return (rv);
  299 }
  300 
  301 static int
  302 openpic_setup_intr(device_t dev, device_t child, struct resource *res,
  303     int flags, driver_intr_t *intr, void *arg, void **cookiep)
  304 {
  305         struct  openpic_softc *sc;
  306         int     error;
  307 
  308         sc = device_get_softc(dev);
  309 
  310         if (res == NULL) {
  311                 device_printf(dev, "null interrupt resource from %s\n",
  312                     device_get_nameunit(child));
  313                 return (EINVAL);
  314         }
  315 
  316         if ((res->r_flags & RF_SHAREABLE) == 0)
  317                 flags |= INTR_EXCL;
  318 
  319         /*
  320          * We depend here on rman_activate_resource() being idempotent.
  321          */
  322         error = rman_activate_resource(res);
  323         if (error)
  324                 return (error);
  325 
  326         error = inthand_add(device_get_nameunit(child), res->r_start, intr,
  327             arg, flags, cookiep);
  328         openpic_enable_irq(sc, res->r_start, IST_LEVEL);
  329 
  330         return (error);
  331 }
  332 
  333 static int
  334 openpic_teardown_intr(device_t dev, device_t child, struct resource *res,
  335     void *ih)
  336 {
  337         int     error;
  338 
  339         error = rman_deactivate_resource(res);
  340         if (error)
  341                 return (error);
  342 
  343         error = inthand_remove(res->r_start, ih);
  344 
  345         return (error);
  346 }
  347 
  348 static int
  349 openpic_release_intr(device_t dev, device_t child, int rid,
  350     struct resource *res)
  351 {
  352         int     error;
  353 
  354         if (rman_get_flags(res) & RF_ACTIVE) {
  355                 error = bus_deactivate_resource(child, SYS_RES_IRQ, rid, res);
  356                 if (error)
  357                         return (error);
  358         }
  359 
  360         return (rman_release_resource(res));
  361 }
  362 
  363 /*
  364  * Local routines
  365  */
  366 
  367 static u_int
  368 openpic_read(struct openpic_softc *sc, int reg)
  369 {
  370         volatile unsigned char *addr;
  371 
  372         addr = (unsigned char *)sc->sc_base + reg;
  373 #if 0
  374         printf("openpic: reading from %p (0x%08x + 0x%08x)\n", addr,
  375             sc->sc_base, reg);
  376 #endif
  377 
  378         return in32rb(addr);
  379 }
  380 
  381 static void
  382 openpic_write(struct openpic_softc *sc, int reg, u_int val)
  383 {
  384         volatile unsigned char *addr;
  385 
  386         addr = (unsigned char *)sc->sc_base + reg;
  387 #if 0
  388         printf("openpic: writing to %p (0x%08x + 0x%08x)\n", addr, sc->sc_base,
  389             reg);
  390 #endif
  391 
  392         out32rb(addr, val);
  393 }
  394 
  395 static int
  396 openpic_read_irq(struct openpic_softc *sc, int cpu)
  397 {
  398         return openpic_read(sc, OPENPIC_IACK(cpu)) & OPENPIC_VECTOR_MASK;
  399 }
  400 
  401 static void
  402 openpic_eoi(struct openpic_softc *sc, int cpu)
  403 {
  404         openpic_write(sc, OPENPIC_EOI(cpu), 0);
  405         if (!sc->sc_psim) {
  406                 /*
  407                  * Probably not needed, since appropriate eieio/sync
  408                  * is done in out32rb. See Darwin src.
  409                  */
  410                 openpic_read(sc, OPENPIC_EOI(cpu));
  411         }
  412 }
  413 
  414 static void
  415 openpic_enable_irq(struct openpic_softc *sc, int irq, int type)
  416 {
  417         u_int   x;
  418 
  419         x = openpic_read(sc, OPENPIC_SRC_VECTOR(irq));
  420         x &= ~(OPENPIC_IMASK | OPENPIC_SENSE_LEVEL | OPENPIC_SENSE_EDGE);
  421         if (type == IST_LEVEL)
  422                 x |= OPENPIC_SENSE_LEVEL;
  423         else
  424                 x |= OPENPIC_SENSE_EDGE;
  425         openpic_write(sc, OPENPIC_SRC_VECTOR(irq), x);
  426 }
  427 
  428 static void
  429 openpic_disable_irq(struct openpic_softc *sc, int irq)
  430 {
  431         u_int   x;
  432 
  433         x = openpic_read(sc, OPENPIC_SRC_VECTOR(irq));
  434         x |= OPENPIC_IMASK;
  435         openpic_write(sc, OPENPIC_SRC_VECTOR(irq), x);
  436 }
  437 
  438 static void
  439 openpic_set_priority(struct openpic_softc *sc, int cpu, int pri)
  440 {
  441         u_int   x;
  442 
  443         x = openpic_read(sc, OPENPIC_CPU_PRIORITY(cpu));
  444         x &= ~OPENPIC_CPU_PRIORITY_MASK;
  445         x |= pri;
  446         openpic_write(sc, OPENPIC_CPU_PRIORITY(cpu), x);
  447 }
  448 
  449 static void
  450 openpic_intr(void)
  451 {
  452         int             irq;
  453         u_int32_t       msr;
  454 
  455         msr = mfmsr();
  456 
  457         irq = openpic_read_irq(softc, 0);
  458         if (irq == 255) {
  459                 return;
  460         }
  461 
  462 start:
  463         openpic_disable_irq(softc, irq);
  464         /*mtmsr(msr | PSL_EE);*/
  465 
  466         /* do the interrupt thang */
  467         intr_handle(irq);
  468 
  469         mtmsr(msr);
  470 
  471         openpic_eoi(softc, 0);
  472 
  473         irq = openpic_read_irq(softc, 0);
  474         if (irq != 255)
  475                 goto start;
  476 }
  477 
  478 static void
  479 irq_enable(uintptr_t irq)
  480 {
  481 
  482         openpic_enable_irq(softc, irq, IST_LEVEL);
  483 }
  484 
  485 static void
  486 irq_disable(uintptr_t irq)
  487 {
  488 
  489         openpic_disable_irq(softc, irq);
  490 }

Cache object: 9fafab87295c75078c6d23d1a8e158a4


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