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 */