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/dev/mvme/vme_two_isr.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 /*      $NetBSD: vme_two_isr.c,v 1.11 2008/04/28 20:23:54 martin Exp $  */
    2 
    3 /*-
    4  * Copyright (c) 2001, 2002 The NetBSD Foundation, Inc.
    5  * All rights reserved.
    6  *
    7  * This code is derived from software contributed to The NetBSD Foundation
    8  * by Steve C. Woodford.
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   29  * POSSIBILITY OF SUCH DAMAGE.
   30  */
   31 
   32 /*
   33  * Split off from vme_two.c specifically to deal with hardware assisted
   34  * soft interrupts when the user hasn't specified `vmetwo0' in the
   35  * kernel config file (mvme1[67]2 only).
   36  */
   37 
   38 #include <sys/cdefs.h>
   39 __KERNEL_RCSID(0, "$NetBSD: vme_two_isr.c,v 1.11 2008/04/28 20:23:54 martin Exp $");
   40 
   41 #include "vmetwo.h"
   42 
   43 #include <sys/param.h>
   44 #include <sys/kernel.h>
   45 #include <sys/systm.h>
   46 #include <sys/device.h>
   47 #include <sys/malloc.h>
   48 #include <sys/cpu.h>
   49 #include <sys/bus.h>
   50 
   51 #include <dev/vme/vmereg.h>
   52 #include <dev/vme/vmevar.h>
   53 
   54 #include <dev/mvme/mvmebus.h>
   55 #include <dev/mvme/vme_tworeg.h>
   56 #include <dev/mvme/vme_twovar.h>
   57 
   58 /*
   59  * Non-zero if there is no VMEChip2 on this board.
   60  */
   61 int vmetwo_not_present;
   62 
   63 /*
   64  * Array of interrupt handlers registered with us for the non-VMEbus
   65  * vectored interrupts. Eg. ABORT Switch, SYSFAIL etc.
   66  *
   67  * We can't just install a caller's handler directly, since these
   68  * interrupts have to be manually cleared, so we have a trampoline
   69  * which does the clearing automatically.
   70  */
   71 static struct vme_two_handler {
   72         int (*isr_hand)(void *);
   73         void *isr_arg;
   74 } vme_two_handlers[(VME2_VECTOR_LOCAL_MAX - VME2_VECTOR_LOCAL_MIN) + 1];
   75 
   76 #define VMETWO_HANDLERS_SZ      (sizeof(vme_two_handlers) /     \
   77                                  sizeof(struct vme_two_handler))
   78 
   79 static  int  vmetwo_local_isr_trampoline(void *);
   80 #ifdef notyet
   81 static  void vmetwo_softintr_assert(void);
   82 #endif
   83 
   84 static  struct vmetwo_softc *vmetwo_sc;
   85 
   86 int
   87 vmetwo_probe(bus_space_tag_t bt, bus_addr_t offset)
   88 {
   89         bus_space_handle_t bh;
   90 
   91         bus_space_map(bt, offset + VME2REG_LCSR_OFFSET, VME2LCSR_SIZE, 0, &bh);
   92 
   93         if (bus_space_peek_4(bt, bh, VME2LCSR_MISC_STATUS, NULL) != 0) {
   94 #if defined(MVME162) || defined(MVME172)
   95 #if defined(MVME167) || defined(MVME177)
   96                 if (machineid == MVME_162 || machineid == MVME_172)
   97 #endif
   98                 {
   99                         /*
  100                          * No VMEChip2 on mvme162/172 is not too big a
  101                          * deal; we can fall back on timer4 in the
  102                          * mcchip for h/w assisted soft interrupts...
  103                          */
  104                         extern void pcctwosoftintrinit(void);
  105                         bus_space_unmap(bt, bh, VME2LCSR_SIZE);
  106                         vmetwo_not_present = 1;
  107                         pcctwosoftintrinit();
  108                         return (0);
  109                 }
  110 #endif
  111 #if defined(MVME167) || defined(MVME177) || defined(MVME88K)
  112                 /*
  113                  * No VMEChip2 on mvme167/177, however, is a Big Deal.
  114                  * In fact, it means the hardware's shot since the
  115                  * VMEChip2 is not a `build-option' on those boards.
  116                  */
  117                 panic("VMEChip2 not responding! Faulty board?");
  118                 /* NOTREACHED */
  119 #endif
  120 #if defined(MVMEPPC)
  121                 /*
  122                  * No VMEChip2 on mvmeppc is no big deal.
  123                  */
  124                 bus_space_unmap(bt, bh, VME2LCSR_SIZE);
  125                 vmetwo_not_present = 1;
  126                 return (0);
  127 #endif
  128         }
  129 #if NVMETWO == 0
  130         else {
  131                 /*
  132                  * The kernel config file has no `vmetwo0' device, but
  133                  * there is a VMEChip2 on the board. Fix up things
  134                  * just enough to hook VMEChip2 local interrupts.
  135                  */
  136                 struct vmetwo_softc *sc;
  137 
  138                 /* XXX Should check sc != NULL here... */
  139                 MALLOC(sc, struct vmetwo_softc *, sizeof(*sc), M_DEVBUF,
  140                     M_NOWAIT);
  141 
  142                 sc->sc_mvmebus.sc_bust = bt;
  143                 sc->sc_lcrh = bh;
  144                 vmetwo_intr_init(sc);
  145                 return 0;
  146         }
  147 #else
  148         bus_space_unmap(bt, bh, VME2LCSR_SIZE);
  149         return (1);
  150 #endif
  151 }
  152 
  153 void
  154 vmetwo_intr_init(struct vmetwo_softc *sc)
  155 {
  156         u_int32_t reg;
  157         int i;
  158 
  159         vmetwo_sc = sc;
  160 
  161         /* Clear out the ISR handler array */
  162         for (i = 0; i < VMETWO_HANDLERS_SZ; i++)
  163                 vme_two_handlers[i].isr_hand = NULL;
  164 
  165         /*
  166          * Initialize the chip.
  167          * Firstly, disable all VMEChip2 Interrupts
  168          */
  169         reg = vme2_lcsr_read(sc, VME2LCSR_MISC_STATUS) & ~VME2_MISC_STATUS_MIEN;
  170         vme2_lcsr_write(sc, VME2LCSR_MISC_STATUS, reg);
  171         vme2_lcsr_write(sc, VME2LCSR_LOCAL_INTERRUPT_ENABLE, 0);
  172         vme2_lcsr_write(sc, VME2LCSR_LOCAL_INTERRUPT_CLEAR,
  173             VME2_LOCAL_INTERRUPT_CLEAR_ALL);
  174 
  175         /* Zap all the IRQ level registers */
  176         for (i = 0; i < VME2_NUM_IL_REGS; i++)
  177                 vme2_lcsr_write(sc, VME2LCSR_INTERRUPT_LEVEL_BASE + (i * 4), 0);
  178 
  179         /* Disable the tick timers */
  180         reg = vme2_lcsr_read(sc, VME2LCSR_TIMER_CONTROL);
  181         reg &= ~VME2_TIMER_CONTROL_EN(0);
  182         reg &= ~VME2_TIMER_CONTROL_EN(1);
  183         vme2_lcsr_write(sc, VME2LCSR_TIMER_CONTROL, reg);
  184 
  185         /* Set the VMEChip2's vector base register to the required value */
  186         reg = vme2_lcsr_read(sc, VME2LCSR_VECTOR_BASE);
  187         reg &= ~VME2_VECTOR_BASE_MASK;
  188         reg |= VME2_VECTOR_BASE_REG_VALUE;
  189         vme2_lcsr_write(sc, VME2LCSR_VECTOR_BASE, reg);
  190 
  191         /* Set the Master Interrupt Enable bit now */
  192         reg = vme2_lcsr_read(sc, VME2LCSR_MISC_STATUS) | VME2_MISC_STATUS_MIEN;
  193         vme2_lcsr_write(sc, VME2LCSR_MISC_STATUS, reg);
  194 
  195         /* Allow the MD code the chance to do some initialising */
  196         vmetwo_md_intr_init(sc);
  197 
  198 #if defined(MVME167) || defined(MVME177)
  199 #if defined(MVME162) || defined(MVME172)
  200         if (machineid != MVME_162 && machineid != MVME_172)
  201 #endif
  202         {
  203                 /*
  204                  * Let the NMI handler deal with level 7 ABORT switch
  205                  * interrupts
  206                  */
  207                 vmetwo_intr_establish(sc, 7, 7, VME2_VEC_ABORT, 1,
  208                     nmihand, NULL, NULL);
  209         }
  210 #endif
  211 
  212         /* Setup hardware assisted soft interrupts */
  213 #ifdef notyet
  214         vmetwo_intr_establish(sc, 1, 1, VME2_VEC_SOFT0, 1,
  215             (int (*)(void *))softintr_dispatch, NULL, NULL);
  216         _softintr_chipset_assert = vmetwo_softintr_assert;
  217 #endif
  218 }
  219 
  220 static int
  221 vmetwo_local_isr_trampoline(arg)
  222         void *arg;
  223 {
  224         struct vme_two_handler *isr;
  225         int vec;
  226 
  227         vec = (int) arg;        /* 0x08 <= vec <= 0x1f */
  228 
  229         /* Clear the interrupt source */
  230         vme2_lcsr_write(vmetwo_sc, VME2LCSR_LOCAL_INTERRUPT_CLEAR,
  231             VME2_LOCAL_INTERRUPT(vec));
  232 
  233         isr = &vme_two_handlers[vec - VME2_VECTOR_LOCAL_OFFSET];
  234         if (isr->isr_hand)
  235                 (void) (*isr->isr_hand) (isr->isr_arg);
  236         else
  237                 printf("vmetwo: Spurious local interrupt, vector 0x%x\n", vec);
  238 
  239         return (1);
  240 }
  241 
  242 void
  243 vmetwo_local_intr_establish(pri, vec, hand, arg, evcnt)
  244         int pri, vec;
  245         int (*hand)(void *);
  246         void *arg;
  247         struct evcnt *evcnt;
  248 {
  249 
  250         vmetwo_intr_establish(vmetwo_sc, pri, pri, vec, 1, hand, arg, evcnt);
  251 }
  252 
  253 /* ARGSUSED */
  254 void
  255 vmetwo_intr_establish(csc, prior, lvl, vec, first, hand, arg, evcnt)
  256         void *csc;
  257         int prior, lvl, vec, first;
  258         int (*hand)(void *);
  259         void *arg;
  260         struct evcnt *evcnt;
  261 {
  262         struct vmetwo_softc *sc = csc;
  263         u_int32_t reg;
  264         int bitoff;
  265         int iloffset, ilshift;
  266         int s;
  267 
  268         s = splhigh();
  269 
  270 #if NVMETWO > 0
  271         /*
  272          * Sort out interrupts generated locally by the VMEChip2 from
  273          * those generated by VMEbus devices...
  274          */
  275         if (vec >= VME2_VECTOR_LOCAL_MIN && vec <= VME2_VECTOR_LOCAL_MAX) {
  276 #endif
  277                 /*
  278                  * Local interrupts need to be bounced through some
  279                  * trampoline code which acknowledges/clears them.
  280                  */
  281                 vme_two_handlers[vec - VME2_VECTOR_LOCAL_MIN].isr_hand = hand;
  282                 vme_two_handlers[vec - VME2_VECTOR_LOCAL_MIN].isr_arg = arg;
  283                 hand = vmetwo_local_isr_trampoline;
  284                 arg = (void *) (vec - VME2_VECTOR_BASE);
  285 
  286                 /*
  287                  * Interrupt enable/clear bit offset is 0x08 - 0x1f
  288                  */
  289                 bitoff = vec - VME2_VECTOR_BASE;
  290 #if NVMETWO > 0
  291                 first = 1;      /* Force the interrupt to be enabled */
  292         } else {
  293                 /*
  294                  * Interrupts originating from the VMEbus are
  295                  * controlled by an offset of 0x00 - 0x07
  296                  */
  297                 bitoff = lvl - 1;
  298         }
  299 #endif
  300 
  301         /* Hook the interrupt */
  302         (*sc->sc_isrlink)(sc->sc_isrcookie, hand, arg, prior, vec, evcnt);
  303 
  304         /*
  305          * Do we need to tell the VMEChip2 to let the interrupt through?
  306          * (This is always true for locally-generated interrupts, but only
  307          * needs doing once for each VMEbus interrupt level which is hooked)
  308          */
  309 #if NVMETWO > 0
  310         if (first) {
  311                 if (evcnt)
  312                         evcnt_attach_dynamic(evcnt, EVCNT_TYPE_INTR,
  313                             (*sc->sc_isrevcnt)(sc->sc_isrcookie, prior),
  314                             device_xname(&sc->sc_mvmebus.sc_dev),
  315                             mvmebus_irq_name[lvl]);
  316 #endif
  317                 iloffset = VME2_ILOFFSET_FROM_VECTOR(bitoff) +
  318                     VME2LCSR_INTERRUPT_LEVEL_BASE;
  319                 ilshift = VME2_ILSHIFT_FROM_VECTOR(bitoff);
  320 
  321                 /* Program the specified interrupt to signal at 'prior' */
  322                 reg = vme2_lcsr_read(sc, iloffset);
  323                 reg &= ~(VME2_INTERRUPT_LEVEL_MASK << ilshift);
  324                 reg |= (prior << ilshift);
  325                 vme2_lcsr_write(sc, iloffset, reg);
  326 
  327                 /* Clear it */
  328                 vme2_lcsr_write(sc, VME2LCSR_LOCAL_INTERRUPT_CLEAR,
  329                     VME2_LOCAL_INTERRUPT(bitoff));
  330 
  331                 /* Enable it. */
  332                 reg = vme2_lcsr_read(sc, VME2LCSR_LOCAL_INTERRUPT_ENABLE);
  333                 reg |= VME2_LOCAL_INTERRUPT(bitoff);
  334                 vme2_lcsr_write(sc, VME2LCSR_LOCAL_INTERRUPT_ENABLE, reg);
  335 #if NVMETWO > 0
  336         }
  337 #ifdef DIAGNOSTIC
  338         else {
  339                 /* Verify the interrupt priority is the same */
  340                 iloffset = VME2_ILOFFSET_FROM_VECTOR(bitoff) +
  341                     VME2LCSR_INTERRUPT_LEVEL_BASE;
  342                 ilshift = VME2_ILSHIFT_FROM_VECTOR(bitoff);
  343 
  344                 reg = vme2_lcsr_read(sc, iloffset);
  345                 reg &= (VME2_INTERRUPT_LEVEL_MASK << ilshift);
  346 
  347                 if ((prior << ilshift) != reg)
  348                         panic("vmetwo_intr_establish: priority mismatch!");
  349         }
  350 #endif
  351 #endif
  352         splx(s);
  353 }
  354 
  355 void
  356 vmetwo_intr_disestablish(csc, lvl, vec, last, evcnt)
  357         void *csc;
  358         int lvl, vec, last;
  359         struct evcnt *evcnt;
  360 {
  361         struct vmetwo_softc *sc = csc;
  362         u_int32_t reg;
  363         int iloffset, ilshift;
  364         int bitoff;
  365         int s;
  366 
  367         s = splhigh();
  368 
  369 #if NVMETWO > 0
  370         /*
  371          * Sort out interrupts generated locally by the VMEChip2 from
  372          * those generated by VMEbus devices...
  373          */
  374         if (vec >= VME2_VECTOR_LOCAL_MIN && vec <= VME2_VECTOR_LOCAL_MAX) {
  375 #endif
  376                 /*
  377                  * Interrupt enable/clear bit offset is 0x08 - 0x1f
  378                  */
  379                 bitoff = vec - VME2_VECTOR_BASE;
  380                 vme_two_handlers[vec - VME2_VECTOR_LOCAL_MIN].isr_hand = NULL;
  381                 last = 1; /* Force the interrupt to be cleared */
  382 #if NVMETWO > 0
  383         } else {
  384                 /*
  385                  * Interrupts originating from the VMEbus are
  386                  * controlled by an offset of 0x00 - 0x07
  387                  */
  388                 bitoff = lvl - 1;
  389         }
  390 #endif
  391 
  392         /*
  393          * Do we need to tell the VMEChip2 to block the interrupt?
  394          * (This is always true for locally-generated interrupts, but only
  395          * needs doing once when the last VMEbus handler for any given level
  396          * has been unhooked.)
  397          */
  398         if (last) {
  399                 iloffset = VME2_ILOFFSET_FROM_VECTOR(bitoff) +
  400                     VME2LCSR_INTERRUPT_LEVEL_BASE;
  401                 ilshift = VME2_ILSHIFT_FROM_VECTOR(bitoff);
  402 
  403                 /* Disable it. */
  404                 reg = vme2_lcsr_read(sc, VME2LCSR_LOCAL_INTERRUPT_ENABLE);
  405                 reg &= ~VME2_LOCAL_INTERRUPT(bitoff);
  406                 vme2_lcsr_write(sc, VME2LCSR_LOCAL_INTERRUPT_ENABLE, reg);
  407 
  408                 /* Set the interrupt's level to zero */
  409                 reg = vme2_lcsr_read(sc, iloffset);
  410                 reg &= ~(VME2_INTERRUPT_LEVEL_MASK << ilshift);
  411                 vme2_lcsr_write(sc, iloffset, reg);
  412 
  413                 /* Clear it */
  414                 vme2_lcsr_write(sc, VME2LCSR_LOCAL_INTERRUPT_CLEAR,
  415                     VME2_LOCAL_INTERRUPT(vec));
  416 
  417                 if (evcnt)
  418                         evcnt_detach(evcnt);
  419         }
  420         /* Un-hook it */
  421         (*sc->sc_isrunlink)(sc->sc_isrcookie, vec);
  422 
  423         splx(s);
  424 }
  425 
  426 #ifdef notyet
  427 static void
  428 vmetwo_softintr_assert(void)
  429 {
  430 
  431         vme2_lcsr_write(vmetwo_sc, VME2LCSR_SOFTINT_SET, VME2_SOFTINT_SET(0));
  432 }
  433 #endif

Cache object: 66d4642e15aed36f5d5e2db2f8e79731


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