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