/* * Flush pte on all active processors. */ void smp_tlb_flush_pte(vaddr_t va, struct pmap * pm) { sparc64_cpuset_t cpuset; struct cpu_info *ci; int ctx; bool kpm = (pm == pmap_kernel()); /* Flush our own TLB */ ctx = pm->pm_ctx[cpu_number()]; KASSERT(ctx >= 0); if (kpm || ctx > 0) sp_tlb_flush_pte(va, ctx); CPUSET_ASSIGN(cpuset, cpus_active); CPUSET_DEL(cpuset, cpu_number()); if (CPUSET_EMPTY(cpuset)) return; /* Flush others */ for (ci = cpus; ci != NULL; ci = ci->ci_next) { if (CPUSET_HAS(cpuset, ci->ci_index)) { CPUSET_DEL(cpuset, ci->ci_index); ctx = pm->pm_ctx[ci->ci_index]; KASSERT(ctx >= 0); if (!kpm && ctx == 0) continue; sparc64_send_ipi(ci->ci_cpuid, smp_tlb_flush_pte_func, va, ctx); } } }
/* * Resume all paused cpus. */ void cpu_resume_others(void) { __cpuset_t cpuset; CPUSET_CLEAR(cpus_resumed); CPUSET_ASSIGN(cpuset, cpus_paused); CPUSET_CLEAR(cpus_paused); /* CPUs awake on cpus_paused clear */ if (cpu_ipi_wait(&cpus_resumed, cpuset)) cpu_ipi_error("resume", cpus_resumed, cpuset); }
/* * Halt all cpus but ourselves. */ void mp_halt_cpus(void) { sparc64_cpuset_t cpumask, cpuset; struct cpu_info *ci; CPUSET_ASSIGN(cpuset, cpus_active); CPUSET_DEL(cpuset, cpu_number()); CPUSET_ASSIGN(cpumask, cpuset); CPUSET_SUB(cpuset, cpus_halted); if (CPUSET_EMPTY(cpuset)) return; CPUSET_CLEAR(cpus_spinning); sparc64_multicast_ipi(cpuset, sparc64_ipi_halt, 0, 0); if (sparc64_ipi_wait(&cpus_halted, cpumask)) sparc64_ipi_error("halt", cpumask, cpus_halted); /* * Depending on available firmware methods, other cpus will * either shut down themselfs, or spin and wait for us to * stop them. */ if (CPUSET_EMPTY(cpus_spinning)) { /* give other cpus a few cycles to actually power down */ delay(10000); return; } /* there are cpus spinning - shut them down if we can */ if (prom_has_stop_other()) { for (ci = cpus; ci != NULL; ci = ci->ci_next) { if (!CPUSET_HAS(cpus_spinning, ci->ci_index)) continue; prom_stop_other(ci->ci_cpuid); } } }
/* * Pause all running cpus, excluding current cpu. */ void cpu_pause_others(void) { __cpuset_t cpuset; CPUSET_ASSIGN(cpuset, cpus_running); CPUSET_DEL(cpuset, cpu_index(curcpu())); if (CPUSET_EMPTY_P(cpuset)) return; cpu_multicast_ipi(cpuset, IPI_SUSPEND); if (cpu_ipi_wait(&cpus_paused, cpuset)) cpu_ipi_error("pause", cpus_paused, cpuset); }
/* * Halt all running cpus, excluding current cpu. */ void cpu_halt_others(void) { __cpuset_t cpumask, cpuset; CPUSET_ASSIGN(cpuset, cpus_running); CPUSET_DEL(cpuset, cpu_index(curcpu())); CPUSET_ASSIGN(cpumask, cpuset); CPUSET_SUB(cpuset, cpus_halted); if (CPUSET_EMPTY_P(cpuset)) return; cpu_multicast_ipi(cpuset, IPI_HALT); if (cpu_ipi_wait(&cpus_halted, cpumask)) cpu_ipi_error("halt", cpumask, cpus_halted); /* * TBD * Depending on available firmware methods, other cpus will * either shut down themselfs, or spin and wait for us to * stop them. */ }
/* * Pause all cpus but ourselves. */ void mp_pause_cpus(void) { int i = 3; sparc64_cpuset_t cpuset; CPUSET_ASSIGN(cpuset, cpus_active); CPUSET_DEL(cpuset, cpu_number()); while (i-- > 0) { if (CPUSET_EMPTY(cpuset)) return; sparc64_multicast_ipi(cpuset, sparc64_ipi_pause, 0, 0); if (!sparc64_ipi_wait(&cpus_paused, cpuset)) return; CPUSET_SUB(cpuset, cpus_paused); } sparc64_ipi_error("pause", cpus_paused, cpuset); }
/* * Resume all paused cpus. */ void mp_resume_cpus(void) { int i = 3; sparc64_cpuset_t cpuset; CPUSET_CLEAR(cpuset); /* XXX: gcc -Wuninitialized */ while (i-- > 0) { CPUSET_CLEAR(cpus_resumed); CPUSET_ASSIGN(cpuset, cpus_paused); membar_Sync(); CPUSET_CLEAR(cpus_paused); /* CPUs awake on cpus_paused clear */ if (!sparc64_ipi_wait(&cpus_resumed, cpuset)) return; } sparc64_ipi_error("resume", cpus_resumed, cpuset); }