Mercurial > illumos > illumos-gate
changeset 3418:b24fafdbfbc2
6459500 prtdiag should show more information with regards to physical slot locations of I/O components
author | subhan |
---|---|
date | Fri, 12 Jan 2007 11:56:47 -0800 |
parents | 0630f537a7e5 |
children | 83f3eb80c815 |
files | usr/src/lib/libprtdiag_psr/sparc/opl/Makefile usr/src/lib/libprtdiag_psr/sparc/opl/common/opl.c usr/src/lib/libprtdiag_psr/sparc/opl/common/opl_picl.c usr/src/lib/libprtdiag_psr/sparc/opl/common/opl_picl.h |
diffstat | 4 files changed, 1082 insertions(+), 8 deletions(-) [+] |
line wrap: on
line diff
--- a/usr/src/lib/libprtdiag_psr/sparc/opl/Makefile Fri Jan 12 11:35:52 2007 -0800 +++ b/usr/src/lib/libprtdiag_psr/sparc/opl/Makefile Fri Jan 12 11:56:47 2007 -0800 @@ -19,23 +19,24 @@ # CDDL HEADER END # # -# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -#ident "%Z%%M% %I% %E% SMI" +#pragma ident "%Z%%M% %I% %E% SMI" # # lib/libprtdiag_psr/sparc/opl/Makefile UTSBASE = ../../../../../src/uts -PLATFORM_OBJECTS= opl.o +PLATFORM_OBJECTS= opl.o opl_picl.o include ../Makefile.com IFLAGS += -I$(USR_PLAT_DIR)/sun4u/include -I ../../../libprtdiag/inc -LINTFLAGS += $(IFLAGS) +IFLAGS += -I$(SRC)/uts/common/ -I$(SRC)/cmd/picl/plugins/inc +LDLIBS += -lpicl -ldevinfo -lkstat -LDLIBS += -ldevinfo -lkstat +LINTFLAGS += $(IFLAGS) #IMPLEMENTED_PLATFORM = SUNW,OPL-Enterprise #PLATFORM=$(IMPLEMENTED_PLATFORM)
--- a/usr/src/lib/libprtdiag_psr/sparc/opl/common/opl.c Fri Jan 12 11:35:52 2007 -0800 +++ b/usr/src/lib/libprtdiag_psr/sparc/opl/common/opl.c Fri Jan 12 11:56:47 2007 -0800 @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * Opl Platform specific functions. @@ -94,9 +94,11 @@ void display_cpus(Board_node *board); void display_memoryconf(Sys_tree *tree, struct grp_info *grps); void display_io_cards(struct io_card *list); +void display_io_devices(Sys_tree *tree); void display_diaginfo(int flag, Prom_node *root, Sys_tree *tree, struct system_kstat_data *kstats); Prop *find_prop(Prom_node *pnode, char *name); +int do_piclinfo(int); /* Local functions */ static void opl_disp_environ(void); @@ -107,6 +109,37 @@ void add_node(Sys_tree *root, Prom_node *pnode); static int get_prop_size(Prop *prop); +static int v_flag = 0; + +/* + * For display of I/O devices for "prtdiag" + */ +void +display_io_devices(Sys_tree *tree) +{ + Board_node *bnode; + + 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(dgettext(TEXT_DOMAIN, " IO Cards "), 0); + log_printf("=========================", 0); + log_printf("\n", 0); + log_printf("\n", 0); + bnode = tree->bd_list; + while (bnode != NULL) { + display_pci(bnode); + bnode = bnode->next; + } + } +} + /* * 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 @@ -682,8 +715,7 @@ struct system_kstat_data *kstats) { /* Print the PROM revisions */ - if (flag) - opl_disp_hw_revisions(tree, root); + opl_disp_hw_revisions(tree, root); } /* @@ -780,6 +812,7 @@ int do_prominfo(int syserrlog, char *pgname, int log_flag, int prt_flag) { + v_flag = syserrlog; return (do_devinfo(syserrlog, pgname, log_flag, prt_flag)); }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libprtdiag_psr/sparc/opl/common/opl_picl.c Fri Jan 12 11:56:47 2007 -0800 @@ -0,0 +1,888 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 PICL functions. + * + * called when : + * machine_type == MTYPE_OPL + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <kstat.h> +#include <fcntl.h> +#include <string.h> +#include <assert.h> +#include <libintl.h> +#include <note.h> +#include <dlfcn.h> +#include <errno.h> +#include <sys/systeminfo.h> +#include <sys/openpromio.h> +#include <sys/sysmacros.h> +#include <picl.h> +#include "picldefs.h" +#include <pdevinfo.h> +#include <display.h> +#include <libprtdiag.h> +#include <alloca.h> +#include "opl_picl.h" +#include <sys/pci.h> +#include <sys/pci_tools.h> +#include <sys/types.h> + +#if !defined(TEXT_DOMAIN) +#define TEXT_DOMAIN "SYS_TEST" +#endif + +static picl_errno_t do_walk(picl_nodehdl_t rooth, const char *classname, + void *c_args, picl_errno_t (*callback_fn)(picl_nodehdl_t hdl, void *args)); +static int opl_get_node_by_name(picl_nodehdl_t rooth, char *name, + picl_nodehdl_t *nodeh); +static picl_errno_t get_lane_width(char *device_path, int bus_no, int func_no, + int dev_no, int *actual, int *maximum, uint32_t *speed_max, + uint32_t *speed_at, int *type); +static int opl_display_pci(int syserrlog, picl_nodehdl_t plafh); +static picl_errno_t opl_pci_callback(picl_nodehdl_t pcih, void *args); +static int opl_get_first_compatible_value(picl_nodehdl_t nodeh, + char **outbuf); +static int picldiag_get_clock_freq(picl_nodehdl_t modh, + uint32_t *freq); +static uint64_t picldiag_get_uint_propval(picl_nodehdl_t modh, + char *prop_name, int *ret); +static uint32_t read_long(int fd, int bus, int dev, int func, + int offset, int *ret); +static uint8_t read_byte(int fd, int bus, int dev, int func, int offset, + int *ret); +static uint16_t read_word(int fd, int bus, int dev, int func, int offset, + int *ret); + + +/* + * Collect I/O nodes information. + */ +/* ARGSUSED */ +static picl_errno_t +opl_pci_callback(picl_nodehdl_t pcih, void *args) +{ + picl_errno_t err = PICL_SUCCESS; + picl_nodehdl_t nodeh; + picl_prophdl_t proph; + picl_propinfo_t pinfo; + char path[MAXSTRLEN]; + char parent_path[MAXSTRLEN]; + static char root_path[MAXSTRLEN]; + char piclclass[PICL_CLASSNAMELEN_MAX]; + char name[MAXSTRLEN]; + char model[MAXSTRLEN]; + char *compatible; + char binding_name[MAXSTRLEN]; + struct io_card pci_card; + char status[6] = "N/A"; + int portid = PROP_INVALID; + int *reg_val; + int board = PROP_INVALID; + static int saved_board = PROP_INVALID; + static int saved_portid = PROP_INVALID; + int actual = PROP_INVALID, maximum = PROP_INVALID; + int bus_type; + int rev_id = PROP_INVALID, dev_id = PROP_INVALID; + int ven_id = PROP_INVALID; + size_t prop_size; + + (void) memset(&pci_card, 0, sizeof (pci_card)); + + err = picl_get_propval_by_name(pcih, PICL_PROP_CLASSNAME, + piclclass, sizeof (piclclass)); + + if (err != PICL_SUCCESS) + /* Do not proceed to parse this branch */ + return (err); + + if (!IS_PCI(piclclass)) + /* Do not parse non-pci nodes */ + return (PICL_INVALIDARG); + + err = picl_get_propval_by_name(pcih, PICL_PROP_DEVFS_PATH, parent_path, + sizeof (parent_path)); + if (err != PICL_SUCCESS) + /* Do not proceed to parse this branch */ + return (err); + err = picl_get_propval_by_name(pcih, OBP_PROP_BOARD_NUM, &board, + sizeof (board)); + + if (err == PICL_NORESPONSE) + /* Do not proceed to parse this branch */ + return (err); + else if (err != PICL_PROPNOTFOUND) { + saved_board = board; + /* Save board node's pathname */ + prop_size = sizeof (parent_path) + 1; + if (prop_size > MAXSTRLEN) + prop_size = MAXSTRLEN; + (void) strlcpy(root_path, parent_path, prop_size); + } + + err = picl_get_propval_by_name + (pcih, OBP_PROP_PORTID, &portid, sizeof (portid)); + + if (err != PICL_PROPNOTFOUND) + saved_portid = portid; + + /* Walk through the children */ + + err = picl_get_propval_by_name(pcih, PICL_PROP_CHILD, &nodeh, + sizeof (picl_nodehdl_t)); + + while (err == PICL_SUCCESS) { + uint32_t freq_max = 0, freq_at = 0; + + err = picl_get_propval_by_name(nodeh, PICL_PROP_CLASSNAME, + piclclass, sizeof (piclclass)); + if (err != PICL_SUCCESS) + /* Do not proceed to parse this node */ + return (err); + + if (IS_EBUS(piclclass)) { + err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER, + &nodeh, sizeof (picl_nodehdl_t)); + continue; + } + + err = picl_get_propval_by_name(nodeh, PICL_PROP_DEVFS_PATH, + path, sizeof (path)); + if (err != PICL_SUCCESS) { + /* Do not proceed to parse this node */ + return (err); + } + + prop_size = sizeof (path) + 1; + if (prop_size > MAXSTRLEN) + prop_size = MAXSTRLEN; + (void) strlcpy(pci_card.notes, path, prop_size); + + pci_card.board = saved_board; + pci_card.schizo_portid = saved_portid; + + /* + * Get bus#, dev# and func# for this card from 'reg' property. + */ + + err = picl_get_propinfo_by_name + (nodeh, OBP_PROP_REG, &pinfo, &proph); + if (err == PICL_SUCCESS) { + /* All of the array of bytes of "reg" have to be read */ + reg_val = malloc(pinfo.size); + if (reg_val == NULL) + return (PICL_FAILURE); + + + err = picl_get_propval_by_name + (nodeh, OBP_PROP_REG, reg_val, pinfo.size); + + if (err != PICL_SUCCESS) { + free(reg_val); + /* Do not proceed to parse this node */ + return (err); + } + + if (reg_val[0] != 0) { + pci_card.dev_no = + (((reg_val[0]) & PCI_DEV_MASK) >> 11); + pci_card.func_no = + (((reg_val[0]) & PCI_FUNC_MASK) >> 8); + pci_card.slot = + (((reg_val[0]) & PCI_BUS_MASK) >> 16); + } else + free(reg_val); + } + + err = get_lane_width + (root_path, pci_card.slot, pci_card.dev_no, + pci_card.func_no, &actual, &maximum, &freq_max, + &freq_at, &bus_type); + + if (err != PICL_SUCCESS) { + /* Move on to next node */ + log_printf("Getting lane width failed for path %s\n", + pci_card.notes); + err = picl_get_propval_by_name + (nodeh, PICL_PROP_PEER, &nodeh, + sizeof (picl_nodehdl_t)); + continue; + } + + + err = picl_get_propval_by_name + (nodeh, PICL_PROP_NAME, name, sizeof (name)); + if (err != PICL_SUCCESS) + (void) strcpy(name, ""); + + /* + * Get the name of this card. If binding_name is found, + * name will be <nodename>-<binding_name> + */ + + err = picl_get_propval_by_name(nodeh, PICL_PROP_BINDING_NAME, + binding_name, sizeof (binding_name)); + if (err == PICL_PROPNOTFOUND) { + /* + * if compatible prop is found, name will be + * <nodename>-<compatible> + */ + err = opl_get_first_compatible_value(nodeh, + &compatible); + if (err == PICL_SUCCESS) { + (void) strlcat(name, "-", MAXSTRLEN); + (void) strlcat(name, compatible, MAXSTRLEN); + free(compatible); + } + } else if (err != PICL_SUCCESS) { + /* No binding-name or compatible */ + (void) strcpy(binding_name, "N/A"); + } else if (strcmp(name, binding_name) != 0) { + (void) strlcat(name, "-", MAXSTRLEN); + (void) strlcat(name, binding_name, MAXSTRLEN); + } + + + prop_size = sizeof (name) + 1; + if (prop_size > MAXSTRLEN) + prop_size = MAXSTRLEN; + (void) strlcpy(pci_card.name, name, prop_size); + + /* Get the status of the card */ + err = picl_get_propval_by_name + (nodeh, PICL_PROP_STATUS, status, sizeof (status)); + + + /* Get the model of this card */ + + err = picl_get_propval_by_name + (nodeh, OBP_PROP_MODEL, model, sizeof (model)); + prop_size = sizeof (model) + 1; + if (prop_size > MAXSTRLEN) + prop_size = MAXSTRLEN; + if (err != PICL_SUCCESS) + (void) strcpy(model, "N/A"); + (void) strlcpy(pci_card.model, model, prop_size); + + if (bus_type == PCI) + (void) strlcpy + (pci_card.bus_type, "PCI", sizeof (pci_card.bus_type)); + else if (bus_type == PCIX) + (void) strlcpy + (pci_card.bus_type, "PCIx", sizeof (pci_card.bus_type)); + else if (bus_type == PCIE) + (void) strlcpy + (pci_card.bus_type, "PCIe", sizeof (pci_card.bus_type)); + else + (void) strlcpy + (pci_card.bus_type, "UNKN", sizeof (pci_card.bus_type)); + + /* Get revision id */ + err = picl_get_propval_by_name + (nodeh, OBP_PROP_REVISION_ID, &rev_id, sizeof (rev_id)); + + /* Get device id */ + err = picl_get_propval_by_name + (nodeh, OBP_PROP_DEVICE_ID, &dev_id, sizeof (dev_id)); + + /* Get vendor id */ + err = picl_get_propval_by_name + (nodeh, OBP_PROP_VENDOR_ID, &ven_id, sizeof (ven_id)); + + /* + * prtdiag -v prints all devices + */ + + /* Print board number */ + log_printf("%02d ", pci_card.board); + /* Print IO Type */ + log_printf("%-5.5s ", pci_card.bus_type); + + log_printf("%-3d ", pci_card.schizo_portid); + log_printf("%4x, %4x, %4x ", rev_id, dev_id, ven_id); + + log_printf + ("%3d, %2d, %2d", + pci_card.slot, pci_card.dev_no, pci_card.func_no); + + /* Print status */ + log_printf(" %-5.5s ", status); + + /* Print Lane widths, Max/Sup Freq, Speed */ + if (bus_type == PCIE) { + PRINT_FMT(actual, maximum); + } else if (bus_type == PCIX) { + PRINT_FREQ_FMT(freq_at, freq_max); + } else if (bus_type == PCI) { + err = picldiag_get_clock_freq(nodeh, &freq_at); + PRINT_FREQ_FMT(freq_at, freq_max); + } else + log_printf(" -- , -- "); + + /* Print Card Name */ + log_printf("%-30.30s", pci_card.name); + + /* Print Card Model */ + log_printf(" %-20.20s", pci_card.model); + + log_printf("\n"); + + log_printf("%4s%-100.100s", " ", pci_card.notes); + log_printf("\n"); + log_printf("\n"); + + + err = picl_get_propval_by_name + (nodeh, PICL_PROP_PEER, &nodeh, sizeof (picl_nodehdl_t)); + + } + + return (PICL_WALK_CONTINUE); +} + +/* + * opl_display_pci + * Display all the PCI IO cards on this board. + */ +static int +opl_display_pci(int syserrlog, picl_nodehdl_t plafh) +{ + picl_errno_t err; + char *fmt = "%-3s %-5s %-4s %-20s %-11s %-5s %-11s %-30s %-20s"; + char *fmt2 = "%-16s"; + static int banner = FALSE; /* Have we printed the column headings? */ + + if (banner == FALSE) { + log_printf("\n", 0); + log_printf("=========================", 0); + log_printf(dgettext(TEXT_DOMAIN, " IO Devices "), 0); + log_printf("=========================", 0); + log_printf("\n", 0); + log_printf("\n", 0); + log_printf(fmt, "", "IO", "", "", "", "", "Lane/Frq", + "", "", 0); + log_printf("\n", 0); + + log_printf(fmt, "LSB", "Type", "LPID", " RvID,DvID,VnID", + " BDF", "State", "Act, Max", "Name", "Model", 0); + + log_printf("\n"); + + log_printf + (fmt, "---", "-----", "----", " ------------------", + " ---------", "-----", "-----------", + "------------------------------", + "--------------------", 0); + log_printf("\n"); + log_printf(fmt2, " Logical Path"); + log_printf("\n"); + log_printf(fmt2, " ------------"); + log_printf("\n"); + banner = TRUE; + } + + err = do_walk(plafh, PICL_CLASS_PCI, PICL_CLASS_PCI, opl_pci_callback); + return (err); +} + + +/* + * return the first compatible value + */ +static int +opl_get_first_compatible_value(picl_nodehdl_t nodeh, char **outbuf) +{ + picl_errno_t err; + picl_prophdl_t proph; + picl_propinfo_t pinfo; + picl_prophdl_t tblh; + picl_prophdl_t rowproph; + char *pval; + + err = picl_get_propinfo_by_name(nodeh, OBP_PROP_COMPATIBLE, + &pinfo, &proph); + if (err != PICL_SUCCESS) + return (err); + + if (pinfo.type == PICL_PTYPE_CHARSTRING) { + pval = malloc(pinfo.size); + if (pval == NULL) + return (PICL_FAILURE); + err = picl_get_propval(proph, pval, pinfo.size); + if (err != PICL_SUCCESS) { + free(pval); + return (err); + } + *outbuf = pval; + return (PICL_SUCCESS); + } + + if (pinfo.type != PICL_PTYPE_TABLE) + return (PICL_FAILURE); + + /* get first string from table */ + err = picl_get_propval(proph, &tblh, pinfo.size); + if (err != PICL_SUCCESS) + return (err); + + err = picl_get_next_by_row(tblh, &rowproph); + if (err != PICL_SUCCESS) + return (err); + + err = picl_get_propinfo(rowproph, &pinfo); + if (err != PICL_SUCCESS) + return (err); + + pval = malloc(pinfo.size); + if (pval == NULL) + return (PICL_FAILURE); + + err = picl_get_propval(rowproph, pval, pinfo.size); + if (err != PICL_SUCCESS) { + free(pval); + return (err); + } + + *outbuf = pval; + return (PICL_SUCCESS); +} + +int +do_piclinfo(int syserrlog) +{ + picl_nodehdl_t rooth; /* root PICL node for IO display */ + picl_nodehdl_t plafh; /* Platform PICL node for IO display */ + + picl_errno_t err; + + err = picl_initialize(); + if (err != PICL_SUCCESS) { + (void) log_printf("picl_initialize failed: %s\n", + picl_strerror(err)); + return (err); + } + + + err = picl_get_root(&rooth); + if (err != PICL_SUCCESS) { + (void) log_printf("Getting root node failed: %s\n", + picl_strerror(err)); + return (err); + } + + err = opl_get_node_by_name(rooth, PICL_NODE_PLATFORM, &plafh); + + if (err != PICL_SUCCESS) { + (void) log_printf("Getting nodes by name failed: %s\n", + picl_strerror(err)); + return (err); + } + + err = opl_display_pci(syserrlog, plafh); + + (void) picl_shutdown(); + + return (err); +} + +/* + * search children to get the node by the nodename + */ +static int +opl_get_node_by_name(picl_nodehdl_t rooth, char *name, + picl_nodehdl_t *nodeh) +{ + picl_nodehdl_t childh; + int err; + char *nodename; + + nodename = alloca(strlen(name) + 1); + if (nodename == NULL) + return (PICL_FAILURE); + + err = picl_get_propval_by_name(rooth, PICL_PROP_CHILD, &childh, + sizeof (picl_nodehdl_t)); + + while (err == PICL_SUCCESS) { + err = picl_get_propval_by_name(childh, PICL_PROP_NAME, + nodename, (strlen(name) + 1)); + if (err != PICL_SUCCESS) { + err = picl_get_propval_by_name(childh, PICL_PROP_PEER, + &childh, sizeof (picl_nodehdl_t)); + continue; + } + + if (strcmp(nodename, name) == 0) { + *nodeh = childh; + return (PICL_SUCCESS); + } + + err = picl_get_propval_by_name(childh, PICL_PROP_PEER, + &childh, sizeof (picl_nodehdl_t)); + } + + return (err); +} + +static int +open_root_complex(char *root_complex) +{ + char *path; + static char device_str[] = {"/devices"}; + static char devctl_str[] = {":reg"}; + int fd; + + path = malloc( + strlen(root_complex) + sizeof (device_str) + sizeof (devctl_str)); + if (path == NULL) + return (PICL_FAILURE); + (void) strcpy(path, device_str); + (void) strcat(path, root_complex); + (void) strcat(path, devctl_str); + + if ((fd = open(path, O_RDWR)) == -1) { + return (-1); + } + return (fd); +} + +static uint32_t +read_long(int fd, int bus, int dev, int func, int offset, int *ret) +{ + int rval; + pcitool_reg_t prg; + + prg.user_version = PCITOOL_USER_VERSION; + prg.barnum = 0; + prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_4 + + PCITOOL_ACC_ATTR_ENDN_LTL; + prg.bus_no = bus; + prg.dev_no = dev; + prg.func_no = func; + prg.offset = offset; + rval = ioctl(fd, PCITOOL_DEVICE_GET_REG, &prg); + if (rval != 0) { + log_printf + ("DEV_GET failed %d %s\n", rval, strerror(errno)); + log_printf + ("%d.%d.%d offset 0x%x\n", bus, dev, func, offset); + } + *ret = rval; + return ((uint32_t)prg.data); +} + +static uint16_t +read_word(int fd, int bus, int dev, int func, int offset, int *ret) +{ + int rval; + pcitool_reg_t prg; + + prg.user_version = PCITOOL_USER_VERSION; + prg.barnum = 0; + prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_2 + + PCITOOL_ACC_ATTR_ENDN_LTL; + prg.bus_no = bus; + prg.dev_no = dev; + prg.func_no = func; + prg.offset = offset; + rval = ioctl(fd, PCITOOL_DEVICE_GET_REG, &prg); + if (rval != 0) { + log_printf + ("DEV_GET failed %d %s\n", rval, strerror(errno)); + log_printf + ("%d.%d.%d offset 0x%x\n", bus, dev, func, offset); + } + *ret = rval; + return ((uint16_t)prg.data); +} + +static uint8_t +read_byte(int fd, int bus, int dev, int func, int offset, int *ret) +{ + int rval; + pcitool_reg_t prg; + + prg.user_version = PCITOOL_USER_VERSION; + prg.barnum = 0; + prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_1 + + PCITOOL_ACC_ATTR_ENDN_LTL; + prg.bus_no = bus; + prg.dev_no = dev; + prg.func_no = func; + prg.offset = offset; + rval = ioctl(fd, PCITOOL_DEVICE_GET_REG, &prg); + if (rval != 0) { + log_printf + ("DEV_GET failed %d %s\n", rval, strerror(errno)); + log_printf + ("%d.%d.%d offset 0x%x\n", bus, dev, func, offset); + } + *ret = rval; + return ((uint8_t)prg.data); +} + + +static picl_errno_t +get_lane_width + (char *device_path, int bus, int dev, int func, int *actual, + int *maximum, uint32_t *speed_max, uint32_t *speed_at, int *type) +{ + uint_t cap_ptr, cap_reg, link_status, link_cap, capid; + int fd, ret; + + if (device_path == NULL) + return (PICL_FAILURE); + + fd = open_root_complex(device_path); + if (fd == -1) + return (PICL_FAILURE); + + /* + * Link Capabilities and Link Status registers are in the + * PCI-E capabilities register. They are at offset + * 0xc and 0x12 respectively. They are documented in section + * 7.8 of the PCI Express Base Specification. The address of + * that structure is not fixed, it's kind of a linked list. + * The Capabilities Pointer reg (8 bits) is always at 0x34. + * It contains a pointer to the first capabilities structure. + * For each capability structure, the first 8 bits is the capability + * ID. The next 8 bits is the pointer to the next structure. + * If the Next Cap register is zero, it's the end of the list. + * The capability ID for the PCI-E strucutre is 0x10. The idea + * is to follow the links until you find a Cap ID of 0x10, then + * read the registers at 0xc and 0x12 from there. + * If there's no Cap ID 0x10, then it's not a PCI-E device. + */ + + cap_ptr = read_byte(fd, bus, dev, func, PCI_CONF_CAP_PTR, &ret); + if (ret != 0) { + /* ioctl failure */ + return (PICL_FAILURE); + } + cap_reg = read_word(fd, bus, dev, func, cap_ptr, &ret); + if (ret != 0) { + /* ioctl failure */ + return (PICL_FAILURE); + } + capid = cap_reg & PCI_CAP_MASK; + while (cap_ptr != 0) { + + if (capid == PCI_CAP_ID_PCI_E) { + link_cap = read_long(fd, bus, dev, func, cap_ptr + + PCIE_LINKCAP, &ret); + if (ret != 0) { + return (PICL_FAILURE); + } + link_status = read_word(fd, bus, dev, func, cap_ptr + + PCIE_LINKSTS, &ret); + if (ret != 0) { + return (PICL_FAILURE); + } + *actual = ((link_status >> PCI_LINK_SHIFT) & + PCI_LINK_MASK); + *maximum = ((link_cap >> PCI_LINK_SHIFT) & + PCI_LINK_MASK); + *type = PCIE; + } + if (capid == PCI_CAP_ID_PCIX) { + uint32_t pcix_status; + uint8_t hdr_type; + int max_speed = PCI_FREQ_66; + + hdr_type = read_byte + (fd, bus, dev, func, PCI_CONF_HEADER, &ret); + if (ret != 0) { + /* ioctl failure */ + return (PICL_FAILURE); + } + if ((hdr_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) { + /* This is a PCI-X bridge */ + uint16_t sec_status, mode; + sec_status = read_word(fd, bus, dev, func, + cap_ptr + PCI_PCIX_SEC_STATUS, &ret); + if (ret != 0) { + /* ioctl failure */ + return (PICL_FAILURE); + } + if (sec_status & PCI_SEC_133) + max_speed = PCI_FREQ_133; + if (sec_status & PCI_SEC_266) + max_speed = PCI_FREQ_266; + if (sec_status & PCI_SEC_533) + max_speed = PCI_FREQ_533; + *speed_max = max_speed; + *type = PCIX; + mode = (sec_status >> PCI_CLASS_BRIDGE) + & PCI_BRIDGE_MC; + if (mode) { + int speed; + if (mode == PCI_MODE_66) + speed = PCI_FREQ_66; + else if (mode == PCI_MODE_100) + speed = PCI_FREQ_100; + else if (mode == PCI_MODE_133) + speed = PCI_FREQ_133; + *speed_at = speed; + } + + } else { /* Leaf device */ + pcix_status = read_long(fd, bus, dev, func, + cap_ptr + PCI_PCIX_STATUS, &ret); + if (ret != 0) { + /* ioctl failure */ + return (PICL_FAILURE); + } + if (pcix_status & + (PCI_LEAF_ULONG << PCI_SHIFT_133)) + max_speed = PCI_FREQ_133; + if (pcix_status & + (PCI_LEAF_ULONG << PCI_SHIFT_266)) + max_speed = PCI_FREQ_266; + if (pcix_status & + (PCI_LEAF_ULONG << PCI_SHIFT_533)) + max_speed = PCI_FREQ_533; + *speed_max = max_speed; + *type = PCI; + } + } + cap_ptr = (cap_reg >> PCI_REG_FUNC_SHIFT); + cap_reg = read_word(fd, bus, dev, func, cap_ptr, &ret); + if (ret != 0) { + /* ioctl failure */ + return (PICL_FAILURE); + } + capid = cap_reg & PCI_CAP_MASK; + } + + return (PICL_SUCCESS); +} + +/* + * get the clock frequency + */ +static int +picldiag_get_clock_freq(picl_nodehdl_t modh, uint32_t *freq) +{ + int err; + uint64_t clk_freq; + + clk_freq = picldiag_get_uint_propval(modh, OBP_PROP_CLOCK_FREQ, &err); + if (err != PICL_SUCCESS) + return (err); + + *freq = ROUND_TO_MHZ(clk_freq); + + return (PICL_SUCCESS); +} + +static uint64_t +picldiag_get_uint_propval(picl_nodehdl_t modh, char *prop_name, int *ret) +{ + int err; + picl_prophdl_t proph; + picl_propinfo_t pinfo; + uint8_t uint8v; + uint16_t uint16v; + uint32_t uint32v; + uint64_t uint64v; + + err = picl_get_propinfo_by_name(modh, prop_name, &pinfo, &proph); + if (err != PICL_SUCCESS) { + *ret = err; + return (0); + } + + /* + * If it is not an int or uint prop, return failure + */ + if ((pinfo.type != PICL_PTYPE_INT) && + (pinfo.type != PICL_PTYPE_UNSIGNED_INT)) { + *ret = PICL_FAILURE; + return (0); + } + + + /* uint prop */ + + switch (pinfo.size) { + case sizeof (uint8_t): + err = picl_get_propval(proph, &uint8v, sizeof (uint8v)); + *ret = err; + return (uint8v); + case sizeof (uint16_t): + err = picl_get_propval(proph, &uint16v, sizeof (uint16v)); + *ret = err; + return (uint16v); + case sizeof (uint32_t): + err = picl_get_propval(proph, &uint32v, sizeof (uint32v)); + *ret = err; + return (uint32v); + case sizeof (uint64_t): + err = picl_get_propval(proph, &uint64v, sizeof (uint64v)); + *ret = err; + return (uint64v); + default: /* not supported size */ + *ret = PICL_FAILURE; + return (0); + } +} + +/* + * recursively visit all nodes + */ +static picl_errno_t +do_walk(picl_nodehdl_t rooth, const char *classname, + void *c_args, picl_errno_t (*callback_fn)(picl_nodehdl_t hdl, void *args)) +{ + picl_errno_t err; + picl_nodehdl_t chdh; + char classval[PICL_CLASSNAMELEN_MAX]; + + err = picl_get_propval_by_name(rooth, PICL_PROP_CHILD, &chdh, + sizeof (chdh)); + while (err == PICL_SUCCESS) { + err = picl_get_propval_by_name(chdh, PICL_PROP_NAME, + classval, sizeof (classval)); + if (err != PICL_SUCCESS) + return (err); + + err = callback_fn(chdh, c_args); + + if ((err = do_walk(chdh, classname, c_args, callback_fn)) != + PICL_WALK_CONTINUE) + return (err); + + err = picl_get_propval_by_name(chdh, PICL_PROP_PEER, &chdh, + sizeof (chdh)); + } + if (err == PICL_PROPNOTFOUND) /* end of a branch */ + return (PICL_WALK_CONTINUE); + return (err); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/libprtdiag_psr/sparc/opl/common/opl_picl.h Fri Jan 12 11:56:47 2007 -0800 @@ -0,0 +1,152 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 header file. + * + * called when : + * machine_type == MTYPE_OPL + */ + +#ifndef _OPL_PICL_H +#define _OPL_PICL_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Property names + */ +#define OBP_PROP_REG "reg" +#define OBP_PROP_CLOCK_FREQ "clock-frequency" +#define OBP_PROP_BOARD_NUM "board#" +#define OBP_PROP_REVISION_ID "revision-id" +#define OBP_PROP_VENDOR_ID "vendor-id" +#define OBP_PROP_DEVICE_ID "device-id" +#define OBP_PROP_VERSION_NUM "version#" +#define OBP_PROP_BOARD_TYPE "board_type" +#define OBP_PROP_ECACHE_SIZE "ecache-size" +#define OBP_PROP_IMPLEMENTATION "implementation#" +#define OBP_PROP_MASK "mask#" +#define OBP_PROP_COMPATIBLE "compatible" +#define OBP_PROP_BANNER_NAME "banner-name" +#define OBP_PROP_MODEL "model" +#define OBP_PROP_66MHZ_CAPABLE "66mhz-capable" +#define OBP_PROP_VERSION "version" +#define OBP_PROP_INSTANCE "instance" + +/* PCI BUS types */ + +#define PCI 10 +#define PCIX 20 +#define PCIE 30 + +/* PCI device defines */ + +#define PCI_CONF_VENID 0x0 /* vendor id, 2 bytes */ +#define PCI_CONF_DEVID 0x2 /* device id, 2 bytes */ +#define PCI_CONF_CAP_PTR 0x34 /* 1 byte capability pointer */ +#define PCI_CAP_ID_PCI_E 0x10 /* PCI Express supported */ +#define PCIE_LINKCAP 0x0C /* Link Capability */ +#define PCIE_LINKSTS 0x12 /* Link Status */ +#define PCI_CAP_MASK 0xff /* CAP Mask */ +#define PCI_DEV_MASK 0xF800 /* Dev# Mask */ +#define PCI_FUNC_MASK 0x700 /* Func# Mask */ +#define PCI_BUS_MASK 0x1ff0000 /* Bus# Mask */ +#define PCI_LINK_MASK 0x1f /* Link Mask */ + +#define PCI_LINK_SHIFT 4 /* Link shift Bits */ +#define PCI_FREQ_66 66 /* PCI default freq */ +#define PCI_FREQ_100 100 + +/* PCI frequencies */ + +#define PCI_FREQ_133 133 +#define PCI_FREQ_266 266 +#define PCI_FREQ_533 533 + +/* PCI frequency shift bits */ + +#define PCI_SHIFT_133 17 +#define PCI_SHIFT_266 30 +#define PCI_SHIFT_533 31 + +/* PCI frequency modes */ + +#define PCI_MODE_66 1 +#define PCI_MODE_100 2 +#define PCI_MODE_133 3 + +/* PCI frequency SEC status masks */ + +#define PCI_SEC_133 0x2 +#define PCI_SEC_266 0x4000 +#define PCI_SEC_533 0x8000 +#define PCI_LEAF_ULONG 1UL + + +/* Invalid property value */ +#define PROP_INVALID -1 + +/* Macros */ + +#define IS_PCI(name) \ + (((name) != NULL) && (strncmp((name), "pci", 3) == 0)) + +#define IS_EBUS(class) \ + (((class) != NULL) && (strncmp((class), "ebus", 4) == 0)) + +#define ROUND_TO_MHZ(x) (((x) + 500000)/ 1000000) + +#define PRINT_FREQ_FMT(arg_1, arg_2) \ + if (((arg_1) != 0) && \ + ((arg_2) != 0)) \ + log_printf("%4d, %4d ", (arg_1), (arg_2)); \ + else if ((arg_2) != 0) \ + log_printf(" --, %4d ", (arg_2)); \ + else if ((arg_1) != 0) \ + log_printf("%4d, -- ", (arg_1)); \ + else \ + log_printf(" --, -- "); + +#define PRINT_FMT(arg_1, arg_2) \ + if (((arg_1) != PROP_INVALID) && \ + ((arg_2) != PROP_INVALID)) \ + log_printf("%4d, %4d ", (arg_1), (arg_2)); \ + else if ((arg_2) != PROP_INVALID) \ + log_printf(" --, %4d ", (arg_2)); \ + else if ((arg_1) != PROP_INVALID) \ + log_printf("%4d, -- ", (arg_1)); \ + else \ + log_printf(" --, -- "); + + + +#ifdef __cplusplus +} +#endif + +#endif /* _OPL_PICL_H */