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.17 2019/11/10 21:16:36 chs 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.17 2019/11/10 21:16:36 chs 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                 sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK);
  139                 sc->sc_mvmebus.sc_bust = bt;
  140                 sc->sc_lcrh = bh;
  141                 vmetwo_intr_init(sc);
  142                 return 0;
  143         }
  144 #else
  145         bus_space_unmap(bt, bh, VME2LCSR_SIZE);
  146         return (1);
  147 #endif
  148 }
  149 
  150 void
  151 vmetwo_intr_init(struct vmetwo_softc *sc)
  152 {
  153         u_int32_t reg;
  154         int i;
  155 
  156         vmetwo_sc = sc;
  157 
  158         /* Clear out the ISR handler array */
  159         for (i = 0; i < VMETWO_HANDLERS_SZ; i++)
  160                 vme_two_handlers[i].isr_hand = NULL;
  161 
  162         /*
  163          * Initialize the chip.
  164          * Firstly, disable all VMEChip2 Interrupts
  165          */
  166         reg = vme2_lcsr_read(sc, VME2LCSR_MISC_STATUS) & ~VME2_MISC_STATUS_MIEN;
  167         vme2_lcsr_write(sc, VME2LCSR_MISC_STATUS, reg);
  168         vme2_lcsr_write(sc, VME2LCSR_LOCAL_INTERRUPT_ENABLE, 0);
  169         vme2_lcsr_write(sc, VME2LCSR_LOCAL_INTERRUPT_CLEAR,
  170             VME2_LOCAL_INTERRUPT_CLEAR_ALL);
  171 
  172         /* Zap all the IRQ level registers */
  173         for (i = 0; i < VME2_NUM_IL_REGS; i++)
  174                 vme2_lcsr_write(sc, VME2LCSR_INTERRUPT_LEVEL_BASE + (i * 4), 0);
  175 
  176         /* Disable the tick timers */
  177         reg = vme2_lcsr_read(sc, VME2LCSR_TIMER_CONTROL);
  178         reg &= ~VME2_TIMER_CONTROL_EN(0);
  179         reg &= ~VME2_TIMER_CONTROL_EN(1);
  180         vme2_lcsr_write(sc, VME2LCSR_TIMER_CONTROL, reg);
  181 
  182         /* Set the VMEChip2's vector base register to the required value */
  183         reg = vme2_lcsr_read(sc, VME2LCSR_VECTOR_BASE);
  184         reg &= ~VME2_VECTOR_BASE_MASK;
  185         reg |= VME2_VECTOR_BASE_REG_VALUE;
  186         vme2_lcsr_write(sc, VME2LCSR_VECTOR_BASE, reg);
  187 
  188         /* Set the Master Interrupt Enable bit now */
  189         reg = vme2_lcsr_read(sc, VME2LCSR_MISC_STATUS) | VME2_MISC_STATUS_MIEN;
  190         vme2_lcsr_write(sc, VME2LCSR_MISC_STATUS, reg);
  191 
  192         /* Allow the MD code the chance to do some initialising */
  193         vmetwo_md_intr_init(sc);
  194 
  195 #if defined(MVME167) || defined(MVME177)
  196 #if defined(MVME162) || defined(MVME172)
  197         if (machineid != MVME_162 && machineid != MVME_172)
  198 #endif
  199         {
  200                 /*
  201                  * Let the NMI handler deal with level 7 ABORT switch
  202                  * interrupts
  203                  */
  204                 vmetwo_intr_establish(sc, 7, 7, VME2_VEC_ABORT, 1,
  205                     nmihand, NULL, NULL);
  206         }
  207 #endif
  208 
  209         /* Setup hardware assisted soft interrupts */
  210 #ifdef notyet
  211         vmetwo_intr_establish(sc, 1, 1, VME2_VEC_SOFT0, 1,
  212             (int (*)(void *))softintr_dispatch, NULL, NULL);
  213         _softintr_chipset_assert = vmetwo_softintr_assert;
  214 #endif
  215 }
  216 
  217 static int
  218 vmetwo_local_isr_trampoline(void *arg)
  219 {
  220         struct vme_two_handler *isr;
  221         int vec;
  222 
  223         vec = (int) arg;        /* 0x08 <= vec <= 0x1f */
  224 
  225         /* Clear the interrupt source */
  226         vme2_lcsr_write(vmetwo_sc, VME2LCSR_LOCAL_INTERRUPT_CLEAR,
  227             VME2_LOCAL_INTERRUPT(vec));
  228 
  229         isr = &vme_two_handlers[vec - VME2_VECTOR_LOCAL_OFFSET];
  230         if (isr->isr_hand)
  231                 (void) (*isr->isr_hand) (isr->isr_arg);
  232         else
  233                 printf("vmetwo: Spurious local interrupt, vector 0x%x\n", vec);
  234 
  235         return (1);
  236 }
  237 
  238 void
  239 vmetwo_local_intr_establish(int pri, int vec, int (*hand)(void *), void *arg, struct evcnt *evcnt)
  240 {
  241 
  242         vmetwo_intr_establish(vmetwo_sc, pri, pri, vec, 1, hand, arg, evcnt);
  243 }
  244 
  245 /* ARGSUSED */
  246 void
  247 vmetwo_intr_establish(void *csc, int prior, int lvl, int vec, int first, int (*hand)(void *), void *arg, struct evcnt *evcnt)
  248 {
  249         struct vmetwo_softc *sc = csc;
  250         u_int32_t reg;
  251         int bitoff;
  252         int iloffset, ilshift;
  253         int s;
  254 
  255         s = splhigh();
  256 
  257 #if NVMETWO > 0
  258         /*
  259          * Sort out interrupts generated locally by the VMEChip2 from
  260          * those generated by VMEbus devices...
  261          */
  262         if (vec >= VME2_VECTOR_LOCAL_MIN && vec <= VME2_VECTOR_LOCAL_MAX) {
  263 #endif
  264                 /*
  265                  * Local interrupts need to be bounced through some
  266                  * trampoline code which acknowledges/clears them.
  267                  */
  268                 vme_two_handlers[vec - VME2_VECTOR_LOCAL_MIN].isr_hand = hand;
  269                 vme_two_handlers[vec - VME2_VECTOR_LOCAL_MIN].isr_arg = arg;
  270                 hand = vmetwo_local_isr_trampoline;
  271                 arg = (void *) (vec - VME2_VECTOR_BASE);
  272 
  273                 /*
  274                  * Interrupt enable/clear bit offset is 0x08 - 0x1f
  275                  */
  276                 bitoff = vec - VME2_VECTOR_BASE;
  277 #if NVMETWO > 0
  278                 first = 1;      /* Force the interrupt to be enabled */
  279         } else {
  280                 /*
  281                  * Interrupts originating from the VMEbus are
  282                  * controlled by an offset of 0x00 - 0x07
  283                  */
  284                 bitoff = lvl - 1;
  285         }
  286 #endif
  287 
  288         /* Hook the interrupt */
  289         (*sc->sc_isrlink)(sc->sc_isrcookie, hand, arg, prior, vec, evcnt);
  290 
  291         /*
  292          * Do we need to tell the VMEChip2 to let the interrupt through?
  293          * (This is always true for locally-generated interrupts, but only
  294          * needs doing once for each VMEbus interrupt level which is hooked)
  295          */
  296 #if NVMETWO > 0
  297         if (first) {
  298                 if (evcnt)
  299                         evcnt_attach_dynamic(evcnt, EVCNT_TYPE_INTR,
  300                             (*sc->sc_isrevcnt)(sc->sc_isrcookie, prior),
  301                             device_xname(sc->sc_mvmebus.sc_dev),
  302                             mvmebus_irq_name[lvl]);
  303 #endif
  304                 iloffset = VME2_ILOFFSET_FROM_VECTOR(bitoff) +
  305                     VME2LCSR_INTERRUPT_LEVEL_BASE;
  306                 ilshift = VME2_ILSHIFT_FROM_VECTOR(bitoff);
  307 
  308                 /* Program the specified interrupt to signal at 'prior' */
  309                 reg = vme2_lcsr_read(sc, iloffset);
  310                 reg &= ~(VME2_INTERRUPT_LEVEL_MASK << ilshift);
  311                 reg |= (prior << ilshift);
  312                 vme2_lcsr_write(sc, iloffset, reg);
  313 
  314                 /* Clear it */
  315                 vme2_lcsr_write(sc, VME2LCSR_LOCAL_INTERRUPT_CLEAR,
  316                     VME2_LOCAL_INTERRUPT(bitoff));
  317 
  318                 /* Enable it. */
  319                 reg = vme2_lcsr_read(sc, VME2LCSR_LOCAL_INTERRUPT_ENABLE);
  320                 reg |= VME2_LOCAL_INTERRUPT(bitoff);
  321                 vme2_lcsr_write(sc, VME2LCSR_LOCAL_INTERRUPT_ENABLE, reg);
  322 #if NVMETWO > 0
  323         }
  324 #ifdef DIAGNOSTIC
  325         else {
  326                 /* Verify the interrupt priority is the same */
  327                 iloffset = VME2_ILOFFSET_FROM_VECTOR(bitoff) +
  328                     VME2LCSR_INTERRUPT_LEVEL_BASE;
  329                 ilshift = VME2_ILSHIFT_FROM_VECTOR(bitoff);
  330 
  331                 reg = vme2_lcsr_read(sc, iloffset);
  332                 reg &= (VME2_INTERRUPT_LEVEL_MASK << ilshift);
  333 
  334                 if ((prior << ilshift) != reg)
  335                         panic("vmetwo_intr_establish: priority mismatch!");
  336         }
  337 #endif
  338 #endif
  339         splx(s);
  340 }
  341 
  342 void
  343 vmetwo_intr_disestablish(void *csc, int lvl, int vec, int last, struct evcnt *evcnt)
  344 {
  345         struct vmetwo_softc *sc = csc;
  346         u_int32_t reg;
  347         int iloffset, ilshift;
  348         int bitoff;
  349         int s;
  350 
  351         s = splhigh();
  352 
  353 #if NVMETWO > 0
  354         /*
  355          * Sort out interrupts generated locally by the VMEChip2 from
  356          * those generated by VMEbus devices...
  357          */
  358         if (vec >= VME2_VECTOR_LOCAL_MIN && vec <= VME2_VECTOR_LOCAL_MAX) {
  359 #endif
  360                 /*
  361                  * Interrupt enable/clear bit offset is 0x08 - 0x1f
  362                  */
  363                 bitoff = vec - VME2_VECTOR_BASE;
  364                 vme_two_handlers[vec - VME2_VECTOR_LOCAL_MIN].isr_hand = NULL;
  365                 last = 1; /* Force the interrupt to be cleared */
  366 #if NVMETWO > 0
  367         } else {
  368                 /*
  369                  * Interrupts originating from the VMEbus are
  370                  * controlled by an offset of 0x00 - 0x07
  371                  */
  372                 bitoff = lvl - 1;
  373         }
  374 #endif
  375 
  376         /*
  377          * Do we need to tell the VMEChip2 to block the interrupt?
  378          * (This is always true for locally-generated interrupts, but only
  379          * needs doing once when the last VMEbus handler for any given level
  380          * has been unhooked.)
  381          */
  382         if (last) {
  383                 iloffset = VME2_ILOFFSET_FROM_VECTOR(bitoff) +
  384                     VME2LCSR_INTERRUPT_LEVEL_BASE;
  385                 ilshift = VME2_ILSHIFT_FROM_VECTOR(bitoff);
  386 
  387                 /* Disable it. */
  388                 reg = vme2_lcsr_read(sc, VME2LCSR_LOCAL_INTERRUPT_ENABLE);
  389                 reg &= ~VME2_LOCAL_INTERRUPT(bitoff);
  390                 vme2_lcsr_write(sc, VME2LCSR_LOCAL_INTERRUPT_ENABLE, reg);
  391 
  392                 /* Set the interrupt's level to zero */
  393                 reg = vme2_lcsr_read(sc, iloffset);
  394                 reg &= ~(VME2_INTERRUPT_LEVEL_MASK << ilshift);
  395                 vme2_lcsr_write(sc, iloffset, reg);
  396 
  397                 /* Clear it */
  398                 vme2_lcsr_write(sc, VME2LCSR_LOCAL_INTERRUPT_CLEAR,
  399                     VME2_LOCAL_INTERRUPT(vec));
  400 
  401                 if (evcnt)
  402                         evcnt_detach(evcnt);
  403         }
  404         /* Un-hook it */
  405         (*sc->sc_isrunlink)(sc->sc_isrcookie, vec);
  406 
  407         splx(s);
  408 }
  409 
  410 #ifdef notyet
  411 static void
  412 vmetwo_softintr_assert(void)
  413 {
  414 
  415         vme2_lcsr_write(vmetwo_sc, VME2LCSR_SOFTINT_SET, VME2_SOFTINT_SET(0));
  416 }
  417 #endif

Cache object: e01890916689af2d850e73a4268d3087


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