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