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 (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. 23 */ 24 25 26 /* 27 * Niagara2 Network Interface Unit (NIU) Nexus Driver 28 */ 29 30 #include <sys/conf.h> 31 #include <sys/modctl.h> 32 #include <sys/ddi_impldefs.h> 33 #include <sys/ddi_subrdefs.h> 34 #include <sys/ddi.h> 35 #include <sys/sunndi.h> 36 #include <sys/sunddi.h> 37 #include <sys/open.h> 38 #include <sys/stat.h> 39 #include <sys/file.h> 40 #include <sys/machsystm.h> 41 #include <sys/hsvc.h> 42 #include <sys/sdt.h> 43 #include <sys/hypervisor_api.h> 44 #include <sys/cpuvar.h> 45 #include "niumx_var.h" 46 47 static int niumx_fm_init_child(dev_info_t *, dev_info_t *, int, 48 ddi_iblock_cookie_t *); 49 static int niumx_intr_ops(dev_info_t *dip, dev_info_t *rdip, 50 ddi_intr_op_t intr_op, ddi_intr_handle_impl_t *hdlp, void *result); 51 static int niumx_attach(dev_info_t *devi, ddi_attach_cmd_t cmd); 52 static int niumx_detach(dev_info_t *devi, ddi_detach_cmd_t cmd); 53 static int niumx_set_intr(dev_info_t *dip, dev_info_t *rdip, 54 ddi_intr_handle_impl_t *hdlp, int valid); 55 static int niumx_add_intr(dev_info_t *dip, dev_info_t *rdip, 56 ddi_intr_handle_impl_t *hdlp); 57 static int niumx_rem_intr(dev_info_t *dip, dev_info_t *rdip, 58 ddi_intr_handle_impl_t *hdlp); 59 static uint_t niumx_intr_hdlr(void *arg); 60 static int niumx_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp, 61 off_t offset, off_t len, caddr_t *addrp); 62 static int niumx_dma_allochdl(dev_info_t *dip, dev_info_t *rdip, 63 ddi_dma_attr_t *attrp, 64 int (*waitfp)(caddr_t), caddr_t arg, ddi_dma_handle_t *handlep); 65 static int niumx_dma_freehdl(dev_info_t *dip, dev_info_t *rdip, 66 ddi_dma_handle_t handlep); 67 static int niumx_dma_bindhdl(dev_info_t *dip, dev_info_t *rdip, 68 ddi_dma_handle_t handle, ddi_dma_req_t *dmareq, 69 ddi_dma_cookie_t *cookiep, uint_t *ccountp); 70 static int niumx_dma_unbindhdl(dev_info_t *dip, dev_info_t *rdip, 71 ddi_dma_handle_t handle); 72 static int niumx_ctlops(dev_info_t *dip, dev_info_t *rdip, 73 ddi_ctl_enum_t op, void *arg, void *result); 74 75 int niumxtool_init(dev_info_t *dip); 76 void niumxtool_uninit(dev_info_t *dip); 77 78 int niumx_get_intr_target(niumx_devstate_t *niumxds_p, niudevino_t ino, 79 niucpuid_t *cpu_id); 80 int niumx_set_intr_target(niumx_devstate_t *niumxds_p, niudevino_t ino, 81 niucpuid_t cpu_id); 82 83 static struct bus_ops niumx_bus_ops = { 84 BUSO_REV, 85 niumx_map, 86 0, 87 0, 88 0, 89 i_ddi_map_fault, 90 0, 91 niumx_dma_allochdl, 92 niumx_dma_freehdl, 93 niumx_dma_bindhdl, 94 niumx_dma_unbindhdl, 95 0, 96 0, 97 0, 98 niumx_ctlops, 99 ddi_bus_prop_op, 100 0, /* (*bus_get_eventcookie)(); */ 101 0, /* (*bus_add_eventcall)(); */ 102 0, /* (*bus_remove_eventcall)(); */ 103 0, /* (*bus_post_event)(); */ 104 0, /* (*bus_intr_ctl)(); */ 105 0, /* (*bus_config)(); */ 106 0, /* (*bus_unconfig)(); */ 107 niumx_fm_init_child, /* (*bus_fm_init)(); */ 108 0, /* (*bus_fm_fini)(); */ 109 0, /* (*bus_enter)() */ 110 0, /* (*bus_exit)() */ 111 0, /* (*bus_power)() */ 112 niumx_intr_ops /* (*bus_intr_op)(); */ 113 }; 114 115 extern struct cb_ops niumx_cb_ops; 116 117 static struct dev_ops niumx_ops = { 118 DEVO_REV, /* devo_rev */ 119 0, /* refcnt */ 120 ddi_no_info, /* info */ 121 nulldev, /* identify */ 122 0, /* probe */ 123 niumx_attach, /* attach */ 124 niumx_detach, /* detach */ 125 nulldev, /* reset */ 126 &niumx_cb_ops, /* driver operations */ 127 &niumx_bus_ops, /* bus operations */ 128 0, /* power */ 129 ddi_quiesce_not_supported, /* devo_quiesce */ 130 }; 131 132 /* Module linkage information for the kernel. */ 133 static struct modldrv modldrv = { 134 &mod_driverops, /* Type of module */ 135 "NIU Nexus Driver", 136 &niumx_ops, /* driver ops */ 137 }; 138 139 static struct modlinkage modlinkage = { 140 MODREV_1, 141 (void *)&modldrv, 142 NULL 143 }; 144 145 void *niumx_state; 146 147 /* 148 * forward function declarations: 149 */ 150 static void niumx_removechild(dev_info_t *); 151 static int niumx_initchild(dev_info_t *child); 152 153 int 154 _init(void) 155 { 156 int e; 157 uint64_t mjrnum; 158 uint64_t mnrnum; 159 160 /* 161 * Check HV intr group api versioning. 162 * This driver uses the old interrupt routines which are supported 163 * in old firmware in the CORE API group and in newer firmware in 164 * the INTR API group. Support for these calls will be dropped 165 * once the INTR API group major goes to 2. 166 */ 167 if ((hsvc_version(HSVC_GROUP_INTR, &mjrnum, &mnrnum) == 0) && 168 (mjrnum > NIUMX_INTR_MAJOR_VER)) { 169 cmn_err(CE_WARN, "niumx: unsupported intr api group: " 170 "maj:0x%lx, min:0x%lx", mjrnum, mnrnum); 171 return (ENOTSUP); 172 } 173 174 if ((e = ddi_soft_state_init(&niumx_state, sizeof (niumx_devstate_t), 175 1)) == 0 && (e = mod_install(&modlinkage)) != 0) 176 ddi_soft_state_fini(&niumx_state); 177 return (e); 178 } 179 180 int 181 _fini(void) 182 { 183 int e; 184 if ((e = mod_remove(&modlinkage)) == 0) 185 ddi_soft_state_fini(&niumx_state); 186 return (e); 187 } 188 189 int 190 _info(struct modinfo *modinfop) 191 { 192 return (mod_info(&modlinkage, modinfop)); 193 } 194 195 196 hrtime_t niumx_intr_timeout = 2ull * NANOSEC; /* 2 seconds in nanoseconds */ 197 198 void 199 niumx_intr_dist(void *arg) 200 { 201 niumx_devstate_t *niumxds_p = (niumx_devstate_t *)arg; 202 kmutex_t *lock_p = &niumxds_p->niumx_mutex; 203 int i; 204 niumx_ih_t *ih_p = niumxds_p->niumx_ihtable; 205 206 DBG(NIUMX_DBG_A_INTX, NULL, "niumx_intr_dist entered\n"); 207 mutex_enter(lock_p); 208 for (i = 0; i < NIUMX_MAX_INTRS; i++, ih_p++) { 209 niusysino_t sysino = ih_p->ih_sysino; 210 niucpuid_t cpuid; 211 int state; 212 hrtime_t start; 213 dev_info_t *dip = ih_p->ih_dip; 214 215 if (!sysino || (cpuid = intr_dist_cpuid()) == ih_p->ih_cpuid) 216 continue; 217 218 (void) hvio_intr_setvalid(sysino, HV_INTR_NOTVALID); 219 220 /* check for pending interrupts, busy wait if so */ 221 for (start = gethrtime(); !panicstr && 222 (hvio_intr_getstate(sysino, &state) == H_EOK) && 223 (state == HV_INTR_DELIVERED_STATE); /* */) { 224 if (gethrtime() - start > niumx_intr_timeout) { 225 cmn_err(CE_WARN, "%s%d: niumx_intr_dist: " 226 "pending interrupt (%x,%lx) timedout\n", 227 ddi_driver_name(dip), ddi_get_instance(dip), 228 ih_p->ih_inum, sysino); 229 (void) hvio_intr_setstate(sysino, 230 HV_INTR_IDLE_STATE); 231 break; 232 } 233 } 234 (void) hvio_intr_settarget(sysino, cpuid); 235 236 if (ih_p->ih_state == HV_INTR_VALID) 237 (void) hvio_intr_setvalid(sysino, HV_INTR_VALID); 238 else 239 (void) hvio_intr_setvalid(sysino, HV_INTR_NOTVALID); 240 241 ih_p->ih_cpuid = cpuid; 242 } 243 mutex_exit(lock_p); 244 } 245 246 static int 247 niumx_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 248 { 249 int instance = ddi_get_instance(dip); 250 niumx_devstate_t *niumxds_p; /* devstate pointer */ 251 niu_regspec_t *reg_p; 252 niumx_ih_t *ih_p; 253 uint_t reglen; 254 int i, ret = DDI_SUCCESS; 255 256 switch (cmd) { 257 case DDI_ATTACH: 258 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, 259 DDI_PROP_DONTPASS, "reg", (int **)®_p, ®len) 260 != DDI_PROP_SUCCESS) { 261 DBG(NIUMX_DBG_ATTACH, dip, "reg lookup failed\n"); 262 ret = DDI_FAILURE; 263 goto done; 264 } 265 266 /* 267 * Allocate and get soft state structure. 268 */ 269 if (ddi_soft_state_zalloc(niumx_state, instance) 270 != DDI_SUCCESS) { 271 ret = DDI_FAILURE; 272 goto prop_free; 273 } 274 niumxds_p = (niumx_devstate_t *)ddi_get_soft_state(niumx_state, 275 instance); 276 niumxds_p->dip = dip; 277 niumxds_p->niumx_open_count = 0; 278 mutex_init(&niumxds_p->niumx_mutex, NULL, MUTEX_DRIVER, NULL); 279 280 DBG(NIUMX_DBG_ATTACH, dip, "soft state alloc'd instance = %d, " 281 "niumxds_p = %p\n", instance, niumxds_p); 282 283 /* hv devhdl: low 28-bit of 1st "reg" entry's addr.hi */ 284 niumxds_p->niumx_dev_hdl = (niudevhandle_t)(reg_p->addr_high & 285 NIUMX_DEVHDLE_MASK); 286 287 ih_p = niumxds_p->niumx_ihtable; 288 for (i = 0; i < NIUMX_MAX_INTRS; i++, ih_p++) { 289 ih_p->ih_sysino = 0; 290 ih_p->ih_state = HV_INTR_NOTVALID; 291 } 292 293 /* add interrupt redistribution callback */ 294 intr_dist_add(niumx_intr_dist, niumxds_p); 295 296 niumxds_p->niumx_fm_cap = DDI_FM_EREPORT_CAPABLE; 297 298 ddi_fm_init(niumxds_p->dip, &niumxds_p->niumx_fm_cap, 299 &niumxds_p->niumx_fm_ibc); 300 301 if (niumxtool_init(dip) != DDI_SUCCESS) { 302 ret = DDI_FAILURE; 303 goto cleanup; 304 } 305 306 ret = DDI_SUCCESS; 307 goto prop_free; 308 cleanup: 309 mutex_destroy(&niumxds_p->niumx_mutex); 310 ddi_soft_state_free(niumx_state, ddi_get_instance(dip)); 311 prop_free: 312 ddi_prop_free(reg_p); 313 done: 314 return (ret); 315 316 case DDI_RESUME: 317 default: 318 break; 319 } 320 return (ret); 321 } 322 323 static int 324 niumx_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 325 { 326 niumx_devstate_t *niumxds_p; 327 328 switch (cmd) { 329 case DDI_DETACH: 330 331 niumxds_p = (niumx_devstate_t *) 332 ddi_get_soft_state(niumx_state, ddi_get_instance(dip)); 333 334 intr_dist_rem(niumx_intr_dist, niumxds_p); 335 ddi_fm_fini(dip); 336 niumxtool_uninit(dip); 337 mutex_destroy(&niumxds_p->niumx_mutex); 338 ddi_soft_state_free(niumx_state, ddi_get_instance(dip)); 339 return (DDI_SUCCESS); 340 341 case DDI_SUSPEND: 342 default: 343 break; 344 } 345 return (DDI_FAILURE); 346 } 347 348 349 /* 350 * Function used to initialize FMA for our children nodes. Called 351 * through pci busops when child node calls ddi_fm_init. 352 */ 353 /*ARGSUSED*/ 354 int 355 niumx_fm_init_child(dev_info_t *dip, dev_info_t *cdip, int cap, 356 ddi_iblock_cookie_t *ibc_p) 357 { 358 niumx_devstate_t *niumxds_p = NIUMX_DIP_TO_STATE(dip); 359 360 ASSERT(ibc_p != NULL); 361 *ibc_p = niumxds_p->niumx_fm_ibc; 362 363 return (niumxds_p->niumx_fm_cap); 364 } 365 366 367 /*ARGSUSED*/ 368 int 369 niumx_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp, 370 off_t offset, off_t len, caddr_t *vaddrp) 371 { 372 struct regspec p_regspec; 373 ddi_map_req_t p_mapreq; 374 niu_regspec_t *reg_p; 375 int i, rn = mp->map_obj.rnumber, reglen, rnglen, rngnum, ret; 376 niumx_ranges_t *rng_p; 377 378 uint32_t reg_begin, rng_begin; 379 380 DBG(NIUMX_DBG_MAP, dip, "%s%d: mapping %s%d reg %d\n", 381 NIUMX_NAMEINST(dip), NIUMX_NAMEINST(rdip), rn); 382 383 if (ddi_getlongprop(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS, 384 "reg", (caddr_t)®_p, ®len) != DDI_SUCCESS) 385 return (DDI_FAILURE); 386 387 if (rn < 0 || (rn >= reglen / sizeof (niu_regspec_t))) { 388 DBG(NIUMX_DBG_MAP, dip, "rnumber out of range: %d\n", rn); 389 kmem_free(reg_p, reglen); 390 return (DDI_ME_RNUMBER_RANGE); 391 } 392 393 /* build regspec up for parent */ 394 p_mapreq = *mp; /* dup the whole structure */ 395 p_mapreq.map_type = DDI_MT_REGSPEC; 396 p_mapreq.map_obj.rp = &p_regspec; 397 398 if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "ranges", 399 (caddr_t)&rng_p, &rnglen) != DDI_SUCCESS) { 400 DBG(NIUMX_DBG_MAP, dip, "%s%d: no ranges property\n", 401 ddi_driver_name(dip), ddi_get_instance(dip)); 402 kmem_free(reg_p, reglen); 403 return (DDI_FAILURE); 404 } 405 406 /* locate matching ranges record */ 407 rngnum = rnglen / sizeof (niumx_ranges_t); 408 for (i = 0, reg_p += rn; i < rngnum; rng_p++, i++) { 409 if (reg_p->addr_high == rng_p->child_hi) 410 break; 411 } 412 413 if (i >= rngnum) { 414 DBG(NIUMX_DBG_MAP, dip, "ranges record for reg[%d] " 415 "not found.\n", rn); 416 ret = DDI_ME_REGSPEC_RANGE; 417 goto err; 418 } 419 420 /* 421 * validate request has matching bus type and within 4G 422 * limit by comparing addr.hi of "ranges" and child "reg". 423 */ 424 425 ASSERT(reg_p->size_high == 0); 426 427 rng_begin = rng_p->child_lo; 428 reg_begin = reg_p->addr_low; 429 /* check to verify reg bounds are within rng bounds */ 430 if (reg_begin < rng_begin || (reg_begin + (reg_p->size_low - 1)) > 431 (rng_begin + (rng_p->size_lo - 1))) { 432 DBG(NIUMX_DBG_MAP, dip, "size out of range for reg[%d].\n", rn); 433 ret = DDI_ME_REGSPEC_RANGE; 434 goto err; 435 } 436 437 p_regspec.regspec_bustype = rng_p->parent_hi; 438 p_regspec.regspec_addr = reg_begin - rng_begin + rng_p->parent_lo; 439 p_regspec.regspec_size = reg_p->size_low; 440 DBG(NIUMX_DBG_MAP, dip, "regspec:bus,addr,size = (%x,%x,%x)\n", 441 p_regspec.regspec_bustype, p_regspec.regspec_addr, 442 p_regspec.regspec_size); 443 ret = ddi_map(dip, &p_mapreq, 0, 0, vaddrp); 444 DBG(NIUMX_DBG_MAP, dip, "niumx_map: ret %d.\n", ret); 445 err: 446 kmem_free(rng_p - i, rnglen); 447 kmem_free(reg_p - rn, reglen); 448 return (ret); 449 } 450 451 /* 452 * niumx_ctlops 453 */ 454 int 455 niumx_ctlops(dev_info_t *dip, dev_info_t *rdip, 456 ddi_ctl_enum_t ctlop, void *arg, void *result) 457 { 458 niu_regspec_t *reg_p; 459 int reglen, totreg; 460 461 DBG(NIUMX_DBG_CTLOPS, dip, "niumx_ctlops ctlop=%d.\n", ctlop); 462 if (rdip == (dev_info_t *)0) 463 return (DDI_FAILURE); 464 465 switch (ctlop) { 466 case DDI_CTLOPS_REPORTDEV: 467 cmn_err(CE_NOTE, "device: %s@%s, %s%d\n", 468 ddi_node_name(rdip), ddi_get_name_addr(rdip), 469 NIUMX_NAMEINST(rdip)); 470 return (DDI_SUCCESS); 471 472 case DDI_CTLOPS_INITCHILD: 473 return (niumx_initchild((dev_info_t *)arg)); 474 475 case DDI_CTLOPS_UNINITCHILD: 476 niumx_removechild((dev_info_t *)arg); 477 return (DDI_SUCCESS); 478 479 case DDI_CTLOPS_REGSIZE: 480 case DDI_CTLOPS_NREGS: 481 /* fall through */ 482 break; 483 default: 484 DBG(NIUMX_DBG_CTLOPS, dip, "just pass to ddi_cltops.\n"); 485 return (ddi_ctlops(dip, rdip, ctlop, arg, result)); 486 } 487 488 /* REGSIZE/NREGS */ 489 490 *(int *)result = 0; 491 492 if (ddi_getlongprop(DDI_DEV_T_NONE, rdip, DDI_PROP_DONTPASS | 493 DDI_PROP_CANSLEEP, "reg", (caddr_t)®_p, ®len) != DDI_SUCCESS) 494 return (DDI_FAILURE); 495 496 totreg = reglen / sizeof (niu_regspec_t); 497 if (ctlop == DDI_CTLOPS_NREGS) { 498 DBG(NIUMX_DBG_CTLOPS, (dev_info_t *)dip, 499 "niumx_ctlops NREGS=%d.\n", totreg); 500 *(int *)result = totreg; 501 } else if (ctlop == DDI_CTLOPS_REGSIZE) { 502 int rn; 503 rn = *(int *)arg; 504 if (rn >= totreg) { 505 kmem_free(reg_p, reglen); 506 return (DDI_FAILURE); 507 } 508 *(off_t *)result = (reg_p + rn)->size_low; 509 DBG(NIUMX_DBG_CTLOPS, (dev_info_t *)dip, 510 "rn = %d, REGSIZE=%x.\n", rn, *(off_t *)result); 511 } 512 513 kmem_free(reg_p, reglen); 514 return (DDI_SUCCESS); 515 } 516 517 /* 518 * niumx_name_child 519 * 520 * This function is called from init_child to name a node. It is 521 * also passed as a callback for node merging functions. 522 * 523 * return value: DDI_SUCCESS, DDI_FAILURE 524 */ 525 static int 526 niumx_name_child(dev_info_t *child, char *name, int namelen) 527 { 528 niu_regspec_t *r; 529 uint_t n; 530 531 DBG(NIUMX_DBG_CHK_MOD, (dev_info_t *)child, "==> niumx_name_child\n"); 532 533 if (ndi_dev_is_persistent_node(child) == 0) { 534 char **unit_addr; 535 536 /* name .conf nodes by "unit-address" property */ 537 if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, child, 538 DDI_PROP_DONTPASS, "unit-address", &unit_addr, &n) != 539 DDI_PROP_SUCCESS) { 540 cmn_err(CE_WARN, "cannot name node from %s.conf", 541 ddi_driver_name(child)); 542 return (DDI_FAILURE); 543 } 544 if (n != 1 || *unit_addr == NULL || **unit_addr == 0) { 545 cmn_err(CE_WARN, "unit-address property in %s.conf" 546 " not well-formed", ddi_driver_name(child)); 547 ddi_prop_free(unit_addr); 548 return (DDI_FAILURE); 549 } 550 551 (void) snprintf(name, namelen, "%s", *unit_addr); 552 ddi_prop_free(unit_addr); 553 return (DDI_SUCCESS); 554 } 555 556 /* name hardware nodes by "reg" property */ 557 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, 558 "reg", (int **)&r, &n) != DDI_SUCCESS) { 559 cmn_err(CE_WARN, "reg property not well-formed"); 560 return (DDI_FAILURE); 561 } 562 (void) snprintf(name, namelen, "%x", (r[0].addr_high)); 563 ddi_prop_free(r); 564 return (DDI_SUCCESS); 565 } 566 567 static int 568 niumx_initchild(dev_info_t *child) 569 { 570 char name[MAXNAMELEN]; 571 572 DBG(NIUMX_DBG_CHK_MOD, (dev_info_t *)child, "==> niumx_initchild\n"); 573 /* 574 * Non-peristent nodes indicate a prototype node with per-instance 575 * properties to be merged into the real h/w device node. 576 */ 577 if (ndi_dev_is_persistent_node(child) == 0) { 578 niu_regspec_t *r; 579 uint_t n; 580 581 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child, 582 DDI_PROP_DONTPASS, "reg", (int **)&r, &n) == 583 DDI_SUCCESS) { 584 cmn_err(CE_WARN, 585 "cannot merge prototype from %s.conf", 586 ddi_driver_name(child)); 587 ddi_prop_free(r); 588 return (DDI_NOT_WELL_FORMED); 589 } 590 591 if (niumx_name_child(child, name, MAXNAMELEN) != DDI_SUCCESS) 592 return (DDI_NOT_WELL_FORMED); 593 594 ddi_set_name_addr(child, name); 595 ddi_set_parent_data(child, NULL); 596 597 /* 598 * Try to merge the properties from this prototype 599 * node into real h/w nodes. 600 */ 601 if (ndi_merge_node(child, niumx_name_child) == DDI_SUCCESS) { 602 /* 603 * Merged ok - return failure to remove the node. 604 */ 605 ddi_set_name_addr(child, NULL); 606 return (DDI_FAILURE); 607 } 608 609 /* 610 * The child was not merged into a h/w node, 611 * but there's not much we can do with it other 612 * than return failure to cause the node to be removed. 613 */ 614 cmn_err(CE_WARN, "!%s@%s: %s.conf properties not merged", 615 ddi_driver_name(child), ddi_get_name_addr(child), 616 ddi_driver_name(child)); 617 ddi_set_name_addr(child, NULL); 618 return (DDI_NOT_WELL_FORMED); 619 } 620 621 /* 622 * Initialize real h/w nodes 623 */ 624 if (niumx_name_child(child, name, MAXNAMELEN) != DDI_SUCCESS) 625 return (DDI_FAILURE); 626 627 ddi_set_name_addr(child, name); 628 return (DDI_SUCCESS); 629 } 630 631 static void 632 niumx_removechild(dev_info_t *dip) 633 { 634 ddi_set_name_addr(dip, NULL); 635 ddi_remove_minor_node(dip, NULL); 636 impl_rem_dev_props(dip); 637 } 638 639 640 641 /* 642 * bus dma alloc handle entry point: 643 */ 644 /*ARGSUSED*/ 645 int 646 niumx_dma_allochdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_attr_t *attrp, 647 int (*waitfp)(caddr_t), caddr_t arg, ddi_dma_handle_t *handlep) 648 { 649 ddi_dma_impl_t *mp; 650 int sleep = (waitfp == DDI_DMA_SLEEP) ? KM_SLEEP : KM_NOSLEEP; 651 652 DBG(NIUMX_DBG_DMA_ALLOCH, dip, "rdip=%s%d\n", NIUMX_NAMEINST(rdip)); 653 654 if (attrp->dma_attr_version != DMA_ATTR_V0) { 655 DBG(NIUMX_DBG_DMA_ALLOCH, 656 (dev_info_t *)dip, "DDI_DMA_BADATTR\n"); 657 return (DDI_DMA_BADATTR); 658 } 659 660 /* Caution: we don't use zalloc to enhance performance! */ 661 if ((mp = kmem_alloc(sizeof (ddi_dma_impl_t), sleep)) == 0) { 662 DBG(NIUMX_DBG_DMA_ALLOCH, dip, "can't alloc ddi_dma_impl_t\n"); 663 return (DDI_FAILURE); 664 } 665 mp->dmai_rdip = rdip; 666 mp->dmai_pfnlst = NULL; 667 mp->dmai_cookie = NULL; 668 mp->dmai_ncookies = 0; 669 mp->dmai_curcookie = 0; 670 mp->dmai_fault = 0; 671 mp->dmai_fault_check = NULL; 672 mp->dmai_fault_notify = NULL; 673 674 mp->dmai_attr = *attrp; /* set requestors attr info */ 675 676 DBG(NIUMX_DBG_DMA_ALLOCH, dip, "mp=%p\n", mp); 677 678 *handlep = (ddi_dma_handle_t)mp; 679 return (DDI_SUCCESS); 680 } 681 682 683 /* 684 * bus dma free handle entry point: 685 */ 686 /*ARGSUSED*/ 687 int 688 niumx_dma_freehdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t handle) 689 { 690 ddi_dma_impl_t *mp = (ddi_dma_impl_t *)handle; 691 692 if (mp->dmai_cookie) 693 kmem_free(mp->dmai_cookie, sizeof (ddi_dma_cookie_t)); 694 kmem_free(mp, sizeof (ddi_dma_impl_t)); 695 696 return (DDI_SUCCESS); 697 } 698 699 700 /* 701 * bus dma bind handle entry point: 702 * 703 * check/enforce DMA type, setup pfn0 and some other key pieces 704 * of this dma request. 705 * Note: this only works with DMA_OTYP_VADDR, and makes use of the known 706 * fact that only contiguous memory blocks will be passed in. 707 * Therefore only one cookie will ever be returned. 708 * 709 * return values: 710 * DDI_DMA_NOMAPPING - can't get valid pfn0, or bad dma type 711 * DDI_DMA_NORESOURCES 712 * DDI_SUCCESS 713 * 714 * dma handle members affected (set on exit): 715 * mp->dmai_object - dmareq->dmar_object 716 * mp->dmai_rflags - dmareq->dmar_flags 717 * mp->dmai_pfn0 - 1st page pfn (if va/size pair and not shadow) 718 * mp->dmai_roffset - initialized to starting page offset 719 * mp->dmai_size - # of total pages of entire object 720 * mp->dmai_cookie - new cookie alloc'd 721 */ 722 /*ARGSUSED*/ 723 int 724 niumx_dma_bindhdl(dev_info_t *dip, dev_info_t *rdip, 725 ddi_dma_handle_t handle, ddi_dma_req_t *dmareq, 726 ddi_dma_cookie_t *cookiep, uint_t *ccountp) 727 { 728 int (*waitfp)(caddr_t) = dmareq->dmar_fp; 729 ddi_dma_impl_t *mp = (ddi_dma_impl_t *)handle; 730 ddi_dma_obj_t *dobj_p = &dmareq->dmar_object; 731 uint32_t offset; 732 pfn_t pfn0; 733 int ret; 734 735 DBG(NIUMX_DBG_DMA_BINDH, dip, "rdip=%s%d mp=%p dmareq=%p\n", 736 NIUMX_NAMEINST(rdip), mp, dmareq); 737 738 /* first check dma type */ 739 mp->dmai_rflags = dmareq->dmar_flags & DMP_DDIFLAGS | DMP_NOSYNC; 740 switch (dobj_p->dmao_type) { 741 case DMA_OTYP_VADDR: { 742 caddr_t vaddr = dobj_p->dmao_obj.virt_obj.v_addr; 743 struct as *as_p = dobj_p->dmao_obj.virt_obj.v_as; 744 struct hat *hat_p = as_p ? as_p->a_hat : kas.a_hat; 745 offset = (ulong_t)vaddr & NIUMX_PAGE_OFFSET; 746 pfn0 = hat_getpfnum(hat_p, vaddr); 747 } 748 break; 749 750 case DMA_OTYP_BUFVADDR: 751 case DMA_OTYP_PAGES: 752 case DMA_OTYP_PADDR: 753 default: 754 cmn_err(CE_WARN, "%s%d requested unsupported dma type %x", 755 NIUMX_NAMEINST(mp->dmai_rdip), dobj_p->dmao_type); 756 ret = DDI_DMA_NOMAPPING; 757 goto err; 758 } 759 if (pfn0 == PFN_INVALID) { 760 cmn_err(CE_WARN, "%s%d: invalid pfn0 for DMA object %p", 761 NIUMX_NAMEINST(dip), (void *)dobj_p); 762 ret = DDI_DMA_NOMAPPING; 763 goto err; 764 } 765 mp->dmai_object = *dobj_p; /* whole object */ 766 mp->dmai_pfn0 = (void *)pfn0; /* cache pfn0 */ 767 mp->dmai_roffset = offset; /* pg0 offset */ 768 mp->dmai_mapping = mp->dmai_roffset | NIUMX_PTOB(pfn0); 769 mp->dmai_size = mp->dmai_object.dmao_size; 770 771 DBG(NIUMX_DBG_DMA_BINDH, dip, "check pfn: mp=%p pfn0=%x\n", 772 mp, mp->dmai_pfn0); 773 if (!(mp->dmai_cookie = kmem_zalloc(sizeof (ddi_dma_cookie_t), 774 waitfp == DDI_DMA_SLEEP ? KM_SLEEP : KM_NOSLEEP))) { 775 ret = DDI_DMA_NORESOURCES; 776 goto err; 777 } 778 mp->dmai_cookie->dmac_laddress = mp->dmai_mapping; 779 mp->dmai_cookie->dmac_size = mp->dmai_size; 780 mp->dmai_ncookies = 1; 781 mp->dmai_curcookie = 0; 782 *ccountp = 1; 783 *cookiep = *mp->dmai_cookie; 784 DBG(NIUMX_DBG_DMA_BINDH, dip, "cookie %" PRIx64 "+%x, count=%d\n", 785 cookiep->dmac_address, cookiep->dmac_size, *ccountp); 786 return (DDI_DMA_MAPPED); 787 788 err: 789 DBG(NIUMX_DBG_DMA_BINDH, (dev_info_t *)dip, 790 "niumx_dma_bindhdl error ret=%d\n", ret); 791 return (ret); 792 } 793 794 /* 795 * bus dma unbind handle entry point: 796 */ 797 /*ARGSUSED*/ 798 int 799 niumx_dma_unbindhdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t handle) 800 { 801 ddi_dma_impl_t *mp = (ddi_dma_impl_t *)handle; 802 803 DBG(NIUMX_DBG_DMA_UNBINDH, dip, "rdip=%s%d, mp=%p\n", 804 ddi_driver_name(rdip), ddi_get_instance(rdip), handle); 805 if (mp->dmai_cookie) { 806 kmem_free(mp->dmai_cookie, sizeof (ddi_dma_cookie_t)); 807 mp->dmai_cookie = NULL; 808 mp->dmai_ncookies = mp->dmai_curcookie = 0; 809 } 810 811 return (DDI_SUCCESS); 812 } 813 814 /*ARGSUSED*/ 815 int 816 niumx_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op, 817 ddi_intr_handle_impl_t *hdlp, void *result) 818 { 819 820 int ret = DDI_SUCCESS; 821 822 DBG(NIUMX_DBG_INTROPS, dip, "niumx_intr_ops: dip=%p rdip=%p intr_op=%x " 823 "handle=%p\n", dip, rdip, intr_op, hdlp); 824 825 switch (intr_op) { 826 827 case DDI_INTROP_SUPPORTED_TYPES: 828 *(int *)result = DDI_INTR_TYPE_FIXED; 829 break; 830 case DDI_INTROP_GETCAP: 831 *(int *)result = DDI_INTR_FLAG_LEVEL; 832 break; 833 case DDI_INTROP_SETCAP: 834 ret = DDI_ENOTSUP; 835 break; 836 case DDI_INTROP_ALLOC: 837 /* scratch1 = count, # of intrs from DDI framework */ 838 *(int *)result = hdlp->ih_scratch1; 839 break; 840 case DDI_INTROP_FREE: 841 /* Do we need to do anything here? */ 842 break; 843 case DDI_INTROP_GETPRI: 844 *(int *)result = NIUMX_DEFAULT_PIL; 845 break; 846 case DDI_INTROP_SETPRI: 847 ret = DDI_ENOTSUP; 848 break; 849 case DDI_INTROP_ADDISR: 850 ret = niumx_add_intr(dip, rdip, hdlp); 851 break; 852 case DDI_INTROP_REMISR: 853 ret = niumx_rem_intr(dip, rdip, hdlp); 854 break; 855 case DDI_INTROP_ENABLE: 856 ret = niumx_set_intr(dip, rdip, hdlp, HV_INTR_VALID); 857 break; 858 case DDI_INTROP_DISABLE: 859 ret = niumx_set_intr(dip, rdip, hdlp, HV_INTR_NOTVALID); 860 break; 861 case DDI_INTROP_SETMASK: 862 ret = DDI_ENOTSUP; 863 break; 864 case DDI_INTROP_CLRMASK: 865 ret = DDI_ENOTSUP; 866 break; 867 case DDI_INTROP_GETPENDING: 868 ret = DDI_ENOTSUP; 869 break; 870 case DDI_INTROP_NINTRS: 871 case DDI_INTROP_NAVAIL: { 872 niudevino_t *inos_p; 873 int inoslen; 874 875 if (ddi_getlongprop(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS, 876 "interrupts", (caddr_t)&inos_p, &inoslen) 877 != DDI_SUCCESS) { 878 ret = DDI_FAILURE; 879 break; 880 } 881 *(int *)result = inoslen / sizeof (uint32_t); 882 kmem_free(inos_p, inoslen); 883 } 884 break; 885 case DDI_INTROP_GETTARGET: { 886 niumx_devstate_t *niumxds_p; 887 888 niumxds_p = (niumx_devstate_t *)ddi_get_soft_state(niumx_state, 889 ddi_get_instance(dip)); 890 891 ret = niumx_get_intr_target(niumxds_p, hdlp->ih_vector, 892 (niucpuid_t *)result); 893 894 } 895 break; 896 case DDI_INTROP_SETTARGET: { 897 niumx_devstate_t *niumxds_p; 898 899 niumxds_p = (niumx_devstate_t *)ddi_get_soft_state(niumx_state, 900 ddi_get_instance(dip)); 901 902 ret = niumx_set_intr_target(niumxds_p, hdlp->ih_vector, 903 *(niucpuid_t *)result); 904 905 } 906 break; 907 default: 908 ret = DDI_ENOTSUP; 909 break; 910 } 911 912 DBG(NIUMX_DBG_INTROPS, dip, "niumx_intr_ops: ret=%d\n", ret); 913 return (ret); 914 } 915 916 int 917 niumx_set_intr(dev_info_t *dip, dev_info_t *rdip, 918 ddi_intr_handle_impl_t *hdlp, int valid) 919 { 920 niumx_ih_t *ih_p; 921 int ret = DDI_SUCCESS; 922 uint64_t hvret; 923 niumx_devstate_t *niumxds_p; /* devstate pointer */ 924 int instance = ddi_get_instance(dip); 925 926 niumxds_p = (niumx_devstate_t *)ddi_get_soft_state(niumx_state, 927 instance); 928 929 ASSERT(hdlp->ih_inum < NIUMX_MAX_INTRS); 930 931 ih_p = niumxds_p->niumx_ihtable + hdlp->ih_vector; 932 933 DBG(NIUMX_DBG_A_INTX, dip, 934 "niumx_set_intr: rdip=%s%d, valid=%d %s (%x,%x)\n", 935 NIUMX_NAMEINST(rdip), valid, valid ? "enabling" : "disabling", 936 ih_p->ih_inum, ih_p->ih_sysino); 937 938 if (valid == HV_INTR_VALID) 939 (void) hvio_intr_setstate(ih_p->ih_sysino, HV_INTR_IDLE_STATE); 940 if ((hvret = hvio_intr_setvalid(ih_p->ih_sysino, valid)) 941 != H_EOK) { 942 DBG(NIUMX_DBG_A_INTX, dip, 943 "hvio_intr_setvalid failed, ret 0x%x\n", hvret); 944 ret = DDI_FAILURE; 945 } else 946 ih_p->ih_state = valid; 947 948 return (ret); 949 } 950 951 int 952 niumx_get_intr_target(niumx_devstate_t *niumxds_p, niudevino_t ino, 953 niucpuid_t *cpu_id) 954 { 955 niumx_ih_t *ih_p; 956 niusysino_t sysino; 957 int rval = DDI_SUCCESS; 958 959 ih_p = niumxds_p->niumx_ihtable + ino; 960 961 sysino = ih_p->ih_sysino; 962 963 if (sysino == 0) { 964 rval = EINVAL; 965 goto done; 966 } 967 968 if (hvio_intr_gettarget(sysino, cpu_id) != H_EOK) { 969 rval = EINVAL; 970 goto done; 971 } 972 973 if (ih_p->ih_cpuid != *cpu_id) 974 rval = EIO; 975 976 done: 977 return (rval); 978 } 979 980 int 981 niumx_set_intr_target(niumx_devstate_t *niumxds_p, niudevino_t ino, 982 niucpuid_t cpu_id) 983 { 984 dev_info_t *dip = niumxds_p->dip; 985 niumx_ih_t *ih_p; 986 niucpuid_t old_cpu_id; 987 niusysino_t sysino; 988 int ret = DDI_SUCCESS; 989 int state; 990 hrtime_t start; 991 extern const int _ncpu; 992 extern cpu_t *cpu[]; 993 994 mutex_enter(&cpu_lock); 995 996 ih_p = niumxds_p->niumx_ihtable + ino; 997 998 sysino = ih_p->ih_sysino; 999 if (sysino == 0) { 1000 ret = EINVAL; 1001 goto done; 1002 } 1003 1004 if (hvio_intr_gettarget(sysino, &old_cpu_id) != H_EOK) { 1005 ret = EINVAL; 1006 goto done; 1007 } 1008 if ((cpu_id < _ncpu) && (cpu[cpu_id] && cpu_is_online(cpu[cpu_id]))) { 1009 if (cpu_id == old_cpu_id) 1010 goto done; 1011 1012 /* check for pending interrupts, busy wait if so */ 1013 for (start = gethrtime(); !panicstr && 1014 (hvio_intr_getstate(sysino, &state) == H_EOK) && 1015 (state == HV_INTR_DELIVERED_STATE); /* */) { 1016 if (gethrtime() - start > niumx_intr_timeout) { 1017 cmn_err(CE_WARN, "%s%d: niumx_intr_dist: " 1018 "pending interrupt (%x,%lx) timedout\n", 1019 ddi_driver_name(dip), ddi_get_instance(dip), 1020 ih_p->ih_inum, sysino); 1021 (void) hvio_intr_setstate(sysino, 1022 HV_INTR_IDLE_STATE); 1023 break; 1024 } 1025 } 1026 (void) hvio_intr_settarget(sysino, cpu_id); 1027 if (ih_p->ih_state == HV_INTR_VALID) 1028 (void) hvio_intr_setvalid(sysino, HV_INTR_VALID); 1029 else 1030 (void) hvio_intr_setvalid(sysino, HV_INTR_NOTVALID); 1031 ih_p->ih_cpuid = cpu_id; 1032 } else { 1033 ret = DDI_EINVAL; 1034 } 1035 1036 done: 1037 mutex_exit(&cpu_lock); 1038 return (ret); 1039 } 1040 1041 1042 /* 1043 * niumx_add_intr: 1044 * 1045 * This function is called to register interrupts. 1046 */ 1047 int 1048 niumx_add_intr(dev_info_t *dip, dev_info_t *rdip, 1049 ddi_intr_handle_impl_t *hdlp) 1050 { 1051 niumx_ih_t *ih_p; 1052 int ret = DDI_SUCCESS; 1053 uint64_t hvret; 1054 niusysino_t sysino; 1055 niumx_devstate_t *niumxds_p; /* devstate pointer */ 1056 int instance = ddi_get_instance(dip); 1057 1058 niumxds_p = (niumx_devstate_t *)ddi_get_soft_state(niumx_state, 1059 instance); 1060 1061 /* get new ino */ 1062 if (hdlp->ih_inum >= NIUMX_MAX_INTRS) { 1063 DBG(NIUMX_DBG_INTR, dip, "error: inum %d out of range\n", 1064 hdlp->ih_inum); 1065 ret = DDI_FAILURE; 1066 goto done; 1067 } 1068 1069 ih_p = niumxds_p->niumx_ihtable + hdlp->ih_vector; 1070 1071 if ((hvret = hvio_intr_devino_to_sysino(NIUMX_DIP_TO_HANDLE(dip), 1072 hdlp->ih_vector, &sysino)) != H_EOK) { 1073 DBG(NIUMX_DBG_INTR, dip, "hvio_intr_devino_to_sysino failed, " 1074 "ret 0x%x\n", hvret); 1075 ret = DDI_FAILURE; 1076 goto done; 1077 } 1078 ih_p->ih_sysino = sysino; 1079 ih_p->ih_dip = rdip; 1080 ih_p->ih_inum = hdlp->ih_inum; 1081 ih_p->ih_hdlr = hdlp->ih_cb_func; 1082 ih_p->ih_arg1 = hdlp->ih_cb_arg1; 1083 ih_p->ih_arg2 = hdlp->ih_cb_arg2; 1084 1085 DBG(NIUMX_DBG_A_INTX, dip, "niumx_add_intr: rdip=%s%d inum=0x%x " 1086 "handler=%p arg1=%p arg2=%p, new ih_p = %p\n", NIUMX_NAMEINST(rdip), 1087 hdlp->ih_inum, hdlp->ih_cb_func, hdlp->ih_cb_arg1, 1088 hdlp->ih_cb_arg2, ih_p); 1089 1090 if (hdlp->ih_pri == 0) 1091 hdlp->ih_pri = NIUMX_DEFAULT_PIL; 1092 1093 ih_p->ih_pri = hdlp->ih_pri; 1094 1095 DBG(NIUMX_DBG_A_INTX, dip, "for ino %x adding (%x,%x)\n", 1096 hdlp->ih_vector, ih_p->ih_inum, ih_p->ih_sysino); 1097 1098 /* Save sysino value in hdlp */ 1099 hdlp->ih_vector = ih_p->ih_sysino; 1100 1101 /* swap in our handler & arg */ 1102 DDI_INTR_ASSIGN_HDLR_N_ARGS(hdlp, (ddi_intr_handler_t *)niumx_intr_hdlr, 1103 (void *)ih_p, NULL); 1104 1105 ret = i_ddi_add_ivintr(hdlp); 1106 1107 /* Restore orig. interrupt handler & args in handle. */ 1108 DDI_INTR_ASSIGN_HDLR_N_ARGS(hdlp, ih_p->ih_hdlr, ih_p->ih_arg1, 1109 ih_p->ih_arg2); 1110 1111 if (ret != DDI_SUCCESS) { 1112 DBG(NIUMX_DBG_A_INTX, dip, "i_ddi_add_ivintr error ret=%x\n", 1113 ret); 1114 goto done; 1115 } 1116 1117 /* select cpu, saving it for removal */ 1118 ih_p->ih_cpuid = intr_dist_cpuid(); 1119 1120 if ((hvret = hvio_intr_settarget(ih_p->ih_sysino, ih_p->ih_cpuid)) 1121 != H_EOK) { 1122 DBG(NIUMX_DBG_A_INTX, dip, 1123 "hvio_intr_settarget failed, ret 0x%x\n", hvret); 1124 ret = DDI_FAILURE; 1125 } 1126 done: 1127 DBG(NIUMX_DBG_A_INTX, dip, "done, ret = %d, ih_p 0x%p, hdlp 0x%p\n", 1128 ih_p, hdlp, ret); 1129 return (ret); 1130 } 1131 1132 /* 1133 * niumx_rem_intr: 1134 * 1135 * This function is called to unregister interrupts. 1136 */ 1137 /*ARGSUSED*/ 1138 int 1139 niumx_rem_intr(dev_info_t *dip, dev_info_t *rdip, 1140 ddi_intr_handle_impl_t *hdlp) 1141 { 1142 niumx_ih_t *ih_p; 1143 int ret = DDI_SUCCESS, state; 1144 hrtime_t start; 1145 niusysino_t sysino; 1146 niumx_devstate_t *niumxds_p; /* devstate pointer */ 1147 int instance = ddi_get_instance(dip); 1148 1149 niumxds_p = (niumx_devstate_t *)ddi_get_soft_state(niumx_state, 1150 instance); 1151 1152 ASSERT(hdlp->ih_inum < NIUMX_MAX_INTRS); 1153 1154 ih_p = niumxds_p->niumx_ihtable + hdlp->ih_vector; 1155 1156 sysino = ih_p->ih_sysino; 1157 DBG(NIUMX_DBG_R_INTX, dip, "removing (%x,%x)\n", ih_p->ih_inum, sysino); 1158 1159 (void) hvio_intr_setvalid(sysino, HV_INTR_NOTVALID); 1160 1161 /* check for pending interrupts, busy wait if so */ 1162 for (start = gethrtime(); !panicstr && 1163 (hvio_intr_getstate(sysino, &state) == H_EOK) && 1164 (state == HV_INTR_DELIVERED_STATE); /* */) { 1165 if (gethrtime() - start > niumx_intr_timeout) { 1166 cmn_err(CE_WARN, "%s%d: niumx_intr_dist: " 1167 "pending interrupt (%x,%lx) timedout\n", 1168 ddi_driver_name(dip), ddi_get_instance(dip), 1169 ih_p->ih_inum, sysino); 1170 ret = DDI_FAILURE; 1171 goto fail; 1172 } 1173 } 1174 1175 ih_p->ih_sysino = 0; 1176 1177 hdlp->ih_vector = (uint32_t)sysino; 1178 if (hdlp->ih_vector != NULL) i_ddi_rem_ivintr(hdlp); 1179 1180 fail: 1181 return (ret); 1182 } 1183 1184 /* 1185 * niumx_intr_hdlr (our interrupt handler) 1186 */ 1187 uint_t 1188 niumx_intr_hdlr(void *arg) 1189 { 1190 niumx_ih_t *ih_p = (niumx_ih_t *)arg; 1191 uint_t r; 1192 1193 DTRACE_PROBE4(interrupt__start, dev_info_t, ih_p->ih_dip, void *, 1194 ih_p->ih_hdlr, caddr_t, ih_p->ih_arg1, caddr_t, ih_p->ih_arg2); 1195 1196 r = (*ih_p->ih_hdlr)(ih_p->ih_arg1, ih_p->ih_arg2); 1197 1198 DTRACE_PROBE4(interrupt__complete, dev_info_t, ih_p->ih_dip, void *, 1199 ih_p->ih_hdlr, caddr_t, ih_p->ih_arg1, int, r); 1200 1201 (void) hvio_intr_setstate(ih_p->ih_sysino, HV_INTR_IDLE_STATE); 1202 return (r); 1203 } 1204 1205 #ifdef DEBUG 1206 uint64_t niumx_debug_flags = 0; 1207 1208 static char *niumx_debug_sym [] = { /* same sequence as niumx_debug_bit */ 1209 /* 0 */ "attach", 1210 /* 1 */ "map", 1211 /* 2 */ "nex-ctlops", 1212 /* 3 */ "introps", 1213 /* 4 */ "intr-add", 1214 /* 5 */ "intr-rem", 1215 /* 6 */ "intr", 1216 /* 7 */ "dma-alloc", 1217 /* 8 */ "dma-bind", 1218 /* 9 */ "dma-unbind", 1219 /* 10 */ "chk-dma-mode" 1220 }; 1221 1222 /*ARGSUSED*/ 1223 void 1224 niumx_dbg(niumx_debug_bit_t bit, dev_info_t *dip, char *fmt, ...) 1225 { 1226 va_list ap; 1227 char msgbuf[1024]; 1228 1229 if (!(1ull << bit & niumx_debug_flags)) 1230 return; 1231 va_start(ap, fmt); 1232 (void) vsprintf(msgbuf, fmt, ap); 1233 va_end(ap); 1234 cmn_err(CE_NOTE, "%s: %s", niumx_debug_sym[bit], msgbuf); 1235 } 1236 1237 #endif /* DEBUG */ 1238