Home | History | Annotate | Download | only in prtconf
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 #include <stdio.h>
     27 #include <stddef.h>
     28 #include <fcntl.h>
     29 #include <string.h>
     30 #include <libdevinfo.h>
     31 #include <sys/pctypes.h>
     32 #include <sys/pcmcia.h>
     33 #include <sys/utsname.h>
     34 #include <sys/avintr.h>
     35 
     36 #include "prtconf.h"
     37 
     38 struct priv_data {
     39 	char *drv_name;		/* parent name */
     40 	void (*pd_print)(uintptr_t, int);	/* print function */
     41 };
     42 
     43 extern void indent_to_level();
     44 static void obio_printregs(struct regspec *, int);
     45 static void obio_printranges(struct rangespec *, int);
     46 static void obio_printintr(struct intrspec *, int);
     47 static void obio_print(uintptr_t, int);
     48 static void pcmcia_printregs(struct pcm_regs *, int);
     49 static void pcmcia_printintr(struct intrspec *, int);
     50 static void pcmcia_print(uintptr_t, int);
     51 static void sbus_print(uintptr_t, int);
     52 static struct priv_data *match_priv_data(di_node_t);
     53 
     54 /*
     55  * This is a hardcoded list of drivers we print parent private
     56  * data as of Solaris 7.
     57  */
     58 static struct di_priv_format ppd_format[] = {
     59 	{
     60 		/*
     61 		 * obio format: applies the following list
     62 		 * of nexus drivers. Note that obio driver
     63 		 * went away with sun4m.
     64 		 */
     65 #ifdef	__sparc
     66 		"central dma ebus fhc isa pci rootnex",
     67 #else
     68 		"central dma ebus fhc isa pci pci_pci rootnex",
     69 #endif	/* __sparc */
     70 		sizeof (struct ddi_parent_private_data),
     71 
     72 		sizeof (struct regspec),		/* first pointer */
     73 		offsetof(struct ddi_parent_private_data, par_reg),
     74 		offsetof(struct ddi_parent_private_data, par_nreg),
     75 
     76 		sizeof (struct intrspec),		/* second pointer */
     77 		offsetof(struct ddi_parent_private_data, par_intr),
     78 		offsetof(struct ddi_parent_private_data, par_nintr),
     79 
     80 		sizeof (struct rangespec),		/* third pointer */
     81 		offsetof(struct ddi_parent_private_data, par_rng),
     82 		offsetof(struct ddi_parent_private_data, par_nrng),
     83 
     84 		0, 0, 0,	/* no more pointers */
     85 		0, 0, 0
     86 	},
     87 
     88 	{	/* pcmcia format */
     89 		"pcic stp4020",
     90 		sizeof (struct pcmcia_parent_private),
     91 
     92 		sizeof (struct pcm_regs),		/* first pointer */
     93 		offsetof(struct pcmcia_parent_private, ppd_reg),
     94 		offsetof(struct pcmcia_parent_private, ppd_nreg),
     95 
     96 		sizeof (struct intrspec),		/* second pointer */
     97 		offsetof(struct pcmcia_parent_private, ppd_intrspec),
     98 		offsetof(struct pcmcia_parent_private, ppd_intr),
     99 
    100 		0, 0, 0,	/* no more pointers */
    101 		0, 0, 0,
    102 		0, 0, 0
    103 	},
    104 
    105 	{	/* sbus format--it's different on sun4u!! */
    106 		"sbus",
    107 		sizeof (struct ddi_parent_private_data),
    108 
    109 		sizeof (struct regspec),		/* first pointer */
    110 		offsetof(struct ddi_parent_private_data, par_reg),
    111 		offsetof(struct ddi_parent_private_data, par_nreg),
    112 
    113 		sizeof (struct intrspec),		/* second pointer */
    114 		offsetof(struct ddi_parent_private_data, par_intr),
    115 		offsetof(struct ddi_parent_private_data, par_nintr),
    116 
    117 		sizeof (struct rangespec),		/* third pointer */
    118 		offsetof(struct ddi_parent_private_data, par_rng),
    119 		offsetof(struct ddi_parent_private_data, par_nrng),
    120 
    121 		0, 0, 0,	/* no more pointers */
    122 		0, 0, 0
    123 	}
    124 };
    125 
    126 static struct priv_data prt_priv_data[] = {
    127 	{ ppd_format[0].drv_name, obio_print},
    128 	{ ppd_format[1].drv_name, pcmcia_print},
    129 	{ ppd_format[2].drv_name, sbus_print}
    130 };
    131 
    132 static int nprt_priv_data = sizeof (prt_priv_data)/sizeof (struct priv_data);
    133 
    134 void
    135 init_priv_data(struct di_priv_data *fetch)
    136 {
    137 	/* no driver private data */
    138 	fetch->version = DI_PRIVDATA_VERSION_0;
    139 	fetch->n_driver = 0;
    140 	fetch->driver = NULL;
    141 
    142 	fetch->n_parent = nprt_priv_data;
    143 	fetch->parent = ppd_format;
    144 }
    145 
    146 static void
    147 obio_printregs(struct regspec *rp, int ilev)
    148 {
    149 	indent_to_level(ilev);
    150 	(void) printf("    Bus Type=0x%x, Address=0x%x, Size=0x%x\n",
    151 	    rp->regspec_bustype, rp->regspec_addr, rp->regspec_size);
    152 }
    153 
    154 static void
    155 obio_printranges(struct rangespec *rp, int ilev)
    156 {
    157 	indent_to_level(ilev);
    158 	(void) printf("    Ch: %.2x,%.8x Pa: %.2x,%.8x, Sz: %x\n",
    159 	    rp->rng_cbustype, rp->rng_coffset,
    160 	    rp->rng_bustype, rp->rng_offset,
    161 	    rp->rng_size);
    162 }
    163 
    164 static void
    165 obio_printintr(struct intrspec *ip, int ilev)
    166 {
    167 	indent_to_level(ilev);
    168 	(void) printf("    Interrupt Priority=0x%x (ipl %d)",
    169 	    ip->intrspec_pri, INT_IPL(ip->intrspec_pri));
    170 	if (ip->intrspec_vec)
    171 		(void) printf(", vector=0x%x (%d)",
    172 		    ip->intrspec_vec, ip->intrspec_vec);
    173 	(void) printf("\n");
    174 }
    175 
    176 static void
    177 obio_print(uintptr_t data, int ilev)
    178 {
    179 	int i, nreg, nrng, nintr;
    180 	struct ddi_parent_private_data *dp;
    181 	struct regspec *reg;
    182 	struct intrspec *intr;
    183 	struct rangespec *rng;
    184 
    185 	dp = (struct ddi_parent_private_data *)data;
    186 #ifdef DEBUG
    187 	dprintf("obio parent private data: nreg = 0x%x offset = 0x%x"
    188 	    " nintr = 0x%x offset = 0x%x nrng = 0x%x offset = %x\n",
    189 	    dp->par_nreg, *((di_off_t *)(&dp->par_reg)),
    190 	    dp->par_nintr, *((di_off_t *)(&dp->par_intr)),
    191 	    dp->par_nrng, *((di_off_t *)(&dp->par_rng)));
    192 #endif /* DEBUG */
    193 	nreg = dp->par_nreg;
    194 	nintr = dp->par_nintr;
    195 	nrng = dp->par_nrng;
    196 
    197 	/*
    198 	 * All pointers are translated to di_off_t by the devinfo driver.
    199 	 * This is a private agreement between libdevinfo and prtconf.
    200 	 */
    201 	if (nreg != 0) {
    202 		indent_to_level(ilev);
    203 		(void) printf("Register Specifications:\n");
    204 
    205 		reg = (struct regspec *)(data + *(di_off_t *)(&dp->par_reg));
    206 		for (i = 0; i < nreg; ++i)
    207 			obio_printregs(reg + i, ilev);
    208 	}
    209 
    210 	if (nrng != 0) {
    211 		indent_to_level(ilev);
    212 		(void) printf("Range Specifications:\n");
    213 
    214 		rng = (struct rangespec *)(data + *(di_off_t *)(&dp->par_rng));
    215 		for (i = 0; i < nrng; ++i)
    216 			obio_printranges(rng + i, ilev);
    217 	}
    218 
    219 	if (nintr != 0) {
    220 		indent_to_level(ilev);
    221 		(void) printf("Interrupt Specifications:\n");
    222 
    223 		intr = (struct intrspec *)(data + *(di_off_t *)(&dp->par_intr));
    224 		for (i = 0; i < nintr; ++i)
    225 			obio_printintr(intr + i, ilev);
    226 	}
    227 }
    228 
    229 static void
    230 pcmcia_printregs(struct pcm_regs *rp, int ilev)
    231 {
    232 	indent_to_level(ilev);
    233 	(void) printf("    Phys hi=0x%x, Phys lo=0x%x, Phys len=%x\n",
    234 	    rp->phys_hi, rp->phys_lo, rp->phys_len);
    235 }
    236 
    237 static void
    238 pcmcia_printintr(struct intrspec *ip, int ilev)
    239 {
    240 	obio_printintr(ip, ilev);
    241 }
    242 
    243 static void
    244 pcmcia_print(uintptr_t data, int ilev)
    245 {
    246 	int i, nreg, nintr;
    247 	struct pcmcia_parent_private *dp;
    248 	struct pcm_regs *reg;
    249 	struct intrspec *intr;
    250 
    251 	dp = (struct pcmcia_parent_private *)data;
    252 #ifdef DEBUG
    253 	dprintf("pcmcia parent private data: nreg = 0x%x offset = 0x%x"
    254 	    " intr = 0x%x offset = %x\n",
    255 	    dp->ppd_nreg, *(di_off_t *)(&dp->ppd_reg),
    256 	    dp->ppd_intr, *(di_off_t *)(&dp->ppd_intrspec));
    257 #endif /* DEBUG */
    258 	nreg = dp->ppd_nreg;
    259 	nintr = dp->ppd_intr;
    260 
    261 	/*
    262 	 * All pointers are translated to di_off_t by the devinfo driver.
    263 	 * This is a private agreement between libdevinfo and prtconf.
    264 	 */
    265 	if (nreg != 0)  {
    266 		indent_to_level(ilev);
    267 		(void) printf("Register Specifications:\n");
    268 
    269 		reg = (struct pcm_regs *)(data + *(di_off_t *)(&dp->ppd_reg));
    270 		for (i = 0; i < nreg; ++i)
    271 			pcmcia_printregs(reg + i, ilev);
    272 	}
    273 
    274 	if (nintr != 0)  {
    275 		indent_to_level(ilev);
    276 		(void) printf("Interrupt Specifications:\n");
    277 
    278 		intr = (struct intrspec *)
    279 		    (data + *(di_off_t *)(&dp->ppd_intrspec));
    280 		for (i = 0; i < nintr; ++i)
    281 			pcmcia_printintr(intr + i, ilev);
    282 	}
    283 }
    284 
    285 static void
    286 sbus_print(uintptr_t data, int ilev)
    287 {
    288 	int i, nreg, nrng, nintr;
    289 	struct ddi_parent_private_data *dp;
    290 	struct regspec *reg;
    291 	struct intrspec *intr;
    292 	struct rangespec *rng;
    293 
    294 	dp = (struct ddi_parent_private_data *)data;
    295 #ifdef DEBUG
    296 	dprintf("sbus parent private data: nreg = 0x%x offset = 0x%x"
    297 	    " nintr = 0x%x offset = 0x%x nrng = 0x%x offset = %x\n",
    298 	    dp->par_nreg, *((di_off_t *)(&dp->par_reg)),
    299 	    dp->par_nintr, *((di_off_t *)(&dp->par_intr)),
    300 	    dp->par_nrng, *((di_off_t *)(&dp->par_rng)));
    301 #endif /* DEBUG */
    302 	nreg = dp->par_nreg;
    303 	nintr = dp->par_nintr;
    304 	nrng = dp->par_nrng;
    305 
    306 	/*
    307 	 * All pointers are translated to di_off_t by the devinfo driver.
    308 	 * This is a private agreement between libdevinfo and prtconf.
    309 	 */
    310 	if (nreg != 0) {
    311 		indent_to_level(ilev);
    312 		(void) printf("Register Specifications:\n");
    313 
    314 		reg = (struct regspec *)(data + *(di_off_t *)(&dp->par_reg));
    315 		for (i = 0; i < nreg; ++i)
    316 			obio_printregs(reg + i, ilev);
    317 	}
    318 
    319 
    320 	if (nrng != 0) {
    321 		indent_to_level(ilev);
    322 		(void) printf("Range Specifications:\n");
    323 
    324 		rng = (struct rangespec *)(data + *(di_off_t *)(&dp->par_rng));
    325 		for (i = 0; i < nrng; ++i)
    326 			obio_printranges(rng + i, ilev);
    327 	}
    328 
    329 	/*
    330 	 * To print interrupt property for children of sbus on sun4u requires
    331 	 * definitions in sysiosbus.h.
    332 	 *
    333 	 * We can't #include <sys/sysiosbus.h> to have the build work on
    334 	 * non sun4u machines. It's not right either to
    335 	 *	#include "../../uts/sun4u/sys/sysiosbus.h"
    336 	 * As a result, we will not print the information.
    337 	 */
    338 	if ((nintr != 0) && (strcmp(opts.o_uts.machine, "sun4u") != 0)) {
    339 		indent_to_level(ilev);
    340 		(void) printf("Interrupt Specifications:\n");
    341 
    342 		for (i = 0; i < nintr; ++i) {
    343 			intr = (struct intrspec *)
    344 			    (data + *(di_off_t *)(&dp->par_intr));
    345 			obio_printintr(intr + i, ilev);
    346 		}
    347 	}
    348 }
    349 
    350 static struct priv_data *
    351 match_priv_data(di_node_t node)
    352 {
    353 	int i;
    354 	size_t len;
    355 	char *drv_name, *tmp;
    356 	di_node_t parent;
    357 	struct priv_data *pdp;
    358 
    359 	if ((parent = di_parent_node(node)) == DI_NODE_NIL)
    360 		return (NULL);
    361 
    362 	if ((drv_name = di_driver_name(parent)) == NULL)
    363 		return (NULL);
    364 
    365 	pdp = prt_priv_data;
    366 	len = strlen(drv_name);
    367 	for (i = 0; i < nprt_priv_data; ++i, ++pdp) {
    368 		tmp = pdp->drv_name;
    369 		while (tmp && (*tmp != '\0')) {
    370 			if (strncmp(tmp, drv_name, len) == 0) {
    371 #ifdef	DEBUG
    372 				dprintf("matched parent private data"
    373 				    " at Node <%s> parent driver <%s>\n",
    374 				    di_node_name(node), drv_name);
    375 #endif	/* DEBUG */
    376 				return (pdp);
    377 			}
    378 			/*
    379 			 * skip a white space
    380 			 */
    381 			if (tmp = strchr(tmp, ' '))
    382 				tmp++;
    383 		}
    384 	}
    385 
    386 	return (NULL);
    387 }
    388 
    389 void
    390 dump_priv_data(int ilev, di_node_t node)
    391 {
    392 	uintptr_t priv;
    393 	struct priv_data *pdp;
    394 
    395 	if ((priv = (uintptr_t)di_parent_private_data(node)) == NULL)
    396 		return;
    397 
    398 	if ((pdp = match_priv_data(node)) == NULL) {
    399 #ifdef DEBUG
    400 		dprintf("Error: parent private data format unknown\n");
    401 #endif /* DEBUG */
    402 		return;
    403 	}
    404 
    405 	pdp->pd_print(priv, ilev);
    406 
    407 	/* ignore driver private data for now */
    408 }
    409 
    410 #define	LOOKUP_PROP(proptype, ph, nodetype, dev, node, name, data)	\
    411 	((nodetype == DI_PROM_NODEID) ?					\
    412 	di_prom_prop_lookup_##proptype(ph, node, name, data) :		\
    413 	di_prop_lookup_##proptype(dev, node, name, data))
    414 #define	ISPCI(s)						\
    415 	(((s) != NULL) && ((strcmp((s), "pci") == 0) ||		\
    416 	(strcmp((s), "pciex") == 0)))
    417 /*
    418  * Print vendor ID and device ID for PCI devices
    419  */
    420 int
    421 print_pciid(di_node_t node, di_prom_handle_t ph)
    422 {
    423 	di_node_t pnode = di_parent_node(node);
    424 	char *s = NULL;
    425 	int *i, type = di_nodeid(node);
    426 
    427 	if (LOOKUP_PROP(strings, ph, type, DDI_DEV_T_ANY, pnode,
    428 	    "device_type", &s) <= 0)
    429 		return (0);
    430 
    431 	if (!ISPCI(s))
    432 		return (0);	/* not a pci device */
    433 
    434 	(void) printf(" (%s", s);
    435 	if (LOOKUP_PROP(ints, ph, type, DDI_DEV_T_ANY, node,
    436 	    "vendor-id", &i) > 0)
    437 		(void) printf("%x", i[0]);
    438 
    439 	if (LOOKUP_PROP(ints, ph, type, DDI_DEV_T_ANY, node,
    440 	    "device-id", &i) > 0)
    441 		(void) printf(",%x", i[0]);
    442 	(void) printf(")");
    443 
    444 	return (1);
    445 }
    446