dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / pcitool / pcitool.c
blob3b54d34b211d0cd04d59fbf5440cf03ca6a62c32
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
25 /* This file is the main module for the pcitool. */
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <unistd.h>
30 #include <sys/inttypes.h>
31 #include <signal.h>
32 #include <sys/types.h>
33 #include <sys/param.h>
34 #include <fcntl.h>
35 #include <strings.h>
36 #include <ctype.h>
37 #include <errno.h>
38 #include <libdevinfo.h>
39 #include <sys/sunddi.h>
41 #ifdef __x86
42 #include <sys/apic_ctlr.h>
43 #endif
45 #include <sys/pci.h>
46 #include <sys/pci_tools.h>
48 #include "pcitool_ui.h"
50 /* First 16 longs of device PCI config header. */
51 typedef union {
52 uint8_t bytes[16 * sizeof (uint32_t)];
53 uint32_t dwords[16];
54 } pci_conf_hdr_t;
56 /* Used by probe printing functions. */
57 typedef struct {
58 uint16_t cfg_offset; /* Offset of data within config space. */
59 uint8_t size; /* Size of desired data field. */
60 char *abbrev_hdr; /* Abbreviated header for this data. */
61 char *full_hdr; /* Full header for this data, verbose option. */
62 } field_type_t;
64 /* Used to package many args into one arg for probe di_node walk function. */
65 typedef struct {
66 pcitool_uiargs_t *input_args_p;
67 char *pathname;
68 di_prom_handle_t di_phdl;
69 } probe_walk_args_t;
72 * Read config space in native processor endianness. Endian-neutral
73 * processing can then take place. On big endian machines, MSB and LSB
74 * of little endian data end up switched if read as little endian.
75 * They are in correct order if read as big endian.
77 #if defined(__sparc)
78 #define NATIVE_ENDIAN PCITOOL_ACC_ATTR_ENDN_BIG
79 #elif defined(__x86)
80 #define NATIVE_ENDIAN PCITOOL_ACC_ATTR_ENDN_LTL
81 #else
82 #error "ISA is neither __sparc nor __x86"
83 #endif
85 /* status error lookup table. */
86 static struct {
87 pcitool_errno_t value;
88 char *string;
89 } pcitool_stat_str[] = {
90 { PCITOOL_SUCCESS,
91 "No error status returned from driver" },
92 { PCITOOL_INVALID_CPUID,
93 "CPU is non-existent or not online" },
94 { PCITOOL_INVALID_INO,
95 "INO is out of range or invalid" },
96 { PCITOOL_INVALID_MSI,
97 "MSI is out of range or invalid" },
98 { PCITOOL_PENDING_INTRTIMEOUT,
99 "Timeout waiting for pending interrupts to clear" },
100 { PCITOOL_REGPROP_NOTWELLFORMED,
101 "Reg property has invalid format" },
102 { PCITOOL_INVALID_ADDRESS,
103 "Address out of range or invalid" },
104 { PCITOOL_NOT_ALIGNED,
105 "Improper address alignment for access attempted" },
106 { PCITOOL_OUT_OF_RANGE,
107 "Argument out of range" },
108 { PCITOOL_END_OF_RANGE,
109 "End of address range" },
110 { PCITOOL_ROM_DISABLED,
111 "Device ROM is disabled. Cannot read" },
112 { PCITOOL_ROM_WRITE,
113 "Write to ROM not allowed" },
114 { PCITOOL_IO_ERROR,
115 "IO error encountered" },
116 { PCITOOL_INVALID_SIZE,
117 "Size is invalid for this platform" },
118 { 0, NULL }
122 /* Used with ^C handler to stop looping in repeat mode in do_device_or_nexus. */
123 static boolean_t keep_looping = B_TRUE;
125 static void signal_handler(int dummy);
126 static char *strstatus(pcitool_errno_t pcitool_status);
127 static int open_node(char *device, pcitool_uiargs_t *input_args_p);
128 static void print_probe_value(pci_conf_hdr_t *config_hdr_p, uint16_t offset,
129 uint8_t size);
130 static void print_probe_info_verbose(pci_conf_hdr_t *config_hdr_p,
131 pcitool_reg_t *info_p);
132 static void print_probe_info_nonverbose(pci_conf_hdr_t *config_hdr_p,
133 pcitool_reg_t *info_p);
134 static void print_probe_info(pci_conf_hdr_t *config_hdr_p,
135 pcitool_reg_t *info_p, boolean_t verbose);
136 static int get_config_header(int fd, uint8_t bus_no, uint8_t dev_no,
137 uint8_t func_no, pci_conf_hdr_t *config_hdr_p);
138 static int supports_ari(int fd, uint8_t bus_no);
139 static int probe_dev(int fd, pcitool_reg_t *prg_p,
140 pcitool_uiargs_t *input_args_p);
141 static int do_probe(int fd, di_node_t di_node, di_prom_handle_t di_phdl,
142 pcitool_uiargs_t *input_args_p);
143 static int process_nexus_node(di_node_t node, di_minor_t minor, void *arg);
144 static int do_probe_walk(pcitool_uiargs_t *input_args_p, char *pathname);
145 static void print_bytedump_header(boolean_t do_chardump);
146 static int bytedump_get(int fd, int cmd, pcitool_reg_t *prg_p,
147 pcitool_uiargs_t *input_args_p);
148 static uint32_t set_acc_attr(pcitool_uiargs_t *input_args_p);
149 static int do_single_access(int fd, int cmd, pcitool_reg_t *prg_p,
150 pcitool_uiargs_t *input_args_p);
151 static int do_device_or_nexus(int fd, pcitool_uiargs_t *input_args_p);
152 static void print_intr_info(pcitool_intr_get_t *iget_p);
153 static int get_single_interrupt(int fd, pcitool_intr_get_t **iget_pp,
154 pcitool_uiargs_t *input_args_p);
155 static int get_interrupts(int fd, pcitool_uiargs_t *input_args_p);
156 static int set_interrupts(int fd, pcitool_uiargs_t *input_args_p);
157 static int do_interrupts(int fd, pcitool_uiargs_t *input_args_p);
160 /* *************** General ************** */
163 * Handler for ^C to stop looping.
165 /*ARGSUSED*/
166 static void
167 signal_handler(int dummy)
169 keep_looping = B_FALSE;
174 * Print string based on PCItool status returned from driver.
176 static char *
177 strstatus(pcitool_errno_t pcitool_status)
179 int i;
181 for (i = 0; pcitool_stat_str[i].string != NULL; i++) {
182 if (pcitool_stat_str[i].value == pcitool_status) {
184 return (pcitool_stat_str[i].string);
188 return ("Unknown status returned from driver.");
192 static int
193 open_node(char *device, pcitool_uiargs_t *input_args_p)
195 int fd;
196 char *path; /* For building full nexus pathname. */
197 int stringsize; /* Device name size. */
198 char *prefix;
199 char *suffix;
200 char *format;
202 static char slash_devices[] = {"/devices"};
203 static char wcolon[] = {"%s%s:%s"};
204 static char wocolon[] = {"%s%s%s"};
206 /* Check for names starting with /devices. */
207 prefix = (strstr(device, slash_devices) == device) ? "" : slash_devices;
209 format = wcolon;
210 if (input_args_p->flags & INTR_FLAG) {
211 if (strstr(device, PCI_MINOR_INTR) ==
212 device + (strlen(device) - strlen(PCI_MINOR_INTR))) {
213 suffix = "";
214 format = wocolon;
215 } else {
216 suffix = PCI_MINOR_INTR;
218 } else {
219 if (strstr(device, PCI_MINOR_REG) ==
220 device + (strlen(device) - strlen(PCI_MINOR_REG))) {
221 suffix = "";
222 format = wocolon;
223 } else {
224 suffix = PCI_MINOR_REG;
229 * Build nexus pathname.
230 * User specified /pci@1f,700000 becomes /devices/pci@1f,700000:intr
231 * for interrupt nodes, and ...:reg for register nodes.
233 * ...The 2 at the end leaves room for a : and the terminating NULL.
235 stringsize = strlen(prefix) + strlen(device) + strlen(suffix) + 2;
236 path = malloc(stringsize);
238 /*LINTED*/
239 (void) snprintf(path, stringsize, format, prefix, device, suffix);
241 /* Open the nexus. */
242 if ((fd = open(path, O_RDWR)) == -1) {
243 if (!(IS_QUIET(input_args_p->flags))) {
244 (void) fprintf(stderr,
245 "Could not open nexus node %s: %s\n",
246 path, strerror(errno));
250 return (fd);
254 /* ****************** Probe **************** */
256 /* The following are used by the probe printing functions. */
258 /* Header 0 and 1 config space headers have these fields. */
259 static field_type_t first_fields[] = {
260 { PCI_CONF_VENID, 2, "Vend", "Vendor ID" },
261 { PCI_CONF_DEVID, 2, "Dev ", "Device ID" },
262 { PCI_CONF_COMM, 2, "Cmd ", "Command" },
263 { PCI_CONF_STAT, 2, "Stat", "Status" },
264 { PCI_CONF_REVID, 1, "Rv", "Revision ID" },
265 { PCI_CONF_PROGCLASS, 3, "Class ", "Class Code" },
266 { PCI_CONF_CACHE_LINESZ, 1, "Ca", "Cache Line Size" },
267 { PCI_CONF_LATENCY_TIMER, 1, "LT", "Latency Timer" },
268 { PCI_CONF_HEADER, 1, "Hd", "Header Type" },
269 { PCI_CONF_BIST, 1, "BI", "BIST" },
270 { 0, 0, NULL, NULL }
273 /* Header 0 (for regular devices) have these fields. */
274 static field_type_t last_dev_fields[] = {
275 { PCI_CONF_BASE0, 4, "BAR0", "Base Address Register 0 (@10)" },
276 { PCI_CONF_BASE1, 4, "BAR1", "Base Address Register 1 (@14)" },
277 { PCI_CONF_BASE2, 4, "BAR2", "Base Address Register 2 (@18)" },
278 { PCI_CONF_BASE3, 4, "BAR3", "Base Address Register 3 (@1C)" },
279 { PCI_CONF_BASE4, 4, "BAR4", "Base Address Register 4 (@20)" },
280 { PCI_CONF_BASE5, 4, "BAR5", "Base Address Register 5 (@24)" },
281 { PCI_CONF_ROM, 4, "ROM", "Expansion ROM Base Address Register (@30)" },
282 { 0, 0, NULL, NULL }
285 /* Header 1 (PCI-PCI bridge devices) have these fields. */
286 static field_type_t last_pcibrg_fields[] = {
287 { PCI_CONF_BASE0, 4, "BAR0", "Base Address Register 0 (@10)" },
288 { PCI_CONF_BASE1, 4, "BAR1", "Base Address Register 1 (@14)" },
289 { PCI_BCNF_ROM, 4, "ROM", "Expansion ROM Base Address Register (@38)" },
290 { 0, 0, NULL, NULL }
293 /* Header 2 (PCI-Cardbus bridge devices) have these fields. */
294 static field_type_t last_cbbrg_fields[] = {
295 { PCI_CBUS_SOCK_REG, 4, "SCKT", "Socket/ExCA Base Address (@10)" },
296 { 0, 0, NULL, NULL }
299 #define FMT_SIZE 7
301 static void
302 print_probe_value(pci_conf_hdr_t *config_hdr_p, uint16_t offset, uint8_t size)
305 char format[FMT_SIZE];
308 /* Size cannot be any larger than 4 bytes. This is not checked. */
309 uint32_t value = 0;
311 /* Build format of print, "%<size*2>.<size*2>x" */
312 (void) snprintf(format, FMT_SIZE, "%%%d.%dx ", size * 2, size * 2);
314 while (size-- > 0) {
315 value = (value << 8) + config_hdr_p->bytes[offset + size];
318 /*LINTED*/
319 (void) printf(format, value);
322 static void
323 print_probe_info_verbose(pci_conf_hdr_t *config_hdr_p, pcitool_reg_t *info_p)
325 field_type_t *last_fields = NULL;
326 int i;
328 (void) printf("\n"
329 "Bus Number: %x Device Number: %x Function Number: %x\n",
330 info_p->bus_no, info_p->dev_no, info_p->func_no);
331 if (info_p->phys_addr != 0) {
332 (void) printf("Physical Address: 0x%" PRIx64 " \n",
333 info_p->phys_addr);
336 switch (config_hdr_p->bytes[PCI_CONF_HEADER] & PCI_HEADER_TYPE_M) {
338 case PCI_HEADER_ZERO: /* Header type 0 is a regular device. */
339 last_fields = last_dev_fields;
340 break;
342 case PCI_HEADER_PPB: /* Header type 1 is a PCI-PCI bridge. */
343 last_fields = last_pcibrg_fields;
344 (void) printf("PCI-PCI bridge\n");
345 break;
347 case PCI_HEADER_CARDBUS: /* Header type 2 is a cardbus bridge */
348 last_fields = last_cbbrg_fields;
349 (void) printf("PCI-Cardbus bridge\n");
350 break;
352 default:
353 (void) printf("Unknown device\n");
354 break;
357 if (last_fields != NULL) {
359 for (i = 0; first_fields[i].size != 0; i++) {
360 (void) printf("%s: ", first_fields[i].full_hdr);
361 print_probe_value(config_hdr_p,
362 first_fields[i].cfg_offset, first_fields[i].size);
363 (void) putchar('\n');
366 for (i = 0; last_fields[i].size != 0; i++) {
367 (void) printf("%s: ", last_fields[i].full_hdr);
368 print_probe_value(config_hdr_p,
369 last_fields[i].cfg_offset, last_fields[i].size);
370 (void) putchar('\n');
375 static void
376 print_probe_info_nonverbose(pci_conf_hdr_t *config_hdr_p, pcitool_reg_t *info_p)
378 int i;
380 (void) printf("%2.2x %2.2x %1.1x ",
381 info_p->bus_no, info_p->dev_no, info_p->func_no);
382 for (i = 0; first_fields[i].size != 0; i++) {
383 print_probe_value(config_hdr_p,
384 first_fields[i].cfg_offset, first_fields[i].size);
386 (void) putchar('\n');
391 * Print device information retrieved during probe mode.
392 * Takes the PCI config header, plus address information retrieved from the
393 * driver.
395 * When called with config_hdr_p == NULL, this function just prints a header
396 * when not in verbose mode.
399 static void
400 print_probe_info(
401 pci_conf_hdr_t *config_hdr_p, pcitool_reg_t *info_p, boolean_t verbose)
403 int i;
405 /* Print header if not in verbose mode. */
406 if (config_hdr_p == NULL) {
407 if (!verbose) {
409 /* Bus dev func not from tble */
410 (void) printf("B D F ");
412 for (i = 0; first_fields[i].size != 0; i++) {
413 (void) printf("%s ",
414 first_fields[i].abbrev_hdr);
416 (void) putchar('\n');
419 return;
422 if (verbose) {
423 print_probe_info_verbose(config_hdr_p, info_p);
424 } else {
425 print_probe_info_nonverbose(config_hdr_p, info_p);
431 * Retrieve first 16 dwords of device's config header, except for the first
432 * dword. First 16 dwords are defined by the PCI specification.
434 static int
435 get_config_header(int fd, uint8_t bus_no, uint8_t dev_no, uint8_t func_no,
436 pci_conf_hdr_t *config_hdr_p)
438 pcitool_reg_t cfg_prg;
439 int i;
440 int rval = SUCCESS;
442 /* Prepare a local pcitool_reg_t so as to not disturb the caller's. */
443 cfg_prg.offset = 0;
444 cfg_prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_4 + NATIVE_ENDIAN;
445 cfg_prg.bus_no = bus_no;
446 cfg_prg.dev_no = dev_no;
447 cfg_prg.func_no = func_no;
448 cfg_prg.barnum = 0;
449 cfg_prg.user_version = PCITOOL_VERSION;
451 /* Get dwords 1-15 of config space. They must be read as uint32_t. */
452 for (i = 1; i < (sizeof (pci_conf_hdr_t) / sizeof (uint32_t)); i++) {
453 cfg_prg.offset += sizeof (uint32_t);
454 if ((rval =
455 ioctl(fd, PCITOOL_DEVICE_GET_REG, &cfg_prg)) != SUCCESS) {
456 break;
458 config_hdr_p->dwords[i] = (uint32_t)cfg_prg.data;
460 return (rval);
463 static int
464 supports_ari(int fd, uint8_t bus_no)
466 pcitool_reg_t cfg_prg;
467 int deadcount = 0;
468 uint32_t data, hdr_next_ptr, hdr_cap_id;
469 uint8_t dev_no = 0;
470 uint8_t func_no = 0;
472 /* Prepare a local pcitool_reg_t so as to not disturb the caller's. */
473 cfg_prg.bus_no = bus_no;
474 cfg_prg.dev_no = dev_no;
475 cfg_prg.func_no = func_no;
476 cfg_prg.barnum = 0;
477 cfg_prg.user_version = PCITOOL_VERSION;
478 cfg_prg.offset = 0;
479 cfg_prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_4 + PCITOOL_ACC_ATTR_ENDN_LTL;
481 if (ioctl(fd, PCITOOL_DEVICE_GET_REG, &cfg_prg) != SUCCESS) {
482 return (FAILURE);
485 data = (uint32_t)cfg_prg.data;
486 if (data == (uint32_t)(-1))
487 return (FAILURE);
489 cfg_prg.offset = PCI_CONF_COMM;
490 if (ioctl(fd, PCITOOL_DEVICE_GET_REG, &cfg_prg) != SUCCESS) {
491 return (FAILURE);
494 data = (uint32_t)cfg_prg.data;
495 if (!((data >> 16) & PCI_STAT_CAP))
496 return (FAILURE);
498 cfg_prg.offset = PCI_CONF_CAP_PTR;
499 if (ioctl(fd, PCITOOL_DEVICE_GET_REG, &cfg_prg) != SUCCESS) {
500 return (FAILURE);
502 data = (uint32_t)cfg_prg.data;
503 hdr_next_ptr = data & 0xff;
504 hdr_cap_id = 0;
507 * Find the PCIe capability.
509 while ((hdr_next_ptr != PCI_CAP_NEXT_PTR_NULL) &&
510 (hdr_cap_id != PCI_CAP_ID_PCI_E)) {
512 if (hdr_next_ptr < 0x40)
513 break;
515 cfg_prg.offset = hdr_next_ptr;
517 if (ioctl(fd, PCITOOL_DEVICE_GET_REG, &cfg_prg) != SUCCESS)
518 return (FAILURE);
520 data = (uint32_t)cfg_prg.data;
522 hdr_next_ptr = (data >> 8) & 0xFF;
523 hdr_cap_id = data & 0xFF;
525 if (deadcount++ > 100)
526 return (FAILURE);
529 if (hdr_cap_id != PCI_CAP_ID_PCI_E)
530 return (FAILURE);
532 /* Found a PCIe Capability */
534 hdr_next_ptr = 0x100;
535 hdr_cap_id = 0;
538 * Now find the ARI Capability.
540 while ((hdr_next_ptr != PCI_CAP_NEXT_PTR_NULL) &&
541 (hdr_cap_id != 0xe)) {
543 if (hdr_next_ptr < 0x40)
544 break;
546 cfg_prg.offset = hdr_next_ptr;
548 if (ioctl(fd, PCITOOL_DEVICE_GET_REG, &cfg_prg) != SUCCESS) {
549 return (FAILURE);
551 data = (uint32_t)cfg_prg.data;
553 hdr_next_ptr = (data >> 20) & 0xFFF;
554 hdr_cap_id = data & 0xFFFF;
556 if (deadcount++ > 100)
557 return (FAILURE);
560 if (hdr_cap_id != 0xe)
561 return (FAILURE);
563 return (SUCCESS);
567 * Identify problematic southbridges. These have device id 0x5249 and
568 * vendor id 0x10b9. Check for revision ID 0 and class code 060400 as well.
569 * Values are little endian, so they are reversed for SPARC.
571 * Check for these southbridges on all architectures, as the issue is a
572 * southbridge issue, independent of processor.
574 * If one of these is found during probing, skip probing other devs/funcs on
575 * the rest of the bus, since the southbridge and all devs underneath will
576 * otherwise disappear.
578 #if (NATIVE_ENDIAN == PCITOOL_ACC_ATTR_ENDN_BIG)
579 #define U45_SB_DEVID_VID 0xb9104952
580 #define U45_SB_CLASS_RID 0x00000406
581 #else
582 #define U45_SB_DEVID_VID 0x524910b9
583 #define U45_SB_CLASS_RID 0x06040000
584 #endif
587 * Probe device's functions. Modifies many fields in the prg_p.
589 static int
590 probe_dev(int fd, pcitool_reg_t *prg_p, pcitool_uiargs_t *input_args_p)
592 pci_conf_hdr_t config_hdr;
593 boolean_t multi_function_device = B_FALSE;
594 int func;
595 int first_func = 0;
596 int last_func = PCI_REG_FUNC_M >> PCI_REG_FUNC_SHIFT;
597 int rval = SUCCESS;
599 if (input_args_p->flags & FUNC_SPEC_FLAG) {
600 first_func = last_func = input_args_p->function;
601 } else if (supports_ari(fd, prg_p->bus_no) == SUCCESS) {
602 multi_function_device = B_TRUE;
603 if (!(input_args_p->flags & DEV_SPEC_FLAG))
604 last_func = 255;
608 * Loop through at least func=first_func. Continue looping through
609 * functions if there are no errors and the device is a multi-function
610 * device.
612 * (Note, if first_func == 0, header will show whether multifunction
613 * device and set multi_function_device. If first_func != 0, then we
614 * will force the loop as the user wants a specific function to be
615 * checked.
617 for (func = first_func; ((func <= last_func) &&
618 ((func == first_func) || (multi_function_device)));
619 func++) {
620 if (last_func > 7) {
621 prg_p->func_no = func & 0x7;
622 prg_p->dev_no = (func >> 3) & 0x1f;
623 } else
624 prg_p->func_no = func;
627 * Four things can happen here:
629 * 1) ioctl comes back as EFAULT and prg_p->status is
630 * PCITOOL_INVALID_ADDRESS. There is no device at this
631 * location.
633 * 2) ioctl comes back successful and the data comes back as
634 * zero. Config space is mapped but no device responded.
636 * 3) ioctl comes back successful and the data comes back as
637 * non-zero. We've found a device.
639 * 4) Some other error occurs in an ioctl.
642 prg_p->status = PCITOOL_SUCCESS;
643 prg_p->offset = 0;
644 prg_p->data = 0;
645 prg_p->user_version = PCITOOL_VERSION;
646 if (((rval = ioctl(fd, PCITOOL_DEVICE_GET_REG, prg_p)) != 0) ||
647 (prg_p->data == 0xffffffff)) {
650 * Accept errno == EINVAL along with status of
651 * PCITOOL_OUT_OF_RANGE because some systems
652 * don't implement the full range of config space.
653 * Leave the loop quietly in this case.
655 if ((errno == EINVAL) ||
656 (prg_p->status == PCITOOL_OUT_OF_RANGE)) {
657 break;
661 * Exit silently with ENXIO as this means that there are
662 * no devices under the pci root nexus.
664 else if ((errno == ENXIO) &&
665 (prg_p->status == PCITOOL_IO_ERROR)) {
666 break;
670 * Expect errno == EFAULT along with status of
671 * PCITOOL_INVALID_ADDRESS because there won't be
672 * devices at each stop. Quit on any other error.
674 else if (((errno != EFAULT) ||
675 (prg_p->status != PCITOOL_INVALID_ADDRESS)) &&
676 (prg_p->data != 0xffffffff)) {
678 if (!(IS_QUIET(input_args_p->flags))) {
679 (void) fprintf(stderr,
680 "Ioctl error: %s\n",
681 strerror(errno));
683 break;
686 * If no function at this location,
687 * just advance to the next function.
689 } else {
690 rval = SUCCESS;
694 * Data came back as 0.
695 * Treat as unresponsive device amd check next device.
697 } else if (prg_p->data == 0) {
698 rval = SUCCESS;
699 /* Found something. */
700 } else {
701 config_hdr.dwords[0] = (uint32_t)prg_p->data;
703 /* Get the rest of the PCI header. */
704 if ((rval = get_config_header(fd, prg_p->bus_no,
705 prg_p->dev_no, prg_p->func_no, &config_hdr)) !=
706 SUCCESS) {
707 break;
710 /* Print the found information. */
711 print_probe_info(&config_hdr, prg_p,
712 IS_VERBOSE(input_args_p->flags));
715 * Special case for the type of Southbridge found on
716 * Ultra-45 and other sun4u fire workstations.
718 if ((config_hdr.dwords[0] == U45_SB_DEVID_VID) &&
719 (config_hdr.dwords[2] == U45_SB_CLASS_RID)) {
720 rval = ECANCELED;
721 break;
725 * Accomodate devices which state their
726 * multi-functionality only in their function 0 config
727 * space. Note multi-functionality throughout probing
728 * of all of this device's functions.
730 if (config_hdr.bytes[PCI_CONF_HEADER] &
731 PCI_HEADER_MULTI) {
732 multi_function_device = B_TRUE;
737 return (rval);
742 * Probe a given nexus config space for devices.
744 * fd is the file descriptor of the nexus.
745 * input_args contains commandline options as specified by the user.
747 static int
748 do_probe(int fd, di_node_t di_node, di_prom_handle_t di_phdl,
749 pcitool_uiargs_t *input_args_p)
751 pcitool_reg_t prg;
752 int bus;
753 int dev;
754 int last_bus = PCI_REG_BUS_M >> PCI_REG_BUS_SHIFT;
755 int last_dev = PCI_REG_DEV_M >> PCI_REG_DEV_SHIFT;
756 int first_bus = 0;
757 int first_dev = 0;
758 int rval = SUCCESS;
760 prg.barnum = 0; /* Config space. */
762 /* Must read in 4-byte quantities. */
763 prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_4 + NATIVE_ENDIAN;
765 prg.data = 0;
767 /* If an explicit bus was specified by the user, go with it. */
768 if (input_args_p->flags & BUS_SPEC_FLAG) {
769 first_bus = last_bus = input_args_p->bus;
771 } else if (input_args_p->flags & PROBERNG_FLAG) {
772 /* Otherwise get the bus range from properties. */
773 int len;
774 uint32_t *rangebuf = NULL;
776 len = di_prop_lookup_ints(DDI_DEV_T_ANY, di_node,
777 "bus-range", (int **)&rangebuf);
779 /* Try PROM property */
780 if (len <= 0) {
781 len = di_prom_prop_lookup_ints(di_phdl, di_node,
782 "bus-range", (int **)&rangebuf);
785 /* Take full range for default if cannot get property. */
786 if (len > 0) {
787 first_bus = rangebuf[0];
788 last_bus = rangebuf[1];
792 /* Take full range for default if not PROBERNG and not BUS_SPEC. */
794 if (last_bus == first_bus) {
795 if (input_args_p->flags & DEV_SPEC_FLAG) {
796 /* Explicit device given. Not probing a whole bus. */
797 (void) puts("");
798 } else {
799 (void) printf("*********** Probing bus %x "
800 "***********\n\n", first_bus);
802 } else {
803 (void) printf("*********** Probing buses %x through %x "
804 "***********\n\n", first_bus, last_bus);
807 /* Print header. */
808 print_probe_info(NULL, NULL, IS_VERBOSE(input_args_p->flags));
810 /* Device number explicitly specified. */
811 if (input_args_p->flags & DEV_SPEC_FLAG) {
812 first_dev = last_dev = input_args_p->device;
816 * Loop through all valid bus / dev / func combinations to check for
817 * all devices, with the following exceptions:
819 * When nothing is found at function 0 of a bus / dev combination, skip
820 * the other functions of that bus / dev combination.
822 * When a found device's function 0 is probed and it is determined that
823 * it is not a multifunction device, skip probing of that device's
824 * other functions.
826 for (bus = first_bus; ((bus <= last_bus) && (rval == SUCCESS)); bus++) {
827 prg.bus_no = bus;
829 /* Device number explicitly specified. */
830 if (input_args_p->flags & DEV_SPEC_FLAG) {
831 first_dev = last_dev = input_args_p->device;
832 } else if (supports_ari(fd, bus) == SUCCESS) {
833 last_dev = 0;
834 first_dev = 0;
835 } else {
836 last_dev = PCI_REG_DEV_M >> PCI_REG_DEV_SHIFT;
839 for (dev = first_dev;
840 ((dev <= last_dev) && (rval == SUCCESS)); dev++) {
841 prg.dev_no = dev;
842 rval = probe_dev(fd, &prg, input_args_p);
846 * Ultra-45 southbridge workaround:
847 * ECANCELED tells to skip to the next bus.
849 if (rval == ECANCELED) {
850 rval = SUCCESS;
854 return (rval);
858 * This function is called-back from di_walk_minor() when any PROBE is processed
860 /*ARGSUSED*/
861 static int
862 process_nexus_node(di_node_t di_node, di_minor_t minor, void *arg)
864 int fd;
865 char *trunc;
866 probe_walk_args_t *walk_args_p = (probe_walk_args_t *)arg;
867 char *pathname = walk_args_p->pathname;
868 char *nexus_path = di_devfs_minor_path(minor);
870 if (nexus_path == NULL) {
871 (void) fprintf(stderr, "Error getting nexus path: %s\n",
872 strerror(errno));
873 return (DI_WALK_CONTINUE);
877 * Display this node if pathname not specified (as all nodes are
878 * displayed) or if the current node matches the single specified
879 * pathname. Pathname form: xxx, nexus form: xxx:reg
881 if ((pathname != NULL) &&
882 ((strstr(nexus_path, pathname) != nexus_path) ||
883 (strlen(nexus_path) !=
884 (strlen(pathname) + strlen(PCI_MINOR_REG) + 1)))) {
885 di_devfs_path_free(nexus_path);
886 return (DI_WALK_CONTINUE);
889 if ((fd = open_node(nexus_path, walk_args_p->input_args_p)) >= 0) {
891 /* Strip off the suffix at the end of the nexus path. */
892 if ((trunc = strstr(nexus_path, PCI_MINOR_REG)) != NULL) {
893 trunc--; /* Get the : just before too. */
894 *trunc = '\0';
897 /* Show header only if no explicit nexus node name given. */
898 (void) puts("");
899 if (pathname == NULL) {
900 (void) printf("********** Devices in tree under %s "
901 "**********\n", nexus_path);
905 * Exit silently with ENXIO as this means that there are
906 * no devices under the pci root nexus.
908 if ((do_probe(fd, di_node, walk_args_p->di_phdl,
909 walk_args_p->input_args_p) != SUCCESS) &&
910 (errno != ENXIO)) {
911 (void) fprintf(stderr, "Error probing node %s: %s\n",
912 nexus_path, strerror(errno));
915 (void) close(fd);
917 di_devfs_path_free(nexus_path);
920 * If node was explicitly specified, it has just been displayed
921 * and no more looping is required.
922 * Otherwise, keep looping for more nodes.
924 return ((pathname == NULL) ? DI_WALK_CONTINUE : DI_WALK_TERMINATE);
929 * Start of probe. If pathname is NULL, search all devices.
931 * di_walk_minor() walks all DDI_NT_REGACC (PCItool register access) nodes
932 * and calls process_nexus_node on them. process_nexus_node will then check
933 * the pathname for a match, unless it is NULL which works like a wildcard.
935 static int
936 do_probe_walk(pcitool_uiargs_t *input_args_p, char *pathname)
938 di_node_t di_node;
939 di_prom_handle_t di_phdl = DI_PROM_HANDLE_NIL;
940 probe_walk_args_t walk_args;
942 int rval = SUCCESS;
944 if ((di_node = di_init("/", DINFOCPYALL)) == DI_NODE_NIL) {
945 (void) fprintf(stderr, "di_init() failed: %s\n",
946 strerror(errno));
947 rval = errno;
949 } else if ((input_args_p->flags & PROBERNG_FLAG) &&
950 ((di_phdl = di_prom_init()) == DI_PROM_HANDLE_NIL)) {
951 (void) fprintf(stderr, "di_prom_init failed: %s\n",
952 strerror(errno));
953 rval = errno;
955 } else {
956 walk_args.input_args_p = input_args_p;
957 walk_args.di_phdl = di_phdl;
958 walk_args.pathname = pathname;
959 (void) di_walk_minor(di_node, DDI_NT_REGACC, 0,
960 &walk_args, process_nexus_node);
963 if (di_phdl != DI_PROM_HANDLE_NIL) {
964 di_prom_fini(di_phdl);
967 if (di_node != DI_NODE_NIL) {
968 di_fini(di_node);
971 return (rval);
975 /* **************** Byte dump specific **************** */
977 static void
978 print_bytedump_header(boolean_t do_chardump)
980 static char header1[] = {" "
981 "0F 0E 0D 0C 0B 0A 09 08 07 06 05 04 03 02 01 00"};
982 static char header2[] = {" "
983 "-----------------------------------------------"};
984 static char cheader1[] = {" 0123456789ABCDEF"};
985 static char cheader2[] = {" ----------------"};
987 (void) puts("");
988 (void) printf(header1);
989 if (do_chardump) {
990 (void) printf(cheader1);
992 (void) puts("");
993 (void) printf(header2);
994 if (do_chardump) {
995 (void) printf(cheader2);
1000 /* Number of bytes per line in a dump. */
1001 #define DUMP_BUF_SIZE 16
1002 #define LINES_BTWN_HEADER 16
1005 * Retrieve several bytes over several reads, and print a formatted byte-dump
1007 * fd is the nexus by which device is accessed.
1008 * prg provided has bus, dev, func, bank, initial offset already specified,
1009 * as well as size and endian attributes.
1011 * No checking is made that this is a read operation, although only read
1012 * operations are allowed.
1014 static int
1015 bytedump_get(int fd, int cmd, pcitool_reg_t *prg_p,
1016 pcitool_uiargs_t *input_args_p)
1018 typedef union {
1019 uint8_t bytes[DUMP_BUF_SIZE];
1020 uint16_t shorts[DUMP_BUF_SIZE / sizeof (uint16_t)];
1021 uint32_t dwords[DUMP_BUF_SIZE / sizeof (uint32_t)];
1022 uint64_t longs[DUMP_BUF_SIZE / sizeof (uint64_t)];
1023 } buffer_t;
1026 * Local copy of pcitool_reg_t, since offset and phys_addrs are
1027 * modified.
1029 pcitool_reg_t local_prg;
1031 /* Loop parameters. */
1032 uint32_t dump_end = prg_p->offset + input_args_p->bytedump_amt;
1033 uint32_t dump_curr = prg_p->offset;
1035 int read_size = input_args_p->size;
1037 /* How many stores to the buffer before it is full. */
1038 int wrap_size = DUMP_BUF_SIZE / read_size;
1040 /* Address prints at the beginning of each line. */
1041 uint64_t print_addr = 0;
1043 /* Skip this num bytes at the beginning of the first dump. */
1044 int skip_begin;
1046 /* Skip this num bytes at the end of the last dump. */
1047 int skip_end = 0;
1049 /* skip_begin and skip_end are needed twice. */
1050 int skip_begin2;
1051 int skip_end2;
1053 /* Number of lines between headers */
1054 int lines_since_header = 0;
1056 boolean_t do_chardump = input_args_p->flags & CHARDUMP_FLAG;
1057 boolean_t continue_on_errs = input_args_p->flags & ERRCONT_FLAG;
1059 int rval = SUCCESS; /* Return status. */
1061 int next;
1062 int i;
1064 buffer_t buffer;
1065 uint16_t error_mask = 0; /* 1 bit/byte in buf. Err when set */
1067 bzero(buffer.bytes, sizeof (uint8_t) * DUMP_BUF_SIZE);
1069 local_prg = *prg_p; /* Make local copy. */
1072 * Flip the bytes to proper order if reading on a big endian machine.
1073 * Do this by reading big as little and vs.
1075 #if (NATIVE_ENDIAN == PCITOOL_ACC_ATTR_ENDN_BIG)
1076 local_prg.acc_attr =
1077 (PCITOOL_ACC_IS_BIG_ENDIAN(local_prg.acc_attr) ?
1078 (local_prg.acc_attr & ~PCITOOL_ACC_ATTR_ENDN_BIG) :
1079 (local_prg.acc_attr | PCITOOL_ACC_ATTR_ENDN_BIG));
1080 #endif
1083 * Get offset into buffer for first store. Assumes the buffer size is
1084 * a multiple of the read size. "next" is the next buffer index to do
1085 * a store.
1087 skip_begin = local_prg.offset % DUMP_BUF_SIZE;
1088 next = skip_begin / read_size;
1090 print_bytedump_header(do_chardump);
1092 while (dump_curr < dump_end) {
1094 /* For reading from the next location. */
1095 local_prg.offset = dump_curr;
1097 /* Access the device. Abort on error. */
1098 if (((rval = ioctl(fd, cmd, &local_prg)) != SUCCESS) &&
1099 (!(continue_on_errs))) {
1100 if (!(IS_QUIET(input_args_p->flags))) {
1101 (void) fprintf(stderr,
1102 "Ioctl failed:\n errno: %s\n status: %s\n",
1103 strerror(errno),
1104 strstatus(local_prg.status));
1106 break;
1110 * Initialize print_addr first time through, in case printing
1111 * is starting in the middle of the buffer. Also reinitialize
1112 * when wrap.
1114 if (print_addr == 0) {
1117 * X86 config space doesn't return phys addr.
1118 * Use offset instead in this case.
1120 if (local_prg.phys_addr == 0) { /* No phys addr ret */
1121 print_addr = local_prg.offset -
1122 (local_prg.offset % DUMP_BUF_SIZE);
1123 } else {
1124 print_addr = local_prg.phys_addr -
1125 (local_prg.phys_addr % DUMP_BUF_SIZE);
1130 * Read error occurred.
1131 * Shift the right number of error bits ((1 << read_size) - 1)
1132 * into the right place (next * read_size)
1134 if (rval != SUCCESS) { /* Read error occurred */
1135 error_mask |=
1136 ((1 << read_size) - 1) << (next * read_size);
1138 } else { /* Save data to the buffer. */
1140 switch (read_size) {
1141 case 1:
1142 buffer.bytes[next] = (uint8_t)local_prg.data;
1143 break;
1144 case 2:
1145 buffer.shorts[next] = (uint16_t)local_prg.data;
1146 break;
1147 case 4:
1148 buffer.dwords[next] = (uint32_t)local_prg.data;
1149 break;
1150 case 8:
1151 buffer.longs[next] = (uint64_t)local_prg.data;
1152 break;
1153 default:
1154 rval = EIO;
1155 break;
1158 next++;
1160 /* Increment index for next store, and wrap. */
1161 next %= wrap_size;
1162 dump_curr += read_size;
1164 /* Zero out the remainder of the buffer if done. */
1165 if (dump_curr >= dump_end) {
1166 if (next != 0) {
1167 bzero(&buffer.bytes[next * read_size],
1168 (wrap_size - next) * read_size);
1169 skip_end = (wrap_size - next) * read_size;
1170 next = 0; /* For printing below. */
1174 /* Dump the buffer if full or if done. */
1175 if (next == 0) {
1177 skip_begin2 = skip_begin;
1178 skip_end2 = skip_end;
1180 (void) printf("\n0x%16.16" PRIx64 ":", print_addr);
1181 for (i = DUMP_BUF_SIZE - 1; i >= 0; i--) {
1182 if (skip_end) {
1183 skip_end--;
1184 (void) printf(" --");
1185 } else if (skip_begin > i) {
1186 skip_begin--;
1187 (void) printf(" --");
1188 } else if (error_mask & (1 << i)) {
1189 (void) printf(" XX");
1190 } else {
1191 (void) printf(" %2.2x",
1192 buffer.bytes[i]);
1196 if (do_chardump) {
1197 (void) putchar(' ');
1198 for (i = 0; i < DUMP_BUF_SIZE; i++) {
1199 if (skip_begin2) {
1200 skip_begin2--;
1201 (void) printf("-");
1202 } else if (
1203 (DUMP_BUF_SIZE - skip_end2) <= i) {
1204 (void) printf("-");
1205 } else if (error_mask & (1 << i)) {
1206 (void) putchar('X');
1207 } else if (isprint(buffer.bytes[i])) {
1208 (void) putchar(buffer.bytes[i]);
1209 } else {
1210 (void) putchar('@');
1215 if ((++lines_since_header == LINES_BTWN_HEADER) &&
1216 (dump_curr < dump_end)) {
1217 lines_since_header = 0;
1218 (void) puts("");
1219 print_bytedump_header(do_chardump);
1222 print_addr += DUMP_BUF_SIZE;
1223 error_mask = 0;
1226 (void) printf("\n");
1228 return (rval);
1232 /* ************** Device and nexus access commands ************** */
1235 * Helper function to set access attributes. Assumes size is valid.
1237 static uint32_t
1238 set_acc_attr(pcitool_uiargs_t *input_args_p)
1240 uint32_t access_attrs;
1242 switch (input_args_p->size) {
1243 case 1:
1244 access_attrs = PCITOOL_ACC_ATTR_SIZE_1;
1245 break;
1246 case 2:
1247 access_attrs = PCITOOL_ACC_ATTR_SIZE_2;
1248 break;
1249 case 4:
1250 access_attrs = PCITOOL_ACC_ATTR_SIZE_4;
1251 break;
1252 case 8:
1253 access_attrs = PCITOOL_ACC_ATTR_SIZE_8;
1254 break;
1257 if (input_args_p->big_endian) {
1258 access_attrs |= PCITOOL_ACC_ATTR_ENDN_BIG;
1261 return (access_attrs);
1264 static int
1265 do_single_access(int fd, int cmd, pcitool_reg_t *prg_p,
1266 pcitool_uiargs_t *input_args_p)
1268 boolean_t is_write = B_FALSE;
1269 int rval;
1271 switch (cmd) {
1272 case PCITOOL_NEXUS_SET_REG:
1273 case PCITOOL_DEVICE_SET_REG:
1274 is_write = B_TRUE;
1275 break;
1276 default:
1277 break;
1280 /* Do the access. Return on error. */
1281 if ((rval = ioctl(fd, cmd, prg_p)) != SUCCESS) {
1282 if (!(IS_QUIET(input_args_p->flags))) {
1283 (void) fprintf(stderr,
1284 "%s ioctl failed:\n errno: %s\n status: %s\n",
1285 is_write ? "write" : "read",
1286 strerror(errno), strstatus(prg_p->status));
1289 return (rval);
1292 /* Print on all verbose requests. */
1293 if (IS_VERBOSE(input_args_p->flags)) {
1296 * Return offset on platforms which return phys_addr == 0
1297 * for config space.
1299 if (prg_p->phys_addr == 0)
1300 prg_p->phys_addr = input_args_p->offset;
1302 (void) printf("Addr:0x%" PRIx64 ", %d-byte %s endian "
1303 "register value: 0x%" PRIx64 "\n",
1304 prg_p->phys_addr, input_args_p->size,
1305 (input_args_p->big_endian ? "big" : "little"), prg_p->data);
1307 /* Non-verbose, read requests. */
1308 } else if (!(is_write)) {
1309 (void) printf("0x%" PRIx64 "\n", prg_p->data);
1312 return (rval);
1317 * fd is the file descriptor of the nexus to access, either to get its
1318 * registers or to access a device through that nexus.
1320 * input args are commandline arguments specified by the user.
1322 static int
1323 do_device_or_nexus(int fd, pcitool_uiargs_t *input_args_p)
1325 pcitool_reg_t prg; /* Request details given to the driver. */
1326 uint32_t write_cmd = 0; /* Command given to the driver. */
1327 uint32_t read_cmd = 0; /* Command given to the driver. */
1328 int rval = SUCCESS; /* Return status. */
1330 if (input_args_p->flags & WRITE_FLAG) {
1331 prg.data = input_args_p->write_value;
1332 if (input_args_p->flags & NEXUS_FLAG) {
1333 write_cmd = PCITOOL_NEXUS_SET_REG;
1334 } else {
1335 write_cmd = PCITOOL_DEVICE_SET_REG;
1338 if (input_args_p->flags & READ_FLAG) {
1339 if (input_args_p->flags & NEXUS_FLAG) {
1340 read_cmd = PCITOOL_NEXUS_GET_REG;
1341 } else {
1342 read_cmd = PCITOOL_DEVICE_GET_REG;
1346 /* Finish initializing access details for driver. */
1349 * For nexus, barnum is the exact bank number, unless it is 0xFF, which
1350 * indicates that it is inactive and a base_address should be read from
1351 * the input_args instead.
1353 * For devices, barnum is the offset to the desired BAR, or 0 for
1354 * config space.
1356 if ((input_args_p->flags & (BASE_SPEC_FLAG | NEXUS_FLAG)) ==
1357 (BASE_SPEC_FLAG | NEXUS_FLAG)) {
1358 prg.barnum = PCITOOL_BASE;
1359 prg.phys_addr = input_args_p->base_address;
1360 } else
1361 prg.barnum = input_args_p->bank;
1363 prg.offset = input_args_p->offset;
1364 prg.acc_attr = set_acc_attr(input_args_p);
1365 prg.bus_no = input_args_p->bus;
1366 prg.dev_no = input_args_p->device;
1367 prg.func_no = input_args_p->function;
1368 prg.user_version = PCITOOL_VERSION;
1370 do {
1371 /* Do a bytedump if desired, or else do single ioctl access. */
1372 if (input_args_p->flags & BYTEDUMP_FLAG) {
1374 if (IS_VERBOSE(input_args_p->flags)) {
1375 (void) printf(
1376 "\nDoing %d-byte %s endian reads:",
1377 input_args_p->size,
1378 input_args_p->big_endian ?
1379 "big" : "little");
1381 rval = bytedump_get(fd, read_cmd, &prg, input_args_p);
1383 } else {
1385 /* Single write and/or read. */
1386 if (write_cmd != 0) {
1387 rval = do_single_access(
1388 fd, write_cmd, &prg, input_args_p);
1391 if ((rval == SUCCESS) && (read_cmd != 0)) {
1392 rval = do_single_access(
1393 fd, read_cmd, &prg, input_args_p);
1396 } while ((IS_LOOP(input_args_p->flags)) && (rval == SUCCESS) &&
1397 (keep_looping));
1399 return (rval != SUCCESS ? errno : SUCCESS);
1402 /* *************** Interrupt routing ************** */
1405 * Display interrupt information.
1406 * iget is filled in with the info to display
1408 static void
1409 print_intr_info(pcitool_intr_get_t *iget_p)
1411 int i;
1413 for (i = 0; i < iget_p->num_devs; i++) {
1414 if (iget_p->flags & PCITOOL_INTR_FLAG_GET_MSI)
1415 (void) printf("0x%x,0x%x: %-10s%d\t %s\n",
1416 iget_p->cpu_id, iget_p->msi & 0xff,
1417 iget_p->dev[i].driver_name, iget_p->dev[i].dev_inst,
1418 iget_p->dev[i].path);
1419 else
1420 (void) printf("0x%x,0x%x: %-10s%d\t %s\n",
1421 iget_p->cpu_id, iget_p->ino & 0xff,
1422 iget_p->dev[i].driver_name, iget_p->dev[i].dev_inst,
1423 iget_p->dev[i].path);
1429 * Interrupt command support.
1431 * fd is the file descriptor of the nexus being probed.
1432 * input_args are commandline options entered by the user.
1434 static int
1435 get_single_interrupt(int fd, pcitool_intr_get_t **iget_pp,
1436 pcitool_uiargs_t *input_args_p)
1438 pcitool_intr_get_t *iget_p = *iget_pp;
1439 const char *str_type = NULL;
1440 uint32_t intr;
1442 if (input_args_p->flags & MSI_SPEC_FLAG) {
1443 intr = input_args_p->intr_msi;
1444 str_type = "msi";
1445 } else {
1446 intr = input_args_p->intr_ino;
1447 str_type = "ino";
1451 * Check if interrupts are active on this ino/msi. Get as much
1452 * device info as there is room for at the moment. If there
1453 * is not enough room for all devices, will call again with a
1454 * larger buffer.
1456 if (ioctl(fd, PCITOOL_DEVICE_GET_INTR, iget_p) != 0) {
1458 * Let EIO errors silently slip through, as
1459 * some inos may not be viewable by design.
1460 * We don't want to stop or print an error for these.
1462 if (errno == EIO) {
1463 return (SUCCESS);
1466 if (!(IS_QUIET(input_args_p->flags))) {
1467 (void) fprintf(stderr, "Ioctl to get %s 0x%x "
1468 "info failed: %s\n", str_type, intr,
1469 strerror(errno));
1471 if (errno != EFAULT) {
1472 (void) fprintf(stderr, "Pcitool status: %s\n",
1473 strstatus(iget_p->status));
1476 return (errno);
1479 /* Nothing to report for this interrupt. */
1480 if (iget_p->num_devs == 0) {
1481 return (SUCCESS);
1484 /* Need more room to return additional device info. */
1485 if (iget_p->num_devs_ret < iget_p->num_devs) {
1486 iget_p = *iget_pp =
1487 realloc(iget_p, PCITOOL_IGET_SIZE(iget_p->num_devs));
1488 iget_p->num_devs_ret = iget_p->num_devs;
1490 if (ioctl(fd, PCITOOL_DEVICE_GET_INTR, iget_p) != 0) {
1491 if (!(IS_QUIET(input_args_p->flags))) {
1492 (void) fprintf(stderr, "Ioctl to get %s 0x%x"
1493 "device info failed: %s\n", str_type,
1494 intr, strerror(errno));
1495 if (errno != EFAULT) {
1496 (void) fprintf(stderr,
1497 "Pcitool status: %s\n",
1498 strstatus(iget_p->status));
1501 return (errno);
1505 print_intr_info(iget_p);
1506 return (SUCCESS);
1509 #define INIT_NUM_DEVS 0
1511 static int
1512 get_interrupts(int fd, pcitool_uiargs_t *input_args_p)
1514 int rval = SUCCESS; /* Return status. */
1515 int ino, cpu_id;
1518 * Start with a struct with space for info of INIT_NUM_DEVS devs
1519 * to be returned.
1521 pcitool_intr_get_t *iget_p = malloc(PCITOOL_IGET_SIZE(INIT_NUM_DEVS));
1523 iget_p->num_devs_ret = INIT_NUM_DEVS;
1524 iget_p->user_version = PCITOOL_VERSION;
1526 /* Explicit MSI requested. */
1527 if (input_args_p->flags & MSI_SPEC_FLAG) {
1528 iget_p->msi = input_args_p->intr_msi;
1529 iget_p->flags = PCITOOL_INTR_FLAG_GET_MSI;
1530 rval = get_single_interrupt(fd, &iget_p, input_args_p);
1531 /* Return all MSIs. */
1532 } else if (input_args_p->flags & MSI_ALL_FLAG) {
1533 pcitool_intr_info_t intr_info;
1534 intr_info.flags = PCITOOL_INTR_FLAG_GET_MSI;
1536 if (ioctl(fd, PCITOOL_SYSTEM_INTR_INFO, &intr_info) != 0) {
1537 if (!(IS_QUIET(input_args_p->flags))) {
1538 (void) fprintf(stderr,
1539 "intr info ioctl failed: %s\n",
1540 strerror(errno));
1542 } else {
1543 int msi;
1546 * Search through all interrupts.
1547 * Display info on enabled ones.
1549 for (msi = 0;
1550 ((msi < intr_info.num_intr) && (rval == SUCCESS));
1551 msi++) {
1552 bzero(iget_p, sizeof (pcitool_intr_get_t));
1553 iget_p->num_devs_ret = INIT_NUM_DEVS;
1554 iget_p->user_version = PCITOOL_VERSION;
1555 iget_p->flags = PCITOOL_INTR_FLAG_GET_MSI;
1556 iget_p->msi = msi;
1557 rval = get_single_interrupt(
1558 fd, &iget_p, input_args_p);
1561 /* Explicit INO requested. */
1562 } else if (input_args_p->flags & INO_SPEC_FLAG) {
1563 iget_p->ino = input_args_p->intr_ino;
1564 iget_p->cpu_id = input_args_p->old_cpu;
1565 rval = get_single_interrupt(fd, &iget_p, input_args_p);
1566 /* Return all INOs. */
1567 } else if (input_args_p->flags & INO_ALL_FLAG) {
1568 pcitool_intr_info_t intr_info;
1569 intr_info.flags = 0;
1571 if (ioctl(fd, PCITOOL_SYSTEM_INTR_INFO, &intr_info) != 0) {
1572 if (!(IS_QUIET(input_args_p->flags))) {
1573 (void) fprintf(stderr,
1574 "intr info ioctl failed: %s\n",
1575 strerror(errno));
1577 free(iget_p);
1578 return (rval);
1582 * Search through all interrupts.
1583 * Display info on enabled ones.
1585 if (intr_info.ctlr_type == PCITOOL_CTLR_TYPE_APIX) {
1586 for (cpu_id = 0;
1587 ((cpu_id < intr_info.num_cpu) && (rval == SUCCESS));
1588 cpu_id++) {
1589 for (ino = 0;
1590 ((ino < intr_info.num_intr) &&
1591 (rval == SUCCESS));
1592 ino++) {
1593 bzero(iget_p,
1594 sizeof (pcitool_intr_get_t));
1595 iget_p->num_devs_ret = INIT_NUM_DEVS;
1596 iget_p->user_version = PCITOOL_VERSION;
1597 iget_p->cpu_id = cpu_id;
1598 iget_p->ino = ino;
1599 rval = get_single_interrupt(
1600 fd, &iget_p, input_args_p);
1603 } else {
1604 for (ino = 0;
1605 (ino < intr_info.num_intr) && (rval == SUCCESS);
1606 ino++) {
1607 bzero(iget_p,
1608 sizeof (pcitool_intr_get_t));
1609 iget_p->num_devs_ret = INIT_NUM_DEVS;
1610 iget_p->user_version = PCITOOL_VERSION;
1611 iget_p->cpu_id = input_args_p->old_cpu;
1612 iget_p->ino = ino;
1613 rval = get_single_interrupt(
1614 fd, &iget_p, input_args_p);
1619 free(iget_p);
1621 return (rval);
1625 static int
1626 get_interrupt_ctlr(int fd, pcitool_uiargs_t *input_args_p)
1628 pcitool_intr_info_t intr_info;
1629 char *ctlr_type = NULL;
1630 int rval = SUCCESS;
1632 intr_info.flags = 0;
1633 if (ioctl(fd, PCITOOL_SYSTEM_INTR_INFO, &intr_info) != 0) {
1634 if (!(IS_QUIET(input_args_p->flags))) {
1635 (void) perror("Ioctl to get intr ctlr info failed");
1637 rval = errno;
1639 } else {
1640 (void) fputs("Controller type: ", stdout);
1641 switch (intr_info.ctlr_type) {
1642 case PCITOOL_CTLR_TYPE_RISC:
1643 ctlr_type = "RISC";
1644 break;
1645 case PCITOOL_CTLR_TYPE_UPPC:
1646 ctlr_type = "UPPC";
1647 break;
1648 case PCITOOL_CTLR_TYPE_PCPLUSMP:
1649 ctlr_type = "PCPLUSMP";
1650 break;
1651 case PCITOOL_CTLR_TYPE_APIX:
1652 ctlr_type = "APIX";
1653 break;
1655 default:
1656 break;
1659 if (ctlr_type == NULL) {
1660 (void) printf("Unknown or new (%d)",
1661 intr_info.ctlr_type);
1662 } else {
1663 (void) fputs(ctlr_type, stdout);
1666 #ifdef __x86
1667 if (intr_info.ctlr_type == PCITOOL_CTLR_TYPE_PCPLUSMP)
1668 (void) printf(", IO APIC version: 0x%x, "
1669 "local APIC version: 0x%x\n",
1670 PSMAT_IO_APIC_VER(intr_info.ctlr_version),
1671 PSMAT_LOCAL_APIC_VER(intr_info.ctlr_version));
1672 else
1673 #endif /* __x86 */
1674 (void) printf(", version: %2.2x.%2.2x.%2.2x.%2.2x\n",
1675 ((intr_info.ctlr_version >> 24) & 0xff),
1676 ((intr_info.ctlr_version >> 16) & 0xff),
1677 ((intr_info.ctlr_version >> 8) & 0xff),
1678 (intr_info.ctlr_version & 0xff));
1681 return (rval);
1686 * fd is the file descriptor of the nexus being changed.
1687 * input_args are commandline options entered by the user.
1689 static int
1690 set_interrupts(int fd, pcitool_uiargs_t *input_args_p)
1692 pcitool_intr_set_t iset;
1693 const char *str_type = NULL;
1694 uint32_t intr;
1695 int rval = SUCCESS; /* Return status. */
1697 /* Load interrupt number and cpu from commandline. */
1698 if (input_args_p->flags & MSI_SPEC_FLAG) {
1699 iset.msi = intr = input_args_p->intr_msi;
1700 iset.flags = PCITOOL_INTR_FLAG_SET_MSI;
1701 str_type = "msi";
1702 } else {
1703 iset.ino = intr = input_args_p->intr_ino;
1704 iset.flags = 0;
1705 str_type = "ino";
1708 iset.cpu_id = input_args_p->intr_cpu;
1709 iset.old_cpu = input_args_p->old_cpu;
1710 iset.user_version = PCITOOL_VERSION;
1711 iset.flags |= (input_args_p->flags & SETGRP_FLAG) ?
1712 PCITOOL_INTR_FLAG_SET_GROUP : 0;
1714 /* Do the deed. */
1715 if (ioctl(fd, PCITOOL_DEVICE_SET_INTR, &iset) != 0) {
1716 if (!(IS_QUIET(input_args_p->flags))) {
1717 (void) fprintf(stderr,
1718 "Ioctl to set %s 0x%x failed: %s\n",
1719 str_type, intr, strerror(errno));
1720 (void) fprintf(stderr, "pcitool status: %s\n",
1721 strstatus(iset.status));
1723 rval = errno;
1724 } else {
1725 if (input_args_p->flags & SETGRP_FLAG) {
1726 if (iset.flags == PCITOOL_INTR_FLAG_SET_MSI)
1727 (void) printf("0x%x,0x%x => 0x%x,0x%x\n",
1728 iset.cpu_id,
1729 (input_args_p->intr_msi) & 0xff,
1730 input_args_p->intr_cpu, iset.msi);
1731 else
1732 (void) printf("0x%x,0x%x => 0x%x,0x%x\n",
1733 iset.cpu_id,
1734 (input_args_p->intr_ino) & 0xff,
1735 input_args_p->intr_cpu, iset.ino);
1736 } else {
1737 if (iset.flags == PCITOOL_INTR_FLAG_SET_MSI)
1738 (void) printf("0x%x,0x%x -> 0x%x,0x%x\n",
1739 iset.cpu_id,
1740 (input_args_p->intr_msi) & 0xff,
1741 input_args_p->intr_cpu, iset.msi);
1742 else
1743 (void) printf("0x%x,0x%x -> 0x%x,0x%x\n",
1744 iset.cpu_id,
1745 (input_args_p->intr_ino) & 0xff,
1746 input_args_p->intr_cpu, iset.ino);
1751 return (rval);
1755 static int
1756 do_interrupts(int fd, pcitool_uiargs_t *input_args_p)
1758 if (input_args_p->flags & READ_FLAG) {
1760 int gic_rval = SUCCESS;
1761 int gi_rval = SUCCESS;
1763 if (input_args_p->flags & SHOWCTLR_FLAG) {
1764 gic_rval = get_interrupt_ctlr(fd, input_args_p);
1767 gi_rval = get_interrupts(fd, input_args_p);
1768 return ((gi_rval != SUCCESS) ? gi_rval : gic_rval);
1770 } else {
1772 return (set_interrupts(fd, input_args_p));
1777 /* *********** Where it all begins... ************* */
1780 main(int argc, char **argv)
1782 pcitool_uiargs_t input_args; /* Commandline args. */
1783 int fd; /* Nexus file descriptor. */
1784 int rval = SUCCESS; /* Return status value. */
1787 /* Get commandline args and options from user. */
1788 if (get_commandline_args(argc, argv, &input_args) != SUCCESS) {
1789 return (EINVAL);
1792 /* Help. */
1793 if (!(input_args.flags & ALL_COMMANDS))
1794 return (SUCCESS);
1797 * Probe mode.
1798 * Nexus is provided as argv[1] unless PROBEALL mode.
1800 if (input_args.flags & PROBE_FLAGS) {
1801 rval = do_probe_walk(&input_args,
1802 ((input_args.flags & PROBEALL_FLAG) ? NULL : argv[1]));
1804 } else if ((fd = open_node(argv[1], &input_args)) >= 0) {
1805 if (input_args.flags & (NEXUS_FLAG | LEAF_FLAG)) {
1806 (void) signal(SIGINT, signal_handler);
1807 (void) signal(SIGTERM, signal_handler);
1808 rval = do_device_or_nexus(fd, &input_args);
1809 } else if (input_args.flags & INTR_FLAG) {
1810 rval = do_interrupts(fd, &input_args);
1811 } else {
1812 /* Should never see this. */
1813 (void) fprintf(stderr, "Nothing to do.\n");
1814 rval = ENOTTY;
1817 (void) close(fd);
1820 return (rval);