11.3Sjmcneill/* $NetBSD: gic_splfuncs_armv8.S,v 1.3 2021/10/31 15:32:14 jmcneill Exp $ */
21.1Sjmcneill
31.1Sjmcneill/*-
41.1Sjmcneill * Copyright (c) 2021 Jared McNeill <jmcneill@invisible.ca>
51.1Sjmcneill * All rights reserved.
61.1Sjmcneill *
71.1Sjmcneill * Redistribution and use in source and binary forms, with or without
81.1Sjmcneill * modification, are permitted provided that the following conditions
91.1Sjmcneill * are met:
101.1Sjmcneill * 1. Redistributions of source code must retain the above copyright
111.1Sjmcneill *    notice, this list of conditions and the following disclaimer.
121.1Sjmcneill * 2. Redistributions in binary form must reproduce the above copyright
131.1Sjmcneill *    notice, this list of conditions and the following disclaimer in the
141.1Sjmcneill *    documentation and/or other materials provided with the distribution.
151.1Sjmcneill *
161.1Sjmcneill * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
171.1Sjmcneill * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
181.1Sjmcneill * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
191.1Sjmcneill * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
201.1Sjmcneill * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
211.1Sjmcneill * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
221.1Sjmcneill * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
231.1Sjmcneill * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
241.1Sjmcneill * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
251.1Sjmcneill * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
261.1Sjmcneill * SUCH DAMAGE.
271.1Sjmcneill */
281.1Sjmcneill
291.1Sjmcneill#include <machine/asm.h>
301.1Sjmcneill#include "assym.h"
311.1Sjmcneill
321.3SjmcneillRCSID("$NetBSD: gic_splfuncs_armv8.S,v 1.3 2021/10/31 15:32:14 jmcneill Exp $")
331.2Sjmcneill
341.2Sjmcneill#ifdef __HAVE_PREEMPTION
351.2Sjmcneill#define	DISABLE_PREEMPTION			\
361.2Sjmcneill	ldr	w1, [x3, #L_NOPREEMPT];		\
371.2Sjmcneill	add	w1, w1, #1;			\
381.2Sjmcneill	str	w1, [x3, #L_NOPREEMPT]
391.2Sjmcneill#define	ENABLE_PREEMPTION			\
401.2Sjmcneill	ldr	w1, [x3, #L_NOPREEMPT];		\
411.2Sjmcneill	sub	w1, w1, #1;			\
421.2Sjmcneill	str	w1, [x3, #L_NOPREEMPT]
431.2Sjmcneill#else
441.2Sjmcneill#define	DISABLE_PREEMPTION
451.2Sjmcneill#define	ENABLE_PREEMPTION
461.2Sjmcneill#endif
471.1Sjmcneill
481.1Sjmcneill/*
491.1Sjmcneill * int
501.1Sjmcneill * gic_splraise(int newipl)
511.1Sjmcneill *
521.1Sjmcneill *	w0 = newipl
531.1Sjmcneill */
541.1Sjmcneill	.align 7        /* cacheline-aligned */
551.1SjmcneillENTRY_NP(gic_splraise)
561.2Sjmcneill	/* Save curlwp in x3, curcpu in x1 */
571.2Sjmcneill	mrs	x3, tpidr_el1			/* get curlwp */
581.2Sjmcneill	DISABLE_PREEMPTION
591.2Sjmcneill	ldr	x1, [x3, #L_CPU]		/* get curcpu */
601.1Sjmcneill
611.1Sjmcneill	/* If newipl > cpl, update cpl */
621.1Sjmcneill	ldr	w2, [x1, #CI_CPL]
631.1Sjmcneill	cmp	w0, w2
641.1Sjmcneill	b.le	.Lnoraise
651.1Sjmcneill	str	w0, [x1, #CI_CPL]
661.1Sjmcneill
671.1Sjmcneill.Lnoraise:
681.2Sjmcneill	ENABLE_PREEMPTION
691.1Sjmcneill	mov	w0, w2				/* return oldipl */
701.1Sjmcneill	ret
711.1SjmcneillEND(gic_splraise)
721.1Sjmcneill
731.1Sjmcneill
741.1Sjmcneill/*
751.1Sjmcneill * void
761.1Sjmcneill * gic_splx(int newipl)
771.1Sjmcneill *
781.1Sjmcneill *	w0 = newipl
791.1Sjmcneill */
801.1Sjmcneill	.align 7        /* cacheline-aligned */
811.1SjmcneillENTRY_NP(gic_splx)
821.2Sjmcneill	/* Save curlwp in x3, curcpu in x1 */
831.2Sjmcneill	mrs	x3, tpidr_el1			/* get curlwp */
841.2Sjmcneill	DISABLE_PREEMPTION
851.2Sjmcneill	ldr	x1, [x3, #L_CPU]		/* get curcpu */
861.1Sjmcneill
871.3Sjmcneill.Lagain:
881.1Sjmcneill	/* If newipl >= cpl, just return */
891.1Sjmcneill	ldr	w2, [x1, #CI_CPL]
901.1Sjmcneill	cmp	w0, w2
911.1Sjmcneill	b.hs	.Ldone
921.1Sjmcneill
931.1Sjmcneill	/* Slow path if ci_intr_depth != 0 */
941.1Sjmcneill	ldr	w2, [x1, #CI_INTR_DEPTH]
951.1Sjmcneill	cbnz	w2, .Lslow
961.1Sjmcneill
971.1Sjmcneill	/* Save newipl and restart address in cpu info */
981.1Sjmcneill	str	w0, [x1, #CI_SPLX_SAVEDIPL]
991.1Sjmcneill	adr	x2, .Lrestart
1001.1Sjmcneill	str	x2, [x1, #CI_SPLX_RESTART]
1011.1Sjmcneill
1021.1Sjmcneill	/* Slow path if hwpl > newipl */
1031.1Sjmcneill	ldr	w2, [x1, #CI_HWPL]
1041.1Sjmcneill	cmp	w2, w0
1051.1Sjmcneill	b.hi	.Lrestore
1061.1Sjmcneill
1071.1Sjmcneill	/* Update cpl */
1081.1Sjmcneill	str	w0, [x1, #CI_CPL]
1091.1Sjmcneill
1101.1Sjmcneill	/* Clear saved restart address from cpu info */
1111.1Sjmcneill	str	xzr, [x1, #CI_SPLX_RESTART]
1121.1Sjmcneill
1131.1Sjmcneill	/* Check for pending softints */
1141.1Sjmcneill	ldr	w2, [x1, #CI_SOFTINTS]
1151.1Sjmcneill	lsr	w2, w2, w0
1161.1Sjmcneill	cbnz	w2, _C_LABEL(dosoftints)
1171.1Sjmcneill
1181.1Sjmcneill.Ldone:
1191.2Sjmcneill	ENABLE_PREEMPTION
1201.1Sjmcneill	ret
1211.1Sjmcneill
1221.1Sjmcneill.Lrestart:
1231.3Sjmcneill	/* Reload registers */
1241.3Sjmcneill	mrs	x3, tpidr_el1			/* get curlwp */
1251.3Sjmcneill	ldr	x1, [x3, #L_CPU]		/* get curcpu */
1261.1Sjmcneill	ldr	w0, [x1, #CI_SPLX_SAVEDIPL]	/* get newipl */
1271.1Sjmcneill	b	.Lagain
1281.1Sjmcneill
1291.1Sjmcneill.Lrestore:
1301.1Sjmcneill	/* Clear saved restart address from cpu info */
1311.1Sjmcneill	str	xzr, [x1, #CI_SPLX_RESTART]
1321.1Sjmcneill
1331.1Sjmcneill.Lslow:
1341.2Sjmcneill	ENABLE_PREEMPTION
1351.1Sjmcneill	/* Jump to slow path */
1361.1Sjmcneill	b	_C_LABEL(Xgic_splx)
1371.1SjmcneillEND(gic_splx)
138