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