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 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
2N/A * Use is subject to license terms.
2N/A *
2N/A * Opl platform specific PICL functions.
2N/A *
2N/A * called when :
2N/A * machine_type == MTYPE_OPL
2N/A */
2N/A
2N/A#include <stdio.h>
2N/A#include <stdlib.h>
2N/A#include <unistd.h>
2N/A#include <kstat.h>
2N/A#include <fcntl.h>
2N/A#include <string.h>
2N/A#include <assert.h>
2N/A#include <libintl.h>
2N/A#include <note.h>
2N/A#include <dlfcn.h>
2N/A#include <errno.h>
2N/A#include <sys/systeminfo.h>
2N/A#include <sys/openpromio.h>
2N/A#include <sys/sysmacros.h>
2N/A#include <picl.h>
2N/A#include "picldefs.h"
2N/A#include <pdevinfo.h>
2N/A#include <display.h>
2N/A#include <libprtdiag.h>
2N/A#include <alloca.h>
2N/A#include "opl_picl.h"
2N/A#include <sys/pci.h>
2N/A#include <sys/pci_tools.h>
2N/A#include <sys/types.h>
2N/A
2N/A#if !defined(TEXT_DOMAIN)
2N/A#define TEXT_DOMAIN "SYS_TEST"
2N/A#endif
2N/A
2N/Astatic picl_errno_t do_walk(picl_nodehdl_t rooth, const char *classname,
2N/A void *c_args, picl_errno_t (*callback_fn)(picl_nodehdl_t hdl, void *args));
2N/Astatic int opl_get_node_by_name(picl_nodehdl_t rooth, char *name,
2N/A picl_nodehdl_t *nodeh);
2N/Astatic picl_errno_t get_lane_width(char *device_path, int bus_no, int func_no,
2N/A int dev_no, int *actual, int *maximum, uint32_t *speed_max,
2N/A uint32_t *speed_at, int *type);
2N/Astatic int opl_display_pci(int syserrlog, picl_nodehdl_t plafh);
2N/Astatic picl_errno_t opl_pci_callback(picl_nodehdl_t pcih, void *args);
2N/Astatic int opl_get_first_compatible_value(picl_nodehdl_t nodeh,
2N/A char **outbuf);
2N/Astatic int picldiag_get_clock_freq(picl_nodehdl_t modh,
2N/A uint32_t *freq, uint32_t *freq_max);
2N/Astatic uint64_t picldiag_get_uint_propval(picl_nodehdl_t modh,
2N/A char *prop_name, int *ret);
2N/Astatic uint32_t read_long(int fd, int bus, int dev, int func,
2N/A int offset, int *ret);
2N/Astatic uint8_t read_byte(int fd, int bus, int dev, int func, int offset,
2N/A int *ret);
2N/Astatic uint16_t read_word(int fd, int bus, int dev, int func, int offset,
2N/A int *ret);
2N/A
2N/A/*
2N/A * Collect I/O nodes information.
2N/A */
2N/A/* ARGSUSED */
2N/Astatic picl_errno_t
2N/Aopl_pci_callback(picl_nodehdl_t pcih, void *args)
2N/A{
2N/A picl_errno_t err = PICL_SUCCESS;
2N/A picl_nodehdl_t nodeh;
2N/A picl_prophdl_t proph;
2N/A picl_propinfo_t pinfo;
2N/A char path[MAXSTRLEN];
2N/A char parent_path[MAXSTRLEN];
2N/A static char root_path[MAXSTRLEN];
2N/A char piclclass[PICL_CLASSNAMELEN_MAX];
2N/A char name[MAXSTRLEN];
2N/A char model[MAXSTRLEN];
2N/A char *compatible;
2N/A char binding_name[MAXSTRLEN];
2N/A struct io_card pci_card;
2N/A char status[6] = "N/A";
2N/A int portid = PROP_INVALID;
2N/A int *reg_val;
2N/A int board = PROP_INVALID;
2N/A static int saved_board = PROP_INVALID;
2N/A static int saved_portid = PROP_INVALID;
2N/A int actual = PROP_INVALID, maximum = PROP_INVALID;
2N/A int bus_type;
2N/A int rev_id = PROP_INVALID, dev_id = PROP_INVALID;
2N/A int ven_id = PROP_INVALID;
2N/A size_t prop_size;
2N/A
2N/A (void) memset(&pci_card, 0, sizeof (pci_card));
2N/A
2N/A err = picl_get_propval_by_name(pcih, PICL_PROP_CLASSNAME,
2N/A piclclass, sizeof (piclclass));
2N/A
2N/A if (err != PICL_SUCCESS)
2N/A /* Do not proceed to parse this branch */
2N/A return (err);
2N/A
2N/A if (!IS_PCI(piclclass))
2N/A /* Do not parse non-pci nodes */
2N/A return (PICL_INVALIDARG);
2N/A
2N/A err = picl_get_propval_by_name(pcih, PICL_PROP_DEVFS_PATH, parent_path,
2N/A sizeof (parent_path));
2N/A if (err != PICL_SUCCESS)
2N/A /* Do not proceed to parse this branch */
2N/A return (err);
2N/A err = picl_get_propval_by_name(pcih, OBP_PROP_BOARD_NUM, &board,
2N/A sizeof (board));
2N/A
2N/A if (err == PICL_NORESPONSE)
2N/A /* Do not proceed to parse this branch */
2N/A return (err);
2N/A else if (err != PICL_PROPNOTFOUND) {
2N/A saved_board = board;
2N/A /* Save board node's pathname */
2N/A prop_size = sizeof (parent_path) + 1;
2N/A if (prop_size > MAXSTRLEN)
2N/A prop_size = MAXSTRLEN;
2N/A (void) strlcpy(root_path, parent_path, prop_size);
2N/A }
2N/A
2N/A err = picl_get_propval_by_name
2N/A (pcih, OBP_PROP_PORTID, &portid, sizeof (portid));
2N/A
2N/A if (err != PICL_PROPNOTFOUND)
2N/A saved_portid = portid;
2N/A
2N/A /* Walk through the children */
2N/A
2N/A err = picl_get_propval_by_name(pcih, PICL_PROP_CHILD, &nodeh,
2N/A sizeof (picl_nodehdl_t));
2N/A
2N/A while (err == PICL_SUCCESS) {
2N/A uint32_t freq_max = 0, freq_at = 0;
2N/A
2N/A err = picl_get_propval_by_name(nodeh, PICL_PROP_CLASSNAME,
2N/A piclclass, sizeof (piclclass));
2N/A if (err != PICL_SUCCESS)
2N/A /* Do not proceed to parse this node */
2N/A return (err);
2N/A
2N/A if (IS_EBUS(piclclass)) {
2N/A err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER,
2N/A &nodeh, sizeof (picl_nodehdl_t));
2N/A continue;
2N/A }
2N/A
2N/A err = picl_get_propval_by_name(nodeh, PICL_PROP_DEVFS_PATH,
2N/A path, sizeof (path));
2N/A if (err != PICL_SUCCESS) {
2N/A /* Do not proceed to parse this node */
2N/A return (err);
2N/A }
2N/A
2N/A prop_size = sizeof (path) + 1;
2N/A if (prop_size > MAXSTRLEN)
2N/A prop_size = MAXSTRLEN;
2N/A (void) strlcpy(pci_card.notes, path, prop_size);
2N/A
2N/A pci_card.board = saved_board;
2N/A pci_card.schizo_portid = saved_portid;
2N/A
2N/A /*
2N/A * Get bus#, dev# and func# for this card from 'reg' property.
2N/A */
2N/A
2N/A err = picl_get_propinfo_by_name
2N/A (nodeh, OBP_PROP_REG, &pinfo, &proph);
2N/A if (err == PICL_SUCCESS) {
2N/A /* All of the array of bytes of "reg" have to be read */
2N/A reg_val = malloc(pinfo.size);
2N/A if (reg_val == NULL)
2N/A return (PICL_FAILURE);
2N/A
2N/A
2N/A err = picl_get_propval_by_name
2N/A (nodeh, OBP_PROP_REG, reg_val, pinfo.size);
2N/A
2N/A if (err != PICL_SUCCESS) {
2N/A free(reg_val);
2N/A /* Do not proceed to parse this node */
2N/A return (err);
2N/A }
2N/A
2N/A if (reg_val[0] != 0) {
2N/A pci_card.dev_no =
2N/A (((reg_val[0]) & PCI_DEV_MASK) >> 11);
2N/A pci_card.func_no =
2N/A (((reg_val[0]) & PCI_FUNC_MASK) >> 8);
2N/A pci_card.slot =
2N/A (((reg_val[0]) & PCI_BUS_MASK) >> 16);
2N/A } else
2N/A free(reg_val);
2N/A }
2N/A
2N/A err = get_lane_width(root_path, pci_card.slot, pci_card.dev_no,
2N/A pci_card.func_no, &actual, &maximum, &freq_max, &freq_at,
2N/A &bus_type);
2N/A
2N/A if (err != PICL_SUCCESS) {
2N/A /*
2N/A * get_lane_width will fail when run as non-root.
2N/A * Set bus_type to PCI_UNKN so that bus frequency,
2N/A * bus type and lane width will print as "--" or UNKN.
2N/A */
2N/A bus_type = PCI_UNKN;
2N/A }
2N/A
2N/A
2N/A err = picl_get_propval_by_name
2N/A (nodeh, PICL_PROP_NAME, name, sizeof (name));
2N/A if (err != PICL_SUCCESS)
2N/A (void) strcpy(name, "");
2N/A
2N/A /*
2N/A * Get the name of this card. If binding_name is found,
2N/A * name will be <nodename>-<binding_name>
2N/A */
2N/A
2N/A err = picl_get_propval_by_name(nodeh, PICL_PROP_BINDING_NAME,
2N/A binding_name, sizeof (binding_name));
2N/A if (err == PICL_PROPNOTFOUND) {
2N/A /*
2N/A * if compatible prop is found, name will be
2N/A * <nodename>-<compatible>
2N/A */
2N/A err = opl_get_first_compatible_value(nodeh,
2N/A &compatible);
2N/A if (err == PICL_SUCCESS) {
2N/A (void) strlcat(name, "-", MAXSTRLEN);
2N/A (void) strlcat(name, compatible, MAXSTRLEN);
2N/A free(compatible);
2N/A }
2N/A } else if (err != PICL_SUCCESS) {
2N/A /* No binding-name or compatible */
2N/A (void) strcpy(binding_name, "N/A");
2N/A } else if (strcmp(name, binding_name) != 0) {
2N/A (void) strlcat(name, "-", MAXSTRLEN);
2N/A (void) strlcat(name, binding_name, MAXSTRLEN);
2N/A }
2N/A
2N/A
2N/A prop_size = sizeof (name) + 1;
2N/A if (prop_size > MAXSTRLEN)
2N/A prop_size = MAXSTRLEN;
2N/A (void) strlcpy(pci_card.name, name, prop_size);
2N/A
2N/A /* Get the status of the card */
2N/A err = picl_get_propval_by_name
2N/A (nodeh, PICL_PROP_STATUS, status, sizeof (status));
2N/A
2N/A
2N/A /* Get the model of this card */
2N/A
2N/A err = picl_get_propval_by_name
2N/A (nodeh, OBP_PROP_MODEL, model, sizeof (model));
2N/A prop_size = sizeof (model) + 1;
2N/A if (prop_size > MAXSTRLEN)
2N/A prop_size = MAXSTRLEN;
2N/A if (err != PICL_SUCCESS)
2N/A (void) strcpy(model, "N/A");
2N/A (void) strlcpy(pci_card.model, model, prop_size);
2N/A
2N/A if (bus_type == PCI)
2N/A (void) strlcpy(pci_card.bus_type,
2N/A "PCI", sizeof (pci_card.bus_type));
2N/A else if (bus_type == PCIX)
2N/A (void) strlcpy(pci_card.bus_type,
2N/A "PCIx", sizeof (pci_card.bus_type));
2N/A else if (bus_type == PCIE)
2N/A (void) strlcpy(pci_card.bus_type,
2N/A "PCIe", sizeof (pci_card.bus_type));
2N/A else
2N/A (void) strlcpy(pci_card.bus_type,
2N/A "UNKN", sizeof (pci_card.bus_type));
2N/A
2N/A /* Get revision id */
2N/A err = picl_get_propval_by_name
2N/A (nodeh, OBP_PROP_REVISION_ID, &rev_id, sizeof (rev_id));
2N/A
2N/A /* Get device id */
2N/A err = picl_get_propval_by_name
2N/A (nodeh, OBP_PROP_DEVICE_ID, &dev_id, sizeof (dev_id));
2N/A
2N/A /* Get vendor id */
2N/A err = picl_get_propval_by_name
2N/A (nodeh, OBP_PROP_VENDOR_ID, &ven_id, sizeof (ven_id));
2N/A
2N/A /*
2N/A * prtdiag -v prints all devices
2N/A */
2N/A
2N/A /* Print board number */
2N/A log_printf("%02d ", pci_card.board);
2N/A /* Print IO Type */
2N/A log_printf("%-5.5s ", pci_card.bus_type);
2N/A
2N/A log_printf("%-3d ", pci_card.schizo_portid);
2N/A log_printf("%4x, %4x, %4x ", rev_id, dev_id, ven_id);
2N/A
2N/A log_printf("%3d, %2d, %2d",
2N/A pci_card.slot, pci_card.dev_no, pci_card.func_no);
2N/A
2N/A /* Print status */
2N/A log_printf(" %-5.5s ", status);
2N/A
2N/A /* Print Lane widths, Max/Sup Freq, Speed */
2N/A if (bus_type == PCIE) {
2N/A PRINT_FMT(actual, maximum);
2N/A } else if (bus_type == PCIX) {
2N/A PRINT_FREQ_FMT(freq_at, freq_max);
2N/A } else if (bus_type == PCI) {
2N/A err = picldiag_get_clock_freq(nodeh, &freq_at,
2N/A &freq_max);
2N/A PRINT_FREQ_FMT(freq_at, freq_max);
2N/A } else
2N/A log_printf(" -- , -- ");
2N/A
2N/A /* Print Card Name */
2N/A log_printf("%-30.30s", pci_card.name);
2N/A
2N/A /* Print Card Model */
2N/A log_printf(" %-20.20s", pci_card.model);
2N/A
2N/A log_printf("\n");
2N/A
2N/A log_printf("%4s%-100.100s", " ", pci_card.notes);
2N/A log_printf("\n");
2N/A log_printf("\n");
2N/A
2N/A
2N/A err = picl_get_propval_by_name
2N/A (nodeh, PICL_PROP_PEER, &nodeh, sizeof (picl_nodehdl_t));
2N/A
2N/A }
2N/A
2N/A return (PICL_WALK_CONTINUE);
2N/A}
2N/A
2N/A/*
2N/A * opl_display_pci
2N/A * Display all the PCI IO cards on this board.
2N/A */
2N/Astatic int
2N/Aopl_display_pci(int syserrlog, picl_nodehdl_t plafh)
2N/A{
2N/A picl_errno_t err;
2N/A char *fmt = "%-3s %-5s %-4s %-20s %-11s %-5s %-11s %-30s %-20s";
2N/A char *fmt2 = "%-16s";
2N/A static int banner = FALSE; /* Have we printed the column headings? */
2N/A
2N/A if (banner == FALSE) {
2N/A log_printf("\n", 0);
2N/A log_printf("=========================", 0);
2N/A log_printf(dgettext(TEXT_DOMAIN, " IO Devices "), 0);
2N/A log_printf("=========================", 0);
2N/A log_printf("\n", 0);
2N/A log_printf("\n", 0);
2N/A log_printf(fmt, "", "IO", "", "", "", "", "Lane/Frq",
2N/A "", "", 0);
2N/A log_printf("\n", 0);
2N/A
2N/A log_printf(fmt, "LSB", "Type", "LPID", " RvID,DvID,VnID",
2N/A " BDF", "State", "Act, Max", "Name", "Model", 0);
2N/A
2N/A log_printf("\n");
2N/A
2N/A log_printf(fmt,
2N/A "---", "-----", "----", " ------------------",
2N/A " ---------", "-----", "-----------",
2N/A "------------------------------",
2N/A "--------------------", 0);
2N/A log_printf("\n");
2N/A log_printf(fmt2, " Logical Path");
2N/A log_printf("\n");
2N/A log_printf(fmt2, " ------------");
2N/A log_printf("\n");
2N/A banner = TRUE;
2N/A }
2N/A
2N/A err = do_walk(plafh, PICL_CLASS_PCI, PICL_CLASS_PCI, opl_pci_callback);
2N/A return (err);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * return the first compatible value
2N/A */
2N/Astatic int
2N/Aopl_get_first_compatible_value(picl_nodehdl_t nodeh, char **outbuf)
2N/A{
2N/A picl_errno_t err;
2N/A picl_prophdl_t proph;
2N/A picl_propinfo_t pinfo;
2N/A picl_prophdl_t tblh;
2N/A picl_prophdl_t rowproph;
2N/A char *pval;
2N/A
2N/A err = picl_get_propinfo_by_name(nodeh, OBP_PROP_COMPATIBLE,
2N/A &pinfo, &proph);
2N/A if (err != PICL_SUCCESS)
2N/A return (err);
2N/A
2N/A if (pinfo.type == PICL_PTYPE_CHARSTRING) {
2N/A pval = malloc(pinfo.size);
2N/A if (pval == NULL)
2N/A return (PICL_FAILURE);
2N/A err = picl_get_propval(proph, pval, pinfo.size);
2N/A if (err != PICL_SUCCESS) {
2N/A free(pval);
2N/A return (err);
2N/A }
2N/A *outbuf = pval;
2N/A return (PICL_SUCCESS);
2N/A }
2N/A
2N/A if (pinfo.type != PICL_PTYPE_TABLE)
2N/A return (PICL_FAILURE);
2N/A
2N/A /* get first string from table */
2N/A err = picl_get_propval(proph, &tblh, pinfo.size);
2N/A if (err != PICL_SUCCESS)
2N/A return (err);
2N/A
2N/A err = picl_get_next_by_row(tblh, &rowproph);
2N/A if (err != PICL_SUCCESS)
2N/A return (err);
2N/A
2N/A err = picl_get_propinfo(rowproph, &pinfo);
2N/A if (err != PICL_SUCCESS)
2N/A return (err);
2N/A
2N/A pval = malloc(pinfo.size);
2N/A if (pval == NULL)
2N/A return (PICL_FAILURE);
2N/A
2N/A err = picl_get_propval(rowproph, pval, pinfo.size);
2N/A if (err != PICL_SUCCESS) {
2N/A free(pval);
2N/A return (err);
2N/A }
2N/A
2N/A *outbuf = pval;
2N/A return (PICL_SUCCESS);
2N/A}
2N/A
2N/Aint
2N/Ado_piclinfo(int syserrlog)
2N/A{
2N/A picl_nodehdl_t rooth; /* root PICL node for IO display */
2N/A picl_nodehdl_t plafh; /* Platform PICL node for IO display */
2N/A
2N/A picl_errno_t err;
2N/A
2N/A err = picl_initialize();
2N/A if (err != PICL_SUCCESS) {
2N/A (void) log_printf("picl_initialize failed: %s\n",
2N/A picl_strerror(err));
2N/A return (err);
2N/A }
2N/A
2N/A
2N/A err = picl_get_root(&rooth);
2N/A if (err != PICL_SUCCESS) {
2N/A (void) log_printf("Getting root node failed: %s\n",
2N/A picl_strerror(err));
2N/A return (err);
2N/A }
2N/A
2N/A err = opl_get_node_by_name(rooth, PICL_NODE_PLATFORM, &plafh);
2N/A
2N/A if (err != PICL_SUCCESS) {
2N/A (void) log_printf("Getting nodes by name failed: %s\n",
2N/A picl_strerror(err));
2N/A return (err);
2N/A }
2N/A
2N/A err = opl_display_pci(syserrlog, plafh);
2N/A
2N/A (void) picl_shutdown();
2N/A
2N/A return (err);
2N/A}
2N/A
2N/A/*
2N/A * search children to get the node by the nodename
2N/A */
2N/Astatic int
2N/Aopl_get_node_by_name(picl_nodehdl_t rooth, char *name,
2N/A picl_nodehdl_t *nodeh)
2N/A{
2N/A picl_nodehdl_t childh;
2N/A int err;
2N/A char *nodename;
2N/A
2N/A nodename = alloca(strlen(name) + 1);
2N/A if (nodename == NULL)
2N/A return (PICL_FAILURE);
2N/A
2N/A err = picl_get_propval_by_name(rooth, PICL_PROP_CHILD, &childh,
2N/A sizeof (picl_nodehdl_t));
2N/A
2N/A while (err == PICL_SUCCESS) {
2N/A err = picl_get_propval_by_name(childh, PICL_PROP_NAME,
2N/A nodename, (strlen(name) + 1));
2N/A if (err != PICL_SUCCESS) {
2N/A err = picl_get_propval_by_name(childh, PICL_PROP_PEER,
2N/A &childh, sizeof (picl_nodehdl_t));
2N/A continue;
2N/A }
2N/A
2N/A if (strcmp(nodename, name) == 0) {
2N/A *nodeh = childh;
2N/A return (PICL_SUCCESS);
2N/A }
2N/A
2N/A err = picl_get_propval_by_name(childh, PICL_PROP_PEER,
2N/A &childh, sizeof (picl_nodehdl_t));
2N/A }
2N/A
2N/A return (err);
2N/A}
2N/A
2N/Astatic int
2N/Aopen_root_complex(char *root_complex)
2N/A{
2N/A char *path;
2N/A static char device_str[] = {"/devices"};
2N/A static char devctl_str[] = {":reg"};
2N/A int fd;
2N/A
2N/A path = malloc(
2N/A strlen(root_complex) + sizeof (device_str) + sizeof (devctl_str));
2N/A if (path == NULL)
2N/A return (PICL_FAILURE);
2N/A (void) strcpy(path, device_str);
2N/A (void) strcat(path, root_complex);
2N/A (void) strcat(path, devctl_str);
2N/A
2N/A if ((fd = open(path, O_RDWR)) == -1) {
2N/A return (-1);
2N/A }
2N/A return (fd);
2N/A}
2N/A
2N/Astatic uint32_t
2N/Aread_long(int fd, int bus, int dev, int func, int offset, int *ret)
2N/A{
2N/A int rval;
2N/A pcitool_reg_t prg;
2N/A
2N/A prg.user_version = PCITOOL_VERSION;
2N/A prg.barnum = 0;
2N/A prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_4 +
2N/A PCITOOL_ACC_ATTR_ENDN_LTL;
2N/A prg.bus_no = bus;
2N/A prg.dev_no = dev;
2N/A prg.func_no = func;
2N/A prg.offset = offset;
2N/A rval = ioctl(fd, PCITOOL_DEVICE_GET_REG, &prg);
2N/A if (rval != 0) {
2N/A log_printf("DEV_GET failed %d %s\n", rval, strerror(errno));
2N/A log_printf("%d.%d.%d offset 0x%x\n", bus, dev, func, offset);
2N/A }
2N/A *ret = rval;
2N/A return ((uint32_t)prg.data);
2N/A}
2N/A
2N/Astatic uint16_t
2N/Aread_word(int fd, int bus, int dev, int func, int offset, int *ret)
2N/A{
2N/A int rval;
2N/A pcitool_reg_t prg;
2N/A
2N/A prg.user_version = PCITOOL_VERSION;
2N/A prg.barnum = 0;
2N/A prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_2 +
2N/A PCITOOL_ACC_ATTR_ENDN_LTL;
2N/A prg.bus_no = bus;
2N/A prg.dev_no = dev;
2N/A prg.func_no = func;
2N/A prg.offset = offset;
2N/A rval = ioctl(fd, PCITOOL_DEVICE_GET_REG, &prg);
2N/A if (rval != 0) {
2N/A log_printf("DEV_GET failed %d %s\n", rval, strerror(errno));
2N/A log_printf("%d.%d.%d offset 0x%x\n", bus, dev, func, offset);
2N/A }
2N/A *ret = rval;
2N/A return ((uint16_t)prg.data);
2N/A}
2N/A
2N/Astatic uint8_t
2N/Aread_byte(int fd, int bus, int dev, int func, int offset, int *ret)
2N/A{
2N/A int rval;
2N/A pcitool_reg_t prg;
2N/A
2N/A prg.user_version = PCITOOL_VERSION;
2N/A prg.barnum = 0;
2N/A prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_1 +
2N/A PCITOOL_ACC_ATTR_ENDN_LTL;
2N/A prg.bus_no = bus;
2N/A prg.dev_no = dev;
2N/A prg.func_no = func;
2N/A prg.offset = offset;
2N/A rval = ioctl(fd, PCITOOL_DEVICE_GET_REG, &prg);
2N/A if (rval != 0) {
2N/A log_printf("DEV_GET failed %d %s\n", rval, strerror(errno));
2N/A log_printf("%d.%d.%d offset 0x%x\n", bus, dev, func, offset);
2N/A }
2N/A *ret = rval;
2N/A return ((uint8_t)prg.data);
2N/A}
2N/A
2N/A
2N/Astatic picl_errno_t
2N/Aget_lane_width
2N/A (char *device_path, int bus, int dev, int func, int *actual,
2N/A int *maximum, uint32_t *speed_max, uint32_t *speed_at, int *type)
2N/A{
2N/A uint_t cap_ptr, cap_reg, link_status, link_cap, capid;
2N/A int fd, ret;
2N/A
2N/A if (device_path == NULL)
2N/A return (PICL_FAILURE);
2N/A
2N/A fd = open_root_complex(device_path);
2N/A if (fd == -1)
2N/A return (PICL_FAILURE);
2N/A
2N/A /*
2N/A * Link Capabilities and Link Status registers are in the
2N/A * PCI-E capabilities register. They are at offset
2N/A * 0xc and 0x12 respectively. They are documented in section
2N/A * 7.8 of the PCI Express Base Specification. The address of
2N/A * that structure is not fixed, it's kind of a linked list.
2N/A * The Capabilities Pointer reg (8 bits) is always at 0x34.
2N/A * It contains a pointer to the first capabilities structure.
2N/A * For each capability structure, the first 8 bits is the capability
2N/A * ID. The next 8 bits is the pointer to the next structure.
2N/A * If the Next Cap register is zero, it's the end of the list.
2N/A * The capability ID for the PCI-E strucutre is 0x10. The idea
2N/A * is to follow the links until you find a Cap ID of 0x10, then
2N/A * read the registers at 0xc and 0x12 from there.
2N/A * If there's no Cap ID 0x10, then it's not a PCI-E device.
2N/A */
2N/A
2N/A cap_ptr = read_byte(fd, bus, dev, func, PCI_CONF_CAP_PTR, &ret);
2N/A if (ret != 0) {
2N/A /* ioctl failure */
2N/A close(fd);
2N/A return (PICL_FAILURE);
2N/A }
2N/A cap_reg = read_word(fd, bus, dev, func, cap_ptr, &ret);
2N/A if (ret != 0) {
2N/A /* ioctl failure */
2N/A close(fd);
2N/A return (PICL_FAILURE);
2N/A }
2N/A *type = PCI;
2N/A capid = cap_reg & PCI_CAP_MASK;
2N/A while (cap_ptr != 0) {
2N/A
2N/A if (capid == PCI_CAP_ID_PCI_E) {
2N/A link_cap = read_long(fd, bus, dev, func, cap_ptr +
2N/A PCIE_LINKCAP, &ret);
2N/A if (ret != 0) {
2N/A close(fd);
2N/A return (PICL_FAILURE);
2N/A }
2N/A link_status = read_word(fd, bus, dev, func,
2N/A cap_ptr + PCIE_LINKSTS, &ret);
2N/A if (ret != 0) {
2N/A close(fd);
2N/A return (PICL_FAILURE);
2N/A }
2N/A *actual = ((link_status >> PCI_LINK_SHIFT) &
2N/A PCI_LINK_MASK);
2N/A *maximum = ((link_cap >> PCI_LINK_SHIFT) &
2N/A PCI_LINK_MASK);
2N/A *type = PCIE;
2N/A } else if (capid == PCI_CAP_ID_PCIX) {
2N/A uint32_t pcix_status;
2N/A uint8_t hdr_type;
2N/A int max_speed = PCI_FREQ_66;
2N/A
2N/A hdr_type = read_byte
2N/A (fd, bus, dev, func, PCI_CONF_HEADER, &ret);
2N/A if (ret != 0) {
2N/A /* ioctl failure */
2N/A close(fd);
2N/A return (PICL_FAILURE);
2N/A }
2N/A *type = PCIX;
2N/A if ((hdr_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) {
2N/A /* This is a PCI-X bridge */
2N/A uint16_t sec_status, mode;
2N/A sec_status = read_word(fd, bus, dev, func,
2N/A cap_ptr + PCI_PCIX_SEC_STATUS, &ret);
2N/A if (ret != 0) {
2N/A /* ioctl failure */
2N/A close(fd);
2N/A return (PICL_FAILURE);
2N/A }
2N/A if (sec_status & PCI_SEC_133)
2N/A max_speed = PCI_FREQ_133;
2N/A if (sec_status & PCI_SEC_266)
2N/A max_speed = PCI_FREQ_266;
2N/A if (sec_status & PCI_SEC_533)
2N/A max_speed = PCI_FREQ_533;
2N/A *speed_max = max_speed;
2N/A mode = (sec_status >> PCI_CLASS_BRIDGE) &
2N/A PCI_BRIDGE_MC;
2N/A if (mode) {
2N/A int speed;
2N/A if (mode == PCI_MODE_66)
2N/A speed = PCI_FREQ_66;
2N/A else if (mode == PCI_MODE_100)
2N/A speed = PCI_FREQ_100;
2N/A else if (mode == PCI_MODE_133)
2N/A speed = PCI_FREQ_133;
2N/A *speed_at = speed;
2N/A }
2N/A
2N/A } else { /* Leaf device */
2N/A pcix_status = read_long(fd, bus, dev, func,
2N/A cap_ptr + PCI_PCIX_STATUS, &ret);
2N/A if (ret != 0) {
2N/A /* ioctl failure */
2N/A close(fd);
2N/A return (PICL_FAILURE);
2N/A }
2N/A if (pcix_status &
2N/A (PCI_LEAF_ULONG << PCI_SHIFT_133))
2N/A max_speed = PCI_FREQ_133;
2N/A if (pcix_status &
2N/A (PCI_LEAF_ULONG << PCI_SHIFT_266))
2N/A max_speed = PCI_FREQ_266;
2N/A if (pcix_status &
2N/A (PCI_LEAF_ULONG << PCI_SHIFT_533))
2N/A max_speed = PCI_FREQ_533;
2N/A *speed_max = max_speed;
2N/A }
2N/A }
2N/A cap_ptr = (cap_reg >> PCI_REG_FUNC_SHIFT);
2N/A cap_reg = read_word(fd, bus, dev, func, cap_ptr, &ret);
2N/A if (ret != 0) {
2N/A /* ioctl failure */
2N/A close(fd);
2N/A return (PICL_FAILURE);
2N/A }
2N/A capid = cap_reg & PCI_CAP_MASK;
2N/A }
2N/A
2N/A if (close(fd) == -1) {
2N/A return (PICL_FAILURE);
2N/A }
2N/A
2N/A return (PICL_SUCCESS);
2N/A}
2N/A
2N/Astatic int
2N/Ais_66mhz_capable(picl_nodehdl_t nodeh)
2N/A{
2N/A picl_errno_t err;
2N/A picl_prophdl_t proph;
2N/A picl_propinfo_t pinfo;
2N/A
2N/A err = picl_get_propinfo_by_name(nodeh, OBP_PROP_66MHZ_CAPABLE,
2N/A &pinfo, &proph);
2N/A if (err == PICL_SUCCESS)
2N/A return (1);
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * get the clock frequency
2N/A */
2N/Astatic int
2N/Apicldiag_get_clock_freq(picl_nodehdl_t modh, uint32_t *freq, uint32_t *freq_max)
2N/A{
2N/A int err;
2N/A uint64_t clk_freq;
2N/A
2N/A *freq_max = PCI_FREQ_33;
2N/A if (is_66mhz_capable(modh))
2N/A *freq_max = PCI_FREQ_66;
2N/A clk_freq = picldiag_get_uint_propval(modh, OBP_PROP_CLOCK_FREQ, &err);
2N/A if (err != PICL_SUCCESS)
2N/A return (err);
2N/A
2N/A *freq = ROUND_TO_MHZ(clk_freq);
2N/A
2N/A return (PICL_SUCCESS);
2N/A}
2N/A
2N/Astatic uint64_t
2N/Apicldiag_get_uint_propval(picl_nodehdl_t modh, char *prop_name, int *ret)
2N/A{
2N/A int err;
2N/A picl_prophdl_t proph;
2N/A picl_propinfo_t pinfo;
2N/A uint8_t uint8v;
2N/A uint16_t uint16v;
2N/A uint32_t uint32v;
2N/A uint64_t uint64v;
2N/A
2N/A err = picl_get_propinfo_by_name(modh, prop_name, &pinfo, &proph);
2N/A if (err != PICL_SUCCESS) {
2N/A *ret = err;
2N/A return (0);
2N/A }
2N/A
2N/A /*
2N/A * If it is not an int or uint prop, return failure
2N/A */
2N/A if ((pinfo.type != PICL_PTYPE_INT) &&
2N/A (pinfo.type != PICL_PTYPE_UNSIGNED_INT)) {
2N/A *ret = PICL_FAILURE;
2N/A return (0);
2N/A }
2N/A
2N/A
2N/A /* uint prop */
2N/A
2N/A switch (pinfo.size) {
2N/A case sizeof (uint8_t):
2N/A err = picl_get_propval(proph, &uint8v, sizeof (uint8v));
2N/A *ret = err;
2N/A return (uint8v);
2N/A case sizeof (uint16_t):
2N/A err = picl_get_propval(proph, &uint16v, sizeof (uint16v));
2N/A *ret = err;
2N/A return (uint16v);
2N/A case sizeof (uint32_t):
2N/A err = picl_get_propval(proph, &uint32v, sizeof (uint32v));
2N/A *ret = err;
2N/A return (uint32v);
2N/A case sizeof (uint64_t):
2N/A err = picl_get_propval(proph, &uint64v, sizeof (uint64v));
2N/A *ret = err;
2N/A return (uint64v);
2N/A default: /* not supported size */
2N/A *ret = PICL_FAILURE;
2N/A return (0);
2N/A }
2N/A}
2N/A
2N/A/*
2N/A * recursively visit all nodes
2N/A */
2N/Astatic picl_errno_t
2N/Ado_walk(picl_nodehdl_t rooth, const char *classname,
2N/A void *c_args, picl_errno_t (*callback_fn)(picl_nodehdl_t hdl, void *args))
2N/A{
2N/A picl_errno_t err;
2N/A picl_nodehdl_t chdh;
2N/A char classval[PICL_CLASSNAMELEN_MAX];
2N/A
2N/A err = picl_get_propval_by_name(rooth, PICL_PROP_CHILD, &chdh,
2N/A sizeof (chdh));
2N/A while (err == PICL_SUCCESS) {
2N/A err = picl_get_propval_by_name(chdh, PICL_PROP_NAME,
2N/A classval, sizeof (classval));
2N/A if (err != PICL_SUCCESS)
2N/A return (err);
2N/A
2N/A err = callback_fn(chdh, c_args);
2N/A
2N/A if ((err = do_walk(chdh, classname, c_args, callback_fn)) !=
2N/A PICL_WALK_CONTINUE)
2N/A return (err);
2N/A
2N/A err = picl_get_propval_by_name(chdh, PICL_PROP_PEER, &chdh,
2N/A sizeof (chdh));
2N/A }
2N/A if (err == PICL_PROPNOTFOUND) /* end of a branch */
2N/A return (PICL_WALK_CONTINUE);
2N/A return (err);
2N/A}
2N/A
2N/Aint
2N/Aget_proc_mode(void)
2N/A{
2N/A picl_nodehdl_t nodeh;
2N/A picl_prophdl_t proph;
2N/A picl_errno_t err;
2N/A
2N/A err = picl_initialize();
2N/A if (err != PICL_SUCCESS) {
2N/A (void) log_printf("picl_initialize failed: %s\n",
2N/A picl_strerror(err));
2N/A return (err);
2N/A }
2N/A
2N/A err = picl_get_node_by_path("/platform", &nodeh);
2N/A if (err != PICL_SUCCESS) {
2N/A (void) log_printf("Getting plat node failed: %s\n",
2N/A picl_strerror(err));
2N/A return (err);
2N/A }
2N/A
2N/A err = picl_get_prop_by_name(nodeh, "SPARC64-VII-mode", &proph);
2N/A if (err != PICL_SUCCESS) {
2N/A /* Do not display error message */
2N/A return (err);
2N/A }
2N/A
2N/A (void) picl_shutdown();
2N/A
2N/A return (err);
2N/A}