1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /*
27 * Facilities for cross-processor subroutine calls using "mailbox" interrupts.
28 */
29
30 #include <sys/types.h>
31 #include <sys/thread.h>
32 #include <sys/cpuvar.h>
33 #include <sys/x_call.h>
34 #include <sys/systm.h>
35 #include <sys/machsystm.h>
36 #include <sys/intr.h>
37 #include <sys/xc_impl.h>
38
39 /*
40 * Interrupt another CPU.
41 * This is useful to make the other CPU go through a trap so that
42 * it recognizes an address space trap (AST) for preempting a thread.
43 *
44 * It is possible to be preempted here and be resumed on the CPU
45 * being poked, so it isn't an error to poke the current CPU.
46 * We could check this and still get preempted after the check, so
47 * we don't bother.
48 */
49 void
poke_cpu(int cpun)50 poke_cpu(int cpun)
51 {
52 uint32_t *ptr = (uint32_t *)&cpu[cpun]->cpu_m.poke_cpu_outstanding;
53
54 /*
55 * If panicstr is set or a poke_cpu is already pending,
56 * no need to send another one. Use atomic swap to protect
57 * against multiple CPUs sending redundant pokes.
58 */
59 if (panicstr || *ptr == B_TRUE ||
60 atomic_swap_32(ptr, B_TRUE) == B_TRUE)
61 return;
62
63 xt_one(cpun, setsoftint_tl1, poke_cpu_inum, 0);
64 }
65
66 extern int xc_spl_enter[];
67
68 /*
69 * Call a function on a target CPU
70 */
71 void
cpu_call(cpu_t * cp,cpu_call_func_t func,uintptr_t arg1,uintptr_t arg2)72 cpu_call(cpu_t *cp, cpu_call_func_t func, uintptr_t arg1, uintptr_t arg2)
73 {
74 if (panicstr)
75 return;
76
77 /*
78 * Prevent CPU from going offline
79 */
80 kpreempt_disable();
81
82 /*
83 * If we are on the target CPU, call the function directly, but raise
84 * the PIL to XC_PIL.
85 * This guarantees that functions called via cpu_call() can not ever
86 * interrupt each other.
87 */
88 if (CPU != cp) {
89 xc_one(cp->cpu_id, (xcfunc_t *)func, (uint64_t)arg1,
90 (uint64_t)arg2);
91 } else {
92 int lcx;
93 int opl;
94
95 XC_SPL_ENTER(lcx, opl);
96 func(arg1, arg2);
97 XC_SPL_EXIT(lcx, opl);
98 }
99
100 kpreempt_enable();
101 }
102