1 /* $NetBSD: ipifuncs.c,v 1.7 2022/04/09 23:43:12 riastradh Exp $ */ 2 /* $OpenBSD: ipi.c,v 1.4 2011/01/14 13:20:06 jsing Exp $ */ 3 4 /* 5 * Copyright (c) 2010 Joel Sing <jsing (at) openbsd.org> 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 #include <sys/param.h> 21 #include <sys/types.h> 22 #include <sys/systm.h> 23 #include <sys/mutex.h> 24 #include <sys/device.h> 25 #include <sys/atomic.h> 26 #include <sys/xcall.h> 27 #include <sys/ipi.h> 28 29 #include <machine/cpu.h> 30 #include <machine/cpufunc.h> 31 #if 0 32 #include <machine/fpu.h> 33 #endif 34 #include <machine/iomod.h> 35 #include <machine/intr.h> 36 #include <machine/mutex.h> 37 #include <machine/reg.h> 38 #include <machine/int_fmtio.h> 39 40 #include <hppa/hppa/cpuvar.h> 41 42 static void hppa_ipi_nop(void); 43 static void hppa_ipi_halt(void); 44 45 void (*ipifunc[HPPA_NIPI])(void) = 46 { 47 hppa_ipi_nop, 48 hppa_ipi_halt, 49 xc_ipi_handler, 50 ipi_cpu_handler, 51 }; 52 53 const char *ipinames[HPPA_NIPI] = { 54 "nop ipi", 55 "halt ipi", 56 "xcall ipi" 57 "generic ipi" 58 }; 59 60 void 61 hppa_ipi_init(struct cpu_info *ci) 62 { 63 struct cpu_softc *sc = ci->ci_softc; 64 int i; 65 66 evcnt_attach_dynamic(&sc->sc_evcnt_ipi, EVCNT_TYPE_INTR, 67 NULL, device_xname(sc->sc_dev), "ipi"); 68 69 for (i = 0; i < HPPA_NIPI; i++) { 70 evcnt_attach_dynamic(&sc->sc_evcnt_which_ipi[i], 71 EVCNT_TYPE_INTR, NULL, device_xname(sc->sc_dev), 72 ipinames[i]); 73 } 74 } 75 76 int 77 hppa_ipi_intr(void *arg) 78 { 79 struct cpu_info *ci = curcpu(); 80 struct cpu_softc *sc = ci->ci_softc; 81 u_long ipi_pending; 82 int bit = 0; 83 84 /* Handle an IPI. */ 85 ipi_pending = atomic_swap_ulong(&ci->ci_ipi, 0); 86 membar_acquire(); /* matches membar_release in xc_send_ipi, cpu_ipi */ 87 88 KASSERT(ipi_pending); 89 90 sc->sc_evcnt_ipi.ev_count++; 91 92 while (ipi_pending) { 93 if (ipi_pending & (1L << bit)) { 94 sc->sc_evcnt_which_ipi[bit].ev_count++; 95 (*ipifunc[bit])(); 96 } 97 ipi_pending &= ~(1L << bit); 98 bit++; 99 } 100 101 return 1; 102 } 103 104 int 105 hppa_ipi_send(struct cpu_info *ci, u_long ipi) 106 { 107 struct iomod *cpu; 108 KASSERT(ci->ci_flags & CPUF_RUNNING); 109 110 atomic_or_ulong(&ci->ci_ipi, (1L << ipi)); 111 112 /* 113 * Send an IPI to the specified CPU by triggering EIR{1} (irq 30). 114 * 115 * The `load-acquire operation' matching this store-release is 116 * somewhere inside the silicon or firmware -- the point is 117 * that the store to ci->ci_ipi above must happen before 118 * writing to EIR{1}; there is conceptually some magic inside 119 * the silicon or firmware on the target CPU that effectively 120 * does 121 * 122 * if (atomic_load_acquire(&cpu->io_eir)) { 123 * enter_interrupt_vector(); 124 * } 125 */ 126 cpu = (struct iomod *)(ci->ci_hpa); 127 atomic_store_release(&cpu->io_eir, 1); 128 129 return 0; 130 } 131 132 int 133 hppa_ipi_broadcast(u_long ipi) 134 { 135 CPU_INFO_ITERATOR cii; 136 struct cpu_info *ci; 137 int count = 0; 138 139 for (CPU_INFO_FOREACH(cii, ci)) { 140 if (ci != curcpu() && (ci->ci_flags & CPUF_RUNNING)) 141 if (hppa_ipi_send(ci, ipi)) 142 count++; 143 } 144 145 return count; 146 } 147 148 static void 149 hppa_ipi_nop(void) 150 { 151 } 152 153 static void 154 hppa_ipi_halt(void) 155 { 156 struct cpu_info *ci = curcpu(); 157 158 /* Turn off interrupts and halt CPU. */ 159 // hppa_intr_disable(); 160 ci->ci_flags &= ~CPUF_RUNNING; 161 162 for (;;) 163 ; 164 } 165 166 void 167 xc_send_ipi(struct cpu_info *ci) 168 { 169 KASSERT(kpreempt_disabled()); 170 KASSERT(curcpu() != ci); 171 172 membar_release(); /* matches membar_acquire in hppa_ipi_intr */ 173 if (ci) { 174 /* Unicast: remote CPU. */ 175 hppa_ipi_send(ci, HPPA_IPI_XCALL); 176 } else { 177 /* Broadcast: all, but local CPU (caller will handle it). */ 178 hppa_ipi_broadcast(HPPA_IPI_XCALL); 179 } 180 } 181 182 void 183 cpu_ipi(struct cpu_info *ci) 184 { 185 KASSERT(kpreempt_disabled()); 186 KASSERT(curcpu() != ci); 187 188 membar_release(); /* matches membar_acquire in hppa_ipi_intr */ 189 if (ci) { 190 /* Unicast: remote CPU. */ 191 hppa_ipi_send(ci, HPPA_IPI_GENERIC); 192 } else { 193 /* Broadcast: all, but local CPU (caller will handle it). */ 194 hppa_ipi_broadcast(HPPA_IPI_GENERIC); 195 } 196 } 197