mach_cpu_states.c revision a3f75865e789d90ccd8aaa11f12d71a83bf5812e
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers/*
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * CDDL HEADER START
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers *
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * The contents of this file are subject to the terms of the
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * Common Development and Distribution License (the "License").
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * You may not use this file except in compliance with the License.
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers *
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * or http://www.opensolaris.org/os/licensing.
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * See the License for the specific language governing permissions
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * and limitations under the License.
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers *
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * When distributing Covered Code, include this CDDL HEADER in each
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * If applicable, add the following below this CDDL HEADER, with the
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * fields enclosed by brackets "[]" replaced with your own identifying
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * information: Portions Copyright [yyyy] [name of copyright owner]
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers *
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * CDDL HEADER END
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers */
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers/*
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * Use is subject to license terms.
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers */
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers#pragma ident "%Z%%M% %I% %E% SMI"
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers#include <sys/types.h>
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers#include <sys/systm.h>
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers#include <sys/archsystm.h>
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers#include <sys/t_lock.h>
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers#include <sys/uadmin.h>
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers#include <sys/panic.h>
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers#include <sys/reboot.h>
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers#include <sys/autoconf.h>
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers#include <sys/machsystm.h>
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers#include <sys/promif.h>
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers#include <sys/membar.h>
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers#include <vm/hat_sfmmu.h>
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers#include <sys/cpu_module.h>
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers#include <sys/cpu_sgnblk_defs.h>
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers#include <sys/intreg.h>
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers#include <sys/consdev.h>
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers#include <sys/kdi_impl.h>
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers#include <sys/traptrace.h>
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers#include <sys/hypervisor_api.h>
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers#include <sys/vmsystm.h>
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers#include <sys/dtrace.h>
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers#include <sys/xc_impl.h>
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers#include <sys/callb.h>
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers#include <sys/mdesc.h>
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers#include <sys/mach_descrip.h>
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers#include <sys/wdt.h>
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers/*
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * hvdump_buf_va is a pointer to the currently-configured hvdump_buf.
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * A value of NULL indicates that this area is not configured.
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * hvdump_buf_sz is tunable but will be clamped to HVDUMP_SIZE_MAX.
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers */
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowerscaddr_t hvdump_buf_va;
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowersuint64_t hvdump_buf_sz = HVDUMP_SIZE_DEFAULT;
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowersstatic uint64_t hvdump_buf_pa;
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowersu_longlong_t panic_tick;
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowersextern u_longlong_t gettick();
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowersstatic void reboot_machine(char *);
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowersstatic void update_hvdump_buffer(void);
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers/*
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * For xt_sync synchronization.
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers */
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowersextern uint64_t xc_tick_limit;
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowersextern uint64_t xc_tick_jump_limit;
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers/*
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * We keep our own copies, used for cache flushing, because we can be called
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * before cpu_fiximpl().
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers */
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowersstatic int kdi_dcache_size;
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowersstatic int kdi_dcache_linesize;
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowersstatic int kdi_icache_size;
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowersstatic int kdi_icache_linesize;
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers/*
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * Assembly support for generic modules in sun4v/ml/mach_xc.s
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers */
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowersextern void init_mondo_nocheck(xcfunc_t *func, uint64_t arg1, uint64_t arg2);
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowersextern void kdi_flush_idcache(int, int, int, int);
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowersextern uint64_t get_cpuaddr(uint64_t, uint64_t);
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers/*
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * Machine dependent code to reboot.
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * "mdep" is interpreted as a character pointer; if non-null, it is a pointer
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * to a string to be used as the argument string when rebooting.
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers *
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * "invoke_cb" is a boolean. It is set to true when mdboot() can safely
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * invoke CB_CL_MDBOOT callbacks before shutting the system down, i.e. when
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * we are in a normal shutdown sequence (interrupts are not blocked, the
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * system is not panic'ing or being suspended).
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers */
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers/*ARGSUSED*/
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowersvoid
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowersmdboot(int cmd, int fcn, char *bootstr, boolean_t invoke_cb)
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers{
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers extern void pm_cfb_check_and_powerup(void);
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers /*
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * XXX - rconsvp is set to NULL to ensure that output messages
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * are sent to the underlying "hardware" device using the
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * monitor's printf routine since we are in the process of
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * either rebooting or halting the machine.
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers */
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers rconsvp = NULL;
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers /*
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * At a high interrupt level we can't:
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * 1) bring up the console
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * or
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * 2) wait for pending interrupts prior to redistribution
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * to the current CPU
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers *
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * so we do them now.
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers */
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers pm_cfb_check_and_powerup();
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers /* make sure there are no more changes to the device tree */
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers devtree_freeze();
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers if (invoke_cb)
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers (void) callb_execute_class(CB_CL_MDBOOT, NULL);
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers /*
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * Clear any unresolved UEs from memory.
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers */
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers if (memsegs != NULL)
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers page_retire_hunt(page_retire_mdboot_cb);
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers /*
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * stop other cpus which also raise our priority. since there is only
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * one active cpu after this, and our priority will be too high
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * for us to be preempted, we're essentially single threaded
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * from here on out.
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers */
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers stop_other_cpus();
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers /*
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * try and reset leaf devices. reset_leaves() should only
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * be called when there are no other threads that could be
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * accessing devices
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers */
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers reset_leaves();
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers watchdog_clear();
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers if (fcn == AD_HALT) {
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers halt((char *)NULL);
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers } else if (fcn == AD_POWEROFF) {
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers power_down(NULL);
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers } else {
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers if (bootstr == NULL) {
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers switch (fcn) {
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers case AD_BOOT:
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers bootstr = "";
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers break;
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers case AD_IBOOT:
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers bootstr = "-a";
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers break;
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers case AD_SBOOT:
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers bootstr = "-s";
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers break;
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers case AD_SIBOOT:
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers bootstr = "-sa";
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers break;
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers default:
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers cmn_err(CE_WARN,
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers "mdboot: invalid function %d", fcn);
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers bootstr = "";
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers break;
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers }
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers }
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers reboot_machine(bootstr);
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers }
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers /* MAYBE REACHED */
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers}
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers/* mdpreboot - may be called prior to mdboot while root fs still mounted */
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers/*ARGSUSED*/
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowersvoid
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowersmdpreboot(int cmd, int fcn, char *bootstr)
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers{
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers}
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers/*
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * Halt the machine and then reboot with the device
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * and arguments specified in bootstr.
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers */
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowersstatic void
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowersreboot_machine(char *bootstr)
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers{
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers flush_windows();
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers stop_other_cpus(); /* send stop signal to other CPUs */
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers prom_printf("rebooting...\n");
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers /*
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * For platforms that use CPU signatures, we
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * need to set the signature block to OS and
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * the state to exiting for all the processors.
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers */
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers CPU_SIGNATURE(OS_SIG, SIGST_EXIT, SIGSUBST_REBOOT, -1);
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers prom_reboot(bootstr);
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers /*NOTREACHED*/
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers}
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers/*
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * We use the x-trap mechanism and idle_stop_xcall() to stop the other CPUs.
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * Once in panic_idle() they raise spl, record their location, and spin.
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers */
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowersstatic void
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowerspanic_idle(void)
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers{
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers (void) spl7();
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers debug_flush_windows();
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers (void) setjmp(&curthread->t_pcb);
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers CPU->cpu_m.in_prom = 1;
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers membar_stld();
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers for (;;);
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers}
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers/*
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * Force the other CPUs to trap into panic_idle(), and then remove them
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * from the cpu_ready_set so they will no longer receive cross-calls.
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers */
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers/*ARGSUSED*/
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowersvoid
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowerspanic_stopcpus(cpu_t *cp, kthread_t *t, int spl)
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers{
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers cpuset_t cps;
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers int i;
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers (void) splzs();
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers CPUSET_ALL_BUT(cps, cp->cpu_id);
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers xt_some(cps, (xcfunc_t *)idle_stop_xcall, (uint64_t)&panic_idle, NULL);
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers for (i = 0; i < NCPU; i++) {
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers if (i != cp->cpu_id && CPU_XCALL_READY(i)) {
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers int ntries = 0x10000;
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers while (!cpu[i]->cpu_m.in_prom && ntries) {
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers DELAY(50);
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers ntries--;
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers }
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers if (!cpu[i]->cpu_m.in_prom)
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers printf("panic: failed to stop cpu%d\n", i);
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers cpu[i]->cpu_flags &= ~CPU_READY;
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers cpu[i]->cpu_flags |= CPU_QUIESCED;
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers CPUSET_DEL(cpu_ready_set, cpu[i]->cpu_id);
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers }
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers }
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers}
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers/*
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * Platform callback following each entry to panicsys(). If we've panicked at
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * level 14, we examine t_panic_trap to see if a fatal trap occurred. If so,
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * we disable further %tick_cmpr interrupts. If not, an explicit call to panic
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * was made and so we re-enqueue an interrupt request structure to allow
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * further level 14 interrupts to be processed once we lower PIL. This allows
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * us to handle panics from the deadman() CY_HIGH_LEVEL cyclic.
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers */
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowersvoid
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowerspanic_enter_hw(int spl)
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers{
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers if (!panic_tick) {
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers panic_tick = gettick();
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers if (mach_htraptrace_enable) {
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers uint64_t prev_freeze;
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers /* there are no possible error codes for this hcall */
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers (void) hv_ttrace_freeze((uint64_t)TRAP_TFREEZE_ALL,
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers &prev_freeze);
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers }
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers#ifdef TRAPTRACE
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers TRAPTRACE_FREEZE;
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers#endif
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers }
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers if (spl == ipltospl(PIL_14)) {
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers uint_t opstate = disable_vec_intr();
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers if (curthread->t_panic_trap != NULL) {
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers tickcmpr_disable();
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers intr_dequeue_req(PIL_14, cbe_level14_inum);
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers } else {
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers if (!tickcmpr_disabled())
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers intr_enqueue_req(PIL_14, cbe_level14_inum);
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers /*
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * Clear SOFTINT<14>, SOFTINT<0> (TICK_INT)
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * and SOFTINT<16> (STICK_INT) to indicate
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * that the current level 14 has been serviced.
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers */
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers wr_clr_softint((1 << PIL_14) |
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers TICK_INT_MASK | STICK_INT_MASK);
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers }
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers enable_vec_intr(opstate);
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers }
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers}
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers/*
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * Miscellaneous hardware-specific code to execute after panicstr is set
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * by the panic code: we also print and record PTL1 panic information here.
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers */
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers/*ARGSUSED*/
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowersvoid
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowerspanic_quiesce_hw(panic_data_t *pdp)
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers{
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers extern uint_t getpstate(void);
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers extern void setpstate(uint_t);
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers /*
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * Turn off TRAPTRACE and save the current %tick value in panic_tick.
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers */
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers if (!panic_tick) {
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers panic_tick = gettick();
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers if (mach_htraptrace_enable) {
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers uint64_t prev_freeze;
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers /* there are no possible error codes for this hcall */
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers (void) hv_ttrace_freeze((uint64_t)TRAP_TFREEZE_ALL,
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers &prev_freeze);
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers }
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers#ifdef TRAPTRACE
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers TRAPTRACE_FREEZE;
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers#endif
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers }
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers /*
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * For Platforms that use CPU signatures, we
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * need to set the signature block to OS, the state to
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * exiting, and the substate to panic for all the processors.
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers */
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers CPU_SIGNATURE(OS_SIG, SIGST_EXIT, SIGSUBST_PANIC, -1);
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers update_hvdump_buffer();
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers /*
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * Disable further ECC errors from the bus nexus.
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers */
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers (void) bus_func_invoke(BF_TYPE_ERRDIS);
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers /*
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * Redirect all interrupts to the current CPU.
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers */
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers intr_redist_all_cpus_shutdown();
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers /*
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * This call exists solely to support dumps to network
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * devices after sync from OBP.
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers *
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * If we came here via the sync callback, then on some
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * platforms, interrupts may have arrived while we were
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * stopped in OBP. OBP will arrange for those interrupts to
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * be redelivered if you say "go", but not if you invoke a
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * client callback like 'sync'. For some dump devices
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * (network swap devices), we need interrupts to be
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * delivered in order to dump, so we have to call the bus
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * nexus driver to reset the interrupt state machines.
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers */
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers (void) bus_func_invoke(BF_TYPE_RESINTR);
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers setpstate(getpstate() | PSTATE_IE);
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers}
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers/*
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * Platforms that use CPU signatures need to set the signature block to OS and
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * the state to exiting for all CPUs. PANIC_CONT indicates that we're about to
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * write the crash dump, which tells the SSP/SMS to begin a timeout routine to
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * reboot the machine if the dump never completes.
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers */
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers/*ARGSUSED*/
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowersvoid
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowerspanic_dump_hw(int spl)
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers{
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers CPU_SIGNATURE(OS_SIG, SIGST_EXIT, SIGSUBST_DUMP, -1);
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers}
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers/*
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * for ptl1_panic
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers */
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowersvoid
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowersptl1_init_cpu(struct cpu *cpu)
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers{
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers ptl1_state_t *pstate = &cpu->cpu_m.ptl1_state;
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers /*CONSTCOND*/
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers if (sizeof (struct cpu) + PTL1_SSIZE > CPU_ALLOC_SIZE) {
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers panic("ptl1_init_cpu: not enough space left for ptl1_panic "
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers "stack, sizeof (struct cpu) = %lu",
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers (unsigned long)sizeof (struct cpu));
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers }
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers pstate->ptl1_stktop = (uintptr_t)cpu + CPU_ALLOC_SIZE;
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers cpu_pa[cpu->cpu_id] = va_to_pa(cpu);
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers}
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowersvoid
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowersptl1_panic_handler(ptl1_state_t *pstate)
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers{
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers static const char *ptl1_reasons[] = {
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers#ifdef PTL1_PANIC_DEBUG
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers "trap for debug purpose", /* PTL1_BAD_DEBUG */
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers#else
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers "unknown trap", /* PTL1_BAD_DEBUG */
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers#endif
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers "register window trap", /* PTL1_BAD_WTRAP */
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers "kernel MMU miss", /* PTL1_BAD_KMISS */
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers "kernel protection fault", /* PTL1_BAD_KPROT_FAULT */
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers "ISM MMU miss", /* PTL1_BAD_ISM */
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers "kernel MMU trap", /* PTL1_BAD_MMUTRAP */
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers "kernel trap handler state", /* PTL1_BAD_TRAP */
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers "floating point trap", /* PTL1_BAD_FPTRAP */
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers#ifdef DEBUG
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers "pointer to intr_vec", /* PTL1_BAD_INTR_VEC */
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers#else
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers "unknown trap", /* PTL1_BAD_INTR_VEC */
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers#endif
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers#ifdef TRAPTRACE
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers "TRACE_PTR state", /* PTL1_BAD_TRACE_PTR */
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers#else
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers "unknown trap", /* PTL1_BAD_TRACE_PTR */
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers#endif
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers "stack overflow", /* PTL1_BAD_STACK */
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers "DTrace flags", /* PTL1_BAD_DTRACE_FLAGS */
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers "attempt to steal locked ctx", /* PTL1_BAD_CTX_STEAL */
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers "CPU ECC error loop", /* PTL1_BAD_ECC */
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers "unexpected error from hypervisor call", /* PTL1_BAD_HCALL */
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers "unexpected global level(%gl)", /* PTL1_BAD_GL */
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers "Watchdog Reset", /* PTL1_BAD_WATCHDOG */
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers "unexpected RED mode trap", /* PTL1_BAD_RED */
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers "return value EINVAL from hcall: "\
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers "UNMAP_PERM_ADDR", /* PTL1_BAD_HCALL_UNMAP_PERM_EINVAL */
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers "return value ENOMAP from hcall: "\
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers "UNMAP_PERM_ADDR", /* PTL1_BAD_HCALL_UNMAP_PERM_ENOMAP */
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers };
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers uint_t reason = pstate->ptl1_regs.ptl1_gregs[0].ptl1_g1;
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers uint_t tl = pstate->ptl1_regs.ptl1_trap_regs[0].ptl1_tl;
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers struct trap_info ti = { 0 };
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers /*
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * Use trap_info for a place holder to call panic_savetrap() and
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * panic_showtrap() to save and print out ptl1_panic information.
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers */
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers if (curthread->t_panic_trap == NULL)
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers curthread->t_panic_trap = &ti;
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers if (reason < sizeof (ptl1_reasons) / sizeof (ptl1_reasons[0]))
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers panic("bad %s at TL %u", ptl1_reasons[reason], tl);
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers else
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers panic("ptl1_panic reason 0x%x at TL %u", reason, tl);
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers}
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowersvoid
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowersclear_watchdog_on_exit(void)
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers{
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers prom_printf("Debugging requested; hardware watchdog suspended.\n");
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers (void) watchdog_suspend();
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers}
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers/*
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * Restore the watchdog timer when returning from a debugger
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * after a panic or L1-A and resume watchdog pat.
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers */
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowersvoid
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowersrestore_watchdog_on_entry()
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers{
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers watchdog_resume();
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers}
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowersint
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowerskdi_watchdog_disable(void)
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers{
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers watchdog_suspend();
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers return (0);
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers}
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowersvoid
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowerskdi_watchdog_restore(void)
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers{
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers watchdog_resume();
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers}
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowersvoid
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowersmach_dump_buffer_init(void)
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers{
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers uint64_t ret, minsize = 0;
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers if (hvdump_buf_sz > HVDUMP_SIZE_MAX)
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers hvdump_buf_sz = HVDUMP_SIZE_MAX;
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers hvdump_buf_va = contig_mem_alloc_align(hvdump_buf_sz, PAGESIZE);
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers if (hvdump_buf_va == NULL)
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers return;
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers hvdump_buf_pa = va_to_pa(hvdump_buf_va);
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers ret = hv_dump_buf_update(hvdump_buf_pa, hvdump_buf_sz,
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers &minsize);
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers if (ret != H_EOK) {
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers contig_mem_free(hvdump_buf_va, hvdump_buf_sz);
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers hvdump_buf_va = NULL;
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers cmn_err(CE_NOTE, "!Error in setting up hvstate"
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers "dump buffer. Error = 0x%lx, size = 0x%lx,"
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers "buf_pa = 0x%lx", ret, hvdump_buf_sz,
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers hvdump_buf_pa);
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers if (ret == H_EINVAL) {
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers cmn_err(CE_NOTE, "!Buffer size too small."
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers "Available buffer size = 0x%lx,"
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers "Minimum buffer size required = 0x%lx",
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers hvdump_buf_sz, minsize);
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers }
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers }
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers}
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowersstatic void
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowersupdate_hvdump_buffer(void)
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers{
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers uint64_t ret, dummy_val;
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers if (hvdump_buf_va == NULL)
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers return;
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers ret = hv_dump_buf_update(hvdump_buf_pa, hvdump_buf_sz,
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers &dummy_val);
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers if (ret != H_EOK) {
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers cmn_err(CE_NOTE, "!Cannot update hvstate dump"
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers "buffer. Error = 0x%lx", ret);
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers }
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers}
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowersstatic int
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowersgetintprop(pnode_t node, char *name, int deflt)
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers{
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers int value;
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers switch (prom_getproplen(node, name)) {
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers case 0:
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers value = 1; /* boolean properties */
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers break;
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers case sizeof (int):
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers (void) prom_getprop(node, name, (caddr_t)&value);
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers break;
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers default:
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers value = deflt;
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers break;
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers }
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers return (value);
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers}
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers/*
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * Called by setcpudelay
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers */
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowersvoid
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowerscpu_init_tick_freq(void)
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers{
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers md_t *mdp;
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers mde_cookie_t rootnode;
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers int listsz;
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers mde_cookie_t *listp = NULL;
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers int num_nodes;
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers uint64_t stick_prop;
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers if (broken_md_flag) {
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers sys_tick_freq = cpunodes[CPU->cpu_id].clock_freq;
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers return;
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers }
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers if ((mdp = md_get_handle()) == NULL)
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers panic("stick_frequency property not found in MD");
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers rootnode = md_root_node(mdp);
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers ASSERT(rootnode != MDE_INVAL_ELEM_COOKIE);
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers num_nodes = md_node_count(mdp);
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers ASSERT(num_nodes > 0);
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers listsz = num_nodes * sizeof (mde_cookie_t);
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers listp = (mde_cookie_t *)prom_alloc((caddr_t)0, listsz, 0);
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers if (listp == NULL)
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers panic("cannot allocate list for MD properties");
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers num_nodes = md_scan_dag(mdp, rootnode, md_find_name(mdp, "platform"),
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers md_find_name(mdp, "fwd"), listp);
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers ASSERT(num_nodes == 1);
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers if (md_get_prop_val(mdp, *listp, "stick-frequency", &stick_prop) != 0)
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers panic("stick_frequency property not found in MD");
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers sys_tick_freq = stick_prop;
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers prom_free((caddr_t)listp, listsz);
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers (void) md_fini_handle(mdp);
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers}
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowersint shipit(int n, uint64_t cpu_list_ra);
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowersextern uint64_t xc_tick_limit;
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowersextern uint64_t xc_tick_jump_limit;
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers#ifdef DEBUG
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers#define SEND_MONDO_STATS 1
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers#endif
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers#ifdef SEND_MONDO_STATS
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowersuint32_t x_one_stimes[64];
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowersuint32_t x_one_ltimes[16];
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowersuint32_t x_set_stimes[64];
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowersuint32_t x_set_ltimes[16];
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowersuint32_t x_set_cpus[NCPU];
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers#endif
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowersvoid
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowerssend_one_mondo(int cpuid)
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers{
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers int retries, stat;
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers uint64_t starttick, endtick, tick, lasttick;
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers struct machcpu *mcpup = &(CPU->cpu_m);
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers CPU_STATS_ADDQ(CPU, sys, xcalls, 1);
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers starttick = lasttick = gettick();
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers mcpup->cpu_list[0] = (uint16_t)cpuid;
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers stat = shipit(1, mcpup->cpu_list_ra);
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers endtick = starttick + xc_tick_limit;
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers retries = 0;
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers while (stat != H_EOK) {
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers if (stat != H_EWOULDBLOCK) {
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers if (panic_quiesce)
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers return;
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers if (stat == H_ECPUERROR)
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers cmn_err(CE_PANIC, "send_one_mondo: "
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers "cpuid: 0x%x has been marked in "
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers "error", cpuid);
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers else
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers cmn_err(CE_PANIC, "send_one_mondo: "
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers "unexpected hypervisor error 0x%x "
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers "while sending a mondo to cpuid: "
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers "0x%x", stat, cpuid);
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers }
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers tick = gettick();
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers /*
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * If there is a big jump between the current tick
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * count and lasttick, we have probably hit a break
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers * point. Adjust endtick accordingly to avoid panic.
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers */
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers if (tick > (lasttick + xc_tick_jump_limit))
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers endtick += (tick - lasttick);
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers lasttick = tick;
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers if (tick > endtick) {
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers if (panic_quiesce)
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers return;
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers cmn_err(CE_PANIC, "send mondo timeout "
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers "(target 0x%x) [retries: 0x%x hvstat: 0x%x]",
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers cpuid, retries, stat);
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers }
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers drv_usecwait(1);
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers stat = shipit(1, mcpup->cpu_list_ra);
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers retries++;
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers }
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers#ifdef SEND_MONDO_STATS
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers {
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers uint64_t n = gettick() - starttick;
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers if (n < 8192)
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers x_one_stimes[n >> 7]++;
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers else if (n < 15*8192)
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers x_one_ltimes[n >> 13]++;
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers else
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers x_one_ltimes[0xf]++;
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers }
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers#endif
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers}
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowers
f9fbec18f5b458b560ecf45d3db8e8bd56bf6942mcpowersvoid
send_mondo_set(cpuset_t set)
{
uint64_t starttick, endtick, tick, lasttick;
uint_t largestid, smallestid;
int i, j;
int ncpuids = 0;
int shipped = 0;
int retries = 0;
struct machcpu *mcpup = &(CPU->cpu_m);
ASSERT(!CPUSET_ISNULL(set));
CPUSET_BOUNDS(set, smallestid, largestid);
if (smallestid == CPUSET_NOTINSET) {
return;
}
starttick = lasttick = gettick();
endtick = starttick + xc_tick_limit;
/*
* Assemble CPU list for HV argument. We already know
* smallestid and largestid are members of set.
*/
mcpup->cpu_list[ncpuids++] = (uint16_t)smallestid;
if (largestid != smallestid) {
for (i = smallestid+1; i <= largestid-1; i++) {
if (CPU_IN_SET(set, i)) {
mcpup->cpu_list[ncpuids++] = (uint16_t)i;
}
}
mcpup->cpu_list[ncpuids++] = (uint16_t)largestid;
}
do {
int stat;
stat = shipit(ncpuids, mcpup->cpu_list_ra);
if (stat == H_EOK) {
shipped += ncpuids;
break;
}
/*
* Either not all CPU mondos were sent, or an
* error occurred. CPUs that were sent mondos
* have their CPU IDs overwritten in cpu_list.
* Reset cpu_list so that it only holds those
* CPU IDs that still need to be sent.
*/
for (i = 0, j = 0; i < ncpuids; i++) {
if (mcpup->cpu_list[i] == HV_SEND_MONDO_ENTRYDONE) {
shipped++;
} else {
mcpup->cpu_list[j++] = mcpup->cpu_list[i];
}
}
ncpuids = j;
/*
* Now handle possible errors returned
* from hypervisor.
*/
if (stat == H_ECPUERROR) {
int errorcpus;
if (!panic_quiesce)
cmn_err(CE_CONT, "send_mondo_set: cpuid(s) ");
/*
* Remove any CPUs in the error state from
* cpu_list. At this point cpu_list only
* contains the CPU IDs for mondos not
* succesfully sent.
*/
for (i = 0, errorcpus = 0; i < ncpuids; i++) {
uint64_t state = CPU_STATE_INVALID;
uint16_t id = mcpup->cpu_list[i];
(void) hv_cpu_state(id, &state);
if (state == CPU_STATE_ERROR) {
if (!panic_quiesce)
cmn_err(CE_CONT, "0x%x ", id);
errorcpus++;
} else if (errorcpus > 0) {
mcpup->cpu_list[i - errorcpus] =
mcpup->cpu_list[i];
}
}
ncpuids -= errorcpus;
if (!panic_quiesce) {
if (errorcpus == 0) {
cmn_err(CE_CONT, "<none> have been "
"marked in error\n");
cmn_err(CE_PANIC, "send_mondo_set: "
"hypervisor returned "
"H_ECPUERROR but no CPU in "
"cpu_list in error state");
} else {
cmn_err(CE_CONT, "have been marked in "
"error\n");
cmn_err(CE_PANIC, "send_mondo_set: "
"CPU(s) in error state");
}
}
} else if (stat != H_EWOULDBLOCK) {
if (panic_quiesce)
return;
/*
* For all other errors, panic.
*/
cmn_err(CE_CONT, "send_mondo_set: unexpected "
"hypervisor error 0x%x while sending a "
"mondo to cpuid(s):", stat);
for (i = 0; i < ncpuids; i++) {
cmn_err(CE_CONT, " 0x%x", mcpup->cpu_list[i]);
}
cmn_err(CE_CONT, "\n");
cmn_err(CE_PANIC, "send_mondo_set: unexpected "
"hypervisor error");
}
tick = gettick();
/*
* If there is a big jump between the current tick
* count and lasttick, we have probably hit a break
* point. Adjust endtick accordingly to avoid panic.
*/
if (tick > (lasttick + xc_tick_jump_limit))
endtick += (tick - lasttick);
lasttick = tick;
if (tick > endtick) {
if (panic_quiesce)
return;
cmn_err(CE_CONT, "send mondo timeout "
"[retries: 0x%x] cpuids: ", retries);
for (i = 0; i < ncpuids; i++)
cmn_err(CE_CONT, " 0x%x", mcpup->cpu_list[i]);
cmn_err(CE_CONT, "\n");
cmn_err(CE_PANIC, "send_mondo_set: timeout");
}
while (gettick() < (tick + sys_clock_mhz))
;
retries++;
} while (ncpuids > 0);
CPU_STATS_ADDQ(CPU, sys, xcalls, shipped);
#ifdef SEND_MONDO_STATS
{
uint64_t n = gettick() - starttick;
if (n < 8192)
x_set_stimes[n >> 7]++;
else if (n < 15*8192)
x_set_ltimes[n >> 13]++;
else
x_set_ltimes[0xf]++;
}
x_set_cpus[shipped]++;
#endif
}
void
syncfpu(void)
{
}
void
cpu_flush_ecache(void)
{
}
void
sticksync_slave(void)
{}
void
sticksync_master(void)
{}
void
cpu_init_cache_scrub(void)
{}
int
dtrace_blksuword32_err(uintptr_t addr, uint32_t *data)
{
int ret, watched;
watched = watch_disable_addr((void *)addr, 4, S_WRITE);
ret = dtrace_blksuword32(addr, data, 0);
if (watched)
watch_enable_addr((void *)addr, 4, S_WRITE);
return (ret);
}
int
dtrace_blksuword32(uintptr_t addr, uint32_t *data, int tryagain)
{
if (suword32((void *)addr, *data) == -1)
return (tryagain ? dtrace_blksuword32_err(addr, data) : -1);
dtrace_flush_sec(addr);
return (0);
}
/*ARGSUSED*/
void
cpu_faulted_enter(struct cpu *cp)
{
}
/*ARGSUSED*/
void
cpu_faulted_exit(struct cpu *cp)
{
}
static int
kdi_cpu_ready_iter(int (*cb)(int, void *), void *arg)
{
int rc, i;
for (rc = 0, i = 0; i < NCPU; i++) {
if (CPU_IN_SET(cpu_ready_set, i))
rc += cb(i, arg);
}
return (rc);
}
/*
* Sends a cross-call to a specified processor. The caller assumes
* responsibility for repetition of cross-calls, as appropriate (MARSA for
* debugging).
*/
static int
kdi_xc_one(int cpuid, void (*func)(uintptr_t, uintptr_t), uintptr_t arg1,
uintptr_t arg2)
{
int stat;
struct machcpu *mcpup;
uint64_t cpuaddr_reg = 0, cpuaddr_scr = 0;
mcpup = &(((cpu_t *)get_cpuaddr(cpuaddr_reg, cpuaddr_scr))->cpu_m);
/*
* if (idsr_busy())
* return (KDI_XC_RES_ERR);
*/
init_mondo_nocheck((xcfunc_t *)func, arg1, arg2);
mcpup->cpu_list[0] = (uint16_t)cpuid;
stat = shipit(1, mcpup->cpu_list_ra);
if (stat == 0)
return (KDI_XC_RES_OK);
else
return (KDI_XC_RES_NACK);
}
static void
kdi_tickwait(clock_t nticks)
{
clock_t endtick = gettick() + nticks;
while (gettick() < endtick);
}
static void
kdi_cpu_init(int dcache_size, int dcache_linesize, int icache_size,
int icache_linesize)
{
kdi_dcache_size = dcache_size;
kdi_dcache_linesize = dcache_linesize;
kdi_icache_size = icache_size;
kdi_icache_linesize = icache_linesize;
}
/* used directly by kdi_read/write_phys */
void
kdi_flush_caches(void)
{
/* Not required on sun4v architecture. */
}
/*ARGSUSED*/
int
kdi_get_stick(uint64_t *stickp)
{
return (-1);
}
void
cpu_kdi_init(kdi_t *kdi)
{
kdi->kdi_flush_caches = kdi_flush_caches;
kdi->mkdi_cpu_init = kdi_cpu_init;
kdi->mkdi_cpu_ready_iter = kdi_cpu_ready_iter;
kdi->mkdi_xc_one = kdi_xc_one;
kdi->mkdi_tickwait = kdi_tickwait;
kdi->mkdi_get_stick = kdi_get_stick;
}
static void
sun4v_system_claim(void)
{
watchdog_suspend();
}
static void
sun4v_system_release(void)
{
watchdog_resume();
}
void
plat_kdi_init(kdi_t *kdi)
{
kdi->pkdi_system_claim = sun4v_system_claim;
kdi->pkdi_system_release = sun4v_system_release;
}
/*
* Routine to return memory information associated
* with a physical address and syndrome.
*/
/* ARGSUSED */
int
cpu_get_mem_info(uint64_t synd, uint64_t afar,
uint64_t *mem_sizep, uint64_t *seg_sizep, uint64_t *bank_sizep,
int *segsp, int *banksp, int *mcidp)
{
return (ENOTSUP);
}
/*
* This routine returns the size of the kernel's FRU name buffer.
*/
size_t
cpu_get_name_bufsize()
{
return (UNUM_NAMLEN);
}
/*
* This routine is a more generic interface to cpu_get_mem_unum(),
* that may be used by other modules (e.g. mm).
*/
/* ARGSUSED */
int
cpu_get_mem_name(uint64_t synd, uint64_t *afsr, uint64_t afar,
char *buf, int buflen, int *lenp)
{
return (ENOTSUP);
}
/* ARGSUSED */
int
cpu_get_mem_sid(char *unum, char *buf, int buflen, int *lenp)
{
return (ENOTSUP);
}
/* ARGSUSED */
int
cpu_get_mem_addr(char *unum, char *sid, uint64_t offset, uint64_t *addrp)
{
return (ENOTSUP);
}
/*
* xt_sync - wait for previous x-traps to finish
*/
void
xt_sync(cpuset_t cpuset)
{
union {
uint8_t volatile byte[NCPU];
uint64_t volatile xword[NCPU / 8];
} cpu_sync;
uint64_t starttick, endtick, tick, lasttick;
uint_t largestid, smallestid;
int i;
kpreempt_disable();
CPUSET_DEL(cpuset, CPU->cpu_id);
CPUSET_AND(cpuset, cpu_ready_set);
CPUSET_BOUNDS(cpuset, smallestid, largestid);
if (smallestid == CPUSET_NOTINSET)
goto out;
/*
* Sun4v uses a queue for receiving mondos. Successful
* transmission of a mondo only indicates that the mondo
* has been written into the queue.
*
* We use an array of bytes to let each cpu to signal back
* to the cross trap sender that the cross trap has been
* executed. Set the byte to 1 before sending the cross trap
* and wait until other cpus reset it to 0.
*/
bzero((void *)&cpu_sync, NCPU);
cpu_sync.byte[smallestid] = 1;
if (largestid != smallestid) {
for (i = (smallestid + 1); i <= (largestid - 1); i++)
if (CPU_IN_SET(cpuset, i))
cpu_sync.byte[i] = 1;
cpu_sync.byte[largestid] = 1;
}
xt_some(cpuset, (xcfunc_t *)xt_sync_tl1,
(uint64_t)cpu_sync.byte, 0);
starttick = lasttick = gettick();
endtick = starttick + xc_tick_limit;
for (i = (smallestid / 8); i <= (largestid / 8); i++) {
while (cpu_sync.xword[i] != 0) {
tick = gettick();
/*
* If there is a big jump between the current tick
* count and lasttick, we have probably hit a break
* point. Adjust endtick accordingly to avoid panic.
*/
if (tick > (lasttick + xc_tick_jump_limit)) {
endtick += (tick - lasttick);
}
lasttick = tick;
if (tick > endtick) {
if (panic_quiesce)
goto out;
cmn_err(CE_CONT, "Cross trap sync timeout "
"at cpu_sync.xword[%d]: 0x%lx\n",
i, cpu_sync.xword[i]);
cmn_err(CE_PANIC, "xt_sync: timeout");
}
}
}
out:
kpreempt_enable();
}
/*
* Recalculate the values of the cross-call timeout variables based
* on the value of the 'inter-cpu-latency' property of the platform node.
* The property sets the number of nanosec to wait for a cross-call
* to be acknowledged. Other timeout variables are derived from it.
*
* N.B. This implementation is aware of the internals of xc_init()
* and updates many of the same variables.
*/
void
recalc_xc_timeouts(void)
{
typedef union {
uint64_t whole;
struct {
uint_t high;
uint_t low;
} half;
} u_number;
/* See x_call.c for descriptions of these extern variables. */
extern uint64_t xc_tick_limit_scale;
extern uint64_t xc_mondo_time_limit;
extern uint64_t xc_func_time_limit;
extern uint64_t xc_scale;
extern uint64_t xc_mondo_multiplier;
extern uint_t nsec_shift;
/* Temp versions of the target variables */
uint64_t tick_limit;
uint64_t tick_jump_limit;
uint64_t mondo_time_limit;
uint64_t func_time_limit;
uint64_t scale;
uint64_t latency; /* nanoseconds */
uint64_t maxfreq;
uint64_t tick_limit_save = xc_tick_limit;
uint_t tick_scale;
uint64_t top;
uint64_t bottom;
u_number tk;
md_t *mdp;
int nrnode;
mde_cookie_t *platlist;
/*
* Look up the 'inter-cpu-latency' (optional) property in the
* platform node of the MD. The units are nanoseconds.
*/
if ((mdp = md_get_handle()) == NULL) {
cmn_err(CE_WARN, "recalc_xc_timeouts: "
"Unable to initialize machine description");
return;
}
nrnode = md_alloc_scan_dag(mdp,
md_root_node(mdp), "platform", "fwd", &platlist);
ASSERT(nrnode == 1);
if (nrnode < 1) {
cmn_err(CE_WARN, "recalc_xc_timeouts: platform node missing");
goto done;
}
if (md_get_prop_val(mdp, platlist[0],
"inter-cpu-latency", &latency) == -1)
goto done;
/*
* clock.h defines an assembly-language macro
* (NATIVE_TIME_TO_NSEC_SCALE) to convert from %stick
* units to nanoseconds. Since the inter-cpu-latency
* units are nanoseconds and the xc_* variables require
* %stick units, we need the inverse of that function.
* The trick is to perform the calculation without
* floating point, but also without integer truncation
* or overflow. To understand the calculation below,
* please read the discussion of the macro in clock.h.
* Since this new code will be invoked infrequently,
* we can afford to implement it in C.
*
* tick_scale is the reciprocal of nsec_scale which is
* calculated at startup in setcpudelay(). The calc
* of tick_limit parallels that of NATIVE_TIME_TO_NSEC_SCALE
* except we use tick_scale instead of nsec_scale and
* C instead of assembler.
*/
tick_scale = (uint_t)(((u_longlong_t)sys_tick_freq
<< (32 - nsec_shift)) / NANOSEC);
tk.whole = latency;
top = ((uint64_t)tk.half.high << 4) * tick_scale;
bottom = (((uint64_t)tk.half.low << 4) * (uint64_t)tick_scale) >> 32;
tick_limit = top + bottom;
/*
* xc_init() calculated 'maxfreq' by looking at all the cpus,
* and used it to derive some of the timeout variables that we
* recalculate below. We can back into the original value by
* using the inverse of one of those calculations.
*/
maxfreq = xc_mondo_time_limit / xc_scale;
/*
* Don't allow the new timeout (xc_tick_limit) to fall below
* the system tick frequency (stick). Allowing the timeout
* to be set more tightly than this empirically determined
* value may cause panics.
*/
tick_limit = tick_limit < sys_tick_freq ? sys_tick_freq : tick_limit;
tick_jump_limit = tick_limit / 32;
tick_limit *= xc_tick_limit_scale;
/*
* Recalculate xc_scale since it is used in a callback function
* (xc_func_timeout_adj) to adjust two of the timeouts dynamically.
* Make the change in xc_scale proportional to the change in
* xc_tick_limit.
*/
scale = (xc_scale * tick_limit + sys_tick_freq / 2) / tick_limit_save;
if (scale == 0)
scale = 1;
mondo_time_limit = maxfreq * scale;
func_time_limit = mondo_time_limit * xc_mondo_multiplier;
/*
* Don't modify the timeouts if nothing has changed. Else,
* stuff the variables with the freshly calculated (temp)
* variables. This minimizes the window where the set of
* values could be inconsistent.
*/
if (tick_limit != xc_tick_limit) {
xc_tick_limit = tick_limit;
xc_tick_jump_limit = tick_jump_limit;
xc_scale = scale;
xc_mondo_time_limit = mondo_time_limit;
xc_func_time_limit = func_time_limit;
/*
* Force the new values to be used for future cross
* calls. This is necessary only when we increase
* the timeouts.
*/
if (tick_limit > tick_limit_save) {
cpuset_t cpuset = cpu_ready_set;
xt_sync(cpuset);
}
}
done:
if (nrnode > 0)
md_free_scan_dag(mdp, &platlist);
(void) md_fini_handle(mdp);
}