1 /* $NetBSD: multicpu.c,v 1.13 2002/09/27 15:36:59 provos Exp $ */ 2 3 /* 4 * Copyright (c) 2000 Ludd, University of Lule}, Sweden. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed at Ludd, University of 17 * Lule}, Sweden and its contributors. 18 * 4. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 /* 34 * CPU-type independent code to spin up other VAX CPU's. 35 */ 36 37 #include "opt_multiprocessor.h" 38 39 #include <sys/param.h> 40 #include <sys/queue.h> 41 #include <sys/malloc.h> 42 #include <sys/proc.h> 43 #include <sys/user.h> 44 #include <sys/device.h> 45 46 #include <uvm/uvm_extern.h> 47 48 #include <machine/cpu.h> 49 #include <machine/../vax/gencons.h> 50 51 #include "ioconf.h" 52 53 struct cpu_mp_dep *mp_dep_call; 54 55 static void slaverun(void); 56 57 struct cpuq { 58 SIMPLEQ_ENTRY(cpuq) cq_q; 59 struct cpu_info *cq_ci; 60 struct device *cq_dev; 61 }; 62 63 SIMPLEQ_HEAD(, cpuq) cpuq = SIMPLEQ_HEAD_INITIALIZER(cpuq); 64 65 extern long avail_start, avail_end, proc0paddr; 66 67 void 68 cpu_boot_secondary_processors() 69 { 70 struct cpuq *q; 71 72 while ((q = SIMPLEQ_FIRST(&cpuq))) { 73 SIMPLEQ_REMOVE_HEAD(&cpuq, cq_q); 74 (*mp_dep_call->cpu_startslave)(q->cq_dev, q->cq_ci); 75 free(q, M_TEMP); 76 } 77 } 78 79 /* 80 * Allocate an UAREA for this CPU, create an idle PCB, get a cpu_info 81 * struct and fill it in and prepare for getting started by 82 * cpu_boot_secondary_processors(). 83 */ 84 void 85 cpu_slavesetup(struct device *dev) 86 { 87 struct cpu_mp_softc *sc = (struct cpu_mp_softc *)dev; 88 struct cpuq *cq; 89 struct cpu_info *ci; 90 struct pglist mlist; 91 struct vm_page *pg; 92 struct pcb *pcb; 93 vaddr_t istackbase, scratch; 94 int error; 95 96 /* Get an UAREA */ 97 error = uvm_pglistalloc(USPACE, avail_start, avail_end, 0, 0, 98 &mlist, 1, 1); 99 if (error) 100 panic("cpu_slavesetup: error %d", error); 101 pcb = (struct pcb *)(VM_PAGE_TO_PHYS(TAILQ_FIRST(&mlist)) | KERNBASE); 102 103 /* Copy our own idle PCB */ 104 memcpy(pcb, (void *)proc0paddr, sizeof(struct user)); 105 kvtopte((u_int)pcb + REDZONEADDR)->pg_v = 0; 106 107 /* Allocate an interrupt stack */ 108 pg = uvm_pagealloc(NULL, 0, NULL, 0); 109 if (pg == NULL) 110 panic("cpu_slavesetup2"); 111 istackbase = VM_PAGE_TO_PHYS(pg) | KERNBASE; 112 kvtopte(istackbase)->pg_v = 0; /* istack safety belt */ 113 114 /* Get scratch pages for different use, see pmap.c for comment */ 115 pg = uvm_pagealloc(NULL, 0, NULL, 0); 116 if (pg == NULL) 117 panic("cpu_slavesetup3"); 118 scratch = VM_PAGE_TO_PHYS(pg) | KERNBASE; 119 120 /* Populate the PCB and the cpu_info struct */ 121 ci = &sc->sc_ci; 122 ci->ci_dev = dev; 123 ci->ci_exit = scratch; 124 (u_long)ci->ci_pcb = (u_long)pcb & ~KERNBASE; 125 ci->ci_istack = istackbase + NBPG; 126 pcb->KSP = (u_long)pcb + USPACE; /* Idle kernel stack */ 127 pcb->SSP = (u_long)ci; 128 pcb->PC = (u_long)slaverun + 2; 129 pcb->PSL = 0; 130 131 cq = malloc(sizeof(*cq), M_TEMP, M_NOWAIT); 132 if (cq == NULL) 133 panic("cpu_slavesetup4"); 134 memset(cq, 0, sizeof(*cq)); 135 cq->cq_ci = ci; 136 cq->cq_dev = dev; 137 SIMPLEQ_INSERT_TAIL(&cpuq, cq, cq_q); 138 } 139 140 volatile int sta; 141 142 void 143 slaverun() 144 { 145 struct cpu_info *ci = curcpu(); 146 147 ((volatile struct cpu_info *)ci)->ci_flags |= CI_RUNNING; 148 cpu_send_ipi(IPI_DEST_MASTER, IPI_RUNNING); 149 printf("%s: running\n", ci->ci_dev->dv_xname); 150 while (sta != ci->ci_dev->dv_unit) 151 ; 152 splsched(); 153 sched_lock_idle(); 154 cpu_switch(NULL,NULL); 155 } 156 157 /* 158 * Send an IPI of type type to the CPU with logical device number cpu. 159 */ 160 void 161 cpu_send_ipi(int cpu, int type) 162 { 163 struct cpu_mp_softc *sc; 164 int i; 165 166 if (cpu >= 0) { 167 sc = cpu_cd.cd_devs[cpu]; 168 bbssi(type, &sc->sc_ci.ci_ipimsgs); 169 (*mp_dep_call->cpu_send_ipi)(&sc->sc_dev); 170 return; 171 } 172 173 for (i = 0; i < cpu_cd.cd_ndevs; i++) { 174 sc = cpu_cd.cd_devs[i]; 175 if (sc == NULL) 176 continue; 177 switch (cpu) { 178 case IPI_DEST_MASTER: 179 if (sc->sc_ci.ci_flags & CI_MASTERCPU) { 180 bbssi(type, &sc->sc_ci.ci_ipimsgs); 181 (*mp_dep_call->cpu_send_ipi)(&sc->sc_dev); 182 } 183 break; 184 case IPI_DEST_ALL: 185 if (i == cpu_number()) 186 continue; /* No IPI to myself */ 187 bbssi(type, &sc->sc_ci.ci_ipimsgs); 188 (*mp_dep_call->cpu_send_ipi)(&sc->sc_dev); 189 break; 190 } 191 } 192 } 193 194 void 195 cpu_handle_ipi() 196 { 197 struct cpu_info *ci = curcpu(); 198 int bitno; 199 200 while ((bitno = ffs(ci->ci_ipimsgs))) { 201 bitno -= 1; /* ffs() starts from 1 */ 202 bbcci(bitno, &ci->ci_ipimsgs); 203 switch (bitno) { 204 case IPI_START_CNTX: 205 #ifdef DIAGNOSTIC 206 if (CPU_IS_PRIMARY(ci) == 0) 207 panic("cpu_handle_ipi"); 208 #endif 209 gencnstarttx(); 210 break; 211 case IPI_SEND_CNCHAR: 212 #ifdef DIAGNOSTIC 213 if (CPU_IS_PRIMARY(ci) == 0) 214 panic("cpu_handle_ipi2"); 215 #endif 216 (*mp_dep_call->cpu_cnintr)(); 217 break; 218 case IPI_RUNNING: 219 break; 220 case IPI_TBIA: 221 mtpr(0, PR_TBIA); 222 break; 223 case IPI_DDB: 224 Debugger(); 225 break; 226 default: 227 panic("cpu_handle_ipi: bad bit %x", bitno); 228 } 229 } 230 } 231