xref: /openbsd-src/sys/arch/sparc64/sparc64/ipifuncs.c (revision d00b7f603c5fc8ad53b75772b6ba7e4b590fcc51)
1 /*	$OpenBSD: ipifuncs.c,v 1.22 2024/04/14 19:08:09 miod Exp $	*/
2 /*	$NetBSD: ipifuncs.c,v 1.8 2006/10/07 18:11:36 rjs Exp $ */
3 
4 /*-
5  * Copyright (c) 2004 The NetBSD Foundation, Inc.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
18  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
21  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/proc.h>
33 
34 #include <uvm/uvm_extern.h>
35 
36 #include <machine/cpu.h>
37 #include <machine/ctlreg.h>
38 #include <machine/hypervisor.h>
39 #include <machine/pte.h>
40 #include <machine/sparc64.h>
41 
42 #define SPARC64_IPI_RETRIES	10000
43 
44 void	sun4u_send_ipi(int, void (*)(void), u_int64_t, u_int64_t);
45 void	sun4u_broadcast_ipi(void (*)(void), u_int64_t, u_int64_t);
46 void	sun4v_send_ipi(int, void (*)(void), u_int64_t, u_int64_t);
47 void	sun4v_broadcast_ipi(void (*)(void), u_int64_t, u_int64_t);
48 
49 /*
50  * These are the "function" entry points in locore.s to handle IPI's.
51  */
52 void	sun4u_ipi_tlb_page_demap(void);
53 void	sun4u_ipi_tlb_context_demap(void);
54 void	sun4v_ipi_tlb_page_demap(void);
55 void	sun4v_ipi_tlb_context_demap(void);
56 void	ipi_softint(void);
57 
58 /*
59  * Send an interprocessor interrupt.
60  */
61 void
sparc64_send_ipi(int itid,void (* func)(void),u_int64_t arg0,u_int64_t arg1)62 sparc64_send_ipi(int itid, void (*func)(void), u_int64_t arg0, u_int64_t arg1)
63 {
64 	if (CPU_ISSUN4V)
65 		sun4v_send_ipi(itid, func, arg0, arg1);
66 	else
67 		sun4u_send_ipi(itid, func, arg0, arg1);
68 }
69 
70 void
sun4u_send_ipi(int itid,void (* func)(void),u_int64_t arg0,u_int64_t arg1)71 sun4u_send_ipi(int itid, void (*func)(void), u_int64_t arg0, u_int64_t arg1)
72 {
73 	int i, j, shift = 0;
74 
75 	KASSERT((u_int64_t)func > MAXINTNUM);
76 
77 	/*
78 	 * UltraSPARC-IIIi CPUs select the BUSY/NACK pair based on the
79 	 * lower two bits of the ITID.
80 	 */
81 	if (((getver() & VER_IMPL) >> VER_IMPL_SHIFT) == IMPL_JALAPENO)
82 		shift = (itid & 0x3) * 2;
83 
84 	if (ldxa(0, ASR_IDSR) & (IDSR_BUSY << shift)) {
85 		__asm volatile("ta 1; nop");
86 	}
87 
88 	/* Schedule an interrupt. */
89 	for (i = 0; i < SPARC64_IPI_RETRIES; i++) {
90 		u_int64_t s = intr_disable();
91 
92 		stxa(IDDR_0H, ASI_INTERRUPT_DISPATCH, (u_int64_t)func);
93 		stxa(IDDR_1H, ASI_INTERRUPT_DISPATCH, arg0);
94 		stxa(IDDR_2H, ASI_INTERRUPT_DISPATCH, arg1);
95 		stxa(IDCR(itid), ASI_INTERRUPT_DISPATCH, 0);
96 		membar_sync();
97 
98 		for (j = 0; j < 1000000; j++) {
99 			if (ldxa(0, ASR_IDSR) & (IDSR_BUSY << shift))
100 				continue;
101 			else
102 				break;
103 		}
104 		intr_restore(s);
105 
106 		if (j == 1000000)
107 			break;
108 
109 		if ((ldxa(0, ASR_IDSR) & (IDSR_NACK << shift)) == 0)
110 			return;
111 	}
112 
113 #if 1
114 	if (db_active || panicstr != NULL)
115 		printf("ipi_send: couldn't send ipi to module %u\n", itid);
116 	else
117 		panic("ipi_send: couldn't send ipi");
118 #else
119 	__asm volatile("ta 1; nop" : :);
120 #endif
121 }
122 
123 void
sun4v_send_ipi(int itid,void (* func)(void),u_int64_t arg0,u_int64_t arg1)124 sun4v_send_ipi(int itid, void (*func)(void), u_int64_t arg0, u_int64_t arg1)
125 {
126 	struct cpu_info *ci = curcpu();
127 	u_int64_t s;
128 	int err, i;
129 
130 	s = intr_disable();
131 
132 	stha(ci->ci_cpuset, ASI_PHYS_CACHED, itid);
133 	stxa(ci->ci_mondo, ASI_PHYS_CACHED, (vaddr_t)func);
134 	stxa(ci->ci_mondo + 8, ASI_PHYS_CACHED, arg0);
135 	stxa(ci->ci_mondo + 16, ASI_PHYS_CACHED, arg1);
136 
137 	for (i = 0; i < SPARC64_IPI_RETRIES; i++) {
138 		err = hv_cpu_mondo_send(1, ci->ci_cpuset, ci->ci_mondo);
139 		if (err != H_EWOULDBLOCK)
140 			break;
141 		delay(10);
142 	}
143 
144 	intr_restore(s);
145 
146 	if (err != H_EOK)
147 		panic("Unable to send mondo %llx to cpu %d: %d",
148 		    (u_int64_t)func, itid, err);
149 }
150 
151 /*
152  * Broadcast an IPI to all but ourselves.
153  */
154 void
sparc64_broadcast_ipi(void (* func)(void),u_int64_t arg0,u_int64_t arg1)155 sparc64_broadcast_ipi(void (*func)(void), u_int64_t arg0, u_int64_t arg1)
156 {
157 	if (CPU_ISSUN4V)
158 		sun4v_broadcast_ipi(func, arg0, arg1);
159 	else
160 		sun4u_broadcast_ipi(func, arg0, arg1);
161 }
162 
163 void
sun4u_broadcast_ipi(void (* func)(void),u_int64_t arg0,u_int64_t arg1)164 sun4u_broadcast_ipi(void (*func)(void), u_int64_t arg0, u_int64_t arg1)
165 {
166 	struct cpu_info *ci;
167 
168 	for (ci = cpus; ci != NULL; ci = ci->ci_next) {
169 		if (ci->ci_cpuid == cpu_number())
170 			continue;
171 		if ((ci->ci_flags & CPUF_RUNNING) == 0)
172 			continue;
173 		sun4u_send_ipi(ci->ci_itid, func, arg0, arg1);
174 	}
175 }
176 
177 void
sun4v_broadcast_ipi(void (* func)(void),u_int64_t arg0,u_int64_t arg1)178 sun4v_broadcast_ipi(void (*func)(void), u_int64_t arg0, u_int64_t arg1)
179 {
180 	struct cpu_info *ci = curcpu();
181 	paddr_t cpuset = ci->ci_cpuset;
182 	int err, i, ncpus = 0;
183 
184 	for (ci = cpus; ci != NULL; ci = ci->ci_next) {
185 		if (ci->ci_cpuid == cpu_number())
186 			continue;
187 		if ((ci->ci_flags & CPUF_RUNNING) == 0)
188 			continue;
189 		stha(cpuset, ASI_PHYS_CACHED, ci->ci_itid);
190 		cpuset += sizeof(int16_t);
191 		ncpus++;
192 	}
193 
194 	if (ncpus == 0)
195 		return;
196 
197 	ci = curcpu();
198 	stxa(ci->ci_mondo, ASI_PHYS_CACHED, (vaddr_t)func);
199 	stxa(ci->ci_mondo + 8, ASI_PHYS_CACHED, arg0);
200 	stxa(ci->ci_mondo + 16, ASI_PHYS_CACHED, arg1);
201 
202 	for (i = 0; i < SPARC64_IPI_RETRIES; i++) {
203 		err = hv_cpu_mondo_send(ncpus, ci->ci_cpuset, ci->ci_mondo);
204 		if (err != H_EWOULDBLOCK)
205 			break;
206 		delay(10);
207 	}
208 	if (err != H_EOK)
209 		panic("Unable to broadcast mondo %llx: %d",
210 		    (u_int64_t)func, err);
211 }
212 
213 void
smp_tlb_flush_pte(vaddr_t va,uint64_t ctx)214 smp_tlb_flush_pte(vaddr_t va, uint64_t ctx)
215 {
216 	(*sp_tlb_flush_pte)(va, ctx);
217 
218 	if (db_active)
219 		return;
220 
221 	if (CPU_ISSUN4V)
222 		sun4v_broadcast_ipi(sun4v_ipi_tlb_page_demap, va, ctx);
223 	else
224 		sun4u_broadcast_ipi(sun4u_ipi_tlb_page_demap, va, ctx);
225 }
226 
227 void
smp_tlb_flush_ctx(uint64_t ctx)228 smp_tlb_flush_ctx(uint64_t ctx)
229 {
230 	(*sp_tlb_flush_ctx)(ctx);
231 
232 	if (db_active)
233 		return;
234 
235 	if (CPU_ISSUN4V)
236 		sun4v_broadcast_ipi(sun4v_ipi_tlb_context_demap, ctx, 0);
237 	else
238 		sun4u_broadcast_ipi(sun4u_ipi_tlb_context_demap, ctx, 0);
239 }
240 
241 void
cpu_unidle(struct cpu_info * ci)242 cpu_unidle(struct cpu_info *ci)
243 {
244 	if (ci == curcpu() || db_active || ((ci->ci_flags & CPUF_RUNNING) == 0))
245 		return;
246 
247 	if (CPU_ISSUN4V)
248 		sun4v_send_ipi(ci->ci_itid, ipi_softint, 1 << IPL_SOFTINT, 0);
249 	else
250 		sun4u_send_ipi(ci->ci_itid, ipi_softint, 1 << IPL_SOFTINT, 0);
251 }
252