1 /* $OpenBSD: ipi.c,v 1.5 2017/09/08 05:36:51 deraadt Exp $ */
2
3 /*
4 * Copyright (c) 2010 Joel Sing <jsing@openbsd.org>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 #include <sys/param.h>
20 #include <sys/systm.h>
21 #include <sys/mutex.h>
22
23 #include <machine/cpu.h>
24 #include <machine/cpufunc.h>
25 #include <machine/fpu.h>
26 #include <machine/iomod.h>
27 #include <machine/intr.h>
28 #include <machine/mutex.h>
29 #include <machine/reg.h>
30
31 void hppa_ipi_nop(void);
32 void hppa_ipi_halt(void);
33 void hppa_ipi_fpu_save(void);
34 void hppa_ipi_fpu_flush(void);
35
36 void (*ipifunc[HPPA_NIPI])(void) =
37 {
38 hppa_ipi_nop,
39 hppa_ipi_halt,
40 hppa_ipi_fpu_save,
41 hppa_ipi_fpu_flush
42 };
43
44 void
hppa_ipi_init(struct cpu_info * ci)45 hppa_ipi_init(struct cpu_info *ci)
46 {
47 /* Initialise IPIs for given CPU. */
48 mtx_init(&ci->ci_ipi_mtx, IPL_IPI);
49 ci->ci_mask |= (1 << 30);
50 }
51
52 int
hppa_ipi_intr(void * arg)53 hppa_ipi_intr(void *arg)
54 {
55 struct cpu_info *ci = curcpu();
56 u_long ipi_pending;
57 int bit = 0;
58
59 /* Handle an IPI. */
60 mtx_enter(&ci->ci_ipi_mtx);
61 ipi_pending = ci->ci_ipi;
62 ci->ci_ipi = 0;
63 mtx_leave(&ci->ci_ipi_mtx);
64
65 while (ipi_pending) {
66 if (ipi_pending & (1L << bit))
67 (*ipifunc[bit])();
68 ipi_pending &= ~(1L << bit);
69 bit++;
70 }
71
72 return 1;
73 }
74
75 int
hppa_ipi_send(struct cpu_info * ci,u_long ipi)76 hppa_ipi_send(struct cpu_info *ci, u_long ipi)
77 {
78 struct iomod *cpu;
79
80 if (!(ci->ci_flags & CPUF_RUNNING))
81 return -1;
82
83 mtx_enter(&ci->ci_ipi_mtx);
84 ci->ci_ipi |= (1L << ipi);
85 asm volatile ("sync" ::: "memory");
86 mtx_leave(&ci->ci_ipi_mtx);
87
88 /* Send an IPI to the specified CPU by triggering EIR{1} (irq 30). */
89 cpu = (struct iomod *)(ci->ci_hpa);
90 cpu->io_eir = 1;
91 asm volatile ("sync" ::: "memory");
92
93 return 0;
94 }
95
96 int
hppa_ipi_broadcast(u_long ipi)97 hppa_ipi_broadcast(u_long ipi)
98 {
99 CPU_INFO_ITERATOR cii;
100 struct cpu_info *ci;
101 int count = 0;
102
103 CPU_INFO_FOREACH(cii, ci)
104 if (ci != curcpu() && (ci->ci_flags & CPUF_RUNNING))
105 if (hppa_ipi_send(ci, ipi))
106 count++;
107
108 return count;
109 }
110
111 void
hppa_ipi_nop(void)112 hppa_ipi_nop(void)
113 {
114 }
115
116 void
hppa_ipi_halt(void)117 hppa_ipi_halt(void)
118 {
119 /* Turn off interrupts and halt CPU. */
120 SCHED_ASSERT_UNLOCKED();
121 hppa_intr_disable();
122 curcpu()->ci_flags &= ~CPUF_RUNNING;
123
124 for (;;) ;
125 }
126
127 void
hppa_ipi_fpu_save(void)128 hppa_ipi_fpu_save(void)
129 {
130 fpu_cpu_save(1);
131 }
132
133 void
hppa_ipi_fpu_flush(void)134 hppa_ipi_fpu_flush(void)
135 {
136 fpu_cpu_save(0);
137 }
138