/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (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 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Copyright (c) 2010, Intel Corporation.
* All rights reserved.
*/
/*
* CPU support routines for DR
*/
#include <sys/dditypes.h>
#include <sys/ndi_impldefs.h>
#include <sys/processor.h>
#include <sys/sysmacros.h>
#include <sys/archsystm.h>
#include <sys/machsystm.h>
#include <sys/cpu_module.h>
int
{
#ifdef DEBUG
#else
#endif
return (1);
}
static int
{
int rv;
switch (error) {
case EBUSY:
break;
case EINVAL:
rv = ESBD_INVAL;
break;
case EALREADY:
rv = ESBD_ALREADY;
break;
case ENODEV:
rv = ESBD_NODEV;
break;
case ENOMEM:
rv = ESBD_NOMEM;
break;
default:
rv = ESBD_INVAL;
}
return (rv);
}
/*
* On x86, the "clock-frequency" and cache size device properties may be
* unavailable before CPU starts. If they are unavailabe, just set them to zero.
*/
static void
{
int ecache_size = 0;
if (err) {
return;
}
return;
}
/* read in the CPU speed */
DDI_PROP_DONTPASS, "clock-frequency", 0);
/*
* The ecache property string is not the same
* for all CPU implementations.
*/
switch (cp->sbc_cpu_impl) {
case X86_CPU_IMPL_NEHALEM_EX:
cache_str = "l3-cache-size";
break;
default:
cp->sbc_cpu_impl);
break;
}
/* read in the ecache size */
/*
* If the property is not found in the CPU node,
* it has to be kept in the core or cmp node so
* we just keep looking.
*/
cache_str, 0);
}
/* convert to the proper units */
}
void
{
int cpuid;
int impl;
} else {
}
if (err) {
goto done;
}
if (err) {
goto done;
}
} else {
goto done;
}
/* if true at init time, it must always be true */
else
done:
/* delay transition until fully initialized */
}
int
{
int i;
static fn_t f = "dr_pre_attach_cpu";
PR_CPU("%s...\n", f);
for (i = 0; i < devnum; i++) {
/*
* Print a console message for each attachment
* point. For CMP devices, this means that only
* one message should be printed, no matter how
* many cores are actually present.
*/
}
}
/*
* Block out status threads while creating
* devinfo tree branches
*/
return (0);
}
/*ARGSUSED*/
void
{
int rv;
if (err) {
return;
}
if (err) {
if (err)
sbd_err_clear(&err);
if (err)
sbd_err_clear(&err);
} else {
}
}
/*
* dr_post_attach_cpu
*
* sbd error policy: Does not stop on error. Processes all units in list.
*/
int
{
int i;
int errflag = 0;
static fn_t f = "dr_post_attach_cpu";
PR_CPU("%s...\n", f);
/* Startup and online newly-attached CPUs */
for (i = 0; i < devnum; i++) {
f, up->sbc_cpu_id);
continue;
}
if (cpu_is_poweredoff(cp)) {
if (cpu_poweron(cp) != 0) {
errflag = 1;
}
}
if (cpu_is_offline(cp)) {
if (cpu_online(cp) != 0) {
errflag = 1;
}
}
}
if (errflag)
return (-1);
else
return (0);
}
/*
* dr_pre_release_cpu
*
* sbd error policy: Stops on first error.
*/
int
{
static fn_t f = "dr_pre_release_cpu";
int cpu_flags = 0;
/* allocate status struct storage. */
for (i = 0; i < devnum; i++) {
continue;
}
/*
* On x86 systems, some CPUs can't be unconfigured.
* For example, CPU0 can't be unconfigured because many other
* components have a dependency on it.
* This check determines if a CPU is currently in use and
* returns a "Device busy" error if so.
*/
for (c = 0; c < cix; c++) {
rv = -1;
break;
}
}
}
if (c < cix)
break;
rv = -1;
break;
}
/* used by dr_cancel_cpu during error flow */
if (CPU_ACTIVE(cp)) {
PR_CPU("%s: failed to offline cpu %d\n", f,
cpuid);
if (disp_bound_threads(cp, 0)) {
}
rv = -1;
break;
} else
lastoffline = i;
}
if (!rv) {
if (err) {
rv = -1;
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 = lastoffline; i >= 0; i--) {
(void) dr_cancel_cpu(up);
}
}
return (rv);
}
/*
* dr_pre_detach_cpu
*
* sbd error policy: Stops on first error.
*/
int
{
int i;
int cpu_flags = 0;
static fn_t f = "dr_pre_detach_cpu";
PR_CPU("%s...\n", f);
/*
* Block out status threads while destroying devinfo tree
* branches
*/
for (i = 0; i < devnum; i++) {
continue;
}
continue;
/*
* Print a console message for each attachment
* point. For CMP devices, this means that only
* one message should be printed, no matter how
* many cores are actually present.
*/
}
/*
* CPUs were offlined during Release.
*/
if (cpu_is_poweredoff(cp)) {
PR_CPU("%s: cpu %d already powered OFF\n",
f, up->sbc_cpu_id);
continue;
}
if (!cpu_is_offline(cp)) {
/* cpu was onlined after release. Offline it again */
PR_CPU("%s: failed to offline cpu %d\n",
f, up->sbc_cpu_id);
if (disp_bound_threads(cp, 0)) {
}
goto err;
}
}
if (cpu_poweroff(cp) != 0) {
goto err;
} else {
}
}
return (0);
err:
return (-1);
}
/*ARGSUSED*/
void
{
int rv;
return;
}
if (err) {
} else {
if (err) {
} else {
}
}
}
/*ARGSUSED1*/
int
{
static fn_t f = "dr_post_detach_cpu";
PR_CPU("%s...\n", f);
return (0);
}
static void
{
/* Fill in the common status information */
csp->cs_suspend = 0;
/* CPU specific status data */
/*
* 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 */
/* ostate must be UNCONFIGURED */
}
}
/*ARGSUSED2*/
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.
*/
SBD_COMP_CMP));
/* adjust time if necessary */
}
/*
* If any of the cores are configured, the
* entire CMP is marked as configured.
*/
}
}
}
int
{
int cmp;
int core;
int ncpu;
int impl;
ncpu = 0;
KM_SLEEP);
/*
* 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;
continue;
}
ncores = 0;
/* present, but not fully initialized */
continue;
}
/* skip if not present */
continue;
}
/* fetch platform status */
if (err) {
continue;
}
/*
* We should set impl here because the last core
* found might be EMPTY or not present.
*/
}
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.
*/
if (CPU_IMPL_IS_CMP(impl)) {
} else {
}
dsp++;
ncpu++;
}
return (ncpu);
}
/*
* 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 there were
* released.
*/
int
{
int rv = 0;
static fn_t f = "dr_cancel_cpu";
/*
* CPU had been online, go ahead
* bring it back online.
*/
if (cpu_is_poweredoff(cp)) {
if (cpu_poweron(cp)) {
rv = -1;
}
}
if (cpu_online(cp)) {
f, up->sbc_cpu_id);
rv = -1;
}
}
if (cpu_intr_disable(cp) != 0) {
"disable interrupts on cpu %d", f,
up->sbc_cpu_id);
}
}
}
}
return (rv);
}
int
{
static fn_t f = "dr_disconnect_cpu";
PR_CPU("%s...\n", f);
/*
* Cpus were never brought in and so are still
* effectively disconnected, so nothing to do here.
*/
return (0);
}
return (0);
else {
return (-1);
}
/*NOTREACHED*/
}