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