/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* CPU support routines for DR
*/
#include <sys/dditypes.h>
#include <sys/ddi_impldefs.h>
#include <sys/ndi_impldefs.h>
#include <sys/processor.h>
#include <sys/mem_config.h>
#include <sys/cpu_sgnblk_defs.h>
#include <sys/sysmacros.h>
#include <sys/machsystm.h>
#include <sys/spitregs.h>
#include <sys/archsystm.h>
#include <vm/hat_sfmmu.h>
#include <sys/cpu_module.h>
#include <sys/cheetahregs.h>
#include <sys/autoconf.h>
void
{
int ecache_size = 0;
/* read in the CPU speed */
DDI_PROP_DONTPASS, "clock-frequency", 0);
ASSERT(clock_freq != 0);
/*
* The ecache property string is not the same
* for all CPU implementations.
*/
switch (cp->sbc_cpu_impl) {
case CHEETAH_IMPL:
case CHEETAH_PLUS_IMPL:
cache_str = "ecache-size";
break;
case JAGUAR_IMPL:
cache_str = "l2-cache-size";
break;
case PANTHER_IMPL:
cache_str = "l3-cache-size";
break;
default:
ASSERT(0);
break;
}
/* read in the ecache size */
DDI_PROP_DONTPASS, cache_str, 0);
}
/*
* In the case the size is still 0,
* a zero value will be displayed running non-debug.
*/
ASSERT(ecache_size != 0);
/* convert to the proper units */
}
static void
{
int namelen;
csp->cs_suspend = 0;
/*
* If we have marked the cpu's condition previously
* then don't rewrite it
*/
/*
* If the speed and ecache properties have not been
* cached yet, read them in from the device tree.
*/
/* use the cached speed and ecache values */
}
static void
{
int core;
/*
* Fill in the common status information based
* on the data for the first core.
*/
/* CMP specific status data */
/*
* Walk through the data for the remaining cores.
* Make any adjustments to the common status data,
* or the shared CMP specific data if necessary.
*/
/*
* The following properties should be the same
* for all the cores of the CMP.
*/
/*
* Jaguar has a split ecache, so the ecache
* for each core must be added together to
* get the total ecache for the whole chip.
*/
}
/* adjust time if necessary */
}
/*
* If any of the cores are configured, the
* entire CMP is marked as configured.
*/
}
}
}
int
{
int cmp;
int ncpu;
/*
* Grab the status lock before accessing the dip as we allow
* concurrent status and branch unconfigure and disconnect.
*
* The disconnect thread clears the present devset first
* and then destroys dips. It is possible that the status
* thread checks the present devset before they are cleared
* but accesses the dip after they are destroyed causing a
* panic. To prevent this, the status thread should check
* the present devset and access dips with status lock held.
* Similarly disconnect thread should clear the present devset
* and destroy dips with status lock held.
*/
/*
* Only look for requested devices that are actually present.
*/
/*
* Treat every CPU as a CMP. In the case where the
* device is not a CMP, treat it as a CMP with only
* one core.
*/
int ncores;
int core;
continue;
ncores = 0;
int unit;
/*
* Check to make sure the cpu is in a state
* where its fully initialized.
*/
continue;
continue;
}
if (ncores == 0)
continue;
/*
* Store the data to the outgoing array. If the
* device is a CMP, combine all the data for the
* cores into a single stat structure.
*
* The check for a CMP device uses the last core
* found, assuming that all cores will have the
* same implementation.
*/
} else {
}
dsp++;
ncpu++;
}
return (ncpu);
}
int
{
static fn_t f = "sbd_pre_release_cpu";
/*
* May have to juggle bootproc in release_component
*/
if (cpuid < 0) {
"sbd:%s: failed to get cpuid for "
"dip (0x%p)", f, (void *)dip);
continue;
} else {
break;
}
}
if (unit < 0) {
"sbd:%s: failed to get unit (cpu %d)",
f, cpuid);
continue;
} else {
break;
}
}
int cpu_offline_flags = 0;
PR_CPU("%s: offlining cpuid %d unit %d", f,
"%s: failed to offline cpu %d",
f, cpuid);
rv = -1;
"bound to cpu %d",
}
break;
}
}
if (rv == 0) {
break;
}
}
if (rv)
break;
}
if (rv) {
/*
* Need to unwind others since at this level (pre-release)
* the device state has not yet transitioned and failures
* will prevent us from reaching the "post" release
* function where states are normally transitioned.
*/
for (; i >= 0; i--, devlist--) {
if (unit < 0) {
"sbd:%s: failed to get unit for "
"dip (0x%p)", f, (void *)dip);
break;
}
}
}
return (rv);
}
int
{
int i;
int unit;
static fn_t f = "sbd_pre_attach_cpu";
PR_CPU("%s...\n", f);
if (cpuid < 0) {
"sbd:%s: failed to get cpuid for "
"dip (0x%p)", f, (void *)dip);
continue;
} else {
break;
}
}
if (unit < 0) {
"sbd:%s: failed to get unit (cpu %d)",
f, cpuid);
continue;
} else {
break;
}
}
PR_CPU("%s: attach cpu-unit (%d.%d)\n",
if (dstate == SBD_STATE_UNCONFIGURED) {
/*
* If we're coming from the UNCONFIGURED
* state then the cpu's sigblock will
* still be mapped in. Need to unmap it
* before continuing with attachment.
*/
PR_CPU("%s: unmapping sigblk for cpu %d\n",
f, cpuid);
/* platform specific release of sigblk */
}
}
return (0);
}
int
{
int i;
static fn_t f = "sbd_post_attach_cpu";
int unit;
/* Startup and online newly-attached CPUs */
if (cpuid < 0) {
"sbd:%s: failed to get cpuid for "
"dip (0x%p)", f, (void *)dip);
continue;
} else {
break;
}
}
"sbd:%s: cpu_get failed for cpu %d",
f, cpuid);
continue;
} else {
break;
}
}
if (cpu_is_poweredoff(cp)) {
if (cpu_poweron(cp) != 0) {
"%s: failed to power-on cpu %d",
f, cpuid);
break;
}
sbp->sb_cpupath[i]);
}
if (cpu_is_offline(cp)) {
if (cpu_online(cp) != 0) {
"%s: failed to online cpu %d",
}
sbp->sb_cpupath[i]);
}
/*
* if there is no error mark the cpu as OK to use
*/
if (SBD_GET_ERR(ep) == 0) {
if (unit < 0) {
"sbd:%s: failed to get unit "
"(cpu %d)", f, cpuid);
continue;
} else {
SBD_HD2ERR(hp));
break;
}
}
}
}
if (err != ESBD_NOERROR) {
return (-1);
} else {
return (0);
}
}
int
{
int i;
int unit;
static fn_t f = "sbd_pre_detach_cpu";
int rv = 0;
PR_CPU("%s...\n", f);
if (cpuid < 0) {
"sbd:%s: failed to get cpuid for "
"dip (0x%p)", f, (void *)dip);
continue;
} else {
break;
}
}
"sbd:%s: failed to get cpu %d",
f, cpuid);
continue;
} else {
break;
}
}
if (unit < 0) {
"sbd:%s: failed to get unit (cpu %d)",
f, cpuid);
continue;
} else {
break;
}
}
PR_CPU("%s: OS detach cpu-unit (%d.%d)\n",
/*
* CPUs were offlined during Release.
*/
if (cpu_is_poweredoff(cpu)) {
continue;
}
if (cpu_is_offline(cpu)) {
int e;
if (e = cpu_poweroff(cpu)) {
"%s: failed to power-off cpu %d "
"(errno %d)",
rv = -1;
break;
} else {
PR_CPU("%s: cpu %d powered OFF\n",
f, cpuid);
}
} else {
rv = -1;
break;
}
}
return (rv);
}
int
{
static fn_t f = "sbd_post_detach_cpu";
int i;
int unit;
PR_CPU("%s...\n", f);
/*
* We should be holding the cpu_lock at this point,
* and should have blocked device tree changes.
*/
if (cpuid < 0) {
"sbd:%s: failed to get cpuid for "
"dip (0x%p)", f, (void *)dip);
continue;
} else {
break;
}
}
/*
* if there is no error mark the cpu as unusable
*/
if (SBD_GET_ERR(ep) == 0) {
if (unit < 0) {
"sbd:%s: failed to get unit "
"(cpu %d)", f, cpuid);
continue;
} else {
SBD_HD2ERR(hp));
break;
}
}
}
}
return (0);
}
/*
* Cancel previous release operation for cpu. For cpus this means simply
* bringing cpus that were offline back online. Note that they had to have been
* online at the time they were released. If attempting to power on or online
* a CPU fails, SBD_CPUERR_FATAL is returned to indicate that the CPU appears to
* be unsalvageable. If a CPU reaches an online or nointr state but can't be
* taken to a "lesser" state, SBD_CPUERR_RECOVERABLE is returned to indicate
* that it was not returned to its original state but appears to be functional.
* Note that the latter case can occur due to unexpected but non-erroneous CPU
* manipulation (e.g. by the "psradm" command) during the DR operation.
*/
int
{
static fn_t f = "sbd_cancel_cpu";
int cpu_offline_flags = 0;
PR_ALL("%s...\n", f);
/*
* If CPU should remain off, nothing needs to be done.
*/
return (rv);
/*
* CPU had been either offline, online, or set to no-intr. We
* will return a component to its original state that it was
* prior to the failed DR operation. There is a possible race
* condition between the calls to this function and re-obtaining
* the cpu_lock where a cpu state could change. Because of this
* we can't externally document that we are trying to roll cpus
* back to their original state, but we believe a best effort
* should be made.
*/
/*
* The following will compare the cpu's current state with a
* snapshot of its state taken before the failed DR operation
* had started.
*/
/* POWEROFF */
if (cpu_is_poweredoff(cpup)) {
if (cpu_poweron(cpup)) {
"sbd:%s: failed to power-on cpu %d",
f, cp->sbc_cpu_id);
goto out;
}
}
/* OFFLINE */
if (cpu_is_offline(cpup)) {
PR_CPU("%s: leaving cpu %d OFFLINE\n",
f, cp->sbc_cpu_id);
} else if (cpu_online(cpup)) {
"sbd:%s: failed to online cpu %d",
f, cp->sbc_cpu_id);
goto out;
} else {
}
}
/* ONLINE */
if (cpu_is_online(cpup)) {
PR_CPU("%s: setting cpu %d ONLINE\n",
f, cp->sbc_cpu_id);
"sbd:%s: failed to offline"
goto out;
}
if (cpu_intr_disable(cpup)) {
"disable interrupts on cpu %d",
f, cp->sbc_cpu_id);
} else {
PR_CPU("%s: setting cpu %d to NOINTR"
" (was online)\n",
f, cp->sbc_cpu_id);
}
goto out;
}
}
/* NOINTR */
if (cpu_is_nointr(cpup)) {
PR_CPU("%s: setting cpu %d ONLINE"
"(was nointr)\n",
f, cp->sbc_cpu_id);
}
"sbd:%s: failed to offline"
}
}
}
out:
return (rv);
}
int
{
int rv;
static fn_t f = "sbd_connect_cpu";
/*
* get dip for cpu just located in tree walk
*/
"sbd:%s: bad dip for cpu unit %d board %d",
return (-1);
}
PR_CPU("%s...\n", f);
} else {
return (0);
}
/*
* if sbd has attached this cpu, no need to bring
* it out of reset
*/
return (0);
}
if (cpuid == -1) {
return (-1);
}
/*
* if the cpu is already under Solaris control,
* do not wake it up
*/
return (0);
}
if (rv != 0) {
sbp->sb_memaccess_ok = 0;
"sbd:%s: failed to wake up cpu unit %d board %d",
return (rv);
}
return (rv);
}
int
{
int rv;
static fn_t f = "sbd_disconnect_cpu";
PR_CPU("%s...\n", f);
if (rv != 0) {
}
return (rv);
}