1 /* $OpenBSD: ipifuncs.c,v 1.27 2015/07/19 18:53:49 sf Exp $ */ 2 /* $NetBSD: ipifuncs.c,v 1.1.2.3 2000/06/26 02:04:06 sommerfeld Exp $ */ 3 4 /*- 5 * Copyright (c) 2000 The NetBSD Foundation, Inc. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to The NetBSD Foundation 9 * by RedBack Networks Inc. 10 * 11 * Author: Bill Sommerfeld 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 23 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 24 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 25 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 26 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32 * POSSIBILITY OF SUCH DAMAGE. 33 */ 34 35 /* 36 * Interprocessor interrupt handlers. 37 */ 38 39 #include "npx.h" 40 41 #include <sys/param.h> 42 #include <sys/device.h> 43 #include <sys/memrange.h> 44 #include <sys/systm.h> 45 46 #include <uvm/uvm_extern.h> 47 48 #include <machine/cpufunc.h> 49 #include <machine/cpuvar.h> 50 #include <machine/intr.h> 51 #include <machine/atomic.h> 52 #include <machine/i82093var.h> 53 #include <machine/db_machdep.h> 54 #include <machine/mplock.h> 55 56 void i386_ipi_nop(struct cpu_info *); 57 void i386_ipi_halt(struct cpu_info *); 58 59 #if NNPX > 0 60 void i386_ipi_synch_fpu(struct cpu_info *); 61 void i386_ipi_flush_fpu(struct cpu_info *); 62 #else 63 #define i386_ipi_synch_fpu NULL 64 #define i386_ipi_flush_fpu NULL 65 #endif 66 67 #ifdef MTRR 68 void i386_ipi_reload_mtrr(struct cpu_info *); 69 #else 70 #define i386_ipi_reload_mtrr 0 71 #endif 72 73 void (*ipifunc[I386_NIPI])(struct cpu_info *) = 74 { 75 i386_ipi_halt, 76 i386_ipi_nop, 77 i386_ipi_flush_fpu, 78 i386_ipi_synch_fpu, 79 i386_ipi_reload_mtrr, 80 #if 0 81 gdt_reload_cpu, 82 #else 83 NULL, 84 #endif 85 #ifdef DDB 86 i386_ipi_db, 87 #else 88 NULL, 89 #endif 90 i386_setperf_ipi, 91 }; 92 93 void 94 i386_ipi_nop(struct cpu_info *ci) 95 { 96 } 97 98 void 99 i386_ipi_halt(struct cpu_info *ci) 100 { 101 SCHED_ASSERT_UNLOCKED(); 102 KASSERT(!__mp_lock_held(&kernel_lock)); 103 104 npxsave_cpu(ci, 1); 105 disable_intr(); 106 lapic_disable(); 107 wbinvd(); 108 ci->ci_flags &= ~CPUF_RUNNING; 109 wbinvd(); 110 111 for(;;) { 112 asm volatile("hlt"); 113 } 114 } 115 116 #if NNPX > 0 117 void 118 i386_ipi_flush_fpu(struct cpu_info *ci) 119 { 120 if (ci->ci_fpsaveproc == ci->ci_fpcurproc) 121 npxsave_cpu(ci, 0); 122 } 123 124 void 125 i386_ipi_synch_fpu(struct cpu_info *ci) 126 { 127 if (ci->ci_fpsaveproc == ci->ci_fpcurproc) 128 npxsave_cpu(ci, 1); 129 } 130 #endif 131 132 #ifdef MTRR 133 void 134 i386_ipi_reload_mtrr(struct cpu_info *ci) 135 { 136 if (mem_range_softc.mr_op != NULL) 137 mem_range_softc.mr_op->reload(&mem_range_softc); 138 } 139 #endif 140 141 void 142 i386_spurious(void) 143 { 144 printf("spurious intr\n"); 145 } 146 147 void 148 i386_send_ipi(struct cpu_info *ci, int ipimask) 149 { 150 i386_atomic_setbits_l(&ci->ci_ipis, ipimask); 151 152 /* Don't send IPI to cpu which isn't (yet) running. */ 153 if (!(ci->ci_flags & CPUF_RUNNING)) 154 return; 155 156 i386_ipi(LAPIC_IPI_VECTOR, ci->ci_apicid, LAPIC_DLMODE_FIXED); 157 158 return; 159 } 160 161 int 162 i386_fast_ipi(struct cpu_info *ci, int ipi) 163 { 164 if (!(ci->ci_flags & CPUF_RUNNING)) 165 return (ENOENT); 166 167 i386_ipi(ipi, ci->ci_apicid, LAPIC_DLMODE_FIXED); 168 169 return 0; 170 } 171 172 void 173 i386_broadcast_ipi(int ipimask) 174 { 175 struct cpu_info *ci, *self = curcpu(); 176 CPU_INFO_ITERATOR cii; 177 int count = 0; 178 179 CPU_INFO_FOREACH(cii, ci) { 180 if (ci == self) 181 continue; 182 if ((ci->ci_flags & CPUF_RUNNING) == 0) 183 continue; 184 i386_atomic_setbits_l(&ci->ci_ipis, ipimask); 185 count++; 186 } 187 if (!count) 188 return; 189 190 i386_ipi(LAPIC_IPI_VECTOR, LAPIC_DEST_ALLEXCL, LAPIC_DLMODE_FIXED); 191 } 192 193 void 194 i386_ipi_handler(void) 195 { 196 extern struct evcount ipi_count; 197 struct cpu_info *ci = curcpu(); 198 u_int32_t pending; 199 int bit; 200 201 pending = i386_atomic_testset_ul(&ci->ci_ipis, 0); 202 203 for (bit = 0; bit < I386_NIPI && pending; bit++) { 204 if (pending & (1<<bit)) { 205 pending &= ~(1<<bit); 206 (*ipifunc[bit])(ci); 207 ipi_count.ec_count++; 208 } 209 } 210 } 211