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 /* 23 * Copyright 2006 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 /* 30 * sun4 specific DDI implementation 31 */ 32 #include <sys/cpuvar.h> 33 #include <sys/ddi_subrdefs.h> 34 #include <sys/machsystm.h> 35 #include <sys/sunndi.h> 36 #include <sys/sysmacros.h> 37 #include <sys/ontrap.h> 38 #include <vm/seg_kmem.h> 39 #include <sys/membar.h> 40 #include <sys/dditypes.h> 41 #include <sys/ndifm.h> 42 #include <sys/fm/io/ddi.h> 43 #include <sys/ivintr.h> 44 #include <sys/bootconf.h> 45 #include <sys/conf.h> 46 #include <sys/ethernet.h> 47 #include <sys/idprom.h> 48 #include <sys/promif.h> 49 #include <sys/prom_plat.h> 50 #include <sys/systeminfo.h> 51 #include <sys/fpu/fpusystm.h> 52 #include <sys/vm.h> 53 #include <sys/fs/dv_node.h> 54 #include <sys/fs/snode.h> 55 #include <sys/ddi_isa.h> 56 #include <sys/modhash.h> 57 58 dev_info_t *get_intr_parent(dev_info_t *, dev_info_t *, 59 ddi_intr_handle_impl_t *); 60 #pragma weak get_intr_parent 61 62 int process_intr_ops(dev_info_t *, dev_info_t *, ddi_intr_op_t, 63 ddi_intr_handle_impl_t *, void *); 64 #pragma weak process_intr_ops 65 66 void cells_1275_copy(prop_1275_cell_t *, prop_1275_cell_t *, int32_t); 67 prop_1275_cell_t *cells_1275_cmp(prop_1275_cell_t *, prop_1275_cell_t *, 68 int32_t len); 69 #pragma weak cells_1275_copy 70 71 /* 72 * Wrapper for ddi_prop_lookup_int_array(). 73 * This is handy because it returns the prop length in 74 * bytes which is what most of the callers require. 75 */ 76 77 static int 78 get_prop_int_array(dev_info_t *di, char *pname, int **pval, uint_t *plen) 79 { 80 int ret; 81 82 if ((ret = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, di, 83 DDI_PROP_DONTPASS, pname, pval, plen)) == DDI_PROP_SUCCESS) { 84 *plen = (*plen) * (uint_t)sizeof (int); 85 } 86 return (ret); 87 } 88 89 /* 90 * SECTION: DDI Node Configuration 91 */ 92 93 /* 94 * init_regspec_64: 95 * 96 * If the parent #size-cells is 2, convert the upa-style or 97 * safari-style reg property from 2-size cells to 1 size cell 98 * format, ignoring the size_hi, which must be zero for devices. 99 * (It won't be zero in the memory list properties in the memory 100 * nodes, but that doesn't matter here.) 101 */ 102 struct ddi_parent_private_data * 103 init_regspec_64(dev_info_t *dip) 104 { 105 struct ddi_parent_private_data *pd; 106 dev_info_t *parent; 107 int size_cells; 108 109 /* 110 * If there are no "reg"s in the child node, return. 111 */ 112 pd = ddi_get_parent_data(dip); 113 if ((pd == NULL) || (pd->par_nreg == 0)) { 114 return (pd); 115 } 116 parent = ddi_get_parent(dip); 117 118 size_cells = ddi_prop_get_int(DDI_DEV_T_ANY, parent, 119 DDI_PROP_DONTPASS, "#size-cells", 1); 120 121 if (size_cells != 1) { 122 123 int n, j; 124 struct regspec *irp; 125 struct reg_64 { 126 uint_t addr_hi, addr_lo, size_hi, size_lo; 127 }; 128 struct reg_64 *r64_rp; 129 struct regspec *rp; 130 uint_t len = 0; 131 int *reg_prop; 132 133 ASSERT(size_cells == 2); 134 135 /* 136 * We already looked the property up once before if 137 * pd is non-NULL. 138 */ 139 (void) ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, 140 DDI_PROP_DONTPASS, OBP_REG, ®_prop, &len); 141 ASSERT(len != 0); 142 143 n = sizeof (struct reg_64) / sizeof (int); 144 n = len / n; 145 146 /* 147 * We're allocating a buffer the size of the PROM's property, 148 * but we're only using a smaller portion when we assign it 149 * to a regspec. We do this so that in the 150 * impl_ddi_sunbus_removechild function, we will 151 * always free the right amount of memory. 152 */ 153 irp = rp = (struct regspec *)reg_prop; 154 r64_rp = (struct reg_64 *)pd->par_reg; 155 156 for (j = 0; j < n; ++j, ++rp, ++r64_rp) { 157 ASSERT(r64_rp->size_hi == 0); 158 rp->regspec_bustype = r64_rp->addr_hi; 159 rp->regspec_addr = r64_rp->addr_lo; 160 rp->regspec_size = r64_rp->size_lo; 161 } 162 163 ddi_prop_free((void *)pd->par_reg); 164 pd->par_nreg = n; 165 pd->par_reg = irp; 166 } 167 return (pd); 168 } 169 170 /* 171 * Create a ddi_parent_private_data structure from the ddi properties of 172 * the dev_info node. 173 * 174 * The "reg" is required if the driver wishes to create mappings on behalf 175 * of the device. The "reg" property is assumed to be a list of at least 176 * one triplet 177 * 178 * <bustype, address, size>*1 179 * 180 * The "interrupt" property is no longer part of parent private data on 181 * sun4u. The interrupt parent is may not be the device tree parent. 182 * 183 * The "ranges" property describes the mapping of child addresses to parent 184 * addresses. 185 * 186 * N.B. struct rangespec is defined for the following default values: 187 * parent child 188 * #address-cells 2 2 189 * #size-cells 1 1 190 * This function doesn't deal with non-default cells and will not create 191 * ranges in such cases. 192 */ 193 void 194 make_ddi_ppd(dev_info_t *child, struct ddi_parent_private_data **ppd) 195 { 196 struct ddi_parent_private_data *pdptr; 197 int *reg_prop, *rng_prop; 198 uint_t reg_len = 0, rng_len = 0; 199 dev_info_t *parent; 200 int parent_addr_cells, parent_size_cells; 201 int child_addr_cells, child_size_cells; 202 203 *ppd = pdptr = kmem_zalloc(sizeof (*pdptr), KM_SLEEP); 204 205 /* 206 * root node has no parent private data, so *ppd should 207 * be initialized for naming to work properly. 208 */ 209 if ((parent = ddi_get_parent(child)) == NULL) 210 return; 211 212 /* 213 * Set reg field of parent data from "reg" property 214 */ 215 if ((get_prop_int_array(child, OBP_REG, ®_prop, ®_len) 216 == DDI_PROP_SUCCESS) && (reg_len != 0)) { 217 pdptr->par_nreg = (int)(reg_len / sizeof (struct regspec)); 218 pdptr->par_reg = (struct regspec *)reg_prop; 219 } 220 221 /* 222 * "ranges" property ... 223 * 224 * This function does not handle cases where #address-cells != 2 225 * and * min(parent, child) #size-cells != 1 (see bugid 4211124). 226 * 227 * Nexus drivers with such exceptions (e.g. pci ranges) 228 * should either create a separate function for handling 229 * ranges or not use parent private data to store ranges. 230 */ 231 232 /* root node has no ranges */ 233 if ((parent = ddi_get_parent(child)) == NULL) 234 return; 235 236 child_addr_cells = ddi_prop_get_int(DDI_DEV_T_ANY, child, 237 DDI_PROP_DONTPASS, "#address-cells", 2); 238 child_size_cells = ddi_prop_get_int(DDI_DEV_T_ANY, child, 239 DDI_PROP_DONTPASS, "#size-cells", 1); 240 parent_addr_cells = ddi_prop_get_int(DDI_DEV_T_ANY, parent, 241 DDI_PROP_DONTPASS, "#address-cells", 2); 242 parent_size_cells = ddi_prop_get_int(DDI_DEV_T_ANY, parent, 243 DDI_PROP_DONTPASS, "#size-cells", 1); 244 if (child_addr_cells != 2 || parent_addr_cells != 2 || 245 (child_size_cells != 1 && parent_size_cells != 1)) { 246 NDI_CONFIG_DEBUG((CE_NOTE, "!ranges not made in parent data; " 247 "#address-cells or #size-cells have non-default value")); 248 return; 249 } 250 251 if (get_prop_int_array(child, OBP_RANGES, &rng_prop, &rng_len) 252 == DDI_PROP_SUCCESS) { 253 pdptr->par_nrng = rng_len / (int)(sizeof (struct rangespec)); 254 pdptr->par_rng = (struct rangespec *)rng_prop; 255 } 256 } 257 258 /* 259 * Free ddi_parent_private_data structure 260 */ 261 void 262 impl_free_ddi_ppd(dev_info_t *dip) 263 { 264 struct ddi_parent_private_data *pdptr = ddi_get_parent_data(dip); 265 266 if (pdptr == NULL) 267 return; 268 269 if (pdptr->par_nrng != 0) 270 ddi_prop_free((void *)pdptr->par_rng); 271 272 if (pdptr->par_nreg != 0) 273 ddi_prop_free((void *)pdptr->par_reg); 274 275 kmem_free(pdptr, sizeof (*pdptr)); 276 ddi_set_parent_data(dip, NULL); 277 } 278 279 /* 280 * Name a child of sun busses based on the reg spec. 281 * Handles the following properties: 282 * 283 * Property value 284 * Name type 285 * 286 * reg register spec 287 * interrupts new (bus-oriented) interrupt spec 288 * ranges range spec 289 * 290 * This may be called multiple times, independent of 291 * initchild calls. 292 */ 293 static int 294 impl_sunbus_name_child(dev_info_t *child, char *name, int namelen) 295 { 296 struct ddi_parent_private_data *pdptr; 297 struct regspec *rp; 298 299 /* 300 * Fill in parent-private data and this function returns to us 301 * an indication if it used "registers" to fill in the data. 302 */ 303 if (ddi_get_parent_data(child) == NULL) { 304 make_ddi_ppd(child, &pdptr); 305 ddi_set_parent_data(child, pdptr); 306 } 307 308 /* 309 * No reg property, return null string as address 310 * (e.g. root node) 311 */ 312 name[0] = '\0'; 313 if (sparc_pd_getnreg(child) == 0) { 314 return (DDI_SUCCESS); 315 } 316 317 rp = sparc_pd_getreg(child, 0); 318 (void) snprintf(name, namelen, "%x,%x", 319 rp->regspec_bustype, rp->regspec_addr); 320 return (DDI_SUCCESS); 321 } 322 323 324 /* 325 * Called from the bus_ctl op of some drivers. 326 * to implement the DDI_CTLOPS_INITCHILD operation. 327 * 328 * NEW drivers should NOT use this function, but should declare 329 * there own initchild/uninitchild handlers. (This function assumes 330 * the layout of the parent private data and the format of "reg", 331 * "ranges", "interrupts" properties and that #address-cells and 332 * #size-cells of the parent bus are defined to be default values.) 333 */ 334 int 335 impl_ddi_sunbus_initchild(dev_info_t *child) 336 { 337 char name[MAXNAMELEN]; 338 339 (void) impl_sunbus_name_child(child, name, MAXNAMELEN); 340 ddi_set_name_addr(child, name); 341 342 /* 343 * Try to merge .conf node. If successful, return failure to 344 * remove this child. 345 */ 346 if ((ndi_dev_is_persistent_node(child) == 0) && 347 (ndi_merge_node(child, impl_sunbus_name_child) == DDI_SUCCESS)) { 348 impl_ddi_sunbus_removechild(child); 349 return (DDI_FAILURE); 350 } 351 return (DDI_SUCCESS); 352 } 353 354 /* 355 * A better name for this function would be impl_ddi_sunbus_uninitchild() 356 * It does not remove the child, it uninitializes it, reclaiming the 357 * resources taken by impl_ddi_sunbus_initchild. 358 */ 359 void 360 impl_ddi_sunbus_removechild(dev_info_t *dip) 361 { 362 impl_free_ddi_ppd(dip); 363 ddi_set_name_addr(dip, NULL); 364 /* 365 * Strip the node to properly convert it back to prototype form 366 */ 367 impl_rem_dev_props(dip); 368 } 369 370 /* 371 * SECTION: DDI Interrupt 372 */ 373 374 void 375 cells_1275_copy(prop_1275_cell_t *from, prop_1275_cell_t *to, int32_t len) 376 { 377 int i; 378 for (i = 0; i < len; i++) 379 *to = *from; 380 } 381 382 prop_1275_cell_t * 383 cells_1275_cmp(prop_1275_cell_t *cell1, prop_1275_cell_t *cell2, int32_t len) 384 { 385 prop_1275_cell_t *match_cell = 0; 386 int32_t i; 387 388 for (i = 0; i < len; i++) 389 if (cell1[i] != cell2[i]) { 390 match_cell = &cell1[i]; 391 break; 392 } 393 394 return (match_cell); 395 } 396 397 /* 398 * get_intr_parent() is a generic routine that process a 1275 interrupt 399 * map (imap) property. This function returns a dev_info_t structure 400 * which claims ownership of the interrupt domain. 401 * It also returns the new interrupt translation within this new domain. 402 * If an interrupt-parent or interrupt-map property are not found, 403 * then we fallback to using the device tree's parent. 404 * 405 * imap entry format: 406 * <reg>,<interrupt>,<phandle>,<translated interrupt> 407 * reg - The register specification in the interrupts domain 408 * interrupt - The interrupt specification 409 * phandle - PROM handle of the device that owns the xlated interrupt domain 410 * translated interrupt - interrupt specifier in the parents domain 411 * note: <reg>,<interrupt> - The reg and interrupt can be combined to create 412 * a unique entry called a unit interrupt specifier. 413 * 414 * Here's the processing steps: 415 * step1 - If the interrupt-parent property exists, create the ispec and 416 * return the dip of the interrupt parent. 417 * step2 - Extract the interrupt-map property and the interrupt-map-mask 418 * If these don't exist, just return the device tree parent. 419 * step3 - build up the unit interrupt specifier to match against the 420 * interrupt map property 421 * step4 - Scan the interrupt-map property until a match is found 422 * step4a - Extract the interrupt parent 423 * step4b - Compare the unit interrupt specifier 424 */ 425 dev_info_t * 426 get_intr_parent(dev_info_t *pdip, dev_info_t *dip, ddi_intr_handle_impl_t *hdlp) 427 { 428 prop_1275_cell_t *imap, *imap_mask, *scan, *reg_p, *match_req; 429 int32_t imap_sz, imap_cells, imap_scan_cells, imap_mask_sz, 430 addr_cells, intr_cells, reg_len, i, j; 431 int32_t match_found = 0; 432 dev_info_t *intr_parent_dip = NULL; 433 uint32_t *intr = &hdlp->ih_vector; 434 uint32_t nodeid; 435 #ifdef DEBUG 436 static int debug = 0; 437 #endif 438 439 /* 440 * step1 441 * If we have an interrupt-parent property, this property represents 442 * the nodeid of our interrupt parent. 443 */ 444 if ((nodeid = ddi_getprop(DDI_DEV_T_ANY, dip, 0, 445 "interrupt-parent", -1)) != -1) { 446 intr_parent_dip = e_ddi_nodeid_to_dip(nodeid); 447 ASSERT(intr_parent_dip); 448 449 /* 450 * Attach the interrupt parent. 451 * 452 * N.B. e_ddi_nodeid_to_dip() isn't safe under DR. 453 * Also, interrupt parent isn't held. This needs 454 * to be revisited if DR-capable platforms implement 455 * interrupt redirection. 456 */ 457 if (i_ddi_attach_node_hierarchy(intr_parent_dip) 458 != DDI_SUCCESS) { 459 ndi_rele_devi(intr_parent_dip); 460 return (NULL); 461 } 462 463 return (intr_parent_dip); 464 } 465 466 /* 467 * step2 468 * Get interrupt map structure from PROM property 469 */ 470 if (ddi_getlongprop(DDI_DEV_T_ANY, pdip, DDI_PROP_DONTPASS, 471 "interrupt-map", (caddr_t)&imap, &imap_sz) 472 != DDI_PROP_SUCCESS) { 473 /* 474 * If we don't have an imap property, default to using the 475 * device tree. 476 */ 477 478 ndi_hold_devi(pdip); 479 return (pdip); 480 } 481 482 /* Get the interrupt mask property */ 483 if (ddi_getlongprop(DDI_DEV_T_ANY, pdip, DDI_PROP_DONTPASS, 484 "interrupt-map-mask", (caddr_t)&imap_mask, &imap_mask_sz) 485 != DDI_PROP_SUCCESS) { 486 /* 487 * If we don't find this property, we have to fail the request 488 * because the 1275 imap property wasn't defined correctly. 489 */ 490 ASSERT(intr_parent_dip == NULL); 491 goto exit2; 492 } 493 494 /* Get the address cell size */ 495 addr_cells = ddi_getprop(DDI_DEV_T_ANY, pdip, 0, 496 "#address-cells", 2); 497 498 /* Get the interrupts cell size */ 499 intr_cells = ddi_getprop(DDI_DEV_T_ANY, pdip, 0, 500 "#interrupt-cells", 1); 501 502 /* 503 * step3 504 * Now lets build up the unit interrupt specifier e.g. reg,intr 505 * and apply the imap mask. match_req will hold this when we're 506 * through. 507 */ 508 if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg", 509 (caddr_t)®_p, ®_len) != DDI_SUCCESS) { 510 ASSERT(intr_parent_dip == NULL); 511 goto exit3; 512 } 513 514 match_req = kmem_alloc(CELLS_1275_TO_BYTES(addr_cells) + 515 CELLS_1275_TO_BYTES(intr_cells), KM_SLEEP); 516 517 for (i = 0; i < addr_cells; i++) 518 match_req[i] = (reg_p[i] & imap_mask[i]); 519 520 for (j = 0; j < intr_cells; i++, j++) 521 match_req[i] = (intr[j] & imap_mask[i]); 522 523 /* Calculate the imap size in cells */ 524 imap_cells = BYTES_TO_1275_CELLS(imap_sz); 525 526 #ifdef DEBUG 527 if (debug) 528 prom_printf("reg cell size 0x%x, intr cell size 0x%x, " 529 "match_request 0x%p, imap 0x%p\n", addr_cells, intr_cells, 530 match_req, imap); 531 #endif 532 533 /* 534 * Scan the imap property looking for a match of the interrupt unit 535 * specifier. This loop is rather complex since the data within the 536 * imap property may vary in size. 537 */ 538 for (scan = imap, imap_scan_cells = i = 0; 539 imap_scan_cells < imap_cells; scan += i, imap_scan_cells += i) { 540 int new_intr_cells; 541 542 /* Set the index to the nodeid field */ 543 i = addr_cells + intr_cells; 544 545 /* 546 * step4a 547 * Translate the nodeid field to a dip 548 */ 549 ASSERT(intr_parent_dip == NULL); 550 intr_parent_dip = e_ddi_nodeid_to_dip((uint_t)scan[i++]); 551 552 ASSERT(intr_parent_dip != 0); 553 #ifdef DEBUG 554 if (debug) 555 prom_printf("scan 0x%p\n", scan); 556 #endif 557 /* 558 * The tmp_dip describes the new domain, get it's interrupt 559 * cell size 560 */ 561 new_intr_cells = ddi_getprop(DDI_DEV_T_ANY, intr_parent_dip, 0, 562 "#interrupts-cells", 1); 563 564 /* 565 * step4b 566 * See if we have a match on the interrupt unit specifier 567 */ 568 if (cells_1275_cmp(match_req, scan, addr_cells + intr_cells) 569 == 0) { 570 uint32_t *intr; 571 572 match_found = 1; 573 574 /* 575 * If we have an imap parent whose not in our device 576 * tree path, we need to hold and install that driver. 577 */ 578 if (i_ddi_attach_node_hierarchy(intr_parent_dip) 579 != DDI_SUCCESS) { 580 ndi_rele_devi(intr_parent_dip); 581 intr_parent_dip = (dev_info_t *)NULL; 582 goto exit4; 583 } 584 585 /* 586 * We need to handcraft an ispec along with a bus 587 * interrupt value, so we can dup it into our 588 * standard ispec structure. 589 */ 590 /* Extract the translated interrupt information */ 591 intr = kmem_alloc( 592 CELLS_1275_TO_BYTES(new_intr_cells), KM_SLEEP); 593 594 for (j = 0; j < new_intr_cells; j++, i++) 595 intr[j] = scan[i]; 596 597 cells_1275_copy(intr, &hdlp->ih_vector, new_intr_cells); 598 599 kmem_free(intr, CELLS_1275_TO_BYTES(new_intr_cells)); 600 601 #ifdef DEBUG 602 if (debug) 603 prom_printf("dip 0x%p\n", intr_parent_dip); 604 #endif 605 break; 606 } else { 607 #ifdef DEBUG 608 if (debug) 609 prom_printf("dip 0x%p\n", intr_parent_dip); 610 #endif 611 ndi_rele_devi(intr_parent_dip); 612 intr_parent_dip = NULL; 613 i += new_intr_cells; 614 } 615 } 616 617 /* 618 * If we haven't found our interrupt parent at this point, fallback 619 * to using the device tree. 620 */ 621 if (!match_found) { 622 ndi_hold_devi(pdip); 623 ASSERT(intr_parent_dip == NULL); 624 intr_parent_dip = pdip; 625 } 626 627 ASSERT(intr_parent_dip != NULL); 628 629 exit4: 630 kmem_free(reg_p, reg_len); 631 kmem_free(match_req, CELLS_1275_TO_BYTES(addr_cells) + 632 CELLS_1275_TO_BYTES(intr_cells)); 633 634 exit3: 635 kmem_free(imap_mask, imap_mask_sz); 636 637 exit2: 638 kmem_free(imap, imap_sz); 639 640 return (intr_parent_dip); 641 } 642 643 /* 644 * process_intr_ops: 645 * 646 * Process the interrupt op via the interrupt parent. 647 */ 648 int 649 process_intr_ops(dev_info_t *pdip, dev_info_t *rdip, ddi_intr_op_t op, 650 ddi_intr_handle_impl_t *hdlp, void *result) 651 { 652 int ret = DDI_FAILURE; 653 654 if (NEXUS_HAS_INTR_OP(pdip)) { 655 ret = (*(DEVI(pdip)->devi_ops->devo_bus_ops-> 656 bus_intr_op)) (pdip, rdip, op, hdlp, result); 657 } else { 658 cmn_err(CE_WARN, "Failed to process interrupt " 659 "for %s%d due to down-rev nexus driver %s%d", 660 ddi_get_name(rdip), ddi_get_instance(rdip), 661 ddi_get_name(pdip), ddi_get_instance(pdip)); 662 } 663 664 return (ret); 665 } 666 667 /*ARGSUSED*/ 668 uint_t 669 softlevel1(caddr_t arg) 670 { 671 softint(); 672 return (1); 673 } 674 675 /* 676 * indirection table, to save us some large switch statements 677 * NOTE: This must agree with "INTLEVEL_foo" constants in 678 * <sys/avintr.h> 679 */ 680 struct autovec *const vectorlist[] = { 0 }; 681 682 /* 683 * This value is exported here for the functions in avintr.c 684 */ 685 const uint_t maxautovec = (sizeof (vectorlist) / sizeof (vectorlist[0])); 686 687 /* 688 * Check for machine specific interrupt levels which cannot be reassigned by 689 * settrap(), sun4u version. 690 * 691 * sun4u does not support V8 SPARC "fast trap" handlers. 692 */ 693 /*ARGSUSED*/ 694 int 695 exclude_settrap(int lvl) 696 { 697 return (1); 698 } 699 700 /* 701 * Check for machine specific interrupt levels which cannot have interrupt 702 * handlers added. We allow levels 1 through 15; level 0 is nonsense. 703 */ 704 /*ARGSUSED*/ 705 int 706 exclude_level(int lvl) 707 { 708 return ((lvl < 1) || (lvl > 15)); 709 } 710 711 /* 712 * Wrapper functions used by New DDI interrupt framework. 713 */ 714 715 /* 716 * i_ddi_intr_ops: 717 */ 718 int 719 i_ddi_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t op, 720 ddi_intr_handle_impl_t *hdlp, void *result) 721 { 722 dev_info_t *pdip = ddi_get_parent(dip); 723 int ret = DDI_FAILURE; 724 725 /* 726 * The following check is required to address 727 * one of the test case of ADDI test suite. 728 */ 729 if (pdip == NULL) 730 return (DDI_FAILURE); 731 732 if (hdlp->ih_type != DDI_INTR_TYPE_FIXED) 733 return (process_intr_ops(pdip, rdip, op, hdlp, result)); 734 735 if (hdlp->ih_vector == 0) 736 hdlp->ih_vector = i_ddi_get_inum(rdip, hdlp->ih_inum); 737 738 if (hdlp->ih_pri == 0) 739 hdlp->ih_pri = i_ddi_get_intr_pri(rdip, hdlp->ih_inum); 740 741 switch (op) { 742 case DDI_INTROP_ADDISR: 743 case DDI_INTROP_REMISR: 744 case DDI_INTROP_ENABLE: 745 case DDI_INTROP_DISABLE: 746 case DDI_INTROP_BLOCKENABLE: 747 case DDI_INTROP_BLOCKDISABLE: 748 /* 749 * Try and determine our parent and possibly an interrupt 750 * translation. intr parent dip returned held 751 */ 752 if ((pdip = get_intr_parent(pdip, dip, hdlp)) == NULL) 753 goto done; 754 } 755 756 ret = process_intr_ops(pdip, rdip, op, hdlp, result); 757 758 done: 759 switch (op) { 760 case DDI_INTROP_ADDISR: 761 case DDI_INTROP_REMISR: 762 case DDI_INTROP_ENABLE: 763 case DDI_INTROP_DISABLE: 764 case DDI_INTROP_BLOCKENABLE: 765 case DDI_INTROP_BLOCKDISABLE: 766 /* Release hold acquired in get_intr_parent() */ 767 if (pdip) 768 ndi_rele_devi(pdip); 769 } 770 771 hdlp->ih_vector = 0; 772 773 return (ret); 774 } 775 776 /* 777 * i_ddi_add_ivintr: 778 */ 779 /*ARGSUSED*/ 780 int 781 i_ddi_add_ivintr(ddi_intr_handle_impl_t *hdlp) 782 { 783 /* Sanity check the entry we're about to add */ 784 if (GET_IVINTR(hdlp->ih_vector)) { 785 cmn_err(CE_WARN, "mondo 0x%x in use", hdlp->ih_vector); 786 return (DDI_FAILURE); 787 } 788 789 /* 790 * If the PIL was set and is valid use it, otherwise 791 * default it to 1 792 */ 793 if ((hdlp->ih_pri < 1) || (hdlp->ih_pri > PIL_MAX)) 794 hdlp->ih_pri = 1; 795 796 VERIFY(add_ivintr(hdlp->ih_vector, hdlp->ih_pri, 797 (intrfunc)hdlp->ih_cb_func, hdlp->ih_cb_arg1, NULL) == 0); 798 799 return (DDI_SUCCESS); 800 } 801 802 /* 803 * i_ddi_rem_ivintr: 804 */ 805 /*ARGSUSED*/ 806 void 807 i_ddi_rem_ivintr(ddi_intr_handle_impl_t *hdlp) 808 { 809 rem_ivintr(hdlp->ih_vector, NULL); 810 } 811 812 /* 813 * i_ddi_get_inum - Get the interrupt number property from the 814 * specified device. Note that this function is called only for 815 * the FIXED interrupt type. 816 */ 817 uint32_t 818 i_ddi_get_inum(dev_info_t *dip, uint_t inumber) 819 { 820 int32_t intrlen, intr_cells, max_intrs; 821 prop_1275_cell_t *ip, intr_sz; 822 uint32_t intr = 0; 823 824 if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS | 825 DDI_PROP_CANSLEEP, 826 "interrupts", (caddr_t)&ip, &intrlen) == DDI_SUCCESS) { 827 828 intr_cells = ddi_getprop(DDI_DEV_T_ANY, dip, 0, 829 "#interrupt-cells", 1); 830 831 /* adjust for number of bytes */ 832 intr_sz = CELLS_1275_TO_BYTES(intr_cells); 833 834 /* Calculate the number of interrupts */ 835 max_intrs = intrlen / intr_sz; 836 837 if (inumber < max_intrs) { 838 prop_1275_cell_t *intrp = ip; 839 840 /* Index into interrupt property */ 841 intrp += (inumber * intr_cells); 842 843 cells_1275_copy(intrp, &intr, intr_cells); 844 } 845 846 kmem_free(ip, intrlen); 847 } 848 849 return (intr); 850 } 851 852 /* 853 * i_ddi_get_intr_pri - Get the interrupt-priorities property from 854 * the specified device. Note that this function is called only for 855 * the FIXED interrupt type. 856 */ 857 uint32_t 858 i_ddi_get_intr_pri(dev_info_t *dip, uint_t inumber) 859 { 860 uint32_t *intr_prio_p; 861 uint32_t pri = 0; 862 int32_t i; 863 864 /* 865 * Use the "interrupt-priorities" property to determine the 866 * the pil/ipl for the interrupt handler. 867 */ 868 if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 869 "interrupt-priorities", (caddr_t)&intr_prio_p, 870 &i) == DDI_SUCCESS) { 871 if (inumber < (i / sizeof (int32_t))) 872 pri = intr_prio_p[inumber]; 873 kmem_free(intr_prio_p, i); 874 } 875 876 return (pri); 877 } 878 879 int 880 i_ddi_get_nintrs(dev_info_t *dip) 881 { 882 int32_t intrlen; 883 prop_1275_cell_t intr_sz; 884 prop_1275_cell_t *ip; 885 int32_t ret = 0; 886 887 if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS | 888 DDI_PROP_CANSLEEP, 889 "interrupts", (caddr_t)&ip, &intrlen) == DDI_SUCCESS) { 890 891 intr_sz = ddi_getprop(DDI_DEV_T_ANY, dip, 0, 892 "#interrupt-cells", 1); 893 /* adjust for number of bytes */ 894 intr_sz = CELLS_1275_TO_BYTES(intr_sz); 895 896 ret = intrlen / intr_sz; 897 898 kmem_free(ip, intrlen); 899 } 900 901 return (ret); 902 } 903 904 /* 905 * i_ddi_add_softint - allocate and add a soft interrupt to the system 906 */ 907 int 908 i_ddi_add_softint(ddi_softint_hdl_impl_t *hdlp) 909 { 910 uint_t rval; 911 912 if ((rval = add_softintr(hdlp->ih_pri, hdlp->ih_cb_func, 913 hdlp->ih_cb_arg1)) == 0) { 914 915 return (DDI_FAILURE); 916 } 917 918 /* use uintptr_t to suppress the gcc warning */ 919 hdlp->ih_private = (void *)(uintptr_t)rval; 920 921 return (DDI_SUCCESS); 922 } 923 924 void 925 i_ddi_remove_softint(ddi_softint_hdl_impl_t *hdlp) 926 { 927 uint_t intr_id; 928 929 /* disable */ 930 ASSERT(hdlp->ih_private != NULL); 931 932 /* use uintptr_t to suppress the gcc warning */ 933 intr_id = (uint_t)(uintptr_t)hdlp->ih_private; 934 935 rem_softintr(intr_id); 936 hdlp->ih_private = NULL; 937 } 938 939 int 940 i_ddi_trigger_softint(ddi_softint_hdl_impl_t *hdlp, void *arg2) 941 { 942 uint_t intr_id; 943 int ret; 944 945 ASSERT(hdlp != NULL); 946 ASSERT(hdlp->ih_private != NULL); 947 948 /* use uintptr_t to suppress the gcc warning */ 949 intr_id = (uint_t)(uintptr_t)hdlp->ih_private; 950 951 /* update the vector table for the 2nd arg */ 952 ret = update_softint_arg2(intr_id, arg2); 953 if (ret == DDI_SUCCESS) 954 setsoftint(intr_id); 955 956 return (ret); 957 } 958 959 /* ARGSUSED */ 960 int 961 i_ddi_set_softint_pri(ddi_softint_hdl_impl_t *hdlp, uint_t old_pri) 962 { 963 uint_t intr_id; 964 int ret; 965 966 ASSERT(hdlp != NULL); 967 ASSERT(hdlp->ih_private != NULL); 968 969 /* use uintptr_t to suppress the gcc warning */ 970 intr_id = (uint_t)(uintptr_t)hdlp->ih_private; 971 972 /* update the vector table for the new priority */ 973 ret = update_softint_pri(intr_id, hdlp->ih_pri); 974 975 return (ret); 976 } 977 978 /*ARGSUSED*/ 979 void 980 i_ddi_alloc_intr_phdl(ddi_intr_handle_impl_t *hdlp) 981 { 982 } 983 984 /*ARGSUSED*/ 985 void 986 i_ddi_free_intr_phdl(ddi_intr_handle_impl_t *hdlp) 987 { 988 } 989 990 /* 991 * SECTION: DDI Memory/DMA 992 */ 993 994 /* set HAT endianess attributes from ddi_device_acc_attr */ 995 void 996 i_ddi_devacc_to_hatacc(ddi_device_acc_attr_t *devaccp, uint_t *hataccp) 997 { 998 if (devaccp != NULL) { 999 if (devaccp->devacc_attr_endian_flags == DDI_STRUCTURE_LE_ACC) { 1000 *hataccp &= ~HAT_ENDIAN_MASK; 1001 *hataccp |= HAT_STRUCTURE_LE; 1002 } 1003 } 1004 } 1005 1006 /* 1007 * Check if the specified cache attribute is supported on the platform. 1008 * This function must be called before i_ddi_cacheattr_to_hatacc(). 1009 */ 1010 boolean_t 1011 i_ddi_check_cache_attr(uint_t flags) 1012 { 1013 /* 1014 * The cache attributes are mutually exclusive. Any combination of 1015 * the attributes leads to a failure. 1016 */ 1017 uint_t cache_attr = IOMEM_CACHE_ATTR(flags); 1018 if ((cache_attr != 0) && ((cache_attr & (cache_attr - 1)) != 0)) 1019 return (B_FALSE); 1020 1021 /* 1022 * On the sparc architecture, only IOMEM_DATA_CACHED is meaningful, 1023 * but others lead to a failure. 1024 */ 1025 if (cache_attr & IOMEM_DATA_CACHED) 1026 return (B_TRUE); 1027 else 1028 return (B_FALSE); 1029 } 1030 1031 /* set HAT cache attributes from the cache attributes */ 1032 void 1033 i_ddi_cacheattr_to_hatacc(uint_t flags, uint_t *hataccp) 1034 { 1035 uint_t cache_attr = IOMEM_CACHE_ATTR(flags); 1036 static char *fname = "i_ddi_cacheattr_to_hatacc"; 1037 #if defined(lint) 1038 *hataccp = *hataccp; 1039 #endif 1040 /* 1041 * set HAT attrs according to the cache attrs. 1042 */ 1043 switch (cache_attr) { 1044 /* 1045 * The cache coherency is always maintained on SPARC, and 1046 * nothing is required. 1047 */ 1048 case IOMEM_DATA_CACHED: 1049 break; 1050 /* 1051 * Both IOMEM_DATA_UC_WRITE_COMBINED and IOMEM_DATA_UNCACHED are 1052 * not supported on SPARC -- this case must not occur because the 1053 * cache attribute is scrutinized before this function is called. 1054 */ 1055 case IOMEM_DATA_UNCACHED: 1056 case IOMEM_DATA_UC_WR_COMBINE: 1057 default: 1058 cmn_err(CE_WARN, "%s: cache_attr=0x%x is ignored.", 1059 fname, cache_attr); 1060 } 1061 } 1062 1063 static vmem_t *little_endian_arena; 1064 static vmem_t *big_endian_arena; 1065 1066 static void * 1067 segkmem_alloc_le(vmem_t *vmp, size_t size, int flag) 1068 { 1069 return (segkmem_xalloc(vmp, NULL, size, flag, HAT_STRUCTURE_LE, 1070 segkmem_page_create, NULL)); 1071 } 1072 1073 static void * 1074 segkmem_alloc_be(vmem_t *vmp, size_t size, int flag) 1075 { 1076 return (segkmem_xalloc(vmp, NULL, size, flag, HAT_STRUCTURE_BE, 1077 segkmem_page_create, NULL)); 1078 } 1079 1080 void 1081 ka_init(void) 1082 { 1083 little_endian_arena = vmem_create("little_endian", NULL, 0, 1, 1084 segkmem_alloc_le, segkmem_free, heap_arena, 0, VM_SLEEP); 1085 big_endian_arena = vmem_create("big_endian", NULL, 0, 1, 1086 segkmem_alloc_be, segkmem_free, heap_arena, 0, VM_SLEEP); 1087 } 1088 1089 /* 1090 * Allocate from the system, aligned on a specific boundary. 1091 * The alignment, if non-zero, must be a power of 2. 1092 */ 1093 static void * 1094 kalloca(size_t size, size_t align, int cansleep, uint_t endian_flags) 1095 { 1096 size_t *addr, *raddr, rsize; 1097 size_t hdrsize = 4 * sizeof (size_t); /* must be power of 2 */ 1098 1099 align = MAX(align, hdrsize); 1100 ASSERT((align & (align - 1)) == 0); 1101 1102 /* 1103 * We need to allocate 1104 * rsize = size + hdrsize + align - MIN(hdrsize, buffer_alignment) 1105 * bytes to be sure we have enough freedom to satisfy the request. 1106 * Since the buffer alignment depends on the request size, this is 1107 * not straightforward to use directly. 1108 * 1109 * kmem guarantees that any allocation of a 64-byte multiple will be 1110 * 64-byte aligned. Since rounding up the request could add more 1111 * than we save, we compute the size with and without alignment, and 1112 * use the smaller of the two. 1113 */ 1114 rsize = size + hdrsize + align; 1115 1116 if (endian_flags == DDI_STRUCTURE_LE_ACC) { 1117 raddr = vmem_alloc(little_endian_arena, rsize, 1118 cansleep ? VM_SLEEP : VM_NOSLEEP); 1119 } else { 1120 raddr = vmem_alloc(big_endian_arena, rsize, 1121 cansleep ? VM_SLEEP : VM_NOSLEEP); 1122 } 1123 1124 if (raddr == NULL) 1125 return (NULL); 1126 1127 addr = (size_t *)P2ROUNDUP((uintptr_t)raddr + hdrsize, align); 1128 ASSERT((uintptr_t)addr + size - (uintptr_t)raddr <= rsize); 1129 1130 addr[-3] = (size_t)endian_flags; 1131 addr[-2] = (size_t)raddr; 1132 addr[-1] = rsize; 1133 1134 return (addr); 1135 } 1136 1137 static void 1138 kfreea(void *addr) 1139 { 1140 size_t *saddr = addr; 1141 1142 if (saddr[-3] == DDI_STRUCTURE_LE_ACC) 1143 vmem_free(little_endian_arena, (void *)saddr[-2], saddr[-1]); 1144 else 1145 vmem_free(big_endian_arena, (void *)saddr[-2], saddr[-1]); 1146 } 1147 1148 int 1149 i_ddi_mem_alloc(dev_info_t *dip, ddi_dma_attr_t *attr, 1150 size_t length, int cansleep, int flags, 1151 ddi_device_acc_attr_t *accattrp, 1152 caddr_t *kaddrp, size_t *real_length, ddi_acc_hdl_t *handlep) 1153 { 1154 caddr_t a; 1155 int iomin, align, streaming; 1156 uint_t endian_flags = DDI_NEVERSWAP_ACC; 1157 1158 #if defined(lint) 1159 *handlep = *handlep; 1160 #endif 1161 1162 /* 1163 * Check legality of arguments 1164 */ 1165 if (length == 0 || kaddrp == NULL || attr == NULL) { 1166 return (DDI_FAILURE); 1167 } 1168 1169 if (attr->dma_attr_minxfer == 0 || attr->dma_attr_align == 0 || 1170 (attr->dma_attr_align & (attr->dma_attr_align - 1)) || 1171 (attr->dma_attr_minxfer & (attr->dma_attr_minxfer - 1))) { 1172 return (DDI_FAILURE); 1173 } 1174 1175 /* 1176 * check if a streaming sequential xfer is requested. 1177 */ 1178 streaming = (flags & DDI_DMA_STREAMING) ? 1 : 0; 1179 1180 /* 1181 * Drivers for 64-bit capable SBus devices will encode 1182 * the burtsizes for 64-bit xfers in the upper 16-bits. 1183 * For DMA alignment, we use the most restrictive 1184 * alignment of 32-bit and 64-bit xfers. 1185 */ 1186 iomin = (attr->dma_attr_burstsizes & 0xffff) | 1187 ((attr->dma_attr_burstsizes >> 16) & 0xffff); 1188 /* 1189 * If a driver set burtsizes to 0, we give him byte alignment. 1190 * Otherwise align at the burtsizes boundary. 1191 */ 1192 if (iomin == 0) 1193 iomin = 1; 1194 else 1195 iomin = 1 << (ddi_fls(iomin) - 1); 1196 iomin = maxbit(iomin, attr->dma_attr_minxfer); 1197 iomin = maxbit(iomin, attr->dma_attr_align); 1198 iomin = ddi_iomin(dip, iomin, streaming); 1199 if (iomin == 0) 1200 return (DDI_FAILURE); 1201 1202 ASSERT((iomin & (iomin - 1)) == 0); 1203 ASSERT(iomin >= attr->dma_attr_minxfer); 1204 ASSERT(iomin >= attr->dma_attr_align); 1205 1206 length = P2ROUNDUP(length, iomin); 1207 align = iomin; 1208 1209 if (accattrp != NULL) 1210 endian_flags = accattrp->devacc_attr_endian_flags; 1211 1212 a = kalloca(length, align, cansleep, endian_flags); 1213 if ((*kaddrp = a) == 0) { 1214 return (DDI_FAILURE); 1215 } else { 1216 if (real_length) { 1217 *real_length = length; 1218 } 1219 if (handlep) { 1220 /* 1221 * assign handle information 1222 */ 1223 impl_acc_hdl_init(handlep); 1224 } 1225 return (DDI_SUCCESS); 1226 } 1227 } 1228 1229 /* 1230 * covert old DMA limits structure to DMA attribute structure 1231 * and continue 1232 */ 1233 int 1234 i_ddi_mem_alloc_lim(dev_info_t *dip, ddi_dma_lim_t *limits, 1235 size_t length, int cansleep, int streaming, 1236 ddi_device_acc_attr_t *accattrp, caddr_t *kaddrp, 1237 uint_t *real_length, ddi_acc_hdl_t *ap) 1238 { 1239 ddi_dma_attr_t dma_attr, *attrp; 1240 size_t rlen; 1241 int ret; 1242 1243 ASSERT(limits); 1244 attrp = &dma_attr; 1245 attrp->dma_attr_version = DMA_ATTR_V0; 1246 attrp->dma_attr_addr_lo = (uint64_t)limits->dlim_addr_lo; 1247 attrp->dma_attr_addr_hi = (uint64_t)limits->dlim_addr_hi; 1248 attrp->dma_attr_count_max = (uint64_t)-1; 1249 attrp->dma_attr_align = 1; 1250 attrp->dma_attr_burstsizes = (uint_t)limits->dlim_burstsizes; 1251 attrp->dma_attr_minxfer = (uint32_t)limits->dlim_minxfer; 1252 attrp->dma_attr_maxxfer = (uint64_t)-1; 1253 attrp->dma_attr_seg = (uint64_t)limits->dlim_cntr_max; 1254 attrp->dma_attr_sgllen = 1; 1255 attrp->dma_attr_granular = 1; 1256 attrp->dma_attr_flags = 0; 1257 1258 ret = i_ddi_mem_alloc(dip, attrp, length, cansleep, streaming, 1259 accattrp, kaddrp, &rlen, ap); 1260 if (ret == DDI_SUCCESS) { 1261 if (real_length) 1262 *real_length = (uint_t)rlen; 1263 } 1264 return (ret); 1265 } 1266 1267 /* ARGSUSED */ 1268 void 1269 i_ddi_mem_free(caddr_t kaddr, ddi_acc_hdl_t *ap) 1270 { 1271 kfreea(kaddr); 1272 } 1273 1274 /* 1275 * SECTION: DDI Data Access 1276 */ 1277 1278 static uintptr_t impl_acc_hdl_id = 0; 1279 1280 /* 1281 * access handle allocator 1282 */ 1283 ddi_acc_hdl_t * 1284 impl_acc_hdl_get(ddi_acc_handle_t hdl) 1285 { 1286 /* 1287 * Extract the access handle address from the DDI implemented 1288 * access handle 1289 */ 1290 return (&((ddi_acc_impl_t *)hdl)->ahi_common); 1291 } 1292 1293 ddi_acc_handle_t 1294 impl_acc_hdl_alloc(int (*waitfp)(caddr_t), caddr_t arg) 1295 { 1296 ddi_acc_impl_t *hp; 1297 on_trap_data_t *otp; 1298 int sleepflag; 1299 1300 sleepflag = ((waitfp == (int (*)())KM_SLEEP) ? KM_SLEEP : KM_NOSLEEP); 1301 1302 /* 1303 * Allocate and initialize the data access handle and error status. 1304 */ 1305 if ((hp = kmem_zalloc(sizeof (ddi_acc_impl_t), sleepflag)) == NULL) 1306 goto fail; 1307 if ((hp->ahi_err = (ndi_err_t *)kmem_zalloc( 1308 sizeof (ndi_err_t), sleepflag)) == NULL) { 1309 kmem_free(hp, sizeof (ddi_acc_impl_t)); 1310 goto fail; 1311 } 1312 if ((otp = (on_trap_data_t *)kmem_zalloc( 1313 sizeof (on_trap_data_t), sleepflag)) == NULL) { 1314 kmem_free(hp->ahi_err, sizeof (ndi_err_t)); 1315 kmem_free(hp, sizeof (ddi_acc_impl_t)); 1316 goto fail; 1317 } 1318 hp->ahi_err->err_ontrap = otp; 1319 hp->ahi_common.ah_platform_private = (void *)hp; 1320 1321 return ((ddi_acc_handle_t)hp); 1322 fail: 1323 if ((waitfp != (int (*)())KM_SLEEP) && 1324 (waitfp != (int (*)())KM_NOSLEEP)) 1325 ddi_set_callback(waitfp, arg, &impl_acc_hdl_id); 1326 return (NULL); 1327 } 1328 1329 void 1330 impl_acc_hdl_free(ddi_acc_handle_t handle) 1331 { 1332 ddi_acc_impl_t *hp; 1333 1334 /* 1335 * The supplied (ddi_acc_handle_t) is actually a (ddi_acc_impl_t *), 1336 * because that's what we allocated in impl_acc_hdl_alloc() above. 1337 */ 1338 hp = (ddi_acc_impl_t *)handle; 1339 if (hp) { 1340 kmem_free(hp->ahi_err->err_ontrap, sizeof (on_trap_data_t)); 1341 kmem_free(hp->ahi_err, sizeof (ndi_err_t)); 1342 kmem_free(hp, sizeof (ddi_acc_impl_t)); 1343 if (impl_acc_hdl_id) 1344 ddi_run_callback(&impl_acc_hdl_id); 1345 } 1346 } 1347 1348 #define PCI_GET_MP_PFN(mp, page_no) ((mp)->dmai_ndvmapages == 1 ? \ 1349 (pfn_t)(mp)->dmai_iopte:(((pfn_t *)(mp)->dmai_iopte)[page_no])) 1350 1351 /* 1352 * Function called after a dma fault occurred to find out whether the 1353 * fault address is associated with a driver that is able to handle faults 1354 * and recover from faults. 1355 */ 1356 /* ARGSUSED */ 1357 int 1358 impl_dma_check(dev_info_t *dip, const void *handle, const void *addr, 1359 const void *not_used) 1360 { 1361 ddi_dma_impl_t *mp = (ddi_dma_impl_t *)handle; 1362 pfn_t fault_pfn = mmu_btop(*(uint64_t *)addr); 1363 pfn_t comp_pfn; 1364 1365 /* 1366 * The driver has to set DDI_DMA_FLAGERR to recover from dma faults. 1367 */ 1368 int page; 1369 1370 ASSERT(mp); 1371 for (page = 0; page < mp->dmai_ndvmapages; page++) { 1372 comp_pfn = PCI_GET_MP_PFN(mp, page); 1373 if (fault_pfn == comp_pfn) 1374 return (DDI_FM_NONFATAL); 1375 } 1376 return (DDI_FM_UNKNOWN); 1377 } 1378 1379 /* 1380 * Function used to check if a given access handle owns the failing address. 1381 * Called by ndi_fmc_error, when we detect a PIO error. 1382 */ 1383 /* ARGSUSED */ 1384 static int 1385 impl_acc_check(dev_info_t *dip, const void *handle, const void *addr, 1386 const void *not_used) 1387 { 1388 pfn_t pfn, fault_pfn; 1389 ddi_acc_hdl_t *hp; 1390 1391 hp = impl_acc_hdl_get((ddi_acc_handle_t)handle); 1392 1393 ASSERT(hp); 1394 1395 if (addr != NULL) { 1396 pfn = hp->ah_pfn; 1397 fault_pfn = mmu_btop(*(uint64_t *)addr); 1398 if (fault_pfn >= pfn && fault_pfn < (pfn + hp->ah_pnum)) 1399 return (DDI_FM_NONFATAL); 1400 } 1401 return (DDI_FM_UNKNOWN); 1402 } 1403 1404 void 1405 impl_acc_err_init(ddi_acc_hdl_t *handlep) 1406 { 1407 int fmcap; 1408 ndi_err_t *errp; 1409 on_trap_data_t *otp; 1410 ddi_acc_impl_t *hp = (ddi_acc_impl_t *)handlep; 1411 1412 fmcap = ddi_fm_capable(handlep->ah_dip); 1413 1414 if (handlep->ah_acc.devacc_attr_version < DDI_DEVICE_ATTR_V1 || 1415 !DDI_FM_ACC_ERR_CAP(fmcap)) { 1416 handlep->ah_acc.devacc_attr_access = DDI_DEFAULT_ACC; 1417 } else if (DDI_FM_ACC_ERR_CAP(fmcap)) { 1418 if (handlep->ah_acc.devacc_attr_access == DDI_DEFAULT_ACC) { 1419 i_ddi_drv_ereport_post(handlep->ah_dip, DVR_EFMCAP, 1420 NULL, DDI_NOSLEEP); 1421 } else { 1422 errp = hp->ahi_err; 1423 otp = (on_trap_data_t *)errp->err_ontrap; 1424 otp->ot_handle = (void *)(hp); 1425 otp->ot_prot = OT_DATA_ACCESS; 1426 if (handlep->ah_acc.devacc_attr_access == 1427 DDI_CAUTIOUS_ACC) 1428 otp->ot_trampoline = 1429 (uintptr_t)&i_ddi_caut_trampoline; 1430 else 1431 otp->ot_trampoline = 1432 (uintptr_t)&i_ddi_prot_trampoline; 1433 errp->err_status = DDI_FM_OK; 1434 errp->err_expected = DDI_FM_ERR_UNEXPECTED; 1435 errp->err_cf = impl_acc_check; 1436 } 1437 } 1438 } 1439 1440 void 1441 impl_acc_hdl_init(ddi_acc_hdl_t *handlep) 1442 { 1443 ddi_acc_impl_t *hp; 1444 1445 ASSERT(handlep); 1446 1447 hp = (ddi_acc_impl_t *)handlep; 1448 1449 /* 1450 * check for SW byte-swapping 1451 */ 1452 hp->ahi_get8 = i_ddi_get8; 1453 hp->ahi_put8 = i_ddi_put8; 1454 hp->ahi_rep_get8 = i_ddi_rep_get8; 1455 hp->ahi_rep_put8 = i_ddi_rep_put8; 1456 if (handlep->ah_acc.devacc_attr_endian_flags & DDI_STRUCTURE_LE_ACC) { 1457 hp->ahi_get16 = i_ddi_swap_get16; 1458 hp->ahi_get32 = i_ddi_swap_get32; 1459 hp->ahi_get64 = i_ddi_swap_get64; 1460 hp->ahi_put16 = i_ddi_swap_put16; 1461 hp->ahi_put32 = i_ddi_swap_put32; 1462 hp->ahi_put64 = i_ddi_swap_put64; 1463 hp->ahi_rep_get16 = i_ddi_swap_rep_get16; 1464 hp->ahi_rep_get32 = i_ddi_swap_rep_get32; 1465 hp->ahi_rep_get64 = i_ddi_swap_rep_get64; 1466 hp->ahi_rep_put16 = i_ddi_swap_rep_put16; 1467 hp->ahi_rep_put32 = i_ddi_swap_rep_put32; 1468 hp->ahi_rep_put64 = i_ddi_swap_rep_put64; 1469 } else { 1470 hp->ahi_get16 = i_ddi_get16; 1471 hp->ahi_get32 = i_ddi_get32; 1472 hp->ahi_get64 = i_ddi_get64; 1473 hp->ahi_put16 = i_ddi_put16; 1474 hp->ahi_put32 = i_ddi_put32; 1475 hp->ahi_put64 = i_ddi_put64; 1476 hp->ahi_rep_get16 = i_ddi_rep_get16; 1477 hp->ahi_rep_get32 = i_ddi_rep_get32; 1478 hp->ahi_rep_get64 = i_ddi_rep_get64; 1479 hp->ahi_rep_put16 = i_ddi_rep_put16; 1480 hp->ahi_rep_put32 = i_ddi_rep_put32; 1481 hp->ahi_rep_put64 = i_ddi_rep_put64; 1482 } 1483 1484 /* Legacy fault flags and support */ 1485 hp->ahi_fault_check = i_ddi_acc_fault_check; 1486 hp->ahi_fault_notify = i_ddi_acc_fault_notify; 1487 hp->ahi_fault = 0; 1488 impl_acc_err_init(handlep); 1489 } 1490 1491 void 1492 i_ddi_acc_set_fault(ddi_acc_handle_t handle) 1493 { 1494 ddi_acc_impl_t *hp = (ddi_acc_impl_t *)handle; 1495 1496 if (!hp->ahi_fault) { 1497 hp->ahi_fault = 1; 1498 (*hp->ahi_fault_notify)(hp); 1499 } 1500 } 1501 1502 void 1503 i_ddi_acc_clr_fault(ddi_acc_handle_t handle) 1504 { 1505 ddi_acc_impl_t *hp = (ddi_acc_impl_t *)handle; 1506 1507 if (hp->ahi_fault) { 1508 hp->ahi_fault = 0; 1509 (*hp->ahi_fault_notify)(hp); 1510 } 1511 } 1512 1513 /* ARGSUSED */ 1514 void 1515 i_ddi_acc_fault_notify(ddi_acc_impl_t *hp) 1516 { 1517 /* Default version, does nothing */ 1518 } 1519 1520 /* 1521 * SECTION: Misc functions 1522 */ 1523 1524 /* 1525 * instance wrappers 1526 */ 1527 /*ARGSUSED*/ 1528 uint_t 1529 impl_assign_instance(dev_info_t *dip) 1530 { 1531 return ((uint_t)-1); 1532 } 1533 1534 /*ARGSUSED*/ 1535 int 1536 impl_keep_instance(dev_info_t *dip) 1537 { 1538 return (DDI_FAILURE); 1539 } 1540 1541 /*ARGSUSED*/ 1542 int 1543 impl_free_instance(dev_info_t *dip) 1544 { 1545 return (DDI_FAILURE); 1546 } 1547 1548 /*ARGSUSED*/ 1549 int 1550 impl_check_cpu(dev_info_t *devi) 1551 { 1552 return (DDI_SUCCESS); 1553 } 1554 1555 1556 static const char *nocopydevs[] = { 1557 "SUNW,ffb", 1558 "SUNW,afb", 1559 NULL 1560 }; 1561 1562 /* 1563 * Perform a copy from a memory mapped device (whose devinfo pointer is devi) 1564 * separately mapped at devaddr in the kernel to a kernel buffer at kaddr. 1565 */ 1566 /*ARGSUSED*/ 1567 int 1568 e_ddi_copyfromdev(dev_info_t *devi, 1569 off_t off, const void *devaddr, void *kaddr, size_t len) 1570 { 1571 const char **argv; 1572 1573 for (argv = nocopydevs; *argv; argv++) 1574 if (strcmp(ddi_binding_name(devi), *argv) == 0) { 1575 bzero(kaddr, len); 1576 return (0); 1577 } 1578 1579 bcopy(devaddr, kaddr, len); 1580 return (0); 1581 } 1582 1583 /* 1584 * Perform a copy to a memory mapped device (whose devinfo pointer is devi) 1585 * separately mapped at devaddr in the kernel from a kernel buffer at kaddr. 1586 */ 1587 /*ARGSUSED*/ 1588 int 1589 e_ddi_copytodev(dev_info_t *devi, 1590 off_t off, const void *kaddr, void *devaddr, size_t len) 1591 { 1592 const char **argv; 1593 1594 for (argv = nocopydevs; *argv; argv++) 1595 if (strcmp(ddi_binding_name(devi), *argv) == 0) 1596 return (1); 1597 1598 bcopy(kaddr, devaddr, len); 1599 return (0); 1600 } 1601 1602 /* 1603 * Boot Configuration 1604 */ 1605 idprom_t idprom; 1606 1607 /* 1608 * Configure the hardware on the system. 1609 * Called before the rootfs is mounted 1610 */ 1611 void 1612 configure(void) 1613 { 1614 extern void i_ddi_init_root(); 1615 1616 /* We better have released boot by this time! */ 1617 ASSERT(!bootops); 1618 1619 /* 1620 * Determine whether or not to use the fpu, V9 SPARC cpus 1621 * always have one. Could check for existence of a fp queue, 1622 * Ultra I, II and IIa do not have a fp queue. 1623 */ 1624 if (fpu_exists) 1625 fpu_probe(); 1626 else 1627 cmn_err(CE_CONT, "FPU not in use\n"); 1628 1629 #if 0 /* XXXQ - not necessary for sun4u */ 1630 /* 1631 * This following line fixes bugid 1041296; we need to do a 1632 * prom_nextnode(0) because this call ALSO patches the DMA+ 1633 * bug in Campus-B and Phoenix. The prom uncaches the traptable 1634 * page as a side-effect of devr_next(0) (which prom_nextnode calls), 1635 * so this *must* be executed early on. (XXX This is untrue for sun4u) 1636 */ 1637 (void) prom_nextnode((pnode_t)0); 1638 #endif 1639 1640 /* 1641 * Initialize devices on the machine. 1642 * Uses configuration tree built by the PROMs to determine what 1643 * is present, and builds a tree of prototype dev_info nodes 1644 * corresponding to the hardware which identified itself. 1645 */ 1646 i_ddi_init_root(); 1647 1648 #ifdef DDI_PROP_DEBUG 1649 (void) ddi_prop_debug(1); /* Enable property debugging */ 1650 #endif /* DDI_PROP_DEBUG */ 1651 } 1652 1653 /* 1654 * The "status" property indicates the operational status of a device. 1655 * If this property is present, the value is a string indicating the 1656 * status of the device as follows: 1657 * 1658 * "okay" operational. 1659 * "disabled" not operational, but might become operational. 1660 * "fail" not operational because a fault has been detected, 1661 * and it is unlikely that the device will become 1662 * operational without repair. no additional details 1663 * are available. 1664 * "fail-xxx" not operational because a fault has been detected, 1665 * and it is unlikely that the device will become 1666 * operational without repair. "xxx" is additional 1667 * human-readable information about the particular 1668 * fault condition that was detected. 1669 * 1670 * The absence of this property means that the operational status is 1671 * unknown or okay. 1672 * 1673 * This routine checks the status property of the specified device node 1674 * and returns 0 if the operational status indicates failure, and 1 otherwise. 1675 * 1676 * The property may exist on plug-in cards the existed before IEEE 1275-1994. 1677 * And, in that case, the property may not even be a string. So we carefully 1678 * check for the value "fail", in the beginning of the string, noting 1679 * the property length. 1680 */ 1681 int 1682 status_okay(int id, char *buf, int buflen) 1683 { 1684 char status_buf[OBP_MAXPROPNAME]; 1685 char *bufp = buf; 1686 int len = buflen; 1687 int proplen; 1688 static const char *status = "status"; 1689 static const char *fail = "fail"; 1690 size_t fail_len = strlen(fail); 1691 1692 /* 1693 * Get the proplen ... if it's smaller than "fail", 1694 * or doesn't exist ... then we don't care, since 1695 * the value can't begin with the char string "fail". 1696 * 1697 * NB: proplen, if it's a string, includes the NULL in the 1698 * the size of the property, and fail_len does not. 1699 */ 1700 proplen = prom_getproplen((pnode_t)id, (caddr_t)status); 1701 if (proplen <= fail_len) /* nonexistent or uninteresting len */ 1702 return (1); 1703 1704 /* 1705 * if a buffer was provided, use it 1706 */ 1707 if ((buf == (char *)NULL) || (buflen <= 0)) { 1708 bufp = status_buf; 1709 len = sizeof (status_buf); 1710 } 1711 *bufp = (char)0; 1712 1713 /* 1714 * Get the property into the buffer, to the extent of the buffer, 1715 * and in case the buffer is smaller than the property size, 1716 * NULL terminate the buffer. (This handles the case where 1717 * a buffer was passed in and the caller wants to print the 1718 * value, but the buffer was too small). 1719 */ 1720 (void) prom_bounded_getprop((pnode_t)id, (caddr_t)status, 1721 (caddr_t)bufp, len); 1722 *(bufp + len - 1) = (char)0; 1723 1724 /* 1725 * If the value begins with the char string "fail", 1726 * then it means the node is failed. We don't care 1727 * about any other values. We assume the node is ok 1728 * although it might be 'disabled'. 1729 */ 1730 if (strncmp(bufp, fail, fail_len) == 0) 1731 return (0); 1732 1733 return (1); 1734 } 1735 1736 1737 /* 1738 * We set the cpu type from the idprom, if we can. 1739 * Note that we just read out the contents of it, for the most part. 1740 */ 1741 void 1742 setcputype(void) 1743 { 1744 /* 1745 * We cache the idprom info early on so that we don't 1746 * rummage through the NVRAM unnecessarily later. 1747 */ 1748 (void) prom_getidprom((caddr_t)&idprom, sizeof (idprom)); 1749 } 1750 1751 /* 1752 * Here is where we actually infer meanings to the members of idprom_t 1753 */ 1754 void 1755 parse_idprom(void) 1756 { 1757 if (idprom.id_format == IDFORM_1) { 1758 uint_t i; 1759 1760 (void) localetheraddr((struct ether_addr *)idprom.id_ether, 1761 (struct ether_addr *)NULL); 1762 1763 i = idprom.id_machine << 24; 1764 i = i + idprom.id_serial; 1765 numtos((ulong_t)i, hw_serial); 1766 } else 1767 prom_printf("Invalid format code in IDprom.\n"); 1768 } 1769 1770 /* 1771 * Allow for implementation specific correction of PROM property values. 1772 */ 1773 /*ARGSUSED*/ 1774 void 1775 impl_fix_props(dev_info_t *dip, dev_info_t *ch_dip, char *name, int len, 1776 caddr_t buffer) 1777 { 1778 /* 1779 * There are no adjustments needed in this implementation. 1780 */ 1781 } 1782 1783 /* 1784 * The following functions ready a cautious request to go up to the nexus 1785 * driver. It is up to the nexus driver to decide how to process the request. 1786 * It may choose to call i_ddi_do_caut_get/put in this file, or do it 1787 * differently. 1788 */ 1789 1790 static void 1791 i_ddi_caut_getput_ctlops( 1792 ddi_acc_impl_t *hp, uint64_t host_addr, uint64_t dev_addr, size_t size, 1793 size_t repcount, uint_t flags, ddi_ctl_enum_t cmd) 1794 { 1795 peekpoke_ctlops_t cautacc_ctlops_arg; 1796 1797 cautacc_ctlops_arg.size = size; 1798 cautacc_ctlops_arg.dev_addr = dev_addr; 1799 cautacc_ctlops_arg.host_addr = host_addr; 1800 cautacc_ctlops_arg.handle = (ddi_acc_handle_t)hp; 1801 cautacc_ctlops_arg.repcount = repcount; 1802 cautacc_ctlops_arg.flags = flags; 1803 1804 (void) ddi_ctlops(hp->ahi_common.ah_dip, hp->ahi_common.ah_dip, cmd, 1805 &cautacc_ctlops_arg, NULL); 1806 } 1807 1808 uint8_t 1809 i_ddi_caut_get8(ddi_acc_impl_t *hp, uint8_t *addr) 1810 { 1811 uint8_t value; 1812 i_ddi_caut_getput_ctlops(hp, (uint64_t)&value, (uint64_t)addr, 1813 sizeof (uint8_t), 1, 0, DDI_CTLOPS_PEEK); 1814 1815 return (value); 1816 } 1817 1818 uint16_t 1819 i_ddi_caut_get16(ddi_acc_impl_t *hp, uint16_t *addr) 1820 { 1821 uint16_t value; 1822 i_ddi_caut_getput_ctlops(hp, (uint64_t)&value, (uint64_t)addr, 1823 sizeof (uint16_t), 1, 0, DDI_CTLOPS_PEEK); 1824 1825 return (value); 1826 } 1827 1828 uint32_t 1829 i_ddi_caut_get32(ddi_acc_impl_t *hp, uint32_t *addr) 1830 { 1831 uint32_t value; 1832 i_ddi_caut_getput_ctlops(hp, (uint64_t)&value, (uint64_t)addr, 1833 sizeof (uint32_t), 1, 0, DDI_CTLOPS_PEEK); 1834 1835 return (value); 1836 } 1837 1838 uint64_t 1839 i_ddi_caut_get64(ddi_acc_impl_t *hp, uint64_t *addr) 1840 { 1841 uint64_t value; 1842 i_ddi_caut_getput_ctlops(hp, (uint64_t)&value, (uint64_t)addr, 1843 sizeof (uint64_t), 1, 0, DDI_CTLOPS_PEEK); 1844 1845 return (value); 1846 } 1847 1848 void 1849 i_ddi_caut_put8(ddi_acc_impl_t *hp, uint8_t *addr, uint8_t value) 1850 { 1851 i_ddi_caut_getput_ctlops(hp, (uint64_t)&value, (uint64_t)addr, 1852 sizeof (uint8_t), 1, 0, DDI_CTLOPS_POKE); 1853 } 1854 1855 void 1856 i_ddi_caut_put16(ddi_acc_impl_t *hp, uint16_t *addr, uint16_t value) 1857 { 1858 i_ddi_caut_getput_ctlops(hp, (uint64_t)&value, (uint64_t)addr, 1859 sizeof (uint16_t), 1, 0, DDI_CTLOPS_POKE); 1860 } 1861 1862 void 1863 i_ddi_caut_put32(ddi_acc_impl_t *hp, uint32_t *addr, uint32_t value) 1864 { 1865 i_ddi_caut_getput_ctlops(hp, (uint64_t)&value, (uint64_t)addr, 1866 sizeof (uint32_t), 1, 0, DDI_CTLOPS_POKE); 1867 } 1868 1869 void 1870 i_ddi_caut_put64(ddi_acc_impl_t *hp, uint64_t *addr, uint64_t value) 1871 { 1872 i_ddi_caut_getput_ctlops(hp, (uint64_t)&value, (uint64_t)addr, 1873 sizeof (uint64_t), 1, 0, DDI_CTLOPS_POKE); 1874 } 1875 1876 void 1877 i_ddi_caut_rep_get8(ddi_acc_impl_t *hp, uint8_t *host_addr, uint8_t *dev_addr, 1878 size_t repcount, uint_t flags) 1879 { 1880 i_ddi_caut_getput_ctlops(hp, (uint64_t)host_addr, (uint64_t)dev_addr, 1881 sizeof (uint8_t), repcount, flags, DDI_CTLOPS_PEEK); 1882 } 1883 1884 void 1885 i_ddi_caut_rep_get16(ddi_acc_impl_t *hp, uint16_t *host_addr, 1886 uint16_t *dev_addr, size_t repcount, uint_t flags) 1887 { 1888 i_ddi_caut_getput_ctlops(hp, (uint64_t)host_addr, (uint64_t)dev_addr, 1889 sizeof (uint16_t), repcount, flags, DDI_CTLOPS_PEEK); 1890 } 1891 1892 void 1893 i_ddi_caut_rep_get32(ddi_acc_impl_t *hp, uint32_t *host_addr, 1894 uint32_t *dev_addr, size_t repcount, uint_t flags) 1895 { 1896 i_ddi_caut_getput_ctlops(hp, (uint64_t)host_addr, (uint64_t)dev_addr, 1897 sizeof (uint32_t), repcount, flags, DDI_CTLOPS_PEEK); 1898 } 1899 1900 void 1901 i_ddi_caut_rep_get64(ddi_acc_impl_t *hp, uint64_t *host_addr, 1902 uint64_t *dev_addr, size_t repcount, uint_t flags) 1903 { 1904 i_ddi_caut_getput_ctlops(hp, (uint64_t)host_addr, (uint64_t)dev_addr, 1905 sizeof (uint64_t), repcount, flags, DDI_CTLOPS_PEEK); 1906 } 1907 1908 void 1909 i_ddi_caut_rep_put8(ddi_acc_impl_t *hp, uint8_t *host_addr, uint8_t *dev_addr, 1910 size_t repcount, uint_t flags) 1911 { 1912 i_ddi_caut_getput_ctlops(hp, (uint64_t)host_addr, (uint64_t)dev_addr, 1913 sizeof (uint8_t), repcount, flags, DDI_CTLOPS_POKE); 1914 } 1915 1916 void 1917 i_ddi_caut_rep_put16(ddi_acc_impl_t *hp, uint16_t *host_addr, 1918 uint16_t *dev_addr, size_t repcount, uint_t flags) 1919 { 1920 i_ddi_caut_getput_ctlops(hp, (uint64_t)host_addr, (uint64_t)dev_addr, 1921 sizeof (uint16_t), repcount, flags, DDI_CTLOPS_POKE); 1922 } 1923 1924 void 1925 i_ddi_caut_rep_put32(ddi_acc_impl_t *hp, uint32_t *host_addr, 1926 uint32_t *dev_addr, size_t repcount, uint_t flags) 1927 { 1928 i_ddi_caut_getput_ctlops(hp, (uint64_t)host_addr, (uint64_t)dev_addr, 1929 sizeof (uint32_t), repcount, flags, DDI_CTLOPS_POKE); 1930 } 1931 1932 void 1933 i_ddi_caut_rep_put64(ddi_acc_impl_t *hp, uint64_t *host_addr, 1934 uint64_t *dev_addr, size_t repcount, uint_t flags) 1935 { 1936 i_ddi_caut_getput_ctlops(hp, (uint64_t)host_addr, (uint64_t)dev_addr, 1937 sizeof (uint64_t), repcount, flags, DDI_CTLOPS_POKE); 1938 } 1939 1940 /* 1941 * This is called only to process peek/poke when the DIP is NULL. 1942 * Assume that this is for memory, as nexi take care of device safe accesses. 1943 */ 1944 int 1945 peekpoke_mem(ddi_ctl_enum_t cmd, peekpoke_ctlops_t *in_args) 1946 { 1947 int err = DDI_SUCCESS; 1948 on_trap_data_t otd; 1949 1950 /* Set up protected environment. */ 1951 if (!on_trap(&otd, OT_DATA_ACCESS)) { 1952 uintptr_t tramp = otd.ot_trampoline; 1953 1954 if (cmd == DDI_CTLOPS_POKE) { 1955 otd.ot_trampoline = (uintptr_t)&poke_fault; 1956 err = do_poke(in_args->size, (void *)in_args->dev_addr, 1957 (void *)in_args->host_addr); 1958 } else { 1959 otd.ot_trampoline = (uintptr_t)&peek_fault; 1960 err = do_peek(in_args->size, (void *)in_args->dev_addr, 1961 (void *)in_args->host_addr); 1962 } 1963 otd.ot_trampoline = tramp; 1964 } else 1965 err = DDI_FAILURE; 1966 1967 /* Take down protected environment. */ 1968 no_trap(); 1969 1970 return (err); 1971 } 1972 1973 /* 1974 * Platform independent DR routines 1975 */ 1976 1977 static int 1978 ndi2errno(int n) 1979 { 1980 int err = 0; 1981 1982 switch (n) { 1983 case NDI_NOMEM: 1984 err = ENOMEM; 1985 break; 1986 case NDI_BUSY: 1987 err = EBUSY; 1988 break; 1989 case NDI_FAULT: 1990 err = EFAULT; 1991 break; 1992 case NDI_FAILURE: 1993 err = EIO; 1994 break; 1995 case NDI_SUCCESS: 1996 break; 1997 case NDI_BADHANDLE: 1998 default: 1999 err = EINVAL; 2000 break; 2001 } 2002 return (err); 2003 } 2004 2005 /* 2006 * Prom tree node list 2007 */ 2008 struct ptnode { 2009 pnode_t nodeid; 2010 struct ptnode *next; 2011 }; 2012 2013 /* 2014 * Prom tree walk arg 2015 */ 2016 struct pta { 2017 dev_info_t *pdip; 2018 devi_branch_t *bp; 2019 uint_t flags; 2020 dev_info_t *fdip; 2021 struct ptnode *head; 2022 }; 2023 2024 static void 2025 visit_node(pnode_t nodeid, struct pta *ap) 2026 { 2027 struct ptnode **nextp; 2028 int (*select)(pnode_t, void *, uint_t); 2029 2030 ASSERT(nodeid != OBP_NONODE && nodeid != OBP_BADNODE); 2031 2032 select = ap->bp->create.prom_branch_select; 2033 2034 ASSERT(select); 2035 2036 if (select(nodeid, ap->bp->arg, 0) == DDI_SUCCESS) { 2037 2038 for (nextp = &ap->head; *nextp; nextp = &(*nextp)->next) 2039 ; 2040 2041 *nextp = kmem_zalloc(sizeof (struct ptnode), KM_SLEEP); 2042 2043 (*nextp)->nodeid = nodeid; 2044 } 2045 2046 if ((ap->flags & DEVI_BRANCH_CHILD) == DEVI_BRANCH_CHILD) 2047 return; 2048 2049 nodeid = prom_childnode(nodeid); 2050 while (nodeid != OBP_NONODE && nodeid != OBP_BADNODE) { 2051 visit_node(nodeid, ap); 2052 nodeid = prom_nextnode(nodeid); 2053 } 2054 } 2055 2056 /*ARGSUSED*/ 2057 static int 2058 set_dip_offline(dev_info_t *dip, void *arg) 2059 { 2060 ASSERT(dip); 2061 2062 mutex_enter(&(DEVI(dip)->devi_lock)); 2063 if (!DEVI_IS_DEVICE_OFFLINE(dip)) 2064 DEVI_SET_DEVICE_OFFLINE(dip); 2065 mutex_exit(&(DEVI(dip)->devi_lock)); 2066 2067 return (DDI_WALK_CONTINUE); 2068 } 2069 2070 /*ARGSUSED*/ 2071 static int 2072 create_prom_branch(void *arg, int has_changed) 2073 { 2074 int circ, c; 2075 int exists, rv; 2076 pnode_t nodeid; 2077 struct ptnode *tnp; 2078 dev_info_t *dip; 2079 struct pta *ap = arg; 2080 devi_branch_t *bp; 2081 2082 ASSERT(ap); 2083 ASSERT(ap->fdip == NULL); 2084 ASSERT(ap->pdip && ndi_dev_is_prom_node(ap->pdip)); 2085 2086 bp = ap->bp; 2087 2088 nodeid = ddi_get_nodeid(ap->pdip); 2089 if (nodeid == OBP_NONODE || nodeid == OBP_BADNODE) { 2090 cmn_err(CE_WARN, "create_prom_branch: invalid " 2091 "nodeid: 0x%x", nodeid); 2092 return (EINVAL); 2093 } 2094 2095 ap->head = NULL; 2096 2097 nodeid = prom_childnode(nodeid); 2098 while (nodeid != OBP_NONODE && nodeid != OBP_BADNODE) { 2099 visit_node(nodeid, ap); 2100 nodeid = prom_nextnode(nodeid); 2101 } 2102 2103 if (ap->head == NULL) 2104 return (ENODEV); 2105 2106 rv = 0; 2107 while ((tnp = ap->head) != NULL) { 2108 ap->head = tnp->next; 2109 2110 ndi_devi_enter(ap->pdip, &circ); 2111 2112 /* 2113 * Check if the branch already exists. 2114 */ 2115 exists = 0; 2116 dip = e_ddi_nodeid_to_dip(tnp->nodeid); 2117 if (dip != NULL) { 2118 exists = 1; 2119 2120 /* Parent is held busy, so release hold */ 2121 ndi_rele_devi(dip); 2122 #ifdef DEBUG 2123 cmn_err(CE_WARN, "create_prom_branch: dip(%p) exists" 2124 " for nodeid 0x%x", (void *)dip, tnp->nodeid); 2125 #endif 2126 } else { 2127 dip = i_ddi_create_branch(ap->pdip, tnp->nodeid); 2128 } 2129 2130 kmem_free(tnp, sizeof (struct ptnode)); 2131 2132 if (dip == NULL) { 2133 ndi_devi_exit(ap->pdip, circ); 2134 rv = EIO; 2135 continue; 2136 } 2137 2138 ASSERT(ddi_get_parent(dip) == ap->pdip); 2139 2140 /* 2141 * Hold the branch if it is not already held 2142 */ 2143 if (!exists) 2144 e_ddi_branch_hold(dip); 2145 2146 ASSERT(e_ddi_branch_held(dip)); 2147 2148 /* 2149 * Set all dips in the branch offline so that 2150 * only a "configure" operation can attach 2151 * the branch 2152 */ 2153 (void) set_dip_offline(dip, NULL); 2154 2155 ndi_devi_enter(dip, &c); 2156 ddi_walk_devs(ddi_get_child(dip), set_dip_offline, NULL); 2157 ndi_devi_exit(dip, c); 2158 2159 ndi_devi_exit(ap->pdip, circ); 2160 2161 if (ap->flags & DEVI_BRANCH_CONFIGURE) { 2162 int error = e_ddi_branch_configure(dip, &ap->fdip, 0); 2163 if (error && rv == 0) 2164 rv = error; 2165 } 2166 2167 /* 2168 * Invoke devi_branch_callback() (if it exists) only for 2169 * newly created branches 2170 */ 2171 if (bp->devi_branch_callback && !exists) 2172 bp->devi_branch_callback(dip, bp->arg, 0); 2173 } 2174 2175 return (rv); 2176 } 2177 2178 static int 2179 sid_node_create(dev_info_t *pdip, devi_branch_t *bp, dev_info_t **rdipp) 2180 { 2181 int rv, circ, len; 2182 int i, flags; 2183 dev_info_t *dip; 2184 char *nbuf; 2185 static const char *noname = "<none>"; 2186 2187 ASSERT(pdip); 2188 ASSERT(DEVI_BUSY_OWNED(pdip)); 2189 2190 flags = 0; 2191 2192 /* 2193 * Creating the root of a branch ? 2194 */ 2195 if (rdipp) { 2196 *rdipp = NULL; 2197 flags = DEVI_BRANCH_ROOT; 2198 } 2199 2200 ndi_devi_alloc_sleep(pdip, (char *)noname, DEVI_SID_NODEID, &dip); 2201 rv = bp->create.sid_branch_create(dip, bp->arg, flags); 2202 2203 nbuf = kmem_alloc(OBP_MAXDRVNAME, KM_SLEEP); 2204 2205 if (rv == DDI_WALK_ERROR) { 2206 cmn_err(CE_WARN, "e_ddi_branch_create: Error setting" 2207 " properties on devinfo node %p", (void *)dip); 2208 goto fail; 2209 } 2210 2211 len = OBP_MAXDRVNAME; 2212 if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 2213 DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "name", nbuf, &len) 2214 != DDI_PROP_SUCCESS) { 2215 cmn_err(CE_WARN, "e_ddi_branch_create: devinfo node %p has" 2216 "no name property", (void *)dip); 2217 goto fail; 2218 } 2219 2220 ASSERT(i_ddi_node_state(dip) == DS_PROTO); 2221 if (ndi_devi_set_nodename(dip, nbuf, 0) != NDI_SUCCESS) { 2222 cmn_err(CE_WARN, "e_ddi_branch_create: cannot set name (%s)" 2223 " for devinfo node %p", nbuf, (void *)dip); 2224 goto fail; 2225 } 2226 2227 kmem_free(nbuf, OBP_MAXDRVNAME); 2228 2229 /* 2230 * Ignore bind failures just like boot does 2231 */ 2232 (void) ndi_devi_bind_driver(dip, 0); 2233 2234 switch (rv) { 2235 case DDI_WALK_CONTINUE: 2236 case DDI_WALK_PRUNESIB: 2237 ndi_devi_enter(dip, &circ); 2238 2239 i = DDI_WALK_CONTINUE; 2240 for (; i == DDI_WALK_CONTINUE; ) { 2241 i = sid_node_create(dip, bp, NULL); 2242 } 2243 2244 ASSERT(i == DDI_WALK_ERROR || i == DDI_WALK_PRUNESIB); 2245 if (i == DDI_WALK_ERROR) 2246 rv = i; 2247 /* 2248 * If PRUNESIB stop creating siblings 2249 * of dip's child. Subsequent walk behavior 2250 * is determined by rv returned by dip. 2251 */ 2252 2253 ndi_devi_exit(dip, circ); 2254 break; 2255 case DDI_WALK_TERMINATE: 2256 /* 2257 * Don't create children and ask our parent 2258 * to not create siblings either. 2259 */ 2260 rv = DDI_WALK_PRUNESIB; 2261 break; 2262 case DDI_WALK_PRUNECHILD: 2263 /* 2264 * Don't create children, but ask parent to continue 2265 * with siblings. 2266 */ 2267 rv = DDI_WALK_CONTINUE; 2268 break; 2269 default: 2270 ASSERT(0); 2271 break; 2272 } 2273 2274 if (rdipp) 2275 *rdipp = dip; 2276 2277 /* 2278 * Set device offline - only the "configure" op should cause an attach 2279 */ 2280 (void) set_dip_offline(dip, NULL); 2281 2282 return (rv); 2283 fail: 2284 (void) ndi_devi_free(dip); 2285 kmem_free(nbuf, OBP_MAXDRVNAME); 2286 return (DDI_WALK_ERROR); 2287 } 2288 2289 static int 2290 create_sid_branch( 2291 dev_info_t *pdip, 2292 devi_branch_t *bp, 2293 dev_info_t **dipp, 2294 uint_t flags) 2295 { 2296 int rv = 0, state = DDI_WALK_CONTINUE; 2297 dev_info_t *rdip; 2298 2299 while (state == DDI_WALK_CONTINUE) { 2300 int circ; 2301 2302 ndi_devi_enter(pdip, &circ); 2303 2304 state = sid_node_create(pdip, bp, &rdip); 2305 if (rdip == NULL) { 2306 ndi_devi_exit(pdip, circ); 2307 ASSERT(state == DDI_WALK_ERROR); 2308 break; 2309 } 2310 2311 e_ddi_branch_hold(rdip); 2312 2313 ndi_devi_exit(pdip, circ); 2314 2315 if (flags & DEVI_BRANCH_CONFIGURE) { 2316 int error = e_ddi_branch_configure(rdip, dipp, 0); 2317 if (error && rv == 0) 2318 rv = error; 2319 } 2320 2321 /* 2322 * devi_branch_callback() is optional 2323 */ 2324 if (bp->devi_branch_callback) 2325 bp->devi_branch_callback(rdip, bp->arg, 0); 2326 } 2327 2328 ASSERT(state == DDI_WALK_ERROR || state == DDI_WALK_PRUNESIB); 2329 2330 return (state == DDI_WALK_ERROR ? EIO : rv); 2331 } 2332 2333 int 2334 e_ddi_branch_create( 2335 dev_info_t *pdip, 2336 devi_branch_t *bp, 2337 dev_info_t **dipp, 2338 uint_t flags) 2339 { 2340 int prom_devi, sid_devi, error; 2341 2342 if (pdip == NULL || bp == NULL || bp->type == 0) 2343 return (EINVAL); 2344 2345 prom_devi = (bp->type == DEVI_BRANCH_PROM) ? 1 : 0; 2346 sid_devi = (bp->type == DEVI_BRANCH_SID) ? 1 : 0; 2347 2348 if (prom_devi && bp->create.prom_branch_select == NULL) 2349 return (EINVAL); 2350 else if (sid_devi && bp->create.sid_branch_create == NULL) 2351 return (EINVAL); 2352 else if (!prom_devi && !sid_devi) 2353 return (EINVAL); 2354 2355 if (flags & DEVI_BRANCH_EVENT) 2356 return (EINVAL); 2357 2358 if (prom_devi) { 2359 struct pta pta = {0}; 2360 2361 pta.pdip = pdip; 2362 pta.bp = bp; 2363 pta.flags = flags; 2364 2365 error = prom_tree_access(create_prom_branch, &pta, NULL); 2366 2367 if (dipp) 2368 *dipp = pta.fdip; 2369 else if (pta.fdip) 2370 ndi_rele_devi(pta.fdip); 2371 } else { 2372 error = create_sid_branch(pdip, bp, dipp, flags); 2373 } 2374 2375 return (error); 2376 } 2377 2378 int 2379 e_ddi_branch_configure(dev_info_t *rdip, dev_info_t **dipp, uint_t flags) 2380 { 2381 int circ, rv; 2382 char *devnm; 2383 dev_info_t *pdip; 2384 2385 if (dipp) 2386 *dipp = NULL; 2387 2388 if (rdip == NULL || flags != 0 || (flags & DEVI_BRANCH_EVENT)) 2389 return (EINVAL); 2390 2391 pdip = ddi_get_parent(rdip); 2392 2393 ndi_devi_enter(pdip, &circ); 2394 2395 if (!e_ddi_branch_held(rdip)) { 2396 ndi_devi_exit(pdip, circ); 2397 cmn_err(CE_WARN, "e_ddi_branch_configure: " 2398 "dip(%p) not held", (void *)rdip); 2399 return (EINVAL); 2400 } 2401 2402 if (i_ddi_node_state(rdip) < DS_INITIALIZED) { 2403 /* 2404 * First attempt to bind a driver. If we fail, return 2405 * success (On some platforms, dips for some device 2406 * types (CPUs) may not have a driver) 2407 */ 2408 if (ndi_devi_bind_driver(rdip, 0) != NDI_SUCCESS) { 2409 ndi_devi_exit(pdip, circ); 2410 return (0); 2411 } 2412 2413 if (ddi_initchild(pdip, rdip) != DDI_SUCCESS) { 2414 rv = NDI_FAILURE; 2415 goto out; 2416 } 2417 } 2418 2419 ASSERT(i_ddi_node_state(rdip) >= DS_INITIALIZED); 2420 2421 devnm = kmem_alloc(MAXNAMELEN + 1, KM_SLEEP); 2422 2423 (void) ddi_deviname(rdip, devnm); 2424 2425 if ((rv = ndi_devi_config_one(pdip, devnm+1, &rdip, 2426 NDI_DEVI_ONLINE | NDI_CONFIG)) == NDI_SUCCESS) { 2427 /* release hold from ndi_devi_config_one() */ 2428 ndi_rele_devi(rdip); 2429 } 2430 2431 kmem_free(devnm, MAXNAMELEN + 1); 2432 out: 2433 if (rv != NDI_SUCCESS && dipp) { 2434 ndi_hold_devi(rdip); 2435 *dipp = rdip; 2436 } 2437 ndi_devi_exit(pdip, circ); 2438 return (ndi2errno(rv)); 2439 } 2440 2441 void 2442 e_ddi_branch_hold(dev_info_t *rdip) 2443 { 2444 if (e_ddi_branch_held(rdip)) { 2445 cmn_err(CE_WARN, "e_ddi_branch_hold: branch already held"); 2446 return; 2447 } 2448 2449 mutex_enter(&DEVI(rdip)->devi_lock); 2450 if ((DEVI(rdip)->devi_flags & DEVI_BRANCH_HELD) == 0) { 2451 DEVI(rdip)->devi_flags |= DEVI_BRANCH_HELD; 2452 DEVI(rdip)->devi_ref++; 2453 } 2454 ASSERT(DEVI(rdip)->devi_ref > 0); 2455 mutex_exit(&DEVI(rdip)->devi_lock); 2456 } 2457 2458 int 2459 e_ddi_branch_held(dev_info_t *rdip) 2460 { 2461 int rv = 0; 2462 2463 mutex_enter(&DEVI(rdip)->devi_lock); 2464 if ((DEVI(rdip)->devi_flags & DEVI_BRANCH_HELD) && 2465 DEVI(rdip)->devi_ref > 0) { 2466 rv = 1; 2467 } 2468 mutex_exit(&DEVI(rdip)->devi_lock); 2469 2470 return (rv); 2471 } 2472 void 2473 e_ddi_branch_rele(dev_info_t *rdip) 2474 { 2475 mutex_enter(&DEVI(rdip)->devi_lock); 2476 DEVI(rdip)->devi_flags &= ~DEVI_BRANCH_HELD; 2477 DEVI(rdip)->devi_ref--; 2478 mutex_exit(&DEVI(rdip)->devi_lock); 2479 } 2480 2481 int 2482 e_ddi_branch_unconfigure( 2483 dev_info_t *rdip, 2484 dev_info_t **dipp, 2485 uint_t flags) 2486 { 2487 int circ, rv; 2488 int destroy; 2489 char *devnm; 2490 uint_t nflags; 2491 dev_info_t *pdip; 2492 2493 if (dipp) 2494 *dipp = NULL; 2495 2496 if (rdip == NULL) 2497 return (EINVAL); 2498 2499 pdip = ddi_get_parent(rdip); 2500 2501 ASSERT(pdip); 2502 2503 /* 2504 * Check if caller holds pdip busy - can cause deadlocks during 2505 * devfs_clean() 2506 */ 2507 if (DEVI_BUSY_OWNED(pdip)) { 2508 cmn_err(CE_WARN, "e_ddi_branch_unconfigure: failed: parent" 2509 " devinfo node(%p) is busy held", (void *)pdip); 2510 return (EINVAL); 2511 } 2512 2513 destroy = (flags & DEVI_BRANCH_DESTROY) ? 1 : 0; 2514 2515 devnm = kmem_alloc(MAXNAMELEN + 1, KM_SLEEP); 2516 2517 ndi_devi_enter(pdip, &circ); 2518 (void) ddi_deviname(rdip, devnm); 2519 ndi_devi_exit(pdip, circ); 2520 2521 /* 2522 * ddi_deviname() returns a component name with / prepended. 2523 */ 2524 rv = devfs_clean(pdip, devnm + 1, DV_CLEAN_FORCE); 2525 if (rv) { 2526 kmem_free(devnm, MAXNAMELEN + 1); 2527 return (rv); 2528 } 2529 2530 ndi_devi_enter(pdip, &circ); 2531 2532 /* 2533 * Recreate device name as it may have changed state (init/uninit) 2534 * when parent busy lock was dropped for devfs_clean() 2535 */ 2536 (void) ddi_deviname(rdip, devnm); 2537 2538 if (!e_ddi_branch_held(rdip)) { 2539 kmem_free(devnm, MAXNAMELEN + 1); 2540 ndi_devi_exit(pdip, circ); 2541 cmn_err(CE_WARN, "e_ddi_%s_branch: dip(%p) not held", 2542 destroy ? "destroy" : "unconfigure", (void *)rdip); 2543 return (EINVAL); 2544 } 2545 2546 /* 2547 * Release hold on the branch. This is ok since we are holding the 2548 * parent busy. If rdip is not removed, we must do a hold on the 2549 * branch before returning. 2550 */ 2551 e_ddi_branch_rele(rdip); 2552 2553 nflags = NDI_DEVI_OFFLINE; 2554 if (destroy || (flags & DEVI_BRANCH_DESTROY)) { 2555 nflags |= NDI_DEVI_REMOVE; 2556 destroy = 1; 2557 } else { 2558 nflags |= NDI_UNCONFIG; /* uninit but don't remove */ 2559 } 2560 2561 if (flags & DEVI_BRANCH_EVENT) 2562 nflags |= NDI_POST_EVENT; 2563 2564 if (i_ddi_devi_attached(pdip) && 2565 (i_ddi_node_state(rdip) >= DS_INITIALIZED)) { 2566 rv = ndi_devi_unconfig_one(pdip, devnm+1, dipp, nflags); 2567 } else { 2568 rv = e_ddi_devi_unconfig(rdip, dipp, nflags); 2569 if (rv == NDI_SUCCESS) { 2570 ASSERT(!destroy || ddi_get_child(rdip) == NULL); 2571 rv = ndi_devi_offline(rdip, nflags); 2572 } 2573 } 2574 2575 if (!destroy || rv != NDI_SUCCESS) { 2576 /* The dip still exists, so do a hold */ 2577 e_ddi_branch_hold(rdip); 2578 } 2579 out: 2580 kmem_free(devnm, MAXNAMELEN + 1); 2581 ndi_devi_exit(pdip, circ); 2582 return (ndi2errno(rv)); 2583 } 2584 2585 int 2586 e_ddi_branch_destroy(dev_info_t *rdip, dev_info_t **dipp, uint_t flag) 2587 { 2588 return (e_ddi_branch_unconfigure(rdip, dipp, 2589 flag|DEVI_BRANCH_DESTROY)); 2590 } 2591 2592 /* 2593 * Number of chains for hash table 2594 */ 2595 #define NUMCHAINS 17 2596 2597 /* 2598 * Devinfo busy arg 2599 */ 2600 struct devi_busy { 2601 int dv_total; 2602 int s_total; 2603 mod_hash_t *dv_hash; 2604 mod_hash_t *s_hash; 2605 int (*callback)(dev_info_t *, void *, uint_t); 2606 void *arg; 2607 }; 2608 2609 static int 2610 visit_dip(dev_info_t *dip, void *arg) 2611 { 2612 uintptr_t sbusy, dvbusy, ref; 2613 struct devi_busy *bsp = arg; 2614 2615 ASSERT(bsp->callback); 2616 2617 /* 2618 * A dip cannot be busy if its reference count is 0 2619 */ 2620 if ((ref = e_ddi_devi_holdcnt(dip)) == 0) { 2621 return (bsp->callback(dip, bsp->arg, 0)); 2622 } 2623 2624 if (mod_hash_find(bsp->dv_hash, dip, (mod_hash_val_t *)&dvbusy)) 2625 dvbusy = 0; 2626 2627 /* 2628 * To catch device opens currently maintained on specfs common snodes. 2629 */ 2630 if (mod_hash_find(bsp->s_hash, dip, (mod_hash_val_t *)&sbusy)) 2631 sbusy = 0; 2632 2633 #ifdef DEBUG 2634 if (ref < sbusy || ref < dvbusy) { 2635 cmn_err(CE_WARN, "dip(%p): sopen = %lu, dvopen = %lu " 2636 "dip ref = %lu\n", (void *)dip, sbusy, dvbusy, ref); 2637 } 2638 #endif 2639 2640 dvbusy = (sbusy > dvbusy) ? sbusy : dvbusy; 2641 2642 return (bsp->callback(dip, bsp->arg, dvbusy)); 2643 } 2644 2645 static int 2646 visit_snode(struct snode *sp, void *arg) 2647 { 2648 uintptr_t sbusy; 2649 dev_info_t *dip; 2650 int count; 2651 struct devi_busy *bsp = arg; 2652 2653 ASSERT(sp); 2654 2655 /* 2656 * The stable lock is held. This prevents 2657 * the snode and its associated dip from 2658 * going away. 2659 */ 2660 dip = NULL; 2661 count = spec_devi_open_count(sp, &dip); 2662 2663 if (count <= 0) 2664 return (DDI_WALK_CONTINUE); 2665 2666 ASSERT(dip); 2667 2668 if (mod_hash_remove(bsp->s_hash, dip, (mod_hash_val_t *)&sbusy)) 2669 sbusy = count; 2670 else 2671 sbusy += count; 2672 2673 if (mod_hash_insert(bsp->s_hash, dip, (mod_hash_val_t)sbusy)) { 2674 cmn_err(CE_WARN, "%s: s_hash insert failed: dip=0x%p, " 2675 "sbusy = %lu", "e_ddi_branch_referenced", 2676 (void *)dip, sbusy); 2677 } 2678 2679 bsp->s_total += count; 2680 2681 return (DDI_WALK_CONTINUE); 2682 } 2683 2684 static void 2685 visit_dvnode(struct dv_node *dv, void *arg) 2686 { 2687 uintptr_t dvbusy; 2688 uint_t count; 2689 struct vnode *vp; 2690 struct devi_busy *bsp = arg; 2691 2692 ASSERT(dv && dv->dv_devi); 2693 2694 vp = DVTOV(dv); 2695 2696 mutex_enter(&vp->v_lock); 2697 count = vp->v_count; 2698 mutex_exit(&vp->v_lock); 2699 2700 if (!count) 2701 return; 2702 2703 if (mod_hash_remove(bsp->dv_hash, dv->dv_devi, 2704 (mod_hash_val_t *)&dvbusy)) 2705 dvbusy = count; 2706 else 2707 dvbusy += count; 2708 2709 if (mod_hash_insert(bsp->dv_hash, dv->dv_devi, 2710 (mod_hash_val_t)dvbusy)) { 2711 cmn_err(CE_WARN, "%s: dv_hash insert failed: dip=0x%p, " 2712 "dvbusy=%lu", "e_ddi_branch_referenced", 2713 (void *)dv->dv_devi, dvbusy); 2714 } 2715 2716 bsp->dv_total += count; 2717 } 2718 2719 /* 2720 * Returns reference count on success or -1 on failure. 2721 */ 2722 int 2723 e_ddi_branch_referenced( 2724 dev_info_t *rdip, 2725 int (*callback)(dev_info_t *dip, void *arg, uint_t ref), 2726 void *arg) 2727 { 2728 int circ; 2729 char *path; 2730 dev_info_t *pdip; 2731 struct devi_busy bsa = {0}; 2732 2733 ASSERT(rdip); 2734 2735 path = kmem_alloc(MAXPATHLEN, KM_SLEEP); 2736 2737 ndi_hold_devi(rdip); 2738 2739 pdip = ddi_get_parent(rdip); 2740 2741 ASSERT(pdip); 2742 2743 /* 2744 * Check if caller holds pdip busy - can cause deadlocks during 2745 * devfs_walk() 2746 */ 2747 if (!e_ddi_branch_held(rdip) || DEVI_BUSY_OWNED(pdip)) { 2748 cmn_err(CE_WARN, "e_ddi_branch_referenced: failed: " 2749 "devinfo branch(%p) not held or parent busy held", 2750 (void *)rdip); 2751 ndi_rele_devi(rdip); 2752 kmem_free(path, MAXPATHLEN); 2753 return (-1); 2754 } 2755 2756 ndi_devi_enter(pdip, &circ); 2757 (void) ddi_pathname(rdip, path); 2758 ndi_devi_exit(pdip, circ); 2759 2760 bsa.dv_hash = mod_hash_create_ptrhash("dv_node busy hash", NUMCHAINS, 2761 mod_hash_null_valdtor, sizeof (struct dev_info)); 2762 2763 bsa.s_hash = mod_hash_create_ptrhash("snode busy hash", NUMCHAINS, 2764 mod_hash_null_valdtor, sizeof (struct snode)); 2765 2766 if (devfs_walk(path, visit_dvnode, &bsa)) { 2767 cmn_err(CE_WARN, "e_ddi_branch_referenced: " 2768 "devfs walk failed for: %s", path); 2769 kmem_free(path, MAXPATHLEN); 2770 bsa.s_total = bsa.dv_total = -1; 2771 goto out; 2772 } 2773 2774 kmem_free(path, MAXPATHLEN); 2775 2776 /* 2777 * Walk the snode table to detect device opens, which are currently 2778 * maintained on specfs common snodes. 2779 */ 2780 spec_snode_walk(visit_snode, &bsa); 2781 2782 if (callback == NULL) 2783 goto out; 2784 2785 bsa.callback = callback; 2786 bsa.arg = arg; 2787 2788 if (visit_dip(rdip, &bsa) == DDI_WALK_CONTINUE) { 2789 ndi_devi_enter(rdip, &circ); 2790 ddi_walk_devs(ddi_get_child(rdip), visit_dip, &bsa); 2791 ndi_devi_exit(rdip, circ); 2792 } 2793 2794 out: 2795 ndi_rele_devi(rdip); 2796 mod_hash_destroy_ptrhash(bsa.s_hash); 2797 mod_hash_destroy_ptrhash(bsa.dv_hash); 2798 return (bsa.s_total > bsa.dv_total ? bsa.s_total : bsa.dv_total); 2799 } 2800