xref: /netbsd/sys/arch/vax/vax/multicpu.c (revision c4a72b64)
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