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.
32 #include <libdevinfo.h>
33 #include <sys/pctypes.h>
34 #include <sys/pcmcia.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 pcmcia_printregs(struct pcm_regs
*, int);
51 static void pcmcia_printintr(struct intrspec
*, int);
52 static void pcmcia_print(uintptr_t, int);
53 static void sbus_print(uintptr_t, int);
54 static struct priv_data
*match_priv_data(di_node_t
);
57 * This is a hardcoded list of drivers we print parent private
58 * data as of Solaris 7.
60 static struct di_priv_format ppd_format
[] = {
63 * obio format: applies the following list
64 * of nexus drivers. Note that obio driver
65 * went away with sun4m.
68 "central dma ebus fhc isa pci rootnex",
70 "central dma ebus fhc isa pci pci_pci rootnex",
72 sizeof (struct ddi_parent_private_data
),
74 sizeof (struct regspec
), /* first pointer */
75 offsetof(struct ddi_parent_private_data
, par_reg
),
76 offsetof(struct ddi_parent_private_data
, par_nreg
),
78 sizeof (struct intrspec
), /* second pointer */
79 offsetof(struct ddi_parent_private_data
, par_intr
),
80 offsetof(struct ddi_parent_private_data
, par_nintr
),
82 sizeof (struct rangespec
), /* third pointer */
83 offsetof(struct ddi_parent_private_data
, par_rng
),
84 offsetof(struct ddi_parent_private_data
, par_nrng
),
86 0, 0, 0, /* no more pointers */
92 sizeof (struct pcmcia_parent_private
),
94 sizeof (struct pcm_regs
), /* first pointer */
95 offsetof(struct pcmcia_parent_private
, ppd_reg
),
96 offsetof(struct pcmcia_parent_private
, ppd_nreg
),
98 sizeof (struct intrspec
), /* second pointer */
99 offsetof(struct pcmcia_parent_private
, ppd_intrspec
),
100 offsetof(struct pcmcia_parent_private
, ppd_intr
),
102 0, 0, 0, /* no more pointers */
107 { /* sbus format--it's different on sun4u!! */
109 sizeof (struct ddi_parent_private_data
),
111 sizeof (struct regspec
), /* first pointer */
112 offsetof(struct ddi_parent_private_data
, par_reg
),
113 offsetof(struct ddi_parent_private_data
, par_nreg
),
115 sizeof (struct intrspec
), /* second pointer */
116 offsetof(struct ddi_parent_private_data
, par_intr
),
117 offsetof(struct ddi_parent_private_data
, par_nintr
),
119 sizeof (struct rangespec
), /* third pointer */
120 offsetof(struct ddi_parent_private_data
, par_rng
),
121 offsetof(struct ddi_parent_private_data
, par_nrng
),
123 0, 0, 0, /* no more pointers */
128 static struct priv_data prt_priv_data
[] = {
129 { ppd_format
[0].drv_name
, obio_print
},
130 { ppd_format
[1].drv_name
, pcmcia_print
},
131 { ppd_format
[2].drv_name
, sbus_print
}
134 static int nprt_priv_data
= sizeof (prt_priv_data
)/sizeof (struct priv_data
);
137 init_priv_data(struct di_priv_data
*fetch
)
139 /* no driver private data */
140 fetch
->version
= DI_PRIVDATA_VERSION_0
;
142 fetch
->driver
= NULL
;
144 fetch
->n_parent
= nprt_priv_data
;
145 fetch
->parent
= ppd_format
;
149 obio_printregs(struct regspec
*rp
, int ilev
)
151 indent_to_level(ilev
);
152 (void) printf(" Bus Type=0x%x, Address=0x%x, Size=0x%x\n",
153 rp
->regspec_bustype
, rp
->regspec_addr
, rp
->regspec_size
);
157 obio_printranges(struct rangespec
*rp
, int ilev
)
159 indent_to_level(ilev
);
160 (void) printf(" Ch: %.2x,%.8x Pa: %.2x,%.8x, Sz: %x\n",
161 rp
->rng_cbustype
, rp
->rng_coffset
,
162 rp
->rng_bustype
, rp
->rng_offset
,
167 obio_printintr(struct intrspec
*ip
, int ilev
)
169 indent_to_level(ilev
);
170 (void) printf(" Interrupt Priority=0x%x (ipl %d)",
171 ip
->intrspec_pri
, INT_IPL(ip
->intrspec_pri
));
172 if (ip
->intrspec_vec
)
173 (void) printf(", vector=0x%x (%d)",
174 ip
->intrspec_vec
, ip
->intrspec_vec
);
179 obio_print(uintptr_t data
, int ilev
)
181 int i
, nreg
, nrng
, nintr
;
182 struct ddi_parent_private_data
*dp
;
184 struct intrspec
*intr
;
185 struct rangespec
*rng
;
187 dp
= (struct ddi_parent_private_data
*)data
;
189 dprintf("obio parent private data: nreg = 0x%x offset = 0x%x"
190 " nintr = 0x%x offset = 0x%x nrng = 0x%x offset = %x\n",
191 dp
->par_nreg
, *((di_off_t
*)(&dp
->par_reg
)),
192 dp
->par_nintr
, *((di_off_t
*)(&dp
->par_intr
)),
193 dp
->par_nrng
, *((di_off_t
*)(&dp
->par_rng
)));
196 nintr
= dp
->par_nintr
;
200 * All pointers are translated to di_off_t by the devinfo driver.
201 * This is a private agreement between libdevinfo and prtconf.
204 indent_to_level(ilev
);
205 (void) printf("Register Specifications:\n");
207 reg
= (struct regspec
*)(data
+ *(di_off_t
*)(&dp
->par_reg
));
208 for (i
= 0; i
< nreg
; ++i
)
209 obio_printregs(reg
+ i
, ilev
);
213 indent_to_level(ilev
);
214 (void) printf("Range Specifications:\n");
216 rng
= (struct rangespec
*)(data
+ *(di_off_t
*)(&dp
->par_rng
));
217 for (i
= 0; i
< nrng
; ++i
)
218 obio_printranges(rng
+ i
, ilev
);
222 indent_to_level(ilev
);
223 (void) printf("Interrupt Specifications:\n");
225 intr
= (struct intrspec
*)(data
+ *(di_off_t
*)(&dp
->par_intr
));
226 for (i
= 0; i
< nintr
; ++i
)
227 obio_printintr(intr
+ i
, ilev
);
232 pcmcia_printregs(struct pcm_regs
*rp
, int ilev
)
234 indent_to_level(ilev
);
235 (void) printf(" Phys hi=0x%x, Phys lo=0x%x, Phys len=%x\n",
236 rp
->phys_hi
, rp
->phys_lo
, rp
->phys_len
);
240 pcmcia_printintr(struct intrspec
*ip
, int ilev
)
242 obio_printintr(ip
, ilev
);
246 pcmcia_print(uintptr_t data
, int ilev
)
249 struct pcmcia_parent_private
*dp
;
250 struct pcm_regs
*reg
;
251 struct intrspec
*intr
;
253 dp
= (struct pcmcia_parent_private
*)data
;
255 dprintf("pcmcia parent private data: nreg = 0x%x offset = 0x%x"
256 " intr = 0x%x offset = %x\n",
257 dp
->ppd_nreg
, *(di_off_t
*)(&dp
->ppd_reg
),
258 dp
->ppd_intr
, *(di_off_t
*)(&dp
->ppd_intrspec
));
261 nintr
= dp
->ppd_intr
;
264 * All pointers are translated to di_off_t by the devinfo driver.
265 * This is a private agreement between libdevinfo and prtconf.
268 indent_to_level(ilev
);
269 (void) printf("Register Specifications:\n");
271 reg
= (struct pcm_regs
*)(data
+ *(di_off_t
*)(&dp
->ppd_reg
));
272 for (i
= 0; i
< nreg
; ++i
)
273 pcmcia_printregs(reg
+ i
, ilev
);
277 indent_to_level(ilev
);
278 (void) printf("Interrupt Specifications:\n");
280 intr
= (struct intrspec
*)
281 (data
+ *(di_off_t
*)(&dp
->ppd_intrspec
));
282 for (i
= 0; i
< nintr
; ++i
)
283 pcmcia_printintr(intr
+ i
, ilev
);
288 sbus_print(uintptr_t data
, int ilev
)
290 int i
, nreg
, nrng
, nintr
;
291 struct ddi_parent_private_data
*dp
;
293 struct intrspec
*intr
;
294 struct rangespec
*rng
;
296 dp
= (struct ddi_parent_private_data
*)data
;
298 dprintf("sbus parent private data: nreg = 0x%x offset = 0x%x"
299 " nintr = 0x%x offset = 0x%x nrng = 0x%x offset = %x\n",
300 dp
->par_nreg
, *((di_off_t
*)(&dp
->par_reg
)),
301 dp
->par_nintr
, *((di_off_t
*)(&dp
->par_intr
)),
302 dp
->par_nrng
, *((di_off_t
*)(&dp
->par_rng
)));
305 nintr
= dp
->par_nintr
;
309 * All pointers are translated to di_off_t by the devinfo driver.
310 * This is a private agreement between libdevinfo and prtconf.
313 indent_to_level(ilev
);
314 (void) printf("Register Specifications:\n");
316 reg
= (struct regspec
*)(data
+ *(di_off_t
*)(&dp
->par_reg
));
317 for (i
= 0; i
< nreg
; ++i
)
318 obio_printregs(reg
+ i
, ilev
);
323 indent_to_level(ilev
);
324 (void) printf("Range Specifications:\n");
326 rng
= (struct rangespec
*)(data
+ *(di_off_t
*)(&dp
->par_rng
));
327 for (i
= 0; i
< nrng
; ++i
)
328 obio_printranges(rng
+ i
, ilev
);
332 * To print interrupt property for children of sbus on sun4u requires
333 * definitions in sysiosbus.h.
335 * We can't #include <sys/sysiosbus.h> to have the build work on
336 * non sun4u machines. It's not right either to
337 * #include "../../uts/sun4u/sys/sysiosbus.h"
338 * As a result, we will not print the information.
340 if ((nintr
!= 0) && (strcmp(opts
.o_uts
.machine
, "sun4u") != 0)) {
341 indent_to_level(ilev
);
342 (void) printf("Interrupt Specifications:\n");
344 for (i
= 0; i
< nintr
; ++i
) {
345 intr
= (struct intrspec
*)
346 (data
+ *(di_off_t
*)(&dp
->par_intr
));
347 obio_printintr(intr
+ i
, ilev
);
352 static struct priv_data
*
353 match_priv_data(di_node_t node
)
357 char *drv_name
, *tmp
;
359 struct priv_data
*pdp
;
361 if ((parent
= di_parent_node(node
)) == DI_NODE_NIL
)
364 if ((drv_name
= di_driver_name(parent
)) == NULL
)
368 len
= strlen(drv_name
);
369 for (i
= 0; i
< nprt_priv_data
; ++i
, ++pdp
) {
371 while (tmp
&& (*tmp
!= '\0')) {
372 if (strncmp(tmp
, drv_name
, len
) == 0) {
374 dprintf("matched parent private data"
375 " at Node <%s> parent driver <%s>\n",
376 di_node_name(node
), drv_name
);
383 if (tmp
= strchr(tmp
, ' '))
392 dump_priv_data(int ilev
, di_node_t node
)
395 struct priv_data
*pdp
;
397 if ((priv
= (uintptr_t)di_parent_private_data(node
)) == NULL
)
400 if ((pdp
= match_priv_data(node
)) == NULL
) {
402 dprintf("Error: parent private data format unknown\n");
407 pdp
->pd_print(priv
, ilev
);
409 /* ignore driver private data for now */
412 #define LOOKUP_PROP(proptype, ph, nodetype, dev, node, name, data) \
413 ((nodetype == DI_PROM_NODEID) ? \
414 di_prom_prop_lookup_##proptype(ph, node, name, data) : \
415 di_prop_lookup_##proptype(dev, node, name, data))
417 (((s) != NULL) && ((strcmp((s), "pci") == 0) || \
418 (strcmp((s), "pciex") == 0)))
420 * Print vendor ID and device ID for PCI devices
423 print_pciid(di_node_t node
, di_prom_handle_t ph
, pcidb_hdl_t
*pci
)
425 pcidb_vendor_t
*vend
= NULL
;
426 pcidb_device_t
*dev
= NULL
;
427 di_node_t pnode
= di_parent_node(node
);
429 int *i
, type
= di_nodeid(node
);
431 if (LOOKUP_PROP(strings
, ph
, type
, DDI_DEV_T_ANY
, pnode
,
432 "device_type", &s
) <= 0)
436 return (0); /* not a pci device */
438 (void) printf(" (%s", s
);
439 if (LOOKUP_PROP(ints
, ph
, type
, DDI_DEV_T_ANY
, node
,
440 "vendor-id", &i
) > 0)
441 (void) printf("%x", i
[0]);
444 vend
= pcidb_lookup_vendor(pci
, i
[0]);
446 if (LOOKUP_PROP(ints
, ph
, type
, DDI_DEV_T_ANY
, node
,
447 "device-id", &i
) > 0)
448 (void) printf(",%x", i
[0]);
451 dev
= pcidb_lookup_device_by_vendor(vend
, i
[0]);
453 (void) printf(") [");
456 (void) printf("%s ", pcidb_vendor_name(vend
));
458 (void) printf("unknown vendor, ");
461 (void) printf("%s", pcidb_device_name(dev
));
463 (void) printf("unknown device");