Home | History | Annotate | Line # | Download | only in vax
      1 /*	$NetBSD: multicpu.c,v 1.37 2022/03/03 06:28:26 riastradh 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  *
     15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     25  */
     26 
     27 /*
     28  * CPU-type independent code to spin up other VAX CPU's.
     29  */
     30 
     31 #include <sys/cdefs.h>
     32 __KERNEL_RCSID(0, "$NetBSD: multicpu.c,v 1.37 2022/03/03 06:28:26 riastradh Exp $");
     33 
     34 #include "opt_multiprocessor.h"
     35 
     36 #include <sys/param.h>
     37 #include <sys/cpu.h>
     38 #include <sys/device.h>
     39 #include <sys/kmem.h>
     40 #include <sys/proc.h>
     41 #include <sys/xcall.h>
     42 #include <sys/ipi.h>
     43 
     44 #include <uvm/uvm_extern.h>
     45 
     46 #include <vax/vax/gencons.h>
     47 
     48 #include "ioconf.h"
     49 
     50 const struct cpu_mp_dep *mp_dep_call;
     51 
     52 struct cpuq {
     53 	SIMPLEQ_ENTRY(cpuq) cq_q;
     54 	struct cpu_info *cq_ci;
     55 	device_t cq_dev;
     56 };
     57 
     58 SIMPLEQ_HEAD(, cpuq) cpuq = SIMPLEQ_HEAD_INITIALIZER(cpuq);
     59 
     60 extern long avail_start, avail_end;
     61 struct cpu_info_qh cpus = SIMPLEQ_HEAD_INITIALIZER(cpus);
     62 
     63 void
     64 cpu_boot_secondary_processors(void)
     65 {
     66 	struct cpuq *q;
     67 
     68 	while ((q = SIMPLEQ_FIRST(&cpuq))) {
     69 		SIMPLEQ_REMOVE_HEAD(&cpuq, cq_q);
     70 		(*mp_dep_call->cpu_startslave)(q->cq_ci);
     71 		kmem_free(q, sizeof(*q));
     72 	}
     73 }
     74 
     75 /*
     76  * Allocate a cpu_info struct and fill it in then prepare for getting
     77  * started by cpu_boot_secondary_processors().
     78  */
     79 void
     80 cpu_slavesetup(device_t self, int slotid)
     81 {
     82 	struct cpu_info *ci;
     83 	struct cpuq *cq;
     84 	struct vm_page *pg;
     85 	vaddr_t istackbase;
     86 
     87 	KASSERT(device_private(self) == NULL);
     88 
     89 	ci = kmem_zalloc(sizeof(*ci), KM_SLEEP);
     90 	device_set_private(self, ci);
     91 	ci->ci_dev = self;
     92 	ci->ci_slotid = slotid;
     93 	ci->ci_cpuid = device_unit(self);
     94 
     95 	/* Allocate an interrupt stack */
     96 	pg = uvm_pagealloc(NULL, 0, NULL, 0);
     97 	if (pg == NULL)
     98 		panic("cpu_slavesetup2");
     99 
    100 	istackbase = VM_PAGE_TO_PHYS(pg) | KERNBASE;
    101 	kvtopte(istackbase)->pg_v = 0; /* istack safety belt */
    102 
    103 	/* Populate the PCB and the cpu_info struct */
    104 	ci->ci_istack = istackbase + PAGE_SIZE;
    105 	SIMPLEQ_INSERT_TAIL(&cpus, ci, ci_next);
    106 
    107 	cq = kmem_zalloc(sizeof(*cq), KM_SLEEP);
    108 	cq->cq_ci = ci;
    109 	cq->cq_dev = ci->ci_dev;
    110 	SIMPLEQ_INSERT_TAIL(&cpuq, cq, cq_q);
    111 
    112 	mi_cpu_attach(ci);	/* let the MI parts know about the new cpu */
    113 }
    114 
    115 /*
    116  * Send an IPI of type type to the CPU with logical device number cpu.
    117  */
    118 void
    119 cpu_send_ipi(int cpu, int type)
    120 {
    121 	struct cpu_info *ci;
    122 	int i;
    123 
    124 	if (cpu >= 0) {
    125 		ci = device_lookup_private(&cpu_cd, cpu);
    126 		bbssi(type, &ci->ci_ipimsgs);
    127 		(*mp_dep_call->cpu_send_ipi)(ci);
    128 		return;
    129 	}
    130 
    131 	for (i = 0; i < cpu_cd.cd_ndevs; i++) {
    132 		ci = device_lookup_private(&cpu_cd, i);
    133 		if (ci == NULL)
    134 			continue;
    135 		switch (cpu) {
    136 		case IPI_DEST_MASTER:
    137 			if (ci->ci_flags & CI_MASTERCPU) {
    138 				bbssi(type, &ci->ci_ipimsgs);
    139 				(*mp_dep_call->cpu_send_ipi)(ci);
    140 			}
    141 			break;
    142 		case IPI_DEST_ALL:
    143 			if (i == cpu_number())
    144 				continue;	/* No IPI to myself */
    145 			bbssi(type, &ci->ci_ipimsgs);
    146 			(*mp_dep_call->cpu_send_ipi)(ci);
    147 			break;
    148 		}
    149 	}
    150 }
    151 
    152 void
    153 cpu_handle_ipi(void)
    154 {
    155 	struct cpu_info * const ci = curcpu();
    156 	int bitno;
    157 	int s;
    158 
    159 	s = splhigh();
    160 
    161 	while ((bitno = ffs(ci->ci_ipimsgs))) {
    162 		bitno -= 1; /* ffs() starts from 1 */
    163 		bbcci(bitno, &ci->ci_ipimsgs);
    164 		switch (bitno) {
    165 		case IPI_START_CNTX:
    166 #ifdef DIAGNOSTIC
    167 			if (CPU_IS_PRIMARY(ci) == 0)
    168 				panic("cpu_handle_ipi");
    169 #endif
    170 			gencnstarttx();
    171 			break;
    172 		case IPI_SEND_CNCHAR:
    173 #ifdef DIAGNOSTIC
    174 			if (CPU_IS_PRIMARY(ci) == 0)
    175 				panic("cpu_handle_ipi2");
    176 #endif
    177 			(*mp_dep_call->cpu_cnintr)();
    178 			break;
    179 		case IPI_RUNNING:
    180 			break;
    181 		case IPI_TBIA:
    182 			mtpr(0, PR_TBIA);
    183 			break;
    184 		case IPI_DDB:
    185 			Debugger();
    186 			break;
    187 		case IPI_XCALL:
    188 			xc_ipi_handler();
    189 			break;
    190 		case IPI_GENERIC:
    191 			ipi_cpu_handler();
    192 			break;
    193 		default:
    194 			panic("cpu_handle_ipi: bad bit %x", bitno);
    195 		}
    196 	}
    197 	splx(s);
    198 }
    199 
    200 /*
    201  * MD support for xcall(9) interface.
    202  */
    203 
    204 void
    205 xc_send_ipi(struct cpu_info *ci)
    206 {
    207 	KASSERT(kpreempt_disabled());
    208 	KASSERT(curcpu() != ci);
    209 
    210 	if (ci) {
    211 		/* Unicast: remote CPU. */
    212 		cpu_send_ipi(ci->ci_cpuid, IPI_XCALL);
    213 	} else {
    214 		/* Broadcast: all, but local CPU (caller will handle it). */
    215 		cpu_send_ipi(IPI_DEST_ALL, IPI_XCALL);
    216 	}
    217 }
    218 
    219 void
    220 cpu_ipi(struct cpu_info *ci)
    221 {
    222 	KASSERT(kpreempt_disabled());
    223 	KASSERT(curcpu() != ci);
    224 
    225 	if (ci) {
    226 		/* Unicast: remote CPU. */
    227 		cpu_send_ipi(ci->ci_cpuid, IPI_GENERIC);
    228 	} else {
    229 		/* Broadcast: all, but local CPU (caller will handle it). */
    230 		cpu_send_ipi(IPI_DEST_ALL, IPI_GENERIC);
    231 	}
    232 }
    233