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