1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * Logical domain channel devices are devices implemented entirely 30 * in software; cnex is the nexus for channel-devices. They use 31 * the HV channel interfaces via the LDC transport module to send 32 * and receive data and to register callbacks. 33 */ 34 35 #include <sys/types.h> 36 #include <sys/cmn_err.h> 37 #include <sys/conf.h> 38 #include <sys/ddi.h> 39 #include <sys/ddi_impldefs.h> 40 #include <sys/devops.h> 41 #include <sys/instance.h> 42 #include <sys/modctl.h> 43 #include <sys/open.h> 44 #include <sys/stat.h> 45 #include <sys/sunddi.h> 46 #include <sys/sunndi.h> 47 #include <sys/systm.h> 48 #include <sys/mkdev.h> 49 #include <sys/machsystm.h> 50 #include <sys/intreg.h> 51 #include <sys/intr.h> 52 #include <sys/ddi_intr_impl.h> 53 #include <sys/ivintr.h> 54 #include <sys/hypervisor_api.h> 55 #include <sys/ldc.h> 56 #include <sys/cnex.h> 57 #include <sys/mach_descrip.h> 58 #include <sys/hsvc.h> 59 #include <sys/sdt.h> 60 61 /* 62 * Internal functions/information 63 */ 64 static struct cnex_pil_map cnex_class_to_pil[] = { 65 {LDC_DEV_GENERIC, PIL_3}, 66 {LDC_DEV_BLK, PIL_4}, 67 {LDC_DEV_BLK_SVC, PIL_3}, 68 {LDC_DEV_NT, PIL_6}, 69 {LDC_DEV_NT_SVC, PIL_4}, 70 {LDC_DEV_SERIAL, PIL_6} 71 }; 72 #define CNEX_MAX_DEVS (sizeof (cnex_class_to_pil) / \ 73 sizeof (cnex_class_to_pil[0])) 74 75 #define SUN4V_REG_SPEC2CFG_HDL(x) ((x >> 32) & ~(0xfull << 28)) 76 77 static clock_t cnex_wait_usecs = 1000; /* wait time in usecs */ 78 static int cnex_wait_retries = 3; 79 static void *cnex_state; 80 81 static void cnex_intr_redist(void *arg); 82 static uint_t cnex_intr_wrapper(caddr_t arg); 83 static dev_info_t *cnex_find_chan_dip(dev_info_t *dip, uint64_t chan_id, 84 md_t *mdp, mde_cookie_t mde); 85 86 /* 87 * Debug info 88 */ 89 #ifdef DEBUG 90 91 /* 92 * Print debug messages 93 * 94 * set cnexdbg to 0xf for enabling all msgs 95 * 0x8 - Errors 96 * 0x4 - Warnings 97 * 0x2 - All debug messages 98 * 0x1 - Minimal debug messages 99 */ 100 101 int cnexdbg = 0x8; 102 103 static void 104 cnexdebug(const char *fmt, ...) 105 { 106 char buf[512]; 107 va_list ap; 108 109 va_start(ap, fmt); 110 (void) vsprintf(buf, fmt, ap); 111 va_end(ap); 112 113 cmn_err(CE_CONT, "%s\n", buf); 114 } 115 116 #define D1 \ 117 if (cnexdbg & 0x01) \ 118 cnexdebug 119 120 #define D2 \ 121 if (cnexdbg & 0x02) \ 122 cnexdebug 123 124 #define DWARN \ 125 if (cnexdbg & 0x04) \ 126 cnexdebug 127 128 #define DERR \ 129 if (cnexdbg & 0x08) \ 130 cnexdebug 131 132 #else 133 134 #define D1 135 #define D2 136 #define DWARN 137 #define DERR 138 139 #endif 140 141 /* 142 * Config information 143 */ 144 static int cnex_attach(dev_info_t *, ddi_attach_cmd_t); 145 static int cnex_detach(dev_info_t *, ddi_detach_cmd_t); 146 static int cnex_open(dev_t *, int, int, cred_t *); 147 static int cnex_close(dev_t, int, int, cred_t *); 148 static int cnex_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 149 static int cnex_ctl(dev_info_t *, dev_info_t *, ddi_ctl_enum_t, void *, 150 void *); 151 152 static struct bus_ops cnex_bus_ops = { 153 BUSO_REV, 154 nullbusmap, /* bus_map */ 155 NULL, /* bus_get_intrspec */ 156 NULL, /* bus_add_intrspec */ 157 NULL, /* bus_remove_intrspec */ 158 i_ddi_map_fault, /* bus_map_fault */ 159 ddi_no_dma_map, /* bus_dma_map */ 160 ddi_no_dma_allochdl, /* bus_dma_allochdl */ 161 NULL, /* bus_dma_freehdl */ 162 NULL, /* bus_dma_bindhdl */ 163 NULL, /* bus_dma_unbindhdl */ 164 NULL, /* bus_dma_flush */ 165 NULL, /* bus_dma_win */ 166 NULL, /* bus_dma_ctl */ 167 cnex_ctl, /* bus_ctl */ 168 ddi_bus_prop_op, /* bus_prop_op */ 169 0, /* bus_get_eventcookie */ 170 0, /* bus_add_eventcall */ 171 0, /* bus_remove_eventcall */ 172 0, /* bus_post_event */ 173 NULL, /* bus_intr_ctl */ 174 NULL, /* bus_config */ 175 NULL, /* bus_unconfig */ 176 NULL, /* bus_fm_init */ 177 NULL, /* bus_fm_fini */ 178 NULL, /* bus_fm_access_enter */ 179 NULL, /* bus_fm_access_exit */ 180 NULL, /* bus_power */ 181 NULL /* bus_intr_op */ 182 }; 183 184 static struct cb_ops cnex_cb_ops = { 185 cnex_open, /* open */ 186 cnex_close, /* close */ 187 nodev, /* strategy */ 188 nodev, /* print */ 189 nodev, /* dump */ 190 nodev, /* read */ 191 nodev, /* write */ 192 cnex_ioctl, /* ioctl */ 193 nodev, /* devmap */ 194 nodev, /* mmap */ 195 nodev, /* segmap */ 196 nochpoll, /* poll */ 197 ddi_prop_op, /* cb_prop_op */ 198 0, /* streamtab */ 199 D_MP | D_NEW | D_HOTPLUG /* Driver compatibility flag */ 200 }; 201 202 static struct dev_ops cnex_ops = { 203 DEVO_REV, /* devo_rev, */ 204 0, /* refcnt */ 205 ddi_getinfo_1to1, /* info */ 206 nulldev, /* identify */ 207 nulldev, /* probe */ 208 cnex_attach, /* attach */ 209 cnex_detach, /* detach */ 210 nodev, /* reset */ 211 &cnex_cb_ops, /* driver operations */ 212 &cnex_bus_ops, /* bus operations */ 213 nulldev /* power */ 214 }; 215 216 /* 217 * Module linkage information for the kernel. 218 */ 219 static struct modldrv modldrv = { 220 &mod_driverops, 221 "sun4v channel-devices nexus %I%", 222 &cnex_ops, 223 }; 224 225 static struct modlinkage modlinkage = { 226 MODREV_1, (void *)&modldrv, NULL 227 }; 228 229 int 230 _init(void) 231 { 232 int err; 233 uint64_t majornum; 234 uint64_t minornum; 235 236 /* 237 * Check HV intr group api versioning. 238 * Note that cnex assumes interrupt cookies is 239 * in version 1.0 of the intr group api. 240 */ 241 if ((err = hsvc_version(HSVC_GROUP_INTR, &majornum, &minornum)) != 0) { 242 cmn_err(CE_WARN, "cnex: failed to get intr api " 243 "group versioning errno=%d", err); 244 return (err); 245 } else if ((majornum != 1) && (majornum != 2)) { 246 cmn_err(CE_WARN, "cnex: unsupported intr api group: " 247 "maj:0x%lx, min:0x%lx", majornum, minornum); 248 return (ENOTSUP); 249 } 250 251 if ((err = ddi_soft_state_init(&cnex_state, 252 sizeof (cnex_soft_state_t), 0)) != 0) { 253 return (err); 254 } 255 if ((err = mod_install(&modlinkage)) != 0) { 256 ddi_soft_state_fini(&cnex_state); 257 return (err); 258 } 259 return (0); 260 } 261 262 int 263 _fini(void) 264 { 265 int err; 266 267 if ((err = mod_remove(&modlinkage)) != 0) 268 return (err); 269 ddi_soft_state_fini(&cnex_state); 270 return (0); 271 } 272 273 int 274 _info(struct modinfo *modinfop) 275 { 276 return (mod_info(&modlinkage, modinfop)); 277 } 278 279 /* 280 * Callback function invoked by the interrupt redistribution 281 * framework. This will redirect interrupts at CPUs that are 282 * currently available in the system. 283 */ 284 static void 285 cnex_intr_redist(void *arg) 286 { 287 cnex_ldc_t *cldcp; 288 cnex_soft_state_t *cnex_ssp = arg; 289 int intr_state; 290 uint64_t cpuid; 291 int rv, retries = 0; 292 293 ASSERT(cnex_ssp != NULL); 294 mutex_enter(&cnex_ssp->clist_lock); 295 296 cldcp = cnex_ssp->clist; 297 while (cldcp != NULL) { 298 299 mutex_enter(&cldcp->lock); 300 301 if (cldcp->tx.hdlr) { 302 /* 303 * Don't do anything for disabled interrupts. 304 */ 305 rv = hvldc_intr_getvalid(cnex_ssp->cfghdl, 306 cldcp->tx.ino, &intr_state); 307 if (rv) { 308 DWARN("cnex_intr_redist: tx ino=0x%llx, " 309 "can't get valid\n", cldcp->tx.ino); 310 mutex_exit(&cldcp->lock); 311 mutex_exit(&cnex_ssp->clist_lock); 312 return; 313 } 314 if (intr_state == HV_INTR_NOTVALID) { 315 mutex_exit(&cldcp->lock); 316 cldcp = cldcp->next; 317 continue; 318 } 319 320 cpuid = intr_dist_cpuid(); 321 322 /* disable interrupts */ 323 rv = hvldc_intr_setvalid(cnex_ssp->cfghdl, 324 cldcp->tx.ino, HV_INTR_NOTVALID); 325 if (rv) { 326 DWARN("cnex_intr_redist: tx ino=0x%llx, " 327 "can't set valid\n", cldcp->tx.ino); 328 mutex_exit(&cldcp->lock); 329 mutex_exit(&cnex_ssp->clist_lock); 330 return; 331 } 332 333 /* 334 * Make a best effort to wait for pending interrupts 335 * to finish. There is not much we can do if we timeout. 336 */ 337 retries = 0; 338 339 do { 340 rv = hvldc_intr_getstate(cnex_ssp->cfghdl, 341 cldcp->tx.ino, &intr_state); 342 if (rv) { 343 DWARN("cnex_intr_redist: tx ino=0x%llx," 344 "can't get state\n", cldcp->tx.ino); 345 mutex_exit(&cldcp->lock); 346 mutex_exit(&cnex_ssp->clist_lock); 347 return; 348 } 349 350 if (intr_state != HV_INTR_DELIVERED_STATE) 351 break; 352 353 drv_usecwait(cnex_wait_usecs); 354 355 } while (!panicstr && ++retries <= cnex_wait_retries); 356 357 cldcp->tx.cpuid = cpuid; 358 (void) hvldc_intr_settarget(cnex_ssp->cfghdl, 359 cldcp->tx.ino, cpuid); 360 (void) hvldc_intr_setvalid(cnex_ssp->cfghdl, 361 cldcp->tx.ino, HV_INTR_VALID); 362 } 363 364 if (cldcp->rx.hdlr) { 365 /* 366 * Don't do anything for disabled interrupts. 367 */ 368 rv = hvldc_intr_getvalid(cnex_ssp->cfghdl, 369 cldcp->rx.ino, &intr_state); 370 if (rv) { 371 DWARN("cnex_intr_redist: rx ino=0x%llx, " 372 "can't get valid\n", cldcp->rx.ino); 373 mutex_exit(&cldcp->lock); 374 mutex_exit(&cnex_ssp->clist_lock); 375 return; 376 } 377 if (intr_state == HV_INTR_NOTVALID) { 378 mutex_exit(&cldcp->lock); 379 cldcp = cldcp->next; 380 continue; 381 } 382 383 cpuid = intr_dist_cpuid(); 384 385 /* disable interrupts */ 386 rv = hvldc_intr_setvalid(cnex_ssp->cfghdl, 387 cldcp->rx.ino, HV_INTR_NOTVALID); 388 if (rv) { 389 DWARN("cnex_intr_redist: rx ino=0x%llx, " 390 "can't set valid\n", cldcp->rx.ino); 391 mutex_exit(&cldcp->lock); 392 mutex_exit(&cnex_ssp->clist_lock); 393 return; 394 } 395 396 /* 397 * Make a best effort to wait for pending interrupts 398 * to finish. There is not much we can do if we timeout. 399 */ 400 retries = 0; 401 402 do { 403 rv = hvldc_intr_getstate(cnex_ssp->cfghdl, 404 cldcp->rx.ino, &intr_state); 405 if (rv) { 406 DWARN("cnex_intr_redist: rx ino=0x%llx," 407 "can't get state\n", cldcp->rx.ino); 408 mutex_exit(&cldcp->lock); 409 mutex_exit(&cnex_ssp->clist_lock); 410 return; 411 } 412 413 if (intr_state != HV_INTR_DELIVERED_STATE) 414 break; 415 416 drv_usecwait(cnex_wait_usecs); 417 418 } while (!panicstr && ++retries <= cnex_wait_retries); 419 420 cldcp->rx.cpuid = cpuid; 421 (void) hvldc_intr_settarget(cnex_ssp->cfghdl, 422 cldcp->rx.ino, cpuid); 423 (void) hvldc_intr_setvalid(cnex_ssp->cfghdl, 424 cldcp->rx.ino, HV_INTR_VALID); 425 } 426 427 mutex_exit(&cldcp->lock); 428 429 /* next channel */ 430 cldcp = cldcp->next; 431 } 432 433 mutex_exit(&cnex_ssp->clist_lock); 434 } 435 436 /* 437 * Exported interface to register a LDC endpoint with 438 * the channel nexus 439 */ 440 static int 441 cnex_reg_chan(dev_info_t *dip, uint64_t id, ldc_dev_t devclass) 442 { 443 int idx; 444 cnex_ldc_t *cldcp; 445 int listsz, num_nodes, num_channels; 446 md_t *mdp = NULL; 447 mde_cookie_t rootnode, *listp = NULL; 448 uint64_t tmp_id; 449 uint64_t rxino = (uint64_t)-1; 450 uint64_t txino = (uint64_t)-1; 451 cnex_soft_state_t *cnex_ssp; 452 int status, instance; 453 dev_info_t *chan_dip = NULL; 454 455 /* Get device instance and structure */ 456 instance = ddi_get_instance(dip); 457 cnex_ssp = ddi_get_soft_state(cnex_state, instance); 458 459 /* Check to see if channel is already registered */ 460 mutex_enter(&cnex_ssp->clist_lock); 461 cldcp = cnex_ssp->clist; 462 while (cldcp) { 463 if (cldcp->id == id) { 464 DWARN("cnex_reg_chan: channel 0x%llx exists\n", id); 465 mutex_exit(&cnex_ssp->clist_lock); 466 return (EINVAL); 467 } 468 cldcp = cldcp->next; 469 } 470 471 /* Get the Tx/Rx inos from the MD */ 472 if ((mdp = md_get_handle()) == NULL) { 473 DWARN("cnex_reg_chan: cannot init MD\n"); 474 mutex_exit(&cnex_ssp->clist_lock); 475 return (ENXIO); 476 } 477 num_nodes = md_node_count(mdp); 478 ASSERT(num_nodes > 0); 479 480 listsz = num_nodes * sizeof (mde_cookie_t); 481 listp = (mde_cookie_t *)kmem_zalloc(listsz, KM_SLEEP); 482 483 rootnode = md_root_node(mdp); 484 485 /* search for all channel_endpoint nodes */ 486 num_channels = md_scan_dag(mdp, rootnode, 487 md_find_name(mdp, "channel-endpoint"), 488 md_find_name(mdp, "fwd"), listp); 489 if (num_channels <= 0) { 490 DWARN("cnex_reg_chan: invalid channel id\n"); 491 kmem_free(listp, listsz); 492 (void) md_fini_handle(mdp); 493 mutex_exit(&cnex_ssp->clist_lock); 494 return (EINVAL); 495 } 496 497 for (idx = 0; idx < num_channels; idx++) { 498 499 /* Get the channel ID */ 500 status = md_get_prop_val(mdp, listp[idx], "id", &tmp_id); 501 if (status) { 502 DWARN("cnex_reg_chan: cannot read LDC ID\n"); 503 kmem_free(listp, listsz); 504 (void) md_fini_handle(mdp); 505 mutex_exit(&cnex_ssp->clist_lock); 506 return (ENXIO); 507 } 508 if (tmp_id != id) 509 continue; 510 511 /* Get the Tx and Rx ino */ 512 status = md_get_prop_val(mdp, listp[idx], "tx-ino", &txino); 513 if (status) { 514 DWARN("cnex_reg_chan: cannot read Tx ino\n"); 515 kmem_free(listp, listsz); 516 (void) md_fini_handle(mdp); 517 mutex_exit(&cnex_ssp->clist_lock); 518 return (ENXIO); 519 } 520 status = md_get_prop_val(mdp, listp[idx], "rx-ino", &rxino); 521 if (status) { 522 DWARN("cnex_reg_chan: cannot read Rx ino\n"); 523 kmem_free(listp, listsz); 524 (void) md_fini_handle(mdp); 525 mutex_exit(&cnex_ssp->clist_lock); 526 return (ENXIO); 527 } 528 chan_dip = cnex_find_chan_dip(dip, id, mdp, listp[idx]); 529 ASSERT(chan_dip != NULL); 530 } 531 kmem_free(listp, listsz); 532 (void) md_fini_handle(mdp); 533 534 /* 535 * check to see if we looped through the list of channel IDs without 536 * matching one (i.e. an 'ino' has not been initialised). 537 */ 538 if ((rxino == -1) || (txino == -1)) { 539 DERR("cnex_reg_chan: no ID matching '%llx' in MD\n", id); 540 mutex_exit(&cnex_ssp->clist_lock); 541 return (ENOENT); 542 } 543 544 /* Allocate a new channel structure */ 545 cldcp = kmem_zalloc(sizeof (*cldcp), KM_SLEEP); 546 547 /* Initialize the channel */ 548 mutex_init(&cldcp->lock, NULL, MUTEX_DRIVER, NULL); 549 550 cldcp->id = id; 551 cldcp->tx.ino = txino; 552 cldcp->rx.ino = rxino; 553 cldcp->devclass = devclass; 554 cldcp->dip = chan_dip; 555 556 /* add channel to nexus channel list */ 557 cldcp->next = cnex_ssp->clist; 558 cnex_ssp->clist = cldcp; 559 560 mutex_exit(&cnex_ssp->clist_lock); 561 562 return (0); 563 } 564 565 /* 566 * Add Tx/Rx interrupt handler for the channel 567 */ 568 static int 569 cnex_add_intr(dev_info_t *dip, uint64_t id, cnex_intrtype_t itype, 570 uint_t (*hdlr)(), caddr_t arg1, caddr_t arg2) 571 { 572 int rv, idx, pil; 573 cnex_ldc_t *cldcp; 574 cnex_intr_t *iinfo; 575 cnex_soft_state_t *cnex_ssp; 576 int instance; 577 578 /* Get device instance and structure */ 579 instance = ddi_get_instance(dip); 580 cnex_ssp = ddi_get_soft_state(cnex_state, instance); 581 582 /* get channel info */ 583 mutex_enter(&cnex_ssp->clist_lock); 584 cldcp = cnex_ssp->clist; 585 while (cldcp) { 586 if (cldcp->id == id) 587 break; 588 cldcp = cldcp->next; 589 } 590 if (cldcp == NULL) { 591 DWARN("cnex_add_intr: channel 0x%llx does not exist\n", id); 592 mutex_exit(&cnex_ssp->clist_lock); 593 return (EINVAL); 594 } 595 mutex_exit(&cnex_ssp->clist_lock); 596 597 /* get channel lock */ 598 mutex_enter(&cldcp->lock); 599 600 /* get interrupt type */ 601 if (itype == CNEX_TX_INTR) { 602 iinfo = &(cldcp->tx); 603 } else if (itype == CNEX_RX_INTR) { 604 iinfo = &(cldcp->rx); 605 } else { 606 DWARN("cnex_add_intr: invalid interrupt type\n", id); 607 mutex_exit(&cldcp->lock); 608 return (EINVAL); 609 } 610 611 /* check if a handler is already added */ 612 if (iinfo->hdlr != 0) { 613 DWARN("cnex_add_intr: interrupt handler exists\n"); 614 mutex_exit(&cldcp->lock); 615 return (EINVAL); 616 } 617 618 /* save interrupt handler info */ 619 iinfo->hdlr = hdlr; 620 iinfo->arg1 = arg1; 621 iinfo->arg2 = arg2; 622 623 iinfo->cldcp = cldcp; 624 625 iinfo->icookie = MINVINTR_COOKIE + iinfo->ino; 626 627 /* 628 * Verify that the ino does not generate a cookie which 629 * is outside the (MINVINTR_COOKIE, MAXIVNUM) range of the 630 * system interrupt table. 631 */ 632 if (iinfo->icookie >= MAXIVNUM || iinfo->icookie < MINVINTR_COOKIE) { 633 DWARN("cnex_add_intr: invalid cookie %x ino %x\n", 634 iinfo->icookie, iinfo->ino); 635 mutex_exit(&cldcp->lock); 636 return (EINVAL); 637 } 638 639 D1("cnex_add_intr: add hdlr, cfghdl=0x%llx, ino=0x%llx, " 640 "cookie=0x%llx\n", cnex_ssp->cfghdl, iinfo->ino, iinfo->icookie); 641 642 /* Pick a PIL on the basis of the channel's devclass */ 643 for (idx = 0, pil = PIL_3; idx < CNEX_MAX_DEVS; idx++) { 644 if (cldcp->devclass == cnex_class_to_pil[idx].devclass) { 645 pil = cnex_class_to_pil[idx].pil; 646 break; 647 } 648 } 649 650 /* add interrupt to solaris ivec table */ 651 if (add_ivintr(iinfo->icookie, pil, (intrfunc)cnex_intr_wrapper, 652 (caddr_t)iinfo, NULL, NULL) != 0) { 653 DWARN("cnex_add_intr: add_ivintr fail cookie %x ino %x\n", 654 iinfo->icookie, iinfo->ino); 655 mutex_exit(&cldcp->lock); 656 return (EINVAL); 657 } 658 659 /* set the cookie in the HV */ 660 rv = hvldc_intr_setcookie(cnex_ssp->cfghdl, iinfo->ino, iinfo->icookie); 661 662 /* pick next CPU in the domain for this channel */ 663 iinfo->cpuid = intr_dist_cpuid(); 664 665 /* set the target CPU and then enable interrupts */ 666 rv = hvldc_intr_settarget(cnex_ssp->cfghdl, iinfo->ino, iinfo->cpuid); 667 if (rv) { 668 DWARN("cnex_add_intr: ino=0x%llx, cannot set target cpu\n", 669 iinfo->ino); 670 goto hv_error; 671 } 672 rv = hvldc_intr_setstate(cnex_ssp->cfghdl, iinfo->ino, 673 HV_INTR_IDLE_STATE); 674 if (rv) { 675 DWARN("cnex_add_intr: ino=0x%llx, cannot set state\n", 676 iinfo->ino); 677 goto hv_error; 678 } 679 rv = hvldc_intr_setvalid(cnex_ssp->cfghdl, iinfo->ino, HV_INTR_VALID); 680 if (rv) { 681 DWARN("cnex_add_intr: ino=0x%llx, cannot set valid\n", 682 iinfo->ino); 683 goto hv_error; 684 } 685 686 mutex_exit(&cldcp->lock); 687 return (0); 688 689 hv_error: 690 (void) rem_ivintr(iinfo->icookie, pil); 691 mutex_exit(&cldcp->lock); 692 return (ENXIO); 693 } 694 695 696 /* 697 * Exported interface to unregister a LDC endpoint with 698 * the channel nexus 699 */ 700 static int 701 cnex_unreg_chan(dev_info_t *dip, uint64_t id) 702 { 703 cnex_ldc_t *cldcp, *prev_cldcp; 704 cnex_soft_state_t *cnex_ssp; 705 int instance; 706 707 /* Get device instance and structure */ 708 instance = ddi_get_instance(dip); 709 cnex_ssp = ddi_get_soft_state(cnex_state, instance); 710 711 /* find and remove channel from list */ 712 mutex_enter(&cnex_ssp->clist_lock); 713 prev_cldcp = NULL; 714 cldcp = cnex_ssp->clist; 715 while (cldcp) { 716 if (cldcp->id == id) 717 break; 718 prev_cldcp = cldcp; 719 cldcp = cldcp->next; 720 } 721 722 if (cldcp == 0) { 723 DWARN("cnex_unreg_chan: invalid channel %d\n", id); 724 mutex_exit(&cnex_ssp->clist_lock); 725 return (EINVAL); 726 } 727 728 if (cldcp->tx.hdlr || cldcp->rx.hdlr) { 729 DWARN("cnex_unreg_chan: handlers still exist: chan %lx\n", id); 730 mutex_exit(&cnex_ssp->clist_lock); 731 return (ENXIO); 732 } 733 734 if (prev_cldcp) 735 prev_cldcp->next = cldcp->next; 736 else 737 cnex_ssp->clist = cldcp->next; 738 739 mutex_exit(&cnex_ssp->clist_lock); 740 741 /* destroy mutex */ 742 mutex_destroy(&cldcp->lock); 743 744 /* free channel */ 745 kmem_free(cldcp, sizeof (*cldcp)); 746 747 return (0); 748 } 749 750 /* 751 * Remove Tx/Rx interrupt handler for the channel 752 */ 753 static int 754 cnex_rem_intr(dev_info_t *dip, uint64_t id, cnex_intrtype_t itype) 755 { 756 int rv, idx, pil; 757 cnex_ldc_t *cldcp; 758 cnex_intr_t *iinfo; 759 cnex_soft_state_t *cnex_ssp; 760 int instance, istate; 761 762 /* Get device instance and structure */ 763 instance = ddi_get_instance(dip); 764 cnex_ssp = ddi_get_soft_state(cnex_state, instance); 765 766 /* get channel info */ 767 mutex_enter(&cnex_ssp->clist_lock); 768 cldcp = cnex_ssp->clist; 769 while (cldcp) { 770 if (cldcp->id == id) 771 break; 772 cldcp = cldcp->next; 773 } 774 if (cldcp == NULL) { 775 DWARN("cnex_rem_intr: channel 0x%llx does not exist\n", id); 776 mutex_exit(&cnex_ssp->clist_lock); 777 return (EINVAL); 778 } 779 mutex_exit(&cnex_ssp->clist_lock); 780 781 /* get rid of the channel intr handler */ 782 mutex_enter(&cldcp->lock); 783 784 /* get interrupt type */ 785 if (itype == CNEX_TX_INTR) { 786 iinfo = &(cldcp->tx); 787 } else if (itype == CNEX_RX_INTR) { 788 iinfo = &(cldcp->rx); 789 } else { 790 DWARN("cnex_rem_intr: invalid interrupt type\n"); 791 mutex_exit(&cldcp->lock); 792 return (EINVAL); 793 } 794 795 D1("cnex_rem_intr: interrupt ino=0x%x\n", iinfo->ino); 796 797 /* check if a handler is already added */ 798 if (iinfo->hdlr == 0) { 799 DWARN("cnex_rem_intr: interrupt handler does not exist\n"); 800 mutex_exit(&cldcp->lock); 801 return (EINVAL); 802 } 803 804 D1("cnex_rem_intr: set intr to invalid ino=0x%x\n", iinfo->ino); 805 rv = hvldc_intr_setvalid(cnex_ssp->cfghdl, 806 iinfo->ino, HV_INTR_NOTVALID); 807 if (rv) { 808 DWARN("cnex_rem_intr: cannot set valid ino=%x\n", iinfo->ino); 809 mutex_exit(&cldcp->lock); 810 return (ENXIO); 811 } 812 813 /* 814 * Check if there are pending interrupts. If interrupts are 815 * pending return EAGAIN. 816 */ 817 rv = hvldc_intr_getstate(cnex_ssp->cfghdl, iinfo->ino, &istate); 818 if (rv) { 819 DWARN("cnex_rem_intr: ino=0x%llx, cannot get state\n", 820 iinfo->ino); 821 mutex_exit(&cldcp->lock); 822 return (ENXIO); 823 } 824 825 /* if interrupts are still pending print warning */ 826 if (istate != HV_INTR_IDLE_STATE) { 827 DWARN("cnex_rem_intr: cannot remove intr busy ino=%x\n", 828 iinfo->ino); 829 mutex_exit(&cldcp->lock); 830 return (EAGAIN); 831 } 832 833 /* Pick a PIL on the basis of the channel's devclass */ 834 for (idx = 0, pil = PIL_3; idx < CNEX_MAX_DEVS; idx++) { 835 if (cldcp->devclass == cnex_class_to_pil[idx].devclass) { 836 pil = cnex_class_to_pil[idx].pil; 837 break; 838 } 839 } 840 841 /* remove interrupt */ 842 (void) rem_ivintr(iinfo->icookie, pil); 843 844 /* clear interrupt info */ 845 bzero(iinfo, sizeof (*iinfo)); 846 847 mutex_exit(&cldcp->lock); 848 849 return (0); 850 } 851 852 853 /* 854 * Clear pending Tx/Rx interrupt 855 */ 856 static int 857 cnex_clr_intr(dev_info_t *dip, uint64_t id, cnex_intrtype_t itype) 858 { 859 int rv; 860 cnex_ldc_t *cldcp; 861 cnex_intr_t *iinfo; 862 cnex_soft_state_t *cnex_ssp; 863 int instance; 864 865 /* Get device instance and structure */ 866 instance = ddi_get_instance(dip); 867 cnex_ssp = ddi_get_soft_state(cnex_state, instance); 868 869 /* get channel info */ 870 mutex_enter(&cnex_ssp->clist_lock); 871 cldcp = cnex_ssp->clist; 872 while (cldcp) { 873 if (cldcp->id == id) 874 break; 875 cldcp = cldcp->next; 876 } 877 if (cldcp == NULL) { 878 DWARN("cnex_clr_intr: channel 0x%llx does not exist\n", id); 879 mutex_exit(&cnex_ssp->clist_lock); 880 return (EINVAL); 881 } 882 mutex_exit(&cnex_ssp->clist_lock); 883 884 mutex_enter(&cldcp->lock); 885 886 /* get interrupt type */ 887 if (itype == CNEX_TX_INTR) { 888 iinfo = &(cldcp->tx); 889 } else if (itype == CNEX_RX_INTR) { 890 iinfo = &(cldcp->rx); 891 } else { 892 DWARN("cnex_clr_intr: invalid interrupt type\n"); 893 mutex_exit(&cldcp->lock); 894 return (EINVAL); 895 } 896 897 D1("cnex_rem_intr: interrupt ino=0x%x\n", iinfo->ino); 898 899 /* check if a handler is already added */ 900 if (iinfo->hdlr == 0) { 901 DWARN("cnex_clr_intr: interrupt handler does not exist\n"); 902 mutex_exit(&cldcp->lock); 903 return (EINVAL); 904 } 905 906 rv = hvldc_intr_setstate(cnex_ssp->cfghdl, iinfo->ino, 907 HV_INTR_IDLE_STATE); 908 if (rv) { 909 DWARN("cnex_clr_intr: cannot clear interrupt state\n"); 910 mutex_exit(&cldcp->lock); 911 return (ENXIO); 912 } 913 914 mutex_exit(&cldcp->lock); 915 916 return (0); 917 } 918 919 /* 920 * Channel nexus interrupt handler wrapper 921 */ 922 static uint_t 923 cnex_intr_wrapper(caddr_t arg) 924 { 925 int res; 926 uint_t (*handler)(); 927 caddr_t handler_arg1; 928 caddr_t handler_arg2; 929 cnex_intr_t *iinfo = (cnex_intr_t *)arg; 930 931 ASSERT(iinfo != NULL); 932 933 handler = iinfo->hdlr; 934 handler_arg1 = iinfo->arg1; 935 handler_arg2 = iinfo->arg2; 936 937 /* 938 * The 'interrupt__start' and 'interrupt__complete' probes 939 * are provided to support 'intrstat' command. These probes 940 * help monitor the interrupts on a per device basis only. 941 * In order to provide the ability to monitor the 942 * activity on a per channel basis, two additional 943 * probes('channelintr__start','channelintr__complete') 944 * are provided here. 945 */ 946 DTRACE_PROBE4(channelintr__start, uint64_t, iinfo->cldcp->id, 947 cnex_intr_t *, iinfo, void *, handler, caddr_t, handler_arg1); 948 949 DTRACE_PROBE4(interrupt__start, dev_info_t, iinfo->cldcp->dip, 950 void *, handler, caddr_t, handler_arg1, caddr_t, handler_arg2); 951 952 D1("cnex_intr_wrapper:ino=0x%llx invoke client handler\n", iinfo->ino); 953 res = (*handler)(handler_arg1, handler_arg2); 954 955 DTRACE_PROBE4(interrupt__complete, dev_info_t, iinfo->cldcp->dip, 956 void *, handler, caddr_t, handler_arg1, int, res); 957 958 DTRACE_PROBE4(channelintr__complete, uint64_t, iinfo->cldcp->id, 959 cnex_intr_t *, iinfo, void *, handler, caddr_t, handler_arg1); 960 961 return (res); 962 } 963 964 /*ARGSUSED*/ 965 static int 966 cnex_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) 967 { 968 int rv, instance, reglen; 969 cnex_regspec_t *reg_p; 970 ldc_cnex_t cinfo; 971 cnex_soft_state_t *cnex_ssp; 972 973 switch (cmd) { 974 case DDI_ATTACH: 975 break; 976 case DDI_RESUME: 977 return (DDI_SUCCESS); 978 default: 979 return (DDI_FAILURE); 980 } 981 982 /* 983 * Get the instance specific soft state structure. 984 * Save the devi for this instance in the soft_state data. 985 */ 986 instance = ddi_get_instance(devi); 987 if (ddi_soft_state_zalloc(cnex_state, instance) != DDI_SUCCESS) 988 return (DDI_FAILURE); 989 cnex_ssp = ddi_get_soft_state(cnex_state, instance); 990 991 cnex_ssp->devi = devi; 992 cnex_ssp->clist = NULL; 993 994 if (ddi_getlongprop(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS, 995 "reg", (caddr_t)®_p, ®len) != DDI_SUCCESS) { 996 return (DDI_FAILURE); 997 } 998 999 /* get the sun4v config handle for this device */ 1000 cnex_ssp->cfghdl = SUN4V_REG_SPEC2CFG_HDL(reg_p->physaddr); 1001 kmem_free(reg_p, reglen); 1002 1003 D1("cnex_attach: cfghdl=0x%llx\n", cnex_ssp->cfghdl); 1004 1005 /* init channel list mutex */ 1006 mutex_init(&cnex_ssp->clist_lock, NULL, MUTEX_DRIVER, NULL); 1007 1008 /* Register with LDC module */ 1009 cinfo.dip = devi; 1010 cinfo.reg_chan = cnex_reg_chan; 1011 cinfo.unreg_chan = cnex_unreg_chan; 1012 cinfo.add_intr = cnex_add_intr; 1013 cinfo.rem_intr = cnex_rem_intr; 1014 cinfo.clr_intr = cnex_clr_intr; 1015 1016 /* 1017 * LDC register will fail if an nexus instance had already 1018 * registered with the LDC framework 1019 */ 1020 rv = ldc_register(&cinfo); 1021 if (rv) { 1022 DWARN("cnex_attach: unable to register with LDC\n"); 1023 ddi_soft_state_free(cnex_state, instance); 1024 mutex_destroy(&cnex_ssp->clist_lock); 1025 return (DDI_FAILURE); 1026 } 1027 1028 if (ddi_create_minor_node(devi, "devctl", S_IFCHR, instance, 1029 DDI_NT_NEXUS, 0) != DDI_SUCCESS) { 1030 ddi_remove_minor_node(devi, NULL); 1031 ddi_soft_state_free(cnex_state, instance); 1032 mutex_destroy(&cnex_ssp->clist_lock); 1033 return (DDI_FAILURE); 1034 } 1035 1036 /* Add interrupt redistribution callback. */ 1037 intr_dist_add(cnex_intr_redist, cnex_ssp); 1038 1039 ddi_report_dev(devi); 1040 return (DDI_SUCCESS); 1041 } 1042 1043 /*ARGSUSED*/ 1044 static int 1045 cnex_detach(dev_info_t *devi, ddi_detach_cmd_t cmd) 1046 { 1047 int instance; 1048 ldc_cnex_t cinfo; 1049 cnex_soft_state_t *cnex_ssp; 1050 1051 switch (cmd) { 1052 case DDI_DETACH: 1053 break; 1054 case DDI_SUSPEND: 1055 return (DDI_SUCCESS); 1056 default: 1057 return (DDI_FAILURE); 1058 } 1059 1060 instance = ddi_get_instance(devi); 1061 cnex_ssp = ddi_get_soft_state(cnex_state, instance); 1062 1063 /* check if there are any channels still registered */ 1064 if (cnex_ssp->clist) { 1065 cmn_err(CE_WARN, "?cnex_dettach: channels registered %d\n", 1066 ddi_get_instance(devi)); 1067 return (DDI_FAILURE); 1068 } 1069 1070 /* Unregister with LDC module */ 1071 cinfo.dip = devi; 1072 (void) ldc_unregister(&cinfo); 1073 1074 /* Remove interrupt redistribution callback. */ 1075 intr_dist_rem(cnex_intr_redist, cnex_ssp); 1076 1077 /* destroy mutex */ 1078 mutex_destroy(&cnex_ssp->clist_lock); 1079 1080 /* free soft state structure */ 1081 ddi_soft_state_free(cnex_state, instance); 1082 1083 return (DDI_SUCCESS); 1084 } 1085 1086 /*ARGSUSED*/ 1087 static int 1088 cnex_open(dev_t *devp, int flags, int otyp, cred_t *credp) 1089 { 1090 int instance; 1091 1092 if (otyp != OTYP_CHR) 1093 return (EINVAL); 1094 1095 instance = getminor(*devp); 1096 if (ddi_get_soft_state(cnex_state, instance) == NULL) 1097 return (ENXIO); 1098 1099 return (0); 1100 } 1101 1102 /*ARGSUSED*/ 1103 static int 1104 cnex_close(dev_t dev, int flags, int otyp, cred_t *credp) 1105 { 1106 int instance; 1107 1108 if (otyp != OTYP_CHR) 1109 return (EINVAL); 1110 1111 instance = getminor(dev); 1112 if (ddi_get_soft_state(cnex_state, instance) == NULL) 1113 return (ENXIO); 1114 1115 return (0); 1116 } 1117 1118 /*ARGSUSED*/ 1119 static int 1120 cnex_ioctl(dev_t dev, 1121 int cmd, intptr_t arg, int mode, cred_t *cred_p, int *rval_p) 1122 { 1123 int instance; 1124 cnex_soft_state_t *cnex_ssp; 1125 1126 instance = getminor(dev); 1127 if ((cnex_ssp = ddi_get_soft_state(cnex_state, instance)) == NULL) 1128 return (ENXIO); 1129 ASSERT(cnex_ssp->devi); 1130 return (ndi_devctl_ioctl(cnex_ssp->devi, cmd, arg, mode, 0)); 1131 } 1132 1133 static int 1134 cnex_ctl(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t ctlop, 1135 void *arg, void *result) 1136 { 1137 char name[MAXNAMELEN]; 1138 uint32_t reglen; 1139 int *cnex_regspec; 1140 1141 switch (ctlop) { 1142 case DDI_CTLOPS_REPORTDEV: 1143 if (rdip == NULL) 1144 return (DDI_FAILURE); 1145 cmn_err(CE_CONT, "?channel-device: %s%d\n", 1146 ddi_driver_name(rdip), ddi_get_instance(rdip)); 1147 return (DDI_SUCCESS); 1148 1149 case DDI_CTLOPS_INITCHILD: 1150 { 1151 dev_info_t *child = (dev_info_t *)arg; 1152 1153 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child, 1154 DDI_PROP_DONTPASS, "reg", 1155 &cnex_regspec, ®len) != DDI_SUCCESS) { 1156 return (DDI_FAILURE); 1157 } 1158 1159 (void) snprintf(name, sizeof (name), "%x", *cnex_regspec); 1160 ddi_set_name_addr(child, name); 1161 ddi_set_parent_data(child, NULL); 1162 ddi_prop_free(cnex_regspec); 1163 return (DDI_SUCCESS); 1164 } 1165 1166 case DDI_CTLOPS_UNINITCHILD: 1167 { 1168 dev_info_t *child = (dev_info_t *)arg; 1169 1170 NDI_CONFIG_DEBUG((CE_NOTE, 1171 "DDI_CTLOPS_UNINITCHILD(%s, instance=%d)", 1172 ddi_driver_name(child), DEVI(child)->devi_instance)); 1173 1174 ddi_set_name_addr(child, NULL); 1175 1176 return (DDI_SUCCESS); 1177 } 1178 1179 case DDI_CTLOPS_DMAPMAPC: 1180 case DDI_CTLOPS_REPORTINT: 1181 case DDI_CTLOPS_REGSIZE: 1182 case DDI_CTLOPS_NREGS: 1183 case DDI_CTLOPS_SIDDEV: 1184 case DDI_CTLOPS_SLAVEONLY: 1185 case DDI_CTLOPS_AFFINITY: 1186 case DDI_CTLOPS_POKE: 1187 case DDI_CTLOPS_PEEK: 1188 /* 1189 * These ops correspond to functions that "shouldn't" be called 1190 * by a channel-device driver. So we whine when we're called. 1191 */ 1192 cmn_err(CE_WARN, "%s%d: invalid op (%d) from %s%d\n", 1193 ddi_driver_name(dip), ddi_get_instance(dip), ctlop, 1194 ddi_driver_name(rdip), ddi_get_instance(rdip)); 1195 return (DDI_FAILURE); 1196 1197 case DDI_CTLOPS_ATTACH: 1198 case DDI_CTLOPS_BTOP: 1199 case DDI_CTLOPS_BTOPR: 1200 case DDI_CTLOPS_DETACH: 1201 case DDI_CTLOPS_DVMAPAGESIZE: 1202 case DDI_CTLOPS_IOMIN: 1203 case DDI_CTLOPS_POWER: 1204 case DDI_CTLOPS_PTOB: 1205 default: 1206 /* 1207 * Everything else (e.g. PTOB/BTOP/BTOPR requests) we pass up 1208 */ 1209 return (ddi_ctlops(dip, rdip, ctlop, arg, result)); 1210 } 1211 } 1212 1213 /* 1214 * cnex_find_chan_dip -- Find the dip of a device that is corresponding 1215 * to the specific channel. Below are the details on how the dip 1216 * is derived. 1217 * 1218 * - In the MD, the cfg-handle is expected to be unique for 1219 * virtual-device nodes that have the same 'name' property value. 1220 * This value is expected to be the same as that of "reg" property 1221 * of the corresponding OBP device node. 1222 * 1223 * - The value of the 'name' property of a virtual-device node 1224 * in the MD is expected to be the same for the corresponding 1225 * OBP device node. 1226 * 1227 * - Find the virtual-device node corresponding to a channel-endpoint 1228 * by walking backwards. Then obtain the values for the 'name' and 1229 * 'cfg-handle' properties. 1230 * 1231 * - Walk all the children of the cnex, find a matching dip which 1232 * has the same 'name' and 'reg' property values. 1233 * 1234 * - The channels that have no corresponding device driver are 1235 * treated as if they correspond to the cnex driver, 1236 * that is, return cnex dip for them. This means, the 1237 * cnex acts as an umbrella device driver. Note, this is 1238 * for 'intrstat' statistics purposes only. As a result of this, 1239 * the 'intrstat' shows cnex as the device that is servicing the 1240 * interrupts corresponding to these channels. 1241 * 1242 * For now, only one such case is known, that is, the channels that 1243 * are used by the "domain-services". 1244 */ 1245 static dev_info_t * 1246 cnex_find_chan_dip(dev_info_t *dip, uint64_t chan_id, 1247 md_t *mdp, mde_cookie_t mde) 1248 { 1249 int listsz; 1250 int num_nodes; 1251 int num_devs; 1252 uint64_t cfghdl; 1253 char *md_name; 1254 mde_cookie_t *listp; 1255 dev_info_t *cdip = NULL; 1256 1257 num_nodes = md_node_count(mdp); 1258 ASSERT(num_nodes > 0); 1259 listsz = num_nodes * sizeof (mde_cookie_t); 1260 listp = (mde_cookie_t *)kmem_zalloc(listsz, KM_SLEEP); 1261 1262 num_devs = md_scan_dag(mdp, mde, md_find_name(mdp, "virtual-device"), 1263 md_find_name(mdp, "back"), listp); 1264 ASSERT(num_devs <= 1); 1265 if (num_devs <= 0) { 1266 DWARN("cnex_find_chan_dip:channel(0x%llx): " 1267 "No virtual-device found\n", chan_id); 1268 goto fdip_exit; 1269 } 1270 if (md_get_prop_str(mdp, listp[0], "name", &md_name) != 0) { 1271 DWARN("cnex_find_chan_dip:channel(0x%llx): " 1272 "name property not found\n", chan_id); 1273 goto fdip_exit; 1274 } 1275 1276 D1("cnex_find_chan_dip: channel(0x%llx): virtual-device " 1277 "name property value = %s\n", chan_id, md_name); 1278 1279 if (md_get_prop_val(mdp, listp[0], "cfg-handle", &cfghdl) != 0) { 1280 DWARN("cnex_find_chan_dip:channel(0x%llx): virtual-device's " 1281 "cfg-handle property not found\n", chan_id); 1282 goto fdip_exit; 1283 } 1284 1285 D1("cnex_find_chan_dip:channel(0x%llx): virtual-device cfg-handle " 1286 " property value = 0x%x\n", chan_id, cfghdl); 1287 1288 for (cdip = ddi_get_child(dip); cdip != NULL; 1289 cdip = ddi_get_next_sibling(cdip)) { 1290 1291 int *cnex_regspec; 1292 uint32_t reglen; 1293 char *dev_name; 1294 1295 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, cdip, 1296 DDI_PROP_DONTPASS, "name", 1297 &dev_name) != DDI_PROP_SUCCESS) { 1298 DWARN("cnex_find_chan_dip: name property not" 1299 " found for dip(0x%p)\n", cdip); 1300 continue; 1301 } 1302 if (strcmp(md_name, dev_name) != 0) { 1303 ddi_prop_free(dev_name); 1304 continue; 1305 } 1306 ddi_prop_free(dev_name); 1307 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, cdip, 1308 DDI_PROP_DONTPASS, "reg", 1309 &cnex_regspec, ®len) != DDI_SUCCESS) { 1310 DWARN("cnex_find_chan_dip: reg property not" 1311 " found for dip(0x%p)\n", cdip); 1312 continue; 1313 } 1314 if (*cnex_regspec == cfghdl) { 1315 D1("cnex_find_chan_dip:channel(0x%llx): found " 1316 "dip(0x%p) drvname=%s\n", chan_id, cdip, 1317 ddi_driver_name(cdip)); 1318 break; 1319 } 1320 ddi_prop_free(cnex_regspec); 1321 } 1322 1323 fdip_exit: 1324 if (cdip == NULL) { 1325 /* 1326 * If a virtual-device node exists but no dip found, 1327 * then for now print a DEBUG error message only. 1328 */ 1329 if (num_devs > 0) { 1330 DERR("cnex_find_chan_dip:channel(0x%llx): " 1331 "No device found\n", chan_id); 1332 } 1333 1334 /* If no dip was found, return cnex device's dip. */ 1335 cdip = dip; 1336 } 1337 1338 kmem_free(listp, listsz); 1339 D1("cnex_find_chan_dip:channel(0x%llx): returning dip=0x%p\n", 1340 chan_id, cdip); 1341 return (cdip); 1342 } 1343 1344 /* -------------------------------------------------------------------------- */ 1345