03831d35f7499c87d51205817c93e9a8d42c4baestevel/*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * CDDL HEADER START
03831d35f7499c87d51205817c93e9a8d42c4baestevel *
03831d35f7499c87d51205817c93e9a8d42c4baestevel * The contents of this file are subject to the terms of the
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Common Development and Distribution License (the "License").
03831d35f7499c87d51205817c93e9a8d42c4baestevel * You may not use this file except in compliance with the License.
03831d35f7499c87d51205817c93e9a8d42c4baestevel *
03831d35f7499c87d51205817c93e9a8d42c4baestevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
03831d35f7499c87d51205817c93e9a8d42c4baestevel * or http://www.opensolaris.org/os/licensing.
03831d35f7499c87d51205817c93e9a8d42c4baestevel * See the License for the specific language governing permissions
03831d35f7499c87d51205817c93e9a8d42c4baestevel * and limitations under the License.
03831d35f7499c87d51205817c93e9a8d42c4baestevel *
03831d35f7499c87d51205817c93e9a8d42c4baestevel * When distributing Covered Code, include this CDDL HEADER in each
03831d35f7499c87d51205817c93e9a8d42c4baestevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
03831d35f7499c87d51205817c93e9a8d42c4baestevel * If applicable, add the following below this CDDL HEADER, with the
03831d35f7499c87d51205817c93e9a8d42c4baestevel * fields enclosed by brackets "[]" replaced with your own identifying
03831d35f7499c87d51205817c93e9a8d42c4baestevel * information: Portions Copyright [yyyy] [name of copyright owner]
03831d35f7499c87d51205817c93e9a8d42c4baestevel *
03831d35f7499c87d51205817c93e9a8d42c4baestevel * CDDL HEADER END
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel/*
07d06da50d310a325b457d6330165aebab1e0064Surya Prakki * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Use is subject to license terms.
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel/*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * CPU management for serengeti DR
03831d35f7499c87d51205817c93e9a8d42c4baestevel *
03831d35f7499c87d51205817c93e9a8d42c4baestevel * There are three states a CPU can be in:
03831d35f7499c87d51205817c93e9a8d42c4baestevel *
03831d35f7499c87d51205817c93e9a8d42c4baestevel * disconnected: In reset
03831d35f7499c87d51205817c93e9a8d42c4baestevel * connect,unconfigured: Idling in OBP's idle loop
03831d35f7499c87d51205817c93e9a8d42c4baestevel * configured: Running Solaris
03831d35f7499c87d51205817c93e9a8d42c4baestevel *
03831d35f7499c87d51205817c93e9a8d42c4baestevel * State transitions:
03831d35f7499c87d51205817c93e9a8d42c4baestevel *
03831d35f7499c87d51205817c93e9a8d42c4baestevel * connect configure
03831d35f7499c87d51205817c93e9a8d42c4baestevel * ------------> ------------>
03831d35f7499c87d51205817c93e9a8d42c4baestevel * disconnected connected configured
03831d35f7499c87d51205817c93e9a8d42c4baestevel * unconfigured
03831d35f7499c87d51205817c93e9a8d42c4baestevel * <----------- <-------------
03831d35f7499c87d51205817c93e9a8d42c4baestevel * disconnect unconfigure
03831d35f7499c87d51205817c93e9a8d42c4baestevel *
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Firmware involvements
03831d35f7499c87d51205817c93e9a8d42c4baestevel *
03831d35f7499c87d51205817c93e9a8d42c4baestevel * start_cpu(SC)
03831d35f7499c87d51205817c93e9a8d42c4baestevel * prom_serengeti_wakeupcpu(OBP)
03831d35f7499c87d51205817c93e9a8d42c4baestevel * ------------> ------------------------->
03831d35f7499c87d51205817c93e9a8d42c4baestevel * disconnected connected configured
03831d35f7499c87d51205817c93e9a8d42c4baestevel * unconfigured
03831d35f7499c87d51205817c93e9a8d42c4baestevel * <----------- <-------------------------
03831d35f7499c87d51205817c93e9a8d42c4baestevel * prom_serengeti_cpu_off(OBP) prom_serengeti_cpu_off(OBP)
03831d35f7499c87d51205817c93e9a8d42c4baestevel * stop_cpu(SC) prom_serengeti_wakeupcpu(OBP)
03831d35f7499c87d51205817c93e9a8d42c4baestevel *
03831d35f7499c87d51205817c93e9a8d42c4baestevel * SIR (Software Initiated Reset) is used to unconfigure a CPU.
03831d35f7499c87d51205817c93e9a8d42c4baestevel * After the CPU has completed flushing the caches, it issues an
03831d35f7499c87d51205817c93e9a8d42c4baestevel * sir instruction to put itself through POST. POST detects that
03831d35f7499c87d51205817c93e9a8d42c4baestevel * it is an SIR, and re-enters OBP as a slave. When the operation
03831d35f7499c87d51205817c93e9a8d42c4baestevel * completes successfully, the CPU will be idling in OBP.
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel#include <sys/obpdefs.h>
03831d35f7499c87d51205817c93e9a8d42c4baestevel#include <sys/types.h>
03831d35f7499c87d51205817c93e9a8d42c4baestevel#include <sys/cmn_err.h>
03831d35f7499c87d51205817c93e9a8d42c4baestevel#include <sys/cpuvar.h>
03831d35f7499c87d51205817c93e9a8d42c4baestevel#include <sys/membar.h>
03831d35f7499c87d51205817c93e9a8d42c4baestevel#include <sys/x_call.h>
03831d35f7499c87d51205817c93e9a8d42c4baestevel#include <sys/machsystm.h>
03831d35f7499c87d51205817c93e9a8d42c4baestevel#include <sys/cpu_sgnblk_defs.h>
03831d35f7499c87d51205817c93e9a8d42c4baestevel#include <sys/pte.h>
03831d35f7499c87d51205817c93e9a8d42c4baestevel#include <vm/hat_sfmmu.h>
03831d35f7499c87d51205817c93e9a8d42c4baestevel#include <sys/promif.h>
03831d35f7499c87d51205817c93e9a8d42c4baestevel#include <sys/note.h>
03831d35f7499c87d51205817c93e9a8d42c4baestevel#include <sys/vmsystm.h>
03831d35f7499c87d51205817c93e9a8d42c4baestevel#include <vm/seg_kmem.h>
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel#include <sys/sbd_ioctl.h>
03831d35f7499c87d51205817c93e9a8d42c4baestevel#include <sys/sbd.h>
03831d35f7499c87d51205817c93e9a8d42c4baestevel#include <sys/sbdp_priv.h>
03831d35f7499c87d51205817c93e9a8d42c4baestevel#include <sys/sbdp_mem.h>
03831d35f7499c87d51205817c93e9a8d42c4baestevel#include <sys/sbdp_error.h>
03831d35f7499c87d51205817c93e9a8d42c4baestevel#include <sys/sgsbbc_iosram.h>
03831d35f7499c87d51205817c93e9a8d42c4baestevel#include <sys/prom_plat.h>
03831d35f7499c87d51205817c93e9a8d42c4baestevel#include <sys/cheetahregs.h>
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baesteveluint64_t *sbdp_valp;
03831d35f7499c87d51205817c93e9a8d42c4baestevelextern uint64_t va_to_pa(void *);
03831d35f7499c87d51205817c93e9a8d42c4baestevelstatic int sbdp_cpu_ntries = 50000;
03831d35f7499c87d51205817c93e9a8d42c4baestevelstatic int sbdp_cpu_delay = 100;
03831d35f7499c87d51205817c93e9a8d42c4baestevelvoid sbdp_get_cpu_sram_addr(uint64_t, uint64_t);
03831d35f7499c87d51205817c93e9a8d42c4baestevelstatic int cpusram_map(caddr_t *, pgcnt_t *);
03831d35f7499c87d51205817c93e9a8d42c4baestevelstatic void cpusram_unmap(caddr_t *, pgcnt_t);
03831d35f7499c87d51205817c93e9a8d42c4baestevelextern int prom_serengeti_wakeupcpu(pnode_t);
03831d35f7499c87d51205817c93e9a8d42c4baestevelextern int prom_serengeti_cpu_off(pnode_t);
03831d35f7499c87d51205817c93e9a8d42c4baestevelextern sbdp_wnode_t *sbdp_get_wnodep(int);
03831d35f7499c87d51205817c93e9a8d42c4baestevelextern caddr_t sbdp_shutdown_va;
03831d35f7499c87d51205817c93e9a8d42c4baestevelstatic int sbdp_prom_get_cpu(void *arg, int changed);
8682d1ef2a0960ed5a9f05b9448eaa3e68ac931fRichard Lowestatic void sbdp_cpu_shutdown_self(void);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevelint
03831d35f7499c87d51205817c93e9a8d42c4baestevelsbdp_disconnect_cpu(sbdp_handle_t *hp, dev_info_t *dip, processorid_t cpuid)
03831d35f7499c87d51205817c93e9a8d42c4baestevel{
03831d35f7499c87d51205817c93e9a8d42c4baestevel pnode_t nodeid;
03831d35f7499c87d51205817c93e9a8d42c4baestevel int bd, wnode;
03831d35f7499c87d51205817c93e9a8d42c4baestevel sbdp_wnode_t *wnodep;
03831d35f7499c87d51205817c93e9a8d42c4baestevel sbdp_bd_t *bdp = NULL;
03831d35f7499c87d51205817c93e9a8d42c4baestevel int rv = 0;
03831d35f7499c87d51205817c93e9a8d42c4baestevel processorid_t cpu = cpuid;
03831d35f7499c87d51205817c93e9a8d42c4baestevel processorid_t portid;
03831d35f7499c87d51205817c93e9a8d42c4baestevel static fn_t f = "sbdp_disconnect_cpu";
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel SBDP_DBG_FUNC("%s\n", f);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel nodeid = ddi_get_nodeid(dip);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Get board number and node number
03831d35f7499c87d51205817c93e9a8d42c4baestevel * The check for determining if nodeid is valid is done inside
03831d35f7499c87d51205817c93e9a8d42c4baestevel * sbdp_get_bd_and_wnode_num.
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (SBDP_INJECT_ERROR(f, 0) ||
03831d35f7499c87d51205817c93e9a8d42c4baestevel sbdp_get_bd_and_wnode_num(nodeid, &bd, &wnode) != 0) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel rv = -1;
03831d35f7499c87d51205817c93e9a8d42c4baestevel goto out;
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Grab the lock to prevent status threads from accessing
03831d35f7499c87d51205817c93e9a8d42c4baestevel * registers on the CPU when it is being put into reset.
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel wnodep = sbdp_get_wnodep(wnode);
03831d35f7499c87d51205817c93e9a8d42c4baestevel bdp = &wnodep->bds[bd];
03831d35f7499c87d51205817c93e9a8d42c4baestevel ASSERT(bdp);
03831d35f7499c87d51205817c93e9a8d42c4baestevel mutex_enter(&bdp->bd_mutex);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Mark the CPU in reset. This should be done before calling
03831d35f7499c87d51205817c93e9a8d42c4baestevel * the SC because we won't know at which stage it failed if
03831d35f7499c87d51205817c93e9a8d42c4baestevel * the SC call returns failure.
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel sbdp_cpu_in_reset(wnode, bd, SG_CPUID_TO_CPU_UNIT(cpuid), 1);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Ask OBP to mark the CPU as in POST
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (SBDP_INJECT_ERROR(f, 1) || prom_serengeti_cpu_off(nodeid) != 0) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel rv = -1;
03831d35f7499c87d51205817c93e9a8d42c4baestevel goto out;
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Ask the SC to put the CPU into reset. If the first
03831d35f7499c87d51205817c93e9a8d42c4baestevel * core is not present, the stop CPU interface needs
03831d35f7499c87d51205817c93e9a8d42c4baestevel * to be called with the portid rather than the cpuid.
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel portid = SG_CPUID_TO_PORTID(cpuid);
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (!SBDP_IS_CPU_PRESENT(bdp, SG_CPUID_TO_CPU_UNIT(portid))) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel cpu = portid;
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (SBDP_INJECT_ERROR(f, 2) || sbdp_stop_cpu(cpu) != 0) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel rv = -1;
03831d35f7499c87d51205817c93e9a8d42c4baestevel goto out;
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevelout:
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (bdp != NULL) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel mutex_exit(&bdp->bd_mutex);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (rv != 0) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel sbdp_set_err(hp->h_err, ESGT_STOPCPU, NULL);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (rv);
03831d35f7499c87d51205817c93e9a8d42c4baestevel}
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevelint
03831d35f7499c87d51205817c93e9a8d42c4baestevelsbdp_connect_cpu(sbdp_handle_t *hp, dev_info_t *dip, processorid_t cpuid)
03831d35f7499c87d51205817c93e9a8d42c4baestevel{
03831d35f7499c87d51205817c93e9a8d42c4baestevel pnode_t nodeid;
03831d35f7499c87d51205817c93e9a8d42c4baestevel sbd_error_t *sep;
03831d35f7499c87d51205817c93e9a8d42c4baestevel int i;
03831d35f7499c87d51205817c93e9a8d42c4baestevel int bd, wnode;
03831d35f7499c87d51205817c93e9a8d42c4baestevel int rv = 0;
03831d35f7499c87d51205817c93e9a8d42c4baestevel static fn_t f = "sbdp_connect_cpu";
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel SBDP_DBG_FUNC("%s\n", f);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel sep = hp->h_err;
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel nodeid = ddi_get_nodeid(dip);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * The check for determining if nodeid is valid is done inside
03831d35f7499c87d51205817c93e9a8d42c4baestevel * sbdp_get_bd_and_wnode_num.
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (SBDP_INJECT_ERROR(f, 0) ||
03831d35f7499c87d51205817c93e9a8d42c4baestevel sbdp_get_bd_and_wnode_num(nodeid, &bd, &wnode) != 0) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel rv = -1;
03831d35f7499c87d51205817c93e9a8d42c4baestevel goto out;
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Ask the SC to bring the CPU out of reset.
03831d35f7499c87d51205817c93e9a8d42c4baestevel * At this point, the sb_dev_present bit is not set for the CPU.
03831d35f7499c87d51205817c93e9a8d42c4baestevel * From sbd point of view the CPU is not present yet. No
03831d35f7499c87d51205817c93e9a8d42c4baestevel * status threads will try to read registers off the CPU.
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Since we are already holding sb_mutex, it is not necessary
03831d35f7499c87d51205817c93e9a8d42c4baestevel * to grab the board mutex when checking and setting the
03831d35f7499c87d51205817c93e9a8d42c4baestevel * cpus_in_reset bit.
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (sbdp_is_cpu_in_reset(wnode, bd, SG_CPUID_TO_CPU_UNIT(cpuid))) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel sbdp_wnode_t *wnodep;
03831d35f7499c87d51205817c93e9a8d42c4baestevel sbdp_bd_t *bdp = NULL;
03831d35f7499c87d51205817c93e9a8d42c4baestevel processorid_t cpu = cpuid;
03831d35f7499c87d51205817c93e9a8d42c4baestevel processorid_t portid;
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel wnodep = sbdp_get_wnodep(wnode);
03831d35f7499c87d51205817c93e9a8d42c4baestevel bdp = &wnodep->bds[bd];
03831d35f7499c87d51205817c93e9a8d42c4baestevel ASSERT(bdp);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * If the first core is not present, the start CPU
03831d35f7499c87d51205817c93e9a8d42c4baestevel * interface needs to be called with the portid rather
03831d35f7499c87d51205817c93e9a8d42c4baestevel * than the cpuid.
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel portid = SG_CPUID_TO_PORTID(cpuid);
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (!SBDP_IS_CPU_PRESENT(bdp, SG_CPUID_TO_CPU_UNIT(portid))) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel cpu = portid;
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (SBDP_INJECT_ERROR(f, 1) || sbdp_start_cpu(cpu) != 0) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel rv = -1;
03831d35f7499c87d51205817c93e9a8d42c4baestevel goto out;
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (SBDP_INJECT_ERROR(f, 2) ||
03831d35f7499c87d51205817c93e9a8d42c4baestevel prom_serengeti_wakeupcpu(nodeid) != 0) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel rv = -1;
03831d35f7499c87d51205817c93e9a8d42c4baestevel goto out;
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Mark the CPU out of reset.
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel sbdp_cpu_in_reset(wnode, bd, SG_CPUID_TO_CPU_UNIT(cpuid), 0);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Refresh the bd info
03831d35f7499c87d51205817c93e9a8d42c4baestevel * we need to wait until all cpus are out of reset
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel for (i = 0; i < SG_MAX_CPUS_PER_BD; i++)
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (sbdp_is_cpu_present(wnode, bd, i) &&
03831d35f7499c87d51205817c93e9a8d42c4baestevel sbdp_is_cpu_in_reset(wnode, bd, i) == 1) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel break;
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (i == SG_MAX_CPUS_PER_BD) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * All cpus are out of reset so it is safe to
03831d35f7499c87d51205817c93e9a8d42c4baestevel * update the bd info
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel sbdp_add_new_bd_info(wnode, bd);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevelout:
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (rv != 0)
03831d35f7499c87d51205817c93e9a8d42c4baestevel sbdp_set_err(sep, ESGT_WAKEUPCPU, NULL);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (rv);
03831d35f7499c87d51205817c93e9a8d42c4baestevel}
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevelint
03831d35f7499c87d51205817c93e9a8d42c4baestevelsbdp_cpu_poweron(struct cpu *cp)
03831d35f7499c87d51205817c93e9a8d42c4baestevel{
03831d35f7499c87d51205817c93e9a8d42c4baestevel int cpuid;
03831d35f7499c87d51205817c93e9a8d42c4baestevel int ntries;
03831d35f7499c87d51205817c93e9a8d42c4baestevel pnode_t nodeid;
03831d35f7499c87d51205817c93e9a8d42c4baestevel extern void restart_other_cpu(int);
03831d35f7499c87d51205817c93e9a8d42c4baestevel static fn_t f = "sbdp_cpu_poweron";
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel SBDP_DBG_FUNC("%s\n", f);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel ASSERT(MUTEX_HELD(&cpu_lock));
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel ntries = sbdp_cpu_ntries;
03831d35f7499c87d51205817c93e9a8d42c4baestevel cpuid = cp->cpu_id;
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel nodeid = cpunodes[cpuid].nodeid;
03831d35f7499c87d51205817c93e9a8d42c4baestevel ASSERT(nodeid != (pnode_t)0);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * This is a safe guard in case the CPU has taken a trap
03831d35f7499c87d51205817c93e9a8d42c4baestevel * and idling in POST.
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (SBDP_INJECT_ERROR(f, 0) ||
03831d35f7499c87d51205817c93e9a8d42c4baestevel prom_serengeti_wakeupcpu(nodeid) != 0) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (EBUSY);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel cp->cpu_flags &= ~CPU_POWEROFF;
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * NOTE: restart_other_cpu pauses cpus during the
03831d35f7499c87d51205817c93e9a8d42c4baestevel * slave cpu start. This helps to quiesce the
03831d35f7499c87d51205817c93e9a8d42c4baestevel * bus traffic a bit which makes the tick sync
03831d35f7499c87d51205817c93e9a8d42c4baestevel * routine in the prom more robust.
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel SBDP_DBG_CPU("%s: COLD START for cpu (%d)\n", f, cpuid);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel restart_other_cpu(cpuid);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel SBDP_DBG_CPU("after restarting other cpus\n");
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Wait for the cpu to reach its idle thread before
03831d35f7499c87d51205817c93e9a8d42c4baestevel * we zap him with a request to blow away the mappings
03831d35f7499c87d51205817c93e9a8d42c4baestevel * he (might) have for the sbdp_shutdown_asm code
03831d35f7499c87d51205817c93e9a8d42c4baestevel * he may have executed on unconfigure.
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel while ((cp->cpu_thread != cp->cpu_idle_thread) && (ntries > 0)) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel DELAY(sbdp_cpu_delay);
03831d35f7499c87d51205817c93e9a8d42c4baestevel ntries--;
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel SBDP_DBG_CPU("%s: waited %d out of %d loops for cpu %d\n",
03831d35f7499c87d51205817c93e9a8d42c4baestevel f, sbdp_cpu_ntries - ntries, sbdp_cpu_ntries, cpuid);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (0);
03831d35f7499c87d51205817c93e9a8d42c4baestevel}
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel#define SBDP_CPU_SRAM_ADDR 0x7fff0900000ull
03831d35f7499c87d51205817c93e9a8d42c4baestevel#define SBDP_CPU_SRAM_SIZE 0x20000ull
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevelstatic const char cpyren_key[] = "COPYREN";
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevelstatic uint64_t bbsram_pa;
03831d35f7499c87d51205817c93e9a8d42c4baestevelstatic uint_t bbsram_size;
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baesteveltypedef struct {
03831d35f7499c87d51205817c93e9a8d42c4baestevel caddr_t vaddr;
03831d35f7499c87d51205817c93e9a8d42c4baestevel pgcnt_t npages;
03831d35f7499c87d51205817c93e9a8d42c4baestevel uint64_t *pa;
03831d35f7499c87d51205817c93e9a8d42c4baestevel uint_t *size;
03831d35f7499c87d51205817c93e9a8d42c4baestevel} sbdp_cpu_sram_map_t;
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevelint
03831d35f7499c87d51205817c93e9a8d42c4baestevelsbdp_cpu_poweroff(struct cpu *cp)
03831d35f7499c87d51205817c93e9a8d42c4baestevel{
03831d35f7499c87d51205817c93e9a8d42c4baestevel processorid_t cpuid;
03831d35f7499c87d51205817c93e9a8d42c4baestevel pnode_t nodeid;
03831d35f7499c87d51205817c93e9a8d42c4baestevel sbdp_cpu_sram_map_t map;
03831d35f7499c87d51205817c93e9a8d42c4baestevel static fn_t f = "sbdp_cpu_poweroff";
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel SBDP_DBG_FUNC("%s\n", f);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel ASSERT(MUTEX_HELD(&cpu_lock));
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Capture all CPUs (except for detaching proc) to prevent
03831d35f7499c87d51205817c93e9a8d42c4baestevel * crosscalls to the detaching proc until it has cleared its
03831d35f7499c87d51205817c93e9a8d42c4baestevel * bit in cpu_ready_set.
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel cpuid = cp->cpu_id;
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel nodeid = cpunodes[cpuid].nodeid;
03831d35f7499c87d51205817c93e9a8d42c4baestevel ASSERT(nodeid != (pnode_t)0);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel *sbdp_valp = 0ull;
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Do the cpu sram mapping now. This avoids problems with
03831d35f7499c87d51205817c93e9a8d42c4baestevel * mutexes and high PILS
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (SBDP_INJECT_ERROR(f, 0) ||
03831d35f7499c87d51205817c93e9a8d42c4baestevel cpusram_map(&map.vaddr, &map.npages) != DDI_SUCCESS) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (EBUSY);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel map.pa = &bbsram_pa;
03831d35f7499c87d51205817c93e9a8d42c4baestevel map.size = &bbsram_size;
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Do a cross call to the cpu so it obtains the base address
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel xc_one(cpuid, sbdp_get_cpu_sram_addr, (uint64_t)&map,
03831d35f7499c87d51205817c93e9a8d42c4baestevel (uint64_t)NULL);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel cpusram_unmap(&map.vaddr, map.npages);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (SBDP_INJECT_ERROR(f, 1) || bbsram_size == 0) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel cmn_err(CE_WARN, "cpu%d: Key \"%s\" missing from CPU SRAM TOC",
03831d35f7499c87d51205817c93e9a8d42c4baestevel cpuid, cpyren_key);
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (EBUSY);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel if ((bbsram_pa & MMU_PAGEOFFSET) != 0) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel cmn_err(CE_WARN, "cpu%d: CPU SRAM key \"%s\" not page aligned, "
03831d35f7499c87d51205817c93e9a8d42c4baestevel "offset = 0x%lx", cpuid, cpyren_key,
07d06da50d310a325b457d6330165aebab1e0064Surya Prakki (bbsram_pa - (uint64_t)SBDP_CPU_SRAM_ADDR));
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (EBUSY);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (bbsram_size < MMU_PAGESIZE) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel cmn_err(CE_WARN, "cpu%d: CPU SRAM key \"%s\" too small, "
03831d35f7499c87d51205817c93e9a8d42c4baestevel "size = 0x%x", cpuid, cpyren_key, bbsram_size);
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (EBUSY);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Capture all CPUs (except for detaching proc) to prevent
03831d35f7499c87d51205817c93e9a8d42c4baestevel * crosscalls to the detaching proc until it has cleared its
03831d35f7499c87d51205817c93e9a8d42c4baestevel * bit in cpu_ready_set.
03831d35f7499c87d51205817c93e9a8d42c4baestevel *
03831d35f7499c87d51205817c93e9a8d42c4baestevel * The CPU's remain paused and the prom_mutex is known to be free.
03831d35f7499c87d51205817c93e9a8d42c4baestevel * This prevents the x-trap victim from blocking when doing prom
03831d35f7499c87d51205817c93e9a8d42c4baestevel * IEEE-1275 calls at a high PIL level.
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel promsafe_pause_cpus();
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Quiesce interrupts on the target CPU. We do this by setting
03831d35f7499c87d51205817c93e9a8d42c4baestevel * the CPU 'not ready'- (i.e. removing the CPU from cpu_ready_set) to
03831d35f7499c87d51205817c93e9a8d42c4baestevel * prevent it from receiving cross calls and cross traps.
03831d35f7499c87d51205817c93e9a8d42c4baestevel * This prevents the processor from receiving any new soft interrupts.
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel mp_cpu_quiesce(cp);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel /* tell the prom the cpu is going away */
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (SBDP_INJECT_ERROR(f, 2) || prom_serengeti_cpu_off(nodeid) != 0)
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (EBUSY);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * An sir instruction is issued at the end of the shutdown
03831d35f7499c87d51205817c93e9a8d42c4baestevel * routine to make the CPU go through POST and re-enter OBP.
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel xt_one_unchecked(cp->cpu_id, (xcfunc_t *)idle_stop_xcall,
03831d35f7499c87d51205817c93e9a8d42c4baestevel (uint64_t)sbdp_cpu_shutdown_self, 0);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel *sbdp_valp = 3ull;
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel start_cpus();
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Wait until we reach the OBP idle loop or time out.
03831d35f7499c87d51205817c93e9a8d42c4baestevel * prom_serengeti_wakeupcpu waits for up to 60 seconds for the
03831d35f7499c87d51205817c93e9a8d42c4baestevel * CPU to reach OBP idle loop.
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (SBDP_INJECT_ERROR(f, 3) ||
03831d35f7499c87d51205817c93e9a8d42c4baestevel prom_serengeti_wakeupcpu(nodeid) != 0) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * If it fails here, we still consider the unconfigure
03831d35f7499c87d51205817c93e9a8d42c4baestevel * operation as successful.
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel cmn_err(CE_WARN, "cpu%d: CPU failed to enter OBP idle loop.\n",
03831d35f7499c87d51205817c93e9a8d42c4baestevel cpuid);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel ASSERT(!(CPU_IN_SET(cpu_ready_set, cpuid)));
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel bbsram_pa = 0;
03831d35f7499c87d51205817c93e9a8d42c4baestevel bbsram_size = 0;
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (0);
03831d35f7499c87d51205817c93e9a8d42c4baestevel}
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevelprocessorid_t
03831d35f7499c87d51205817c93e9a8d42c4baestevelsbdp_get_cpuid(sbdp_handle_t *hp, dev_info_t *dip)
03831d35f7499c87d51205817c93e9a8d42c4baestevel{
03831d35f7499c87d51205817c93e9a8d42c4baestevel int cpuid;
03831d35f7499c87d51205817c93e9a8d42c4baestevel char type[OBP_MAXPROPNAME];
03831d35f7499c87d51205817c93e9a8d42c4baestevel pnode_t nodeid;
03831d35f7499c87d51205817c93e9a8d42c4baestevel sbd_error_t *sep;
03831d35f7499c87d51205817c93e9a8d42c4baestevel static fn_t f = "sbdp_get_cpuid";
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel SBDP_DBG_FUNC("%s\n", f);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel nodeid = ddi_get_nodeid(dip);
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (sbdp_is_node_bad(nodeid))
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (-1);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel sep = hp->h_err;
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (prom_getproplen(nodeid, "device_type") < OBP_MAXPROPNAME)
03831d35f7499c87d51205817c93e9a8d42c4baestevel (void) prom_getprop(nodeid, "device_type", (caddr_t)type);
03831d35f7499c87d51205817c93e9a8d42c4baestevel else {
03831d35f7499c87d51205817c93e9a8d42c4baestevel sbdp_set_err(sep, ESGT_NO_DEV_TYPE, NULL);
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (-1);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (strcmp(type, "cpu") != 0) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel sbdp_set_err(sep, ESGT_NOT_CPUTYPE, NULL);
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (-1);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Check to see if property "cpuid" exists first.
03831d35f7499c87d51205817c93e9a8d42c4baestevel * If not, check for "portid".
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (prom_getprop(nodeid, "cpuid", (caddr_t)&cpuid) == -1)
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (prom_getprop(nodeid, "portid", (caddr_t)&cpuid) == -1) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (-1);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel return ((processorid_t)cpuid & SG_CPU_ID_MASK);
03831d35f7499c87d51205817c93e9a8d42c4baestevel}
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevelint
03831d35f7499c87d51205817c93e9a8d42c4baestevelsbdp_cpu_get_impl(sbdp_handle_t *hp, dev_info_t *dip)
03831d35f7499c87d51205817c93e9a8d42c4baestevel{
03831d35f7499c87d51205817c93e9a8d42c4baestevel int impl;
03831d35f7499c87d51205817c93e9a8d42c4baestevel char type[OBP_MAXPROPNAME];
03831d35f7499c87d51205817c93e9a8d42c4baestevel pnode_t nodeid;
03831d35f7499c87d51205817c93e9a8d42c4baestevel sbd_error_t *sep;
03831d35f7499c87d51205817c93e9a8d42c4baestevel static fn_t f = "sbdp_cpu_get_impl";
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel SBDP_DBG_FUNC("%s\n", f);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel nodeid = ddi_get_nodeid(dip);
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (sbdp_is_node_bad(nodeid))
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (-1);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel sep = hp->h_err;
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (prom_getproplen(nodeid, "device_type") < OBP_MAXPROPNAME)
03831d35f7499c87d51205817c93e9a8d42c4baestevel (void) prom_getprop(nodeid, "device_type", (caddr_t)type);
03831d35f7499c87d51205817c93e9a8d42c4baestevel else {
03831d35f7499c87d51205817c93e9a8d42c4baestevel sbdp_set_err(sep, ESGT_NO_DEV_TYPE, NULL);
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (-1);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (strcmp(type, "cpu") != 0) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel sbdp_set_err(sep, ESGT_NOT_CPUTYPE, NULL);
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (-1);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Get the implementation# property.
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (prom_getprop(nodeid, "implementation#", (caddr_t)&impl) == -1)
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (-1);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (impl);
03831d35f7499c87d51205817c93e9a8d42c4baestevel}
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevelstruct sbdp_prom_get_node_args {
03831d35f7499c87d51205817c93e9a8d42c4baestevel pnode_t node; /* current node */
03831d35f7499c87d51205817c93e9a8d42c4baestevel processorid_t portid; /* portid we are looking for */
03831d35f7499c87d51205817c93e9a8d42c4baestevel pnode_t result_node; /* node found with the above portid */
03831d35f7499c87d51205817c93e9a8d42c4baestevel};
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevelpnode_t
03831d35f7499c87d51205817c93e9a8d42c4baestevelsbdp_find_nearby_cpu_by_portid(pnode_t nodeid, processorid_t portid)
03831d35f7499c87d51205817c93e9a8d42c4baestevel{
03831d35f7499c87d51205817c93e9a8d42c4baestevel struct sbdp_prom_get_node_args arg;
03831d35f7499c87d51205817c93e9a8d42c4baestevel static fn_t f = "sbdp_find_nearby_cpu_by_portid";
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel SBDP_DBG_FUNC("%s\n", f);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel arg.node = nodeid;
03831d35f7499c87d51205817c93e9a8d42c4baestevel arg.portid = portid;
03831d35f7499c87d51205817c93e9a8d42c4baestevel (void) prom_tree_access(sbdp_prom_get_cpu, &arg, NULL);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (arg.result_node);
03831d35f7499c87d51205817c93e9a8d42c4baestevel}
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel/*ARGSUSED*/
03831d35f7499c87d51205817c93e9a8d42c4baestevelstatic int
03831d35f7499c87d51205817c93e9a8d42c4baestevelsbdp_prom_get_cpu(void *arg, int changed)
03831d35f7499c87d51205817c93e9a8d42c4baestevel{
03831d35f7499c87d51205817c93e9a8d42c4baestevel int portid;
03831d35f7499c87d51205817c93e9a8d42c4baestevel pnode_t parent, cur_node;
03831d35f7499c87d51205817c93e9a8d42c4baestevel struct sbdp_prom_get_node_args *argp = arg;
03831d35f7499c87d51205817c93e9a8d42c4baestevel static fn_t f = "sbdp_prom_get_cpu";
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel SBDP_DBG_FUNC("%s\n", f);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel parent = prom_parentnode(argp->node);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel for (cur_node = prom_childnode(parent); cur_node != OBP_NONODE;
03831d35f7499c87d51205817c93e9a8d42c4baestevel cur_node = prom_nextnode(cur_node)) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (prom_getprop(cur_node, OBP_PORTID, (caddr_t)&portid) < 0)
03831d35f7499c87d51205817c93e9a8d42c4baestevel continue;
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel if ((portid == argp->portid) && (cur_node != argp->node))
03831d35f7499c87d51205817c93e9a8d42c4baestevel break;
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel argp->result_node = cur_node;
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (0);
03831d35f7499c87d51205817c93e9a8d42c4baestevel}
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel/*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * A detaching CPU is xcalled with an xtrap to sbdp_cpu_stop_self() after
03831d35f7499c87d51205817c93e9a8d42c4baestevel * it has been offlined. The function of this routine is to get the cpu
03831d35f7499c87d51205817c93e9a8d42c4baestevel * spinning in a safe place. The requirement is that the system will not
03831d35f7499c87d51205817c93e9a8d42c4baestevel * reference anything on the detaching board (memory and i/o is detached
03831d35f7499c87d51205817c93e9a8d42c4baestevel * elsewhere) and that the CPU not reference anything on any other board
03831d35f7499c87d51205817c93e9a8d42c4baestevel * in the system. This isolation is required during and after the writes
03831d35f7499c87d51205817c93e9a8d42c4baestevel * to the domain masks to remove the board from the domain.
03831d35f7499c87d51205817c93e9a8d42c4baestevel *
03831d35f7499c87d51205817c93e9a8d42c4baestevel * To accomplish this isolation the following is done:
03831d35f7499c87d51205817c93e9a8d42c4baestevel * 0) Map the CPUSRAM to obtain the correct address in SRAM
03831d35f7499c87d51205817c93e9a8d42c4baestevel * 1) Create a locked mapping to a location in CPU SRAM where
03831d35f7499c87d51205817c93e9a8d42c4baestevel * the cpu will execute.
03831d35f7499c87d51205817c93e9a8d42c4baestevel * 2) Copy the target function (sbdp_shutdown_asm) in which
03831d35f7499c87d51205817c93e9a8d42c4baestevel * the cpu will execute into CPU SRAM.
03831d35f7499c87d51205817c93e9a8d42c4baestevel * 3) Jump into function with CPU SRAM.
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Function will:
03831d35f7499c87d51205817c93e9a8d42c4baestevel * 3.1) Flush its Ecache (displacement).
03831d35f7499c87d51205817c93e9a8d42c4baestevel * 3.2) Flush its Dcache with HW mechanism.
03831d35f7499c87d51205817c93e9a8d42c4baestevel * 3.3) Flush its Icache with HW mechanism.
03831d35f7499c87d51205817c93e9a8d42c4baestevel * 3.4) Flush all valid and _unlocked_ D-TLB entries.
03831d35f7499c87d51205817c93e9a8d42c4baestevel * 3.5) Flush all valid and _unlocked_ I-TLB entries.
03831d35f7499c87d51205817c93e9a8d42c4baestevel * 4) Jump into a tight loop.
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevelstatic void
03831d35f7499c87d51205817c93e9a8d42c4baestevelsbdp_cpu_stop_self(uint64_t pa)
03831d35f7499c87d51205817c93e9a8d42c4baestevel{
03831d35f7499c87d51205817c93e9a8d42c4baestevel cpu_t *cp = CPU;
03831d35f7499c87d51205817c93e9a8d42c4baestevel int cpuid = cp->cpu_id;
03831d35f7499c87d51205817c93e9a8d42c4baestevel tte_t tte;
03831d35f7499c87d51205817c93e9a8d42c4baestevel volatile uint_t *src, *dst;
e0731422366620894c16c1ee6515551c5f00733dRichard Lowe size_t funclen;
03831d35f7499c87d51205817c93e9a8d42c4baestevel sbdp_shutdown_t sht;
03831d35f7499c87d51205817c93e9a8d42c4baestevel uint_t bbsram_pfn;
03831d35f7499c87d51205817c93e9a8d42c4baestevel uint64_t bbsram_addr;
03831d35f7499c87d51205817c93e9a8d42c4baestevel void (*bbsram_func)(sbdp_shutdown_t *);
03831d35f7499c87d51205817c93e9a8d42c4baestevel extern void sbdp_shutdown_asm(sbdp_shutdown_t *);
03831d35f7499c87d51205817c93e9a8d42c4baestevel extern void sbdp_shutdown_asm_end(void);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
e0731422366620894c16c1ee6515551c5f00733dRichard Lowe funclen = (uintptr_t)sbdp_shutdown_asm_end -
e0731422366620894c16c1ee6515551c5f00733dRichard Lowe (uintptr_t)sbdp_shutdown_asm;
03831d35f7499c87d51205817c93e9a8d42c4baestevel ASSERT(funclen <= MMU_PAGESIZE);
03831d35f7499c87d51205817c93e9a8d42c4baestevel ASSERT(bbsram_pa != 0);
03831d35f7499c87d51205817c93e9a8d42c4baestevel ASSERT((bbsram_pa & MMU_PAGEOFFSET) == 0);
03831d35f7499c87d51205817c93e9a8d42c4baestevel ASSERT(bbsram_size >= MMU_PAGESIZE);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel stdphys(pa, 3);
03831d35f7499c87d51205817c93e9a8d42c4baestevel bbsram_pfn = (uint_t)(bbsram_pa >> MMU_PAGESHIFT);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel bbsram_addr = (uint64_t)sbdp_shutdown_va;
03831d35f7499c87d51205817c93e9a8d42c4baestevel sht.estack = bbsram_addr + MMU_PAGESIZE;
03831d35f7499c87d51205817c93e9a8d42c4baestevel sht.flushaddr = ecache_flushaddr;
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel tte.tte_inthi = TTE_VALID_INT | TTE_SZ_INT(TTE8K) |
03831d35f7499c87d51205817c93e9a8d42c4baestevel TTE_PFN_INTHI(bbsram_pfn);
03831d35f7499c87d51205817c93e9a8d42c4baestevel tte.tte_intlo = TTE_PFN_INTLO(bbsram_pfn) |
03831d35f7499c87d51205817c93e9a8d42c4baestevel TTE_HWWR_INT | TTE_PRIV_INT | TTE_LCK_INT;
1e2e7a75ddb1eedcefa449ce98fd5862749b72eehuah sfmmu_dtlb_ld_kva(sbdp_shutdown_va, &tte); /* load dtlb */
1e2e7a75ddb1eedcefa449ce98fd5862749b72eehuah sfmmu_itlb_ld_kva(sbdp_shutdown_va, &tte); /* load itlb */
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel for (src = (uint_t *)sbdp_shutdown_asm, dst = (uint_t *)bbsram_addr;
03831d35f7499c87d51205817c93e9a8d42c4baestevel src < (uint_t *)sbdp_shutdown_asm_end; src++, dst++)
03831d35f7499c87d51205817c93e9a8d42c4baestevel *dst = *src;
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel bbsram_func = (void (*)())bbsram_addr;
03831d35f7499c87d51205817c93e9a8d42c4baestevel sht.size = (uint32_t)cpunodes[cpuid].ecache_size << 1;
03831d35f7499c87d51205817c93e9a8d42c4baestevel sht.linesize = (uint32_t)cpunodes[cpuid].ecache_linesize;
03831d35f7499c87d51205817c93e9a8d42c4baestevel sht.physaddr = pa;
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Signal to sbdp_cpu_poweroff() that we're just
03831d35f7499c87d51205817c93e9a8d42c4baestevel * about done.
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel cp->cpu_m.in_prom = 1;
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel stdphys(pa, 4);
03831d35f7499c87d51205817c93e9a8d42c4baestevel (*bbsram_func)(&sht);
03831d35f7499c87d51205817c93e9a8d42c4baestevel}
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel/* ARGSUSED */
03831d35f7499c87d51205817c93e9a8d42c4baestevelvoid
03831d35f7499c87d51205817c93e9a8d42c4baestevelsbdp_get_cpu_sram_addr(uint64_t arg1, uint64_t arg2)
03831d35f7499c87d51205817c93e9a8d42c4baestevel{
03831d35f7499c87d51205817c93e9a8d42c4baestevel uint64_t *pap;
03831d35f7499c87d51205817c93e9a8d42c4baestevel uint_t *sizep;
03831d35f7499c87d51205817c93e9a8d42c4baestevel struct iosram_toc *tocp;
03831d35f7499c87d51205817c93e9a8d42c4baestevel uint_t offset;
03831d35f7499c87d51205817c93e9a8d42c4baestevel uint_t size;
03831d35f7499c87d51205817c93e9a8d42c4baestevel sbdp_cpu_sram_map_t *map;
03831d35f7499c87d51205817c93e9a8d42c4baestevel int i;
03831d35f7499c87d51205817c93e9a8d42c4baestevel fn_t f = "sbdp_get_cpu_sram_addr";
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel SBDP_DBG_FUNC("%s\n", f);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel map = (sbdp_cpu_sram_map_t *)arg1;
03831d35f7499c87d51205817c93e9a8d42c4baestevel tocp = (struct iosram_toc *)map->vaddr;
03831d35f7499c87d51205817c93e9a8d42c4baestevel pap = map->pa;
03831d35f7499c87d51205817c93e9a8d42c4baestevel sizep = map->size;
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel for (i = 0; i < tocp->iosram_tagno; i++) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (strcmp(tocp->iosram_keys[i].key, cpyren_key) == 0)
03831d35f7499c87d51205817c93e9a8d42c4baestevel break;
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (i == tocp->iosram_tagno) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel *pap = 0;
03831d35f7499c87d51205817c93e9a8d42c4baestevel *sizep = 0;
03831d35f7499c87d51205817c93e9a8d42c4baestevel return;
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel offset = tocp->iosram_keys[i].offset;
03831d35f7499c87d51205817c93e9a8d42c4baestevel size = tocp->iosram_keys[i].size;
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * The address we want is the begining of cpusram + offset
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel *pap = SBDP_CPU_SRAM_ADDR + offset;
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel *sizep = size;
03831d35f7499c87d51205817c93e9a8d42c4baestevel}
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevelstatic int
03831d35f7499c87d51205817c93e9a8d42c4baestevelcpusram_map(caddr_t *vaddrp, pgcnt_t *npp)
03831d35f7499c87d51205817c93e9a8d42c4baestevel{
03831d35f7499c87d51205817c93e9a8d42c4baestevel uint_t pgoffset;
03831d35f7499c87d51205817c93e9a8d42c4baestevel pgcnt_t npages;
03831d35f7499c87d51205817c93e9a8d42c4baestevel pfn_t pfn;
03831d35f7499c87d51205817c93e9a8d42c4baestevel uint64_t base;
03831d35f7499c87d51205817c93e9a8d42c4baestevel caddr_t kaddr;
03831d35f7499c87d51205817c93e9a8d42c4baestevel uint_t mapping_attr;
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel base = (uint64_t)SBDP_CPU_SRAM_ADDR & (~MMU_PAGEOFFSET);
03831d35f7499c87d51205817c93e9a8d42c4baestevel pfn = mmu_btop(base);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Do a quick sanity check to make sure we are in I/O space.
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (pf_is_memory(pfn))
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (DDI_FAILURE);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel pgoffset = (ulong_t)SBDP_CPU_SRAM_ADDR & MMU_PAGEOFFSET;
03831d35f7499c87d51205817c93e9a8d42c4baestevel npages = mmu_btopr(SBDP_CPU_SRAM_SIZE + pgoffset);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel kaddr = vmem_alloc(heap_arena, ptob(npages), VM_NOSLEEP);
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (kaddr == NULL)
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (DDI_ME_NORESOURCES);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel mapping_attr = PROT_READ;
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Now map in the pages we've allocated...
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel hat_devload(kas.a_hat, kaddr, ptob(npages), pfn, mapping_attr,
03831d35f7499c87d51205817c93e9a8d42c4baestevel HAT_LOAD_LOCK);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel *vaddrp = kaddr + pgoffset;
03831d35f7499c87d51205817c93e9a8d42c4baestevel *npp = npages;
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (DDI_SUCCESS);
03831d35f7499c87d51205817c93e9a8d42c4baestevel}
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevelstatic void
03831d35f7499c87d51205817c93e9a8d42c4baestevelcpusram_unmap(caddr_t *vaddrp, pgcnt_t npages)
03831d35f7499c87d51205817c93e9a8d42c4baestevel{
03831d35f7499c87d51205817c93e9a8d42c4baestevel uint_t pgoffset;
03831d35f7499c87d51205817c93e9a8d42c4baestevel caddr_t base;
03831d35f7499c87d51205817c93e9a8d42c4baestevel caddr_t addr = *vaddrp;
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel pgoffset = (ulong_t)SBDP_CPU_SRAM_ADDR & MMU_PAGEOFFSET;
03831d35f7499c87d51205817c93e9a8d42c4baestevel base = addr - pgoffset;
03831d35f7499c87d51205817c93e9a8d42c4baestevel hat_unload(kas.a_hat, base, ptob(npages), HAT_UNLOAD_UNLOCK);
03831d35f7499c87d51205817c93e9a8d42c4baestevel vmem_free(heap_arena, base, ptob(npages));
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel *vaddrp = 0;
03831d35f7499c87d51205817c93e9a8d42c4baestevel}
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevelstatic void
03831d35f7499c87d51205817c93e9a8d42c4baestevelsbdp_cpu_shutdown_self(void)
03831d35f7499c87d51205817c93e9a8d42c4baestevel{
03831d35f7499c87d51205817c93e9a8d42c4baestevel cpu_t *cp = CPU;
03831d35f7499c87d51205817c93e9a8d42c4baestevel int cpuid = cp->cpu_id;
03831d35f7499c87d51205817c93e9a8d42c4baestevel extern void flush_windows(void);
03831d35f7499c87d51205817c93e9a8d42c4baestevel uint64_t pa = va_to_pa((void *)sbdp_valp);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel stdphys(pa, 8);
03831d35f7499c87d51205817c93e9a8d42c4baestevel flush_windows();
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel (void) spl8();
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel stdphys(pa, 6);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel ASSERT(cp->cpu_intr_actv == 0);
03831d35f7499c87d51205817c93e9a8d42c4baestevel ASSERT(cp->cpu_thread == cp->cpu_idle_thread ||
03831d35f7499c87d51205817c93e9a8d42c4baestevel cp->cpu_thread == cp->cpu_startup_thread);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel cp->cpu_flags = CPU_OFFLINE | CPU_QUIESCED | CPU_POWEROFF;
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel CPU_SIGNATURE(OS_SIG, SIGST_DETACHED, SIGSUBST_NULL, cpuid);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel stdphys(pa, 7);
03831d35f7499c87d51205817c93e9a8d42c4baestevel sbdp_cpu_stop_self(pa);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel cmn_err(CE_PANIC, "sbdp_cpu_shutdown_self: CPU %d FAILED TO SHUTDOWN",
03831d35f7499c87d51205817c93e9a8d42c4baestevel cpuid);
03831d35f7499c87d51205817c93e9a8d42c4baestevel}
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baesteveltypedef struct {
03831d35f7499c87d51205817c93e9a8d42c4baestevel int node;
03831d35f7499c87d51205817c93e9a8d42c4baestevel int board;
03831d35f7499c87d51205817c93e9a8d42c4baestevel int non_panther_cpus;
03831d35f7499c87d51205817c93e9a8d42c4baestevel} sbdp_node_walk_t;
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevelstatic int
03831d35f7499c87d51205817c93e9a8d42c4baestevelsbdp_find_non_panther_cpus(dev_info_t *dip, void *node_args)
03831d35f7499c87d51205817c93e9a8d42c4baestevel{
03831d35f7499c87d51205817c93e9a8d42c4baestevel int impl, cpuid, portid;
03831d35f7499c87d51205817c93e9a8d42c4baestevel int buflen;
03831d35f7499c87d51205817c93e9a8d42c4baestevel char buf[OBP_MAXPROPNAME];
03831d35f7499c87d51205817c93e9a8d42c4baestevel sbdp_node_walk_t *args = (sbdp_node_walk_t *)node_args;
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip,
03831d35f7499c87d51205817c93e9a8d42c4baestevel DDI_PROP_DONTPASS, OBP_DEVICETYPE, (caddr_t)buf,
03831d35f7499c87d51205817c93e9a8d42c4baestevel &buflen) != DDI_PROP_SUCCESS) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (DDI_WALK_CONTINUE);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (strcmp(buf, "cpu") != 0) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (DDI_WALK_CONTINUE);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel if ((impl = ddi_getprop(DDI_DEV_T_ANY, dip,
03831d35f7499c87d51205817c93e9a8d42c4baestevel DDI_PROP_DONTPASS, "implementation#", -1)) == -1) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (DDI_WALK_CONTINUE);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel if ((cpuid = ddi_getprop(DDI_DEV_T_ANY, dip,
03831d35f7499c87d51205817c93e9a8d42c4baestevel DDI_PROP_DONTPASS, "cpuid", -1)) == -1) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (DDI_WALK_CONTINUE);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel portid = SG_CPUID_TO_PORTID(cpuid);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel /* filter out nodes not on this board */
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (SG_PORTID_TO_BOARD_NUM(portid) != args->board ||
03831d35f7499c87d51205817c93e9a8d42c4baestevel SG_PORTID_TO_NODEID(portid) != args->node) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (DDI_WALK_PRUNECHILD);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel switch (impl) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel case CHEETAH_IMPL:
03831d35f7499c87d51205817c93e9a8d42c4baestevel case CHEETAH_PLUS_IMPL:
03831d35f7499c87d51205817c93e9a8d42c4baestevel case JAGUAR_IMPL:
03831d35f7499c87d51205817c93e9a8d42c4baestevel args->non_panther_cpus++;
03831d35f7499c87d51205817c93e9a8d42c4baestevel break;
03831d35f7499c87d51205817c93e9a8d42c4baestevel case PANTHER_IMPL:
03831d35f7499c87d51205817c93e9a8d42c4baestevel break;
03831d35f7499c87d51205817c93e9a8d42c4baestevel default:
03831d35f7499c87d51205817c93e9a8d42c4baestevel ASSERT(0);
03831d35f7499c87d51205817c93e9a8d42c4baestevel args->non_panther_cpus++;
03831d35f7499c87d51205817c93e9a8d42c4baestevel break;
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel SBDP_DBG_CPU("cpuid=0x%x, portid=0x%x, impl=0x%x, device_type=%s",
03831d35f7499c87d51205817c93e9a8d42c4baestevel cpuid, portid, impl, buf);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (DDI_WALK_CONTINUE);
03831d35f7499c87d51205817c93e9a8d42c4baestevel}
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevelint
03831d35f7499c87d51205817c93e9a8d42c4baestevelsbdp_board_non_panther_cpus(int node, int board)
03831d35f7499c87d51205817c93e9a8d42c4baestevel{
03831d35f7499c87d51205817c93e9a8d42c4baestevel sbdp_node_walk_t arg = {0};
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel arg.node = node;
03831d35f7499c87d51205817c93e9a8d42c4baestevel arg.board = board;
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Root node doesn't have to be held.
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel ddi_walk_devs(ddi_root_node(), sbdp_find_non_panther_cpus,
03831d35f7499c87d51205817c93e9a8d42c4baestevel (void *)&arg);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (arg.non_panther_cpus);
03831d35f7499c87d51205817c93e9a8d42c4baestevel}