4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
25 * Copyright (c) 2012, Joyent, Inc. All rights reserved.
26 * Copyright 2014 Garrett D'Amore <garrett@damore.org>
33 #include <libdevinfo.h>
34 #include <sys/pctypes.h>
35 #include <sys/utsname.h>
36 #include <sys/avintr.h>
41 char *drv_name
; /* parent name */
42 void (*pd_print
)(uintptr_t, int); /* print function */
45 extern void indent_to_level();
46 static void obio_printregs(struct regspec
*, int);
47 static void obio_printranges(struct rangespec
*, int);
48 static void obio_printintr(struct intrspec
*, int);
49 static void obio_print(uintptr_t, int);
50 static void sbus_print(uintptr_t, int);
51 static struct priv_data
*match_priv_data(di_node_t
);
54 * This is a hardcoded list of drivers we print parent private
55 * data as of Solaris 7.
57 static struct di_priv_format ppd_format
[] = {
60 * obio format: applies the following list
61 * of nexus drivers. Note that obio driver
62 * went away with sun4m.
64 "central dma ebus fhc isa pci pci_pci rootnex",
65 sizeof (struct ddi_parent_private_data
),
67 sizeof (struct regspec
), /* first pointer */
68 offsetof(struct ddi_parent_private_data
, par_reg
),
69 offsetof(struct ddi_parent_private_data
, par_nreg
),
71 sizeof (struct intrspec
), /* second pointer */
72 offsetof(struct ddi_parent_private_data
, par_intr
),
73 offsetof(struct ddi_parent_private_data
, par_nintr
),
75 sizeof (struct rangespec
), /* third pointer */
76 offsetof(struct ddi_parent_private_data
, par_rng
),
77 offsetof(struct ddi_parent_private_data
, par_nrng
),
79 0, 0, 0, /* no more pointers */
83 { /* sbus format--it's different on sun4u!! */
85 sizeof (struct ddi_parent_private_data
),
87 sizeof (struct regspec
), /* first pointer */
88 offsetof(struct ddi_parent_private_data
, par_reg
),
89 offsetof(struct ddi_parent_private_data
, par_nreg
),
91 sizeof (struct intrspec
), /* second pointer */
92 offsetof(struct ddi_parent_private_data
, par_intr
),
93 offsetof(struct ddi_parent_private_data
, par_nintr
),
95 sizeof (struct rangespec
), /* third pointer */
96 offsetof(struct ddi_parent_private_data
, par_rng
),
97 offsetof(struct ddi_parent_private_data
, par_nrng
),
99 0, 0, 0, /* no more pointers */
104 static struct priv_data prt_priv_data
[] = {
105 { ppd_format
[0].drv_name
, obio_print
},
106 { ppd_format
[1].drv_name
, sbus_print
}
109 static int nprt_priv_data
= sizeof (prt_priv_data
)/sizeof (struct priv_data
);
112 init_priv_data(struct di_priv_data
*fetch
)
114 /* no driver private data */
115 fetch
->version
= DI_PRIVDATA_VERSION_0
;
117 fetch
->driver
= NULL
;
119 fetch
->n_parent
= nprt_priv_data
;
120 fetch
->parent
= ppd_format
;
124 obio_printregs(struct regspec
*rp
, int ilev
)
126 indent_to_level(ilev
);
127 (void) printf(" Bus Type=0x%x, Address=0x%x, Size=0x%x\n",
128 rp
->regspec_bustype
, rp
->regspec_addr
, rp
->regspec_size
);
132 obio_printranges(struct rangespec
*rp
, int ilev
)
134 indent_to_level(ilev
);
135 (void) printf(" Ch: %.2x,%.8x Pa: %.2x,%.8x, Sz: %x\n",
136 rp
->rng_cbustype
, rp
->rng_coffset
,
137 rp
->rng_bustype
, rp
->rng_offset
,
142 obio_printintr(struct intrspec
*ip
, int ilev
)
144 indent_to_level(ilev
);
145 (void) printf(" Interrupt Priority=0x%x (ipl %d)",
146 ip
->intrspec_pri
, INT_IPL(ip
->intrspec_pri
));
147 if (ip
->intrspec_vec
)
148 (void) printf(", vector=0x%x (%d)",
149 ip
->intrspec_vec
, ip
->intrspec_vec
);
154 obio_print(uintptr_t data
, int ilev
)
156 int i
, nreg
, nrng
, nintr
;
157 struct ddi_parent_private_data
*dp
;
159 struct intrspec
*intr
;
160 struct rangespec
*rng
;
162 dp
= (struct ddi_parent_private_data
*)data
;
164 dprintf("obio parent private data: nreg = 0x%x offset = 0x%x"
165 " nintr = 0x%x offset = 0x%x nrng = 0x%x offset = %x\n",
166 dp
->par_nreg
, *((di_off_t
*)(&dp
->par_reg
)),
167 dp
->par_nintr
, *((di_off_t
*)(&dp
->par_intr
)),
168 dp
->par_nrng
, *((di_off_t
*)(&dp
->par_rng
)));
171 nintr
= dp
->par_nintr
;
175 * All pointers are translated to di_off_t by the devinfo driver.
176 * This is a private agreement between libdevinfo and prtconf.
179 indent_to_level(ilev
);
180 (void) printf("Register Specifications:\n");
182 reg
= (struct regspec
*)(data
+ *(di_off_t
*)(&dp
->par_reg
));
183 for (i
= 0; i
< nreg
; ++i
)
184 obio_printregs(reg
+ i
, ilev
);
188 indent_to_level(ilev
);
189 (void) printf("Range Specifications:\n");
191 rng
= (struct rangespec
*)(data
+ *(di_off_t
*)(&dp
->par_rng
));
192 for (i
= 0; i
< nrng
; ++i
)
193 obio_printranges(rng
+ i
, ilev
);
197 indent_to_level(ilev
);
198 (void) printf("Interrupt Specifications:\n");
200 intr
= (struct intrspec
*)(data
+ *(di_off_t
*)(&dp
->par_intr
));
201 for (i
= 0; i
< nintr
; ++i
)
202 obio_printintr(intr
+ i
, ilev
);
207 sbus_print(uintptr_t data
, int ilev
)
209 int i
, nreg
, nrng
, nintr
;
210 struct ddi_parent_private_data
*dp
;
212 struct intrspec
*intr
;
213 struct rangespec
*rng
;
215 dp
= (struct ddi_parent_private_data
*)data
;
217 dprintf("sbus parent private data: nreg = 0x%x offset = 0x%x"
218 " nintr = 0x%x offset = 0x%x nrng = 0x%x offset = %x\n",
219 dp
->par_nreg
, *((di_off_t
*)(&dp
->par_reg
)),
220 dp
->par_nintr
, *((di_off_t
*)(&dp
->par_intr
)),
221 dp
->par_nrng
, *((di_off_t
*)(&dp
->par_rng
)));
224 nintr
= dp
->par_nintr
;
228 * All pointers are translated to di_off_t by the devinfo driver.
229 * This is a private agreement between libdevinfo and prtconf.
232 indent_to_level(ilev
);
233 (void) printf("Register Specifications:\n");
235 reg
= (struct regspec
*)(data
+ *(di_off_t
*)(&dp
->par_reg
));
236 for (i
= 0; i
< nreg
; ++i
)
237 obio_printregs(reg
+ i
, ilev
);
242 indent_to_level(ilev
);
243 (void) printf("Range Specifications:\n");
245 rng
= (struct rangespec
*)(data
+ *(di_off_t
*)(&dp
->par_rng
));
246 for (i
= 0; i
< nrng
; ++i
)
247 obio_printranges(rng
+ i
, ilev
);
251 * To print interrupt property for children of sbus on sun4u requires
252 * definitions in sysiosbus.h.
254 * We can't #include <sys/sysiosbus.h> to have the build work on
255 * non sun4u machines. It's not right either to
256 * #include "../../uts/sun4u/sys/sysiosbus.h"
257 * As a result, we will not print the information.
259 if ((nintr
!= 0) && (strcmp(opts
.o_uts
.machine
, "sun4u") != 0)) {
260 indent_to_level(ilev
);
261 (void) printf("Interrupt Specifications:\n");
263 for (i
= 0; i
< nintr
; ++i
) {
264 intr
= (struct intrspec
*)
265 (data
+ *(di_off_t
*)(&dp
->par_intr
));
266 obio_printintr(intr
+ i
, ilev
);
271 static struct priv_data
*
272 match_priv_data(di_node_t node
)
276 char *drv_name
, *tmp
;
278 struct priv_data
*pdp
;
280 if ((parent
= di_parent_node(node
)) == DI_NODE_NIL
)
283 if ((drv_name
= di_driver_name(parent
)) == NULL
)
287 len
= strlen(drv_name
);
288 for (i
= 0; i
< nprt_priv_data
; ++i
, ++pdp
) {
290 while (tmp
&& (*tmp
!= '\0')) {
291 if (strncmp(tmp
, drv_name
, len
) == 0) {
293 dprintf("matched parent private data"
294 " at Node <%s> parent driver <%s>\n",
295 di_node_name(node
), drv_name
);
302 if (tmp
= strchr(tmp
, ' '))
311 dump_priv_data(int ilev
, di_node_t node
)
314 struct priv_data
*pdp
;
316 if ((priv
= (uintptr_t)di_parent_private_data(node
)) == (uintptr_t)NULL
)
319 if ((pdp
= match_priv_data(node
)) == NULL
) {
321 dprintf("Error: parent private data format unknown\n");
326 pdp
->pd_print(priv
, ilev
);
328 /* ignore driver private data for now */
331 #define LOOKUP_PROP(proptype, ph, nodetype, dev, node, name, data) \
332 ((nodetype == DI_PROM_NODEID) ? \
333 di_prom_prop_lookup_##proptype(ph, node, name, data) : \
334 di_prop_lookup_##proptype(dev, node, name, data))
336 (((s) != NULL) && ((strcmp((s), "pci") == 0) || \
337 (strcmp((s), "pciex") == 0)))
339 * Print vendor ID and device ID for PCI devices
342 print_pciid(di_node_t node
, di_prom_handle_t ph
, pcidb_hdl_t
*pci
)
344 pcidb_vendor_t
*vend
= NULL
;
345 pcidb_device_t
*dev
= NULL
;
346 di_node_t pnode
= di_parent_node(node
);
348 int *i
, type
= di_nodeid(node
);
350 if (LOOKUP_PROP(strings
, ph
, type
, DDI_DEV_T_ANY
, pnode
,
351 "device_type", &s
) <= 0)
355 return (0); /* not a pci device */
357 (void) printf(" (%s", s
);
358 if (LOOKUP_PROP(ints
, ph
, type
, DDI_DEV_T_ANY
, node
,
359 "vendor-id", &i
) > 0)
360 (void) printf("%x", i
[0]);
363 vend
= pcidb_lookup_vendor(pci
, i
[0]);
365 if (LOOKUP_PROP(ints
, ph
, type
, DDI_DEV_T_ANY
, node
,
366 "device-id", &i
) > 0)
367 (void) printf(",%x", i
[0]);
370 dev
= pcidb_lookup_device_by_vendor(vend
, i
[0]);
372 (void) printf(") [");
375 (void) printf("%s ", pcidb_vendor_name(vend
));
377 (void) printf("unknown vendor, ");
380 (void) printf("%s", pcidb_device_name(dev
));
382 (void) printf("unknown device");