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 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <stdio.h> 29 #include <stddef.h> 30 #include <fcntl.h> 31 #include <string.h> 32 #include <libdevinfo.h> 33 #include <sys/pctypes.h> 34 #include <sys/pcmcia.h> 35 #include <sys/utsname.h> 36 #include <sys/avintr.h> 37 38 #include "prtconf.h" 39 40 struct priv_data { 41 char *drv_name; /* parent name */ 42 void (*pd_print)(uintptr_t, int); /* print function */ 43 }; 44 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); 55 56 /* 57 * This is a hardcoded list of drivers we print parent private 58 * data as of Solaris 7. 59 */ 60 static struct di_priv_format ppd_format[] = { 61 { 62 /* 63 * obio format: applies the following list 64 * of nexus drivers. Note that obio driver 65 * went away with sun4m. 66 */ 67 #ifdef __sparc 68 "central dma ebus fhc isa pci rootnex", 69 #else 70 "central dma ebus fhc isa pci pci_pci rootnex", 71 #endif /* __sparc */ 72 sizeof (struct ddi_parent_private_data), 73 74 sizeof (struct regspec), /* first pointer */ 75 offsetof(struct ddi_parent_private_data, par_reg), 76 offsetof(struct ddi_parent_private_data, par_nreg), 77 78 sizeof (struct intrspec), /* second pointer */ 79 offsetof(struct ddi_parent_private_data, par_intr), 80 offsetof(struct ddi_parent_private_data, par_nintr), 81 82 sizeof (struct rangespec), /* third pointer */ 83 offsetof(struct ddi_parent_private_data, par_rng), 84 offsetof(struct ddi_parent_private_data, par_nrng), 85 86 0, 0, 0, /* no more pointers */ 87 0, 0, 0 88 }, 89 90 { /* pcmcia format */ 91 "pcic stp4020", 92 sizeof (struct pcmcia_parent_private), 93 94 sizeof (struct pcm_regs), /* first pointer */ 95 offsetof(struct pcmcia_parent_private, ppd_reg), 96 offsetof(struct pcmcia_parent_private, ppd_nreg), 97 98 sizeof (struct intrspec), /* second pointer */ 99 offsetof(struct pcmcia_parent_private, ppd_intrspec), 100 offsetof(struct pcmcia_parent_private, ppd_intr), 101 102 0, 0, 0, /* no more pointers */ 103 0, 0, 0, 104 0, 0, 0 105 }, 106 107 { /* sbus format--it's different on sun4u!! */ 108 "sbus", 109 sizeof (struct ddi_parent_private_data), 110 111 sizeof (struct regspec), /* first pointer */ 112 offsetof(struct ddi_parent_private_data, par_reg), 113 offsetof(struct ddi_parent_private_data, par_nreg), 114 115 sizeof (struct intrspec), /* second pointer */ 116 offsetof(struct ddi_parent_private_data, par_intr), 117 offsetof(struct ddi_parent_private_data, par_nintr), 118 119 sizeof (struct rangespec), /* third pointer */ 120 offsetof(struct ddi_parent_private_data, par_rng), 121 offsetof(struct ddi_parent_private_data, par_nrng), 122 123 0, 0, 0, /* no more pointers */ 124 0, 0, 0 125 } 126 }; 127 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} 132 }; 133 134 static int nprt_priv_data = sizeof (prt_priv_data)/sizeof (struct priv_data); 135 136 void 137 init_priv_data(struct di_priv_data *fetch) 138 { 139 /* no driver private data */ 140 fetch->version = DI_PRIVDATA_VERSION_0; 141 fetch->n_driver = 0; 142 fetch->driver = NULL; 143 144 fetch->n_parent = nprt_priv_data; 145 fetch->parent = ppd_format; 146 } 147 148 static void 149 obio_printregs(struct regspec *rp, int ilev) 150 { 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); 154 } 155 156 static void 157 obio_printranges(struct rangespec *rp, int ilev) 158 { 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, 163 rp->rng_size); 164 } 165 166 static void 167 obio_printintr(struct intrspec *ip, int ilev) 168 { 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); 175 (void) printf("\n"); 176 } 177 178 static void 179 obio_print(uintptr_t data, int ilev) 180 { 181 int i, nreg, nrng, nintr; 182 struct ddi_parent_private_data *dp; 183 struct regspec *reg; 184 struct intrspec *intr; 185 struct rangespec *rng; 186 187 dp = (struct ddi_parent_private_data *)data; 188 #ifdef DEBUG 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))); 194 #endif /* DEBUG */ 195 nreg = dp->par_nreg; 196 nintr = dp->par_nintr; 197 nrng = dp->par_nrng; 198 199 /* 200 * All pointers are translated to di_off_t by the devinfo driver. 201 * This is a private agreement between libdevinfo and prtconf. 202 */ 203 if (nreg != 0) { 204 indent_to_level(ilev); 205 (void) printf("Register Specifications:\n"); 206 207 reg = (struct regspec *)(data + *(di_off_t *)(&dp->par_reg)); 208 for (i = 0; i < nreg; ++i) 209 obio_printregs(reg + i, ilev); 210 } 211 212 if (nrng != 0) { 213 indent_to_level(ilev); 214 (void) printf("Range Specifications:\n"); 215 216 rng = (struct rangespec *)(data + *(di_off_t *)(&dp->par_rng)); 217 for (i = 0; i < nrng; ++i) 218 obio_printranges(rng + i, ilev); 219 } 220 221 if (nintr != 0) { 222 indent_to_level(ilev); 223 (void) printf("Interrupt Specifications:\n"); 224 225 intr = (struct intrspec *)(data + *(di_off_t *)(&dp->par_intr)); 226 for (i = 0; i < nintr; ++i) 227 obio_printintr(intr + i, ilev); 228 } 229 } 230 231 static void 232 pcmcia_printregs(struct pcm_regs *rp, int ilev) 233 { 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); 237 } 238 239 static void 240 pcmcia_printintr(struct intrspec *ip, int ilev) 241 { 242 obio_printintr(ip, ilev); 243 } 244 245 static void 246 pcmcia_print(uintptr_t data, int ilev) 247 { 248 int i, nreg, nintr; 249 struct pcmcia_parent_private *dp; 250 struct pcm_regs *reg; 251 struct intrspec *intr; 252 253 dp = (struct pcmcia_parent_private *)data; 254 #ifdef DEBUG 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)); 259 #endif /* DEBUG */ 260 nreg = dp->ppd_nreg; 261 nintr = dp->ppd_intr; 262 263 /* 264 * All pointers are translated to di_off_t by the devinfo driver. 265 * This is a private agreement between libdevinfo and prtconf. 266 */ 267 if (nreg != 0) { 268 indent_to_level(ilev); 269 (void) printf("Register Specifications:\n"); 270 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); 274 } 275 276 if (nintr != 0) { 277 indent_to_level(ilev); 278 (void) printf("Interrupt Specifications:\n"); 279 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); 284 } 285 } 286 287 static void 288 sbus_print(uintptr_t data, int ilev) 289 { 290 int i, nreg, nrng, nintr; 291 struct ddi_parent_private_data *dp; 292 struct regspec *reg; 293 struct intrspec *intr; 294 struct rangespec *rng; 295 296 dp = (struct ddi_parent_private_data *)data; 297 #ifdef DEBUG 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))); 303 #endif /* DEBUG */ 304 nreg = dp->par_nreg; 305 nintr = dp->par_nintr; 306 nrng = dp->par_nrng; 307 308 /* 309 * All pointers are translated to di_off_t by the devinfo driver. 310 * This is a private agreement between libdevinfo and prtconf. 311 */ 312 if (nreg != 0) { 313 indent_to_level(ilev); 314 (void) printf("Register Specifications:\n"); 315 316 reg = (struct regspec *)(data + *(di_off_t *)(&dp->par_reg)); 317 for (i = 0; i < nreg; ++i) 318 obio_printregs(reg + i, ilev); 319 } 320 321 322 if (nrng != 0) { 323 indent_to_level(ilev); 324 (void) printf("Range Specifications:\n"); 325 326 rng = (struct rangespec *)(data + *(di_off_t *)(&dp->par_rng)); 327 for (i = 0; i < nrng; ++i) 328 obio_printranges(rng + i, ilev); 329 } 330 331 /* 332 * To print interrupt property for children of sbus on sun4u requires 333 * definitions in sysiosbus.h. 334 * 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. 339 */ 340 if ((nintr != 0) && (strcmp(opts.o_uts.machine, "sun4u") != 0)) { 341 indent_to_level(ilev); 342 (void) printf("Interrupt Specifications:\n"); 343 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); 348 } 349 } 350 } 351 352 static struct priv_data * 353 match_priv_data(di_node_t node) 354 { 355 int i; 356 size_t len; 357 char *drv_name, *tmp; 358 di_node_t parent; 359 struct priv_data *pdp; 360 361 if ((parent = di_parent_node(node)) == DI_NODE_NIL) 362 return (NULL); 363 364 if ((drv_name = di_driver_name(parent)) == NULL) 365 return (NULL); 366 367 pdp = prt_priv_data; 368 len = strlen(drv_name); 369 for (i = 0; i < nprt_priv_data; ++i, ++pdp) { 370 tmp = pdp->drv_name; 371 while (tmp && (*tmp != '\0')) { 372 if (strncmp(tmp, drv_name, len) == 0) { 373 #ifdef DEBUG 374 dprintf("matched parent private data" 375 " at Node <%s> parent driver <%s>\n", 376 di_node_name(node), drv_name); 377 #endif /* DEBUG */ 378 return (pdp); 379 } 380 /* 381 * skip a white space 382 */ 383 if (tmp = strchr(tmp, ' ')) 384 tmp++; 385 } 386 } 387 388 return (NULL); 389 } 390 391 void 392 dump_priv_data(int ilev, di_node_t node) 393 { 394 uintptr_t priv; 395 struct priv_data *pdp; 396 397 if ((priv = (uintptr_t)di_parent_private_data(node)) == NULL) 398 return; 399 400 if ((pdp = match_priv_data(node)) == NULL) { 401 #ifdef DEBUG 402 dprintf("Error: parent private data format unknown\n"); 403 #endif /* DEBUG */ 404 return; 405 } 406 407 pdp->pd_print(priv, ilev); 408 409 /* ignore driver private data for now */ 410 } 411