xref: /openbsd/sys/arch/alpha/alpha/ipifuncs.c (revision 5bcb7d0d)
1 /* $OpenBSD: ipifuncs.c,v 1.6 2014/02/02 22:49:38 miod Exp $	*/
2 /* $NetBSD: ipifuncs.c,v 1.9 1999/12/02 01:09:11 thorpej Exp $ */
3 
4 /*-
5  * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc.
6  * All rights reserved.
7  *
8  * This code is derived from software contributed to The NetBSD Foundation
9  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
10  * NASA Ames Research Center.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
25  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 /*
35  * Interprocessor interrupt handlers.
36  */
37 
38 #include <sys/param.h>
39 #include <sys/device.h>
40 #include <sys/systm.h>
41 #include <sys/reboot.h>
42 
43 #include <uvm/uvm_extern.h>
44 
45 #include <machine/atomic.h>
46 #include <machine/alpha_cpu.h>
47 #include <machine/cpu.h>
48 #include <machine/intr.h>
49 #include <machine/prom.h>
50 #include <machine/rpb.h>
51 
52 typedef void (*ipifunc_t)(struct cpu_info *, struct trapframe *);
53 
54 void	alpha_ipi_halt(struct cpu_info *, struct trapframe *);
55 void	alpha_ipi_imb(struct cpu_info *, struct trapframe *);
56 void	alpha_ipi_ast(struct cpu_info *, struct trapframe *);
57 void	alpha_ipi_synch_fpu(struct cpu_info *, struct trapframe *);
58 void	alpha_ipi_discard_fpu(struct cpu_info *, struct trapframe *);
59 void	alpha_ipi_pause(struct cpu_info *, struct trapframe *);
60 
61 /*
62  * NOTE: This table must be kept in order with the bit definitions
63  * in <machine/intr.h>.
64  */
65 const ipifunc_t ipifuncs[ALPHA_NIPIS] = {
66 	alpha_ipi_halt,
67 	pmap_do_tlb_shootdown,
68 	alpha_ipi_imb,
69 	alpha_ipi_ast,
70 	alpha_ipi_synch_fpu,
71 	alpha_ipi_discard_fpu,
72 	alpha_ipi_pause
73 };
74 
75 /*
76  * Process IPIs for a CPU.
77  */
78 void
alpha_ipi_process(struct cpu_info * ci,struct trapframe * framep)79 alpha_ipi_process(struct cpu_info *ci, struct trapframe *framep)
80 {
81 	u_long pending_ipis, bit;
82 
83 	while ((pending_ipis = atomic_loadlatch_ulong(&ci->ci_ipis, 0)) != 0) {
84 		for (bit = 0; bit < ALPHA_NIPIS; bit++) {
85 			if (pending_ipis & (1UL << bit)) {
86 				(*ipifuncs[bit])(ci, framep);
87 			}
88 		}
89 	}
90 }
91 
92 /*
93  * Send an interprocessor interrupt.
94  */
95 void
alpha_send_ipi(u_long cpu_id,u_long ipimask)96 alpha_send_ipi(u_long cpu_id, u_long ipimask)
97 {
98 
99 #ifdef DIAGNOSTIC
100 	if (cpu_id >= hwrpb->rpb_pcs_cnt ||
101 	    cpu_info[cpu_id] == NULL)
102 		panic("alpha_send_ipi: bogus cpu_id");
103 	if (((1UL << cpu_id) & cpus_running) == 0)
104 		panic("alpha_send_ipi: CPU %ld not running", cpu_id);
105 #endif
106 
107 	atomic_setbits_ulong(&cpu_info[cpu_id]->ci_ipis, ipimask);
108 	alpha_pal_wripir(cpu_id);
109 }
110 
111 /*
112  * Broadcast an IPI to all but ourselves.
113  */
114 void
alpha_broadcast_ipi(u_long ipimask)115 alpha_broadcast_ipi(u_long ipimask)
116 {
117 	struct cpu_info *ci;
118 	CPU_INFO_ITERATOR cii;
119 	u_long cpu_id = cpu_number();
120 	u_long cpumask;
121 
122 	cpumask = cpus_running & ~(1UL << cpu_id);
123 	if (cpumask == 0)
124 		return;
125 
126 	CPU_INFO_FOREACH(cii, ci) {
127 		if ((cpumask & (1UL << ci->ci_cpuid)) == 0)
128 			continue;
129 		alpha_send_ipi(ci->ci_cpuid, ipimask);
130 	}
131 }
132 
133 /*
134  * Send an IPI to all in the list but ourselves.
135  */
136 void
alpha_multicast_ipi(u_long cpumask,u_long ipimask)137 alpha_multicast_ipi(u_long cpumask, u_long ipimask)
138 {
139 	struct cpu_info *ci;
140 	CPU_INFO_ITERATOR cii;
141 	u_long cpu_id = cpu_number();
142 
143 	cpumask &= cpus_running;
144 	cpumask &= ~(1UL << cpu_id);
145 	if (cpumask == 0)
146 		return;
147 
148 	CPU_INFO_FOREACH(cii, ci) {
149 		if ((cpumask & (1UL << ci->ci_cpuid)) == 0)
150 			continue;
151 		alpha_send_ipi(ci->ci_cpuid, ipimask);
152 	}
153 }
154 
155 void
alpha_ipi_halt(struct cpu_info * ci,struct trapframe * framep)156 alpha_ipi_halt(struct cpu_info *ci, struct trapframe *framep)
157 {
158 	SCHED_ASSERT_UNLOCKED();
159 	fpusave_cpu(ci, 1);
160 	(void)splhigh();
161 
162 	cpu_halt();
163 	/* NOTREACHED */
164 }
165 
166 void
alpha_ipi_imb(struct cpu_info * ci,struct trapframe * framep)167 alpha_ipi_imb(struct cpu_info *ci, struct trapframe *framep)
168 {
169 	alpha_pal_imb();
170 }
171 
172 void
alpha_ipi_ast(struct cpu_info * ci,struct trapframe * framep)173 alpha_ipi_ast(struct cpu_info *ci, struct trapframe *framep)
174 {
175 #if 0 /* useless */
176 	cpu_unidle(ci);
177 #endif
178 }
179 
180 void
alpha_ipi_synch_fpu(struct cpu_info * ci,struct trapframe * framep)181 alpha_ipi_synch_fpu(struct cpu_info *ci, struct trapframe *framep)
182 {
183 	if (ci->ci_flags & CPUF_FPUSAVE)
184 		return;
185 	fpusave_cpu(ci, 1);
186 }
187 
188 void
alpha_ipi_discard_fpu(struct cpu_info * ci,struct trapframe * framep)189 alpha_ipi_discard_fpu(struct cpu_info *ci, struct trapframe *framep)
190 {
191 	if (ci->ci_flags & CPUF_FPUSAVE)
192 		return;
193 	fpusave_cpu(ci, 0);
194 }
195 
196 void
alpha_ipi_pause(struct cpu_info * ci,struct trapframe * framep)197 alpha_ipi_pause(struct cpu_info *ci, struct trapframe *framep)
198 {
199 	u_long cpumask = (1UL << ci->ci_cpuid);
200 	int s;
201 
202 	s = splhigh();
203 
204 	/* Point debuggers at our trapframe for register state. */
205 	ci->ci_db_regs = framep;
206 
207 	atomic_setbits_ulong(&ci->ci_flags, CPUF_PAUSED);
208 
209 	/* Spin with interrupts disabled until we're resumed. */
210 	do {
211 		alpha_mb();
212 	} while (cpus_paused & cpumask);
213 
214 	atomic_clearbits_ulong(&ci->ci_flags, CPUF_PAUSED);
215 
216 	ci->ci_db_regs = NULL;
217 
218 	splx(s);
219 
220 	/* Do an IMB on the way out, in case the kernel text was changed. */
221 	alpha_pal_imb();
222 }
223