1 /* $NetBSD: rmixl_cpu.c,v 1.4 2011/04/29 22:00:03 matt Exp $ */ 2 3 /* 4 * Copyright 2002 Wasabi Systems, Inc. 5 * All rights reserved. 6 * 7 * Written by Simon Burge for Wasabi Systems, Inc. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed for the NetBSD Project by 20 * Wasabi Systems, Inc. 21 * 4. The name of Wasabi Systems, Inc. may not be used to endorse 22 * or promote products derived from this software without specific prior 23 * written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 * POSSIBILITY OF SUCH DAMAGE. 36 */ 37 38 #include "locators.h" 39 40 #include <sys/cdefs.h> 41 __KERNEL_RCSID(0, "$NetBSD: rmixl_cpu.c,v 1.4 2011/04/29 22:00:03 matt Exp $"); 42 43 #include "opt_multiprocessor.h" 44 #include "opt_ddb.h" 45 46 #include <sys/param.h> 47 #include <sys/device.h> 48 #include <sys/systm.h> 49 #include <sys/cpu.h> 50 #include <sys/lock.h> 51 #include <sys/lwp.h> 52 #include <sys/cpu.h> 53 #include <sys/malloc.h> 54 #include <uvm/uvm_pglist.h> 55 #include <uvm/uvm_extern.h> 56 #include <mips/regnum.h> 57 #include <mips/asm.h> 58 #include <mips/pmap.h> 59 #include <mips/rmi/rmixlreg.h> 60 #include <mips/rmi/rmixlvar.h> 61 #include <mips/rmi/rmixl_cpucorevar.h> 62 #include <mips/rmi/rmixl_cpuvar.h> 63 #include <mips/rmi/rmixl_intr.h> 64 #include <mips/rmi/rmixl_fmnvar.h> 65 #ifdef DDB 66 #include <mips/db_machdep.h> 67 #endif 68 69 70 static int cpu_rmixl_match(device_t, cfdata_t, void *); 71 static void cpu_rmixl_attach(device_t, device_t, void *); 72 static void cpu_rmixl_attach_primary(struct rmixl_cpu_softc * const); 73 #ifdef NOTYET 74 static int cpu_fmn_intr(void *, rmixl_fmn_rxmsg_t *); 75 #endif 76 77 #ifdef MULTIPROCESSOR 78 void cpu_rmixl_hatch(struct cpu_info *); 79 void cpu_rmixl_run(struct cpu_info *); 80 #if 0 81 static void cpu_setup_trampoline_ipi(struct device *, struct cpu_info *); 82 #endif 83 static int cpu_setup_trampoline_common(struct cpu_info *, struct rmixl_cpu_trampoline_args *); 84 static void cpu_setup_trampoline_callback(struct cpu_info *); 85 #endif /* MULTIPROCESSOR */ 86 87 #ifdef DEBUG 88 void rmixl_cpu_data_print(struct cpu_data *); 89 struct cpu_info * 90 rmixl_cpuinfo_print(u_int); 91 #endif /* DEBUG */ 92 93 CFATTACH_DECL_NEW(cpu_rmixl, sizeof(struct rmixl_cpu_softc), 94 cpu_rmixl_match, cpu_rmixl_attach, NULL, NULL); 95 96 #ifdef MULTIPROCESSOR 97 static struct rmixl_cpu_trampoline_args rmixl_cpu_trampoline_args; 98 #endif 99 100 /* 101 * cpu_rmixl_watchpoint_init - initialize COP0 watchpoint stuff 102 * 103 * clear IEU_DEFEATURE[DBE] to ensure T_WATCH on watchpoint exception 104 * set COP0 watchhi and watchlo 105 * 106 * disable all watchpoints 107 */ 108 static void 109 cpu_rmixl_watchpoint_init(void) 110 { 111 uint32_t r; 112 113 r = rmixl_mfcr(RMIXL_PCR_IEU_DEFEATURE); 114 r &= ~__BIT(7); /* DBE */ 115 rmixl_mtcr(RMIXL_PCR_IEU_DEFEATURE, r); 116 117 cpuwatch_clr_all(); 118 } 119 120 /* 121 * cpu_xls616_erratum 122 * 123 * on the XLS616, COUNT/COMPARE clock regs seem to interact between 124 * threads on a core 125 * 126 * the symptom of the error is retarded clock interrupts 127 * and very slow apparent system performance 128 * 129 * other XLS chips may have the same problem. 130 * we may need to add other PID checks. 131 */ 132 static inline bool 133 cpu_xls616_erratum(device_t parent, struct cpucore_attach_args *ca) 134 { 135 #if 0 136 if (mips_options.mips_cpu->cpu_pid == MIPS_XLS616) { 137 if (ca->ca_thread > 0) { 138 aprint_error_dev(parent, "XLS616 CLOCK ERRATUM: " 139 "deconfigure cpu%d\n", ca->ca_thread); 140 return true; 141 } 142 } 143 #endif 144 return false; 145 } 146 147 static bool 148 cpu_rmixl_erratum(device_t parent, struct cpucore_attach_args *ca) 149 { 150 return cpu_xls616_erratum(parent, ca); 151 } 152 153 static int 154 cpu_rmixl_match(device_t parent, cfdata_t cf, void *aux) 155 { 156 struct cpucore_attach_args *ca = aux; 157 int thread = cf->cf_loc[CPUCORECF_THREAD]; 158 159 if (!cpu_rmixl(mips_options.mips_cpu)) 160 return 0; 161 162 if (strncmp(ca->ca_name, cf->cf_name, strlen(cf->cf_name)) == 0 163 #ifndef MULTIPROCESSOR 164 && ca->ca_thread == 0 165 #endif 166 && (thread == CPUCORECF_THREAD_DEFAULT || thread == ca->ca_thread) 167 && (!cpu_rmixl_erratum(parent, ca))) 168 return 1; 169 170 return 0; 171 } 172 173 static void 174 cpu_rmixl_attach(device_t parent, device_t self, void *aux) 175 { 176 struct rmixl_cpu_softc * const sc = device_private(self); 177 struct cpu_info *ci = NULL; 178 static bool once = false; 179 extern void rmixl_spl_init_cpu(void); 180 181 if (once == false) { 182 /* first attach is the primary cpu */ 183 once = true; 184 ci = curcpu(); 185 sc->sc_dev = self; 186 sc->sc_ci = ci; 187 ci->ci_softc = (void *)sc; 188 189 rmixl_spl_init_cpu(); /* spl initialization for CPU#0 */ 190 cpu_rmixl_attach_primary(sc); 191 192 #ifdef MULTIPROCESSOR 193 mips_locoresw.lsw_cpu_init = cpu_rmixl_hatch; 194 mips_locoresw.lsw_cpu_run = cpu_rmixl_run; 195 } else { 196 struct cpucore_attach_args * const ca = aux; 197 struct cpucore_softc * const ccsc = device_private(parent); 198 rmixlfw_psb_type_t psb_type = rmixl_configuration.rc_psb_type; 199 cpuid_t cpuid; 200 201 KASSERT(ca->ca_core < 8); 202 KASSERT(ca->ca_thread < 4); 203 cpuid = (ca->ca_core << 2) | ca->ca_thread; 204 ci = cpu_info_alloc(ccsc->sc_tlbinfo, cpuid, 205 /* XXX */ 0, ca->ca_core, ca->ca_thread); 206 KASSERT(ci != NULL); 207 if (ccsc->sc_tlbinfo == NULL) 208 ccsc->sc_tlbinfo = ci->ci_tlb_info; 209 sc->sc_dev = self; 210 sc->sc_ci = ci; 211 ci->ci_softc = (void *)sc; 212 213 switch (psb_type) { 214 case PSB_TYPE_RMI: 215 case PSB_TYPE_DELL: 216 cpu_setup_trampoline_callback(ci); 217 break; 218 default: 219 aprint_error(": psb type=%s cpu_wakeup unsupported\n", 220 rmixlfw_psb_type_name(psb_type)); 221 return; 222 } 223 224 const u_long cpu_mask = 1L << cpu_index(ci); 225 for (size_t i=0; i < 10000; i++) { 226 if ((cpus_hatched & cpu_mask) != 0) 227 break; 228 DELAY(100); 229 } 230 if ((cpus_hatched & cpu_mask) == 0) { 231 aprint_error(": failed to hatch\n"); 232 return; 233 } 234 #endif /* MULTIPROCESSOR */ 235 } 236 237 /* 238 * do per-cpu interrupt initialization 239 */ 240 rmixl_intr_init_cpu(ci); 241 242 aprint_normal("\n"); 243 244 cpu_attach_common(self, ci); 245 } 246 247 /* 248 * attach the primary processor 249 */ 250 static void 251 cpu_rmixl_attach_primary(struct rmixl_cpu_softc * const sc) 252 { 253 struct cpu_info *ci = sc->sc_ci; 254 uint32_t ebase; 255 256 KASSERT(CPU_IS_PRIMARY(ci)); 257 258 /* 259 * obtain and set cpuid of the primary processor 260 */ 261 asm volatile("dmfc0 %0, $15, 1;" : "=r"(ebase)); 262 ci->ci_cpuid = ebase & __BITS(9,0); 263 264 cpu_rmixl_watchpoint_init(); 265 266 rmixl_fmn_init(); 267 268 rmixl_intr_init_clk(); 269 #ifdef MULTIPROCESSOR 270 rmixl_intr_init_ipi(); 271 #endif 272 273 #ifdef NOTYET 274 void *ih = rmixl_fmn_intr_establish(RMIXL_FMN_STID_CORE0, 275 cpu_fmn_intr, ci); 276 if (ih == NULL) 277 panic("%s: rmixl_fmn_intr_establish failed", 278 __func__); 279 sc->sc_ih_fmn = ih; 280 #endif 281 } 282 283 #ifdef NOTYET 284 static int 285 cpu_fmn_intr(void *arg, rmixl_fmn_rxmsg_t *rxmsg) 286 { 287 if (CPU_IS_PRIMARY(curcpu())) { 288 printf("%s: cpu%ld: rxsid=%#x, code=%d, size=%d\n", 289 __func__, cpu_number(), 290 rxmsg->rxsid, rxmsg->code, rxmsg->size); 291 for (int i=0; i < rxmsg->size; i++) 292 printf("\t%#"PRIx64"\n", rxmsg->msg.data[i]); 293 } 294 295 return 1; 296 } 297 #endif 298 299 #ifdef MULTIPROCESSOR 300 /* 301 * cpu_rmixl_run 302 * 303 * - chip-specific post-running code called from cpu_hatch via lsw_cpu_run 304 */ 305 void 306 cpu_rmixl_run(struct cpu_info *ci) 307 { 308 struct rmixl_cpu_softc * const sc = (void *)ci->ci_softc; 309 cpucore_rmixl_run(device_parent(sc->sc_dev)); 310 } 311 312 /* 313 * cpu_rmixl_hatch 314 * 315 * - chip-specific hatch code called from cpu_hatch via lsw_cpu_init 316 */ 317 void 318 cpu_rmixl_hatch(struct cpu_info *ci) 319 { 320 struct rmixl_cpu_softc * const sc = (void *)ci->ci_softc; 321 extern void rmixl_spl_init_cpu(void); 322 323 rmixl_spl_init_cpu(); /* spl initialization for this CPU */ 324 325 (void)splhigh(); 326 327 #ifdef DEBUG 328 uint32_t ebase; 329 asm volatile("dmfc0 %0, $15, 1;" : "=r"(ebase)); 330 KASSERT((ebase & __BITS(9,0)) == ci->ci_cpuid); 331 KASSERT(curcpu() == ci); 332 #endif 333 334 cpucore_rmixl_hatch(device_parent(sc->sc_dev)); 335 336 cpu_rmixl_watchpoint_init(); 337 } 338 339 static int 340 cpu_setup_trampoline_common(struct cpu_info *ci, struct rmixl_cpu_trampoline_args *ta) 341 { 342 struct lwp *l = ci->ci_data.cpu_idlelwp; 343 uintptr_t stacktop; 344 345 #ifdef DIAGNOSTIC 346 /* Ensure our current stack can be used by the firmware */ 347 uint64_t sp; 348 __asm__ volatile("move %0, $sp\n" : "=r"(sp)); 349 #ifdef _LP64 350 /* can be made into a KSEG0 addr */ 351 KASSERT(MIPS_XKPHYS_P(sp)); 352 KASSERT((MIPS_XKPHYS_TO_PHYS(sp) >> 32) == 0); 353 #else 354 /* is a KSEG0 addr */ 355 KASSERT(MIPS_KSEG0_P(sp)); 356 #endif /* _LP64 */ 357 #endif /* DIAGNOSTIC */ 358 359 #ifndef _LP64 360 /* 361 * Ensure 'ci' is a KSEG0 address for trampoline args 362 * to avoid TLB fault in cpu_trampoline() when loading ci_idlelwp 363 */ 364 KASSERT(MIPS_KSEG0_P(ci)); 365 #endif 366 367 /* 368 * Ensure 'ta' is a KSEG0 address for trampoline args 369 * to avoid TLB fault in trampoline when loading args. 370 * 371 * Note: 372 * RMI firmware only passes the lower 32-bit half of 'ta' 373 * to rmixl_cpu_trampoline (the upper half is clear) 374 * so rmixl_cpu_trampoline must reconstruct the missing upper half 375 * rmixl_cpu_trampoline "knows" 'ta' is a KSEG0 address 376 * and sign-extends to make an LP64 KSEG0 address. 377 */ 378 KASSERT(MIPS_KSEG0_P(ta)); 379 380 /* 381 * marshal args for rmixl_cpu_trampoline; 382 * note for non-LP64 kernel, use of intptr_t 383 * forces sign extension of 32 bit pointers 384 */ 385 stacktop = (uintptr_t)l->l_md.md_utf - CALLFRAME_SIZ; 386 ta->ta_sp = (uint64_t)(intptr_t)stacktop; 387 ta->ta_lwp = (uint64_t)(intptr_t)l; 388 ta->ta_cpuinfo = (uint64_t)(intptr_t)ci; 389 390 return 0; 391 } 392 393 static void 394 cpu_setup_trampoline_callback(struct cpu_info *ci) 395 { 396 void (*wakeup_cpu)(void *, void *, unsigned int); 397 struct rmixl_cpu_trampoline_args *ta = &rmixl_cpu_trampoline_args; 398 extern void rmixl_cpu_trampoline(void *); 399 extern void rmixlfw_wakeup_cpu(void *, void *, u_int64_t, void *); 400 401 cpu_setup_trampoline_common(ci, ta); 402 403 #if _LP64 404 wakeup_cpu = (void *)rmixl_configuration.rc_psb_info.wakeup; 405 #else 406 wakeup_cpu = (void *)(intptr_t) 407 (rmixl_configuration.rc_psb_info.wakeup & 0xffffffff); 408 #endif 409 410 rmixlfw_wakeup_cpu(rmixl_cpu_trampoline, (void *)ta, 411 (uint64_t)1 << ci->ci_cpuid, wakeup_cpu); 412 } 413 #endif /* MULTIPROCESSOR */ 414 415 416 #ifdef DEBUG 417 void 418 rmixl_cpu_data_print(struct cpu_data *dp) 419 { 420 printf("cpu_biglock_wanted %p\n", dp->cpu_biglock_wanted); 421 printf("cpu_callout %p\n", dp->cpu_callout); 422 printf("cpu_unused1 %p\n", dp->cpu_unused1); 423 printf("cpu_unused2 %d\n", dp->cpu_unused2); 424 printf("&cpu_schedstate %p\n", &dp->cpu_schedstate); /* TBD */ 425 printf("&cpu_xcall %p\n", &dp->cpu_xcall); /* TBD */ 426 printf("cpu_xcall_pending %d\n", dp->cpu_xcall_pending); 427 printf("cpu_onproc %p\n", dp->cpu_onproc); 428 printf("&cpu_qchain %p\n", &dp->cpu_qchain); /* TBD */ 429 printf("cpu_idlelwp %p\n", dp->cpu_idlelwp); 430 printf("cpu_lockstat %p\n", dp->cpu_lockstat); 431 printf("cpu_index %d\n", dp->cpu_index); 432 printf("cpu_biglock_count %d\n", dp->cpu_biglock_count); 433 printf("cpu_spin_locks %d\n", dp->cpu_spin_locks); 434 printf("cpu_simple_locks %d\n", dp->cpu_simple_locks); 435 printf("cpu_spin_locks2 %d\n", dp->cpu_spin_locks2); 436 printf("cpu_lkdebug_recurse %d\n", dp->cpu_lkdebug_recurse); 437 printf("cpu_softints %d\n", dp->cpu_softints); 438 printf("cpu_nsyscall %"PRIu64"\n", dp->cpu_nsyscall); 439 printf("cpu_ntrap %"PRIu64"\n", dp->cpu_ntrap); 440 printf("cpu_nfault %"PRIu64"\n", dp->cpu_nfault); 441 printf("cpu_nintr %"PRIu64"\n", dp->cpu_nintr); 442 printf("cpu_nsoft %"PRIu64"\n", dp->cpu_nsoft); 443 printf("cpu_nswtch %"PRIu64"\n", dp->cpu_nswtch); 444 printf("cpu_uvm %p\n", dp->cpu_uvm); 445 printf("cpu_softcpu %p\n", dp->cpu_softcpu); 446 printf("&cpu_biodone %p\n", &dp->cpu_biodone); /* TBD */ 447 printf("&cpu_percpu %p\n", &dp->cpu_percpu); /* TBD */ 448 printf("cpu_selcluster %p\n", dp->cpu_selcluster); 449 printf("cpu_nch %p\n", dp->cpu_nch); 450 printf("&cpu_ld_locks %p\n", &dp->cpu_ld_locks); /* TBD */ 451 printf("&cpu_ld_lock %p\n", &dp->cpu_ld_lock); /* TBD */ 452 printf("cpu_cc_freq %#"PRIx64"\n", dp->cpu_cc_freq); 453 printf("cpu_cc_skew %#"PRIx64"\n", dp->cpu_cc_skew); 454 } 455 456 struct cpu_info * 457 rmixl_cpuinfo_print(u_int cpuindex) 458 { 459 struct cpu_info * const ci = cpu_lookup(cpuindex); 460 461 if (ci != NULL) { 462 rmixl_cpu_data_print(&ci->ci_data); 463 printf("ci_dev %p\n", ci->ci_dev); 464 printf("ci_cpuid %ld\n", ci->ci_cpuid); 465 printf("ci_cctr_freq %ld\n", ci->ci_cctr_freq); 466 printf("ci_cpu_freq %ld\n", ci->ci_cpu_freq); 467 printf("ci_cycles_per_hz %ld\n", ci->ci_cycles_per_hz); 468 printf("ci_divisor_delay %ld\n", ci->ci_divisor_delay); 469 printf("ci_divisor_recip %ld\n", ci->ci_divisor_recip); 470 printf("ci_curlwp %p\n", ci->ci_curlwp); 471 printf("ci_want_resched %d\n", ci->ci_want_resched); 472 printf("ci_mtx_count %d\n", ci->ci_mtx_count); 473 printf("ci_mtx_oldspl %d\n", ci->ci_mtx_oldspl); 474 printf("ci_idepth %d\n", ci->ci_idepth); 475 printf("ci_cpl %d\n", ci->ci_cpl); 476 printf("&ci_cpl %p\n", &ci->ci_cpl); /* XXX */ 477 printf("ci_next_cp0_clk_intr %#x\n", ci->ci_next_cp0_clk_intr); 478 for (int i=0; i < SOFTINT_COUNT; i++) 479 printf("ci_softlwps[%d] %p\n", i, ci->ci_softlwps[i]); 480 printf("ci_tlb_slot %d\n", ci->ci_tlb_slot); 481 printf("ci_pmap_asid_cur %d\n", ci->ci_pmap_asid_cur); 482 printf("ci_tlb_info %p\n", ci->ci_tlb_info); 483 printf("ci_pmap_seg0tab %p\n", ci->ci_pmap_seg0tab); 484 #ifdef _LP64 485 printf("ci_pmap_segtab %p\n", ci->ci_pmap_segtab); 486 #else 487 printf("ci_pmap_srcbase %#"PRIxVADDR"\n", ci->ci_pmap_srcbase); 488 printf("ci_pmap_dstbase %#"PRIxVADDR"\n", ci->ci_pmap_dstbase); 489 #endif 490 #ifdef MULTIPROCESSOR 491 printf("ci_flags %#lx\n", ci->ci_flags); 492 printf("ci_request_ipis %#"PRIx64"\n", ci->ci_request_ipis); 493 printf("ci_active_ipis %#"PRIx64"\n", ci->ci_active_ipis); 494 printf("ci_ksp_tlb_slot %d\n", ci->ci_ksp_tlb_slot); 495 #endif 496 } 497 498 return ci; 499 } 500 #endif /* DEBUG */ 501