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