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