opl.c revision 3d808a5295b8e731b863fdf7705b85d639514263
/*
* 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 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
* Opl Platform specific functions.
*
* called when :
* machine_type == MTYPE_OPL
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <ctype.h>
#include <string.h>
#include <varargs.h>
#include <fcntl.h>
#include <assert.h>
#include <sys/systeminfo.h>
#include <sys/openpromio.h>
#include <libintl.h>
#include <syslog.h>
#include <pdevinfo.h>
#include <libprtdiag.h>
#include <libdevinfo.h>
#include <kstat.h>
/*
* Globals and externs
*/
#define KBYTE 1024
#define SCF_SECURE_MODE_KSTAT_NAMED "secure_mode"
#define SCF_STAT_MODE_UNLOCK 0
#define SCF_STAT_MODE_LOCK 1
#define SCF_SYSTEM_KSTAT_NAME "scf"
#ifndef TEXT_DOMAIN
#define TEXT_DOMAIN "SYS_TEST"
#endif /* TEXT_DOMAIN */
/*
* Global functions and variables
* these functions will overlay the symbol table of libprtdiag
* at runtime (Opl systems only)
*/
struct cs_status {
int cs_number;
int status;
int dimms;
};
void display_pci(Board_node *);
void display_ffb(Board_node *, int);
struct system_kstat_data *kstats);
int do_piclinfo(int);
/* Local functions */
static void opl_disp_environ(void);
int ngrps);
static int v_flag = 0;
/*
* For display of I/O devices for "prtdiag"
*/
void
{
if (v_flag) {
/*
* OPL's PICL interface for display of PCI I/O devices
* for "prtdiag -v"
*/
(void) do_piclinfo(v_flag);
} else {
log_printf("\n", 0);
log_printf("=========================", 0);
log_printf("=========================", 0);
log_printf("\n", 0);
log_printf("\n", 0);
}
}
}
/*
* Display all the leaf PCI nodes on this board that have "reg" property.
* If the "reg" property is NULL for a leaf node, skip parsing its sibling
* nodes and display the parent node properties.
*/
void
{
int *int_val;
return;
/* Initialize common information */
/* Skip non-PCI board nodes */
continue;
}
/*
* They have name == "pci" and type == "pci"
*/
continue;
}
int pci_parent_bridge = 0;
/* If it does have a child, skip to leaf child */
continue;
}
/* Get name of the card */
(card_node, "name"));
/* Get type of card */
(card_node, "device_type"));
/* Leaf pci-bridges are to be ignored */
/* Get reg property of the node */
(card_node, "reg"));
/*
* If no "reg" property check to see
* whether parent node has reg property.
* and check if parent is a bridge
*/
break;
(cparent, "name"));
(cparent, "device_type"));
/* check if parent is a bridge */
pci_parent_bridge = 1;
int_val = (int *)get_prop_val(
/* Switch to parent */
else
/* parent node has no reg */
break;
}
if (!pci_parent_bridge) {
(card_node, "name"));
else {
}
/* Get the model of this card */
(card_node, "model"));
} else {
}
/* insert card to the list */
}
}
/*
* Parse sibling nodes.
* Then move up the parent's sibling upto the top
* intermediate node
* Stop if pci board node is reached.
*/
else
} else {
break;
break;
}
}
}
}
/* On to the next board node */
}
}
/*
* There are no FFB's on OPL.
*/
/*ARGSUSED*/
void
{
}
/*
* There are no Sbus's on OPL.
*/
/*ARGSUSED*/
void
{
}
/*
* Details of I/O information. Print out all the io cards.
*/
void
{
char *hdrfmt = "%-6.6s %-14.14s %-12.12s\n";
struct io_card *p;
return;
(void) textdomain(TEXT_DOMAIN);
0);
/* Board number */
/* Card name */
/* Card model */
log_printf("\n", 0);
}
log_printf("\n", 0);
}
/*
* Details of CPU information.
*/
void
{
char *hdrfmt =
"%-5.5s %-8.8s %-20.20s %-8.8s %-8.8s %-8.8s %-8.8s\n";
(void) textdomain(TEXT_DOMAIN);
/*
* Display the table header for CPUs . Then display the CPU
* frequency, cache size, and processor revision of all cpus.
*/
log_printf("\n", 0);
log_printf("====================================", 0);
log_printf("====================================", 0);
log_printf("\n\n", 0);
"",
gettext("CPU"),
gettext(" CPU "),
gettext("Run"),
gettext("L2$"),
gettext("CPU"),
gettext("CPU"), 0);
gettext("LSB"),
gettext("Chip"),
gettext(" ID "),
gettext("MHz"),
gettext(" MB"),
gettext("Impl."),
gettext("Mask"), 0);
"---", "----", "--------------------", "----",
"---", "-----", "----", 0);
/* Now display all of the cpus on each board */
}
log_printf("\n", 0);
}
/*
* Display the CPUs present on this board.
*/
void
{
char *name;
(void) textdomain(TEXT_DOMAIN);
/*
* Get the Cpus' properties for display
*/
continue;
}
(int *)get_prop_val
impl =
(int *)get_prop_val
/* Lsb id */
/*
* The internal cpu tree built by walk_di_tree()
* in common code can be illustrated by the diagram
* below:
*
* cmp->cpu->cpu->cpu->cpu->(next board nodes)
* / \
* core core
* where "/" or "\" are children
* and "->" are siblings
*/
break;
}
/* Id assigned to Virtual processor core */
}
}
/* Used for printing in comma format */
} else {
}
}
/* Running frequency */
if (freq != 0)
else
/* L2 cache size */
if (l2cache_size == NULL)
else {
log_printf("%4.1f ",
}
/* Implementation number of processor */
else
/* Mask Set version */
/* Bits 31:24 of VER register is mask. */
/* Mask value : Non MTP mode - 00-7f, MTP mode - 80-ff */
else
log_printf("\n", 0);
}
}
/*
* Gather memory information: Details of memory information.
*/
static uint64_t
{
if (cs_size > 0) {
/* OBP returns lists of 7 ints */
/*
* The units of cs_size will be either number of bytes
* or number of int array elements as this is derived
* from the libprtdiag Prop node size field which has
* inconsistent units. Until this is addressed in
* libprtdiag, we need a heuristic to determine the
* number of CS groups. Given that the maximum number
* of CS groups is 2, the maximum number of cs-status
* array elements will be 2*7=14. Since this is smaller
* than the byte size of a single struct status, we use
* this to decide if we are dealing with bytes or array
* elements in determining the number of CS groups.
*/
/* cs_size is number of total int [] elements */
} else {
/* cs_size is total byte count */
}
total_mem +=
}
}
}
return (total_mem);
}
/*
* Display memory information.
*/
/*ARGSUSED*/
void
{
char *hdrfmt = "\n%-5.5s %-6.6s %-18.18s %-10.10s"
" %-8.8s %-10.10s";
(void) textdomain(TEXT_DOMAIN);
log_printf("======================", 0);
log_printf("======================", 0);
log_printf("\n", 0);
"",
gettext("Memory"),
gettext("Available"),
gettext("Memory"),
gettext("DIMM"),
gettext("Number of"),
0);
gettext("LSB"),
gettext("Group"),
gettext("Size"),
gettext("Status"),
gettext("Size"),
gettext("DIMMs"), 0);
"---", "-------", "------------------", "-------", "------",
"---------", 0);
log_printf("\n", 0);
}
/*
* Sanity check to ensure that the total amount of system
* memory matches the total number of memory that
* we find here. Display error message if there is a mis-match.
*/
(_SC_PHYS_PAGES)) / MBYTE);
if (total_mem != total_sys_mem) {
"\nError:total available size [%lldMB] does not match"
" total system memory [%lldMB]\n"),
total_mem, total_sys_mem, 0);
}
}
/*
* This function provides Opl's formatting of the memory config
* information that get_opl_mem_regs() has gathered.
*/
static uint64_t
{
int i;
uint64_t total_board_mem = 0;
(void) textdomain(TEXT_DOMAIN);
for (i = 0; i < ngrps; i++) {
if (mem_size == 0)
continue;
/* Lsb Id */
/* Memory Group Number */
else
/* Memory Group Size */
/* Memory Group Status */
log_printf("%-11.11s",
/* DIMM Size */
log_printf("%4lldMB ",
/* Number of DIMMs */
}
return (total_board_mem);
}
/*
* Details of hardware revision and environmental status.
*/
/*ARGSUSED*/
void
struct system_kstat_data *kstats)
{
/* Print the PROM revisions */
}
/*
* Gather and display hardware revision and environmental status
*/
/*ARGSUSED*/
static void
{
char *version;
(void) textdomain(TEXT_DOMAIN);
/* Print the header */
log_printf("\n", 0);
log_printf("====================", 0);
log_printf("====================", 0);
log_printf("\n\n", 0);
/* Display Prom revision header */
log_printf("\n----------------------\n", 0);
log_printf("\n", 0);
/* Display OBP version info */
else
}
/* Print the header */
log_printf("\n", 0);
log_printf("===================", 0);
log_printf("===================", 0);
log_printf("\n\n", 0);
}
/*
* Gather environmental information
*/
static void
opl_disp_environ(void)
{
kstat_named_t *k;
return;
if ((ksp = kstat_lookup
(void) kstat_close(kc);
return;
}
(void) kstat_close(kc);
return;
}
if ((k = (kstat_named_t *)kstat_data_lookup
(void) kstat_close(kc);
return;
}
if (k->value.c[0] == SCF_STAT_MODE_LOCK)
log_printf("Mode switch is in LOCK mode ", 0);
else if (k->value.c[0] == SCF_STAT_MODE_UNLOCK)
log_printf("Mode switch is in UNLOCK mode", 0);
else
log_printf("Mode switch is in UNKNOWN mode", 0);
log_printf("\n", 0);
(void) kstat_close(kc);
}
/*
* Calls do_devinfo() in order to use the libdevinfo device tree
* instead of OBP's device tree.
*/
int
{
}
/*
* Return the property value for the Prop
* passed in. (When using libdevinfo)
*/
void *
{
return (NULL);
}
/*
* Return the property size for the Prop
* passed in. (When using libdevinfo)
*/
static int
{
else
return (0);
}
/*
* Search a Prom node and retrieve the property with the correct
* name. (When using libdevinfo)
*/
Prop *
{
return (NULL);
break;
}
return (prop);
}
/*
* This function adds a board node to the board structure where that
* that node's physical component lives.
*/
void
{
int board;
Prom_node *p;
char *type;
}
/* find the node with the same board number */
}
/* now attach this prom node to the board list */
/* Insert this node at the end of the list */
else {
p = p->sibling;
}
}