1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <sys/types.h> 29 #include <sys/systm.h> 30 #include <sys/archsystm.h> 31 #include <sys/machparam.h> 32 #include <sys/machsystm.h> 33 #include <sys/cpu.h> 34 #include <sys/elf_SPARC.h> 35 #include <vm/hat_sfmmu.h> 36 #include <vm/page.h> 37 #include <sys/cpuvar.h> 38 #include <sys/async.h> 39 #include <sys/cmn_err.h> 40 #include <sys/debug.h> 41 #include <sys/dditypes.h> 42 #include <sys/sunddi.h> 43 #include <sys/cpu_module.h> 44 #include <sys/prom_debug.h> 45 #include <sys/vmsystm.h> 46 #include <sys/prom_plat.h> 47 #include <sys/sysmacros.h> 48 #include <sys/intreg.h> 49 #include <sys/machtrap.h> 50 #include <sys/ontrap.h> 51 #include <sys/ivintr.h> 52 #include <sys/atomic.h> 53 #include <sys/panic.h> 54 #include <sys/dtrace.h> 55 #include <sys/simulate.h> 56 #include <sys/fault.h> 57 #include <sys/niagararegs.h> 58 #include <sys/trapstat.h> 59 #include <sys/hsvc.h> 60 61 #define NI_MMU_PAGESIZE_MASK ((1 << TTE8K) | (1 << TTE64K) | (1 << TTE4M) \ 62 | (1 << TTE256M)) 63 64 uint_t root_phys_addr_lo_mask = 0xffffffffU; 65 static niagara_mmustat_t *cpu_tstat_va; /* VA of mmustat buffer */ 66 static uint64_t cpu_tstat_pa; /* PA of mmustat buffer */ 67 char cpu_module_name[] = "SUNW,UltraSPARC-T1"; 68 69 /* 70 * Hypervisor services information for the NIAGARA CPU module 71 */ 72 static boolean_t niagara_hsvc_available = B_TRUE; 73 static uint64_t niagara_sup_minor; /* Supported minor number */ 74 static hsvc_info_t niagara_hsvc = { 75 HSVC_REV_1, NULL, HSVC_GROUP_NIAGARA_CPU, 1, 0, cpu_module_name 76 }; 77 78 void 79 cpu_setup(void) 80 { 81 extern int mmu_exported_pagesize_mask; 82 extern int cpc_has_overflow_intr; 83 int status; 84 char *ni_isa_set[] = { 85 "sparcv9+vis", 86 "sparcv9+vis2", 87 "sparcv8plus+vis", 88 "sparcv8plus+vis2", 89 NULL 90 }; 91 92 /* 93 * Negotiate the API version for Niagara specific hypervisor 94 * services. 95 */ 96 status = hsvc_register(&niagara_hsvc, &niagara_sup_minor); 97 if (status != 0) { 98 cmn_err(CE_WARN, "%s: cannot negotiate hypervisor services " 99 "group: 0x%lx major: 0x%lx minor: 0x%lx errno: %d\n", 100 niagara_hsvc.hsvc_modname, niagara_hsvc.hsvc_group, 101 niagara_hsvc.hsvc_major, niagara_hsvc.hsvc_minor, status); 102 niagara_hsvc_available = B_FALSE; 103 } 104 105 /* 106 * The setup common to all CPU modules is done in cpu_setup_common 107 * routine. 108 */ 109 cpu_setup_common(ni_isa_set); 110 111 cache |= (CACHE_PTAG | CACHE_IOCOHERENT); 112 113 if (broken_md_flag) { 114 /* 115 * Turn on the missing bits supported by Niagara CPU in 116 * MMU pagesize mask returned by MD. 117 */ 118 mmu_exported_pagesize_mask |= NI_MMU_PAGESIZE_MASK; 119 } else { 120 if ((mmu_exported_pagesize_mask & 121 DEFAULT_SUN4V_MMU_PAGESIZE_MASK) != 122 DEFAULT_SUN4V_MMU_PAGESIZE_MASK) 123 cmn_err(CE_PANIC, "machine description" 124 " does not have required sun4v page sizes" 125 " 8K, 64K and 4M: MD mask is 0x%x", 126 mmu_exported_pagesize_mask); 127 } 128 129 cpu_hwcap_flags |= AV_SPARC_ASI_BLK_INIT; 130 131 /* 132 * Niagara supports a 48-bit subset of the full 64-bit virtual 133 * address space. Virtual addresses between 0x0000800000000000 134 * and 0xffff.7fff.ffff.ffff inclusive lie within a "VA Hole" 135 * and must never be mapped. In addition, software must not use 136 * pages within 4GB of the VA hole as instruction pages to 137 * avoid problems with prefetching into the VA hole. 138 */ 139 hole_start = (caddr_t)((1ull << (va_bits - 1)) - (1ull << 32)); 140 hole_end = (caddr_t)((0ull - (1ull << (va_bits - 1))) + (1ull << 32)); 141 142 /* 143 * Niagara has a performance counter overflow interrupt 144 */ 145 cpc_has_overflow_intr = 1; 146 } 147 148 #define MB(n) ((n) * 1024 * 1024) 149 /* 150 * Set the magic constants of the implementation. 151 */ 152 void 153 cpu_fiximp(struct cpu_node *cpunode) 154 { 155 /* 156 * The Cache node is optional in MD. Therefore in case "Cache" 157 * node does not exists in MD, set the default L2 cache associativity, 158 * size, linesize. 159 */ 160 if (cpunode->ecache_size == 0) 161 cpunode->ecache_size = MB(3); 162 if (cpunode->ecache_linesize == 0) 163 cpunode->ecache_linesize = 64; 164 if (cpunode->ecache_associativity == 0) 165 cpunode->ecache_associativity = 12; 166 } 167 168 static int niagara_cpucnt; 169 170 void 171 cpu_init_private(struct cpu *cp) 172 { 173 extern int niagara_kstat_init(void); 174 175 /* 176 * The cpu_ipipe and cpu_fpu fields are initialized based on 177 * the execution unit sharing information from the MD. They default 178 * to the virtual CPU id in the absence of such information. 179 */ 180 cp->cpu_m.cpu_ipipe = cpunodes[cp->cpu_id].exec_unit_mapping; 181 if (cp->cpu_m.cpu_ipipe == NO_EU_MAPPING_FOUND) 182 cp->cpu_m.cpu_ipipe = (id_t)(cp->cpu_id); 183 184 cp->cpu_m.cpu_fpu = cpunodes[cp->cpu_id].fpu_mapping; 185 if (cp->cpu_m.cpu_fpu == NO_EU_MAPPING_FOUND) 186 cp->cpu_m.cpu_fpu = (id_t)(cp->cpu_id); 187 188 /* 189 * Niagara defines the the core to be at the ipipe level 190 */ 191 cp->cpu_m.cpu_core = cp->cpu_m.cpu_ipipe; 192 193 ASSERT(MUTEX_HELD(&cpu_lock)); 194 if (niagara_cpucnt++ == 0 && niagara_hsvc_available == B_TRUE) { 195 (void) niagara_kstat_init(); 196 } 197 } 198 199 void 200 cpu_uninit_private(struct cpu *cp) 201 { 202 extern int niagara_kstat_fini(void); 203 204 ASSERT(MUTEX_HELD(&cpu_lock)); 205 if (--niagara_cpucnt == 0 && niagara_hsvc_available == B_TRUE) { 206 (void) niagara_kstat_fini(); 207 } 208 } 209 210 /* 211 * On Niagara, any flush will cause all preceding stores to be 212 * synchronized wrt the i$, regardless of address or ASI. In fact, 213 * the address is ignored, so we always flush address 0. 214 */ 215 void 216 dtrace_flush_sec(uintptr_t addr) 217 { 218 doflush(0); 219 } 220 221 #define IS_FLOAT(i) (((i) & 0x1000000) != 0) 222 #define IS_IBIT_SET(x) (x & 0x2000) 223 #define IS_VIS1(op, op3)(op == 2 && op3 == 0x36) 224 #define IS_PARTIAL_OR_SHORT_FLOAT_LD_ST(op, op3, asi) \ 225 (op == 3 && (op3 == IOP_V8_LDDFA || \ 226 op3 == IOP_V8_STDFA) && asi > ASI_SNFL) 227 int 228 vis1_partial_support(struct regs *rp, k_siginfo_t *siginfo, uint_t *fault) 229 { 230 char *badaddr; 231 int instr; 232 uint_t optype, op3, asi; 233 uint_t rd, ignor; 234 235 if (!USERMODE(rp->r_tstate)) 236 return (-1); 237 238 instr = fetch_user_instr((caddr_t)rp->r_pc); 239 240 rd = (instr >> 25) & 0x1f; 241 optype = (instr >> 30) & 0x3; 242 op3 = (instr >> 19) & 0x3f; 243 ignor = (instr >> 5) & 0xff; 244 if (IS_IBIT_SET(instr)) { 245 asi = (uint32_t)((rp->r_tstate >> TSTATE_ASI_SHIFT) & 246 TSTATE_ASI_MASK); 247 } else { 248 asi = ignor; 249 } 250 251 if (!IS_VIS1(optype, op3) && 252 !IS_PARTIAL_OR_SHORT_FLOAT_LD_ST(optype, op3, asi)) { 253 return (-1); 254 } 255 switch (simulate_unimp(rp, &badaddr)) { 256 case SIMU_RETRY: 257 break; /* regs are already set up */ 258 /*NOTREACHED*/ 259 260 case SIMU_SUCCESS: 261 /* 262 * skip the successfully 263 * simulated instruction 264 */ 265 rp->r_pc = rp->r_npc; 266 rp->r_npc += 4; 267 break; 268 /*NOTREACHED*/ 269 270 case SIMU_FAULT: 271 siginfo->si_signo = SIGSEGV; 272 siginfo->si_code = SEGV_MAPERR; 273 siginfo->si_addr = badaddr; 274 *fault = FLTBOUNDS; 275 break; 276 277 case SIMU_DZERO: 278 siginfo->si_signo = SIGFPE; 279 siginfo->si_code = FPE_INTDIV; 280 siginfo->si_addr = (caddr_t)rp->r_pc; 281 *fault = FLTIZDIV; 282 break; 283 284 case SIMU_UNALIGN: 285 siginfo->si_signo = SIGBUS; 286 siginfo->si_code = BUS_ADRALN; 287 siginfo->si_addr = badaddr; 288 *fault = FLTACCESS; 289 break; 290 291 case SIMU_ILLEGAL: 292 default: 293 siginfo->si_signo = SIGILL; 294 op3 = (instr >> 19) & 0x3F; 295 if ((IS_FLOAT(instr) && (op3 == IOP_V8_STQFA) || 296 (op3 == IOP_V8_STDFA))) 297 siginfo->si_code = ILL_ILLADR; 298 else 299 siginfo->si_code = ILL_ILLOPC; 300 siginfo->si_addr = (caddr_t)rp->r_pc; 301 *fault = FLTILL; 302 break; 303 } 304 return (0); 305 } 306 307 /* 308 * Trapstat support for Niagara processor 309 */ 310 int 311 cpu_trapstat_conf(int cmd) 312 { 313 size_t len; 314 uint64_t mmustat_pa, hvret; 315 int status = 0; 316 317 if (niagara_hsvc_available == B_FALSE) 318 return (ENOTSUP); 319 320 switch (cmd) { 321 case CPU_TSTATCONF_INIT: 322 ASSERT(cpu_tstat_va == NULL); 323 len = (NCPU+1) * sizeof (niagara_mmustat_t); 324 cpu_tstat_va = contig_mem_alloc_align(len, 325 sizeof (niagara_mmustat_t)); 326 if (cpu_tstat_va == NULL) 327 status = EAGAIN; 328 else { 329 bzero(cpu_tstat_va, len); 330 cpu_tstat_pa = va_to_pa(cpu_tstat_va); 331 } 332 break; 333 334 case CPU_TSTATCONF_FINI: 335 if (cpu_tstat_va) { 336 len = (NCPU+1) * sizeof (niagara_mmustat_t); 337 contig_mem_free(cpu_tstat_va, len); 338 cpu_tstat_va = NULL; 339 cpu_tstat_pa = 0; 340 } 341 break; 342 343 case CPU_TSTATCONF_ENABLE: 344 hvret = hv_niagara_mmustat_conf((cpu_tstat_pa + 345 (CPU->cpu_id+1) * sizeof (niagara_mmustat_t)), 346 (uint64_t *)&mmustat_pa); 347 if (hvret != H_EOK) 348 status = EINVAL; 349 break; 350 351 case CPU_TSTATCONF_DISABLE: 352 hvret = hv_niagara_mmustat_conf(0, (uint64_t *)&mmustat_pa); 353 if (hvret != H_EOK) 354 status = EINVAL; 355 break; 356 357 default: 358 status = EINVAL; 359 break; 360 } 361 return (status); 362 } 363 364 void 365 cpu_trapstat_data(void *buf, uint_t tstat_pgszs) 366 { 367 niagara_mmustat_t *mmustatp; 368 tstat_pgszdata_t *tstatp = (tstat_pgszdata_t *)buf; 369 int i, pgcnt; 370 371 if (cpu_tstat_va == NULL) 372 return; 373 374 mmustatp = &((niagara_mmustat_t *)cpu_tstat_va)[CPU->cpu_id+1]; 375 if (tstat_pgszs > NIAGARA_MMUSTAT_PGSZS) 376 tstat_pgszs = NIAGARA_MMUSTAT_PGSZS; 377 378 for (i = 0; i < tstat_pgszs; i++, tstatp++) { 379 tstatp->tpgsz_kernel.tmode_itlb.ttlb_tlb.tmiss_count = 380 mmustatp->kitsb[i].tsbhit_count; 381 tstatp->tpgsz_kernel.tmode_itlb.ttlb_tlb.tmiss_time = 382 mmustatp->kitsb[i].tsbhit_time; 383 tstatp->tpgsz_user.tmode_itlb.ttlb_tlb.tmiss_count = 384 mmustatp->uitsb[i].tsbhit_count; 385 tstatp->tpgsz_user.tmode_itlb.ttlb_tlb.tmiss_time = 386 mmustatp->uitsb[i].tsbhit_time; 387 tstatp->tpgsz_kernel.tmode_dtlb.ttlb_tlb.tmiss_count = 388 mmustatp->kdtsb[i].tsbhit_count; 389 tstatp->tpgsz_kernel.tmode_dtlb.ttlb_tlb.tmiss_time = 390 mmustatp->kdtsb[i].tsbhit_time; 391 tstatp->tpgsz_user.tmode_dtlb.ttlb_tlb.tmiss_count = 392 mmustatp->udtsb[i].tsbhit_count; 393 tstatp->tpgsz_user.tmode_dtlb.ttlb_tlb.tmiss_time = 394 mmustatp->udtsb[i].tsbhit_time; 395 } 396 } 397