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