103831d35Sstevel /* 203831d35Sstevel * CDDL HEADER START 303831d35Sstevel * 403831d35Sstevel * The contents of this file are subject to the terms of the 525cf1a30Sjl139090 * Common Development and Distribution License (the "License"). 625cf1a30Sjl139090 * You may not use this file except in compliance with the License. 703831d35Sstevel * 803831d35Sstevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 903831d35Sstevel * or http://www.opensolaris.org/os/licensing. 1003831d35Sstevel * See the License for the specific language governing permissions 1103831d35Sstevel * and limitations under the License. 1203831d35Sstevel * 1303831d35Sstevel * When distributing Covered Code, include this CDDL HEADER in each 1403831d35Sstevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1503831d35Sstevel * If applicable, add the following below this CDDL HEADER, with the 1603831d35Sstevel * fields enclosed by brackets "[]" replaced with your own identifying 1703831d35Sstevel * information: Portions Copyright [yyyy] [name of copyright owner] 1803831d35Sstevel * 1903831d35Sstevel * CDDL HEADER END 2003831d35Sstevel */ 2103831d35Sstevel /* 22*e79c98e6Szk194757 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 2303831d35Sstevel * Use is subject to license terms. 2403831d35Sstevel */ 2503831d35Sstevel #pragma ident "%Z%%M% %I% %E% SMI" 2603831d35Sstevel 2703831d35Sstevel #include <stdio.h> 2803831d35Sstevel #include <stdlib.h> 2903831d35Sstevel #include <unistd.h> 3003831d35Sstevel #include <ctype.h> 3103831d35Sstevel #include <string.h> 3203831d35Sstevel #include <kvm.h> 3303831d35Sstevel #include <varargs.h> 3403831d35Sstevel #include <errno.h> 3503831d35Sstevel #include <time.h> 3603831d35Sstevel #include <dirent.h> 3703831d35Sstevel #include <fcntl.h> 3803831d35Sstevel #include <sys/param.h> 3903831d35Sstevel #include <sys/stat.h> 4003831d35Sstevel #include <sys/types.h> 4103831d35Sstevel #include <sys/utsname.h> 4203831d35Sstevel #include <sys/openpromio.h> 4303831d35Sstevel #include <sys/spitregs.h> 4403831d35Sstevel #include <sys/cheetahregs.h> 4503831d35Sstevel #include <kstat.h> 4603831d35Sstevel #include <libintl.h> 4703831d35Sstevel #include <syslog.h> 4803831d35Sstevel #include <sys/dkio.h> 4903831d35Sstevel #include "pdevinfo.h" 5003831d35Sstevel #include "display.h" 5103831d35Sstevel #include "pdevinfo_sun4u.h" 5203831d35Sstevel #include "display_sun4u.h" 5303831d35Sstevel #include "libprtdiag.h" 5403831d35Sstevel 5503831d35Sstevel /* 5603831d35Sstevel * Return the operating frequency of a processor in Hertz. This function 5703831d35Sstevel * requires as input a legal prom node pointer. If a NULL 5803831d35Sstevel * is passed in or the clock-frequency property does not exist, the 5903831d35Sstevel * function returns 0. 6003831d35Sstevel */ 6125cf1a30Sjl139090 uint_t 6203831d35Sstevel get_cpu_freq(Prom_node *pnode) 6303831d35Sstevel { 6403831d35Sstevel Prop *prop; 6525cf1a30Sjl139090 uint_t *value; 6603831d35Sstevel 6703831d35Sstevel /* find the property */ 6803831d35Sstevel if ((prop = find_prop(pnode, "clock-frequency")) == NULL) { 6903831d35Sstevel return (0); 7003831d35Sstevel } 7103831d35Sstevel 7225cf1a30Sjl139090 if ((value = (uint_t *)get_prop_val(prop)) == NULL) { 7303831d35Sstevel return (0); 7403831d35Sstevel } 7503831d35Sstevel 7603831d35Sstevel return (*value); 7703831d35Sstevel } 7803831d35Sstevel 7903831d35Sstevel /* 8003831d35Sstevel * returns the size of the given processors external cache in 8103831d35Sstevel * bytes. If the properties required to determine this are not 8203831d35Sstevel * present, then the function returns 0. 8303831d35Sstevel */ 8403831d35Sstevel int 8503831d35Sstevel get_ecache_size(Prom_node *node) 8603831d35Sstevel { 8703831d35Sstevel int *cache_size_p; /* pointer to number of cache lines */ 8803831d35Sstevel 8903831d35Sstevel /* find the properties */ 9003831d35Sstevel if (cache_size_p = (int *)get_prop_val(find_prop(node, 9103831d35Sstevel "ecache-size"))) { 9203831d35Sstevel return (*cache_size_p); 9303831d35Sstevel } 9403831d35Sstevel if (cache_size_p = (int *)get_prop_val(find_prop(node, 9503831d35Sstevel "l3-cache-size"))) { 9603831d35Sstevel return (*cache_size_p); 9703831d35Sstevel } 9803831d35Sstevel if (cache_size_p = (int *)get_prop_val(find_prop(node, 9903831d35Sstevel "l2-cache-size"))) { 10003831d35Sstevel return (*cache_size_p); 10103831d35Sstevel } 10203831d35Sstevel 10303831d35Sstevel return (0); 10403831d35Sstevel } 10503831d35Sstevel 10603831d35Sstevel 10703831d35Sstevel /* 10803831d35Sstevel * This routine is the generic link into displaying CPU and memory info. 10903831d35Sstevel * It displays the table header, then calls the CPU and memory display 11003831d35Sstevel * routine for all boards. 11103831d35Sstevel */ 11203831d35Sstevel void 11303831d35Sstevel display_cpu_devices(Sys_tree *tree) 11403831d35Sstevel { 11503831d35Sstevel Board_node *bnode; 11603831d35Sstevel 11703831d35Sstevel /* 11803831d35Sstevel * Display the table header for CPUs . Then display the CPU 11903831d35Sstevel * frequency, cache size, and processor revision of all cpus. 12003831d35Sstevel */ 12103831d35Sstevel log_printf("\n", 0); 12203831d35Sstevel log_printf("=========================", 0); 12303831d35Sstevel log_printf(" CPUs ", 0); 12403831d35Sstevel log_printf("=========================", 0); 12503831d35Sstevel log_printf("\n", 0); 12603831d35Sstevel log_printf("\n", 0); 12703831d35Sstevel log_printf(" Run Ecache " 12803831d35Sstevel " CPU CPU\n", 0); 12903831d35Sstevel log_printf("Brd CPU Module MHz MB " 13003831d35Sstevel "Impl. Mask\n", 0); 13103831d35Sstevel log_printf("--- --- ------- ----- ------ " 13203831d35Sstevel "------ ----\n", 0); 13303831d35Sstevel 13403831d35Sstevel /* Now display all of the cpus on each board */ 13503831d35Sstevel bnode = tree->bd_list; 13603831d35Sstevel while (bnode != NULL) { 13703831d35Sstevel display_cpus(bnode); 13803831d35Sstevel bnode = bnode->next; 13903831d35Sstevel } 14003831d35Sstevel 14103831d35Sstevel log_printf("\n", 0); 14203831d35Sstevel } 14303831d35Sstevel 14403831d35Sstevel /* 14503831d35Sstevel * Display the CPUs present on this board. 14603831d35Sstevel */ 14703831d35Sstevel void 14803831d35Sstevel display_cpus(Board_node *board) 14903831d35Sstevel { 15003831d35Sstevel Prom_node *cpu; 15103831d35Sstevel 15203831d35Sstevel /* 15303831d35Sstevel * display the CPUs' operating frequency, cache size, impl. field 15403831d35Sstevel * and mask revision. 15503831d35Sstevel */ 15603831d35Sstevel for (cpu = dev_find_type(board->nodes, "cpu"); cpu != NULL; 15703831d35Sstevel cpu = dev_next_type(cpu, "cpu")) { 158*e79c98e6Szk194757 uint_t freq; /* CPU clock frequency */ 15903831d35Sstevel int ecache_size; /* External cache size */ 16003831d35Sstevel int *mid; 16103831d35Sstevel int *impl; 16203831d35Sstevel int *mask, decoded_mask; 16303831d35Sstevel 16403831d35Sstevel mid = (int *)get_prop_val(find_prop(cpu, "upa-portid")); 16503831d35Sstevel if (mid == NULL) { 16603831d35Sstevel mid = (int *)get_prop_val(find_prop(cpu, "portid")); 16703831d35Sstevel } 16803831d35Sstevel 16903831d35Sstevel freq = (get_cpu_freq(cpu) + 500000) / 1000000; 17003831d35Sstevel ecache_size = get_ecache_size(cpu); 17103831d35Sstevel impl = (int *)get_prop_val(find_prop(cpu, "implementation#")); 17203831d35Sstevel mask = (int *)get_prop_val(find_prop(cpu, "mask#")); 17303831d35Sstevel 17403831d35Sstevel /* Do not display a failed CPU node */ 17503831d35Sstevel if ((freq != 0) && (node_failed(cpu) == 0)) { 17603831d35Sstevel /* Board number */ 17703831d35Sstevel display_boardnum(board->board_num); 17803831d35Sstevel 17903831d35Sstevel /* CPU MID */ 18003831d35Sstevel log_printf(" %2d ", *mid, 0); 18103831d35Sstevel 18203831d35Sstevel /* Module number */ 18303831d35Sstevel display_mid(*mid); 18403831d35Sstevel 18503831d35Sstevel /* Running frequency */ 186*e79c98e6Szk194757 log_printf(" %3u ", freq, 0); 18703831d35Sstevel 18803831d35Sstevel /* Ecache size */ 18903831d35Sstevel if (ecache_size == 0) 19003831d35Sstevel log_printf(" %3s ", "N/A", 0); 19103831d35Sstevel else 19203831d35Sstevel log_printf(" %4.1f ", 19303831d35Sstevel (float)ecache_size / (float)(1<<20), 19403831d35Sstevel 0); 19503831d35Sstevel 19603831d35Sstevel /* Implementation */ 19703831d35Sstevel if (impl == NULL) { 19803831d35Sstevel log_printf("%6s ", "N/A", 0); 19903831d35Sstevel } else { 20003831d35Sstevel switch (*impl) { 20103831d35Sstevel case SPITFIRE_IMPL: 20203831d35Sstevel log_printf("%-6s ", "US-I", 0); 20303831d35Sstevel break; 20403831d35Sstevel case BLACKBIRD_IMPL: 20503831d35Sstevel log_printf("%-6s ", "US-II", 0); 20603831d35Sstevel break; 20703831d35Sstevel case CHEETAH_IMPL: 20803831d35Sstevel log_printf("%-6s ", "US-III", 0); 20903831d35Sstevel break; 21003831d35Sstevel case CHEETAH_PLUS_IMPL: 21103831d35Sstevel log_printf("%-7s ", "US-III+", 0); 21203831d35Sstevel break; 21303831d35Sstevel case JAGUAR_IMPL: 21403831d35Sstevel log_printf("%-6s ", "US-IV", 0); 21503831d35Sstevel break; 21603831d35Sstevel default: 21703831d35Sstevel log_printf("%-6x ", *impl, 0); 21803831d35Sstevel break; 21903831d35Sstevel } 22003831d35Sstevel } 22103831d35Sstevel 22203831d35Sstevel /* CPU Mask */ 22303831d35Sstevel if (mask == NULL) { 22403831d35Sstevel log_printf(" %3s", "N/A", 0); 22503831d35Sstevel } else { 22603831d35Sstevel if ((impl) && IS_CHEETAH(*impl)) 22703831d35Sstevel decoded_mask = 22803831d35Sstevel REMAP_CHEETAH_MASK(*mask); 22903831d35Sstevel else 23003831d35Sstevel decoded_mask = *mask; 23103831d35Sstevel 23203831d35Sstevel log_printf(" %d.%d", (decoded_mask >> 4) & 0xf, 23303831d35Sstevel decoded_mask & 0xf, 0); 23403831d35Sstevel } 23503831d35Sstevel 23603831d35Sstevel log_printf("\n", 0); 23703831d35Sstevel } 23803831d35Sstevel } 23903831d35Sstevel } 24003831d35Sstevel 24103831d35Sstevel void 24203831d35Sstevel display_mid(int mid) 24303831d35Sstevel { 24403831d35Sstevel log_printf(" %2d ", mid, 0); 24503831d35Sstevel } 246