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 * Niagara2 Network Interface Unit (NIU) Nexus Driver 30 */ 31 32 #include <sys/conf.h> 33 #include <sys/modctl.h> 34 #include <sys/ddi_impldefs.h> 35 #include <sys/ddi_subrdefs.h> 36 #include <sys/ddi.h> 37 #include <sys/sunndi.h> 38 #include <sys/sunddi.h> 39 #include <sys/open.h> 40 #include <sys/stat.h> 41 #include <sys/file.h> 42 #include <sys/machsystm.h> 43 #include <sys/hsvc.h> 44 #include <sys/sdt.h> 45 #include <sys/hypervisor_api.h> 46 #include "niumx_var.h" 47 48 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 static struct bus_ops niumx_bus_ops = { 76 BUSO_REV, 77 niumx_map, 78 0, 79 0, 80 0, 81 i_ddi_map_fault, 82 0, 83 niumx_dma_allochdl, 84 niumx_dma_freehdl, 85 niumx_dma_bindhdl, 86 niumx_dma_unbindhdl, 87 0, 88 0, 89 0, 90 niumx_ctlops, 91 ddi_bus_prop_op, 92 0, /* (*bus_get_eventcookie)(); */ 93 0, /* (*bus_add_eventcall)(); */ 94 0, /* (*bus_remove_eventcall)(); */ 95 0, /* (*bus_post_event)(); */ 96 0, /* (*bus_intr_ctl)(); */ 97 0, /* (*bus_config)(); */ 98 0, /* (*bus_unconfig)(); */ 99 0, /* (*bus_fm_init)(); */ 100 0, /* (*bus_fm_fini)(); */ 101 0, /* (*bus_enter)() */ 102 0, /* (*bus_exit)() */ 103 0, /* (*bus_power)() */ 104 niumx_intr_ops /* (*bus_intr_op)(); */ 105 }; 106 107 static struct dev_ops niumx_ops = { 108 DEVO_REV, /* devo_rev */ 109 0, /* refcnt */ 110 ddi_no_info, /* info */ 111 nulldev, /* identify */ 112 0, /* probe */ 113 niumx_attach, /* attach */ 114 niumx_detach, /* detach */ 115 nulldev, /* reset */ 116 (struct cb_ops *)0, /* driver operations */ 117 &niumx_bus_ops, /* bus operations */ 118 0 119 }; 120 121 /* Module linkage information for the kernel. */ 122 static struct modldrv modldrv = { 123 &mod_driverops, /* Type of module */ 124 "NIU Nexus Driver %I%", 125 &niumx_ops, /* driver ops */ 126 }; 127 128 static struct modlinkage modlinkage = { 129 MODREV_1, 130 (void *)&modldrv, 131 NULL 132 }; 133 134 static void *niumx_state; 135 static niumx_ih_t niumx_ihtable[NIUMX_MAX_INTRS]; 136 137 /* 138 * forward function declarations: 139 */ 140 static void niumx_removechild(dev_info_t *); 141 static int niumx_initchild(dev_info_t *child); 142 143 int 144 _init(void) 145 { 146 int e; 147 if ((e = ddi_soft_state_init(&niumx_state, sizeof (niumx_devstate_t), 148 1)) == 0 && (e = mod_install(&modlinkage)) != 0) 149 ddi_soft_state_fini(&niumx_state); 150 return (e); 151 } 152 153 int 154 _fini(void) 155 { 156 int e; 157 if ((e = mod_remove(&modlinkage)) == 0) 158 ddi_soft_state_fini(&niumx_state); 159 return (e); 160 } 161 162 int 163 _info(struct modinfo *modinfop) 164 { 165 return (mod_info(&modlinkage, modinfop)); 166 } 167 168 169 /* 170 * Hypervisor VPCI services information for the NIU nexus driver. 171 */ 172 static uint64_t niumx_vpci_min_ver; /* Neg. VPCI API minor version */ 173 static hsvc_info_t niumx_hv_vpci = { 174 HSVC_REV_1, NULL, HSVC_GROUP_VPCI, NIUMX_VPCI_MAJOR_VER, 175 NIUMX_VPCI_MINOR_VER, "NIUMX" 176 }; 177 static uint64_t niumx_intr_min_ver; /* Neg. VPCI API minor version */ 178 static hsvc_info_t niumx_hv_intr = { 179 HSVC_REV_1, NULL, HSVC_GROUP_INTR, NIUMX_INTR_MAJOR_VER, 180 NIUMX_INTR_MINOR_VER, "NIUMX" 181 }; 182 183 static int 184 niumx_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 185 { 186 int instance = ddi_get_instance(dip); 187 niumx_devstate_t *niumxds_p; /* devstate pointer */ 188 niu_regspec_t *reg_p; 189 uint_t reglen; 190 int ret = DDI_SUCCESS; 191 192 switch (cmd) { 193 case DDI_ATTACH: 194 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, 195 DDI_PROP_DONTPASS, "reg", (int **)®_p, ®len) 196 != DDI_PROP_SUCCESS) { 197 DBG(DBG_ATTACH, dip, "reg lookup failed\n"); 198 ret = DDI_FAILURE; 199 goto done; 200 } 201 202 /* 203 * Allocate and get soft state structure. 204 */ 205 if (ddi_soft_state_zalloc(niumx_state, instance) 206 != DDI_SUCCESS) { 207 ret = DDI_FAILURE; 208 goto prop_free; 209 } 210 niumxds_p = (niumx_devstate_t *)ddi_get_soft_state(niumx_state, 211 instance); 212 niumxds_p->dip = dip; 213 mutex_init(&niumxds_p->niumx_mutex, NULL, MUTEX_DRIVER, NULL); 214 215 DBG(DBG_ATTACH, dip, "soft state alloc'd instance = %d, " 216 "niumxds_p = %p\n", instance, niumxds_p); 217 218 /* 219 * Negotiate the API version for HV VPCI & INTR services. 220 */ 221 if ((ret = hsvc_register(&niumx_hv_vpci, &niumx_vpci_min_ver)) 222 != H_EOK) { 223 cmn_err(CE_WARN, "%s: cannot negotiate hypervisor services " 224 "group: 0x%lx major: 0x%lx minor: 0x%lx errno: %d\n", 225 niumx_hv_vpci.hsvc_modname, niumx_hv_vpci.hsvc_group, 226 niumx_hv_vpci.hsvc_major, niumx_hv_vpci.hsvc_minor, ret); 227 ret = DDI_FAILURE; 228 goto cleanup; 229 } 230 231 if ((ret = hsvc_register(&niumx_hv_intr, &niumx_intr_min_ver)) 232 != H_EOK) { 233 cmn_err(CE_WARN, "%s: cannot negotiate hypervisor services " 234 "group: 0x%lx major: 0x%lx minor: 0x%lx errno: %d\n", 235 niumx_hv_intr.hsvc_modname, niumx_hv_intr.hsvc_group, 236 niumx_hv_intr.hsvc_major, niumx_hv_intr.hsvc_minor, ret); 237 ret = DDI_FAILURE; 238 goto unregister; 239 } 240 241 DBG(DBG_ATTACH, dip, "neg. HV API major 0x%lx minor 0x%lx\n", 242 niumx_hv_vpci.hsvc_major, niumx_vpci_min_ver); 243 244 /* hv devhdl: low 28-bit of 1st "reg" entry's addr.hi */ 245 niumxds_p->niumx_dev_hdl = (devhandle_t)(reg_p->addr_high & 246 NIUMX_DEVHDLE_MASK); 247 248 ret = DDI_SUCCESS; 249 goto prop_free; 250 251 unregister: 252 (void) hsvc_unregister(&niumx_hv_vpci); 253 cleanup: 254 mutex_destroy(&niumxds_p->niumx_mutex); 255 ddi_soft_state_free(niumx_state, ddi_get_instance(dip)); 256 prop_free: 257 ddi_prop_free(reg_p); 258 done: 259 return (ret); 260 261 case DDI_RESUME: 262 default: 263 break; 264 } 265 return (ret); 266 } 267 268 static int 269 niumx_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 270 { 271 niumx_devstate_t *niumxds_p; 272 273 switch (cmd) { 274 case DDI_DETACH: 275 (void) hsvc_unregister(&niumx_hv_vpci); 276 (void) hsvc_unregister(&niumx_hv_intr); 277 278 niumxds_p = (niumx_devstate_t *) 279 ddi_get_soft_state(niumx_state, ddi_get_instance(dip)); 280 281 mutex_destroy(&niumxds_p->niumx_mutex); 282 ddi_soft_state_free(niumx_state, ddi_get_instance(dip)); 283 return (DDI_SUCCESS); 284 285 case DDI_SUSPEND: 286 default: 287 break; 288 } 289 return (DDI_FAILURE); 290 } 291 292 /*ARGSUSED*/ 293 int 294 niumx_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp, 295 off_t offset, off_t len, caddr_t *vaddrp) 296 { 297 struct regspec p_regspec; 298 ddi_map_req_t p_mapreq; 299 niu_regspec_t *reg_p; 300 int i, rn = mp->map_obj.rnumber, reglen, rnglen, rngnum, ret; 301 niumx_ranges_t *rng_p; 302 303 uint32_t reg_begin, rng_begin; 304 305 DBG(DBG_MAP, dip, "%s%d: mapping %s%d reg %d\n", NAMEINST(dip), 306 NAMEINST(rdip), rn); 307 308 if (ddi_getlongprop(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS, 309 "reg", (caddr_t)®_p, ®len) != DDI_SUCCESS) 310 return (DDI_FAILURE); 311 312 if (rn < 0 || (rn >= reglen / sizeof (niu_regspec_t))) { 313 DBG(DBG_MAP, dip, "rnumber out of range: %d\n", rn); 314 kmem_free(reg_p, reglen); 315 return (DDI_ME_RNUMBER_RANGE); 316 } 317 318 /* build regspec up for parent */ 319 p_mapreq = *mp; /* dup the whole structure */ 320 p_mapreq.map_type = DDI_MT_REGSPEC; 321 p_mapreq.map_obj.rp = &p_regspec; 322 323 if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "ranges", 324 (caddr_t)&rng_p, &rnglen) != DDI_SUCCESS) { 325 DBG(DBG_MAP, dip, "%s%d: no ranges property\n", 326 ddi_driver_name(dip), ddi_get_instance(dip)); 327 kmem_free(reg_p, reglen); 328 return (DDI_FAILURE); 329 } 330 331 /* locate matching ranges record */ 332 rngnum = rnglen / sizeof (niumx_ranges_t); 333 for (i = 0, reg_p += rn; i < rngnum; rng_p++, i++) { 334 if (reg_p->addr_high == rng_p->child_hi) 335 break; 336 } 337 338 if (i >= rngnum) { 339 DBG(DBG_MAP, dip, "ranges record for reg[%d] not found.\n", rn); 340 ret = DDI_ME_REGSPEC_RANGE; 341 goto err; 342 } 343 344 /* 345 * validate request has matching bus type and within 4G 346 * limit by comparing addr.hi of "ranges" and child "reg". 347 */ 348 349 ASSERT(reg_p->size_high == 0); 350 351 rng_begin = rng_p->child_lo; 352 reg_begin = reg_p->addr_low; 353 /* check to verify reg bounds are within rng bounds */ 354 if (reg_begin < rng_begin || (reg_begin + (reg_p->size_low - 1)) > 355 (rng_begin + (rng_p->size_lo - 1))) { 356 DBG(DBG_MAP, dip, "size out of range for reg[%d].\n", rn); 357 ret = DDI_ME_REGSPEC_RANGE; 358 goto err; 359 } 360 361 p_regspec.regspec_bustype = rng_p->parent_hi; 362 p_regspec.regspec_addr = reg_begin - rng_begin + rng_p->parent_lo; 363 p_regspec.regspec_size = reg_p->size_low; 364 DBG(DBG_MAP, dip, "regspec:bus,addr,size = (%x,%x,%x)\n", 365 p_regspec.regspec_bustype, p_regspec.regspec_addr, 366 p_regspec.regspec_size); 367 ret = ddi_map(dip, &p_mapreq, 0, 0, vaddrp); 368 DBG(DBG_MAP, dip, "niumx_map: ret %d.\n", ret); 369 err: 370 kmem_free(rng_p - i, rnglen); 371 kmem_free(reg_p - rn, reglen); 372 return (ret); 373 } 374 375 /* 376 * niumx_ctlops 377 */ 378 int 379 niumx_ctlops(dev_info_t *dip, dev_info_t *rdip, 380 ddi_ctl_enum_t ctlop, void *arg, void *result) 381 { 382 niu_regspec_t *reg_p; 383 int reglen, totreg; 384 385 DBG(DBG_CTLOPS, dip, "niumx_ctlops ctlop=%d.\n", ctlop); 386 if (rdip == (dev_info_t *)0) 387 return (DDI_FAILURE); 388 389 switch (ctlop) { 390 case DDI_CTLOPS_REPORTDEV: 391 cmn_err(CE_NOTE, "device: %s@%s, %s%d\n", 392 ddi_node_name(rdip), ddi_get_name_addr(rdip), 393 NAMEINST(rdip)); 394 return (DDI_SUCCESS); 395 396 case DDI_CTLOPS_INITCHILD: 397 return (niumx_initchild((dev_info_t *)arg)); 398 399 case DDI_CTLOPS_UNINITCHILD: 400 niumx_removechild((dev_info_t *)arg); 401 return (DDI_SUCCESS); 402 403 case DDI_CTLOPS_REGSIZE: 404 case DDI_CTLOPS_NREGS: 405 /* fall through */ 406 break; 407 default: 408 DBG(DBG_CTLOPS, dip, "just pass to ddi_cltops.\n"); 409 return (ddi_ctlops(dip, rdip, ctlop, arg, result)); 410 } 411 412 /* REGSIZE/NREGS */ 413 414 *(int *)result = 0; 415 416 if (ddi_getlongprop(DDI_DEV_T_NONE, rdip, DDI_PROP_DONTPASS | 417 DDI_PROP_CANSLEEP, "reg", (caddr_t)®_p, ®len) 418 != DDI_SUCCESS) 419 return (DDI_FAILURE); 420 421 totreg = reglen / sizeof (niu_regspec_t); 422 if (ctlop == DDI_CTLOPS_NREGS) { 423 DBG(DBG_CTLOPS, (dev_info_t *)dip, "niumx_ctlops NREGS=%d.\n", 424 totreg); 425 *(int *)result = totreg; 426 } else if (ctlop == DDI_CTLOPS_REGSIZE) { 427 int rn; 428 rn = *(int *)arg; 429 if (rn >= totreg) { 430 kmem_free(reg_p, reglen); 431 return (DDI_FAILURE); 432 } 433 *(off_t *)result = (reg_p + rn)->size_low; 434 DBG(DBG_CTLOPS, (dev_info_t *)dip, "rn = %d, REGSIZE=%x.\n", 435 rn, *(off_t *)result); 436 } 437 438 kmem_free(reg_p, reglen); 439 return (DDI_SUCCESS); 440 } 441 442 static int 443 niumx_initchild(dev_info_t *child) 444 { 445 char name[MAXNAMELEN]; 446 niu_regspec_t *r; 447 uint_t n; 448 449 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, 450 "reg", (int **)&r, &n) != DDI_SUCCESS) { 451 return (DDI_FAILURE); 452 } 453 (void) snprintf(name, MAXNAMELEN, "%x", (r[0].addr_high & 454 NIUMX_FUNC_NUM_MASK)); 455 ddi_prop_free(r); 456 ddi_set_name_addr(child, name); 457 return (DDI_SUCCESS); 458 } 459 460 static void 461 niumx_removechild(dev_info_t *dip) 462 { 463 ddi_set_name_addr(dip, NULL); 464 ddi_remove_minor_node(dip, NULL); 465 impl_rem_dev_props(dip); 466 } 467 468 469 470 /* 471 * bus dma alloc handle entry point: 472 */ 473 /*ARGSUSED*/ 474 int 475 niumx_dma_allochdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_attr_t *attrp, 476 int (*waitfp)(caddr_t), caddr_t arg, ddi_dma_handle_t *handlep) 477 { 478 ddi_dma_impl_t *mp; 479 int sleep = (waitfp == DDI_DMA_SLEEP) ? KM_SLEEP : KM_NOSLEEP; 480 481 DBG(DBG_DMA_ALLOCH, dip, "rdip=%s%d\n", NAMEINST(rdip)); 482 483 if (attrp->dma_attr_version != DMA_ATTR_V0) { 484 DBG(DBG_DMA_ALLOCH, (dev_info_t *)dip, "DDI_DMA_BADATTR\n"); 485 return (DDI_DMA_BADATTR); 486 } 487 488 /* Caution: we don't use zalloc to enhance performance! */ 489 if ((mp = kmem_alloc(sizeof (ddi_dma_impl_t), sleep)) == 0) { 490 DBG(DBG_DMA_ALLOCH, dip, "can't alloc ddi_dma_impl_t\n"); 491 return (DDI_FAILURE); 492 } 493 mp->dmai_rdip = rdip; 494 mp->dmai_pfnlst = NULL; 495 mp->dmai_cookie = NULL; 496 mp->dmai_fault = 0; 497 mp->dmai_fault_check = NULL; 498 mp->dmai_fault_notify = NULL; 499 500 mp->dmai_attr = *attrp; /* set requestors attr info */ 501 502 DBG(DBG_DMA_ALLOCH, dip, "mp=%p\n", mp); 503 504 *handlep = (ddi_dma_handle_t)mp; 505 return (DDI_SUCCESS); 506 } 507 508 509 /* 510 * bus dma free handle entry point: 511 */ 512 /*ARGSUSED*/ 513 int 514 niumx_dma_freehdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t handle) 515 { 516 ddi_dma_impl_t *mp = (ddi_dma_impl_t *)handle; 517 518 if (mp->dmai_cookie) 519 kmem_free(mp->dmai_cookie, sizeof (ddi_dma_cookie_t)); 520 kmem_free(mp, sizeof (ddi_dma_impl_t)); 521 522 return (DDI_SUCCESS); 523 } 524 525 526 /* 527 * bus dma bind handle entry point: 528 * 529 * check/enforce DMA type, setup pfn0 and some other key pieces 530 * of this dma request. 531 * Note: this only works with DMA_OTYP_VADDR, and makes use of the known 532 * fact that only contiguous memory blocks will be passed in. 533 * Therefore only one cookie will ever be returned. 534 * 535 * return values: 536 * DDI_DMA_NOMAPPING - can't get valid pfn0, or bad dma type 537 * DDI_DMA_NORESOURCES 538 * DDI_SUCCESS 539 * 540 * dma handle members affected (set on exit): 541 * mp->dmai_object - dmareq->dmar_object 542 * mp->dmai_rflags - dmareq->dmar_flags 543 * mp->dmai_pfn0 - 1st page pfn (if va/size pair and not shadow) 544 * mp->dmai_roffset - initialized to starting page offset 545 * mp->dmai_size - # of total pages of entire object 546 * mp->dmai_cookie - new cookie alloc'd 547 */ 548 /*ARGSUSED*/ 549 int 550 niumx_dma_bindhdl(dev_info_t *dip, dev_info_t *rdip, 551 ddi_dma_handle_t handle, ddi_dma_req_t *dmareq, 552 ddi_dma_cookie_t *cookiep, uint_t *ccountp) 553 { 554 int (*waitfp)(caddr_t) = dmareq->dmar_fp; 555 ddi_dma_impl_t *mp = (ddi_dma_impl_t *)handle; 556 ddi_dma_obj_t *dobj_p = &dmareq->dmar_object; 557 uint32_t offset; 558 pfn_t pfn0; 559 int ret; 560 561 DBG(DBG_DMA_BINDH, dip, "rdip=%s%d mp=%p dmareq=%p\n", NAMEINST(rdip), 562 mp, dmareq); 563 564 /* first check dma type */ 565 mp->dmai_rflags = dmareq->dmar_flags & DMP_DDIFLAGS | DMP_NOSYNC; 566 switch (dobj_p->dmao_type) { 567 case DMA_OTYP_VADDR: { 568 caddr_t vaddr = dobj_p->dmao_obj.virt_obj.v_addr; 569 struct as *as_p = dobj_p->dmao_obj.virt_obj.v_as; 570 struct hat *hat_p = as_p ? as_p->a_hat : kas.a_hat; 571 offset = (ulong_t)vaddr & NIUMX_PAGE_OFFSET; 572 pfn0 = hat_getpfnum(hat_p, vaddr); 573 } 574 break; 575 576 case DMA_OTYP_BUFVADDR: 577 case DMA_OTYP_PAGES: 578 case DMA_OTYP_PADDR: 579 default: 580 cmn_err(CE_WARN, "%s%d requested unsupported dma type %x", 581 NAMEINST(mp->dmai_rdip), dobj_p->dmao_type); 582 ret = DDI_DMA_NOMAPPING; 583 goto err; 584 } 585 if (pfn0 == PFN_INVALID) { 586 cmn_err(CE_WARN, "%s%d: invalid pfn0 for DMA object %p", 587 NAMEINST(dip), (void *)dobj_p); 588 ret = DDI_DMA_NOMAPPING; 589 goto err; 590 } 591 mp->dmai_object = *dobj_p; /* whole object */ 592 mp->dmai_pfn0 = (void *)pfn0; /* cache pfn0 */ 593 mp->dmai_roffset = offset; /* pg0 offset */ 594 mp->dmai_mapping = mp->dmai_roffset | NIUMX_PTOB(pfn0); 595 mp->dmai_size = mp->dmai_object.dmao_size; 596 597 DBG(DBG_DMA_BINDH, dip, "check pfn: mp=%p pfn0=%x\n", 598 mp, mp->dmai_pfn0); 599 if (!(mp->dmai_cookie = kmem_zalloc(sizeof (ddi_dma_cookie_t), 600 waitfp == DDI_DMA_SLEEP ? KM_SLEEP : KM_NOSLEEP))) { 601 ret = DDI_DMA_NORESOURCES; 602 goto err; 603 } 604 mp->dmai_cookie->dmac_laddress = mp->dmai_mapping; 605 mp->dmai_cookie->dmac_size = mp->dmai_size; 606 *ccountp = 1; 607 *cookiep = *mp->dmai_cookie; 608 DBG(DBG_DMA_BINDH, dip, "cookie %" PRIx64 "+%x, count=%d\n", 609 cookiep->dmac_address, cookiep->dmac_size, *ccountp); 610 return (DDI_DMA_MAPPED); 611 612 err: 613 DBG(DBG_DMA_BINDH, (dev_info_t *)dip, 614 "niumx_dma_bindhdl error ret=%d\n", ret); 615 return (ret); 616 } 617 618 /* 619 * bus dma unbind handle entry point: 620 */ 621 /*ARGSUSED*/ 622 int 623 niumx_dma_unbindhdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t handle) 624 { 625 ddi_dma_impl_t *mp = (ddi_dma_impl_t *)handle; 626 627 DBG(DBG_DMA_UNBINDH, dip, "rdip=%s%d, mp=%p\n", 628 ddi_driver_name(rdip), ddi_get_instance(rdip), handle); 629 if (mp->dmai_cookie) { 630 kmem_free(mp->dmai_cookie, sizeof (ddi_dma_cookie_t)); 631 mp->dmai_cookie = NULL; 632 } 633 634 return (DDI_SUCCESS); 635 } 636 637 /*ARGSUSED*/ 638 int 639 niumx_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op, 640 ddi_intr_handle_impl_t *hdlp, void *result) 641 { 642 643 int ret = DDI_SUCCESS; 644 645 DBG(DBG_INTROPS, dip, "niumx_intr_ops: dip=%p rdip=%p intr_op=%x " 646 "handle=%p\n", dip, rdip, intr_op, hdlp); 647 648 switch (intr_op) { 649 650 case DDI_INTROP_SUPPORTED_TYPES: 651 *(int *)result = DDI_INTR_TYPE_FIXED; 652 break; 653 case DDI_INTROP_GETCAP: 654 *(int *)result = DDI_INTR_FLAG_LEVEL; 655 break; 656 case DDI_INTROP_SETCAP: 657 ret = DDI_ENOTSUP; 658 break; 659 case DDI_INTROP_ALLOC: 660 /* scratch1 = count, # of intrs from DDI framework */ 661 *(int *)result = hdlp->ih_scratch1; 662 break; 663 case DDI_INTROP_FREE: 664 /* Do we need to do anything here? */ 665 break; 666 case DDI_INTROP_GETPRI: 667 *(int *)result = NIUMX_DEFAULT_PIL; 668 break; 669 case DDI_INTROP_SETPRI: 670 ret = DDI_ENOTSUP; 671 break; 672 case DDI_INTROP_ADDISR: 673 ret = niumx_add_intr(dip, rdip, hdlp); 674 break; 675 case DDI_INTROP_REMISR: 676 ret = niumx_rem_intr(dip, rdip, hdlp); 677 break; 678 case DDI_INTROP_ENABLE: 679 ret = niumx_set_intr(dip, rdip, hdlp, HV_INTR_VALID); 680 break; 681 case DDI_INTROP_DISABLE: 682 ret = niumx_set_intr(dip, rdip, hdlp, HV_INTR_NOTVALID); 683 break; 684 case DDI_INTROP_SETMASK: 685 ret = DDI_ENOTSUP; 686 break; 687 case DDI_INTROP_CLRMASK: 688 ret = DDI_ENOTSUP; 689 break; 690 case DDI_INTROP_GETPENDING: 691 ret = DDI_ENOTSUP; 692 break; 693 case DDI_INTROP_NINTRS: 694 case DDI_INTROP_NAVAIL: { 695 devino_t *inos_p; 696 int inoslen; 697 if (ddi_getlongprop(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS, 698 "interrupts", (caddr_t)&inos_p, &inoslen) 699 != DDI_SUCCESS) { 700 ret = DDI_FAILURE; 701 break; 702 } 703 *(int *)result = inoslen / sizeof (uint32_t); 704 kmem_free(inos_p, inoslen); 705 } 706 break; 707 default: 708 ret = DDI_ENOTSUP; 709 break; 710 } 711 712 DBG(DBG_INTROPS, dip, "niumx_intr_ops: ret=%d\n", ret); 713 return (ret); 714 } 715 716 int 717 niumx_set_intr(dev_info_t *dip, dev_info_t *rdip, 718 ddi_intr_handle_impl_t *hdlp, int valid) 719 { 720 niumx_ih_t *ih_p; 721 devino_t *inos_p; 722 int inoslen, ret = DDI_SUCCESS; 723 uint64_t hvret; 724 725 DBG(DBG_A_INTX, dip, "niumx_set_intr: rdip=%s%d, valid=%d\n", 726 NAMEINST(rdip), valid); 727 728 ASSERT(hdlp->ih_inum < NIUMX_MAX_INTRS); 729 730 /* find the appropriate slot from the fixed table */ 731 if (ddi_getlongprop(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS, 732 "interrupts", (caddr_t)&inos_p, &inoslen) != DDI_SUCCESS) { 733 ret = DDI_FAILURE; 734 goto fail; 735 } 736 ih_p = niumx_ihtable + inos_p[hdlp->ih_inum]; 737 DBG(DBG_A_INTX, dip, "enabling (%x,%x,%x)\n", ih_p->ih_inum, 738 ih_p->ih_ino, ih_p->ih_sysino); 739 740 if ((hvret = hvio_intr_setvalid(ih_p->ih_sysino, valid)) 741 != H_EOK) { 742 DBG(DBG_A_INTX, dip, "hvio_intr_setvalid failed, ret 0x%x\n", 743 hvret); 744 ret = DDI_FAILURE; 745 } 746 kmem_free(inos_p, inoslen); 747 fail: 748 return (ret); 749 } 750 751 752 753 /* 754 * niumx_add_intr: 755 * 756 * This is the leaf/nexus/HV mapping, now read from "interrupts": 757 * 758 * we have a range of 64 to work with: 759 * [0-15] - reserved 760 * [16] - mac0 761 * [17] - MIF 762 * [18] - SYSERR 763 * [19-26] - func0 Rx (qty. 8) 764 * [27-34] - func0 Tx (qty. 8) 765 * [35] - mac1 766 * [36-43] - func1 Rx (qty. 8) 767 * [44-51] - func1 Tx (qty. 8) 768 * 769 * [52] - Error Interrupt hook 770 */ 771 int 772 niumx_add_intr(dev_info_t *dip, dev_info_t *rdip, 773 ddi_intr_handle_impl_t *hdlp) 774 { 775 niumx_ih_t *ih_p; 776 int inoslen, ret = DDI_SUCCESS; 777 uint64_t hvret; 778 devino_t *inos_p; 779 sysino_t sysino; 780 781 /* FMA Err handling hook */ 782 if (dip == rdip) { 783 /* 784 * this is not the leaf calling us, so hardwire in the 785 * FMA interrupt details. 786 */ 787 ih_p = niumx_ihtable + NIUMX_EI_IH; 788 ih_p->ih_ino = NIUMX_EI_IH; 789 goto get_sysino; 790 } 791 792 /* get new ino */ 793 if (hdlp->ih_inum >= NIUMX_MAX_INTRS) { 794 DBG(DBG_INTR, dip, "error: inum %d out of range\n", 795 hdlp->ih_inum); 796 ret = DDI_FAILURE; 797 goto done; 798 } 799 if (ddi_getlongprop(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS, 800 "interrupts", (caddr_t)&inos_p, &inoslen) != DDI_SUCCESS) { 801 ret = DDI_FAILURE; 802 goto done; 803 } 804 ih_p = niumx_ihtable + inos_p[hdlp->ih_inum]; 805 ih_p->ih_ino = inos_p[hdlp->ih_inum]; 806 kmem_free(inos_p, inoslen); 807 get_sysino: 808 if ((hvret = hvio_intr_devino_to_sysino(DIP_TO_HANDLE(dip), 809 ih_p->ih_ino, &sysino)) != H_EOK) { 810 DBG(DBG_INTR, dip, "hvio_intr_devino_to_sysino failed, " 811 "ret 0x%x\n", hvret); 812 ret = DDI_FAILURE; 813 goto done; 814 } 815 ih_p->ih_sysino = sysino; 816 ih_p->ih_dip = dip; 817 ih_p->ih_inum = hdlp->ih_inum; 818 ih_p->ih_hdlr = hdlp->ih_cb_func; 819 ih_p->ih_arg1 = hdlp->ih_cb_arg1; 820 ih_p->ih_arg2 = hdlp->ih_cb_arg2; 821 822 DBG(DBG_A_INTX, dip, "niumx_add_intr: rdip=%s%d inum=0x%x " 823 "handler=%p arg1=%p arg2=%p, new ih_p = %p\n", NAMEINST(rdip), 824 hdlp->ih_inum, hdlp->ih_cb_func, hdlp->ih_cb_arg1, 825 hdlp->ih_cb_arg2, ih_p); 826 827 if (hdlp->ih_pri == 0) 828 hdlp->ih_pri = NIUMX_DEFAULT_PIL; 829 830 /* Save sysino value in hdlp */ 831 hdlp->ih_vector = ih_p->ih_sysino; 832 833 /* swap in our handler & arg */ 834 DDI_INTR_ASSIGN_HDLR_N_ARGS(hdlp, (ddi_intr_handler_t *)niumx_intr_hdlr, 835 (void *)ih_p, NULL); 836 837 DBG(DBG_A_INTX, dip, "adding (%x,%x,%x)\n", ih_p->ih_inum, 838 ih_p->ih_ino, ih_p->ih_sysino); 839 ret = i_ddi_add_ivintr(hdlp); 840 841 /* Restore orig. interrupt handler & args in handle. */ 842 DDI_INTR_ASSIGN_HDLR_N_ARGS(hdlp, ih_p->ih_hdlr, ih_p->ih_arg1, 843 ih_p->ih_arg2); 844 845 if (ret != DDI_SUCCESS) { 846 DBG(DBG_A_INTX, dip, "i_ddi_add_ivintr error ret=%x\n", ret); 847 goto done; 848 } 849 850 /* select cpu, saving it for removal */ 851 ih_p->ih_cpuid = intr_dist_cpuid(); 852 853 if ((hvret = hvio_intr_settarget(ih_p->ih_sysino, ih_p->ih_cpuid)) 854 != H_EOK) { 855 DBG(DBG_A_INTX, dip, "hvio_intr_settarget failed, ret 0x%x\n", 856 hvret); 857 ret = DDI_FAILURE; 858 } 859 done: 860 DBG(DBG_A_INTX, dip, "done, ret = %d, ih_p 0x%p, hdlp 0x%p\n", ih_p, 861 hdlp, ret); 862 return (ret); 863 } 864 865 /* 866 * niumx_rem_intr: 867 * 868 * This function is called to unregister interrupts. 869 */ 870 int 871 niumx_rem_intr(dev_info_t *dip, dev_info_t *rdip, 872 ddi_intr_handle_impl_t *hdlp) 873 { 874 niumx_ih_t *ih_p; 875 cpuid_t curr_cpu; 876 devino_t *inos_p; 877 int inoslen, ret = DDI_SUCCESS; 878 uint64_t hvret; 879 880 ASSERT(hdlp->ih_inum < NIUMX_MAX_INTRS); 881 882 /* find the appropriate slot from the fixed table */ 883 if (ddi_getlongprop(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS, 884 "interrupts", (caddr_t)&inos_p, &inoslen) != DDI_SUCCESS) { 885 ret = DDI_FAILURE; 886 goto fail1; 887 } 888 ih_p = niumx_ihtable + inos_p[hdlp->ih_inum]; 889 DBG(DBG_R_INTX, dip, "removing (%x,%x,%x)\n", ih_p->ih_inum, 890 ih_p->ih_ino, ih_p->ih_sysino); 891 892 /* Get the current cpu */ 893 if ((hvret = hvio_intr_gettarget(ih_p->ih_sysino, &curr_cpu)) 894 != H_EOK) { 895 DBG(DBG_R_INTX, dip, "hvio_intr_gettarget failed, ret 0x%x\n", 896 hvret); 897 ret = DDI_FAILURE; 898 goto fail2; 899 } 900 901 intr_dist_cpuid_rem_device_weight(ih_p->ih_cpuid, rdip); 902 903 hdlp->ih_vector = ih_p->ih_sysino; 904 if (hdlp->ih_vector != NULL) i_ddi_rem_ivintr(hdlp); 905 906 /* clear out this entry */ 907 ih_p->ih_ino = NULL; 908 fail2: 909 kmem_free(inos_p, inoslen); 910 fail1: 911 return (ret); 912 } 913 914 /* 915 * niumx_intr_hdlr (our interrupt handler) 916 */ 917 uint_t 918 niumx_intr_hdlr(void *arg) 919 { 920 niumx_ih_t *ih_p = (niumx_ih_t *)arg; 921 uint_t r; 922 923 DTRACE_PROBE4(interrupt__start, dev_info_t, ih_p->ih_dip, void *, 924 ih_p->ih_hdlr, caddr_t, ih_p->ih_arg1, caddr_t, ih_p->ih_arg2); 925 926 r = (*ih_p->ih_hdlr)(ih_p->ih_arg1, ih_p->ih_arg2); 927 928 DTRACE_PROBE4(interrupt__complete, dev_info_t, ih_p->ih_dip, void *, 929 ih_p->ih_hdlr, caddr_t, ih_p->ih_arg1, int, r); 930 return (r); 931 } 932 933 #ifdef DEBUG 934 uint64_t niumx_debug_flags = 0; 935 936 static char *niumx_debug_sym [] = { /* same sequence as niumx_debug_bit */ 937 /* 0 */ "attach", 938 /* 1 */ "map", 939 /* 2 */ "nex-ctlops", 940 /* 3 */ "introps", 941 /* 4 */ "intr-add", 942 /* 5 */ "intr-rem", 943 /* 6 */ "intr", 944 /* 7 */ "dma-alloc", 945 /* 8 */ "dma-bind", 946 /* 9 */ "dma-unbind", 947 /* 10 */ "chk-dma-mode" 948 }; 949 950 /*ARGSUSED*/ 951 void 952 niumx_dbg(niumx_debug_bit_t bit, dev_info_t *dip, char *fmt, ...) 953 { 954 va_list ap; 955 char msgbuf[1024]; 956 957 if (!(1ull << bit & niumx_debug_flags)) 958 return; 959 va_start(ap, fmt); 960 (void) vsprintf(msgbuf, fmt, ap); 961 va_end(ap); 962 cmn_err(CE_NOTE, "%s: %s", niumx_debug_sym[bit], msgbuf); 963 } 964 965 #endif /* DEBUG */ 966