1d5ace945SErwin T Tsaur /* 2d5ace945SErwin T Tsaur * CDDL HEADER START 3d5ace945SErwin T Tsaur * 4d5ace945SErwin T Tsaur * The contents of this file are subject to the terms of the 5d5ace945SErwin T Tsaur * Common Development and Distribution License (the "License"). 6d5ace945SErwin T Tsaur * You may not use this file except in compliance with the License. 7d5ace945SErwin T Tsaur * 8d5ace945SErwin T Tsaur * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9d5ace945SErwin T Tsaur * or http://www.opensolaris.org/os/licensing. 10d5ace945SErwin T Tsaur * See the License for the specific language governing permissions 11d5ace945SErwin T Tsaur * and limitations under the License. 12d5ace945SErwin T Tsaur * 13d5ace945SErwin T Tsaur * When distributing Covered Code, include this CDDL HEADER in each 14d5ace945SErwin T Tsaur * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15d5ace945SErwin T Tsaur * If applicable, add the following below this CDDL HEADER, with the 16d5ace945SErwin T Tsaur * fields enclosed by brackets "[]" replaced with your own identifying 17d5ace945SErwin T Tsaur * information: Portions Copyright [yyyy] [name of copyright owner] 18d5ace945SErwin T Tsaur * 19d5ace945SErwin T Tsaur * CDDL HEADER END 20d5ace945SErwin T Tsaur */ 21d5ace945SErwin T Tsaur /* 228d7fafffSZhi-Jun Robin Fu * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. 23d5ace945SErwin T Tsaur */ 24d5ace945SErwin T Tsaur 25d5ace945SErwin T Tsaur /* This file is the main module for the pcitool. */ 26d5ace945SErwin T Tsaur 27d5ace945SErwin T Tsaur #include <stdio.h> 28d5ace945SErwin T Tsaur #include <stdlib.h> 29d5ace945SErwin T Tsaur #include <unistd.h> 30d5ace945SErwin T Tsaur #include <sys/inttypes.h> 31d5ace945SErwin T Tsaur #include <signal.h> 32d5ace945SErwin T Tsaur #include <sys/types.h> 33d5ace945SErwin T Tsaur #include <sys/param.h> 34d5ace945SErwin T Tsaur #include <fcntl.h> 35d5ace945SErwin T Tsaur #include <strings.h> 36d5ace945SErwin T Tsaur #include <ctype.h> 37d5ace945SErwin T Tsaur #include <errno.h> 38d5ace945SErwin T Tsaur #include <libdevinfo.h> 39d5ace945SErwin T Tsaur #include <sys/sunddi.h> 40d5ace945SErwin T Tsaur 41d5ace945SErwin T Tsaur #ifdef __x86 42d5ace945SErwin T Tsaur #include <sys/apic_ctlr.h> 43d5ace945SErwin T Tsaur #endif 44d5ace945SErwin T Tsaur 45d5ace945SErwin T Tsaur #include <sys/pci.h> 46d5ace945SErwin T Tsaur #include <sys/pci_tools.h> 47d5ace945SErwin T Tsaur 48d5ace945SErwin T Tsaur #include "pcitool_ui.h" 49d5ace945SErwin T Tsaur 50d5ace945SErwin T Tsaur /* First 16 longs of device PCI config header. */ 51d5ace945SErwin T Tsaur typedef union { 52d5ace945SErwin T Tsaur uint8_t bytes[16 * sizeof (uint32_t)]; 53d5ace945SErwin T Tsaur uint32_t dwords[16]; 54d5ace945SErwin T Tsaur } pci_conf_hdr_t; 55d5ace945SErwin T Tsaur 56d5ace945SErwin T Tsaur /* Used by probe printing functions. */ 57d5ace945SErwin T Tsaur typedef struct { 58d5ace945SErwin T Tsaur uint16_t cfg_offset; /* Offset of data within config space. */ 59d5ace945SErwin T Tsaur uint8_t size; /* Size of desired data field. */ 60d5ace945SErwin T Tsaur char *abbrev_hdr; /* Abbreviated header for this data. */ 61d5ace945SErwin T Tsaur char *full_hdr; /* Full header for this data, verbose option. */ 62d5ace945SErwin T Tsaur } field_type_t; 63d5ace945SErwin T Tsaur 64d5ace945SErwin T Tsaur /* Used to package many args into one arg for probe di_node walk function. */ 65d5ace945SErwin T Tsaur typedef struct { 66d5ace945SErwin T Tsaur pcitool_uiargs_t *input_args_p; 67d5ace945SErwin T Tsaur char *pathname; 68d5ace945SErwin T Tsaur di_prom_handle_t di_phdl; 69d5ace945SErwin T Tsaur } probe_walk_args_t; 70d5ace945SErwin T Tsaur 71d5ace945SErwin T Tsaur /* 72d5ace945SErwin T Tsaur * Read config space in native processor endianness. Endian-neutral 73d5ace945SErwin T Tsaur * processing can then take place. On big endian machines, MSB and LSB 74d5ace945SErwin T Tsaur * of little endian data end up switched if read as little endian. 75d5ace945SErwin T Tsaur * They are in correct order if read as big endian. 76d5ace945SErwin T Tsaur */ 77d5ace945SErwin T Tsaur #if defined(__sparc) 78d5ace945SErwin T Tsaur #define NATIVE_ENDIAN PCITOOL_ACC_ATTR_ENDN_BIG 79d5ace945SErwin T Tsaur #elif defined(__x86) 80d5ace945SErwin T Tsaur #define NATIVE_ENDIAN PCITOOL_ACC_ATTR_ENDN_LTL 81d5ace945SErwin T Tsaur #else 82d5ace945SErwin T Tsaur #error "ISA is neither __sparc nor __x86" 83d5ace945SErwin T Tsaur #endif 84d5ace945SErwin T Tsaur 85d5ace945SErwin T Tsaur /* status error lookup table. */ 86d5ace945SErwin T Tsaur static struct { 87d5ace945SErwin T Tsaur pcitool_errno_t value; 88d5ace945SErwin T Tsaur char *string; 89d5ace945SErwin T Tsaur } pcitool_stat_str[] = { 90d5ace945SErwin T Tsaur { PCITOOL_SUCCESS, 91d5ace945SErwin T Tsaur "No error status returned from driver" }, 92d5ace945SErwin T Tsaur { PCITOOL_INVALID_CPUID, 93d5ace945SErwin T Tsaur "CPU is non-existent or not online" }, 94d5ace945SErwin T Tsaur { PCITOOL_INVALID_INO, 95d5ace945SErwin T Tsaur "INO is out of range or invalid" }, 9609b1eac2SEvan Yan { PCITOOL_INVALID_MSI, 9709b1eac2SEvan Yan "MSI is out of range or invalid" }, 98d5ace945SErwin T Tsaur { PCITOOL_PENDING_INTRTIMEOUT, 99d5ace945SErwin T Tsaur "Timeout waiting for pending interrupts to clear" }, 100d5ace945SErwin T Tsaur { PCITOOL_REGPROP_NOTWELLFORMED, 101d5ace945SErwin T Tsaur "Reg property has invalid format" }, 102d5ace945SErwin T Tsaur { PCITOOL_INVALID_ADDRESS, 103d5ace945SErwin T Tsaur "Address out of range or invalid" }, 104d5ace945SErwin T Tsaur { PCITOOL_NOT_ALIGNED, 105d5ace945SErwin T Tsaur "Improper address alignment for access attempted" }, 106d5ace945SErwin T Tsaur { PCITOOL_OUT_OF_RANGE, 107d5ace945SErwin T Tsaur "Argument out of range" }, 108d5ace945SErwin T Tsaur { PCITOOL_END_OF_RANGE, 109d5ace945SErwin T Tsaur "End of address range" }, 110d5ace945SErwin T Tsaur { PCITOOL_ROM_DISABLED, 111d5ace945SErwin T Tsaur "Device ROM is disabled. Cannot read" }, 112d5ace945SErwin T Tsaur { PCITOOL_ROM_WRITE, 113d5ace945SErwin T Tsaur "Write to ROM not allowed" }, 114d5ace945SErwin T Tsaur { PCITOOL_IO_ERROR, 115d5ace945SErwin T Tsaur "IO error encountered" }, 116d5ace945SErwin T Tsaur { PCITOOL_INVALID_SIZE, 117d5ace945SErwin T Tsaur "Size is invalid for this platform" }, 118d5ace945SErwin T Tsaur { 0, NULL } 119d5ace945SErwin T Tsaur }; 120d5ace945SErwin T Tsaur 121d5ace945SErwin T Tsaur 122d5ace945SErwin T Tsaur /* Used with ^C handler to stop looping in repeat mode in do_device_or_nexus. */ 123d5ace945SErwin T Tsaur static boolean_t keep_looping = B_TRUE; 124d5ace945SErwin T Tsaur 125d5ace945SErwin T Tsaur static void signal_handler(int dummy); 126d5ace945SErwin T Tsaur static char *strstatus(pcitool_errno_t pcitool_status); 127d5ace945SErwin T Tsaur static int open_node(char *device, pcitool_uiargs_t *input_args_p); 128d5ace945SErwin T Tsaur static void print_probe_value(pci_conf_hdr_t *config_hdr_p, uint16_t offset, 129d5ace945SErwin T Tsaur uint8_t size); 130d5ace945SErwin T Tsaur static void print_probe_info_verbose(pci_conf_hdr_t *config_hdr_p, 131d5ace945SErwin T Tsaur pcitool_reg_t *info_p); 132d5ace945SErwin T Tsaur static void print_probe_info_nonverbose(pci_conf_hdr_t *config_hdr_p, 133d5ace945SErwin T Tsaur pcitool_reg_t *info_p); 134d5ace945SErwin T Tsaur static void print_probe_info(pci_conf_hdr_t *config_hdr_p, 135d5ace945SErwin T Tsaur pcitool_reg_t *info_p, boolean_t verbose); 136d5ace945SErwin T Tsaur static int get_config_header(int fd, uint8_t bus_no, uint8_t dev_no, 137d5ace945SErwin T Tsaur uint8_t func_no, pci_conf_hdr_t *config_hdr_p); 13826947304SEvan Yan static int supports_ari(int fd, uint8_t bus_no); 139d5ace945SErwin T Tsaur static int probe_dev(int fd, pcitool_reg_t *prg_p, 140d5ace945SErwin T Tsaur pcitool_uiargs_t *input_args_p); 141d5ace945SErwin T Tsaur static int do_probe(int fd, di_node_t di_node, di_prom_handle_t di_phdl, 142d5ace945SErwin T Tsaur pcitool_uiargs_t *input_args_p); 143d5ace945SErwin T Tsaur static int process_nexus_node(di_node_t node, di_minor_t minor, void *arg); 144d5ace945SErwin T Tsaur static int do_probe_walk(pcitool_uiargs_t *input_args_p, char *pathname); 145d5ace945SErwin T Tsaur static void print_bytedump_header(boolean_t do_chardump); 146d5ace945SErwin T Tsaur static int bytedump_get(int fd, int cmd, pcitool_reg_t *prg_p, 147d5ace945SErwin T Tsaur pcitool_uiargs_t *input_args_p); 148d5ace945SErwin T Tsaur static uint32_t set_acc_attr(pcitool_uiargs_t *input_args_p); 149d5ace945SErwin T Tsaur static int do_single_access(int fd, int cmd, pcitool_reg_t *prg_p, 150d5ace945SErwin T Tsaur pcitool_uiargs_t *input_args_p); 151d5ace945SErwin T Tsaur static int do_device_or_nexus(int fd, pcitool_uiargs_t *input_args_p); 152d5ace945SErwin T Tsaur static void print_intr_info(pcitool_intr_get_t *iget_p); 153d5ace945SErwin T Tsaur static int get_single_interrupt(int fd, pcitool_intr_get_t **iget_pp, 154d5ace945SErwin T Tsaur pcitool_uiargs_t *input_args_p); 155d5ace945SErwin T Tsaur static int get_interrupts(int fd, pcitool_uiargs_t *input_args_p); 156d5ace945SErwin T Tsaur static int set_interrupts(int fd, pcitool_uiargs_t *input_args_p); 157d5ace945SErwin T Tsaur static int do_interrupts(int fd, pcitool_uiargs_t *input_args_p); 158d5ace945SErwin T Tsaur 159d5ace945SErwin T Tsaur 160d5ace945SErwin T Tsaur /* *************** General ************** */ 161d5ace945SErwin T Tsaur 162d5ace945SErwin T Tsaur /* 163d5ace945SErwin T Tsaur * Handler for ^C to stop looping. 164d5ace945SErwin T Tsaur */ 165d5ace945SErwin T Tsaur /*ARGSUSED*/ 166d5ace945SErwin T Tsaur static void 167d5ace945SErwin T Tsaur signal_handler(int dummy) 168d5ace945SErwin T Tsaur { 169d5ace945SErwin T Tsaur keep_looping = B_FALSE; 170d5ace945SErwin T Tsaur } 171d5ace945SErwin T Tsaur 172d5ace945SErwin T Tsaur 173d5ace945SErwin T Tsaur /* 174d5ace945SErwin T Tsaur * Print string based on PCItool status returned from driver. 175d5ace945SErwin T Tsaur */ 176d5ace945SErwin T Tsaur static char * 177d5ace945SErwin T Tsaur strstatus(pcitool_errno_t pcitool_status) 178d5ace945SErwin T Tsaur { 179d5ace945SErwin T Tsaur int i; 180d5ace945SErwin T Tsaur 181d5ace945SErwin T Tsaur for (i = 0; pcitool_stat_str[i].string != NULL; i++) { 182d5ace945SErwin T Tsaur if (pcitool_stat_str[i].value == pcitool_status) { 183d5ace945SErwin T Tsaur 184d5ace945SErwin T Tsaur return (pcitool_stat_str[i].string); 185d5ace945SErwin T Tsaur } 186d5ace945SErwin T Tsaur } 187d5ace945SErwin T Tsaur 188d5ace945SErwin T Tsaur return ("Unknown status returned from driver."); 189d5ace945SErwin T Tsaur } 190d5ace945SErwin T Tsaur 191d5ace945SErwin T Tsaur 192d5ace945SErwin T Tsaur static int 193d5ace945SErwin T Tsaur open_node(char *device, pcitool_uiargs_t *input_args_p) 194d5ace945SErwin T Tsaur { 195d5ace945SErwin T Tsaur int fd; 196d5ace945SErwin T Tsaur char *path; /* For building full nexus pathname. */ 197d5ace945SErwin T Tsaur int stringsize; /* Device name size. */ 198d5ace945SErwin T Tsaur char *prefix; 199d5ace945SErwin T Tsaur char *suffix; 200d5ace945SErwin T Tsaur char *format; 201d5ace945SErwin T Tsaur 202d5ace945SErwin T Tsaur static char slash_devices[] = {"/devices"}; 203d5ace945SErwin T Tsaur static char wcolon[] = {"%s%s:%s"}; 204d5ace945SErwin T Tsaur static char wocolon[] = {"%s%s%s"}; 205d5ace945SErwin T Tsaur 206d5ace945SErwin T Tsaur /* Check for names starting with /devices. */ 207d5ace945SErwin T Tsaur prefix = (strstr(device, slash_devices) == device) ? "" : slash_devices; 208d5ace945SErwin T Tsaur 209d5ace945SErwin T Tsaur format = wcolon; 210d5ace945SErwin T Tsaur if (input_args_p->flags & INTR_FLAG) { 211d5ace945SErwin T Tsaur if (strstr(device, PCI_MINOR_INTR) == 212d5ace945SErwin T Tsaur device + (strlen(device) - strlen(PCI_MINOR_INTR))) { 213d5ace945SErwin T Tsaur suffix = ""; 214d5ace945SErwin T Tsaur format = wocolon; 215d5ace945SErwin T Tsaur } else { 216d5ace945SErwin T Tsaur suffix = PCI_MINOR_INTR; 217d5ace945SErwin T Tsaur } 218d5ace945SErwin T Tsaur } else { 219d5ace945SErwin T Tsaur if (strstr(device, PCI_MINOR_REG) == 220d5ace945SErwin T Tsaur device + (strlen(device) - strlen(PCI_MINOR_REG))) { 221d5ace945SErwin T Tsaur suffix = ""; 222d5ace945SErwin T Tsaur format = wocolon; 223d5ace945SErwin T Tsaur } else { 224d5ace945SErwin T Tsaur suffix = PCI_MINOR_REG; 225d5ace945SErwin T Tsaur } 226d5ace945SErwin T Tsaur } 227d5ace945SErwin T Tsaur 228d5ace945SErwin T Tsaur /* 229d5ace945SErwin T Tsaur * Build nexus pathname. 230d5ace945SErwin T Tsaur * User specified /pci@1f,700000 becomes /devices/pci@1f,700000:intr 231d5ace945SErwin T Tsaur * for interrupt nodes, and ...:reg for register nodes. 232d5ace945SErwin T Tsaur * 233d5ace945SErwin T Tsaur * ...The 2 at the end leaves room for a : and the terminating NULL. 234d5ace945SErwin T Tsaur */ 235d5ace945SErwin T Tsaur stringsize = strlen(prefix) + strlen(device) + strlen(suffix) + 2; 236d5ace945SErwin T Tsaur path = malloc(stringsize); 237d5ace945SErwin T Tsaur 238d5ace945SErwin T Tsaur /*LINTED*/ 239d5ace945SErwin T Tsaur (void) snprintf(path, stringsize, format, prefix, device, suffix); 240d5ace945SErwin T Tsaur 241d5ace945SErwin T Tsaur /* Open the nexus. */ 242d5ace945SErwin T Tsaur if ((fd = open(path, O_RDWR)) == -1) { 243d5ace945SErwin T Tsaur if (!(IS_QUIET(input_args_p->flags))) { 244d5ace945SErwin T Tsaur (void) fprintf(stderr, 245d5ace945SErwin T Tsaur "Could not open nexus node %s: %s\n", 246d5ace945SErwin T Tsaur path, strerror(errno)); 247d5ace945SErwin T Tsaur } 248d5ace945SErwin T Tsaur } 249d5ace945SErwin T Tsaur 250d5ace945SErwin T Tsaur return (fd); 251d5ace945SErwin T Tsaur } 252d5ace945SErwin T Tsaur 253d5ace945SErwin T Tsaur 254d5ace945SErwin T Tsaur /* ****************** Probe **************** */ 255d5ace945SErwin T Tsaur 256d5ace945SErwin T Tsaur /* The following are used by the probe printing functions. */ 257d5ace945SErwin T Tsaur 258d5ace945SErwin T Tsaur /* Header 0 and 1 config space headers have these fields. */ 259d5ace945SErwin T Tsaur static field_type_t first_fields[] = { 260d5ace945SErwin T Tsaur { PCI_CONF_VENID, 2, "Vend", "Vendor ID" }, 261d5ace945SErwin T Tsaur { PCI_CONF_DEVID, 2, "Dev ", "Device ID" }, 262d5ace945SErwin T Tsaur { PCI_CONF_COMM, 2, "Cmd ", "Command" }, 263d5ace945SErwin T Tsaur { PCI_CONF_STAT, 2, "Stat", "Status" }, 264d5ace945SErwin T Tsaur { PCI_CONF_REVID, 1, "Rv", "Revision ID" }, 265d5ace945SErwin T Tsaur { PCI_CONF_PROGCLASS, 3, "Class ", "Class Code" }, 266d5ace945SErwin T Tsaur { PCI_CONF_CACHE_LINESZ, 1, "Ca", "Cache Line Size" }, 267d5ace945SErwin T Tsaur { PCI_CONF_LATENCY_TIMER, 1, "LT", "Latency Timer" }, 268d5ace945SErwin T Tsaur { PCI_CONF_HEADER, 1, "Hd", "Header Type" }, 269d5ace945SErwin T Tsaur { PCI_CONF_BIST, 1, "BI", "BIST" }, 270d5ace945SErwin T Tsaur { 0, 0, NULL, NULL } 271d5ace945SErwin T Tsaur }; 272d5ace945SErwin T Tsaur 273d5ace945SErwin T Tsaur /* Header 0 (for regular devices) have these fields. */ 274d5ace945SErwin T Tsaur static field_type_t last_dev_fields[] = { 275d5ace945SErwin T Tsaur { PCI_CONF_BASE0, 4, "BAR0", "Base Address Register 0 (@10)" }, 276d5ace945SErwin T Tsaur { PCI_CONF_BASE1, 4, "BAR1", "Base Address Register 1 (@14)" }, 277d5ace945SErwin T Tsaur { PCI_CONF_BASE2, 4, "BAR2", "Base Address Register 2 (@18)" }, 278d5ace945SErwin T Tsaur { PCI_CONF_BASE3, 4, "BAR3", "Base Address Register 3 (@1C)" }, 279d5ace945SErwin T Tsaur { PCI_CONF_BASE4, 4, "BAR4", "Base Address Register 4 (@20)" }, 280d5ace945SErwin T Tsaur { PCI_CONF_BASE5, 4, "BAR5", "Base Address Register 5 (@24)" }, 281d5ace945SErwin T Tsaur { PCI_CONF_ROM, 4, "ROM", "Expansion ROM Base Address Register (@30)" }, 282d5ace945SErwin T Tsaur { 0, 0, NULL, NULL } 283d5ace945SErwin T Tsaur }; 284d5ace945SErwin T Tsaur 285d5ace945SErwin T Tsaur /* Header 1 (PCI-PCI bridge devices) have these fields. */ 286d5ace945SErwin T Tsaur static field_type_t last_pcibrg_fields[] = { 287d5ace945SErwin T Tsaur { PCI_CONF_BASE0, 4, "BAR0", "Base Address Register 0 (@10)" }, 288d5ace945SErwin T Tsaur { PCI_CONF_BASE1, 4, "BAR1", "Base Address Register 1 (@14)" }, 289d5ace945SErwin T Tsaur { PCI_BCNF_ROM, 4, "ROM", "Expansion ROM Base Address Register (@38)" }, 290d5ace945SErwin T Tsaur { 0, 0, NULL, NULL } 291d5ace945SErwin T Tsaur }; 292d5ace945SErwin T Tsaur 293d5ace945SErwin T Tsaur /* Header 2 (PCI-Cardbus bridge devices) have these fields. */ 294d5ace945SErwin T Tsaur static field_type_t last_cbbrg_fields[] = { 295d5ace945SErwin T Tsaur { PCI_CBUS_SOCK_REG, 4, "SCKT", "Socket/ExCA Base Address (@10)" }, 296d5ace945SErwin T Tsaur { 0, 0, NULL, NULL } 297d5ace945SErwin T Tsaur }; 298d5ace945SErwin T Tsaur 299d5ace945SErwin T Tsaur #define FMT_SIZE 7 300d5ace945SErwin T Tsaur 301d5ace945SErwin T Tsaur static void 302d5ace945SErwin T Tsaur print_probe_value(pci_conf_hdr_t *config_hdr_p, uint16_t offset, uint8_t size) 303d5ace945SErwin T Tsaur { 304d5ace945SErwin T Tsaur 305d5ace945SErwin T Tsaur char format[FMT_SIZE]; 306d5ace945SErwin T Tsaur 307d5ace945SErwin T Tsaur 308d5ace945SErwin T Tsaur /* Size cannot be any larger than 4 bytes. This is not checked. */ 309d5ace945SErwin T Tsaur uint32_t value = 0; 310d5ace945SErwin T Tsaur 311d5ace945SErwin T Tsaur /* Build format of print, "%<size*2>.<size*2>x" */ 312d5ace945SErwin T Tsaur (void) snprintf(format, FMT_SIZE, "%%%d.%dx ", size * 2, size * 2); 313d5ace945SErwin T Tsaur 314d5ace945SErwin T Tsaur while (size-- > 0) { 315d5ace945SErwin T Tsaur value = (value << 8) + config_hdr_p->bytes[offset + size]; 316d5ace945SErwin T Tsaur } 317d5ace945SErwin T Tsaur 318d5ace945SErwin T Tsaur /*LINTED*/ 319d5ace945SErwin T Tsaur (void) printf(format, value); 320d5ace945SErwin T Tsaur } 321d5ace945SErwin T Tsaur 322d5ace945SErwin T Tsaur static void 323d5ace945SErwin T Tsaur print_probe_info_verbose(pci_conf_hdr_t *config_hdr_p, pcitool_reg_t *info_p) 324d5ace945SErwin T Tsaur { 325d5ace945SErwin T Tsaur field_type_t *last_fields = NULL; 326d5ace945SErwin T Tsaur int i; 327d5ace945SErwin T Tsaur 328d5ace945SErwin T Tsaur (void) printf("\n" 329d5ace945SErwin T Tsaur "Bus Number: %x Device Number: %x Function Number: %x\n", 330d5ace945SErwin T Tsaur info_p->bus_no, info_p->dev_no, info_p->func_no); 331d5ace945SErwin T Tsaur if (info_p->phys_addr != 0) { 332d5ace945SErwin T Tsaur (void) printf("Physical Address: 0x%" PRIx64 " \n", 333d5ace945SErwin T Tsaur info_p->phys_addr); 334d5ace945SErwin T Tsaur } 335d5ace945SErwin T Tsaur 336d5ace945SErwin T Tsaur switch (config_hdr_p->bytes[PCI_CONF_HEADER] & PCI_HEADER_TYPE_M) { 337d5ace945SErwin T Tsaur 338d5ace945SErwin T Tsaur case PCI_HEADER_ZERO: /* Header type 0 is a regular device. */ 339d5ace945SErwin T Tsaur last_fields = last_dev_fields; 340d5ace945SErwin T Tsaur break; 341d5ace945SErwin T Tsaur 342d5ace945SErwin T Tsaur case PCI_HEADER_PPB: /* Header type 1 is a PCI-PCI bridge. */ 343d5ace945SErwin T Tsaur last_fields = last_pcibrg_fields; 344d5ace945SErwin T Tsaur (void) printf("PCI-PCI bridge\n"); 345d5ace945SErwin T Tsaur break; 346d5ace945SErwin T Tsaur 347d5ace945SErwin T Tsaur case PCI_HEADER_CARDBUS: /* Header type 2 is a cardbus bridge */ 348d5ace945SErwin T Tsaur last_fields = last_cbbrg_fields; 349d5ace945SErwin T Tsaur (void) printf("PCI-Cardbus bridge\n"); 350d5ace945SErwin T Tsaur break; 351d5ace945SErwin T Tsaur 352d5ace945SErwin T Tsaur default: 353d5ace945SErwin T Tsaur (void) printf("Unknown device\n"); 354d5ace945SErwin T Tsaur break; 355d5ace945SErwin T Tsaur } 356d5ace945SErwin T Tsaur 357d5ace945SErwin T Tsaur if (last_fields != NULL) { 358d5ace945SErwin T Tsaur 359d5ace945SErwin T Tsaur for (i = 0; first_fields[i].size != 0; i++) { 360d5ace945SErwin T Tsaur (void) printf("%s: ", first_fields[i].full_hdr); 361d5ace945SErwin T Tsaur print_probe_value(config_hdr_p, 362d5ace945SErwin T Tsaur first_fields[i].cfg_offset, first_fields[i].size); 363d5ace945SErwin T Tsaur (void) putchar('\n'); 364d5ace945SErwin T Tsaur } 365d5ace945SErwin T Tsaur 366d5ace945SErwin T Tsaur for (i = 0; last_fields[i].size != 0; i++) { 367d5ace945SErwin T Tsaur (void) printf("%s: ", last_fields[i].full_hdr); 368d5ace945SErwin T Tsaur print_probe_value(config_hdr_p, 369d5ace945SErwin T Tsaur last_fields[i].cfg_offset, last_fields[i].size); 370d5ace945SErwin T Tsaur (void) putchar('\n'); 371d5ace945SErwin T Tsaur } 372d5ace945SErwin T Tsaur } 373d5ace945SErwin T Tsaur } 374d5ace945SErwin T Tsaur 375d5ace945SErwin T Tsaur static void 376d5ace945SErwin T Tsaur print_probe_info_nonverbose(pci_conf_hdr_t *config_hdr_p, pcitool_reg_t *info_p) 377d5ace945SErwin T Tsaur { 378d5ace945SErwin T Tsaur int i; 379d5ace945SErwin T Tsaur 380d5ace945SErwin T Tsaur (void) printf("%2.2x %2.2x %1.1x ", 381d5ace945SErwin T Tsaur info_p->bus_no, info_p->dev_no, info_p->func_no); 382d5ace945SErwin T Tsaur for (i = 0; first_fields[i].size != 0; i++) { 383d5ace945SErwin T Tsaur print_probe_value(config_hdr_p, 384d5ace945SErwin T Tsaur first_fields[i].cfg_offset, first_fields[i].size); 385d5ace945SErwin T Tsaur } 386d5ace945SErwin T Tsaur (void) putchar('\n'); 387d5ace945SErwin T Tsaur } 388d5ace945SErwin T Tsaur 389d5ace945SErwin T Tsaur 390d5ace945SErwin T Tsaur /* 391d5ace945SErwin T Tsaur * Print device information retrieved during probe mode. 392d5ace945SErwin T Tsaur * Takes the PCI config header, plus address information retrieved from the 393d5ace945SErwin T Tsaur * driver. 394d5ace945SErwin T Tsaur * 395d5ace945SErwin T Tsaur * When called with config_hdr_p == NULL, this function just prints a header 396d5ace945SErwin T Tsaur * when not in verbose mode. 397d5ace945SErwin T Tsaur */ 398d5ace945SErwin T Tsaur 399d5ace945SErwin T Tsaur static void 400d5ace945SErwin T Tsaur print_probe_info( 401d5ace945SErwin T Tsaur pci_conf_hdr_t *config_hdr_p, pcitool_reg_t *info_p, boolean_t verbose) 402d5ace945SErwin T Tsaur { 403d5ace945SErwin T Tsaur int i; 404d5ace945SErwin T Tsaur 405d5ace945SErwin T Tsaur /* Print header if not in verbose mode. */ 406d5ace945SErwin T Tsaur if (config_hdr_p == NULL) { 407d5ace945SErwin T Tsaur if (!verbose) { 408d5ace945SErwin T Tsaur 409d5ace945SErwin T Tsaur /* Bus dev func not from tble */ 410d5ace945SErwin T Tsaur (void) printf("B D F "); 411d5ace945SErwin T Tsaur 412d5ace945SErwin T Tsaur for (i = 0; first_fields[i].size != 0; i++) { 413d5ace945SErwin T Tsaur (void) printf("%s ", 414d5ace945SErwin T Tsaur first_fields[i].abbrev_hdr); 415d5ace945SErwin T Tsaur } 416d5ace945SErwin T Tsaur (void) putchar('\n'); 417d5ace945SErwin T Tsaur } 418d5ace945SErwin T Tsaur 419d5ace945SErwin T Tsaur return; 420d5ace945SErwin T Tsaur } 421d5ace945SErwin T Tsaur 422d5ace945SErwin T Tsaur if (verbose) { 423d5ace945SErwin T Tsaur print_probe_info_verbose(config_hdr_p, info_p); 424d5ace945SErwin T Tsaur } else { 425d5ace945SErwin T Tsaur print_probe_info_nonverbose(config_hdr_p, info_p); 426d5ace945SErwin T Tsaur } 427d5ace945SErwin T Tsaur } 428d5ace945SErwin T Tsaur 429d5ace945SErwin T Tsaur 430d5ace945SErwin T Tsaur /* 431d5ace945SErwin T Tsaur * Retrieve first 16 dwords of device's config header, except for the first 432d5ace945SErwin T Tsaur * dword. First 16 dwords are defined by the PCI specification. 433d5ace945SErwin T Tsaur */ 434d5ace945SErwin T Tsaur static int 435d5ace945SErwin T Tsaur get_config_header(int fd, uint8_t bus_no, uint8_t dev_no, uint8_t func_no, 436d5ace945SErwin T Tsaur pci_conf_hdr_t *config_hdr_p) 437d5ace945SErwin T Tsaur { 438d5ace945SErwin T Tsaur pcitool_reg_t cfg_prg; 439d5ace945SErwin T Tsaur int i; 440d5ace945SErwin T Tsaur int rval = SUCCESS; 441d5ace945SErwin T Tsaur 442d5ace945SErwin T Tsaur /* Prepare a local pcitool_reg_t so as to not disturb the caller's. */ 443d5ace945SErwin T Tsaur cfg_prg.offset = 0; 444d5ace945SErwin T Tsaur cfg_prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_4 + NATIVE_ENDIAN; 445d5ace945SErwin T Tsaur cfg_prg.bus_no = bus_no; 446d5ace945SErwin T Tsaur cfg_prg.dev_no = dev_no; 447d5ace945SErwin T Tsaur cfg_prg.func_no = func_no; 448d5ace945SErwin T Tsaur cfg_prg.barnum = 0; 449d5ace945SErwin T Tsaur cfg_prg.user_version = PCITOOL_VERSION; 450d5ace945SErwin T Tsaur 451d5ace945SErwin T Tsaur /* Get dwords 1-15 of config space. They must be read as uint32_t. */ 452d5ace945SErwin T Tsaur for (i = 1; i < (sizeof (pci_conf_hdr_t) / sizeof (uint32_t)); i++) { 453d5ace945SErwin T Tsaur cfg_prg.offset += sizeof (uint32_t); 454d5ace945SErwin T Tsaur if ((rval = 455d5ace945SErwin T Tsaur ioctl(fd, PCITOOL_DEVICE_GET_REG, &cfg_prg)) != SUCCESS) { 456d5ace945SErwin T Tsaur break; 457d5ace945SErwin T Tsaur } 458d5ace945SErwin T Tsaur config_hdr_p->dwords[i] = (uint32_t)cfg_prg.data; 459d5ace945SErwin T Tsaur } 460d5ace945SErwin T Tsaur return (rval); 461d5ace945SErwin T Tsaur } 462d5ace945SErwin T Tsaur 46326947304SEvan Yan static int 46426947304SEvan Yan supports_ari(int fd, uint8_t bus_no) 46526947304SEvan Yan { 46626947304SEvan Yan pcitool_reg_t cfg_prg; 46726947304SEvan Yan int deadcount = 0; 46826947304SEvan Yan uint32_t data, hdr_next_ptr, hdr_cap_id; 46926947304SEvan Yan uint8_t dev_no = 0; 47026947304SEvan Yan uint8_t func_no = 0; 47126947304SEvan Yan 47226947304SEvan Yan /* Prepare a local pcitool_reg_t so as to not disturb the caller's. */ 47326947304SEvan Yan cfg_prg.bus_no = bus_no; 47426947304SEvan Yan cfg_prg.dev_no = dev_no; 47526947304SEvan Yan cfg_prg.func_no = func_no; 47626947304SEvan Yan cfg_prg.barnum = 0; 47726947304SEvan Yan cfg_prg.user_version = PCITOOL_VERSION; 4788d7fafffSZhi-Jun Robin Fu cfg_prg.offset = 0; 47926947304SEvan Yan cfg_prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_4 + PCITOOL_ACC_ATTR_ENDN_LTL; 48026947304SEvan Yan 48126947304SEvan Yan if (ioctl(fd, PCITOOL_DEVICE_GET_REG, &cfg_prg) != SUCCESS) { 48226947304SEvan Yan return (FAILURE); 48326947304SEvan Yan } 48426947304SEvan Yan 48526947304SEvan Yan data = (uint32_t)cfg_prg.data; 4868d7fafffSZhi-Jun Robin Fu if (data == (uint32_t)(-1)) 4878d7fafffSZhi-Jun Robin Fu return (FAILURE); 48826947304SEvan Yan 4898d7fafffSZhi-Jun Robin Fu cfg_prg.offset = PCI_CONF_COMM; 4908d7fafffSZhi-Jun Robin Fu if (ioctl(fd, PCITOOL_DEVICE_GET_REG, &cfg_prg) != SUCCESS) { 4918d7fafffSZhi-Jun Robin Fu return (FAILURE); 4928d7fafffSZhi-Jun Robin Fu } 4938d7fafffSZhi-Jun Robin Fu 4948d7fafffSZhi-Jun Robin Fu data = (uint32_t)cfg_prg.data; 49526947304SEvan Yan if (!((data >> 16) & PCI_STAT_CAP)) 49626947304SEvan Yan return (FAILURE); 49726947304SEvan Yan 49826947304SEvan Yan cfg_prg.offset = PCI_CONF_CAP_PTR; 49926947304SEvan Yan if (ioctl(fd, PCITOOL_DEVICE_GET_REG, &cfg_prg) != SUCCESS) { 50026947304SEvan Yan return (FAILURE); 50126947304SEvan Yan } 50226947304SEvan Yan data = (uint32_t)cfg_prg.data; 50326947304SEvan Yan hdr_next_ptr = data & 0xff; 50426947304SEvan Yan hdr_cap_id = 0; 50526947304SEvan Yan 50626947304SEvan Yan /* 50726947304SEvan Yan * Find the PCIe capability. 50826947304SEvan Yan */ 50926947304SEvan Yan while ((hdr_next_ptr != PCI_CAP_NEXT_PTR_NULL) && 51026947304SEvan Yan (hdr_cap_id != PCI_CAP_ID_PCI_E)) { 51126947304SEvan Yan 51226947304SEvan Yan if (hdr_next_ptr < 0x40) 51326947304SEvan Yan break; 51426947304SEvan Yan 51526947304SEvan Yan cfg_prg.offset = hdr_next_ptr; 51626947304SEvan Yan 51726947304SEvan Yan if (ioctl(fd, PCITOOL_DEVICE_GET_REG, &cfg_prg) != SUCCESS) 51826947304SEvan Yan return (FAILURE); 51926947304SEvan Yan 52026947304SEvan Yan data = (uint32_t)cfg_prg.data; 52126947304SEvan Yan 52226947304SEvan Yan hdr_next_ptr = (data >> 8) & 0xFF; 52326947304SEvan Yan hdr_cap_id = data & 0xFF; 52426947304SEvan Yan 52526947304SEvan Yan if (deadcount++ > 100) 52626947304SEvan Yan return (FAILURE); 52726947304SEvan Yan } 52826947304SEvan Yan 52926947304SEvan Yan if (hdr_cap_id != PCI_CAP_ID_PCI_E) 53026947304SEvan Yan return (FAILURE); 53126947304SEvan Yan 53226947304SEvan Yan /* Found a PCIe Capability */ 53326947304SEvan Yan 53426947304SEvan Yan hdr_next_ptr = 0x100; 53526947304SEvan Yan hdr_cap_id = 0; 53626947304SEvan Yan 53726947304SEvan Yan /* 53826947304SEvan Yan * Now find the ARI Capability. 53926947304SEvan Yan */ 54026947304SEvan Yan while ((hdr_next_ptr != PCI_CAP_NEXT_PTR_NULL) && 54126947304SEvan Yan (hdr_cap_id != 0xe)) { 54226947304SEvan Yan 54326947304SEvan Yan if (hdr_next_ptr < 0x40) 54426947304SEvan Yan break; 54526947304SEvan Yan 54626947304SEvan Yan cfg_prg.offset = hdr_next_ptr; 54726947304SEvan Yan 54826947304SEvan Yan if (ioctl(fd, PCITOOL_DEVICE_GET_REG, &cfg_prg) != SUCCESS) { 54926947304SEvan Yan return (FAILURE); 55026947304SEvan Yan } 55126947304SEvan Yan data = (uint32_t)cfg_prg.data; 55226947304SEvan Yan 55326947304SEvan Yan hdr_next_ptr = (data >> 20) & 0xFFF; 55426947304SEvan Yan hdr_cap_id = data & 0xFFFF; 55526947304SEvan Yan 55626947304SEvan Yan if (deadcount++ > 100) 55726947304SEvan Yan return (FAILURE); 55826947304SEvan Yan } 55926947304SEvan Yan 56026947304SEvan Yan if (hdr_cap_id != 0xe) 56126947304SEvan Yan return (FAILURE); 56226947304SEvan Yan 56326947304SEvan Yan return (SUCCESS); 56426947304SEvan Yan } 56526947304SEvan Yan 566d5ace945SErwin T Tsaur /* 567d5ace945SErwin T Tsaur * Identify problematic southbridges. These have device id 0x5249 and 568d5ace945SErwin T Tsaur * vendor id 0x10b9. Check for revision ID 0 and class code 060400 as well. 569d5ace945SErwin T Tsaur * Values are little endian, so they are reversed for SPARC. 570d5ace945SErwin T Tsaur * 571d5ace945SErwin T Tsaur * Check for these southbridges on all architectures, as the issue is a 572d5ace945SErwin T Tsaur * southbridge issue, independent of processor. 573d5ace945SErwin T Tsaur * 574d5ace945SErwin T Tsaur * If one of these is found during probing, skip probing other devs/funcs on 575d5ace945SErwin T Tsaur * the rest of the bus, since the southbridge and all devs underneath will 576d5ace945SErwin T Tsaur * otherwise disappear. 577d5ace945SErwin T Tsaur */ 578d5ace945SErwin T Tsaur #if (NATIVE_ENDIAN == PCITOOL_ACC_ATTR_ENDN_BIG) 579d5ace945SErwin T Tsaur #define U45_SB_DEVID_VID 0xb9104952 580d5ace945SErwin T Tsaur #define U45_SB_CLASS_RID 0x00000406 581d5ace945SErwin T Tsaur #else 582d5ace945SErwin T Tsaur #define U45_SB_DEVID_VID 0x524910b9 583d5ace945SErwin T Tsaur #define U45_SB_CLASS_RID 0x06040000 584d5ace945SErwin T Tsaur #endif 585d5ace945SErwin T Tsaur 586d5ace945SErwin T Tsaur /* 587d5ace945SErwin T Tsaur * Probe device's functions. Modifies many fields in the prg_p. 588d5ace945SErwin T Tsaur */ 589d5ace945SErwin T Tsaur static int 590d5ace945SErwin T Tsaur probe_dev(int fd, pcitool_reg_t *prg_p, pcitool_uiargs_t *input_args_p) 591d5ace945SErwin T Tsaur { 592d5ace945SErwin T Tsaur pci_conf_hdr_t config_hdr; 59326947304SEvan Yan boolean_t multi_function_device = B_FALSE; 594d5ace945SErwin T Tsaur int func; 595d5ace945SErwin T Tsaur int first_func = 0; 596d5ace945SErwin T Tsaur int last_func = PCI_REG_FUNC_M >> PCI_REG_FUNC_SHIFT; 597d5ace945SErwin T Tsaur int rval = SUCCESS; 598d5ace945SErwin T Tsaur 599d5ace945SErwin T Tsaur if (input_args_p->flags & FUNC_SPEC_FLAG) { 600d5ace945SErwin T Tsaur first_func = last_func = input_args_p->function; 60126947304SEvan Yan } else if (supports_ari(fd, prg_p->bus_no) == SUCCESS) { 60226947304SEvan Yan multi_function_device = B_TRUE; 60326947304SEvan Yan if (!(input_args_p->flags & DEV_SPEC_FLAG)) 60426947304SEvan Yan last_func = 255; 605d5ace945SErwin T Tsaur } 606d5ace945SErwin T Tsaur 607d5ace945SErwin T Tsaur /* 608d5ace945SErwin T Tsaur * Loop through at least func=first_func. Continue looping through 609d5ace945SErwin T Tsaur * functions if there are no errors and the device is a multi-function 610d5ace945SErwin T Tsaur * device. 611d5ace945SErwin T Tsaur * 612d5ace945SErwin T Tsaur * (Note, if first_func == 0, header will show whether multifunction 613d5ace945SErwin T Tsaur * device and set multi_function_device. If first_func != 0, then we 614d5ace945SErwin T Tsaur * will force the loop as the user wants a specific function to be 615d5ace945SErwin T Tsaur * checked. 616d5ace945SErwin T Tsaur */ 61726947304SEvan Yan for (func = first_func; ((func <= last_func) && 618d5ace945SErwin T Tsaur ((func == first_func) || (multi_function_device))); 619d5ace945SErwin T Tsaur func++) { 62026947304SEvan Yan if (last_func > 7) { 62126947304SEvan Yan prg_p->func_no = func & 0x7; 62226947304SEvan Yan prg_p->dev_no = (func >> 3) & 0x1f; 62326947304SEvan Yan } else 624d5ace945SErwin T Tsaur prg_p->func_no = func; 625d5ace945SErwin T Tsaur 626d5ace945SErwin T Tsaur /* 627d5ace945SErwin T Tsaur * Four things can happen here: 628d5ace945SErwin T Tsaur * 629d5ace945SErwin T Tsaur * 1) ioctl comes back as EFAULT and prg_p->status is 630d5ace945SErwin T Tsaur * PCITOOL_INVALID_ADDRESS. There is no device at this 631d5ace945SErwin T Tsaur * location. 632d5ace945SErwin T Tsaur * 633d5ace945SErwin T Tsaur * 2) ioctl comes back successful and the data comes back as 634d5ace945SErwin T Tsaur * zero. Config space is mapped but no device responded. 635d5ace945SErwin T Tsaur * 636d5ace945SErwin T Tsaur * 3) ioctl comes back successful and the data comes back as 637d5ace945SErwin T Tsaur * non-zero. We've found a device. 638d5ace945SErwin T Tsaur * 639d5ace945SErwin T Tsaur * 4) Some other error occurs in an ioctl. 640d5ace945SErwin T Tsaur */ 641d5ace945SErwin T Tsaur 642d5ace945SErwin T Tsaur prg_p->status = PCITOOL_SUCCESS; 643d5ace945SErwin T Tsaur prg_p->offset = 0; 644d5ace945SErwin T Tsaur prg_p->data = 0; 645d5ace945SErwin T Tsaur prg_p->user_version = PCITOOL_VERSION; 646d5ace945SErwin T Tsaur if (((rval = ioctl(fd, PCITOOL_DEVICE_GET_REG, prg_p)) != 0) || 647d5ace945SErwin T Tsaur (prg_p->data == 0xffffffff)) { 648d5ace945SErwin T Tsaur 649d5ace945SErwin T Tsaur /* 650d5ace945SErwin T Tsaur * Accept errno == EINVAL along with status of 651d5ace945SErwin T Tsaur * PCITOOL_OUT_OF_RANGE because some systems 652d5ace945SErwin T Tsaur * don't implement the full range of config space. 653d5ace945SErwin T Tsaur * Leave the loop quietly in this case. 654d5ace945SErwin T Tsaur */ 655d5ace945SErwin T Tsaur if ((errno == EINVAL) || 656d5ace945SErwin T Tsaur (prg_p->status == PCITOOL_OUT_OF_RANGE)) { 657d5ace945SErwin T Tsaur break; 658d5ace945SErwin T Tsaur } 659d5ace945SErwin T Tsaur 660d5ace945SErwin T Tsaur /* 661d5ace945SErwin T Tsaur * Exit silently with ENXIO as this means that there are 662d5ace945SErwin T Tsaur * no devices under the pci root nexus. 663d5ace945SErwin T Tsaur */ 664d5ace945SErwin T Tsaur else if ((errno == ENXIO) && 665d5ace945SErwin T Tsaur (prg_p->status == PCITOOL_IO_ERROR)) { 666d5ace945SErwin T Tsaur break; 667d5ace945SErwin T Tsaur } 668d5ace945SErwin T Tsaur 669d5ace945SErwin T Tsaur /* 670d5ace945SErwin T Tsaur * Expect errno == EFAULT along with status of 671d5ace945SErwin T Tsaur * PCITOOL_INVALID_ADDRESS because there won't be 672d5ace945SErwin T Tsaur * devices at each stop. Quit on any other error. 673d5ace945SErwin T Tsaur */ 674d5ace945SErwin T Tsaur else if (((errno != EFAULT) || 675d5ace945SErwin T Tsaur (prg_p->status != PCITOOL_INVALID_ADDRESS)) && 676d5ace945SErwin T Tsaur (prg_p->data != 0xffffffff)) { 677d5ace945SErwin T Tsaur 678d5ace945SErwin T Tsaur if (!(IS_QUIET(input_args_p->flags))) { 679d5ace945SErwin T Tsaur (void) fprintf(stderr, 680d5ace945SErwin T Tsaur "Ioctl error: %s\n", 681d5ace945SErwin T Tsaur strerror(errno)); 682d5ace945SErwin T Tsaur } 683d5ace945SErwin T Tsaur break; 684d5ace945SErwin T Tsaur 685d5ace945SErwin T Tsaur /* 686d5ace945SErwin T Tsaur * If no function at this location, 687d5ace945SErwin T Tsaur * just advance to the next function. 688d5ace945SErwin T Tsaur */ 689d5ace945SErwin T Tsaur } else { 690d5ace945SErwin T Tsaur rval = SUCCESS; 691d5ace945SErwin T Tsaur } 692d5ace945SErwin T Tsaur 693d5ace945SErwin T Tsaur /* 694d5ace945SErwin T Tsaur * Data came back as 0. 695d5ace945SErwin T Tsaur * Treat as unresponsive device amd check next device. 696d5ace945SErwin T Tsaur */ 697d5ace945SErwin T Tsaur } else if (prg_p->data == 0) { 698d5ace945SErwin T Tsaur rval = SUCCESS; 699d5ace945SErwin T Tsaur /* Found something. */ 700d5ace945SErwin T Tsaur } else { 701d5ace945SErwin T Tsaur config_hdr.dwords[0] = (uint32_t)prg_p->data; 702d5ace945SErwin T Tsaur 703d5ace945SErwin T Tsaur /* Get the rest of the PCI header. */ 704d5ace945SErwin T Tsaur if ((rval = get_config_header(fd, prg_p->bus_no, 705d5ace945SErwin T Tsaur prg_p->dev_no, prg_p->func_no, &config_hdr)) != 706d5ace945SErwin T Tsaur SUCCESS) { 707d5ace945SErwin T Tsaur break; 708d5ace945SErwin T Tsaur } 709d5ace945SErwin T Tsaur 710d5ace945SErwin T Tsaur /* Print the found information. */ 711d5ace945SErwin T Tsaur print_probe_info(&config_hdr, prg_p, 712d5ace945SErwin T Tsaur IS_VERBOSE(input_args_p->flags)); 713d5ace945SErwin T Tsaur 714d5ace945SErwin T Tsaur /* 715d5ace945SErwin T Tsaur * Special case for the type of Southbridge found on 716d5ace945SErwin T Tsaur * Ultra-45 and other sun4u fire workstations. 717d5ace945SErwin T Tsaur */ 718d5ace945SErwin T Tsaur if ((config_hdr.dwords[0] == U45_SB_DEVID_VID) && 719d5ace945SErwin T Tsaur (config_hdr.dwords[2] == U45_SB_CLASS_RID)) { 720d5ace945SErwin T Tsaur rval = ECANCELED; 721d5ace945SErwin T Tsaur break; 722d5ace945SErwin T Tsaur } 723d5ace945SErwin T Tsaur 724d5ace945SErwin T Tsaur /* 725d5ace945SErwin T Tsaur * Accomodate devices which state their 726d5ace945SErwin T Tsaur * multi-functionality only in their function 0 config 727d5ace945SErwin T Tsaur * space. Note multi-functionality throughout probing 728d5ace945SErwin T Tsaur * of all of this device's functions. 729d5ace945SErwin T Tsaur */ 730d5ace945SErwin T Tsaur if (config_hdr.bytes[PCI_CONF_HEADER] & 731d5ace945SErwin T Tsaur PCI_HEADER_MULTI) { 732d5ace945SErwin T Tsaur multi_function_device = B_TRUE; 733d5ace945SErwin T Tsaur } 734d5ace945SErwin T Tsaur } 735d5ace945SErwin T Tsaur } 736d5ace945SErwin T Tsaur 737d5ace945SErwin T Tsaur return (rval); 738d5ace945SErwin T Tsaur } 739d5ace945SErwin T Tsaur 740d5ace945SErwin T Tsaur 741d5ace945SErwin T Tsaur /* 742d5ace945SErwin T Tsaur * Probe a given nexus config space for devices. 743d5ace945SErwin T Tsaur * 744d5ace945SErwin T Tsaur * fd is the file descriptor of the nexus. 745d5ace945SErwin T Tsaur * input_args contains commandline options as specified by the user. 746d5ace945SErwin T Tsaur */ 747d5ace945SErwin T Tsaur static int 748d5ace945SErwin T Tsaur do_probe(int fd, di_node_t di_node, di_prom_handle_t di_phdl, 749d5ace945SErwin T Tsaur pcitool_uiargs_t *input_args_p) 750d5ace945SErwin T Tsaur { 751d5ace945SErwin T Tsaur pcitool_reg_t prg; 752d5ace945SErwin T Tsaur int bus; 753d5ace945SErwin T Tsaur int dev; 754d5ace945SErwin T Tsaur int last_bus = PCI_REG_BUS_M >> PCI_REG_BUS_SHIFT; 755d5ace945SErwin T Tsaur int last_dev = PCI_REG_DEV_M >> PCI_REG_DEV_SHIFT; 756d5ace945SErwin T Tsaur int first_bus = 0; 757d5ace945SErwin T Tsaur int first_dev = 0; 758d5ace945SErwin T Tsaur int rval = SUCCESS; 759d5ace945SErwin T Tsaur 760d5ace945SErwin T Tsaur prg.barnum = 0; /* Config space. */ 761d5ace945SErwin T Tsaur 762d5ace945SErwin T Tsaur /* Must read in 4-byte quantities. */ 763d5ace945SErwin T Tsaur prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_4 + NATIVE_ENDIAN; 764d5ace945SErwin T Tsaur 765d5ace945SErwin T Tsaur prg.data = 0; 766d5ace945SErwin T Tsaur 767d5ace945SErwin T Tsaur /* If an explicit bus was specified by the user, go with it. */ 768d5ace945SErwin T Tsaur if (input_args_p->flags & BUS_SPEC_FLAG) { 769d5ace945SErwin T Tsaur first_bus = last_bus = input_args_p->bus; 770d5ace945SErwin T Tsaur 771d5ace945SErwin T Tsaur } else if (input_args_p->flags & PROBERNG_FLAG) { 772d5ace945SErwin T Tsaur /* Otherwise get the bus range from properties. */ 773d5ace945SErwin T Tsaur int len; 774d5ace945SErwin T Tsaur uint32_t *rangebuf = NULL; 775d5ace945SErwin T Tsaur 776d5ace945SErwin T Tsaur len = di_prop_lookup_ints(DDI_DEV_T_ANY, di_node, 777d5ace945SErwin T Tsaur "bus-range", (int **)&rangebuf); 778d5ace945SErwin T Tsaur 779d5ace945SErwin T Tsaur /* Try PROM property */ 780d5ace945SErwin T Tsaur if (len <= 0) { 781d5ace945SErwin T Tsaur len = di_prom_prop_lookup_ints(di_phdl, di_node, 782d5ace945SErwin T Tsaur "bus-range", (int **)&rangebuf); 783d5ace945SErwin T Tsaur } 784d5ace945SErwin T Tsaur 785d5ace945SErwin T Tsaur /* Take full range for default if cannot get property. */ 786d5ace945SErwin T Tsaur if (len > 0) { 787d5ace945SErwin T Tsaur first_bus = rangebuf[0]; 788d5ace945SErwin T Tsaur last_bus = rangebuf[1]; 789d5ace945SErwin T Tsaur } 790d5ace945SErwin T Tsaur } 791d5ace945SErwin T Tsaur 792d5ace945SErwin T Tsaur /* Take full range for default if not PROBERNG and not BUS_SPEC. */ 793d5ace945SErwin T Tsaur 794d5ace945SErwin T Tsaur if (last_bus == first_bus) { 795d5ace945SErwin T Tsaur if (input_args_p->flags & DEV_SPEC_FLAG) { 796d5ace945SErwin T Tsaur /* Explicit device given. Not probing a whole bus. */ 797d5ace945SErwin T Tsaur (void) puts(""); 798d5ace945SErwin T Tsaur } else { 799d5ace945SErwin T Tsaur (void) printf("*********** Probing bus %x " 800d5ace945SErwin T Tsaur "***********\n\n", first_bus); 801d5ace945SErwin T Tsaur } 802d5ace945SErwin T Tsaur } else { 803d5ace945SErwin T Tsaur (void) printf("*********** Probing buses %x through %x " 804d5ace945SErwin T Tsaur "***********\n\n", first_bus, last_bus); 805d5ace945SErwin T Tsaur } 806d5ace945SErwin T Tsaur 807d5ace945SErwin T Tsaur /* Print header. */ 808d5ace945SErwin T Tsaur print_probe_info(NULL, NULL, IS_VERBOSE(input_args_p->flags)); 809d5ace945SErwin T Tsaur 810d5ace945SErwin T Tsaur /* Device number explicitly specified. */ 811d5ace945SErwin T Tsaur if (input_args_p->flags & DEV_SPEC_FLAG) { 812d5ace945SErwin T Tsaur first_dev = last_dev = input_args_p->device; 813d5ace945SErwin T Tsaur } 814d5ace945SErwin T Tsaur 815d5ace945SErwin T Tsaur /* 816d5ace945SErwin T Tsaur * Loop through all valid bus / dev / func combinations to check for 817d5ace945SErwin T Tsaur * all devices, with the following exceptions: 818d5ace945SErwin T Tsaur * 819d5ace945SErwin T Tsaur * When nothing is found at function 0 of a bus / dev combination, skip 820d5ace945SErwin T Tsaur * the other functions of that bus / dev combination. 821d5ace945SErwin T Tsaur * 822d5ace945SErwin T Tsaur * When a found device's function 0 is probed and it is determined that 823d5ace945SErwin T Tsaur * it is not a multifunction device, skip probing of that device's 824d5ace945SErwin T Tsaur * other functions. 825d5ace945SErwin T Tsaur */ 826d5ace945SErwin T Tsaur for (bus = first_bus; ((bus <= last_bus) && (rval == SUCCESS)); bus++) { 827d5ace945SErwin T Tsaur prg.bus_no = bus; 82826947304SEvan Yan 82926947304SEvan Yan /* Device number explicitly specified. */ 83026947304SEvan Yan if (input_args_p->flags & DEV_SPEC_FLAG) { 83126947304SEvan Yan first_dev = last_dev = input_args_p->device; 83226947304SEvan Yan } else if (supports_ari(fd, bus) == SUCCESS) { 83326947304SEvan Yan last_dev = 0; 83426947304SEvan Yan first_dev = 0; 83526947304SEvan Yan } else { 83626947304SEvan Yan last_dev = PCI_REG_DEV_M >> PCI_REG_DEV_SHIFT; 83726947304SEvan Yan } 83826947304SEvan Yan 839d5ace945SErwin T Tsaur for (dev = first_dev; 840d5ace945SErwin T Tsaur ((dev <= last_dev) && (rval == SUCCESS)); dev++) { 841d5ace945SErwin T Tsaur prg.dev_no = dev; 842d5ace945SErwin T Tsaur rval = probe_dev(fd, &prg, input_args_p); 843d5ace945SErwin T Tsaur } 844d5ace945SErwin T Tsaur 845d5ace945SErwin T Tsaur /* 846d5ace945SErwin T Tsaur * Ultra-45 southbridge workaround: 847d5ace945SErwin T Tsaur * ECANCELED tells to skip to the next bus. 848d5ace945SErwin T Tsaur */ 849d5ace945SErwin T Tsaur if (rval == ECANCELED) { 850d5ace945SErwin T Tsaur rval = SUCCESS; 851d5ace945SErwin T Tsaur } 852d5ace945SErwin T Tsaur } 853d5ace945SErwin T Tsaur 854d5ace945SErwin T Tsaur return (rval); 855d5ace945SErwin T Tsaur } 856d5ace945SErwin T Tsaur 857d5ace945SErwin T Tsaur /* 858d5ace945SErwin T Tsaur * This function is called-back from di_walk_minor() when any PROBE is processed 859d5ace945SErwin T Tsaur */ 860d5ace945SErwin T Tsaur /*ARGSUSED*/ 861d5ace945SErwin T Tsaur static int 862d5ace945SErwin T Tsaur process_nexus_node(di_node_t di_node, di_minor_t minor, void *arg) 863d5ace945SErwin T Tsaur { 864d5ace945SErwin T Tsaur int fd; 865d5ace945SErwin T Tsaur char *trunc; 866d5ace945SErwin T Tsaur probe_walk_args_t *walk_args_p = (probe_walk_args_t *)arg; 867d5ace945SErwin T Tsaur char *pathname = walk_args_p->pathname; 868d5ace945SErwin T Tsaur char *nexus_path = di_devfs_minor_path(minor); 869d5ace945SErwin T Tsaur 870d5ace945SErwin T Tsaur if (nexus_path == NULL) { 871d5ace945SErwin T Tsaur (void) fprintf(stderr, "Error getting nexus path: %s\n", 872d5ace945SErwin T Tsaur strerror(errno)); 873d5ace945SErwin T Tsaur return (DI_WALK_CONTINUE); 874d5ace945SErwin T Tsaur } 875d5ace945SErwin T Tsaur 876d5ace945SErwin T Tsaur /* 877d5ace945SErwin T Tsaur * Display this node if pathname not specified (as all nodes are 878d5ace945SErwin T Tsaur * displayed) or if the current node matches the single specified 879d5ace945SErwin T Tsaur * pathname. Pathname form: xxx, nexus form: xxx:reg 880d5ace945SErwin T Tsaur */ 881d5ace945SErwin T Tsaur if ((pathname != NULL) && 882d5ace945SErwin T Tsaur ((strstr(nexus_path, pathname) != nexus_path) || 883d5ace945SErwin T Tsaur (strlen(nexus_path) != 884d5ace945SErwin T Tsaur (strlen(pathname) + strlen(PCI_MINOR_REG) + 1)))) { 885d5ace945SErwin T Tsaur di_devfs_path_free(nexus_path); 886d5ace945SErwin T Tsaur return (DI_WALK_CONTINUE); 887d5ace945SErwin T Tsaur } 888d5ace945SErwin T Tsaur 889d5ace945SErwin T Tsaur if ((fd = open_node(nexus_path, walk_args_p->input_args_p)) >= 0) { 890d5ace945SErwin T Tsaur 891d5ace945SErwin T Tsaur /* Strip off the suffix at the end of the nexus path. */ 892d5ace945SErwin T Tsaur if ((trunc = strstr(nexus_path, PCI_MINOR_REG)) != NULL) { 893d5ace945SErwin T Tsaur trunc--; /* Get the : just before too. */ 894d5ace945SErwin T Tsaur *trunc = '\0'; 895d5ace945SErwin T Tsaur } 896d5ace945SErwin T Tsaur 897d5ace945SErwin T Tsaur /* Show header only if no explicit nexus node name given. */ 898d5ace945SErwin T Tsaur (void) puts(""); 899d5ace945SErwin T Tsaur if (pathname == NULL) { 900d5ace945SErwin T Tsaur (void) printf("********** Devices in tree under %s " 901d5ace945SErwin T Tsaur "**********\n", nexus_path); 902d5ace945SErwin T Tsaur } 903d5ace945SErwin T Tsaur 904d5ace945SErwin T Tsaur /* 905d5ace945SErwin T Tsaur * Exit silently with ENXIO as this means that there are 906d5ace945SErwin T Tsaur * no devices under the pci root nexus. 907d5ace945SErwin T Tsaur */ 908d5ace945SErwin T Tsaur if ((do_probe(fd, di_node, walk_args_p->di_phdl, 909d5ace945SErwin T Tsaur walk_args_p->input_args_p) != SUCCESS) && 910d5ace945SErwin T Tsaur (errno != ENXIO)) { 911d5ace945SErwin T Tsaur (void) fprintf(stderr, "Error probing node %s: %s\n", 912d5ace945SErwin T Tsaur nexus_path, strerror(errno)); 913d5ace945SErwin T Tsaur } 914d5ace945SErwin T Tsaur 915d5ace945SErwin T Tsaur (void) close(fd); 916d5ace945SErwin T Tsaur } 917d5ace945SErwin T Tsaur di_devfs_path_free(nexus_path); 918d5ace945SErwin T Tsaur 919d5ace945SErwin T Tsaur /* 920d5ace945SErwin T Tsaur * If node was explicitly specified, it has just been displayed 921d5ace945SErwin T Tsaur * and no more looping is required. 922d5ace945SErwin T Tsaur * Otherwise, keep looping for more nodes. 923d5ace945SErwin T Tsaur */ 924d5ace945SErwin T Tsaur return ((pathname == NULL) ? DI_WALK_CONTINUE : DI_WALK_TERMINATE); 925d5ace945SErwin T Tsaur } 926d5ace945SErwin T Tsaur 927d5ace945SErwin T Tsaur 928d5ace945SErwin T Tsaur /* 929d5ace945SErwin T Tsaur * Start of probe. If pathname is NULL, search all devices. 930d5ace945SErwin T Tsaur * 931d5ace945SErwin T Tsaur * di_walk_minor() walks all DDI_NT_REGACC (PCItool register access) nodes 932d5ace945SErwin T Tsaur * and calls process_nexus_node on them. process_nexus_node will then check 933d5ace945SErwin T Tsaur * the pathname for a match, unless it is NULL which works like a wildcard. 934d5ace945SErwin T Tsaur */ 935d5ace945SErwin T Tsaur static int 936d5ace945SErwin T Tsaur do_probe_walk(pcitool_uiargs_t *input_args_p, char *pathname) 937d5ace945SErwin T Tsaur { 938d5ace945SErwin T Tsaur di_node_t di_node; 939d5ace945SErwin T Tsaur di_prom_handle_t di_phdl = DI_PROM_HANDLE_NIL; 940d5ace945SErwin T Tsaur probe_walk_args_t walk_args; 941d5ace945SErwin T Tsaur 942d5ace945SErwin T Tsaur int rval = SUCCESS; 943d5ace945SErwin T Tsaur 944d5ace945SErwin T Tsaur if ((di_node = di_init("/", DINFOCPYALL)) == DI_NODE_NIL) { 945d5ace945SErwin T Tsaur (void) fprintf(stderr, "di_init() failed: %s\n", 946d5ace945SErwin T Tsaur strerror(errno)); 947d5ace945SErwin T Tsaur rval = errno; 948d5ace945SErwin T Tsaur 949d5ace945SErwin T Tsaur } else if ((input_args_p->flags & PROBERNG_FLAG) && 950d5ace945SErwin T Tsaur ((di_phdl = di_prom_init()) == DI_PROM_HANDLE_NIL)) { 951d5ace945SErwin T Tsaur (void) fprintf(stderr, "di_prom_init failed: %s\n", 952d5ace945SErwin T Tsaur strerror(errno)); 953d5ace945SErwin T Tsaur rval = errno; 954d5ace945SErwin T Tsaur 955d5ace945SErwin T Tsaur } else { 956d5ace945SErwin T Tsaur walk_args.input_args_p = input_args_p; 957d5ace945SErwin T Tsaur walk_args.di_phdl = di_phdl; 958d5ace945SErwin T Tsaur walk_args.pathname = pathname; 959d5ace945SErwin T Tsaur (void) di_walk_minor(di_node, DDI_NT_REGACC, 0, 960d5ace945SErwin T Tsaur &walk_args, process_nexus_node); 961d5ace945SErwin T Tsaur } 962d5ace945SErwin T Tsaur 963d5ace945SErwin T Tsaur if (di_phdl != DI_PROM_HANDLE_NIL) { 964d5ace945SErwin T Tsaur di_prom_fini(di_phdl); 965d5ace945SErwin T Tsaur } 966d5ace945SErwin T Tsaur 967d5ace945SErwin T Tsaur if (di_node != DI_NODE_NIL) { 968d5ace945SErwin T Tsaur di_fini(di_node); 969d5ace945SErwin T Tsaur } 970d5ace945SErwin T Tsaur 971d5ace945SErwin T Tsaur return (rval); 972d5ace945SErwin T Tsaur } 973d5ace945SErwin T Tsaur 974d5ace945SErwin T Tsaur 975d5ace945SErwin T Tsaur /* **************** Byte dump specific **************** */ 976d5ace945SErwin T Tsaur 977d5ace945SErwin T Tsaur static void 978d5ace945SErwin T Tsaur print_bytedump_header(boolean_t do_chardump) 979d5ace945SErwin T Tsaur { 980d5ace945SErwin T Tsaur static char header1[] = {" " 981d5ace945SErwin T Tsaur "0F 0E 0D 0C 0B 0A 09 08 07 06 05 04 03 02 01 00"}; 982d5ace945SErwin T Tsaur static char header2[] = {" " 983d5ace945SErwin T Tsaur "-----------------------------------------------"}; 984d5ace945SErwin T Tsaur static char cheader1[] = {" 0123456789ABCDEF"}; 985d5ace945SErwin T Tsaur static char cheader2[] = {" ----------------"}; 986d5ace945SErwin T Tsaur 987d5ace945SErwin T Tsaur (void) puts(""); 988d5ace945SErwin T Tsaur (void) printf(header1); 989d5ace945SErwin T Tsaur if (do_chardump) { 990d5ace945SErwin T Tsaur (void) printf(cheader1); 991d5ace945SErwin T Tsaur } 992d5ace945SErwin T Tsaur (void) puts(""); 993d5ace945SErwin T Tsaur (void) printf(header2); 994d5ace945SErwin T Tsaur if (do_chardump) { 995d5ace945SErwin T Tsaur (void) printf(cheader2); 996d5ace945SErwin T Tsaur } 997d5ace945SErwin T Tsaur } 998d5ace945SErwin T Tsaur 999d5ace945SErwin T Tsaur 1000d5ace945SErwin T Tsaur /* Number of bytes per line in a dump. */ 1001d5ace945SErwin T Tsaur #define DUMP_BUF_SIZE 16 1002d5ace945SErwin T Tsaur #define LINES_BTWN_HEADER 16 1003d5ace945SErwin T Tsaur 1004d5ace945SErwin T Tsaur /* 1005d5ace945SErwin T Tsaur * Retrieve several bytes over several reads, and print a formatted byte-dump 1006d5ace945SErwin T Tsaur * 1007d5ace945SErwin T Tsaur * fd is the nexus by which device is accessed. 1008d5ace945SErwin T Tsaur * prg provided has bus, dev, func, bank, initial offset already specified, 1009d5ace945SErwin T Tsaur * as well as size and endian attributes. 1010d5ace945SErwin T Tsaur * 1011d5ace945SErwin T Tsaur * No checking is made that this is a read operation, although only read 1012d5ace945SErwin T Tsaur * operations are allowed. 1013d5ace945SErwin T Tsaur */ 1014d5ace945SErwin T Tsaur static int 1015d5ace945SErwin T Tsaur bytedump_get(int fd, int cmd, pcitool_reg_t *prg_p, 1016d5ace945SErwin T Tsaur pcitool_uiargs_t *input_args_p) 1017d5ace945SErwin T Tsaur { 1018d5ace945SErwin T Tsaur typedef union { 1019d5ace945SErwin T Tsaur uint8_t bytes[DUMP_BUF_SIZE]; 1020d5ace945SErwin T Tsaur uint16_t shorts[DUMP_BUF_SIZE / sizeof (uint16_t)]; 1021d5ace945SErwin T Tsaur uint32_t dwords[DUMP_BUF_SIZE / sizeof (uint32_t)]; 1022d5ace945SErwin T Tsaur uint64_t longs[DUMP_BUF_SIZE / sizeof (uint64_t)]; 1023d5ace945SErwin T Tsaur } buffer_t; 1024d5ace945SErwin T Tsaur 1025d5ace945SErwin T Tsaur /* 1026d5ace945SErwin T Tsaur * Local copy of pcitool_reg_t, since offset and phys_addrs are 1027d5ace945SErwin T Tsaur * modified. 1028d5ace945SErwin T Tsaur */ 1029d5ace945SErwin T Tsaur pcitool_reg_t local_prg; 1030d5ace945SErwin T Tsaur 1031d5ace945SErwin T Tsaur /* Loop parameters. */ 1032d5ace945SErwin T Tsaur uint32_t dump_end = prg_p->offset + input_args_p->bytedump_amt; 1033d5ace945SErwin T Tsaur uint32_t dump_curr = prg_p->offset; 1034d5ace945SErwin T Tsaur 1035d5ace945SErwin T Tsaur int read_size = input_args_p->size; 1036d5ace945SErwin T Tsaur 1037d5ace945SErwin T Tsaur /* How many stores to the buffer before it is full. */ 1038d5ace945SErwin T Tsaur int wrap_size = DUMP_BUF_SIZE / read_size; 1039d5ace945SErwin T Tsaur 1040d5ace945SErwin T Tsaur /* Address prints at the beginning of each line. */ 1041d5ace945SErwin T Tsaur uint64_t print_addr = 0; 1042d5ace945SErwin T Tsaur 1043d5ace945SErwin T Tsaur /* Skip this num bytes at the beginning of the first dump. */ 1044d5ace945SErwin T Tsaur int skip_begin; 1045d5ace945SErwin T Tsaur 1046d5ace945SErwin T Tsaur /* Skip this num bytes at the end of the last dump. */ 1047d5ace945SErwin T Tsaur int skip_end = 0; 1048d5ace945SErwin T Tsaur 1049d5ace945SErwin T Tsaur /* skip_begin and skip_end are needed twice. */ 1050d5ace945SErwin T Tsaur int skip_begin2; 1051d5ace945SErwin T Tsaur int skip_end2; 1052d5ace945SErwin T Tsaur 1053d5ace945SErwin T Tsaur /* Number of lines between headers */ 1054d5ace945SErwin T Tsaur int lines_since_header = 0; 1055d5ace945SErwin T Tsaur 1056d5ace945SErwin T Tsaur boolean_t do_chardump = input_args_p->flags & CHARDUMP_FLAG; 1057d5ace945SErwin T Tsaur boolean_t continue_on_errs = input_args_p->flags & ERRCONT_FLAG; 1058d5ace945SErwin T Tsaur 1059d5ace945SErwin T Tsaur int rval = SUCCESS; /* Return status. */ 1060d5ace945SErwin T Tsaur 1061d5ace945SErwin T Tsaur int next; 1062d5ace945SErwin T Tsaur int i; 1063d5ace945SErwin T Tsaur 1064d5ace945SErwin T Tsaur buffer_t buffer; 1065d5ace945SErwin T Tsaur uint16_t error_mask = 0; /* 1 bit/byte in buf. Err when set */ 1066d5ace945SErwin T Tsaur 1067d5ace945SErwin T Tsaur bzero(buffer.bytes, sizeof (uint8_t) * DUMP_BUF_SIZE); 1068d5ace945SErwin T Tsaur 1069d5ace945SErwin T Tsaur local_prg = *prg_p; /* Make local copy. */ 1070d5ace945SErwin T Tsaur 1071d5ace945SErwin T Tsaur /* 1072d5ace945SErwin T Tsaur * Flip the bytes to proper order if reading on a big endian machine. 1073d5ace945SErwin T Tsaur * Do this by reading big as little and vs. 1074d5ace945SErwin T Tsaur */ 1075d5ace945SErwin T Tsaur #if (NATIVE_ENDIAN == PCITOOL_ACC_ATTR_ENDN_BIG) 1076d5ace945SErwin T Tsaur local_prg.acc_attr = 1077d5ace945SErwin T Tsaur (PCITOOL_ACC_IS_BIG_ENDIAN(local_prg.acc_attr) ? 1078d5ace945SErwin T Tsaur (local_prg.acc_attr & ~PCITOOL_ACC_ATTR_ENDN_BIG) : 1079d5ace945SErwin T Tsaur (local_prg.acc_attr | PCITOOL_ACC_ATTR_ENDN_BIG)); 1080d5ace945SErwin T Tsaur #endif 1081d5ace945SErwin T Tsaur 1082d5ace945SErwin T Tsaur /* 1083d5ace945SErwin T Tsaur * Get offset into buffer for first store. Assumes the buffer size is 1084d5ace945SErwin T Tsaur * a multiple of the read size. "next" is the next buffer index to do 1085d5ace945SErwin T Tsaur * a store. 1086d5ace945SErwin T Tsaur */ 1087d5ace945SErwin T Tsaur skip_begin = local_prg.offset % DUMP_BUF_SIZE; 1088d5ace945SErwin T Tsaur next = skip_begin / read_size; 1089d5ace945SErwin T Tsaur 1090d5ace945SErwin T Tsaur print_bytedump_header(do_chardump); 1091d5ace945SErwin T Tsaur 1092d5ace945SErwin T Tsaur while (dump_curr < dump_end) { 1093d5ace945SErwin T Tsaur 1094d5ace945SErwin T Tsaur /* For reading from the next location. */ 1095d5ace945SErwin T Tsaur local_prg.offset = dump_curr; 1096d5ace945SErwin T Tsaur 1097d5ace945SErwin T Tsaur /* Access the device. Abort on error. */ 1098d5ace945SErwin T Tsaur if (((rval = ioctl(fd, cmd, &local_prg)) != SUCCESS) && 1099d5ace945SErwin T Tsaur (!(continue_on_errs))) { 1100d5ace945SErwin T Tsaur if (!(IS_QUIET(input_args_p->flags))) { 1101d5ace945SErwin T Tsaur (void) fprintf(stderr, 1102d5ace945SErwin T Tsaur "Ioctl failed:\n errno: %s\n status: %s\n", 1103d5ace945SErwin T Tsaur strerror(errno), 1104d5ace945SErwin T Tsaur strstatus(local_prg.status)); 1105d5ace945SErwin T Tsaur } 1106d5ace945SErwin T Tsaur break; 1107d5ace945SErwin T Tsaur } 1108d5ace945SErwin T Tsaur 1109d5ace945SErwin T Tsaur /* 1110d5ace945SErwin T Tsaur * Initialize print_addr first time through, in case printing 1111d5ace945SErwin T Tsaur * is starting in the middle of the buffer. Also reinitialize 1112d5ace945SErwin T Tsaur * when wrap. 1113d5ace945SErwin T Tsaur */ 1114d5ace945SErwin T Tsaur if (print_addr == 0) { 1115d5ace945SErwin T Tsaur 1116d5ace945SErwin T Tsaur /* 1117d5ace945SErwin T Tsaur * X86 config space doesn't return phys addr. 1118d5ace945SErwin T Tsaur * Use offset instead in this case. 1119d5ace945SErwin T Tsaur */ 1120d5ace945SErwin T Tsaur if (local_prg.phys_addr == 0) { /* No phys addr ret */ 1121d5ace945SErwin T Tsaur print_addr = local_prg.offset - 1122d5ace945SErwin T Tsaur (local_prg.offset % DUMP_BUF_SIZE); 1123d5ace945SErwin T Tsaur } else { 1124d5ace945SErwin T Tsaur print_addr = local_prg.phys_addr - 1125d5ace945SErwin T Tsaur (local_prg.phys_addr % DUMP_BUF_SIZE); 1126d5ace945SErwin T Tsaur } 1127d5ace945SErwin T Tsaur } 1128d5ace945SErwin T Tsaur 1129d5ace945SErwin T Tsaur /* 1130d5ace945SErwin T Tsaur * Read error occurred. 1131d5ace945SErwin T Tsaur * Shift the right number of error bits ((1 << read_size) - 1) 1132d5ace945SErwin T Tsaur * into the right place (next * read_size) 1133d5ace945SErwin T Tsaur */ 1134d5ace945SErwin T Tsaur if (rval != SUCCESS) { /* Read error occurred */ 1135d5ace945SErwin T Tsaur error_mask |= 1136d5ace945SErwin T Tsaur ((1 << read_size) - 1) << (next * read_size); 1137d5ace945SErwin T Tsaur 1138d5ace945SErwin T Tsaur } else { /* Save data to the buffer. */ 1139d5ace945SErwin T Tsaur 1140d5ace945SErwin T Tsaur switch (read_size) { 1141d5ace945SErwin T Tsaur case 1: 1142d5ace945SErwin T Tsaur buffer.bytes[next] = (uint8_t)local_prg.data; 1143d5ace945SErwin T Tsaur break; 1144d5ace945SErwin T Tsaur case 2: 1145d5ace945SErwin T Tsaur buffer.shorts[next] = (uint16_t)local_prg.data; 1146d5ace945SErwin T Tsaur break; 1147d5ace945SErwin T Tsaur case 4: 1148d5ace945SErwin T Tsaur buffer.dwords[next] = (uint32_t)local_prg.data; 1149d5ace945SErwin T Tsaur break; 1150d5ace945SErwin T Tsaur case 8: 1151d5ace945SErwin T Tsaur buffer.longs[next] = (uint64_t)local_prg.data; 1152d5ace945SErwin T Tsaur break; 1153d5ace945SErwin T Tsaur default: 1154d5ace945SErwin T Tsaur rval = EIO; 1155d5ace945SErwin T Tsaur break; 1156d5ace945SErwin T Tsaur } 1157d5ace945SErwin T Tsaur } 1158d5ace945SErwin T Tsaur next++; 1159d5ace945SErwin T Tsaur 1160d5ace945SErwin T Tsaur /* Increment index for next store, and wrap. */ 1161d5ace945SErwin T Tsaur next %= wrap_size; 1162d5ace945SErwin T Tsaur dump_curr += read_size; 1163d5ace945SErwin T Tsaur 1164d5ace945SErwin T Tsaur /* Zero out the remainder of the buffer if done. */ 1165d5ace945SErwin T Tsaur if (dump_curr >= dump_end) { 1166d5ace945SErwin T Tsaur if (next != 0) { 1167d5ace945SErwin T Tsaur bzero(&buffer.bytes[next * read_size], 1168d5ace945SErwin T Tsaur (wrap_size - next) * read_size); 1169d5ace945SErwin T Tsaur skip_end = (wrap_size - next) * read_size; 1170d5ace945SErwin T Tsaur next = 0; /* For printing below. */ 1171d5ace945SErwin T Tsaur } 1172d5ace945SErwin T Tsaur } 1173d5ace945SErwin T Tsaur 1174d5ace945SErwin T Tsaur /* Dump the buffer if full or if done. */ 1175d5ace945SErwin T Tsaur if (next == 0) { 1176d5ace945SErwin T Tsaur 1177d5ace945SErwin T Tsaur skip_begin2 = skip_begin; 1178d5ace945SErwin T Tsaur skip_end2 = skip_end; 1179d5ace945SErwin T Tsaur 1180d5ace945SErwin T Tsaur (void) printf("\n0x%16.16" PRIx64 ":", print_addr); 1181d5ace945SErwin T Tsaur for (i = DUMP_BUF_SIZE - 1; i >= 0; i--) { 1182d5ace945SErwin T Tsaur if (skip_end) { 1183d5ace945SErwin T Tsaur skip_end--; 1184d5ace945SErwin T Tsaur (void) printf(" --"); 1185d5ace945SErwin T Tsaur } else if (skip_begin > i) { 1186d5ace945SErwin T Tsaur skip_begin--; 1187d5ace945SErwin T Tsaur (void) printf(" --"); 1188d5ace945SErwin T Tsaur } else if (error_mask & (1 << i)) { 1189d5ace945SErwin T Tsaur (void) printf(" XX"); 1190d5ace945SErwin T Tsaur } else { 1191d5ace945SErwin T Tsaur (void) printf(" %2.2x", 1192d5ace945SErwin T Tsaur buffer.bytes[i]); 1193d5ace945SErwin T Tsaur } 1194d5ace945SErwin T Tsaur } 1195d5ace945SErwin T Tsaur 1196d5ace945SErwin T Tsaur if (do_chardump) { 1197d5ace945SErwin T Tsaur (void) putchar(' '); 1198d5ace945SErwin T Tsaur for (i = 0; i < DUMP_BUF_SIZE; i++) { 1199d5ace945SErwin T Tsaur if (skip_begin2) { 1200d5ace945SErwin T Tsaur skip_begin2--; 1201d5ace945SErwin T Tsaur (void) printf("-"); 1202d5ace945SErwin T Tsaur } else if ( 1203d5ace945SErwin T Tsaur (DUMP_BUF_SIZE - skip_end2) <= i) { 1204d5ace945SErwin T Tsaur (void) printf("-"); 1205d5ace945SErwin T Tsaur } else if (error_mask & (1 << i)) { 1206d5ace945SErwin T Tsaur (void) putchar('X'); 1207d5ace945SErwin T Tsaur } else if (isprint(buffer.bytes[i])) { 1208d5ace945SErwin T Tsaur (void) putchar(buffer.bytes[i]); 1209d5ace945SErwin T Tsaur } else { 1210d5ace945SErwin T Tsaur (void) putchar('@'); 1211d5ace945SErwin T Tsaur } 1212d5ace945SErwin T Tsaur } 1213d5ace945SErwin T Tsaur } 1214d5ace945SErwin T Tsaur 1215d5ace945SErwin T Tsaur if ((++lines_since_header == LINES_BTWN_HEADER) && 1216d5ace945SErwin T Tsaur (dump_curr < dump_end)) { 1217d5ace945SErwin T Tsaur lines_since_header = 0; 1218d5ace945SErwin T Tsaur (void) puts(""); 1219d5ace945SErwin T Tsaur print_bytedump_header(do_chardump); 1220d5ace945SErwin T Tsaur } 1221d5ace945SErwin T Tsaur 1222d5ace945SErwin T Tsaur print_addr += DUMP_BUF_SIZE; 1223d5ace945SErwin T Tsaur error_mask = 0; 1224d5ace945SErwin T Tsaur } 1225d5ace945SErwin T Tsaur } 1226d5ace945SErwin T Tsaur (void) printf("\n"); 1227d5ace945SErwin T Tsaur 1228d5ace945SErwin T Tsaur return (rval); 1229d5ace945SErwin T Tsaur } 1230d5ace945SErwin T Tsaur 1231d5ace945SErwin T Tsaur 1232d5ace945SErwin T Tsaur /* ************** Device and nexus access commands ************** */ 1233d5ace945SErwin T Tsaur 1234d5ace945SErwin T Tsaur /* 1235d5ace945SErwin T Tsaur * Helper function to set access attributes. Assumes size is valid. 1236d5ace945SErwin T Tsaur */ 1237d5ace945SErwin T Tsaur static uint32_t 1238d5ace945SErwin T Tsaur set_acc_attr(pcitool_uiargs_t *input_args_p) 1239d5ace945SErwin T Tsaur { 1240d5ace945SErwin T Tsaur uint32_t access_attrs; 1241d5ace945SErwin T Tsaur 1242d5ace945SErwin T Tsaur switch (input_args_p->size) { 1243d5ace945SErwin T Tsaur case 1: 1244d5ace945SErwin T Tsaur access_attrs = PCITOOL_ACC_ATTR_SIZE_1; 1245d5ace945SErwin T Tsaur break; 1246d5ace945SErwin T Tsaur case 2: 1247d5ace945SErwin T Tsaur access_attrs = PCITOOL_ACC_ATTR_SIZE_2; 1248d5ace945SErwin T Tsaur break; 1249d5ace945SErwin T Tsaur case 4: 1250d5ace945SErwin T Tsaur access_attrs = PCITOOL_ACC_ATTR_SIZE_4; 1251d5ace945SErwin T Tsaur break; 1252d5ace945SErwin T Tsaur case 8: 1253d5ace945SErwin T Tsaur access_attrs = PCITOOL_ACC_ATTR_SIZE_8; 1254d5ace945SErwin T Tsaur break; 1255d5ace945SErwin T Tsaur } 1256d5ace945SErwin T Tsaur 1257d5ace945SErwin T Tsaur if (input_args_p->big_endian) { 1258d5ace945SErwin T Tsaur access_attrs |= PCITOOL_ACC_ATTR_ENDN_BIG; 1259d5ace945SErwin T Tsaur } 1260d5ace945SErwin T Tsaur 1261d5ace945SErwin T Tsaur return (access_attrs); 1262d5ace945SErwin T Tsaur } 1263d5ace945SErwin T Tsaur 1264d5ace945SErwin T Tsaur static int 1265d5ace945SErwin T Tsaur do_single_access(int fd, int cmd, pcitool_reg_t *prg_p, 1266d5ace945SErwin T Tsaur pcitool_uiargs_t *input_args_p) 1267d5ace945SErwin T Tsaur { 1268d5ace945SErwin T Tsaur boolean_t is_write = B_FALSE; 1269d5ace945SErwin T Tsaur int rval; 1270d5ace945SErwin T Tsaur 1271d5ace945SErwin T Tsaur switch (cmd) { 1272d5ace945SErwin T Tsaur case PCITOOL_NEXUS_SET_REG: 1273d5ace945SErwin T Tsaur case PCITOOL_DEVICE_SET_REG: 1274d5ace945SErwin T Tsaur is_write = B_TRUE; 1275d5ace945SErwin T Tsaur break; 1276d5ace945SErwin T Tsaur default: 1277d5ace945SErwin T Tsaur break; 1278d5ace945SErwin T Tsaur } 1279d5ace945SErwin T Tsaur 1280d5ace945SErwin T Tsaur /* Do the access. Return on error. */ 1281d5ace945SErwin T Tsaur if ((rval = ioctl(fd, cmd, prg_p)) != SUCCESS) { 1282d5ace945SErwin T Tsaur if (!(IS_QUIET(input_args_p->flags))) { 1283d5ace945SErwin T Tsaur (void) fprintf(stderr, 1284d5ace945SErwin T Tsaur "%s ioctl failed:\n errno: %s\n status: %s\n", 1285d5ace945SErwin T Tsaur is_write ? "write" : "read", 1286d5ace945SErwin T Tsaur strerror(errno), strstatus(prg_p->status)); 1287d5ace945SErwin T Tsaur } 1288d5ace945SErwin T Tsaur 1289d5ace945SErwin T Tsaur return (rval); 1290d5ace945SErwin T Tsaur } 1291d5ace945SErwin T Tsaur 1292d5ace945SErwin T Tsaur /* Print on all verbose requests. */ 1293d5ace945SErwin T Tsaur if (IS_VERBOSE(input_args_p->flags)) { 1294d5ace945SErwin T Tsaur 1295d5ace945SErwin T Tsaur /* 1296d5ace945SErwin T Tsaur * Return offset on platforms which return phys_addr == 0 1297d5ace945SErwin T Tsaur * for config space. 1298d5ace945SErwin T Tsaur */ 1299d5ace945SErwin T Tsaur if (prg_p->phys_addr == 0) 1300d5ace945SErwin T Tsaur prg_p->phys_addr = input_args_p->offset; 1301d5ace945SErwin T Tsaur 1302d5ace945SErwin T Tsaur (void) printf("Addr:0x%" PRIx64 ", %d-byte %s endian " 1303d5ace945SErwin T Tsaur "register value: 0x%" PRIx64 "\n", 1304d5ace945SErwin T Tsaur prg_p->phys_addr, input_args_p->size, 1305d5ace945SErwin T Tsaur (input_args_p->big_endian ? "big" : "little"), prg_p->data); 1306d5ace945SErwin T Tsaur 1307d5ace945SErwin T Tsaur /* Non-verbose, read requests. */ 1308d5ace945SErwin T Tsaur } else if (!(is_write)) { 1309d5ace945SErwin T Tsaur (void) printf("0x%" PRIx64 "\n", prg_p->data); 1310d5ace945SErwin T Tsaur } 1311d5ace945SErwin T Tsaur 1312d5ace945SErwin T Tsaur return (rval); 1313d5ace945SErwin T Tsaur } 1314d5ace945SErwin T Tsaur 1315d5ace945SErwin T Tsaur 1316d5ace945SErwin T Tsaur /* 1317d5ace945SErwin T Tsaur * fd is the file descriptor of the nexus to access, either to get its 1318d5ace945SErwin T Tsaur * registers or to access a device through that nexus. 1319d5ace945SErwin T Tsaur * 1320d5ace945SErwin T Tsaur * input args are commandline arguments specified by the user. 1321d5ace945SErwin T Tsaur */ 1322d5ace945SErwin T Tsaur static int 1323d5ace945SErwin T Tsaur do_device_or_nexus(int fd, pcitool_uiargs_t *input_args_p) 1324d5ace945SErwin T Tsaur { 1325d5ace945SErwin T Tsaur pcitool_reg_t prg; /* Request details given to the driver. */ 1326d5ace945SErwin T Tsaur uint32_t write_cmd = 0; /* Command given to the driver. */ 1327d5ace945SErwin T Tsaur uint32_t read_cmd = 0; /* Command given to the driver. */ 1328d5ace945SErwin T Tsaur int rval = SUCCESS; /* Return status. */ 1329d5ace945SErwin T Tsaur 1330d5ace945SErwin T Tsaur if (input_args_p->flags & WRITE_FLAG) { 1331d5ace945SErwin T Tsaur prg.data = input_args_p->write_value; 1332d5ace945SErwin T Tsaur if (input_args_p->flags & NEXUS_FLAG) { 1333d5ace945SErwin T Tsaur write_cmd = PCITOOL_NEXUS_SET_REG; 1334d5ace945SErwin T Tsaur } else { 1335d5ace945SErwin T Tsaur write_cmd = PCITOOL_DEVICE_SET_REG; 1336d5ace945SErwin T Tsaur } 1337d5ace945SErwin T Tsaur } 1338d5ace945SErwin T Tsaur if (input_args_p->flags & READ_FLAG) { 1339d5ace945SErwin T Tsaur if (input_args_p->flags & NEXUS_FLAG) { 1340d5ace945SErwin T Tsaur read_cmd = PCITOOL_NEXUS_GET_REG; 1341d5ace945SErwin T Tsaur } else { 1342d5ace945SErwin T Tsaur read_cmd = PCITOOL_DEVICE_GET_REG; 1343d5ace945SErwin T Tsaur } 1344d5ace945SErwin T Tsaur } 1345d5ace945SErwin T Tsaur 1346d5ace945SErwin T Tsaur /* Finish initializing access details for driver. */ 1347d5ace945SErwin T Tsaur 1348d5ace945SErwin T Tsaur /* 1349d5ace945SErwin T Tsaur * For nexus, barnum is the exact bank number, unless it is 0xFF, which 1350d5ace945SErwin T Tsaur * indicates that it is inactive and a base_address should be read from 1351d5ace945SErwin T Tsaur * the input_args instead. 1352d5ace945SErwin T Tsaur * 1353d5ace945SErwin T Tsaur * For devices, barnum is the offset to the desired BAR, or 0 for 1354d5ace945SErwin T Tsaur * config space. 1355d5ace945SErwin T Tsaur */ 1356d5ace945SErwin T Tsaur if ((input_args_p->flags & (BASE_SPEC_FLAG | NEXUS_FLAG)) == 1357d5ace945SErwin T Tsaur (BASE_SPEC_FLAG | NEXUS_FLAG)) { 1358d5ace945SErwin T Tsaur prg.barnum = PCITOOL_BASE; 1359d5ace945SErwin T Tsaur prg.phys_addr = input_args_p->base_address; 1360d5ace945SErwin T Tsaur } else 1361d5ace945SErwin T Tsaur prg.barnum = input_args_p->bank; 1362d5ace945SErwin T Tsaur 1363d5ace945SErwin T Tsaur prg.offset = input_args_p->offset; 1364d5ace945SErwin T Tsaur prg.acc_attr = set_acc_attr(input_args_p); 1365d5ace945SErwin T Tsaur prg.bus_no = input_args_p->bus; 1366d5ace945SErwin T Tsaur prg.dev_no = input_args_p->device; 1367d5ace945SErwin T Tsaur prg.func_no = input_args_p->function; 1368d5ace945SErwin T Tsaur prg.user_version = PCITOOL_VERSION; 1369d5ace945SErwin T Tsaur 1370d5ace945SErwin T Tsaur do { 1371d5ace945SErwin T Tsaur /* Do a bytedump if desired, or else do single ioctl access. */ 1372d5ace945SErwin T Tsaur if (input_args_p->flags & BYTEDUMP_FLAG) { 1373d5ace945SErwin T Tsaur 1374d5ace945SErwin T Tsaur if (IS_VERBOSE(input_args_p->flags)) { 1375d5ace945SErwin T Tsaur (void) printf( 1376d5ace945SErwin T Tsaur "\nDoing %d-byte %s endian reads:", 1377d5ace945SErwin T Tsaur input_args_p->size, 1378d5ace945SErwin T Tsaur input_args_p->big_endian ? 1379d5ace945SErwin T Tsaur "big" : "little"); 1380d5ace945SErwin T Tsaur } 1381d5ace945SErwin T Tsaur rval = bytedump_get(fd, read_cmd, &prg, input_args_p); 1382d5ace945SErwin T Tsaur 1383d5ace945SErwin T Tsaur } else { 1384d5ace945SErwin T Tsaur 1385d5ace945SErwin T Tsaur /* Single write and/or read. */ 1386d5ace945SErwin T Tsaur if (write_cmd != 0) { 1387d5ace945SErwin T Tsaur rval = do_single_access( 1388d5ace945SErwin T Tsaur fd, write_cmd, &prg, input_args_p); 1389d5ace945SErwin T Tsaur } 1390d5ace945SErwin T Tsaur 1391d5ace945SErwin T Tsaur if ((rval == SUCCESS) && (read_cmd != 0)) { 1392d5ace945SErwin T Tsaur rval = do_single_access( 1393d5ace945SErwin T Tsaur fd, read_cmd, &prg, input_args_p); 1394d5ace945SErwin T Tsaur } 1395d5ace945SErwin T Tsaur } 1396d5ace945SErwin T Tsaur } while ((IS_LOOP(input_args_p->flags)) && (rval == SUCCESS) && 1397d5ace945SErwin T Tsaur (keep_looping)); 1398d5ace945SErwin T Tsaur 1399d5ace945SErwin T Tsaur return (rval != SUCCESS ? errno : SUCCESS); 1400d5ace945SErwin T Tsaur } 1401d5ace945SErwin T Tsaur 1402d5ace945SErwin T Tsaur /* *************** Interrupt routing ************** */ 1403d5ace945SErwin T Tsaur 1404d5ace945SErwin T Tsaur /* 1405d5ace945SErwin T Tsaur * Display interrupt information. 1406d5ace945SErwin T Tsaur * iget is filled in with the info to display 1407d5ace945SErwin T Tsaur */ 1408d5ace945SErwin T Tsaur static void 1409d5ace945SErwin T Tsaur print_intr_info(pcitool_intr_get_t *iget_p) 1410d5ace945SErwin T Tsaur { 1411d5ace945SErwin T Tsaur int i; 1412d5ace945SErwin T Tsaur 1413d5ace945SErwin T Tsaur for (i = 0; i < iget_p->num_devs; i++) { 1414*7ff178cdSJimmy Vetayases if (iget_p->flags & PCITOOL_INTR_FLAG_GET_MSI) 1415*7ff178cdSJimmy Vetayases (void) printf("0x%x,0x%x: %-10s%d\t %s\n", 1416*7ff178cdSJimmy Vetayases iget_p->cpu_id, iget_p->msi & 0xff, 1417*7ff178cdSJimmy Vetayases iget_p->dev[i].driver_name, iget_p->dev[i].dev_inst, 1418*7ff178cdSJimmy Vetayases iget_p->dev[i].path); 1419*7ff178cdSJimmy Vetayases else 1420*7ff178cdSJimmy Vetayases (void) printf("0x%x,0x%x: %-10s%d\t %s\n", 1421*7ff178cdSJimmy Vetayases iget_p->cpu_id, iget_p->ino & 0xff, 1422*7ff178cdSJimmy Vetayases iget_p->dev[i].driver_name, iget_p->dev[i].dev_inst, 1423*7ff178cdSJimmy Vetayases iget_p->dev[i].path); 1424d5ace945SErwin T Tsaur } 1425*7ff178cdSJimmy Vetayases 1426d5ace945SErwin T Tsaur } 1427d5ace945SErwin T Tsaur 1428d5ace945SErwin T Tsaur /* 1429d5ace945SErwin T Tsaur * Interrupt command support. 1430d5ace945SErwin T Tsaur * 1431d5ace945SErwin T Tsaur * fd is the file descriptor of the nexus being probed. 1432d5ace945SErwin T Tsaur * input_args are commandline options entered by the user. 1433d5ace945SErwin T Tsaur */ 1434d5ace945SErwin T Tsaur static int 1435d5ace945SErwin T Tsaur get_single_interrupt(int fd, pcitool_intr_get_t **iget_pp, 1436d5ace945SErwin T Tsaur pcitool_uiargs_t *input_args_p) 1437d5ace945SErwin T Tsaur { 1438d5ace945SErwin T Tsaur pcitool_intr_get_t *iget_p = *iget_pp; 143909b1eac2SEvan Yan const char *str_type = NULL; 144009b1eac2SEvan Yan uint32_t intr; 144109b1eac2SEvan Yan 144209b1eac2SEvan Yan if (input_args_p->flags & MSI_SPEC_FLAG) { 144309b1eac2SEvan Yan intr = input_args_p->intr_msi; 144409b1eac2SEvan Yan str_type = "msi"; 144509b1eac2SEvan Yan } else { 144609b1eac2SEvan Yan intr = input_args_p->intr_ino; 144709b1eac2SEvan Yan str_type = "ino"; 144809b1eac2SEvan Yan } 1449d5ace945SErwin T Tsaur 1450d5ace945SErwin T Tsaur /* 145109b1eac2SEvan Yan * Check if interrupts are active on this ino/msi. Get as much 1452d5ace945SErwin T Tsaur * device info as there is room for at the moment. If there 1453d5ace945SErwin T Tsaur * is not enough room for all devices, will call again with a 1454d5ace945SErwin T Tsaur * larger buffer. 1455d5ace945SErwin T Tsaur */ 1456d5ace945SErwin T Tsaur if (ioctl(fd, PCITOOL_DEVICE_GET_INTR, iget_p) != 0) { 1457d5ace945SErwin T Tsaur /* 1458d5ace945SErwin T Tsaur * Let EIO errors silently slip through, as 1459d5ace945SErwin T Tsaur * some inos may not be viewable by design. 1460d5ace945SErwin T Tsaur * We don't want to stop or print an error for these. 1461d5ace945SErwin T Tsaur */ 1462d5ace945SErwin T Tsaur if (errno == EIO) { 1463d5ace945SErwin T Tsaur return (SUCCESS); 1464d5ace945SErwin T Tsaur } 1465d5ace945SErwin T Tsaur 1466d5ace945SErwin T Tsaur if (!(IS_QUIET(input_args_p->flags))) { 146709b1eac2SEvan Yan (void) fprintf(stderr, "Ioctl to get %s 0x%x " 146809b1eac2SEvan Yan "info failed: %s\n", str_type, intr, 146909b1eac2SEvan Yan strerror(errno)); 147009b1eac2SEvan Yan 1471d5ace945SErwin T Tsaur if (errno != EFAULT) { 1472d5ace945SErwin T Tsaur (void) fprintf(stderr, "Pcitool status: %s\n", 1473d5ace945SErwin T Tsaur strstatus(iget_p->status)); 1474d5ace945SErwin T Tsaur } 1475d5ace945SErwin T Tsaur } 1476d5ace945SErwin T Tsaur return (errno); 1477d5ace945SErwin T Tsaur } 1478d5ace945SErwin T Tsaur 1479d5ace945SErwin T Tsaur /* Nothing to report for this interrupt. */ 1480d5ace945SErwin T Tsaur if (iget_p->num_devs == 0) { 1481d5ace945SErwin T Tsaur return (SUCCESS); 1482d5ace945SErwin T Tsaur } 1483d5ace945SErwin T Tsaur 1484d5ace945SErwin T Tsaur /* Need more room to return additional device info. */ 1485d5ace945SErwin T Tsaur if (iget_p->num_devs_ret < iget_p->num_devs) { 1486d5ace945SErwin T Tsaur iget_p = *iget_pp = 1487d5ace945SErwin T Tsaur realloc(iget_p, PCITOOL_IGET_SIZE(iget_p->num_devs)); 1488d5ace945SErwin T Tsaur iget_p->num_devs_ret = iget_p->num_devs; 148909b1eac2SEvan Yan 1490d5ace945SErwin T Tsaur if (ioctl(fd, PCITOOL_DEVICE_GET_INTR, iget_p) != 0) { 1491d5ace945SErwin T Tsaur if (!(IS_QUIET(input_args_p->flags))) { 149209b1eac2SEvan Yan (void) fprintf(stderr, "Ioctl to get %s 0x%x" 149309b1eac2SEvan Yan "device info failed: %s\n", str_type, 149409b1eac2SEvan Yan intr, strerror(errno)); 1495d5ace945SErwin T Tsaur if (errno != EFAULT) { 1496d5ace945SErwin T Tsaur (void) fprintf(stderr, 1497d5ace945SErwin T Tsaur "Pcitool status: %s\n", 1498d5ace945SErwin T Tsaur strstatus(iget_p->status)); 1499d5ace945SErwin T Tsaur } 1500d5ace945SErwin T Tsaur } 1501d5ace945SErwin T Tsaur return (errno); 1502d5ace945SErwin T Tsaur } 1503d5ace945SErwin T Tsaur } 1504d5ace945SErwin T Tsaur 1505d5ace945SErwin T Tsaur print_intr_info(iget_p); 1506d5ace945SErwin T Tsaur return (SUCCESS); 1507d5ace945SErwin T Tsaur } 1508d5ace945SErwin T Tsaur 1509d5ace945SErwin T Tsaur #define INIT_NUM_DEVS 0 1510d5ace945SErwin T Tsaur 1511d5ace945SErwin T Tsaur static int 1512d5ace945SErwin T Tsaur get_interrupts(int fd, pcitool_uiargs_t *input_args_p) 1513d5ace945SErwin T Tsaur { 1514d5ace945SErwin T Tsaur int rval = SUCCESS; /* Return status. */ 1515*7ff178cdSJimmy Vetayases int ino, cpu_id; 1516d5ace945SErwin T Tsaur 1517d5ace945SErwin T Tsaur /* 1518d5ace945SErwin T Tsaur * Start with a struct with space for info of INIT_NUM_DEVS devs 1519d5ace945SErwin T Tsaur * to be returned. 1520d5ace945SErwin T Tsaur */ 1521d5ace945SErwin T Tsaur pcitool_intr_get_t *iget_p = malloc(PCITOOL_IGET_SIZE(INIT_NUM_DEVS)); 1522d5ace945SErwin T Tsaur 1523d5ace945SErwin T Tsaur iget_p->num_devs_ret = INIT_NUM_DEVS; 1524d5ace945SErwin T Tsaur iget_p->user_version = PCITOOL_VERSION; 1525d5ace945SErwin T Tsaur 152609b1eac2SEvan Yan /* Explicit MSI requested. */ 152709b1eac2SEvan Yan if (input_args_p->flags & MSI_SPEC_FLAG) { 152809b1eac2SEvan Yan iget_p->msi = input_args_p->intr_msi; 152909b1eac2SEvan Yan iget_p->flags = PCITOOL_INTR_FLAG_GET_MSI; 1530d5ace945SErwin T Tsaur rval = get_single_interrupt(fd, &iget_p, input_args_p); 153109b1eac2SEvan Yan /* Return all MSIs. */ 153209b1eac2SEvan Yan } else if (input_args_p->flags & MSI_ALL_FLAG) { 1533d5ace945SErwin T Tsaur pcitool_intr_info_t intr_info; 153409b1eac2SEvan Yan intr_info.flags = PCITOOL_INTR_FLAG_GET_MSI; 1535d5ace945SErwin T Tsaur 1536d5ace945SErwin T Tsaur if (ioctl(fd, PCITOOL_SYSTEM_INTR_INFO, &intr_info) != 0) { 1537d5ace945SErwin T Tsaur if (!(IS_QUIET(input_args_p->flags))) { 1538d5ace945SErwin T Tsaur (void) fprintf(stderr, 1539d5ace945SErwin T Tsaur "intr info ioctl failed: %s\n", 1540d5ace945SErwin T Tsaur strerror(errno)); 1541d5ace945SErwin T Tsaur } 1542d5ace945SErwin T Tsaur } else { 154309b1eac2SEvan Yan int msi; 1544d5ace945SErwin T Tsaur 154509b1eac2SEvan Yan /* 154609b1eac2SEvan Yan * Search through all interrupts. 154709b1eac2SEvan Yan * Display info on enabled ones. 154809b1eac2SEvan Yan */ 154909b1eac2SEvan Yan for (msi = 0; 155009b1eac2SEvan Yan ((msi < intr_info.num_intr) && (rval == SUCCESS)); 155109b1eac2SEvan Yan msi++) { 155209b1eac2SEvan Yan bzero(iget_p, sizeof (pcitool_intr_get_t)); 155309b1eac2SEvan Yan iget_p->num_devs_ret = INIT_NUM_DEVS; 155409b1eac2SEvan Yan iget_p->user_version = PCITOOL_VERSION; 155509b1eac2SEvan Yan iget_p->flags = PCITOOL_INTR_FLAG_GET_MSI; 155609b1eac2SEvan Yan iget_p->msi = msi; 155709b1eac2SEvan Yan rval = get_single_interrupt( 155809b1eac2SEvan Yan fd, &iget_p, input_args_p); 155909b1eac2SEvan Yan } 156009b1eac2SEvan Yan } 156109b1eac2SEvan Yan /* Explicit INO requested. */ 156209b1eac2SEvan Yan } else if (input_args_p->flags & INO_SPEC_FLAG) { 156309b1eac2SEvan Yan iget_p->ino = input_args_p->intr_ino; 1564*7ff178cdSJimmy Vetayases iget_p->cpu_id = input_args_p->old_cpu; 156509b1eac2SEvan Yan rval = get_single_interrupt(fd, &iget_p, input_args_p); 156609b1eac2SEvan Yan /* Return all INOs. */ 156709b1eac2SEvan Yan } else if (input_args_p->flags & INO_ALL_FLAG) { 156809b1eac2SEvan Yan pcitool_intr_info_t intr_info; 156909b1eac2SEvan Yan intr_info.flags = 0; 157009b1eac2SEvan Yan 157109b1eac2SEvan Yan if (ioctl(fd, PCITOOL_SYSTEM_INTR_INFO, &intr_info) != 0) { 157209b1eac2SEvan Yan if (!(IS_QUIET(input_args_p->flags))) { 157309b1eac2SEvan Yan (void) fprintf(stderr, 157409b1eac2SEvan Yan "intr info ioctl failed: %s\n", 157509b1eac2SEvan Yan strerror(errno)); 157609b1eac2SEvan Yan } 1577*7ff178cdSJimmy Vetayases free(iget_p); 1578*7ff178cdSJimmy Vetayases return (rval); 1579*7ff178cdSJimmy Vetayases } 1580d5ace945SErwin T Tsaur 1581d5ace945SErwin T Tsaur /* 1582d5ace945SErwin T Tsaur * Search through all interrupts. 1583d5ace945SErwin T Tsaur * Display info on enabled ones. 1584d5ace945SErwin T Tsaur */ 1585*7ff178cdSJimmy Vetayases if (intr_info.ctlr_type == PCITOOL_CTLR_TYPE_APIX) { 1586*7ff178cdSJimmy Vetayases for (cpu_id = 0; 1587*7ff178cdSJimmy Vetayases ((cpu_id < intr_info.num_cpu) && (rval == SUCCESS)); 1588*7ff178cdSJimmy Vetayases cpu_id++) { 1589d5ace945SErwin T Tsaur for (ino = 0; 1590*7ff178cdSJimmy Vetayases ((ino < intr_info.num_intr) && 1591*7ff178cdSJimmy Vetayases (rval == SUCCESS)); 1592d5ace945SErwin T Tsaur ino++) { 1593*7ff178cdSJimmy Vetayases bzero(iget_p, 1594*7ff178cdSJimmy Vetayases sizeof (pcitool_intr_get_t)); 159509b1eac2SEvan Yan iget_p->num_devs_ret = INIT_NUM_DEVS; 159609b1eac2SEvan Yan iget_p->user_version = PCITOOL_VERSION; 1597*7ff178cdSJimmy Vetayases iget_p->cpu_id = cpu_id; 1598*7ff178cdSJimmy Vetayases iget_p->ino = ino; 1599*7ff178cdSJimmy Vetayases rval = get_single_interrupt( 1600*7ff178cdSJimmy Vetayases fd, &iget_p, input_args_p); 1601*7ff178cdSJimmy Vetayases } 1602*7ff178cdSJimmy Vetayases } 1603*7ff178cdSJimmy Vetayases } else { 1604*7ff178cdSJimmy Vetayases for (ino = 0; 1605*7ff178cdSJimmy Vetayases (ino < intr_info.num_intr) && (rval == SUCCESS); 1606*7ff178cdSJimmy Vetayases ino++) { 1607*7ff178cdSJimmy Vetayases bzero(iget_p, 1608*7ff178cdSJimmy Vetayases sizeof (pcitool_intr_get_t)); 1609*7ff178cdSJimmy Vetayases iget_p->num_devs_ret = INIT_NUM_DEVS; 1610*7ff178cdSJimmy Vetayases iget_p->user_version = PCITOOL_VERSION; 1611*7ff178cdSJimmy Vetayases iget_p->cpu_id = input_args_p->old_cpu; 1612d5ace945SErwin T Tsaur iget_p->ino = ino; 1613d5ace945SErwin T Tsaur rval = get_single_interrupt( 1614d5ace945SErwin T Tsaur fd, &iget_p, input_args_p); 1615d5ace945SErwin T Tsaur } 1616d5ace945SErwin T Tsaur } 1617d5ace945SErwin T Tsaur } 1618d5ace945SErwin T Tsaur 1619d5ace945SErwin T Tsaur free(iget_p); 1620d5ace945SErwin T Tsaur 1621d5ace945SErwin T Tsaur return (rval); 1622d5ace945SErwin T Tsaur } 1623d5ace945SErwin T Tsaur 1624d5ace945SErwin T Tsaur 1625d5ace945SErwin T Tsaur static int 1626d5ace945SErwin T Tsaur get_interrupt_ctlr(int fd, pcitool_uiargs_t *input_args_p) 1627d5ace945SErwin T Tsaur { 1628d5ace945SErwin T Tsaur pcitool_intr_info_t intr_info; 1629d5ace945SErwin T Tsaur char *ctlr_type = NULL; 1630d5ace945SErwin T Tsaur int rval = SUCCESS; 1631d5ace945SErwin T Tsaur 163209b1eac2SEvan Yan intr_info.flags = 0; 1633d5ace945SErwin T Tsaur if (ioctl(fd, PCITOOL_SYSTEM_INTR_INFO, &intr_info) != 0) { 1634d5ace945SErwin T Tsaur if (!(IS_QUIET(input_args_p->flags))) { 1635d5ace945SErwin T Tsaur (void) perror("Ioctl to get intr ctlr info failed"); 1636d5ace945SErwin T Tsaur } 1637d5ace945SErwin T Tsaur rval = errno; 1638d5ace945SErwin T Tsaur 1639d5ace945SErwin T Tsaur } else { 1640d5ace945SErwin T Tsaur (void) fputs("Controller type: ", stdout); 1641d5ace945SErwin T Tsaur switch (intr_info.ctlr_type) { 1642d5ace945SErwin T Tsaur case PCITOOL_CTLR_TYPE_RISC: 1643d5ace945SErwin T Tsaur ctlr_type = "RISC"; 1644d5ace945SErwin T Tsaur break; 1645d5ace945SErwin T Tsaur case PCITOOL_CTLR_TYPE_UPPC: 1646d5ace945SErwin T Tsaur ctlr_type = "UPPC"; 1647d5ace945SErwin T Tsaur break; 1648d5ace945SErwin T Tsaur case PCITOOL_CTLR_TYPE_PCPLUSMP: 1649d5ace945SErwin T Tsaur ctlr_type = "PCPLUSMP"; 1650d5ace945SErwin T Tsaur break; 1651*7ff178cdSJimmy Vetayases case PCITOOL_CTLR_TYPE_APIX: 1652*7ff178cdSJimmy Vetayases ctlr_type = "APIX"; 1653*7ff178cdSJimmy Vetayases break; 1654*7ff178cdSJimmy Vetayases 1655d5ace945SErwin T Tsaur default: 1656d5ace945SErwin T Tsaur break; 1657d5ace945SErwin T Tsaur } 1658d5ace945SErwin T Tsaur 1659d5ace945SErwin T Tsaur if (ctlr_type == NULL) { 1660d5ace945SErwin T Tsaur (void) printf("Unknown or new (%d)", 1661d5ace945SErwin T Tsaur intr_info.ctlr_type); 1662d5ace945SErwin T Tsaur } else { 1663d5ace945SErwin T Tsaur (void) fputs(ctlr_type, stdout); 1664d5ace945SErwin T Tsaur } 1665d5ace945SErwin T Tsaur 1666d5ace945SErwin T Tsaur #ifdef __x86 1667d5ace945SErwin T Tsaur if (intr_info.ctlr_type == PCITOOL_CTLR_TYPE_PCPLUSMP) 1668d5ace945SErwin T Tsaur (void) printf(", IO APIC version: 0x%x, " 1669d5ace945SErwin T Tsaur "local APIC version: 0x%x\n", 1670d5ace945SErwin T Tsaur PSMAT_IO_APIC_VER(intr_info.ctlr_version), 1671d5ace945SErwin T Tsaur PSMAT_LOCAL_APIC_VER(intr_info.ctlr_version)); 1672d5ace945SErwin T Tsaur else 1673d5ace945SErwin T Tsaur #endif /* __x86 */ 1674d5ace945SErwin T Tsaur (void) printf(", version: %2.2x.%2.2x.%2.2x.%2.2x\n", 1675d5ace945SErwin T Tsaur ((intr_info.ctlr_version >> 24) & 0xff), 1676d5ace945SErwin T Tsaur ((intr_info.ctlr_version >> 16) & 0xff), 1677d5ace945SErwin T Tsaur ((intr_info.ctlr_version >> 8) & 0xff), 1678d5ace945SErwin T Tsaur (intr_info.ctlr_version & 0xff)); 1679d5ace945SErwin T Tsaur } 1680d5ace945SErwin T Tsaur 1681d5ace945SErwin T Tsaur return (rval); 1682d5ace945SErwin T Tsaur } 1683d5ace945SErwin T Tsaur 1684d5ace945SErwin T Tsaur /* 1685d5ace945SErwin T Tsaur * 1686d5ace945SErwin T Tsaur * fd is the file descriptor of the nexus being changed. 1687d5ace945SErwin T Tsaur * input_args are commandline options entered by the user. 1688d5ace945SErwin T Tsaur */ 1689d5ace945SErwin T Tsaur static int 1690d5ace945SErwin T Tsaur set_interrupts(int fd, pcitool_uiargs_t *input_args_p) 1691d5ace945SErwin T Tsaur { 169209b1eac2SEvan Yan pcitool_intr_set_t iset; 169309b1eac2SEvan Yan const char *str_type = NULL; 169409b1eac2SEvan Yan uint32_t intr; 1695d5ace945SErwin T Tsaur int rval = SUCCESS; /* Return status. */ 1696d5ace945SErwin T Tsaur 1697d5ace945SErwin T Tsaur /* Load interrupt number and cpu from commandline. */ 169809b1eac2SEvan Yan if (input_args_p->flags & MSI_SPEC_FLAG) { 169909b1eac2SEvan Yan iset.msi = intr = input_args_p->intr_msi; 170009b1eac2SEvan Yan iset.flags = PCITOOL_INTR_FLAG_SET_MSI; 170109b1eac2SEvan Yan str_type = "msi"; 170209b1eac2SEvan Yan } else { 170309b1eac2SEvan Yan iset.ino = intr = input_args_p->intr_ino; 170409b1eac2SEvan Yan iset.flags = 0; 170509b1eac2SEvan Yan str_type = "ino"; 170609b1eac2SEvan Yan } 170709b1eac2SEvan Yan 1708d5ace945SErwin T Tsaur iset.cpu_id = input_args_p->intr_cpu; 1709*7ff178cdSJimmy Vetayases iset.old_cpu = input_args_p->old_cpu; 1710d5ace945SErwin T Tsaur iset.user_version = PCITOOL_VERSION; 171109b1eac2SEvan Yan iset.flags |= (input_args_p->flags & SETGRP_FLAG) ? 171209b1eac2SEvan Yan PCITOOL_INTR_FLAG_SET_GROUP : 0; 1713d5ace945SErwin T Tsaur 1714d5ace945SErwin T Tsaur /* Do the deed. */ 1715d5ace945SErwin T Tsaur if (ioctl(fd, PCITOOL_DEVICE_SET_INTR, &iset) != 0) { 1716d5ace945SErwin T Tsaur if (!(IS_QUIET(input_args_p->flags))) { 1717d5ace945SErwin T Tsaur (void) fprintf(stderr, 171809b1eac2SEvan Yan "Ioctl to set %s 0x%x failed: %s\n", 171909b1eac2SEvan Yan str_type, intr, strerror(errno)); 1720d5ace945SErwin T Tsaur (void) fprintf(stderr, "pcitool status: %s\n", 1721d5ace945SErwin T Tsaur strstatus(iset.status)); 1722d5ace945SErwin T Tsaur } 1723d5ace945SErwin T Tsaur rval = errno; 1724d5ace945SErwin T Tsaur } else { 1725d5ace945SErwin T Tsaur if (input_args_p->flags & SETGRP_FLAG) { 1726*7ff178cdSJimmy Vetayases if (iset.flags == PCITOOL_INTR_FLAG_SET_MSI) 1727*7ff178cdSJimmy Vetayases (void) printf("0x%x,0x%x => 0x%x,0x%x\n", 1728*7ff178cdSJimmy Vetayases iset.cpu_id, 1729*7ff178cdSJimmy Vetayases (input_args_p->intr_msi) & 0xff, 1730*7ff178cdSJimmy Vetayases input_args_p->intr_cpu, iset.msi); 1731*7ff178cdSJimmy Vetayases else 1732*7ff178cdSJimmy Vetayases (void) printf("0x%x,0x%x => 0x%x,0x%x\n", 1733*7ff178cdSJimmy Vetayases iset.cpu_id, 1734*7ff178cdSJimmy Vetayases (input_args_p->intr_ino) & 0xff, 1735*7ff178cdSJimmy Vetayases input_args_p->intr_cpu, iset.ino); 1736d5ace945SErwin T Tsaur } else { 1737*7ff178cdSJimmy Vetayases if (iset.flags == PCITOOL_INTR_FLAG_SET_MSI) 1738*7ff178cdSJimmy Vetayases (void) printf("0x%x,0x%x -> 0x%x,0x%x\n", 1739*7ff178cdSJimmy Vetayases iset.cpu_id, 1740*7ff178cdSJimmy Vetayases (input_args_p->intr_msi) & 0xff, 1741*7ff178cdSJimmy Vetayases input_args_p->intr_cpu, iset.msi); 1742*7ff178cdSJimmy Vetayases else 1743*7ff178cdSJimmy Vetayases (void) printf("0x%x,0x%x -> 0x%x,0x%x\n", 1744*7ff178cdSJimmy Vetayases iset.cpu_id, 1745*7ff178cdSJimmy Vetayases (input_args_p->intr_ino) & 0xff, 1746*7ff178cdSJimmy Vetayases input_args_p->intr_cpu, iset.ino); 1747d5ace945SErwin T Tsaur } 1748*7ff178cdSJimmy Vetayases 1749d5ace945SErwin T Tsaur } 1750d5ace945SErwin T Tsaur 1751d5ace945SErwin T Tsaur return (rval); 1752d5ace945SErwin T Tsaur } 1753d5ace945SErwin T Tsaur 1754d5ace945SErwin T Tsaur 1755d5ace945SErwin T Tsaur static int 1756d5ace945SErwin T Tsaur do_interrupts(int fd, pcitool_uiargs_t *input_args_p) 1757d5ace945SErwin T Tsaur { 1758d5ace945SErwin T Tsaur if (input_args_p->flags & READ_FLAG) { 1759d5ace945SErwin T Tsaur 17603004e88eSlipeng sang - Sun Microsystems - Beijing China int gic_rval = SUCCESS; 17613004e88eSlipeng sang - Sun Microsystems - Beijing China int gi_rval = SUCCESS; 1762d5ace945SErwin T Tsaur 1763d5ace945SErwin T Tsaur if (input_args_p->flags & SHOWCTLR_FLAG) { 1764d5ace945SErwin T Tsaur gic_rval = get_interrupt_ctlr(fd, input_args_p); 1765d5ace945SErwin T Tsaur } 1766d5ace945SErwin T Tsaur 1767d5ace945SErwin T Tsaur gi_rval = get_interrupts(fd, input_args_p); 1768d5ace945SErwin T Tsaur return ((gi_rval != SUCCESS) ? gi_rval : gic_rval); 1769d5ace945SErwin T Tsaur 1770d5ace945SErwin T Tsaur } else { 1771d5ace945SErwin T Tsaur 1772d5ace945SErwin T Tsaur return (set_interrupts(fd, input_args_p)); 1773d5ace945SErwin T Tsaur } 1774d5ace945SErwin T Tsaur } 1775d5ace945SErwin T Tsaur 1776d5ace945SErwin T Tsaur 1777d5ace945SErwin T Tsaur /* *********** Where it all begins... ************* */ 1778d5ace945SErwin T Tsaur 1779d5ace945SErwin T Tsaur int 1780d5ace945SErwin T Tsaur main(int argc, char **argv) 1781d5ace945SErwin T Tsaur { 1782d5ace945SErwin T Tsaur pcitool_uiargs_t input_args; /* Commandline args. */ 1783d5ace945SErwin T Tsaur int fd; /* Nexus file descriptor. */ 1784d5ace945SErwin T Tsaur int rval = SUCCESS; /* Return status value. */ 1785d5ace945SErwin T Tsaur 1786d5ace945SErwin T Tsaur 1787d5ace945SErwin T Tsaur /* Get commandline args and options from user. */ 1788d5ace945SErwin T Tsaur if (get_commandline_args(argc, argv, &input_args) != SUCCESS) { 1789d5ace945SErwin T Tsaur return (EINVAL); 1790d5ace945SErwin T Tsaur } 1791d5ace945SErwin T Tsaur 1792d5ace945SErwin T Tsaur /* Help. */ 1793d5ace945SErwin T Tsaur if (!(input_args.flags & ALL_COMMANDS)) 1794d5ace945SErwin T Tsaur return (SUCCESS); 1795d5ace945SErwin T Tsaur 1796d5ace945SErwin T Tsaur /* 1797d5ace945SErwin T Tsaur * Probe mode. 1798d5ace945SErwin T Tsaur * Nexus is provided as argv[1] unless PROBEALL mode. 1799d5ace945SErwin T Tsaur */ 1800d5ace945SErwin T Tsaur if (input_args.flags & PROBE_FLAGS) { 1801d5ace945SErwin T Tsaur rval = do_probe_walk(&input_args, 1802d5ace945SErwin T Tsaur ((input_args.flags & PROBEALL_FLAG) ? NULL : argv[1])); 1803d5ace945SErwin T Tsaur 1804d5ace945SErwin T Tsaur } else if ((fd = open_node(argv[1], &input_args)) >= 0) { 1805d5ace945SErwin T Tsaur if (input_args.flags & (NEXUS_FLAG | LEAF_FLAG)) { 1806d5ace945SErwin T Tsaur (void) signal(SIGINT, signal_handler); 1807d5ace945SErwin T Tsaur (void) signal(SIGTERM, signal_handler); 1808d5ace945SErwin T Tsaur rval = do_device_or_nexus(fd, &input_args); 1809d5ace945SErwin T Tsaur } else if (input_args.flags & INTR_FLAG) { 1810d5ace945SErwin T Tsaur rval = do_interrupts(fd, &input_args); 1811d5ace945SErwin T Tsaur } else { 1812d5ace945SErwin T Tsaur /* Should never see this. */ 1813d5ace945SErwin T Tsaur (void) fprintf(stderr, "Nothing to do.\n"); 1814d5ace945SErwin T Tsaur rval = ENOTTY; 1815d5ace945SErwin T Tsaur } 1816d5ace945SErwin T Tsaur 1817d5ace945SErwin T Tsaur (void) close(fd); 1818d5ace945SErwin T Tsaur } 1819d5ace945SErwin T Tsaur 1820d5ace945SErwin T Tsaur return (rval); 1821d5ace945SErwin T Tsaur } 1822