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 2006 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 field is initialized based on the execution 177 * unit sharing information from the MD. It defaults to the 178 * 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 ASSERT(MUTEX_HELD(&cpu_lock)); 185 if (niagara_cpucnt++ == 0 && niagara_hsvc_available == B_TRUE) { 186 (void) niagara_kstat_init(); 187 } 188 } 189 190 void 191 cpu_uninit_private(struct cpu *cp) 192 { 193 extern int niagara_kstat_fini(void); 194 195 ASSERT(MUTEX_HELD(&cpu_lock)); 196 if (--niagara_cpucnt == 0 && niagara_hsvc_available == B_TRUE) { 197 (void) niagara_kstat_fini(); 198 } 199 } 200 201 /* 202 * On Niagara, any flush will cause all preceding stores to be 203 * synchronized wrt the i$, regardless of address or ASI. In fact, 204 * the address is ignored, so we always flush address 0. 205 */ 206 void 207 dtrace_flush_sec(uintptr_t addr) 208 { 209 doflush(0); 210 } 211 212 #define IS_FLOAT(i) (((i) & 0x1000000) != 0) 213 #define IS_IBIT_SET(x) (x & 0x2000) 214 #define IS_VIS1(op, op3)(op == 2 && op3 == 0x36) 215 #define IS_PARTIAL_OR_SHORT_FLOAT_LD_ST(op, op3, asi) \ 216 (op == 3 && (op3 == IOP_V8_LDDFA || \ 217 op3 == IOP_V8_STDFA) && asi > ASI_SNFL) 218 int 219 vis1_partial_support(struct regs *rp, k_siginfo_t *siginfo, uint_t *fault) 220 { 221 char *badaddr; 222 int instr; 223 uint_t optype, op3, asi; 224 uint_t rd, ignor; 225 226 if (!USERMODE(rp->r_tstate)) 227 return (-1); 228 229 instr = fetch_user_instr((caddr_t)rp->r_pc); 230 231 rd = (instr >> 25) & 0x1f; 232 optype = (instr >> 30) & 0x3; 233 op3 = (instr >> 19) & 0x3f; 234 ignor = (instr >> 5) & 0xff; 235 if (IS_IBIT_SET(instr)) { 236 asi = (uint32_t)((rp->r_tstate >> TSTATE_ASI_SHIFT) & 237 TSTATE_ASI_MASK); 238 } else { 239 asi = ignor; 240 } 241 242 if (!IS_VIS1(optype, op3) && 243 !IS_PARTIAL_OR_SHORT_FLOAT_LD_ST(optype, op3, asi)) { 244 return (-1); 245 } 246 switch (simulate_unimp(rp, &badaddr)) { 247 case SIMU_RETRY: 248 break; /* regs are already set up */ 249 /*NOTREACHED*/ 250 251 case SIMU_SUCCESS: 252 /* 253 * skip the successfully 254 * simulated instruction 255 */ 256 rp->r_pc = rp->r_npc; 257 rp->r_npc += 4; 258 break; 259 /*NOTREACHED*/ 260 261 case SIMU_FAULT: 262 siginfo->si_signo = SIGSEGV; 263 siginfo->si_code = SEGV_MAPERR; 264 siginfo->si_addr = badaddr; 265 *fault = FLTBOUNDS; 266 break; 267 268 case SIMU_DZERO: 269 siginfo->si_signo = SIGFPE; 270 siginfo->si_code = FPE_INTDIV; 271 siginfo->si_addr = (caddr_t)rp->r_pc; 272 *fault = FLTIZDIV; 273 break; 274 275 case SIMU_UNALIGN: 276 siginfo->si_signo = SIGBUS; 277 siginfo->si_code = BUS_ADRALN; 278 siginfo->si_addr = badaddr; 279 *fault = FLTACCESS; 280 break; 281 282 case SIMU_ILLEGAL: 283 default: 284 siginfo->si_signo = SIGILL; 285 op3 = (instr >> 19) & 0x3F; 286 if ((IS_FLOAT(instr) && (op3 == IOP_V8_STQFA) || 287 (op3 == IOP_V8_STDFA))) 288 siginfo->si_code = ILL_ILLADR; 289 else 290 siginfo->si_code = ILL_ILLOPC; 291 siginfo->si_addr = (caddr_t)rp->r_pc; 292 *fault = FLTILL; 293 break; 294 } 295 return (0); 296 } 297 298 /* 299 * Trapstat support for Niagara processor 300 */ 301 int 302 cpu_trapstat_conf(int cmd) 303 { 304 size_t len; 305 uint64_t mmustat_pa, hvret; 306 int status = 0; 307 308 if (niagara_hsvc_available == B_FALSE) 309 return (ENOTSUP); 310 311 switch (cmd) { 312 case CPU_TSTATCONF_INIT: 313 ASSERT(cpu_tstat_va == NULL); 314 len = (NCPU+1) * sizeof (niagara_mmustat_t); 315 cpu_tstat_va = contig_mem_alloc_align(len, 316 sizeof (niagara_mmustat_t)); 317 if (cpu_tstat_va == NULL) 318 status = EAGAIN; 319 else { 320 bzero(cpu_tstat_va, len); 321 cpu_tstat_pa = va_to_pa(cpu_tstat_va); 322 } 323 break; 324 325 case CPU_TSTATCONF_FINI: 326 if (cpu_tstat_va) { 327 len = (NCPU+1) * sizeof (niagara_mmustat_t); 328 contig_mem_free(cpu_tstat_va, len); 329 cpu_tstat_va = NULL; 330 cpu_tstat_pa = 0; 331 } 332 break; 333 334 case CPU_TSTATCONF_ENABLE: 335 hvret = hv_niagara_mmustat_conf((cpu_tstat_pa + 336 (CPU->cpu_id+1) * sizeof (niagara_mmustat_t)), 337 (uint64_t *)&mmustat_pa); 338 if (hvret != H_EOK) 339 status = EINVAL; 340 break; 341 342 case CPU_TSTATCONF_DISABLE: 343 hvret = hv_niagara_mmustat_conf(0, (uint64_t *)&mmustat_pa); 344 if (hvret != H_EOK) 345 status = EINVAL; 346 break; 347 348 default: 349 status = EINVAL; 350 break; 351 } 352 return (status); 353 } 354 355 void 356 cpu_trapstat_data(void *buf, uint_t tstat_pgszs) 357 { 358 niagara_mmustat_t *mmustatp; 359 tstat_pgszdata_t *tstatp = (tstat_pgszdata_t *)buf; 360 int i, pgcnt; 361 362 if (cpu_tstat_va == NULL) 363 return; 364 365 mmustatp = &((niagara_mmustat_t *)cpu_tstat_va)[CPU->cpu_id+1]; 366 if (tstat_pgszs > NIAGARA_MMUSTAT_PGSZS) 367 tstat_pgszs = NIAGARA_MMUSTAT_PGSZS; 368 369 for (i = 0; i < tstat_pgszs; i++, tstatp++) { 370 tstatp->tpgsz_kernel.tmode_itlb.ttlb_tlb.tmiss_count = 371 mmustatp->kitsb[i].tsbhit_count; 372 tstatp->tpgsz_kernel.tmode_itlb.ttlb_tlb.tmiss_time = 373 mmustatp->kitsb[i].tsbhit_time; 374 tstatp->tpgsz_user.tmode_itlb.ttlb_tlb.tmiss_count = 375 mmustatp->uitsb[i].tsbhit_count; 376 tstatp->tpgsz_user.tmode_itlb.ttlb_tlb.tmiss_time = 377 mmustatp->uitsb[i].tsbhit_time; 378 tstatp->tpgsz_kernel.tmode_dtlb.ttlb_tlb.tmiss_count = 379 mmustatp->kdtsb[i].tsbhit_count; 380 tstatp->tpgsz_kernel.tmode_dtlb.ttlb_tlb.tmiss_time = 381 mmustatp->kdtsb[i].tsbhit_time; 382 tstatp->tpgsz_user.tmode_dtlb.ttlb_tlb.tmiss_count = 383 mmustatp->udtsb[i].tsbhit_count; 384 tstatp->tpgsz_user.tmode_dtlb.ttlb_tlb.tmiss_time = 385 mmustatp->udtsb[i].tsbhit_time; 386 } 387 } 388