1/* $NetBSD: spl.S,v 1.20 2023/05/22 06:50:52 skrll Exp $ */ 2 3/*- 4 * Copyright (c) 2009, 2010 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Matt Thomas <matt@3am-software.com>. 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#include "opt_multiprocessor.h" /* MP kernel? */ 33#include "opt_cputype.h" /* which mips CPU levels do we support? */ 34#include "opt_ddb.h" 35 36#include <sys/cdefs.h> 37 38#include <mips/asm.h> 39#include <mips/cpuregs.h> 40 41RCSID("$NetBSD: spl.S,v 1.20 2023/05/22 06:50:52 skrll Exp $") 42 43#include "assym.h" 44 45 .data 46 .globl _C_LABEL(ipl_sr_map) 47 .type _C_LABEL(ipl_sr_map),@object 48 .p2align INT_SCALESHIFT 49_C_LABEL(ipl_sr_map): 50 .word 0 /* IPL_NONE */ 51 .word MIPS_SOFT_INT_MASK_0 /* IPL_SOFT{CLOCK,BIO} */ 52 .word MIPS_SOFT_INT_MASK /* IPL_SOFT{NET,SERIAL} */ 53 .word MIPS_INT_MASK /* IPL_VM */ 54 .word MIPS_INT_MASK /* IPL_SCHED */ 55 .word MIPS_INT_MASK /* IPL_DDB */ 56 .word MIPS_INT_MASK /* IPL_HIGH */ 57 58 .text 59 .set noreorder 60/* 61 * MIPS processor interrupt control 62 * 63 * Used as building blocks for spl(9) kernel interface. 64 */ 65_splraise: 66 /* 67 * a0 = SR bits to be cleared for this IPL 68 * a1 = this IPL (IPL_*) 69 * Can only use a0-a3 and v0-v1 70 */ 71 PTR_L a3, L_CPU(MIPS_CURLWP) 72 NOP_L # load delay 73 INT_L v0, CPU_INFO_CPL(a3) # get current IPL from cpu_info 74 NOP_L # load delay 75 sltu v1, a1, v0 # newipl < curipl 76 bnez v1, 1f # yes, don't change. 77 nop # branch delay 78 mfc0 v1, MIPS_COP_0_STATUS # fetch status register 79 MFC0_HAZARD # load delay 80 or v1, MIPS_INT_MASK # enable all interrupts 81 xor a0, v1 # disable ipl's masked bits 82 DYNAMIC_STATUS_MASK(a0,v0) # machine dependent masking 83#if !defined(__mips_o32) 84 or v1, MIPS_SR_INT_IE # 85 xor v1, MIPS_SR_INT_IE # clear interrupt enable bit 86 mtc0 v1, MIPS_COP_0_STATUS # disable interrupts 87#else 88 mtc0 zero, MIPS_COP_0_STATUS # disable interrupts 89#endif 90 COP0_SYNC 91#ifdef MULTIPROCESSOR 92 PTR_L a3, L_CPU(MIPS_CURLWP) # make sure curcpu is correct 93 NOP_L # load delay 94#endif 95 INT_S a1, CPU_INFO_CPL(a3) # save IPL in cpu_info 96 mtc0 a0, MIPS_COP_0_STATUS # store back 97 COP0_SYNC 98#ifdef PARANOIA 99 jr ra 100 nop # branch delay 101#endif /* PARANOIA */ 1021: 103#ifdef PARANOIA 104 mfc0 v1, MIPS_COP_0_STATUS 105 MFC0_HAZARD # load delay 106 and a0, v1 # a1 contains bit that MBZ 1073: bnez a0, 3b # loop forever 108 nop # branch delay 109#endif /* PARANOIA */ 110 jr ra 111 nop # branch delay 112 113STATIC_LEAF(_splsw_splx) 114STATIC_XLEAF(_splsw_splx_noprof) # does not get mcount hooks 115#ifdef PARANOIA 116 sltiu v0, a0, IPL_HIGH+1 # v0 = a0 <= IPL_HIGH 11798: beqz v0, 98b 118 nop 119#endif 120 PTR_L a3, L_CPU(MIPS_CURLWP) # get cpu_info 121 NOP_L # load delay 122 INT_L a2, CPU_INFO_CPL(a3) # get IPL from cpu_info 123 NOP_L # load delay 124 beq a0, a2, 2f # if same, nothing to do 125 nop # branch delay 126#ifdef PARANOIA 127 sltu v0, a0, a2 # v0 = a0 < a2 12899: beqz v0, 99b # loop forever if false 129 nop # branch delay 130#endif /* PARANOIA */ 131 PTR_LA v1, _C_LABEL(ipl_sr_map) # get address of table 132 sll a2, a0, INT_SCALESHIFT # convert IPL to array offset 133 PTR_ADDU v1, a2 # add to table addr 134 INT_L a1, (v1) # load SR bits for this IPL 1351: 136 mfc0 v1, MIPS_COP_0_STATUS # fetch status register 137 xor a1, MIPS_INT_MASK # invert SR bits 138 or v1, a1 # set any bits for this IPL 139 DYNAMIC_STATUS_MASK(v1,t0) # machine dependent masking 140#if !defined(__mips_o32) 141 or v0, v1, MIPS_SR_INT_IE # 142 xor v0, MIPS_SR_INT_IE # clear interrupt enable bit 143 mtc0 v0, MIPS_COP_0_STATUS # disable interrupts 144#else 145 mtc0 zero, MIPS_COP_0_STATUS # disable interrupts 146#endif 147 COP0_SYNC 148 INT_S a0, CPU_INFO_CPL(a3) # save IPL in cpu_info (KSEG0) 149 mtc0 v1, MIPS_COP_0_STATUS # store back 150 COP0_SYNC 151#ifdef PARANOIA 152 jr ra 153 nop # branch delay 154#endif /* PARANOIA */ 1552: 156#ifdef PARANOIA 157 PTR_LA v1, _C_LABEL(ipl_sr_map) # get address of table 158 sll a2, a0, INT_SCALESHIFT # convert IPL to array offset 159 PTR_ADDU v1, a2 # add to table addr 160 INT_L a1, (v1) # load SR bits for this IPL 161 mfc0 v1, MIPS_COP_0_STATUS 162 MFC0_HAZARD # load delay 163 and v1, MIPS_INT_MASK 164 xor a1, MIPS_INT_MASK 1653: bne a1, v1, 3b 166 nop # branch delay 167#endif /* PARANOIA */ 168 jr ra 169 nop # branch delay 170END(_splsw_splx) 171 172STATIC_LEAF(_splsw_spl0) 173 INT_L v1, _C_LABEL(ipl_sr_map) + 4*IPL_NONE 174 PTR_L a3, L_CPU(MIPS_CURLWP) 175 or v1, MIPS_SR_INT_IE # make sure interrupts are on 176 xor v1, MIPS_INT_MASK # invert 177 mfc0 a0, MIPS_COP_0_STATUS 178 MFC0_HAZARD # load delay 179 or v0, a0, v1 180 DYNAMIC_STATUS_MASK(v0,t0) # machine dependent masking 181#if !defined(__mips_o32) 182 or v1, v0, MIPS_SR_INT_IE # 183 xor v1, MIPS_SR_INT_IE # clear interrupt enable bit 184 mtc0 v1, MIPS_COP_0_STATUS # disable interrupts 185#else 186 mtc0 zero, MIPS_COP_0_STATUS # disable interrupts 187#endif 188 COP0_SYNC 189#if IPL_NONE == 0 190 INT_S zero, CPU_INFO_CPL(a3) # set ipl to 0 191#else 192#error IPL_NONE != 0 193#endif 194 mtc0 v0, MIPS_COP_0_STATUS # enable all sources 195 JR_HB_RA # return (clear hazards) 196END(_splsw_spl0) 197 198STATIC_LEAF(_splsw_setsoftintr) 199 mfc0 v1, MIPS_COP_0_STATUS # save status register 200#if !defined(__mips_o32) 201 MFC0_HAZARD # load delay 202 or v0, v1, MIPS_SR_INT_IE # 203 xor v0, MIPS_SR_INT_IE # clear interrupt enable bit 204 mtc0 v0, MIPS_COP_0_STATUS # disable interrupts 205#else 206 mtc0 zero, MIPS_COP_0_STATUS # disable interrupts 207#endif 208 COP0_SYNC 209 mfc0 v0, MIPS_COP_0_CAUSE # fetch cause register 210 MFC0_HAZARD # load delay 211 or v0, v0, a0 # set soft intr. bits 212 mtc0 v0, MIPS_COP_0_CAUSE # store back 213 COP0_SYNC 214 mtc0 v1, MIPS_COP_0_STATUS # enable interrupts 215 JR_HB_RA # return (clear hazards) 216END(_splsw_setsoftintr) 217 218STATIC_LEAF(_splsw_clrsoftintr) 219 mfc0 v1, MIPS_COP_0_STATUS # save status register 220#if !defined(__mips_o32) 221 MFC0_HAZARD # load delay 222 or v0, v1, MIPS_SR_INT_IE # 223 xor v0, MIPS_SR_INT_IE # clear interrupt enable bit 224 mtc0 v0, MIPS_COP_0_STATUS # disable interrupts 225#else 226 mtc0 zero, MIPS_COP_0_STATUS # disable interrupts 227#endif 228 COP0_SYNC 229 mfc0 v0, MIPS_COP_0_CAUSE # fetch cause register 230 nor a0, zero, a0 # bitwise inverse of A0 231 and v0, v0, a0 # clear soft intr. bits 232 mtc0 v0, MIPS_COP_0_CAUSE # store back 233 COP0_SYNC 234 mtc0 v1, MIPS_COP_0_STATUS # enable interrupts 235 JR_HB_RA # return (clear hazards) 236END(_splsw_clrsoftintr) 237 238STATIC_LEAF(_splsw_splraise) 239#if defined(DDB) && __mips >= 32 240 tgeiu a0, IPL_HIGH+1 241#endif 242 move a1, a0 243 PTR_LA v1, _C_LABEL(ipl_sr_map) 244 sll a2, a0, INT_SCALESHIFT 245 PTR_ADDU v1, a2 246 b _splraise 247 INT_L a0, (v1) 248END(_splsw_splraise) 249 250STATIC_LEAF(_splsw_splhigh) 251STATIC_XLEAF(_splsw_splhigh_noprof) 252 PTR_L a3, L_CPU(MIPS_CURLWP) 253 NOP_L # load delay 254 INT_L v0, CPU_INFO_CPL(a3) # get current IPL from cpu_info 255 li a1, IPL_HIGH # 256 beq v0, a1, 1f # don't do anything if IPL_HIGH 257 nop # branch delay 258 mfc0 v1, MIPS_COP_0_STATUS # fetch status register 259 MFC0_HAZARD # load delay 260 and a0, v1, MIPS_INT_MASK # select all interrupts 261 xor a0, v1 # clear all interrupts 262 DYNAMIC_STATUS_MASK(a0,a2) # machine dependent masking 263 mtc0 a0, MIPS_COP_0_STATUS # store back 264 COP0_SYNC 265#ifdef MULTIPROCESSOR 266 PTR_L a3, L_CPU(MIPS_CURLWP) # make sure curcpu is correct 267 NOP_L # load delay 268#endif 269 INT_S a1, CPU_INFO_CPL(a3) # save IPL in cpu_info 270#ifdef PARANOIA 271 jr ra # return 272 nop # branch delay 273#endif /* PARANOIA */ 2741: 275#ifdef PARANOIA 276 mfc0 v1, MIPS_COP_0_STATUS # fetch status register 277 MFC0_HAZARD # load delay 278 and v1, MIPS_INT_MASK # any int bits set? 2792: bnez v1, 2b # loop forever. 280 nop # branch delay 281#endif /* PARANOIA */ 282 jr ra # return 283 nop # branch delay 284END(_splsw_splhigh) 285 286 .p2align 4 287STATIC_LEAF(_splsw_splddb) 288 INT_L a0, _C_LABEL(ipl_sr_map) + 4*IPL_DDB 289 b _splraise 290 li a1, IPL_DDB 291 nop 292END(_splsw_splddb) 293 294STATIC_LEAF(_splsw_splsched) 295 INT_L a0, _C_LABEL(ipl_sr_map) + 4*IPL_SCHED 296 b _splraise 297 li a1, IPL_SCHED 298 nop 299END(_splsw_splsched) 300 301STATIC_LEAF(_splsw_splvm) 302 INT_L a0, _C_LABEL(ipl_sr_map) + 4*IPL_VM 303 b _splraise 304 li a1, IPL_VM 305 nop 306END(_splsw_splvm) 307 308STATIC_LEAF(_splsw_splsoftserial) 309 INT_L a0, _C_LABEL(ipl_sr_map) + 4*IPL_SOFTSERIAL 310 b _splraise 311 li a1, IPL_SOFTSERIAL 312 nop 313END(_splsw_splsoftserial) 314 315STATIC_LEAF(_splsw_splsoftnet) 316 INT_L a0, _C_LABEL(ipl_sr_map) + 4*IPL_SOFTNET 317 b _splraise 318 li a1, IPL_SOFTNET 319 nop 320END(_splsw_splsoftnet) 321 322STATIC_LEAF(_splsw_splsoftbio) 323 INT_L a0, _C_LABEL(ipl_sr_map) + 4*IPL_SOFTBIO 324 b _splraise 325 li a1, IPL_SOFTBIO 326 nop 327END(_splsw_splsoftbio) 328 329STATIC_LEAF(_splsw_splsoftclock) 330 INT_L a0, _C_LABEL(ipl_sr_map) + 4*IPL_SOFTCLOCK 331 b _splraise 332 li a1, IPL_SOFTCLOCK 333 nop 334END(_splsw_splsoftclock) 335 336STATIC_LEAF(_splsw_splintr) 337 mfc0 ta1, MIPS_COP_0_CAUSE # get active interrupts 338 MFC0_HAZARD # load delay 339 # restrict to hard int bits 340 and v1, ta1, MIPS_HARD_INT_MASK # now have pending interrupts 341 li v0, IPL_NONE # return IPL_NONE 342 beq v1, zero, 2f # quick exit if nothing pending 343 nop # branch delay 344 345 li v0, IPL_VM # start at IPL_VM 346 PTR_LA ta3, _C_LABEL(ipl_sr_map) + 4*IPL_VM 347 INT_L ta2, -4(ta3) # load mask for IPL_SOFTSERIAL 348 NOP_L # load delay 349 xor ta2, MIPS_INT_MASK # invert 350 and v1, ta2 # apply to pending bits 351 3521: 353 INT_L ta2, (ta3) # get SR bits for ipl in ta2 354 NOP_L # load delay 355 xor ta2, MIPS_INT_MASK # invert 356 and ta2, v1 # any match to pending intrs? 357 beq ta2, zero, 2f # no, return ipl 358 nop # branch delay 359 360 PTR_ADDU ta3, 1 << INT_SCALESHIFT # point to next entry 361 addiu v0, 1 # increase ipl by 1 362 b 1b # and check it 363 move v1, ta2 # whittle down pending intrs 364 3652: 366 jr ra 367 INT_S v1, (a0) # return a new pending mask 368END(_splsw_splintr) 369 370STATIC_LEAF(_splsw_splcheck) 371#ifdef PARANOIA 372 PTR_L t0, L_CPU(MIPS_CURLWP) 373 NOP_L # load delay 374 INT_L t1, CPU_INFO_CPL(t0) # get current priority level 375 376 mfc0 t0, MIPS_COP_0_STATUS # get current status 377 MFC0_HAZARD # load delay 378 and t0, MIPS_INT_MASK # just want INT bits 379 380 PTR_LA t2, _C_LABEL(ipl_sr_map) 381 sll t1, INT_SCALESHIFT # shift cpl to array index 382 PTR_ADDU t2, t1 383 INT_L t3, (t2) # load value 384 NOP_L # load delay 385 xor t3, MIPS_INT_MASK # invert 3861: bne t0, t3, 1b # loop forever if not equal 387 nop # branch delay 388#endif /* PARANOIA */ 389 jr ra 390 nop # branch delay 391END(_splsw_splcheck) 392 393 .rdata 394 .globl _C_LABEL(std_splsw) 395_C_LABEL(std_splsw): 396 PTR_WORD _C_LABEL(_splsw_splhigh) 397 PTR_WORD _C_LABEL(_splsw_splsched) 398 PTR_WORD _C_LABEL(_splsw_splvm) 399 PTR_WORD _C_LABEL(_splsw_splsoftserial) 400 PTR_WORD _C_LABEL(_splsw_splsoftnet) 401 PTR_WORD _C_LABEL(_splsw_splsoftbio) 402 PTR_WORD _C_LABEL(_splsw_splsoftclock) 403 PTR_WORD _C_LABEL(_splsw_splraise) 404 PTR_WORD _C_LABEL(_splsw_spl0) 405 PTR_WORD _C_LABEL(_splsw_splx) 406 PTR_WORD _C_LABEL(_splsw_splhigh_noprof) 407 PTR_WORD _C_LABEL(_splsw_splx_noprof) 408 PTR_WORD _C_LABEL(_splsw_setsoftintr) 409 PTR_WORD _C_LABEL(_splsw_clrsoftintr) 410 PTR_WORD _C_LABEL(_splsw_splintr) 411 PTR_WORD _C_LABEL(_splsw_splcheck) 412