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) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A#include <string.h>
2N/A#include <umem.h>
2N/A#include <sys/mdesc.h>
2N/A#include <sys/fm/ldom.h>
2N/A
2N/A#include <cpu_mdesc.h>
2N/A
2N/Astatic void *
2N/Acpu_alloc(size_t size)
2N/A{
2N/A return (umem_alloc(size, UMEM_DEFAULT));
2N/A}
2N/A
2N/Astatic void
2N/Acpu_free(void *data, size_t size)
2N/A{
2N/A umem_free(data, size);
2N/A}
2N/A
2N/Amd_proc_t *
2N/Acpu_find_proc(md_info_t *chip, uint32_t procid) {
2N/A int i;
2N/A md_proc_t *procp;
2N/A
2N/A /* search the processor based on the physical id */
2N/A for (i = 0, procp = chip->procs; i < chip->nprocs; i++, procp++) {
2N/A if (procp->serialno != 0 && procid == procp->id) {
2N/A return (procp);
2N/A }
2N/A }
2N/A
2N/A return (NULL);
2N/A}
2N/A
2N/Amd_cpumap_t *
2N/Acpu_find_cpumap(md_info_t *chip, uint32_t cpuid) {
2N/A int i;
2N/A md_cpumap_t *mcmp;
2N/A
2N/A for (i = 0, mcmp = chip->cpus; i < chip->ncpus; i++, mcmp++) {
2N/A if (cpuid == mcmp->cpumap_pid) {
2N/A return (mcmp);
2N/A }
2N/A }
2N/A return (NULL);
2N/A}
2N/A
2N/Aint
2N/Acpu_get_serialid_mdesc(md_info_t *chip, uint32_t cpuid, uint64_t *serialidp)
2N/A{
2N/A md_cpumap_t *mcmp;
2N/A if ((mcmp = cpu_find_cpumap(chip, cpuid)) != NULL) {
2N/A *serialidp = mcmp->cpumap_serialno;
2N/A return (0);
2N/A }
2N/A return (-1);
2N/A}
2N/A
2N/Astatic int
2N/Acpu_n1_mdesc_init(topo_mod_t *mod, md_t *mdp, md_info_t *chip)
2N/A{
2N/A mde_cookie_t *listp;
2N/A md_cpumap_t *mcmp;
2N/A int i, num_nodes, idx;
2N/A uint64_t x;
2N/A
2N/A num_nodes = md_node_count(mdp);
2N/A listp = topo_mod_zalloc(mod, sizeof (mde_cookie_t) * num_nodes);
2N/A
2N/A chip->ncpus = md_scan_dag(mdp,
2N/A MDE_INVAL_ELEM_COOKIE,
2N/A md_find_name(mdp, "cpu"),
2N/A md_find_name(mdp, "fwd"),
2N/A listp);
2N/A topo_mod_dprintf(mod, "Found %d cpus\n", chip->ncpus);
2N/A
2N/A chip->cpus = topo_mod_zalloc(mod, chip->ncpus * sizeof (md_cpumap_t));
2N/A chip->nprocs = chip->ncpus;
2N/A chip->procs = topo_mod_zalloc(mod, chip->nprocs * sizeof (md_proc_t));
2N/A
2N/A for (idx = 0, mcmp = chip->cpus; idx < chip->ncpus; idx++, mcmp++) {
2N/A
2N/A if (md_get_prop_val(mdp, listp[idx], MD_STR_ID, &x) < 0)
2N/A x = (uint64_t)-1; /* invalid value */
2N/A mcmp->cpumap_id = x;
2N/A
2N/A if (md_get_prop_val(mdp, listp[idx], MD_STR_PID, &x) < 0)
2N/A x = mcmp->cpumap_id;
2N/A mcmp->cpumap_pid = x;
2N/A
2N/A mcmp->cpumap_serialno = 0;
2N/A mcmp->cpumap_chipidx = -1;
2N/A if (md_get_prop_val(mdp, listp[idx], MD_STR_CPU_SERIAL,
2N/A &mcmp->cpumap_serialno) < 0) {
2N/A continue;
2N/A }
2N/A if (mcmp->cpumap_serialno == 0) {
2N/A continue;
2N/A }
2N/A
2N/A /*
2N/A * This PRI/MD has no indentity info. of the FRU and no
2N/A * physical proc id.
2N/A * Find if there is already an existing processor entry
2N/A * Assign procid based on the order found during reading
2N/A */
2N/A for (i = 0; i < chip->nprocs &&
2N/A chip->procs[i].serialno != 0; i++) {
2N/A if (mcmp->cpumap_serialno == chip->procs[i].serialno) {
2N/A break;
2N/A }
2N/A }
2N/A if (i < chip->nprocs) {
2N/A mcmp->cpumap_chipidx = i;
2N/A if (chip->procs[i].serialno == 0) {
2N/A chip->procs[i].id = i;
2N/A chip->procs[i].serialno = mcmp->cpumap_serialno;
2N/A topo_mod_dprintf(mod,
2N/A "chip[%d] serial is %llx\n",
2N/A i, chip->procs[i].serialno);
2N/A }
2N/A }
2N/A
2N/A }
2N/A
2N/A topo_mod_free(mod, listp, sizeof (mde_cookie_t) * num_nodes);
2N/A
2N/A return (0);
2N/A}
2N/A
2N/Astatic int
2N/Acpu_n2_mdesc_init(topo_mod_t *mod, md_t *mdp, md_info_t *chip)
2N/A{
2N/A mde_cookie_t *list1p, *list2p;
2N/A md_cpumap_t *mcmp;
2N/A md_proc_t *procp;
2N/A md_fru_t *frup;
2N/A int i, j, cnt;
2N/A int procid_flag = 0;
2N/A int nnode, ncomp, nproc, ncpu;
2N/A char *str = NULL;
2N/A uint64_t x, sn;
2N/A char *strserial, *end;
2N/A
2N/A nnode = md_node_count(mdp);
2N/A list1p = topo_mod_zalloc(mod, sizeof (mde_cookie_t) * nnode);
2N/A
2N/A /* Count the number of processors and strands */
2N/A ncomp = md_scan_dag(mdp,
2N/A MDE_INVAL_ELEM_COOKIE,
2N/A md_find_name(mdp, MD_STR_COMPONENT),
2N/A md_find_name(mdp, "fwd"),
2N/A list1p);
2N/A if (ncomp <= 0) {
2N/A topo_mod_dprintf(mod, "Component nodes not found\n");
2N/A topo_mod_free(mod, list1p, sizeof (mde_cookie_t) * nnode);
2N/A return (-1);
2N/A }
2N/A for (i = 0, nproc = 0, ncpu = 0; i < ncomp; i++) {
2N/A if (md_get_prop_str(mdp, list1p[i], MD_STR_TYPE, &str) == 0 &&
2N/A str != NULL && strcmp(str, MD_STR_PROCESSOR) == 0) {
2N/A nproc++;
2N/A /* check if the physical id exists */
2N/A if (md_get_prop_val(mdp, list1p[i], MD_STR_ID, &x)
2N/A == 0) {
2N/A procid_flag = 1;
2N/A }
2N/A }
2N/A if (md_get_prop_str(mdp, list1p[i], MD_STR_TYPE, &str) == 0 &&
2N/A str && strcmp(str, MD_STR_STRAND) == 0) {
2N/A ncpu++;
2N/A }
2N/A }
2N/A topo_mod_dprintf(mod, "Found %d procs and %d strands\n", nproc, ncpu);
2N/A if (nproc == 0 || ncpu == 0) {
2N/A topo_mod_free(mod, list1p, sizeof (mde_cookie_t) * nnode);
2N/A return (-1);
2N/A }
2N/A
2N/A /* Alloc processors and strand entries */
2N/A list2p = topo_mod_zalloc(mod, sizeof (mde_cookie_t) * 2 * ncpu);
2N/A chip->nprocs = nproc;
2N/A chip->procs = topo_mod_zalloc(mod, nproc * sizeof (md_proc_t));
2N/A chip->ncpus = ncpu;
2N/A chip->cpus = topo_mod_zalloc(mod, ncpu * sizeof (md_cpumap_t));
2N/A
2N/A /* Visit each processor node */
2N/A procp = chip->procs;
2N/A mcmp = chip->cpus;
2N/A for (i = 0, nproc = 0, ncpu = 0; i < ncomp; i++) {
2N/A if (md_get_prop_str(mdp, list1p[i], MD_STR_TYPE, &str) < 0 ||
2N/A str == NULL || strcmp(str, MD_STR_PROCESSOR))
2N/A continue;
2N/A if (md_get_prop_val(mdp, list1p[i], MD_STR_SERIAL, &sn) < 0) {
2N/A if (md_get_prop_str(mdp, list1p[i], MD_STR_SERIAL,
2N/A &strserial) < 0) {
2N/A topo_mod_dprintf(mod,
2N/A "Failed to get the serial number of"
2N/A "proc[%d]\n", nproc);
2N/A continue;
2N/A } else {
2N/A sn = (uint64_t)strtoull(strserial, &end, 16);
2N/A if (strserial == end) {
2N/A topo_mod_dprintf(mod,
2N/A "Failed to convert the serial "
2N/A "string to serial int of "
2N/A "proc[%d]\n", nproc);
2N/A continue;
2N/A }
2N/A }
2N/A }
2N/A procp->serialno = sn;
2N/A
2N/A /* Assign physical proc id */
2N/A procp->id = -1;
2N/A if (procid_flag) {
2N/A if (md_get_prop_val(mdp, list1p[i], MD_STR_ID, &x)
2N/A == 0) {
2N/A procp->id = x;
2N/A }
2N/A } else {
2N/A procp->id = nproc;
2N/A }
2N/A topo_mod_dprintf(mod, "proc %d: sn=%llx, id=%d\n", nproc,
2N/A procp->serialno, procp->id);
2N/A
2N/A /* Get all the strands below this proc */
2N/A cnt = md_scan_dag(mdp,
2N/A list1p[i],
2N/A md_find_name(mdp, MD_STR_COMPONENT),
2N/A md_find_name(mdp, "fwd"),
2N/A list2p);
2N/A topo_mod_dprintf(mod, "proc[%llx]: Found %d fwd components\n",
2N/A sn, cnt);
2N/A if (cnt <= 0) {
2N/A nproc++;
2N/A procp++;
2N/A continue;
2N/A }
2N/A for (j = 0; j < cnt; j++) {
2N/A /* Consider only the strand nodes */
2N/A if (md_get_prop_str(mdp, list2p[j], MD_STR_TYPE, &str)
2N/A < 0 || str == NULL || strcmp(str, MD_STR_STRAND))
2N/A continue;
2N/A
2N/A if (md_get_prop_val(mdp, list2p[j], MD_STR_ID, &x) < 0)
2N/A x = (uint64_t)-1; /* invalid value */
2N/A mcmp->cpumap_id = x;
2N/A
2N/A if (md_get_prop_val(mdp, list2p[j], MD_STR_PID, &x) < 0)
2N/A x = mcmp->cpumap_id;
2N/A mcmp->cpumap_pid = x;
2N/A
2N/A mcmp->cpumap_serialno = sn;
2N/A mcmp->cpumap_chipidx = nproc;
2N/A ncpu++;
2N/A mcmp++;
2N/A }
2N/A
2N/A /*
2N/A * To get the fru of this proc, follow the back arc up to
2N/A * find the first node whose fru field is set
2N/A */
2N/A cnt = md_scan_dag(mdp,
2N/A list1p[i],
2N/A md_find_name(mdp, MD_STR_COMPONENT),
2N/A md_find_name(mdp, "back"),
2N/A list2p);
2N/A topo_mod_dprintf(mod, "proc[%d]: Found %d back components\n",
2N/A nproc, cnt);
2N/A if (cnt <= 0) {
2N/A nproc++;
2N/A procp++;
2N/A continue;
2N/A }
2N/A for (j = 0; j < cnt; j++) {
2N/A /* test the fru field which must be positive number */
2N/A if ((md_get_prop_val(mdp, list2p[j], MD_STR_FRU, &x)
2N/A == 0) && x > 0)
2N/A break;
2N/A }
2N/A if (j < cnt) {
2N/A /* Found the FRU node, get the fru identity */
2N/A topo_mod_dprintf(mod, "proc[%d] sn=%llx has a fru %d\n",
2N/A nproc, procp->serialno, j);
2N/A frup = topo_mod_zalloc(mod, sizeof (md_fru_t));
2N/A procp->fru = frup;
2N/A if (!md_get_prop_str(mdp, list2p[j], MD_STR_NAC, &str))
2N/A frup->nac = topo_mod_strdup(mod, str);
2N/A else
2N/A frup->nac = topo_mod_strdup(mod, MD_FRU_DEF);
2N/A if (!md_get_prop_str(mdp, list2p[j], MD_STR_PART, &str))
2N/A frup->part = topo_mod_strdup(mod, str);
2N/A if (!md_get_prop_str(mdp, list2p[j], MD_STR_SERIAL,
2N/A &str))
2N/A frup->serial = topo_mod_strdup(mod, str);
2N/A if (!md_get_prop_str(mdp, list2p[j], MD_STR_DASH, &str))
2N/A frup->dash = topo_mod_strdup(mod, str);
2N/A } else {
2N/A topo_mod_dprintf(mod, "proc[%d] sn=%llx has no fru\n",
2N/A i, procp->serialno);
2N/A }
2N/A
2N/A nproc++;
2N/A procp++;
2N/A } /* for i */
2N/A
2N/A topo_mod_free(mod, list1p, sizeof (mde_cookie_t) * nnode);
2N/A topo_mod_free(mod, list2p, sizeof (mde_cookie_t) * 2*chip->ncpus);
2N/A
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * Extract from the PRI the processor, strand and their fru identity
2N/A */
2N/Aint
2N/Acpu_mdesc_init(topo_mod_t *mod, md_info_t *chip)
2N/A{
2N/A int rc = -1;
2N/A md_t *mdp;
2N/A ssize_t bufsiz = 0;
2N/A uint64_t *bufp;
2N/A ldom_hdl_t *lhp;
2N/A uint32_t type = 0;
2N/A
2N/A /* get the PRI/MD */
2N/A if ((lhp = ldom_init(cpu_alloc, cpu_free)) == NULL) {
2N/A topo_mod_dprintf(mod, "ldom_init() failed\n");
2N/A return (topo_mod_seterrno(mod, EMOD_NOMEM));
2N/A }
2N/A
2N/A (void) ldom_get_type(lhp, &type);
2N/A if ((type & LDOM_TYPE_CONTROL) != 0) {
2N/A bufsiz = ldom_get_core_md(lhp, &bufp);
2N/A } else {
2N/A bufsiz = ldom_get_local_md(lhp, &bufp);
2N/A }
2N/A if (bufsiz <= 0) {
2N/A topo_mod_dprintf(mod, "failed to get the PRI/MD\n");
2N/A ldom_fini(lhp);
2N/A return (-1);
2N/A }
2N/A
2N/A if ((mdp = md_init_intern(bufp, cpu_alloc, cpu_free)) == NULL ||
2N/A md_node_count(mdp) <= 0) {
2N/A cpu_free(bufp, (size_t)bufsiz);
2N/A ldom_fini(lhp);
2N/A return (-1);
2N/A }
2N/A
2N/A /*
2N/A * N1 MD contains cpu nodes while N2 MD contains component nodes.
2N/A */
2N/A if (md_find_name(mdp, MD_STR_COMPONENT) != MDE_INVAL_STR_COOKIE) {
2N/A rc = cpu_n2_mdesc_init(mod, mdp, chip);
2N/A } else if (md_find_name(mdp, MD_STR_CPU) != MDE_INVAL_STR_COOKIE) {
2N/A rc = cpu_n1_mdesc_init(mod, mdp, chip);
2N/A } else {
2N/A topo_mod_dprintf(mod, "Unsupported PRI/MD\n");
2N/A rc = -1;
2N/A }
2N/A
2N/A cpu_free(bufp, (size_t)bufsiz);
2N/A (void) md_fini(mdp);
2N/A ldom_fini(lhp);
2N/A
2N/A return (rc);
2N/A}
2N/A
2N/Avoid
2N/Acpu_mdesc_fini(topo_mod_t *mod, md_info_t *chip)
2N/A{
2N/A int i;
2N/A md_proc_t *procp;
2N/A md_fru_t *frup;
2N/A
2N/A if (chip->cpus != NULL)
2N/A topo_mod_free(mod, chip->cpus,
2N/A chip->ncpus * sizeof (md_cpumap_t));
2N/A
2N/A if (chip->procs != NULL) {
2N/A procp = chip->procs;
2N/A for (i = 0; i < chip->nprocs; i++) {
2N/A if ((frup = procp->fru) != NULL) {
2N/A topo_mod_strfree(mod, frup->nac);
2N/A topo_mod_strfree(mod, frup->serial);
2N/A topo_mod_strfree(mod, frup->part);
2N/A topo_mod_strfree(mod, frup->dash);
2N/A topo_mod_free(mod, frup, sizeof (md_fru_t));
2N/A }
2N/A procp++;
2N/A }
2N/A topo_mod_free(mod, chip->procs,
2N/A chip->nprocs * sizeof (md_proc_t));
2N/A }
2N/A}