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