1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 #if defined(lint)
  27 #include <sys/types.h>
  28 #include <sys/thread.h>
  29 #else   /* lint */
  30 #include "assym.h"
  31 #endif  /* lint */
  32 
  33 #include <sys/asm_linkage.h>
  34 #include <sys/machthread.h>
  35 #include <sys/machcpuvar.h>
  36 #include <sys/mmu.h>
  37 #include <sys/intreg.h>
  38 #include <sys/dmv.h>
  39 
  40 #ifdef TRAPTRACE
  41 #include <sys/traptrace.h>
  42 #endif /* TRAPTRACE */
  43 
  44 
  45 #if defined(lint)
  46 
  47 void
  48 vec_interrupt(void)
  49 {}
  50 
  51 #else   /* lint */
  52 
  53 vec_uiii_irdr_tab:
  54         .byte   UIII_IRDR_0, UIII_IRDR_1, UIII_IRDR_2, UIII_IRDR_3
  55         .byte   UIII_IRDR_4, UIII_IRDR_5, UIII_IRDR_6, UIII_IRDR_7
  56 
  57 /*
  58  * (TT 0x60, TL>0) Interrupt Vector Handler
  59  *      Globals are the Interrupt Globals.
  60  */
  61         ENTRY_NP(vec_interrupt)
  62         !
  63         ! Load the interrupt receive data register 0.
  64         ! It could be a fast trap handler address (pc > KERNELBASE) at TL>0
  65         ! or an interrupt number.
  66         !
  67         mov     IRDR_0, %g2
  68         ldxa    [%g2]ASI_INTR_RECEIVE, %g5      ! %g5 = PC or Interrupt Number
  69 
  70         ! If the high bit of IRDR_0 is set, then this is a
  71         ! data bearing mondo vector.
  72         brlz,pt %g5, dmv_vector
  73         .empty
  74 
  75 
  76 vec_interrupt_resume:   
  77         set     KERNELBASE, %g4
  78         cmp     %g5, %g4
  79         bl,a,pt %xcc, 0f                        ! an interrupt number found
  80           nop
  81         !
  82         ! intercept OBP xcalls and set PCONTEXT=0
  83         !
  84         set     _end, %g4               ! _end is highest kernel address
  85         cmp     %g5, %g4
  86         bl,a,pt %xcc, 7f
  87           nop
  88 
  89 #ifndef _OPL
  90         mov     MMU_PCONTEXT, %g1
  91         ldxa    [%g1]ASI_DMMU, %g1
  92         srlx    %g1, CTXREG_NEXT_SHIFT, %g3
  93         brz,pt  %g3, 7f                 ! nucleus pgsz is 0, no problem
  94           sllx  %g3, CTXREG_NEXT_SHIFT, %g3
  95         set     CTXREG_CTX_MASK, %g4    ! check Pcontext
  96         btst    %g4, %g1
  97         bz,a,pt %xcc, 6f
  98           clr   %g3                     ! kernel:  PCONTEXT=0
  99         xor     %g3, %g1, %g3           ! user: clr N_pgsz0/1 bits
 100 6:
 101         set     DEMAP_ALL_TYPE, %g1
 102         stxa    %g0, [%g1]ASI_DTLB_DEMAP
 103         stxa    %g0, [%g1]ASI_ITLB_DEMAP
 104         mov     MMU_PCONTEXT, %g1
 105         stxa    %g3, [%g1]ASI_DMMU
 106         membar  #Sync
 107         sethi   %hi(FLUSH_ADDR), %g1
 108         flush   %g1                     ! flush required by immu
 109 #endif /* _OPL */
 110 
 111 7:
 112         !
 113         !  Cross-trap request case
 114         !
 115         ! Load interrupt receive data registers 1 and 2 to fetch
 116         ! the arguments for the fast trap handler.
 117         !
 118         ! Register usage:
 119         !       g5: TL>0 handler
 120         !       g1: arg1
 121         !       g2: arg2
 122         !       g3: arg3
 123         !       g4: arg4
 124         !
 125         mov     IRDR_1, %g2
 126         ldxa    [%g2]ASI_INTR_RECEIVE, %g1
 127         mov     IRDR_2, %g2
 128         ldxa    [%g2]ASI_INTR_RECEIVE, %g2
 129 #ifdef TRAPTRACE
 130         TRACE_PTR(%g4, %g6)
 131         GET_TRACE_TICK(%g6, %g3)
 132         stxa    %g6, [%g4 + TRAP_ENT_TICK]%asi
 133         rdpr    %tl, %g6
 134         stha    %g6, [%g4 + TRAP_ENT_TL]%asi
 135         rdpr    %tt, %g6
 136         stha    %g6, [%g4 + TRAP_ENT_TT]%asi
 137         rdpr    %tpc, %g6
 138         stna    %g6, [%g4 + TRAP_ENT_TPC]%asi
 139         rdpr    %tstate, %g6
 140         stxa    %g6, [%g4 + TRAP_ENT_TSTATE]%asi
 141         stna    %sp, [%g4 + TRAP_ENT_SP]%asi
 142         stna    %g5, [%g4 + TRAP_ENT_TR]%asi    ! pc of the TL>0 handler
 143         stxa    %g1, [%g4 + TRAP_ENT_F1]%asi
 144         stxa    %g2, [%g4 + TRAP_ENT_F3]%asi
 145         stxa    %g0, [%g4 + TRAP_ENT_F2]%asi
 146         stxa    %g0, [%g4 + TRAP_ENT_F4]%asi
 147         TRACE_NEXT(%g4, %g6, %g3)
 148 #endif /* TRAPTRACE */
 149         stxa    %g0, [%g0]ASI_INTR_RECEIVE_STATUS       ! clear the BUSY bit
 150         membar  #Sync
 151 #ifdef SF_ERRATA_51
 152         ba,pt   %icc, 1f
 153         nop
 154         .align 32
 155 1:      jmp     %g5                             ! call the fast trap handler
 156         nop
 157 #else
 158         jmp     %g5
 159         nop
 160 #endif /* SF_ERRATA_51 */
 161         /* Never Reached */
 162 
 163 0:
 164         ! We have an interrupt number.
 165         !
 166         ! Register usage:
 167         !       %g5 - inum
 168         !       %g1 - temp
 169         !
 170         ! We don't bother to verify that the received inum is valid (it should
 171         ! be < MAXIVNUM) since setvecint_tl1 will do that for us.
 172         !
 173         ! clear BUSY bit
 174         !
 175         stxa    %g0, [%g0]ASI_INTR_RECEIVE_STATUS
 176         membar  #Sync
 177 
 178         ! setvecint_tl1 will do all the work, and finish with a retry
 179         !
 180         ba,pt   %xcc, setvecint_tl1
 181         mov     %g5, %g1                ! setvecint_tl1 expects inum in %g1
 182 
 183         /* Never Reached */
 184         SET_SIZE(vec_interrupt)
 185 
 186 
 187 !       
 188 !   See usr/src/uts/sun4u/sys/dmv.h for the Databearing Mondo Vector
 189 !        interrupt format
 190 !
 191 ! Inputs:
 192 !       g1: value of ASI_INTR_RECEIVE_STATUS
 193 !       g5: word 0 of the interrupt data
 194 ! Register use:
 195 !       g2: dmv inum
 196 !       g3: scratch
 197 !       g4: pointer to dmv_dispatch_table
 198 !       g6: handler pointer from dispatch table
 199 
 200 
 201         DGDEF(dmv_spurious_cnt)
 202         .word   0
 203 
 204         ENTRY_NP(dmv_vector)
 205         srlx    %g5, DMV_INUM_SHIFT, %g2
 206         set     DMV_INUM_MASK, %g3
 207         and     %g2, %g3, %g2              ! %g2 = inum
 208 
 209         set     dmv_totalints, %g3
 210         ld      [%g3], %g3
 211         cmp     %g2, %g3
 212         bge,pn  %xcc, 2f                   ! inum >= dmv_totalints
 213         nop
 214         
 215         set     dmv_dispatch_table, %g3
 216         ldn     [%g3], %g4
 217         brz,pn  %g4, 2f
 218         sll     %g2, DMV_DISP_SHIFT, %g3   ! %g3 = inum*sizeof(struct dmv_disp)
 219                 
 220         add     %g4, %g3, %g4           ! %g4 = &dmv_dispatch_table[inum]
 221 #if (DMV_FUNC != 0) || (DMV_ARG != 8)
 222 #error "DMV_FUNC or DMV_SIZE has changed"
 223 #endif
 224         ldda    [%g4]ASI_NQUAD_LD, %g2  ! %g2=handler %g3=argument
 225         mov     %g3, %g1
 226         brz,pn  %g2, 2f 
 227         nop
 228         
 229         ! we have a handler, so call it
 230         ! On entry to the handler, the %g registers are set as follows:
 231         !
 232         !       %g1     The argument (arg) passed to dmv_add_intr().
 233         !       %g2     Word 0 of the incoming mondo vector.
 234         !
 235         jmp     %g2
 236         mov     %g5, %g2
 237                 
 238         ! No handler was listed in the table, so just record it
 239         ! as an error condition and continue.  There is a race
 240         ! window here updating the counter, but that's ok since
 241         ! just knowing that spurious interrupts happened is enough,
 242         ! we probably won't need to know exactly how many.
 243 2:
 244         set     dmv_spurious_cnt, %g1
 245         ld      [%g1], %g2
 246         inc     %g2
 247         ba,pt   %xcc,3f
 248         st      %g2, [%g1]
 249         
 250         !       When the handler's processing (which should be as quick as
 251         !       possible) is complete, the handler must exit by jumping to
 252         !       the label dmv_finish_intr.  The contents of %g1 at this time
 253         !       determine whether a software interrupt will be issued, as
 254         !       follows:
 255         !
 256         !               If %g1 is less than zero, no interrupt will be queued.
 257         !               Otherwise, %g1 will be used as the interrupt number
 258         !               to simulate; this means that the behavior of the
 259         !               interrupt system will be exactly that which would have
 260         !               occurred if the first word of the incoming interrupt
 261         !               vector had contained the contents of %g1.
 262 
 263         ENTRY_NP(dmv_finish_intr)
 264         brlz,pn %g1,3f
 265         nop
 266         !       generate an interrupt based on the contents of %g1
 267         ba,pt   %xcc,vec_interrupt_resume
 268         mov     %g1, %g5
 269         !       We are done
 270 3:      
 271         stxa    %g0, [%g0]ASI_INTR_RECEIVE_STATUS ! clear the busy bit
 272         retry
 273         SET_SIZE(dmv_vector)
 274 
 275 #endif  /* lint */
 276 
 277 #if defined(lint)
 278 
 279 void
 280 vec_intr_spurious(void)
 281 {}
 282 
 283 #else   /* lint */
 284 
 285         DGDEF(vec_spurious_cnt)
 286         .word   0
 287 
 288         ENTRY_NP(vec_intr_spurious)
 289         sethi   %hi(vec_spurious_cnt), %g2
 290         ld      [%g2 + %lo(vec_spurious_cnt)], %g2
 291 #ifdef TRAPTRACE
 292         TRACE_PTR(%g4, %g6)
 293         GET_TRACE_TICK(%g6, %g3)
 294         stxa    %g6, [%g4 + TRAP_ENT_TICK]%asi
 295         rdpr    %tl, %g6
 296         stha    %g6, [%g4 + TRAP_ENT_TL]%asi
 297         rdpr    %tt, %g6
 298         or      %g6, TT_SPURIOUS_INT, %g6
 299         stha    %g6, [%g4 + TRAP_ENT_TT]%asi
 300         rdpr    %tpc, %g6
 301         stna    %g6, [%g4 + TRAP_ENT_TPC]%asi
 302         rdpr    %tstate, %g6
 303         stxa    %g6, [%g4 + TRAP_ENT_TSTATE]%asi
 304         stna    %sp, [%g4 + TRAP_ENT_SP]%asi
 305         stna    %g1, [%g4 + TRAP_ENT_TR]%asi    ! irsr
 306         stna    %g2, [%g4 + TRAP_ENT_F1]%asi
 307         ldxa    [%g0]ASI_INTR_RECEIVE_STATUS, %g5
 308         stxa    %g5, [%g4 + TRAP_ENT_F2]%asi
 309         stxa    %g0, [%g4 + TRAP_ENT_F4]%asi
 310         TRACE_NEXT(%g4, %g6, %g3)
 311 #endif /* TRAPTRACE */
 312         cmp     %g2, 16
 313         bl,a,pt %xcc, 1f
 314         inc     %g2
 315         !
 316         ! prepare for sys_trap()
 317         !       %g1 - sys_tl1_panic
 318         !       %g2 - panic message
 319         !       %g4 - current pil
 320         !
 321 #ifdef CLEAR_INTR_BUSYBIT_ON_SPURIOUS
 322         /*
 323          * Certain processors (OPL) need to explicitly
 324          * clear the intr busy bit even though it is
 325          * not visibly set (spurious intrs)
 326          */
 327         stxa    %g0, [%g0]ASI_INTR_RECEIVE_STATUS       ! clear the BUSY bit
 328         membar  #Sync
 329 #endif /* CLEAR_INTR_BUSYBIT_ON_SPURIOUS */
 330         sub     %g0, 1, %g4
 331         set     _not_ready, %g2
 332         sethi   %hi(sys_tl1_panic), %g1
 333         ba,pt   %xcc, sys_trap
 334         or      %g1, %lo(sys_tl1_panic), %g1
 335         !
 336 1:      sethi   %hi(vec_spurious_cnt), %g1
 337         st      %g2, [%g1 + %lo(vec_spurious_cnt)]
 338         retry
 339         SET_SIZE(vec_intr_spurious)
 340 
 341 _not_ready:     .asciz  "Interrupt Vector Receive Register not READY"
 342 
 343 #endif  /* lint */