2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A
2N/A/*
2N/A * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A/*
2N/A * Enumerate a CPU node
2N/A */
2N/A#include <sys/types.h>
2N/A#include <strings.h>
2N/A#include <sys/fm/protocol.h>
2N/A#include <fm/topo_mod.h>
2N/A#include <fm/topo_hc.h>
2N/A#include "pi_impl.h"
2N/A
2N/A#define _ENUM_NAME "enum_cpu"
2N/A
2N/Atypedef struct cpuwalk_s {
2N/A topo_mod_t *mod;
2N/A char *serial;
2N/A} cpuwalk_t;
2N/A
2N/Astatic int pi_enum_cpu_serial(topo_mod_t *, md_t *, mde_cookie_t, char **);
2N/Astatic int pi_enum_cpu_serial_cb(md_t *, mde_cookie_t, mde_cookie_t, void *);
2N/A
2N/Aint
2N/Api_enum_cpu(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node,
2N/A topo_instance_t inst, tnode_t *t_parent, const char *hc_name,
2N/A tnode_t **t_node)
2N/A{
2N/A int result;
2N/A int err;
2N/A int cpumask;
2N/A nvlist_t *asru = NULL;
2N/A char *serial = NULL;
2N/A
2N/A *t_node = NULL;
2N/A
2N/A /*
2N/A * Create the basic topology node for the CPU using the generic
2N/A * enumerator.
2N/A */
2N/A result = pi_enum_generic_impl(mod, mdp, mde_node, inst, t_parent,
2N/A t_parent, hc_name, _ENUM_NAME, t_node, SUN4VPI_ENUM_ADD_SERIAL);
2N/A if (result != 0) {
2N/A /* Error messages are printed by the generic routine */
2N/A return (result);
2N/A }
2N/A
2N/A /*
2N/A * If the hc_name is "chip" or "core", a topo method is set to compute
2N/A * asru, otherwise for "cpu" and "strand", set asru to CPU scheme FMRI.
2N/A */
2N/A if (strcmp(hc_name, CHIP) == 0 || strcmp(hc_name, CORE) == 0) {
2N/A result = topo_node_resource(*t_node, &asru, &err);
2N/A if (result != 0) {
2N/A topo_mod_dprintf(mod,
2N/A "%s node_0x%llx failed to get resource: %s\n",
2N/A _ENUM_NAME, (uint64_t)mde_node, topo_strerror(err));
2N/A return (-1);
2N/A }
2N/A result = topo_node_asru_set(*t_node, asru, TOPO_ASRU_COMPUTE,
2N/A &err);
2N/A if (result != 0) {
2N/A topo_mod_dprintf(mod,
2N/A "%s node_0x%llx failed to set ASRU: %s\n",
2N/A _ENUM_NAME, (uint64_t)mde_node, topo_strerror(err));
2N/A nvlist_free(asru);
2N/A return (-1);
2N/A }
2N/A } else {
2N/A /*
2N/A * Compute ASRU for "cpu" and "strand" node.
2N/A * Get the parameters required to create an FMRI. The cpumask
2N/A * is on the chip itself and while it may be part of an ereport
2N/A * payload is unavailable here, so we set it to zero.
2N/A */
2N/A cpumask = 0;
2N/A
2N/A /*
2N/A * Find the serial number, which is on the "chip" node, not the
2N/A * "cpu" node.
2N/A */
2N/A result = pi_enum_cpu_serial(mod, mdp, mde_node, &serial);
2N/A if (result != 0 || serial == NULL) {
2N/A topo_mod_dprintf(mod,
2N/A "%s node_0x%llx failed to find serial number.\n",
2N/A _ENUM_NAME, (uint64_t)mde_node);
2N/A return (result);
2N/A }
2N/A
2N/A /*
2N/A * Create a CPU scheme FMRI and set it as the ASRU for the CPU
2N/A * node
2N/A */
2N/A asru = topo_mod_cpufmri(mod, FM_CPU_SCHEME_VERSION, inst,
2N/A cpumask, serial);
2N/A topo_mod_strfree(mod, serial);
2N/A if (asru == NULL) {
2N/A topo_mod_dprintf(mod, "%s node_0x%llx failed to "
2N/A "compute cpu scheme ASRU: %s\n",
2N/A _ENUM_NAME, (uint64_t)mde_node,
2N/A topo_strerror(topo_mod_errno(mod)));
2N/A return (-1);
2N/A }
2N/A
2N/A /* Set the ASRU on the node without flags (the 0) */
2N/A result = topo_node_asru_set(*t_node, asru, 0, &err);
2N/A }
2N/A
2N/A nvlist_free(asru);
2N/A if (result != 0) {
2N/A topo_mod_dprintf(mod,
2N/A "%s node_0x%llx failed to set ASRU: %s\n", _ENUM_NAME,
2N/A (uint64_t)mde_node, topo_strerror(err));
2N/A return (-1);
2N/A }
2N/A
2N/A return (0);
2N/A}
2N/A
2N/A
2N/Astatic int
2N/Api_enum_cpu_serial(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node,
2N/A char **serial)
2N/A{
2N/A int result;
2N/A cpuwalk_t args;
2N/A mde_str_cookie_t component_cookie;
2N/A mde_str_cookie_t back_cookie;
2N/A
2N/A args.mod = mod;
2N/A args.serial = NULL;
2N/A
2N/A /*
2N/A * Search backwards through the PRI graph, starting at the current
2N/A * strand (aka cpu) mde_node, and find the MD_STR_CHIP node. This
2N/A * node has the serial number for the cpu.
2N/A */
2N/A component_cookie = md_find_name(mdp, MD_STR_COMPONENT);
2N/A back_cookie = md_find_name(mdp, MD_STR_BACK);
2N/A
2N/A result = md_walk_dag(mdp, mde_node, component_cookie, back_cookie,
2N/A pi_enum_cpu_serial_cb, (void *)&args);
2N/A *serial = args.serial;
2N/A
2N/A return (result);
2N/A}
2N/A
2N/A
2N/A/*ARGSUSED*/
2N/Astatic int
2N/Api_enum_cpu_serial_cb(md_t *mdp, mde_cookie_t mde_parent,
2N/A mde_cookie_t mde_node, void *private)
2N/A{
2N/A char *hc_name;
2N/A cpuwalk_t *args = (cpuwalk_t *)private;
2N/A
2N/A if (args == NULL) {
2N/A return (MDE_WALK_ERROR);
2N/A }
2N/A args->serial = NULL;
2N/A
2N/A hc_name = pi_get_topo_hc_name(args->mod, mdp, mde_node);
2N/A if (hc_name != NULL && strcmp(hc_name, MD_STR_CHIP) == 0) {
2N/A args->serial = pi_get_serial(args->mod, mdp, mde_node);
2N/A }
2N/A topo_mod_strfree(args->mod, hc_name);
2N/A
2N/A return ((args->serial == NULL ? MDE_WALK_NEXT : MDE_WALK_DONE));
2N/A}