13156Sgirish /*
23156Sgirish * CDDL HEADER START
33156Sgirish *
43156Sgirish * The contents of this file are subject to the terms of the
53156Sgirish * Common Development and Distribution License (the "License").
63156Sgirish * You may not use this file except in compliance with the License.
73156Sgirish *
83156Sgirish * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
93156Sgirish * or http://www.opensolaris.org/os/licensing.
103156Sgirish * See the License for the specific language governing permissions
113156Sgirish * and limitations under the License.
123156Sgirish *
133156Sgirish * When distributing Covered Code, include this CDDL HEADER in each
143156Sgirish * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
153156Sgirish * If applicable, add the following below this CDDL HEADER, with the
163156Sgirish * fields enclosed by brackets "[]" replaced with your own identifying
173156Sgirish * information: Portions Copyright [yyyy] [name of copyright owner]
183156Sgirish *
193156Sgirish * CDDL HEADER END
203156Sgirish */
213156Sgirish /*
22*12564SGongtian.Zhao@Sun.COM * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
233156Sgirish */
243156Sgirish
253156Sgirish
263156Sgirish /*
273156Sgirish * Niagara2 Network Interface Unit (NIU) Nexus Driver
283156Sgirish */
293156Sgirish
303156Sgirish #include <sys/conf.h>
313156Sgirish #include <sys/modctl.h>
323156Sgirish #include <sys/ddi_impldefs.h>
333156Sgirish #include <sys/ddi_subrdefs.h>
343156Sgirish #include <sys/ddi.h>
353156Sgirish #include <sys/sunndi.h>
363156Sgirish #include <sys/sunddi.h>
373156Sgirish #include <sys/open.h>
383156Sgirish #include <sys/stat.h>
393156Sgirish #include <sys/file.h>
403156Sgirish #include <sys/machsystm.h>
413156Sgirish #include <sys/hsvc.h>
423156Sgirish #include <sys/sdt.h>
433156Sgirish #include <sys/hypervisor_api.h>
4411513SAlan.Adamson@Sun.COM #include <sys/cpuvar.h>
453156Sgirish #include "niumx_var.h"
463156Sgirish
473794Sjf137018 static int niumx_fm_init_child(dev_info_t *, dev_info_t *, int,
483794Sjf137018 ddi_iblock_cookie_t *);
493156Sgirish static int niumx_intr_ops(dev_info_t *dip, dev_info_t *rdip,
503156Sgirish ddi_intr_op_t intr_op, ddi_intr_handle_impl_t *hdlp, void *result);
513156Sgirish static int niumx_attach(dev_info_t *devi, ddi_attach_cmd_t cmd);
523156Sgirish static int niumx_detach(dev_info_t *devi, ddi_detach_cmd_t cmd);
533156Sgirish static int niumx_set_intr(dev_info_t *dip, dev_info_t *rdip,
543156Sgirish ddi_intr_handle_impl_t *hdlp, int valid);
553156Sgirish static int niumx_add_intr(dev_info_t *dip, dev_info_t *rdip,
563156Sgirish ddi_intr_handle_impl_t *hdlp);
573156Sgirish static int niumx_rem_intr(dev_info_t *dip, dev_info_t *rdip,
583156Sgirish ddi_intr_handle_impl_t *hdlp);
593156Sgirish static uint_t niumx_intr_hdlr(void *arg);
603156Sgirish static int niumx_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
613156Sgirish off_t offset, off_t len, caddr_t *addrp);
623156Sgirish static int niumx_dma_allochdl(dev_info_t *dip, dev_info_t *rdip,
633156Sgirish ddi_dma_attr_t *attrp,
643156Sgirish int (*waitfp)(caddr_t), caddr_t arg, ddi_dma_handle_t *handlep);
653156Sgirish static int niumx_dma_freehdl(dev_info_t *dip, dev_info_t *rdip,
663156Sgirish ddi_dma_handle_t handlep);
673156Sgirish static int niumx_dma_bindhdl(dev_info_t *dip, dev_info_t *rdip,
683156Sgirish ddi_dma_handle_t handle, ddi_dma_req_t *dmareq,
693156Sgirish ddi_dma_cookie_t *cookiep, uint_t *ccountp);
703156Sgirish static int niumx_dma_unbindhdl(dev_info_t *dip, dev_info_t *rdip,
713156Sgirish ddi_dma_handle_t handle);
723156Sgirish static int niumx_ctlops(dev_info_t *dip, dev_info_t *rdip,
733156Sgirish ddi_ctl_enum_t op, void *arg, void *result);
743156Sgirish
7511513SAlan.Adamson@Sun.COM int niumxtool_init(dev_info_t *dip);
7611548SAlan.Adamson@Sun.COM void niumxtool_uninit(dev_info_t *dip);
7711513SAlan.Adamson@Sun.COM
7811513SAlan.Adamson@Sun.COM int niumx_get_intr_target(niumx_devstate_t *niumxds_p, niudevino_t ino,
7911513SAlan.Adamson@Sun.COM niucpuid_t *cpu_id);
8011513SAlan.Adamson@Sun.COM int niumx_set_intr_target(niumx_devstate_t *niumxds_p, niudevino_t ino,
8111513SAlan.Adamson@Sun.COM niucpuid_t cpu_id);
8211513SAlan.Adamson@Sun.COM
833156Sgirish static struct bus_ops niumx_bus_ops = {
843156Sgirish BUSO_REV,
853156Sgirish niumx_map,
863156Sgirish 0,
873156Sgirish 0,
883156Sgirish 0,
893156Sgirish i_ddi_map_fault,
903156Sgirish 0,
913156Sgirish niumx_dma_allochdl,
923156Sgirish niumx_dma_freehdl,
933156Sgirish niumx_dma_bindhdl,
943156Sgirish niumx_dma_unbindhdl,
953156Sgirish 0,
963156Sgirish 0,
973156Sgirish 0,
983156Sgirish niumx_ctlops,
993156Sgirish ddi_bus_prop_op,
1003156Sgirish 0, /* (*bus_get_eventcookie)(); */
1013156Sgirish 0, /* (*bus_add_eventcall)(); */
1023156Sgirish 0, /* (*bus_remove_eventcall)(); */
1033156Sgirish 0, /* (*bus_post_event)(); */
1043156Sgirish 0, /* (*bus_intr_ctl)(); */
1053156Sgirish 0, /* (*bus_config)(); */
1063156Sgirish 0, /* (*bus_unconfig)(); */
1073794Sjf137018 niumx_fm_init_child, /* (*bus_fm_init)(); */
1083156Sgirish 0, /* (*bus_fm_fini)(); */
1093156Sgirish 0, /* (*bus_enter)() */
1103156Sgirish 0, /* (*bus_exit)() */
1113156Sgirish 0, /* (*bus_power)() */
1123156Sgirish niumx_intr_ops /* (*bus_intr_op)(); */
1133156Sgirish };
1143156Sgirish
11511513SAlan.Adamson@Sun.COM extern struct cb_ops niumx_cb_ops;
11611513SAlan.Adamson@Sun.COM
1173156Sgirish static struct dev_ops niumx_ops = {
1183156Sgirish DEVO_REV, /* devo_rev */
1193156Sgirish 0, /* refcnt */
1203156Sgirish ddi_no_info, /* info */
1213156Sgirish nulldev, /* identify */
1223156Sgirish 0, /* probe */
1233156Sgirish niumx_attach, /* attach */
1243156Sgirish niumx_detach, /* detach */
1253156Sgirish nulldev, /* reset */
12611513SAlan.Adamson@Sun.COM &niumx_cb_ops, /* driver operations */
1273156Sgirish &niumx_bus_ops, /* bus operations */
1287656SSherry.Moore@Sun.COM 0, /* power */
1297656SSherry.Moore@Sun.COM ddi_quiesce_not_supported, /* devo_quiesce */
1303156Sgirish };
1313156Sgirish
1323156Sgirish /* Module linkage information for the kernel. */
1333156Sgirish static struct modldrv modldrv = {
1343156Sgirish &mod_driverops, /* Type of module */
1357656SSherry.Moore@Sun.COM "NIU Nexus Driver",
1363156Sgirish &niumx_ops, /* driver ops */
1373156Sgirish };
1383156Sgirish
1393156Sgirish static struct modlinkage modlinkage = {
1403156Sgirish MODREV_1,
1413156Sgirish (void *)&modldrv,
1423156Sgirish NULL
1433156Sgirish };
1443156Sgirish
14511513SAlan.Adamson@Sun.COM void *niumx_state;
1463156Sgirish
1473156Sgirish /*
1483156Sgirish * forward function declarations:
1493156Sgirish */
1503156Sgirish static void niumx_removechild(dev_info_t *);
1513156Sgirish static int niumx_initchild(dev_info_t *child);
1523156Sgirish
1533156Sgirish int
_init(void)1543156Sgirish _init(void)
1553156Sgirish {
1563156Sgirish int e;
1574423Sjb145095 uint64_t mjrnum;
1584423Sjb145095 uint64_t mnrnum;
1594423Sjb145095
1604423Sjb145095 /*
1614423Sjb145095 * Check HV intr group api versioning.
1624423Sjb145095 * This driver uses the old interrupt routines which are supported
1634423Sjb145095 * in old firmware in the CORE API group and in newer firmware in
1644423Sjb145095 * the INTR API group. Support for these calls will be dropped
1654423Sjb145095 * once the INTR API group major goes to 2.
1664423Sjb145095 */
1674423Sjb145095 if ((hsvc_version(HSVC_GROUP_INTR, &mjrnum, &mnrnum) == 0) &&
1684423Sjb145095 (mjrnum > NIUMX_INTR_MAJOR_VER)) {
1694423Sjb145095 cmn_err(CE_WARN, "niumx: unsupported intr api group: "
1704423Sjb145095 "maj:0x%lx, min:0x%lx", mjrnum, mnrnum);
1714423Sjb145095 return (ENOTSUP);
1724423Sjb145095 }
1734423Sjb145095
1743156Sgirish if ((e = ddi_soft_state_init(&niumx_state, sizeof (niumx_devstate_t),
1753156Sgirish 1)) == 0 && (e = mod_install(&modlinkage)) != 0)
1763156Sgirish ddi_soft_state_fini(&niumx_state);
1773156Sgirish return (e);
1783156Sgirish }
1793156Sgirish
1803156Sgirish int
_fini(void)1813156Sgirish _fini(void)
1823156Sgirish {
1833156Sgirish int e;
1843156Sgirish if ((e = mod_remove(&modlinkage)) == 0)
1853156Sgirish ddi_soft_state_fini(&niumx_state);
1863156Sgirish return (e);
1873156Sgirish }
1883156Sgirish
1893156Sgirish int
_info(struct modinfo * modinfop)1903156Sgirish _info(struct modinfo *modinfop)
1913156Sgirish {
1923156Sgirish return (mod_info(&modlinkage, modinfop));
1933156Sgirish }
1943156Sgirish
1954329Sjf137018
1964329Sjf137018 hrtime_t niumx_intr_timeout = 2ull * NANOSEC; /* 2 seconds in nanoseconds */
1974329Sjf137018
1983310Sjf137018 void
niumx_intr_dist(void * arg)1993310Sjf137018 niumx_intr_dist(void *arg)
2003310Sjf137018 {
20111304SJanie.Lu@Sun.COM niumx_devstate_t *niumxds_p = (niumx_devstate_t *)arg;
20211304SJanie.Lu@Sun.COM kmutex_t *lock_p = &niumxds_p->niumx_mutex;
2037741SRaghuram.Kothakota@Sun.COM int i;
20411304SJanie.Lu@Sun.COM niumx_ih_t *ih_p = niumxds_p->niumx_ihtable;
2053310Sjf137018
20611513SAlan.Adamson@Sun.COM DBG(NIUMX_DBG_A_INTX, NULL, "niumx_intr_dist entered\n");
2073310Sjf137018 mutex_enter(lock_p);
2087741SRaghuram.Kothakota@Sun.COM for (i = 0; i < NIUMX_MAX_INTRS; i++, ih_p++) {
20911513SAlan.Adamson@Sun.COM niusysino_t sysino = ih_p->ih_sysino;
21011513SAlan.Adamson@Sun.COM niucpuid_t cpuid;
21111513SAlan.Adamson@Sun.COM int state;
2124329Sjf137018 hrtime_t start;
2134329Sjf137018 dev_info_t *dip = ih_p->ih_dip;
21411513SAlan.Adamson@Sun.COM
21511513SAlan.Adamson@Sun.COM if (!sysino || (cpuid = intr_dist_cpuid()) == ih_p->ih_cpuid)
2163310Sjf137018 continue;
2173310Sjf137018
2183310Sjf137018 (void) hvio_intr_setvalid(sysino, HV_INTR_NOTVALID);
2194329Sjf137018
2204329Sjf137018 /* check for pending interrupts, busy wait if so */
2214329Sjf137018 for (start = gethrtime(); !panicstr &&
2224329Sjf137018 (hvio_intr_getstate(sysino, &state) == H_EOK) &&
2234329Sjf137018 (state == HV_INTR_DELIVERED_STATE); /* */) {
2244329Sjf137018 if (gethrtime() - start > niumx_intr_timeout) {
2254329Sjf137018 cmn_err(CE_WARN, "%s%d: niumx_intr_dist: "
2264329Sjf137018 "pending interrupt (%x,%lx) timedout\n",
2274329Sjf137018 ddi_driver_name(dip), ddi_get_instance(dip),
2284329Sjf137018 ih_p->ih_inum, sysino);
2294329Sjf137018 (void) hvio_intr_setstate(sysino,
2304990Sjf137018 HV_INTR_IDLE_STATE);
2314329Sjf137018 break;
2324329Sjf137018 }
2334329Sjf137018 }
2343310Sjf137018 (void) hvio_intr_settarget(sysino, cpuid);
23511513SAlan.Adamson@Sun.COM
23611513SAlan.Adamson@Sun.COM if (ih_p->ih_state == HV_INTR_VALID)
23711513SAlan.Adamson@Sun.COM (void) hvio_intr_setvalid(sysino, HV_INTR_VALID);
23811513SAlan.Adamson@Sun.COM else
23911513SAlan.Adamson@Sun.COM (void) hvio_intr_setvalid(sysino, HV_INTR_NOTVALID);
24011513SAlan.Adamson@Sun.COM
2413310Sjf137018 ih_p->ih_cpuid = cpuid;
2423310Sjf137018 }
2433310Sjf137018 mutex_exit(lock_p);
2443310Sjf137018 }
2453156Sgirish
2463156Sgirish static int
niumx_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)2473156Sgirish niumx_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
2483156Sgirish {
2493156Sgirish int instance = ddi_get_instance(dip);
2503156Sgirish niumx_devstate_t *niumxds_p; /* devstate pointer */
2513156Sgirish niu_regspec_t *reg_p;
25211513SAlan.Adamson@Sun.COM niumx_ih_t *ih_p;
2533156Sgirish uint_t reglen;
25411513SAlan.Adamson@Sun.COM int i, ret = DDI_SUCCESS;
2553156Sgirish
2563156Sgirish switch (cmd) {
2573156Sgirish case DDI_ATTACH:
2583156Sgirish if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip,
2594990Sjf137018 DDI_PROP_DONTPASS, "reg", (int **)®_p, ®len)
2604990Sjf137018 != DDI_PROP_SUCCESS) {
26111513SAlan.Adamson@Sun.COM DBG(NIUMX_DBG_ATTACH, dip, "reg lookup failed\n");
2623156Sgirish ret = DDI_FAILURE;
2633156Sgirish goto done;
2643156Sgirish }
2653156Sgirish
2663156Sgirish /*
2673156Sgirish * Allocate and get soft state structure.
2683156Sgirish */
2693156Sgirish if (ddi_soft_state_zalloc(niumx_state, instance)
2704990Sjf137018 != DDI_SUCCESS) {
2713156Sgirish ret = DDI_FAILURE;
2723156Sgirish goto prop_free;
2733156Sgirish }
2743156Sgirish niumxds_p = (niumx_devstate_t *)ddi_get_soft_state(niumx_state,
2754990Sjf137018 instance);
2763156Sgirish niumxds_p->dip = dip;
27711513SAlan.Adamson@Sun.COM niumxds_p->niumx_open_count = 0;
2783156Sgirish mutex_init(&niumxds_p->niumx_mutex, NULL, MUTEX_DRIVER, NULL);
2793156Sgirish
28011513SAlan.Adamson@Sun.COM DBG(NIUMX_DBG_ATTACH, dip, "soft state alloc'd instance = %d, "
2814990Sjf137018 "niumxds_p = %p\n", instance, niumxds_p);
2823156Sgirish
2833156Sgirish /* hv devhdl: low 28-bit of 1st "reg" entry's addr.hi */
28411513SAlan.Adamson@Sun.COM niumxds_p->niumx_dev_hdl = (niudevhandle_t)(reg_p->addr_high &
2854990Sjf137018 NIUMX_DEVHDLE_MASK);
2863156Sgirish
28711513SAlan.Adamson@Sun.COM ih_p = niumxds_p->niumx_ihtable;
28811513SAlan.Adamson@Sun.COM for (i = 0; i < NIUMX_MAX_INTRS; i++, ih_p++) {
28911513SAlan.Adamson@Sun.COM ih_p->ih_sysino = 0;
29011513SAlan.Adamson@Sun.COM ih_p->ih_state = HV_INTR_NOTVALID;
29111513SAlan.Adamson@Sun.COM }
29211513SAlan.Adamson@Sun.COM
2933310Sjf137018 /* add interrupt redistribution callback */
29411304SJanie.Lu@Sun.COM intr_dist_add(niumx_intr_dist, niumxds_p);
2953310Sjf137018
2963794Sjf137018 niumxds_p->niumx_fm_cap = DDI_FM_EREPORT_CAPABLE;
2973325Ssd77468
2983325Ssd77468 ddi_fm_init(niumxds_p->dip, &niumxds_p->niumx_fm_cap,
2994990Sjf137018 &niumxds_p->niumx_fm_ibc);
3003325Ssd77468
30111513SAlan.Adamson@Sun.COM if (niumxtool_init(dip) != DDI_SUCCESS) {
30211513SAlan.Adamson@Sun.COM ret = DDI_FAILURE;
30311513SAlan.Adamson@Sun.COM goto cleanup;
30411513SAlan.Adamson@Sun.COM }
30511513SAlan.Adamson@Sun.COM
3063156Sgirish ret = DDI_SUCCESS;
3073156Sgirish goto prop_free;
3083156Sgirish cleanup:
3093156Sgirish mutex_destroy(&niumxds_p->niumx_mutex);
3103156Sgirish ddi_soft_state_free(niumx_state, ddi_get_instance(dip));
3113156Sgirish prop_free:
3123156Sgirish ddi_prop_free(reg_p);
3133156Sgirish done:
3143156Sgirish return (ret);
3153156Sgirish
3163156Sgirish case DDI_RESUME:
3173156Sgirish default:
3183156Sgirish break;
3193156Sgirish }
3203156Sgirish return (ret);
3213156Sgirish }
3223156Sgirish
3233156Sgirish static int
niumx_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)3243156Sgirish niumx_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
3253156Sgirish {
3263156Sgirish niumx_devstate_t *niumxds_p;
3273156Sgirish
3283156Sgirish switch (cmd) {
3293156Sgirish case DDI_DETACH:
3303156Sgirish
3313156Sgirish niumxds_p = (niumx_devstate_t *)
3323156Sgirish ddi_get_soft_state(niumx_state, ddi_get_instance(dip));
3333156Sgirish
33411304SJanie.Lu@Sun.COM intr_dist_rem(niumx_intr_dist, niumxds_p);
3353325Ssd77468 ddi_fm_fini(dip);
33611513SAlan.Adamson@Sun.COM niumxtool_uninit(dip);
3373156Sgirish mutex_destroy(&niumxds_p->niumx_mutex);
3383156Sgirish ddi_soft_state_free(niumx_state, ddi_get_instance(dip));
3393156Sgirish return (DDI_SUCCESS);
3403156Sgirish
3413156Sgirish case DDI_SUSPEND:
3423156Sgirish default:
3433156Sgirish break;
3443156Sgirish }
3453156Sgirish return (DDI_FAILURE);
3463156Sgirish }
3473156Sgirish
3483794Sjf137018
3493794Sjf137018 /*
3503794Sjf137018 * Function used to initialize FMA for our children nodes. Called
3513794Sjf137018 * through pci busops when child node calls ddi_fm_init.
3523794Sjf137018 */
3533794Sjf137018 /*ARGSUSED*/
3543794Sjf137018 int
niumx_fm_init_child(dev_info_t * dip,dev_info_t * cdip,int cap,ddi_iblock_cookie_t * ibc_p)3553794Sjf137018 niumx_fm_init_child(dev_info_t *dip, dev_info_t *cdip, int cap,
3563794Sjf137018 ddi_iblock_cookie_t *ibc_p)
3573794Sjf137018 {
35811513SAlan.Adamson@Sun.COM niumx_devstate_t *niumxds_p = NIUMX_DIP_TO_STATE(dip);
3593794Sjf137018
3603794Sjf137018 ASSERT(ibc_p != NULL);
3613794Sjf137018 *ibc_p = niumxds_p->niumx_fm_ibc;
3623794Sjf137018
3633794Sjf137018 return (niumxds_p->niumx_fm_cap);
3643794Sjf137018 }
3653794Sjf137018
3663794Sjf137018
3673156Sgirish /*ARGSUSED*/
3683156Sgirish int
niumx_map(dev_info_t * dip,dev_info_t * rdip,ddi_map_req_t * mp,off_t offset,off_t len,caddr_t * vaddrp)3693156Sgirish niumx_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
3703156Sgirish off_t offset, off_t len, caddr_t *vaddrp)
3713156Sgirish {
3723156Sgirish struct regspec p_regspec;
3733156Sgirish ddi_map_req_t p_mapreq;
3743156Sgirish niu_regspec_t *reg_p;
3753156Sgirish int i, rn = mp->map_obj.rnumber, reglen, rnglen, rngnum, ret;
3763156Sgirish niumx_ranges_t *rng_p;
3773156Sgirish
3783156Sgirish uint32_t reg_begin, rng_begin;
3793156Sgirish
38011513SAlan.Adamson@Sun.COM DBG(NIUMX_DBG_MAP, dip, "%s%d: mapping %s%d reg %d\n",
38111513SAlan.Adamson@Sun.COM NIUMX_NAMEINST(dip), NIUMX_NAMEINST(rdip), rn);
3823156Sgirish
3833156Sgirish if (ddi_getlongprop(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS,
3844990Sjf137018 "reg", (caddr_t)®_p, ®len) != DDI_SUCCESS)
3853156Sgirish return (DDI_FAILURE);
3863156Sgirish
3873156Sgirish if (rn < 0 || (rn >= reglen / sizeof (niu_regspec_t))) {
38811513SAlan.Adamson@Sun.COM DBG(NIUMX_DBG_MAP, dip, "rnumber out of range: %d\n", rn);
3893156Sgirish kmem_free(reg_p, reglen);
3903156Sgirish return (DDI_ME_RNUMBER_RANGE);
3913156Sgirish }
3923156Sgirish
3933156Sgirish /* build regspec up for parent */
3943156Sgirish p_mapreq = *mp; /* dup the whole structure */
3953156Sgirish p_mapreq.map_type = DDI_MT_REGSPEC;
3963156Sgirish p_mapreq.map_obj.rp = &p_regspec;
3973156Sgirish
3983156Sgirish if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "ranges",
3994990Sjf137018 (caddr_t)&rng_p, &rnglen) != DDI_SUCCESS) {
40011513SAlan.Adamson@Sun.COM DBG(NIUMX_DBG_MAP, dip, "%s%d: no ranges property\n",
4014990Sjf137018 ddi_driver_name(dip), ddi_get_instance(dip));
4023156Sgirish kmem_free(reg_p, reglen);
4033156Sgirish return (DDI_FAILURE);
4043156Sgirish }
4053156Sgirish
4063156Sgirish /* locate matching ranges record */
4073156Sgirish rngnum = rnglen / sizeof (niumx_ranges_t);
4083156Sgirish for (i = 0, reg_p += rn; i < rngnum; rng_p++, i++) {
4093156Sgirish if (reg_p->addr_high == rng_p->child_hi)
4103156Sgirish break;
4113156Sgirish }
4123156Sgirish
4133156Sgirish if (i >= rngnum) {
41411513SAlan.Adamson@Sun.COM DBG(NIUMX_DBG_MAP, dip, "ranges record for reg[%d] "
41511513SAlan.Adamson@Sun.COM "not found.\n", rn);
4163156Sgirish ret = DDI_ME_REGSPEC_RANGE;
4173156Sgirish goto err;
4183156Sgirish }
4193156Sgirish
4203156Sgirish /*
4213156Sgirish * validate request has matching bus type and within 4G
4223156Sgirish * limit by comparing addr.hi of "ranges" and child "reg".
4233156Sgirish */
4243156Sgirish
4253156Sgirish ASSERT(reg_p->size_high == 0);
4263156Sgirish
4273156Sgirish rng_begin = rng_p->child_lo;
4283156Sgirish reg_begin = reg_p->addr_low;
4293156Sgirish /* check to verify reg bounds are within rng bounds */
4303156Sgirish if (reg_begin < rng_begin || (reg_begin + (reg_p->size_low - 1)) >
4314990Sjf137018 (rng_begin + (rng_p->size_lo - 1))) {
43211513SAlan.Adamson@Sun.COM DBG(NIUMX_DBG_MAP, dip, "size out of range for reg[%d].\n", rn);
4333156Sgirish ret = DDI_ME_REGSPEC_RANGE;
4343156Sgirish goto err;
4353156Sgirish }
4363156Sgirish
4373156Sgirish p_regspec.regspec_bustype = rng_p->parent_hi;
4383156Sgirish p_regspec.regspec_addr = reg_begin - rng_begin + rng_p->parent_lo;
4393156Sgirish p_regspec.regspec_size = reg_p->size_low;
44011513SAlan.Adamson@Sun.COM DBG(NIUMX_DBG_MAP, dip, "regspec:bus,addr,size = (%x,%x,%x)\n",
4414990Sjf137018 p_regspec.regspec_bustype, p_regspec.regspec_addr,
4424990Sjf137018 p_regspec.regspec_size);
4433156Sgirish ret = ddi_map(dip, &p_mapreq, 0, 0, vaddrp);
44411513SAlan.Adamson@Sun.COM DBG(NIUMX_DBG_MAP, dip, "niumx_map: ret %d.\n", ret);
4453156Sgirish err:
4463156Sgirish kmem_free(rng_p - i, rnglen);
4473156Sgirish kmem_free(reg_p - rn, reglen);
4483156Sgirish return (ret);
4493156Sgirish }
4503156Sgirish
4513156Sgirish /*
4523156Sgirish * niumx_ctlops
4533156Sgirish */
4543156Sgirish int
niumx_ctlops(dev_info_t * dip,dev_info_t * rdip,ddi_ctl_enum_t ctlop,void * arg,void * result)4553156Sgirish niumx_ctlops(dev_info_t *dip, dev_info_t *rdip,
4563156Sgirish ddi_ctl_enum_t ctlop, void *arg, void *result)
4573156Sgirish {
4583156Sgirish niu_regspec_t *reg_p;
4593156Sgirish int reglen, totreg;
4603156Sgirish
46111513SAlan.Adamson@Sun.COM DBG(NIUMX_DBG_CTLOPS, dip, "niumx_ctlops ctlop=%d.\n", ctlop);
4623156Sgirish if (rdip == (dev_info_t *)0)
4633156Sgirish return (DDI_FAILURE);
4643156Sgirish
4653156Sgirish switch (ctlop) {
4663156Sgirish case DDI_CTLOPS_REPORTDEV:
4673156Sgirish cmn_err(CE_NOTE, "device: %s@%s, %s%d\n",
4683156Sgirish ddi_node_name(rdip), ddi_get_name_addr(rdip),
46911513SAlan.Adamson@Sun.COM NIUMX_NAMEINST(rdip));
4703156Sgirish return (DDI_SUCCESS);
4713156Sgirish
4723156Sgirish case DDI_CTLOPS_INITCHILD:
4733156Sgirish return (niumx_initchild((dev_info_t *)arg));
4743156Sgirish
4753156Sgirish case DDI_CTLOPS_UNINITCHILD:
4763156Sgirish niumx_removechild((dev_info_t *)arg);
4773156Sgirish return (DDI_SUCCESS);
4783156Sgirish
4793156Sgirish case DDI_CTLOPS_REGSIZE:
4803156Sgirish case DDI_CTLOPS_NREGS:
4813156Sgirish /* fall through */
4823156Sgirish break;
4833156Sgirish default:
48411513SAlan.Adamson@Sun.COM DBG(NIUMX_DBG_CTLOPS, dip, "just pass to ddi_cltops.\n");
4853156Sgirish return (ddi_ctlops(dip, rdip, ctlop, arg, result));
4863156Sgirish }
4873156Sgirish
4883156Sgirish /* REGSIZE/NREGS */
4893156Sgirish
4903156Sgirish *(int *)result = 0;
4913156Sgirish
4923156Sgirish if (ddi_getlongprop(DDI_DEV_T_NONE, rdip, DDI_PROP_DONTPASS |
4934990Sjf137018 DDI_PROP_CANSLEEP, "reg", (caddr_t)®_p, ®len) != DDI_SUCCESS)
4943156Sgirish return (DDI_FAILURE);
4953156Sgirish
4963156Sgirish totreg = reglen / sizeof (niu_regspec_t);
4973156Sgirish if (ctlop == DDI_CTLOPS_NREGS) {
49811513SAlan.Adamson@Sun.COM DBG(NIUMX_DBG_CTLOPS, (dev_info_t *)dip,
49911513SAlan.Adamson@Sun.COM "niumx_ctlops NREGS=%d.\n", totreg);
5003156Sgirish *(int *)result = totreg;
5013156Sgirish } else if (ctlop == DDI_CTLOPS_REGSIZE) {
5023156Sgirish int rn;
5033156Sgirish rn = *(int *)arg;
5043156Sgirish if (rn >= totreg) {
5053156Sgirish kmem_free(reg_p, reglen);
5063156Sgirish return (DDI_FAILURE);
5073156Sgirish }
5083156Sgirish *(off_t *)result = (reg_p + rn)->size_low;
50911513SAlan.Adamson@Sun.COM DBG(NIUMX_DBG_CTLOPS, (dev_info_t *)dip,
51011513SAlan.Adamson@Sun.COM "rn = %d, REGSIZE=%x.\n", rn, *(off_t *)result);
5113156Sgirish }
5123156Sgirish
5133156Sgirish kmem_free(reg_p, reglen);
5143156Sgirish return (DDI_SUCCESS);
5153156Sgirish }
5163156Sgirish
5174990Sjf137018 /*
5184990Sjf137018 * niumx_name_child
5194990Sjf137018 *
5204990Sjf137018 * This function is called from init_child to name a node. It is
5214990Sjf137018 * also passed as a callback for node merging functions.
5224990Sjf137018 *
5234990Sjf137018 * return value: DDI_SUCCESS, DDI_FAILURE
5244990Sjf137018 */
5254990Sjf137018 static int
niumx_name_child(dev_info_t * child,char * name,int namelen)5264990Sjf137018 niumx_name_child(dev_info_t *child, char *name, int namelen)
5274990Sjf137018 {
5284990Sjf137018 niu_regspec_t *r;
5294990Sjf137018 uint_t n;
5304990Sjf137018
53111513SAlan.Adamson@Sun.COM DBG(NIUMX_DBG_CHK_MOD, (dev_info_t *)child, "==> niumx_name_child\n");
5324990Sjf137018
5334990Sjf137018 if (ndi_dev_is_persistent_node(child) == 0) {
5344990Sjf137018 char **unit_addr;
5354990Sjf137018
5364990Sjf137018 /* name .conf nodes by "unit-address" property */
5374990Sjf137018 if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, child,
5384990Sjf137018 DDI_PROP_DONTPASS, "unit-address", &unit_addr, &n) !=
5394990Sjf137018 DDI_PROP_SUCCESS) {
5404990Sjf137018 cmn_err(CE_WARN, "cannot name node from %s.conf",
5414990Sjf137018 ddi_driver_name(child));
5424990Sjf137018 return (DDI_FAILURE);
5434990Sjf137018 }
5444990Sjf137018 if (n != 1 || *unit_addr == NULL || **unit_addr == 0) {
5454990Sjf137018 cmn_err(CE_WARN, "unit-address property in %s.conf"
5464990Sjf137018 " not well-formed", ddi_driver_name(child));
5474990Sjf137018 ddi_prop_free(unit_addr);
5484990Sjf137018 return (DDI_FAILURE);
5494990Sjf137018 }
5504990Sjf137018
5514990Sjf137018 (void) snprintf(name, namelen, "%s", *unit_addr);
5524990Sjf137018 ddi_prop_free(unit_addr);
5534990Sjf137018 return (DDI_SUCCESS);
5544990Sjf137018 }
5554990Sjf137018
5564990Sjf137018 /* name hardware nodes by "reg" property */
5574990Sjf137018 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
5584990Sjf137018 "reg", (int **)&r, &n) != DDI_SUCCESS) {
5594990Sjf137018 cmn_err(CE_WARN, "reg property not well-formed");
5604990Sjf137018 return (DDI_FAILURE);
5614990Sjf137018 }
5626495Sspeer (void) snprintf(name, namelen, "%x", (r[0].addr_high));
5634990Sjf137018 ddi_prop_free(r);
5644990Sjf137018 return (DDI_SUCCESS);
5654990Sjf137018 }
5664990Sjf137018
5673156Sgirish static int
niumx_initchild(dev_info_t * child)5683156Sgirish niumx_initchild(dev_info_t *child)
5693156Sgirish {
5703156Sgirish char name[MAXNAMELEN];
5714990Sjf137018
57211513SAlan.Adamson@Sun.COM DBG(NIUMX_DBG_CHK_MOD, (dev_info_t *)child, "==> niumx_initchild\n");
5734990Sjf137018 /*
5744990Sjf137018 * Non-peristent nodes indicate a prototype node with per-instance
5754990Sjf137018 * properties to be merged into the real h/w device node.
5764990Sjf137018 */
5774990Sjf137018 if (ndi_dev_is_persistent_node(child) == 0) {
5784990Sjf137018 niu_regspec_t *r;
5794990Sjf137018 uint_t n;
5804990Sjf137018
5814990Sjf137018 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child,
5824990Sjf137018 DDI_PROP_DONTPASS, "reg", (int **)&r, &n) ==
5834990Sjf137018 DDI_SUCCESS) {
5844990Sjf137018 cmn_err(CE_WARN,
5854990Sjf137018 "cannot merge prototype from %s.conf",
5864990Sjf137018 ddi_driver_name(child));
5874990Sjf137018 ddi_prop_free(r);
5884990Sjf137018 return (DDI_NOT_WELL_FORMED);
5894990Sjf137018 }
5904990Sjf137018
5914990Sjf137018 if (niumx_name_child(child, name, MAXNAMELEN) != DDI_SUCCESS)
5924990Sjf137018 return (DDI_NOT_WELL_FORMED);
5934990Sjf137018
5944990Sjf137018 ddi_set_name_addr(child, name);
5954990Sjf137018 ddi_set_parent_data(child, NULL);
5963156Sgirish
5974990Sjf137018 /*
5984990Sjf137018 * Try to merge the properties from this prototype
5994990Sjf137018 * node into real h/w nodes.
6004990Sjf137018 */
6014990Sjf137018 if (ndi_merge_node(child, niumx_name_child) == DDI_SUCCESS) {
6024990Sjf137018 /*
6034990Sjf137018 * Merged ok - return failure to remove the node.
6044990Sjf137018 */
6054990Sjf137018 ddi_set_name_addr(child, NULL);
6064990Sjf137018 return (DDI_FAILURE);
6074990Sjf137018 }
6084990Sjf137018
6094990Sjf137018 /*
6104990Sjf137018 * The child was not merged into a h/w node,
6114990Sjf137018 * but there's not much we can do with it other
6124990Sjf137018 * than return failure to cause the node to be removed.
6134990Sjf137018 */
6144990Sjf137018 cmn_err(CE_WARN, "!%s@%s: %s.conf properties not merged",
6154990Sjf137018 ddi_driver_name(child), ddi_get_name_addr(child),
6164990Sjf137018 ddi_driver_name(child));
6174990Sjf137018 ddi_set_name_addr(child, NULL);
6184990Sjf137018 return (DDI_NOT_WELL_FORMED);
6193156Sgirish }
6204990Sjf137018
6214990Sjf137018 /*
6224990Sjf137018 * Initialize real h/w nodes
6234990Sjf137018 */
6244990Sjf137018 if (niumx_name_child(child, name, MAXNAMELEN) != DDI_SUCCESS)
6254990Sjf137018 return (DDI_FAILURE);
6264990Sjf137018
6273156Sgirish ddi_set_name_addr(child, name);
6283156Sgirish return (DDI_SUCCESS);
6293156Sgirish }
6303156Sgirish
6313156Sgirish static void
niumx_removechild(dev_info_t * dip)6323156Sgirish niumx_removechild(dev_info_t *dip)
6333156Sgirish {
6343156Sgirish ddi_set_name_addr(dip, NULL);
6353156Sgirish ddi_remove_minor_node(dip, NULL);
6363156Sgirish impl_rem_dev_props(dip);
6373156Sgirish }
6383156Sgirish
6393156Sgirish
6403156Sgirish
6413156Sgirish /*
6423156Sgirish * bus dma alloc handle entry point:
6433156Sgirish */
6443156Sgirish /*ARGSUSED*/
6453156Sgirish int
niumx_dma_allochdl(dev_info_t * dip,dev_info_t * rdip,ddi_dma_attr_t * attrp,int (* waitfp)(caddr_t),caddr_t arg,ddi_dma_handle_t * handlep)6463156Sgirish niumx_dma_allochdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_attr_t *attrp,
6473156Sgirish int (*waitfp)(caddr_t), caddr_t arg, ddi_dma_handle_t *handlep)
6483156Sgirish {
6493156Sgirish ddi_dma_impl_t *mp;
6503156Sgirish int sleep = (waitfp == DDI_DMA_SLEEP) ? KM_SLEEP : KM_NOSLEEP;
6513156Sgirish
65211513SAlan.Adamson@Sun.COM DBG(NIUMX_DBG_DMA_ALLOCH, dip, "rdip=%s%d\n", NIUMX_NAMEINST(rdip));
6533156Sgirish
6543156Sgirish if (attrp->dma_attr_version != DMA_ATTR_V0) {
65511513SAlan.Adamson@Sun.COM DBG(NIUMX_DBG_DMA_ALLOCH,
65611513SAlan.Adamson@Sun.COM (dev_info_t *)dip, "DDI_DMA_BADATTR\n");
6573156Sgirish return (DDI_DMA_BADATTR);
6583156Sgirish }
6593156Sgirish
6603156Sgirish /* Caution: we don't use zalloc to enhance performance! */
6613156Sgirish if ((mp = kmem_alloc(sizeof (ddi_dma_impl_t), sleep)) == 0) {
66211513SAlan.Adamson@Sun.COM DBG(NIUMX_DBG_DMA_ALLOCH, dip, "can't alloc ddi_dma_impl_t\n");
6633156Sgirish return (DDI_FAILURE);
6643156Sgirish }
6653156Sgirish mp->dmai_rdip = rdip;
6663156Sgirish mp->dmai_pfnlst = NULL;
6673156Sgirish mp->dmai_cookie = NULL;
6683156Sgirish mp->dmai_fault = 0;
6693156Sgirish mp->dmai_fault_check = NULL;
6703156Sgirish mp->dmai_fault_notify = NULL;
6713156Sgirish
6723156Sgirish mp->dmai_attr = *attrp; /* set requestors attr info */
6733156Sgirish
67411513SAlan.Adamson@Sun.COM DBG(NIUMX_DBG_DMA_ALLOCH, dip, "mp=%p\n", mp);
6753156Sgirish
6763156Sgirish *handlep = (ddi_dma_handle_t)mp;
6773156Sgirish return (DDI_SUCCESS);
6783156Sgirish }
6793156Sgirish
6803156Sgirish
6813156Sgirish /*
6823156Sgirish * bus dma free handle entry point:
6833156Sgirish */
6843156Sgirish /*ARGSUSED*/
6853156Sgirish int
niumx_dma_freehdl(dev_info_t * dip,dev_info_t * rdip,ddi_dma_handle_t handle)6863156Sgirish niumx_dma_freehdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t handle)
6873156Sgirish {
6883156Sgirish ddi_dma_impl_t *mp = (ddi_dma_impl_t *)handle;
6893156Sgirish
6903156Sgirish if (mp->dmai_cookie)
6913156Sgirish kmem_free(mp->dmai_cookie, sizeof (ddi_dma_cookie_t));
6923156Sgirish kmem_free(mp, sizeof (ddi_dma_impl_t));
6933156Sgirish
6943156Sgirish return (DDI_SUCCESS);
6953156Sgirish }
6963156Sgirish
6973156Sgirish
6983156Sgirish /*
6993156Sgirish * bus dma bind handle entry point:
7003156Sgirish *
7013156Sgirish * check/enforce DMA type, setup pfn0 and some other key pieces
7023156Sgirish * of this dma request.
7033156Sgirish * Note: this only works with DMA_OTYP_VADDR, and makes use of the known
7043156Sgirish * fact that only contiguous memory blocks will be passed in.
7053156Sgirish * Therefore only one cookie will ever be returned.
7063156Sgirish *
7073156Sgirish * return values:
7083156Sgirish * DDI_DMA_NOMAPPING - can't get valid pfn0, or bad dma type
7093156Sgirish * DDI_DMA_NORESOURCES
7103156Sgirish * DDI_SUCCESS
7113156Sgirish *
7123156Sgirish * dma handle members affected (set on exit):
7133156Sgirish * mp->dmai_object - dmareq->dmar_object
7143156Sgirish * mp->dmai_rflags - dmareq->dmar_flags
7153156Sgirish * mp->dmai_pfn0 - 1st page pfn (if va/size pair and not shadow)
7163156Sgirish * mp->dmai_roffset - initialized to starting page offset
7173156Sgirish * mp->dmai_size - # of total pages of entire object
7183156Sgirish * mp->dmai_cookie - new cookie alloc'd
7193156Sgirish */
7203156Sgirish /*ARGSUSED*/
7213156Sgirish int
niumx_dma_bindhdl(dev_info_t * dip,dev_info_t * rdip,ddi_dma_handle_t handle,ddi_dma_req_t * dmareq,ddi_dma_cookie_t * cookiep,uint_t * ccountp)7223156Sgirish niumx_dma_bindhdl(dev_info_t *dip, dev_info_t *rdip,
7233156Sgirish ddi_dma_handle_t handle, ddi_dma_req_t *dmareq,
7243156Sgirish ddi_dma_cookie_t *cookiep, uint_t *ccountp)
7253156Sgirish {
7263156Sgirish int (*waitfp)(caddr_t) = dmareq->dmar_fp;
7273156Sgirish ddi_dma_impl_t *mp = (ddi_dma_impl_t *)handle;
7283156Sgirish ddi_dma_obj_t *dobj_p = &dmareq->dmar_object;
7293156Sgirish uint32_t offset;
7303156Sgirish pfn_t pfn0;
7313156Sgirish int ret;
7323156Sgirish
73311513SAlan.Adamson@Sun.COM DBG(NIUMX_DBG_DMA_BINDH, dip, "rdip=%s%d mp=%p dmareq=%p\n",
73411513SAlan.Adamson@Sun.COM NIUMX_NAMEINST(rdip), mp, dmareq);
7353156Sgirish
7363156Sgirish /* first check dma type */
7373156Sgirish mp->dmai_rflags = dmareq->dmar_flags & DMP_DDIFLAGS | DMP_NOSYNC;
7383156Sgirish switch (dobj_p->dmao_type) {
7393156Sgirish case DMA_OTYP_VADDR: {
7403156Sgirish caddr_t vaddr = dobj_p->dmao_obj.virt_obj.v_addr;
7413156Sgirish struct as *as_p = dobj_p->dmao_obj.virt_obj.v_as;
7423156Sgirish struct hat *hat_p = as_p ? as_p->a_hat : kas.a_hat;
7433156Sgirish offset = (ulong_t)vaddr & NIUMX_PAGE_OFFSET;
7443156Sgirish pfn0 = hat_getpfnum(hat_p, vaddr);
7453156Sgirish }
7463156Sgirish break;
7473156Sgirish
7483156Sgirish case DMA_OTYP_BUFVADDR:
7493156Sgirish case DMA_OTYP_PAGES:
7503156Sgirish case DMA_OTYP_PADDR:
7513156Sgirish default:
7523156Sgirish cmn_err(CE_WARN, "%s%d requested unsupported dma type %x",
75311513SAlan.Adamson@Sun.COM NIUMX_NAMEINST(mp->dmai_rdip), dobj_p->dmao_type);
7543156Sgirish ret = DDI_DMA_NOMAPPING;
7553156Sgirish goto err;
7563156Sgirish }
7573156Sgirish if (pfn0 == PFN_INVALID) {
7583156Sgirish cmn_err(CE_WARN, "%s%d: invalid pfn0 for DMA object %p",
75911513SAlan.Adamson@Sun.COM NIUMX_NAMEINST(dip), (void *)dobj_p);
7603156Sgirish ret = DDI_DMA_NOMAPPING;
7613156Sgirish goto err;
7623156Sgirish }
7633156Sgirish mp->dmai_object = *dobj_p; /* whole object */
7643156Sgirish mp->dmai_pfn0 = (void *)pfn0; /* cache pfn0 */
7653156Sgirish mp->dmai_roffset = offset; /* pg0 offset */
7663156Sgirish mp->dmai_mapping = mp->dmai_roffset | NIUMX_PTOB(pfn0);
7673156Sgirish mp->dmai_size = mp->dmai_object.dmao_size;
7683156Sgirish
76911513SAlan.Adamson@Sun.COM DBG(NIUMX_DBG_DMA_BINDH, dip, "check pfn: mp=%p pfn0=%x\n",
7704990Sjf137018 mp, mp->dmai_pfn0);
7713156Sgirish if (!(mp->dmai_cookie = kmem_zalloc(sizeof (ddi_dma_cookie_t),
7724990Sjf137018 waitfp == DDI_DMA_SLEEP ? KM_SLEEP : KM_NOSLEEP))) {
7733156Sgirish ret = DDI_DMA_NORESOURCES;
7743156Sgirish goto err;
7753156Sgirish }
7763156Sgirish mp->dmai_cookie->dmac_laddress = mp->dmai_mapping;
7773156Sgirish mp->dmai_cookie->dmac_size = mp->dmai_size;
7783156Sgirish *ccountp = 1;
7793156Sgirish *cookiep = *mp->dmai_cookie;
78011513SAlan.Adamson@Sun.COM DBG(NIUMX_DBG_DMA_BINDH, dip, "cookie %" PRIx64 "+%x, count=%d\n",
7814990Sjf137018 cookiep->dmac_address, cookiep->dmac_size, *ccountp);
7823156Sgirish return (DDI_DMA_MAPPED);
7833156Sgirish
7843156Sgirish err:
78511513SAlan.Adamson@Sun.COM DBG(NIUMX_DBG_DMA_BINDH, (dev_info_t *)dip,
7864990Sjf137018 "niumx_dma_bindhdl error ret=%d\n", ret);
7873156Sgirish return (ret);
7883156Sgirish }
7893156Sgirish
7903156Sgirish /*
7913156Sgirish * bus dma unbind handle entry point:
7923156Sgirish */
7933156Sgirish /*ARGSUSED*/
7943156Sgirish int
niumx_dma_unbindhdl(dev_info_t * dip,dev_info_t * rdip,ddi_dma_handle_t handle)7953156Sgirish niumx_dma_unbindhdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t handle)
7963156Sgirish {
7973156Sgirish ddi_dma_impl_t *mp = (ddi_dma_impl_t *)handle;
7983156Sgirish
79911513SAlan.Adamson@Sun.COM DBG(NIUMX_DBG_DMA_UNBINDH, dip, "rdip=%s%d, mp=%p\n",
8004990Sjf137018 ddi_driver_name(rdip), ddi_get_instance(rdip), handle);
8013156Sgirish if (mp->dmai_cookie) {
8023156Sgirish kmem_free(mp->dmai_cookie, sizeof (ddi_dma_cookie_t));
8033156Sgirish mp->dmai_cookie = NULL;
8043156Sgirish }
8053156Sgirish
8063156Sgirish return (DDI_SUCCESS);
8073156Sgirish }
8083156Sgirish
8093156Sgirish /*ARGSUSED*/
8103156Sgirish int
niumx_intr_ops(dev_info_t * dip,dev_info_t * rdip,ddi_intr_op_t intr_op,ddi_intr_handle_impl_t * hdlp,void * result)8113156Sgirish niumx_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
8123156Sgirish ddi_intr_handle_impl_t *hdlp, void *result)
8133156Sgirish {
8143156Sgirish
8153156Sgirish int ret = DDI_SUCCESS;
8163156Sgirish
81711513SAlan.Adamson@Sun.COM DBG(NIUMX_DBG_INTROPS, dip, "niumx_intr_ops: dip=%p rdip=%p intr_op=%x "
8183156Sgirish "handle=%p\n", dip, rdip, intr_op, hdlp);
8193156Sgirish
8203156Sgirish switch (intr_op) {
8213156Sgirish
8223156Sgirish case DDI_INTROP_SUPPORTED_TYPES:
8233156Sgirish *(int *)result = DDI_INTR_TYPE_FIXED;
8243156Sgirish break;
8253156Sgirish case DDI_INTROP_GETCAP:
826*12564SGongtian.Zhao@Sun.COM *(int *)result = DDI_INTR_FLAG_LEVEL;
8273156Sgirish break;
8283156Sgirish case DDI_INTROP_SETCAP:
8293156Sgirish ret = DDI_ENOTSUP;
8303156Sgirish break;
8313156Sgirish case DDI_INTROP_ALLOC:
8323156Sgirish /* scratch1 = count, # of intrs from DDI framework */
8333156Sgirish *(int *)result = hdlp->ih_scratch1;
8343156Sgirish break;
8353156Sgirish case DDI_INTROP_FREE:
8363156Sgirish /* Do we need to do anything here? */
8373156Sgirish break;
8383156Sgirish case DDI_INTROP_GETPRI:
8393156Sgirish *(int *)result = NIUMX_DEFAULT_PIL;
8403156Sgirish break;
8413156Sgirish case DDI_INTROP_SETPRI:
8423156Sgirish ret = DDI_ENOTSUP;
8433156Sgirish break;
8443156Sgirish case DDI_INTROP_ADDISR:
8453156Sgirish ret = niumx_add_intr(dip, rdip, hdlp);
8463156Sgirish break;
8473156Sgirish case DDI_INTROP_REMISR:
8483156Sgirish ret = niumx_rem_intr(dip, rdip, hdlp);
8493156Sgirish break;
8503156Sgirish case DDI_INTROP_ENABLE:
8513156Sgirish ret = niumx_set_intr(dip, rdip, hdlp, HV_INTR_VALID);
8523156Sgirish break;
8533156Sgirish case DDI_INTROP_DISABLE:
8543156Sgirish ret = niumx_set_intr(dip, rdip, hdlp, HV_INTR_NOTVALID);
8553156Sgirish break;
8563156Sgirish case DDI_INTROP_SETMASK:
8573156Sgirish ret = DDI_ENOTSUP;
8583156Sgirish break;
8593156Sgirish case DDI_INTROP_CLRMASK:
8603156Sgirish ret = DDI_ENOTSUP;
8613156Sgirish break;
8623156Sgirish case DDI_INTROP_GETPENDING:
8633156Sgirish ret = DDI_ENOTSUP;
8643156Sgirish break;
8653156Sgirish case DDI_INTROP_NINTRS:
8663156Sgirish case DDI_INTROP_NAVAIL: {
86711513SAlan.Adamson@Sun.COM niudevino_t *inos_p;
8683156Sgirish int inoslen;
86911513SAlan.Adamson@Sun.COM
8703156Sgirish if (ddi_getlongprop(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS,
8714990Sjf137018 "interrupts", (caddr_t)&inos_p, &inoslen)
8724990Sjf137018 != DDI_SUCCESS) {
8734990Sjf137018 ret = DDI_FAILURE;
8744990Sjf137018 break;
8753156Sgirish }
8763156Sgirish *(int *)result = inoslen / sizeof (uint32_t);
8773156Sgirish kmem_free(inos_p, inoslen);
8783156Sgirish }
8793156Sgirish break;
88011513SAlan.Adamson@Sun.COM case DDI_INTROP_GETTARGET: {
88111513SAlan.Adamson@Sun.COM niumx_devstate_t *niumxds_p;
88211513SAlan.Adamson@Sun.COM
88311513SAlan.Adamson@Sun.COM niumxds_p = (niumx_devstate_t *)ddi_get_soft_state(niumx_state,
88411513SAlan.Adamson@Sun.COM ddi_get_instance(dip));
88511513SAlan.Adamson@Sun.COM
88611513SAlan.Adamson@Sun.COM ret = niumx_get_intr_target(niumxds_p, hdlp->ih_vector,
88711513SAlan.Adamson@Sun.COM (niucpuid_t *)result);
88811513SAlan.Adamson@Sun.COM
88911513SAlan.Adamson@Sun.COM }
89011513SAlan.Adamson@Sun.COM break;
89111513SAlan.Adamson@Sun.COM case DDI_INTROP_SETTARGET: {
89211513SAlan.Adamson@Sun.COM niumx_devstate_t *niumxds_p;
89311513SAlan.Adamson@Sun.COM
89411513SAlan.Adamson@Sun.COM niumxds_p = (niumx_devstate_t *)ddi_get_soft_state(niumx_state,
89511513SAlan.Adamson@Sun.COM ddi_get_instance(dip));
89611513SAlan.Adamson@Sun.COM
89711513SAlan.Adamson@Sun.COM ret = niumx_set_intr_target(niumxds_p, hdlp->ih_vector,
89811513SAlan.Adamson@Sun.COM *(niucpuid_t *)result);
89911513SAlan.Adamson@Sun.COM
90011513SAlan.Adamson@Sun.COM }
90111513SAlan.Adamson@Sun.COM break;
9023156Sgirish default:
9033156Sgirish ret = DDI_ENOTSUP;
9043156Sgirish break;
9053156Sgirish }
9063156Sgirish
90711513SAlan.Adamson@Sun.COM DBG(NIUMX_DBG_INTROPS, dip, "niumx_intr_ops: ret=%d\n", ret);
9083156Sgirish return (ret);
9093156Sgirish }
9103156Sgirish
9113156Sgirish int
niumx_set_intr(dev_info_t * dip,dev_info_t * rdip,ddi_intr_handle_impl_t * hdlp,int valid)9123156Sgirish niumx_set_intr(dev_info_t *dip, dev_info_t *rdip,
9133156Sgirish ddi_intr_handle_impl_t *hdlp, int valid)
9143156Sgirish {
9153156Sgirish niumx_ih_t *ih_p;
91611513SAlan.Adamson@Sun.COM int ret = DDI_SUCCESS;
9173156Sgirish uint64_t hvret;
91811304SJanie.Lu@Sun.COM niumx_devstate_t *niumxds_p; /* devstate pointer */
91911304SJanie.Lu@Sun.COM int instance = ddi_get_instance(dip);
92011304SJanie.Lu@Sun.COM
92111304SJanie.Lu@Sun.COM niumxds_p = (niumx_devstate_t *)ddi_get_soft_state(niumx_state,
92211304SJanie.Lu@Sun.COM instance);
9233156Sgirish
9243156Sgirish ASSERT(hdlp->ih_inum < NIUMX_MAX_INTRS);
9253156Sgirish
92611513SAlan.Adamson@Sun.COM ih_p = niumxds_p->niumx_ihtable + hdlp->ih_vector;
92711304SJanie.Lu@Sun.COM
92811513SAlan.Adamson@Sun.COM DBG(NIUMX_DBG_A_INTX, dip,
92911513SAlan.Adamson@Sun.COM "niumx_set_intr: rdip=%s%d, valid=%d %s (%x,%x)\n",
93011513SAlan.Adamson@Sun.COM NIUMX_NAMEINST(rdip), valid, valid ? "enabling" : "disabling",
9314990Sjf137018 ih_p->ih_inum, ih_p->ih_sysino);
9323156Sgirish
9334285Sspeer if (valid == HV_INTR_VALID)
9344285Sspeer (void) hvio_intr_setstate(ih_p->ih_sysino, HV_INTR_IDLE_STATE);
9353156Sgirish if ((hvret = hvio_intr_setvalid(ih_p->ih_sysino, valid))
9364990Sjf137018 != H_EOK) {
93711513SAlan.Adamson@Sun.COM DBG(NIUMX_DBG_A_INTX, dip,
93811513SAlan.Adamson@Sun.COM "hvio_intr_setvalid failed, ret 0x%x\n", hvret);
9393156Sgirish ret = DDI_FAILURE;
94011513SAlan.Adamson@Sun.COM } else
94111513SAlan.Adamson@Sun.COM ih_p->ih_state = valid;
94211513SAlan.Adamson@Sun.COM
9433156Sgirish return (ret);
9443156Sgirish }
9453156Sgirish
94611513SAlan.Adamson@Sun.COM int
niumx_get_intr_target(niumx_devstate_t * niumxds_p,niudevino_t ino,niucpuid_t * cpu_id)94711513SAlan.Adamson@Sun.COM niumx_get_intr_target(niumx_devstate_t *niumxds_p, niudevino_t ino,
94811513SAlan.Adamson@Sun.COM niucpuid_t *cpu_id)
94911513SAlan.Adamson@Sun.COM {
95011513SAlan.Adamson@Sun.COM niumx_ih_t *ih_p;
95111513SAlan.Adamson@Sun.COM niusysino_t sysino;
95211513SAlan.Adamson@Sun.COM int rval = DDI_SUCCESS;
95311513SAlan.Adamson@Sun.COM
95411513SAlan.Adamson@Sun.COM ih_p = niumxds_p->niumx_ihtable + ino;
95511513SAlan.Adamson@Sun.COM
95611513SAlan.Adamson@Sun.COM sysino = ih_p->ih_sysino;
95711513SAlan.Adamson@Sun.COM
95811513SAlan.Adamson@Sun.COM if (sysino == 0) {
95911513SAlan.Adamson@Sun.COM rval = EINVAL;
96011513SAlan.Adamson@Sun.COM goto done;
96111513SAlan.Adamson@Sun.COM }
96211513SAlan.Adamson@Sun.COM
96311513SAlan.Adamson@Sun.COM if (hvio_intr_gettarget(sysino, cpu_id) != H_EOK) {
96411513SAlan.Adamson@Sun.COM rval = EINVAL;
96511513SAlan.Adamson@Sun.COM goto done;
96611513SAlan.Adamson@Sun.COM }
96711513SAlan.Adamson@Sun.COM
96811513SAlan.Adamson@Sun.COM if (ih_p->ih_cpuid != *cpu_id)
96911513SAlan.Adamson@Sun.COM rval = EIO;
97011513SAlan.Adamson@Sun.COM
97111513SAlan.Adamson@Sun.COM done:
97211513SAlan.Adamson@Sun.COM return (rval);
97311513SAlan.Adamson@Sun.COM }
97411513SAlan.Adamson@Sun.COM
97511513SAlan.Adamson@Sun.COM int
niumx_set_intr_target(niumx_devstate_t * niumxds_p,niudevino_t ino,niucpuid_t cpu_id)97611513SAlan.Adamson@Sun.COM niumx_set_intr_target(niumx_devstate_t *niumxds_p, niudevino_t ino,
97711513SAlan.Adamson@Sun.COM niucpuid_t cpu_id)
97811513SAlan.Adamson@Sun.COM {
97911513SAlan.Adamson@Sun.COM dev_info_t *dip = niumxds_p->dip;
98011513SAlan.Adamson@Sun.COM niumx_ih_t *ih_p;
98111513SAlan.Adamson@Sun.COM niucpuid_t old_cpu_id;
98211513SAlan.Adamson@Sun.COM niusysino_t sysino;
98311513SAlan.Adamson@Sun.COM int ret = DDI_SUCCESS;
98411513SAlan.Adamson@Sun.COM int state;
98511513SAlan.Adamson@Sun.COM hrtime_t start;
98611513SAlan.Adamson@Sun.COM extern const int _ncpu;
98711513SAlan.Adamson@Sun.COM extern cpu_t *cpu[];
98811513SAlan.Adamson@Sun.COM
98911513SAlan.Adamson@Sun.COM mutex_enter(&cpu_lock);
99011513SAlan.Adamson@Sun.COM
99111513SAlan.Adamson@Sun.COM ih_p = niumxds_p->niumx_ihtable + ino;
99211513SAlan.Adamson@Sun.COM
99311513SAlan.Adamson@Sun.COM sysino = ih_p->ih_sysino;
99411513SAlan.Adamson@Sun.COM if (sysino == 0) {
99511513SAlan.Adamson@Sun.COM ret = EINVAL;
99611513SAlan.Adamson@Sun.COM goto done;
99711513SAlan.Adamson@Sun.COM }
99811513SAlan.Adamson@Sun.COM
99911513SAlan.Adamson@Sun.COM if (hvio_intr_gettarget(sysino, &old_cpu_id) != H_EOK) {
100011513SAlan.Adamson@Sun.COM ret = EINVAL;
100111513SAlan.Adamson@Sun.COM goto done;
100211513SAlan.Adamson@Sun.COM }
100311513SAlan.Adamson@Sun.COM if ((cpu_id < _ncpu) && (cpu[cpu_id] && cpu_is_online(cpu[cpu_id]))) {
100411513SAlan.Adamson@Sun.COM if (cpu_id == old_cpu_id)
100511513SAlan.Adamson@Sun.COM goto done;
100611513SAlan.Adamson@Sun.COM
100711513SAlan.Adamson@Sun.COM /* check for pending interrupts, busy wait if so */
100811513SAlan.Adamson@Sun.COM for (start = gethrtime(); !panicstr &&
100911513SAlan.Adamson@Sun.COM (hvio_intr_getstate(sysino, &state) == H_EOK) &&
101011513SAlan.Adamson@Sun.COM (state == HV_INTR_DELIVERED_STATE); /* */) {
101111513SAlan.Adamson@Sun.COM if (gethrtime() - start > niumx_intr_timeout) {
101211513SAlan.Adamson@Sun.COM cmn_err(CE_WARN, "%s%d: niumx_intr_dist: "
101311513SAlan.Adamson@Sun.COM "pending interrupt (%x,%lx) timedout\n",
101411513SAlan.Adamson@Sun.COM ddi_driver_name(dip), ddi_get_instance(dip),
101511513SAlan.Adamson@Sun.COM ih_p->ih_inum, sysino);
101611513SAlan.Adamson@Sun.COM (void) hvio_intr_setstate(sysino,
101711513SAlan.Adamson@Sun.COM HV_INTR_IDLE_STATE);
101811513SAlan.Adamson@Sun.COM break;
101911513SAlan.Adamson@Sun.COM }
102011513SAlan.Adamson@Sun.COM }
102111513SAlan.Adamson@Sun.COM (void) hvio_intr_settarget(sysino, cpu_id);
102211513SAlan.Adamson@Sun.COM if (ih_p->ih_state == HV_INTR_VALID)
102311513SAlan.Adamson@Sun.COM (void) hvio_intr_setvalid(sysino, HV_INTR_VALID);
102411513SAlan.Adamson@Sun.COM else
102511513SAlan.Adamson@Sun.COM (void) hvio_intr_setvalid(sysino, HV_INTR_NOTVALID);
102611513SAlan.Adamson@Sun.COM ih_p->ih_cpuid = cpu_id;
102711513SAlan.Adamson@Sun.COM } else {
102811513SAlan.Adamson@Sun.COM ret = DDI_EINVAL;
102911513SAlan.Adamson@Sun.COM }
103011513SAlan.Adamson@Sun.COM
103111513SAlan.Adamson@Sun.COM done:
103211513SAlan.Adamson@Sun.COM mutex_exit(&cpu_lock);
103311513SAlan.Adamson@Sun.COM return (ret);
103411513SAlan.Adamson@Sun.COM }
10353156Sgirish
10363156Sgirish
10373156Sgirish /*
10383156Sgirish * niumx_add_intr:
10393156Sgirish *
10407741SRaghuram.Kothakota@Sun.COM * This function is called to register interrupts.
10413156Sgirish */
10423156Sgirish int
niumx_add_intr(dev_info_t * dip,dev_info_t * rdip,ddi_intr_handle_impl_t * hdlp)10433156Sgirish niumx_add_intr(dev_info_t *dip, dev_info_t *rdip,
10443156Sgirish ddi_intr_handle_impl_t *hdlp)
10453156Sgirish {
10463156Sgirish niumx_ih_t *ih_p;
104711513SAlan.Adamson@Sun.COM int ret = DDI_SUCCESS;
10483156Sgirish uint64_t hvret;
104911513SAlan.Adamson@Sun.COM niusysino_t sysino;
105011304SJanie.Lu@Sun.COM niumx_devstate_t *niumxds_p; /* devstate pointer */
105111304SJanie.Lu@Sun.COM int instance = ddi_get_instance(dip);
105211304SJanie.Lu@Sun.COM
105311304SJanie.Lu@Sun.COM niumxds_p = (niumx_devstate_t *)ddi_get_soft_state(niumx_state,
105411304SJanie.Lu@Sun.COM instance);
10553156Sgirish
10563156Sgirish /* get new ino */
10573156Sgirish if (hdlp->ih_inum >= NIUMX_MAX_INTRS) {
105811513SAlan.Adamson@Sun.COM DBG(NIUMX_DBG_INTR, dip, "error: inum %d out of range\n",
10594990Sjf137018 hdlp->ih_inum);
10603156Sgirish ret = DDI_FAILURE;
10613156Sgirish goto done;
10623156Sgirish }
106311513SAlan.Adamson@Sun.COM
106411513SAlan.Adamson@Sun.COM ih_p = niumxds_p->niumx_ihtable + hdlp->ih_vector;
106511513SAlan.Adamson@Sun.COM
106611513SAlan.Adamson@Sun.COM if ((hvret = hvio_intr_devino_to_sysino(NIUMX_DIP_TO_HANDLE(dip),
106711513SAlan.Adamson@Sun.COM hdlp->ih_vector, &sysino)) != H_EOK) {
106811513SAlan.Adamson@Sun.COM DBG(NIUMX_DBG_INTR, dip, "hvio_intr_devino_to_sysino failed, "
10694990Sjf137018 "ret 0x%x\n", hvret);
10703156Sgirish ret = DDI_FAILURE;
10713156Sgirish goto done;
10723156Sgirish }
10733156Sgirish ih_p->ih_sysino = sysino;
107411513SAlan.Adamson@Sun.COM ih_p->ih_dip = rdip;
10753156Sgirish ih_p->ih_inum = hdlp->ih_inum;
10763156Sgirish ih_p->ih_hdlr = hdlp->ih_cb_func;
10773156Sgirish ih_p->ih_arg1 = hdlp->ih_cb_arg1;
10783156Sgirish ih_p->ih_arg2 = hdlp->ih_cb_arg2;
10793156Sgirish
108011513SAlan.Adamson@Sun.COM DBG(NIUMX_DBG_A_INTX, dip, "niumx_add_intr: rdip=%s%d inum=0x%x "
108111513SAlan.Adamson@Sun.COM "handler=%p arg1=%p arg2=%p, new ih_p = %p\n", NIUMX_NAMEINST(rdip),
10824990Sjf137018 hdlp->ih_inum, hdlp->ih_cb_func, hdlp->ih_cb_arg1,
10834990Sjf137018 hdlp->ih_cb_arg2, ih_p);
10843156Sgirish
10853156Sgirish if (hdlp->ih_pri == 0)
10863156Sgirish hdlp->ih_pri = NIUMX_DEFAULT_PIL;
10873156Sgirish
108811513SAlan.Adamson@Sun.COM ih_p->ih_pri = hdlp->ih_pri;
108911513SAlan.Adamson@Sun.COM
109011513SAlan.Adamson@Sun.COM DBG(NIUMX_DBG_A_INTX, dip, "for ino %x adding (%x,%x)\n",
109111513SAlan.Adamson@Sun.COM hdlp->ih_vector, ih_p->ih_inum, ih_p->ih_sysino);
109211513SAlan.Adamson@Sun.COM
10933156Sgirish /* Save sysino value in hdlp */
10943156Sgirish hdlp->ih_vector = ih_p->ih_sysino;
10953156Sgirish
10963156Sgirish /* swap in our handler & arg */
10973156Sgirish DDI_INTR_ASSIGN_HDLR_N_ARGS(hdlp, (ddi_intr_handler_t *)niumx_intr_hdlr,
10984990Sjf137018 (void *)ih_p, NULL);
10993156Sgirish
11003156Sgirish ret = i_ddi_add_ivintr(hdlp);
11013156Sgirish
11023156Sgirish /* Restore orig. interrupt handler & args in handle. */
11033156Sgirish DDI_INTR_ASSIGN_HDLR_N_ARGS(hdlp, ih_p->ih_hdlr, ih_p->ih_arg1,
11044990Sjf137018 ih_p->ih_arg2);
11053156Sgirish
11063156Sgirish if (ret != DDI_SUCCESS) {
110711513SAlan.Adamson@Sun.COM DBG(NIUMX_DBG_A_INTX, dip, "i_ddi_add_ivintr error ret=%x\n",
110811513SAlan.Adamson@Sun.COM ret);
11093156Sgirish goto done;
11103156Sgirish }
11113156Sgirish
11123156Sgirish /* select cpu, saving it for removal */
11133156Sgirish ih_p->ih_cpuid = intr_dist_cpuid();
11143156Sgirish
11153156Sgirish if ((hvret = hvio_intr_settarget(ih_p->ih_sysino, ih_p->ih_cpuid))
11164990Sjf137018 != H_EOK) {
111711513SAlan.Adamson@Sun.COM DBG(NIUMX_DBG_A_INTX, dip,
111811513SAlan.Adamson@Sun.COM "hvio_intr_settarget failed, ret 0x%x\n", hvret);
11193156Sgirish ret = DDI_FAILURE;
11203156Sgirish }
11213156Sgirish done:
112211513SAlan.Adamson@Sun.COM DBG(NIUMX_DBG_A_INTX, dip, "done, ret = %d, ih_p 0x%p, hdlp 0x%p\n",
112311513SAlan.Adamson@Sun.COM ih_p, hdlp, ret);
11243156Sgirish return (ret);
11253156Sgirish }
11263156Sgirish
11273156Sgirish /*
11283156Sgirish * niumx_rem_intr:
11293156Sgirish *
11303156Sgirish * This function is called to unregister interrupts.
11313156Sgirish */
113211513SAlan.Adamson@Sun.COM /*ARGSUSED*/
11333156Sgirish int
niumx_rem_intr(dev_info_t * dip,dev_info_t * rdip,ddi_intr_handle_impl_t * hdlp)11343156Sgirish niumx_rem_intr(dev_info_t *dip, dev_info_t *rdip,
11353156Sgirish ddi_intr_handle_impl_t *hdlp)
11363156Sgirish {
11373156Sgirish niumx_ih_t *ih_p;
113811513SAlan.Adamson@Sun.COM int ret = DDI_SUCCESS, state;
11394329Sjf137018 hrtime_t start;
114011513SAlan.Adamson@Sun.COM niusysino_t sysino;
114111304SJanie.Lu@Sun.COM niumx_devstate_t *niumxds_p; /* devstate pointer */
114211304SJanie.Lu@Sun.COM int instance = ddi_get_instance(dip);
114311304SJanie.Lu@Sun.COM
114411304SJanie.Lu@Sun.COM niumxds_p = (niumx_devstate_t *)ddi_get_soft_state(niumx_state,
114511304SJanie.Lu@Sun.COM instance);
11463156Sgirish
11473156Sgirish ASSERT(hdlp->ih_inum < NIUMX_MAX_INTRS);
11483156Sgirish
114911513SAlan.Adamson@Sun.COM ih_p = niumxds_p->niumx_ihtable + hdlp->ih_vector;
115011513SAlan.Adamson@Sun.COM
11514329Sjf137018 sysino = ih_p->ih_sysino;
115211513SAlan.Adamson@Sun.COM DBG(NIUMX_DBG_R_INTX, dip, "removing (%x,%x)\n", ih_p->ih_inum, sysino);
11534329Sjf137018
11544329Sjf137018 (void) hvio_intr_setvalid(sysino, HV_INTR_NOTVALID);
11553156Sgirish
11564329Sjf137018 /* check for pending interrupts, busy wait if so */
11574329Sjf137018 for (start = gethrtime(); !panicstr &&
11584329Sjf137018 (hvio_intr_getstate(sysino, &state) == H_EOK) &&
11594329Sjf137018 (state == HV_INTR_DELIVERED_STATE); /* */) {
11604329Sjf137018 if (gethrtime() - start > niumx_intr_timeout) {
11614329Sjf137018 cmn_err(CE_WARN, "%s%d: niumx_intr_dist: "
11624329Sjf137018 "pending interrupt (%x,%lx) timedout\n",
11634329Sjf137018 ddi_driver_name(dip), ddi_get_instance(dip),
11644329Sjf137018 ih_p->ih_inum, sysino);
11654329Sjf137018 ret = DDI_FAILURE;
116611513SAlan.Adamson@Sun.COM goto fail;
11674329Sjf137018 }
11683156Sgirish }
11693156Sgirish
11706495Sspeer ih_p->ih_sysino = 0;
11716495Sspeer
11724329Sjf137018 hdlp->ih_vector = (uint32_t)sysino;
11733156Sgirish if (hdlp->ih_vector != NULL) i_ddi_rem_ivintr(hdlp);
11743156Sgirish
117511513SAlan.Adamson@Sun.COM fail:
11763156Sgirish return (ret);
11773156Sgirish }
11783156Sgirish
11793156Sgirish /*
11803156Sgirish * niumx_intr_hdlr (our interrupt handler)
11813156Sgirish */
11823156Sgirish uint_t
niumx_intr_hdlr(void * arg)11833156Sgirish niumx_intr_hdlr(void *arg)
11843156Sgirish {
11853156Sgirish niumx_ih_t *ih_p = (niumx_ih_t *)arg;
11863156Sgirish uint_t r;
11873156Sgirish
11883156Sgirish DTRACE_PROBE4(interrupt__start, dev_info_t, ih_p->ih_dip, void *,
11894990Sjf137018 ih_p->ih_hdlr, caddr_t, ih_p->ih_arg1, caddr_t, ih_p->ih_arg2);
11903156Sgirish
11913156Sgirish r = (*ih_p->ih_hdlr)(ih_p->ih_arg1, ih_p->ih_arg2);
11923156Sgirish
11933156Sgirish DTRACE_PROBE4(interrupt__complete, dev_info_t, ih_p->ih_dip, void *,
11944990Sjf137018 ih_p->ih_hdlr, caddr_t, ih_p->ih_arg1, int, r);
11954285Sspeer
11964285Sspeer (void) hvio_intr_setstate(ih_p->ih_sysino, HV_INTR_IDLE_STATE);
11973156Sgirish return (r);
11983156Sgirish }
11993156Sgirish
12003156Sgirish #ifdef DEBUG
12013156Sgirish uint64_t niumx_debug_flags = 0;
12023156Sgirish
12033156Sgirish static char *niumx_debug_sym [] = { /* same sequence as niumx_debug_bit */
12043156Sgirish /* 0 */ "attach",
12053156Sgirish /* 1 */ "map",
12063156Sgirish /* 2 */ "nex-ctlops",
12073156Sgirish /* 3 */ "introps",
12083156Sgirish /* 4 */ "intr-add",
12093156Sgirish /* 5 */ "intr-rem",
12103156Sgirish /* 6 */ "intr",
12113156Sgirish /* 7 */ "dma-alloc",
12123156Sgirish /* 8 */ "dma-bind",
12133156Sgirish /* 9 */ "dma-unbind",
12143156Sgirish /* 10 */ "chk-dma-mode"
12153156Sgirish };
12163156Sgirish
12173156Sgirish /*ARGSUSED*/
12183156Sgirish void
niumx_dbg(niumx_debug_bit_t bit,dev_info_t * dip,char * fmt,...)12193156Sgirish niumx_dbg(niumx_debug_bit_t bit, dev_info_t *dip, char *fmt, ...)
12203156Sgirish {
12213156Sgirish va_list ap;
12223156Sgirish char msgbuf[1024];
12233156Sgirish
12243156Sgirish if (!(1ull << bit & niumx_debug_flags))
12253156Sgirish return;
12263156Sgirish va_start(ap, fmt);
12273156Sgirish (void) vsprintf(msgbuf, fmt, ap);
12283156Sgirish va_end(ap);
12293156Sgirish cmn_err(CE_NOTE, "%s: %s", niumx_debug_sym[bit], msgbuf);
12303156Sgirish }
12313156Sgirish
12323156Sgirish #endif /* DEBUG */
1233