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 eisa esp fas fhc glm iommu isa" 69 " isp mc pci pci_pci pln rootnex" 70 " sf socal", 71 sizeof (struct ddi_parent_private_data), 72 73 sizeof (struct regspec), /* first pointer */ 74 offsetof(struct ddi_parent_private_data, par_reg), 75 offsetof(struct ddi_parent_private_data, par_nreg), 76 77 sizeof (struct intrspec), /* second pointer */ 78 offsetof(struct ddi_parent_private_data, par_intr), 79 offsetof(struct ddi_parent_private_data, par_nintr), 80 81 sizeof (struct rangespec), /* third pointer */ 82 offsetof(struct ddi_parent_private_data, par_rng), 83 offsetof(struct ddi_parent_private_data, par_nrng), 84 85 0, 0, 0, /* no more pointers */ 86 0, 0, 0 87 }, 88 89 { /* pcmcia format */ 90 "pcic stp4020", 91 sizeof (struct pcmcia_parent_private), 92 93 sizeof (struct pcm_regs), /* first pointer */ 94 offsetof(struct pcmcia_parent_private, ppd_reg), 95 offsetof(struct pcmcia_parent_private, ppd_nreg), 96 97 sizeof (struct intrspec), /* second pointer */ 98 offsetof(struct pcmcia_parent_private, ppd_intrspec), 99 offsetof(struct pcmcia_parent_private, ppd_intr), 100 101 0, 0, 0, /* no more pointers */ 102 0, 0, 0, 103 0, 0, 0 104 }, 105 106 { /* sbus format--it's different on sun4u!! */ 107 "sbus", 108 sizeof (struct ddi_parent_private_data), 109 110 sizeof (struct regspec), /* first pointer */ 111 offsetof(struct ddi_parent_private_data, par_reg), 112 offsetof(struct ddi_parent_private_data, par_nreg), 113 114 sizeof (struct intrspec), /* second pointer */ 115 offsetof(struct ddi_parent_private_data, par_intr), 116 offsetof(struct ddi_parent_private_data, par_nintr), 117 118 sizeof (struct rangespec), /* third pointer */ 119 offsetof(struct ddi_parent_private_data, par_rng), 120 offsetof(struct ddi_parent_private_data, par_nrng), 121 122 0, 0, 0, /* no more pointers */ 123 0, 0, 0 124 } 125 }; 126 127 static struct priv_data prt_priv_data[] = { 128 { ppd_format[0].drv_name, obio_print}, 129 { ppd_format[1].drv_name, pcmcia_print}, 130 { ppd_format[2].drv_name, sbus_print} 131 }; 132 133 static int nprt_priv_data = sizeof (prt_priv_data)/sizeof (struct priv_data); 134 135 void 136 init_priv_data(struct di_priv_data *fetch) 137 { 138 /* no driver private data */ 139 fetch->version = DI_PRIVDATA_VERSION_0; 140 fetch->n_driver = 0; 141 fetch->driver = NULL; 142 143 fetch->n_parent = nprt_priv_data; 144 fetch->parent = ppd_format; 145 } 146 147 static void 148 obio_printregs(struct regspec *rp, int ilev) 149 { 150 indent_to_level(ilev); 151 (void) printf(" Bus Type=0x%x, Address=0x%x, Size=0x%x\n", 152 rp->regspec_bustype, rp->regspec_addr, rp->regspec_size); 153 } 154 155 static void 156 obio_printranges(struct rangespec *rp, int ilev) 157 { 158 indent_to_level(ilev); 159 (void) printf(" Ch: %.2x,%.8x Pa: %.2x,%.8x, Sz: %x\n", 160 rp->rng_cbustype, rp->rng_coffset, 161 rp->rng_bustype, rp->rng_offset, 162 rp->rng_size); 163 } 164 165 static void 166 obio_printintr(struct intrspec *ip, int ilev) 167 { 168 indent_to_level(ilev); 169 (void) printf(" Interrupt Priority=0x%x (ipl %d)", 170 ip->intrspec_pri, INT_IPL(ip->intrspec_pri)); 171 if (ip->intrspec_vec) 172 (void) printf(", vector=0x%x (%d)", 173 ip->intrspec_vec, ip->intrspec_vec); 174 (void) printf("\n"); 175 } 176 177 static void 178 obio_print(uintptr_t data, int ilev) 179 { 180 int i, nreg, nrng, nintr; 181 struct ddi_parent_private_data *dp; 182 struct regspec *reg; 183 struct intrspec *intr; 184 struct rangespec *rng; 185 186 dp = (struct ddi_parent_private_data *)data; 187 #ifdef DEBUG 188 dprintf("obio parent private data: nreg = 0x%x offset = 0x%x" 189 " nintr = 0x%x offset = 0x%x nrng = 0x%x offset = %x\n", 190 dp->par_nreg, *((di_off_t *)(&dp->par_reg)), 191 dp->par_nintr, *((di_off_t *)(&dp->par_intr)), 192 dp->par_nrng, *((di_off_t *)(&dp->par_rng))); 193 #endif /* DEBUG */ 194 nreg = dp->par_nreg; 195 nintr = dp->par_nintr; 196 nrng = dp->par_nrng; 197 198 /* 199 * All pointers are translated to di_off_t by the devinfo driver. 200 * This is a private agreement between libdevinfo and prtconf. 201 */ 202 if (nreg != 0) { 203 indent_to_level(ilev); 204 (void) printf("Register Specifications:\n"); 205 206 reg = (struct regspec *)(data + *(di_off_t *)(&dp->par_reg)); 207 for (i = 0; i < nreg; ++i) 208 obio_printregs(reg + i, ilev); 209 } 210 211 if (nrng != 0) { 212 indent_to_level(ilev); 213 (void) printf("Range Specifications:\n"); 214 215 rng = (struct rangespec *)(data + *(di_off_t *)(&dp->par_rng)); 216 for (i = 0; i < nrng; ++i) 217 obio_printranges(rng + i, ilev); 218 } 219 220 if (nintr != 0) { 221 indent_to_level(ilev); 222 (void) printf("Interrupt Specifications:\n"); 223 224 intr = (struct intrspec *)(data + *(di_off_t *)(&dp->par_intr)); 225 for (i = 0; i < nintr; ++i) 226 obio_printintr(intr + i, ilev); 227 } 228 } 229 230 static void 231 pcmcia_printregs(struct pcm_regs *rp, int ilev) 232 { 233 indent_to_level(ilev); 234 (void) printf(" Phys hi=0x%x, Phys lo=0x%x, Phys len=%x\n", 235 rp->phys_hi, rp->phys_lo, rp->phys_len); 236 } 237 238 static void 239 pcmcia_printintr(struct intrspec *ip, int ilev) 240 { 241 obio_printintr(ip, ilev); 242 } 243 244 static void 245 pcmcia_print(uintptr_t data, int ilev) 246 { 247 int i, nreg, nintr; 248 struct pcmcia_parent_private *dp; 249 struct pcm_regs *reg; 250 struct intrspec *intr; 251 252 dp = (struct pcmcia_parent_private *)data; 253 #ifdef DEBUG 254 dprintf("pcmcia parent private data: nreg = 0x%x offset = 0x%x" 255 " intr = 0x%x offset = %x\n", 256 dp->ppd_nreg, *(di_off_t *)(&dp->ppd_reg), 257 dp->ppd_intr, *(di_off_t *)(&dp->ppd_intrspec)); 258 #endif /* DEBUG */ 259 nreg = dp->ppd_nreg; 260 nintr = dp->ppd_intr; 261 262 /* 263 * All pointers are translated to di_off_t by the devinfo driver. 264 * This is a private agreement between libdevinfo and prtconf. 265 */ 266 if (nreg != 0) { 267 indent_to_level(ilev); 268 (void) printf("Register Specifications:\n"); 269 270 reg = (struct pcm_regs *)(data + *(di_off_t *)(&dp->ppd_reg)); 271 for (i = 0; i < nreg; ++i) 272 pcmcia_printregs(reg + i, ilev); 273 } 274 275 if (nintr != 0) { 276 indent_to_level(ilev); 277 (void) printf("Interrupt Specifications:\n"); 278 279 intr = (struct intrspec *) 280 (data + *(di_off_t *)(&dp->ppd_intrspec)); 281 for (i = 0; i < nintr; ++i) 282 pcmcia_printintr(intr + i, ilev); 283 } 284 } 285 286 static void 287 sbus_print(uintptr_t data, int ilev) 288 { 289 int i, nreg, nrng, nintr; 290 struct ddi_parent_private_data *dp; 291 struct regspec *reg; 292 struct intrspec *intr; 293 struct rangespec *rng; 294 295 dp = (struct ddi_parent_private_data *)data; 296 #ifdef DEBUG 297 dprintf("sbus parent private data: nreg = 0x%x offset = 0x%x" 298 " nintr = 0x%x offset = 0x%x nrng = 0x%x offset = %x\n", 299 dp->par_nreg, *((di_off_t *)(&dp->par_reg)), 300 dp->par_nintr, *((di_off_t *)(&dp->par_intr)), 301 dp->par_nrng, *((di_off_t *)(&dp->par_rng))); 302 #endif /* DEBUG */ 303 nreg = dp->par_nreg; 304 nintr = dp->par_nintr; 305 nrng = dp->par_nrng; 306 307 /* 308 * All pointers are translated to di_off_t by the devinfo driver. 309 * This is a private agreement between libdevinfo and prtconf. 310 */ 311 if (nreg != 0) { 312 indent_to_level(ilev); 313 (void) printf("Register Specifications:\n"); 314 315 reg = (struct regspec *)(data + *(di_off_t *)(&dp->par_reg)); 316 for (i = 0; i < nreg; ++i) 317 obio_printregs(reg + i, ilev); 318 } 319 320 321 if (nrng != 0) { 322 indent_to_level(ilev); 323 (void) printf("Range Specifications:\n"); 324 325 rng = (struct rangespec *)(data + *(di_off_t *)(&dp->par_rng)); 326 for (i = 0; i < nrng; ++i) 327 obio_printranges(rng + i, ilev); 328 } 329 330 /* 331 * To print interrupt property for children of sbus on sun4u requires 332 * definitions in sysiosbus.h. 333 * 334 * We can't #include <sys/sysiosbus.h> to have the build work on 335 * non sun4u machines. It's not right either to 336 * #include "../../uts/sun4u/sys/sysiosbus.h" 337 * As a result, we will not print the information. 338 */ 339 if ((nintr != 0) && (strcmp(opts.o_uts.machine, "sun4u") != 0)) { 340 indent_to_level(ilev); 341 (void) printf("Interrupt Specifications:\n"); 342 343 for (i = 0; i < nintr; ++i) { 344 intr = (struct intrspec *) 345 (data + *(di_off_t *)(&dp->par_intr)); 346 obio_printintr(intr + i, ilev); 347 } 348 } 349 } 350 351 static struct priv_data * 352 match_priv_data(di_node_t node) 353 { 354 int i; 355 size_t len; 356 char *drv_name, *tmp; 357 di_node_t parent; 358 struct priv_data *pdp; 359 360 if ((parent = di_parent_node(node)) == DI_NODE_NIL) 361 return (NULL); 362 363 if ((drv_name = di_driver_name(parent)) == NULL) 364 return (NULL); 365 366 pdp = prt_priv_data; 367 len = strlen(drv_name); 368 for (i = 0; i < nprt_priv_data; ++i, ++pdp) { 369 tmp = pdp->drv_name; 370 while (tmp && (*tmp != '\0')) { 371 if (strncmp(tmp, drv_name, len) == 0) { 372 #ifdef DEBUG 373 dprintf("matched parent private data" 374 " at Node <%s> parent driver <%s>\n", 375 di_node_name(node), drv_name); 376 #endif /* DEBUG */ 377 return (pdp); 378 } 379 /* 380 * skip a white space 381 */ 382 if (tmp = strchr(tmp, ' ')) 383 tmp++; 384 } 385 } 386 387 return (NULL); 388 } 389 390 void 391 dump_priv_data(int ilev, di_node_t node) 392 { 393 uintptr_t priv; 394 struct priv_data *pdp; 395 396 if ((priv = (uintptr_t)di_parent_private_data(node)) == NULL) 397 return; 398 399 if ((pdp = match_priv_data(node)) == NULL) { 400 #ifdef DEBUG 401 dprintf("Error: parent private data format unknown\n"); 402 #endif /* DEBUG */ 403 return; 404 } 405 406 pdp->pd_print(priv, ilev); 407 408 /* ignore driver private data for now */ 409 } 410