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