1 /* $OpenBSD: cpu.c,v 1.42 2020/05/29 04:42:23 deraadt Exp $ */ 2 3 /* 4 * Copyright (c) 1998-2003 Michael Shalayeff 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT, 20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 25 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 26 * THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <sys/param.h> 30 #include <sys/systm.h> 31 #include <sys/device.h> 32 #include <sys/proc.h> 33 #include <sys/reboot.h> 34 35 #include <uvm/uvm_extern.h> 36 37 #include <machine/cpufunc.h> 38 #include <machine/pdc.h> 39 #include <machine/reg.h> 40 #include <machine/iomod.h> 41 #include <machine/autoconf.h> 42 43 #include <hppa/dev/cpudevs.h> 44 45 struct cpu_softc { 46 struct device sc_dev; 47 }; 48 49 #ifdef MULTIPROCESSOR 50 struct cpu_info *cpu_hatch_info; 51 static volatile int start_secondary_cpu; 52 #endif 53 54 int cpumatch(struct device *, void *, void *); 55 void cpuattach(struct device *, struct device *, void *); 56 57 struct cfattach cpu_ca = { 58 sizeof(struct cpu_softc), cpumatch, cpuattach 59 }; 60 61 struct cfdriver cpu_cd = { 62 NULL, "cpu", DV_DULL 63 }; 64 65 int 66 cpumatch(struct device *parent, void *cfdata, void *aux) 67 { 68 struct cfdata *cf = cfdata; 69 struct confargs *ca = aux; 70 71 /* probe any 1.0, 1.1 or 2.0 */ 72 if (ca->ca_type.iodc_type != HPPA_TYPE_NPROC || 73 ca->ca_type.iodc_sv_model != HPPA_NPROC_HPPA) 74 return 0; 75 76 if (cf->cf_unit >= MAXCPUS) 77 return 0; 78 79 return 1; 80 } 81 82 void 83 cpuattach(struct device *parent, struct device *self, void *aux) 84 { 85 /* machdep.c */ 86 extern struct pdc_model pdc_model; 87 extern struct pdc_cache pdc_cache; 88 extern struct pdc_btlb pdc_btlb; 89 extern u_int cpu_ticksnum, cpu_ticksdenom; 90 extern u_int fpu_enable; 91 /* clock.c */ 92 extern int cpu_hardclock(void *); 93 /* ipi.c */ 94 extern int hppa_ipi_intr(void *); 95 96 struct confargs *ca = (struct confargs *)aux; 97 struct cpu_info *ci; 98 u_int mhz = 100 * cpu_ticksnum / cpu_ticksdenom; 99 int cpuno = self->dv_unit; 100 struct pglist mlist; 101 struct vm_page *m; 102 const char *p; 103 int error; 104 105 ci = &cpu_info[cpuno]; 106 ci->ci_dev = self; 107 ci->ci_cpuid = cpuno; 108 ci->ci_hpa = ca->ca_hpa; 109 110 /* Allocate stack for spin up and FPU emulation. */ 111 TAILQ_INIT(&mlist); 112 error = uvm_pglistalloc(PAGE_SIZE, 0, -1L, 0, 0, &mlist, 1, 113 UVM_PLA_NOWAIT); 114 if (error) { 115 printf(": unable to allocate CPU stack!\n"); 116 return; 117 } 118 m = TAILQ_FIRST(&mlist); 119 ci->ci_stack = VM_PAGE_TO_PHYS(m); 120 121 printf (": %s ", cpu_typename); 122 if (pdc_model.hvers) { 123 static const char lvls[4][4] = { "0", "1", "1.5", "2" }; 124 125 printf("L%s-%c ", lvls[pdc_model.pa_lvl], "AB"[pdc_model.mc]); 126 } 127 128 printf ("%d", mhz / 100); 129 if (mhz % 100 > 9) 130 printf(".%02d", mhz % 100); 131 printf("MHz"); 132 133 if (fpu_enable) { 134 extern u_int fpu_version; 135 u_int32_t ver[2]; 136 137 mtctl(fpu_enable, CR_CCR); 138 __asm volatile( 139 "fstds %%fr0,0(%0)\n\t" 140 "copr,0,0\n\t" 141 "fstds %%fr0,0(%0)" 142 :: "r" (&ver) : "memory"); 143 mtctl(0, CR_CCR); 144 fpu_version = HPPA_FPUVER(ver[0]); 145 printf(", FPU %s rev %d", 146 hppa_mod_info(HPPA_TYPE_FPU, fpu_version >> 5), 147 fpu_version & 0x1f); 148 } 149 150 printf("\n%s: ", self->dv_xname); 151 p = ""; 152 if (!pdc_cache.dc_conf.cc_sh) { 153 printf("%uK(%db/l) Icache, ", 154 pdc_cache.ic_size / 1024, pdc_cache.ic_conf.cc_line * 16); 155 p = "D"; 156 } 157 158 printf("%uK(%db/l) wr-%s %scache, ", 159 pdc_cache.dc_size / 1024, pdc_cache.dc_conf.cc_line * 16, 160 pdc_cache.dc_conf.cc_wt? "thru" : "back", p); 161 162 p = ""; 163 if (!pdc_cache.dt_conf.tc_sh) { 164 printf("%u ITLB, ", pdc_cache.it_size); 165 p = "D"; 166 } 167 printf("%u %scoherent %sTLB", 168 pdc_cache.dt_size, pdc_cache.dt_conf.tc_cst? "" : "in", p); 169 170 if (pdc_btlb.finfo.num_c) 171 printf(", %u BTLB", pdc_btlb.finfo.num_c); 172 else if (pdc_btlb.finfo.num_i || pdc_btlb.finfo.num_d) 173 printf(", %u/%u D/I BTLBs", 174 pdc_btlb.finfo.num_i, pdc_btlb.finfo.num_d); 175 176 cpu_intr_establish(IPL_CLOCK, 31, cpu_hardclock, NULL, "clock"); 177 #ifdef MULTIPROCESSOR 178 cpu_intr_establish(IPL_IPI, 30, hppa_ipi_intr, NULL, "ipi"); 179 #endif 180 181 printf("\n"); 182 } 183 184 #ifdef MULTIPROCESSOR 185 void 186 cpu_boot_secondary_processors(void) 187 { 188 struct cpu_info *ci; 189 struct iomod *cpu; 190 int i, j; 191 192 /* Initialise primary CPU. */ 193 ci = curcpu(); 194 ci->ci_flags |= CPUF_RUNNING; 195 hppa_ipi_init(ci); 196 197 for (i = 0; i < HPPA_MAXCPUS; i++) { 198 199 ci = &cpu_info[i]; 200 if (ci->ci_cpuid == 0) 201 continue; 202 203 ci->ci_randseed = (arc4random() & 0x7fffffff) + 1; 204 205 sched_init_cpu(ci); 206 207 /* Release the specified CPU by triggering an EIR{0}. */ 208 cpu_hatch_info = ci; 209 cpu = (struct iomod *)(ci->ci_hpa); 210 cpu->io_eir = 0; 211 asm volatile ("sync" ::: "memory"); 212 213 /* Wait for CPU to wake up... */ 214 j = 0; 215 while (!(ci->ci_flags & CPUF_RUNNING) && j++ < 10000) 216 delay(1000); 217 if (!(ci->ci_flags & CPUF_RUNNING)) 218 printf("failed to hatch cpu %i!\n", ci->ci_cpuid); 219 } 220 221 /* Release secondary CPUs. */ 222 start_secondary_cpu = 1; 223 asm volatile ("sync" ::: "memory"); 224 } 225 226 void 227 cpu_hw_init(void) 228 { 229 struct cpu_info *ci = curcpu(); 230 231 /* Purge TLB and flush caches. */ 232 ptlball(); 233 ficacheall(); 234 fdcacheall(); 235 236 /* Enable address translations. */ 237 ci->ci_psw = PSL_I | PSL_Q | PSL_P | PSL_C | PSL_D; 238 ci->ci_psw |= (cpu_info[0].ci_psw & PSL_O); 239 } 240 241 void 242 cpu_hatch(void) 243 { 244 struct cpu_info *ci = curcpu(); 245 extern u_long cpu_hzticks; 246 u_long itmr; 247 int s; 248 249 /* Initialise IPIs. */ 250 hppa_ipi_init(ci); 251 252 /* Initialise clock. */ 253 mtctl((1U << 31), CR_EIRR); 254 mfctl(CR_ITMR, itmr); 255 ci->ci_itmr = itmr; 256 itmr += cpu_hzticks; 257 mtctl(itmr, CR_ITMR); 258 ci->ci_mask |= (1U << 31); 259 260 /* Enable interrupts. */ 261 mtctl(ci->ci_mask, CR_EIEM); 262 263 ncpus++; 264 ci->ci_flags |= CPUF_RUNNING; 265 266 /* Wait for additional CPUs to spinup. */ 267 while (!start_secondary_cpu) 268 ; 269 270 SCHED_LOCK(s); 271 cpu_switchto(NULL, sched_chooseproc()); 272 } 273 274 void 275 cpu_unidle(struct cpu_info *ci) 276 { 277 if (ci != curcpu()) 278 hppa_ipi_send(ci, HPPA_IPI_NOP); 279 } 280 #endif 281 282 void 283 need_resched(struct cpu_info *ci) 284 { 285 ci->ci_want_resched = 1; 286 287 /* There's a risk we'll be called before the idle threads start */ 288 if (ci->ci_curproc) { 289 setsoftast(ci->ci_curproc); 290 cpu_unidle(ci); 291 } 292 } 293