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