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/machsystm.h> 29 #include <sys/archsystm.h> 30 #include <sys/prom_plat.h> 31 #include <sys/promif.h> 32 #include <sys/vm.h> 33 #include <sys/cpu.h> 34 #include <sys/atomic.h> 35 #include <sys/cpupart.h> 36 #include <sys/disp.h> 37 #include <sys/hypervisor_api.h> 38 #include <sys/traptrace.h> 39 40 #ifdef TRAPTRACE 41 int mach_htraptrace_enable = 1; 42 #else 43 int mach_htraptrace_enable = 0; 44 #endif 45 int htrap_tr0_inuse = 0; 46 extern char htrap_tr0[]; /* prealloc buf for boot cpu */ 47 48 caddr_t mmu_fault_status_area; 49 50 extern void sfmmu_set_tsbs(void); 51 /* 52 * CPU IDLE optimization variables/routines 53 */ 54 static int enable_halt_idle_cpus = 1; 55 56 void 57 setup_trap_table(void) 58 { 59 caddr_t mmfsa_va; 60 extern caddr_t mmu_fault_status_area; 61 mmfsa_va = 62 mmu_fault_status_area + (MMFSA_SIZE * CPU->cpu_id); 63 64 intr_init(CPU); /* init interrupt request free list */ 65 setwstate(WSTATE_KERN); 66 set_mmfsa_scratchpad(mmfsa_va); 67 prom_set_mmfsa_traptable(&trap_table, va_to_pa(mmfsa_va)); 68 sfmmu_set_tsbs(); 69 } 70 71 void 72 phys_install_has_changed(void) 73 { 74 75 } 76 77 /* 78 * Halt the present CPU until awoken via an interrupt 79 */ 80 static void 81 cpu_halt(void) 82 { 83 cpu_t *cpup = CPU; 84 processorid_t cpun = cpup->cpu_id; 85 cpupart_t *cp = cpup->cpu_part; 86 int hset_update = 1; 87 uint_t s; 88 89 /* 90 * If this CPU is online, and there's multiple CPUs 91 * in the system, then we should notate our halting 92 * by adding ourselves to the partition's halted CPU 93 * bitmap. This allows other CPUs to find/awaken us when 94 * work becomes available. 95 */ 96 if (CPU->cpu_flags & CPU_OFFLINE || ncpus == 1) 97 hset_update = 0; 98 99 /* 100 * Add ourselves to the partition's halted CPUs bitmask 101 * and set our HALTED flag, if necessary. 102 * 103 * When a thread becomes runnable, it is placed on the queue 104 * and then the halted cpuset is checked to determine who 105 * (if anyone) should be awoken. We therefore need to first 106 * add ourselves to the halted cpuset, and then check if there 107 * is any work available. 108 */ 109 if (hset_update) { 110 cpup->cpu_disp_flags |= CPU_DISP_HALTED; 111 membar_producer(); 112 CPUSET_ATOMIC_ADD(cp->cp_haltset, cpun); 113 } 114 115 /* 116 * Check to make sure there's really nothing to do. 117 * Work destined for this CPU may become available after 118 * this check. We'll be notified through the clearing of our 119 * bit in the halted CPU bitmask, and a poke. 120 */ 121 if (disp_anywork()) { 122 if (hset_update) { 123 cpup->cpu_disp_flags &= ~CPU_DISP_HALTED; 124 CPUSET_ATOMIC_DEL(cp->cp_haltset, cpun); 125 } 126 return; 127 } 128 129 /* 130 * We're on our way to being halted. 131 * 132 * Disable interrupts now, so that we'll awaken immediately 133 * after halting if someone tries to poke us between now and 134 * the time we actually halt. 135 * 136 * We check for the presence of our bit after disabling interrupts. 137 * If it's cleared, we'll return. If the bit is cleared after 138 * we check then the poke will pop us out of the halted state. 139 * 140 * The ordering of the poke and the clearing of the bit by cpu_wakeup 141 * is important. 142 * cpu_wakeup() must clear, then poke. 143 * cpu_halt() must disable interrupts, then check for the bit. 144 */ 145 s = disable_vec_intr(); 146 147 if (hset_update && !CPU_IN_SET(cp->cp_haltset, cpun)) { 148 cpup->cpu_disp_flags &= ~CPU_DISP_HALTED; 149 enable_vec_intr(s); 150 return; 151 } 152 153 /* 154 * The check for anything locally runnable is here for performance 155 * and isn't needed for correctness. disp_nrunnable ought to be 156 * in our cache still, so it's inexpensive to check, and if there 157 * is anything runnable we won't have to wait for the poke. 158 */ 159 if (cpup->cpu_disp->disp_nrunnable != 0) { 160 if (hset_update) { 161 cpup->cpu_disp_flags &= ~CPU_DISP_HALTED; 162 CPUSET_ATOMIC_DEL(cp->cp_haltset, cpun); 163 } 164 enable_vec_intr(s); 165 return; 166 } 167 168 /* 169 * Halt the strand 170 */ 171 (void) hv_cpu_yield(); 172 173 /* 174 * We're no longer halted 175 */ 176 enable_vec_intr(s); 177 if (hset_update) { 178 cpup->cpu_disp_flags &= ~CPU_DISP_HALTED; 179 CPUSET_ATOMIC_DEL(cp->cp_haltset, cpun); 180 } 181 } 182 183 /* 184 * If "cpu" is halted, then wake it up clearing its halted bit in advance. 185 * Otherwise, see if other CPUs in the cpu partition are halted and need to 186 * be woken up so that they can steal the thread we placed on this CPU. 187 * This function is only used on MP systems. 188 */ 189 static void 190 cpu_wakeup(cpu_t *cpu, int bound) 191 { 192 uint_t cpu_found; 193 int result; 194 cpupart_t *cp; 195 196 cp = cpu->cpu_part; 197 if (CPU_IN_SET(cp->cp_haltset, cpu->cpu_id)) { 198 /* 199 * Clear the halted bit for that CPU since it will be 200 * poked in a moment. 201 */ 202 CPUSET_ATOMIC_DEL(cp->cp_haltset, cpu->cpu_id); 203 /* 204 * We may find the current CPU present in the halted cpuset 205 * if we're in the context of an interrupt that occurred 206 * before we had a chance to clear our bit in cpu_halt(). 207 * Poking ourself is obviously unnecessary, since if 208 * we're here, we're not halted. 209 */ 210 if (cpu != CPU) 211 poke_cpu(cpu->cpu_id); 212 return; 213 } else { 214 /* 215 * This cpu isn't halted, but it's idle or undergoing a 216 * context switch. No need to awaken anyone else. 217 */ 218 if (cpu->cpu_thread == cpu->cpu_idle_thread || 219 cpu->cpu_disp_flags & CPU_DISP_DONTSTEAL) 220 return; 221 } 222 223 /* 224 * No need to wake up other CPUs if the thread we just enqueued 225 * is bound. 226 */ 227 if (bound) 228 return; 229 230 /* 231 * See if there's any other halted CPUs. If there are, then 232 * select one, and awaken it. 233 * It's possible that after we find a CPU, somebody else 234 * will awaken it before we get the chance. 235 * In that case, look again. 236 */ 237 do { 238 CPUSET_FIND(cp->cp_haltset, cpu_found); 239 if (cpu_found == CPUSET_NOTINSET) 240 return; 241 242 ASSERT(cpu_found >= 0 && cpu_found < NCPU); 243 CPUSET_ATOMIC_XDEL(cp->cp_haltset, cpu_found, result); 244 } while (result < 0); 245 246 if (cpu_found != CPU->cpu_id) 247 poke_cpu(cpu_found); 248 } 249 250 void 251 mach_cpu_halt_idle() 252 { 253 if (enable_halt_idle_cpus) { 254 idle_cpu = cpu_halt; 255 disp_enq_thread = cpu_wakeup; 256 } 257 } 258 259 int 260 ndata_alloc_mmfsa(struct memlist *ndata) 261 { 262 size_t size; 263 264 size = MMFSA_SIZE * max_ncpus; 265 mmu_fault_status_area = ndata_alloc(ndata, size, ecache_alignsize); 266 if (mmu_fault_status_area == NULL) 267 return (-1); 268 return (0); 269 } 270 271 void 272 mach_memscrub(void) 273 { 274 /* no memscrub support for sun4v for now */ 275 } 276 277 void 278 mach_fpras() 279 { 280 /* no fpras support for sun4v for now */ 281 } 282 283 void 284 mach_hw_copy_limit(void) 285 { 286 /* HW copy limits set by individual CPU module */ 287 } 288 289 /* 290 * We need to enable soft ring functionality on Niagara platform since 291 * one strand can't handle interrupts for a 1Gb NIC. Set the tunable 292 * ip_squeue_soft_ring by default on this platform. We can also set 293 * ip_threads_per_cpu to track number of threads per core. The variables 294 * themselves are defined in space.c and used by IP module 295 */ 296 extern uint_t ip_threads_per_cpu; 297 extern boolean_t ip_squeue_soft_ring; 298 void 299 startup_platform(void) 300 { 301 ip_squeue_soft_ring = B_TRUE; 302 } 303 304 /* 305 * This function sets up hypervisor traptrace buffer 306 * This routine is called by the boot cpu only 307 */ 308 void 309 mach_htraptrace_setup(int cpuid) 310 { 311 TRAP_TRACE_CTL *ctlp; 312 int bootcpuid = getprocessorid(); /* invoked on boot cpu only */ 313 314 if (mach_htraptrace_enable && ((cpuid != bootcpuid) || 315 !htrap_tr0_inuse)) { 316 ctlp = &trap_trace_ctl[cpuid]; 317 ctlp->d.hvaddr_base = (cpuid == bootcpuid) ? htrap_tr0 : 318 contig_mem_alloc_align(HTRAP_TSIZE, HTRAP_TSIZE); 319 if (ctlp->d.hvaddr_base == NULL) { 320 ctlp->d.hlimit = 0; 321 ctlp->d.hpaddr_base = NULL; 322 cmn_err(CE_WARN, "!cpu%d: failed to allocate HV " 323 "traptrace buffer", cpuid); 324 } else { 325 ctlp->d.hlimit = HTRAP_TSIZE; 326 ctlp->d.hpaddr_base = va_to_pa(ctlp->d.hvaddr_base); 327 } 328 } 329 } 330 331 /* 332 * This function enables or disables the hypervisor traptracing 333 */ 334 void 335 mach_htraptrace_configure(int cpuid) 336 { 337 uint64_t ret; 338 uint64_t prev_buf, prev_bufsize; 339 uint64_t prev_enable; 340 uint64_t size; 341 TRAP_TRACE_CTL *ctlp; 342 343 ctlp = &trap_trace_ctl[cpuid]; 344 if (mach_htraptrace_enable) { 345 if ((ctlp->d.hvaddr_base != NULL) && 346 ((ctlp->d.hvaddr_base != htrap_tr0) || 347 (!htrap_tr0_inuse))) { 348 ret = hv_ttrace_buf_info(&prev_buf, &prev_bufsize); 349 if ((ret == H_EOK) && (prev_bufsize != 0)) { 350 cmn_err(CE_CONT, 351 "!cpu%d: previous HV traptrace buffer of " 352 "size 0x%lx at address 0x%lx", cpuid, 353 prev_bufsize, prev_buf); 354 } 355 356 ret = hv_ttrace_buf_conf(ctlp->d.hpaddr_base, 357 ctlp->d.hlimit / 358 (sizeof (struct htrap_trace_record)), &size); 359 if (ret == H_EOK) { 360 ret = hv_ttrace_enable(\ 361 (uint64_t)TRAP_TENABLE_ALL, &prev_enable); 362 if (ret != H_EOK) { 363 cmn_err(CE_WARN, 364 "!cpu%d: HV traptracing not " 365 "enabled, ta: 0x%x returned error: " 366 "%ld", cpuid, TTRACE_ENABLE, ret); 367 } else { 368 if (ctlp->d.hvaddr_base == htrap_tr0) 369 htrap_tr0_inuse = 1; 370 } 371 } else { 372 cmn_err(CE_WARN, 373 "!cpu%d: HV traptrace buffer not " 374 "configured, ta: 0x%x returned error: %ld", 375 cpuid, TTRACE_BUF_CONF, ret); 376 } 377 /* 378 * set hvaddr_base to NULL when traptrace buffer 379 * registration fails 380 */ 381 if (ret != H_EOK) { 382 ctlp->d.hvaddr_base = NULL; 383 ctlp->d.hlimit = 0; 384 ctlp->d.hpaddr_base = NULL; 385 } 386 } 387 } else { 388 ret = hv_ttrace_buf_info(&prev_buf, &prev_bufsize); 389 if ((ret == H_EOK) && (prev_bufsize != 0)) { 390 ret = hv_ttrace_enable((uint64_t)TRAP_TDISABLE_ALL, 391 &prev_enable); 392 if (ret == H_EOK) { 393 if (ctlp->d.hvaddr_base == htrap_tr0) 394 htrap_tr0_inuse = 0; 395 ctlp->d.hvaddr_base = NULL; 396 ctlp->d.hlimit = 0; 397 ctlp->d.hpaddr_base = NULL; 398 } else 399 cmn_err(CE_WARN, 400 "!cpu%d: HV traptracing is not disabled, " 401 "ta: 0x%x returned error: %ld", 402 cpuid, TTRACE_ENABLE, ret); 403 } 404 } 405 } 406 407 /* 408 * This function cleans up the hypervisor traptrace buffer 409 */ 410 void 411 mach_htraptrace_cleanup(int cpuid) 412 { 413 if (mach_htraptrace_enable) { 414 TRAP_TRACE_CTL *ctlp; 415 caddr_t httrace_buf_va; 416 417 ASSERT(cpuid < max_ncpus); 418 ctlp = &trap_trace_ctl[cpuid]; 419 httrace_buf_va = ctlp->d.hvaddr_base; 420 if (httrace_buf_va == htrap_tr0) { 421 bzero(httrace_buf_va, HTRAP_TSIZE); 422 } else if (httrace_buf_va != NULL) { 423 contig_mem_free(httrace_buf_va, HTRAP_TSIZE); 424 } 425 ctlp->d.hvaddr_base = NULL; 426 ctlp->d.hlimit = 0; 427 ctlp->d.hpaddr_base = NULL; 428 } 429 } 430