xref: /illumos-gate/usr/src/uts/sun4v/io/niumx/niumx.c (revision 4df55fde)
144961713Sgirish /*
244961713Sgirish  * CDDL HEADER START
344961713Sgirish  *
444961713Sgirish  * The contents of this file are subject to the terms of the
544961713Sgirish  * Common Development and Distribution License (the "License").
644961713Sgirish  * You may not use this file except in compliance with the License.
744961713Sgirish  *
844961713Sgirish  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
944961713Sgirish  * or http://www.opensolaris.org/os/licensing.
1044961713Sgirish  * See the License for the specific language governing permissions
1144961713Sgirish  * and limitations under the License.
1244961713Sgirish  *
1344961713Sgirish  * When distributing Covered Code, include this CDDL HEADER in each
1444961713Sgirish  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1544961713Sgirish  * If applicable, add the following below this CDDL HEADER, with the
1644961713Sgirish  * fields enclosed by brackets "[]" replaced with your own identifying
1744961713Sgirish  * information: Portions Copyright [yyyy] [name of copyright owner]
1844961713Sgirish  *
1944961713Sgirish  * CDDL HEADER END
2044961713Sgirish  */
2144961713Sgirish /*
22*4df55fdeSJanie Lu  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
2344961713Sgirish  * Use is subject to license terms.
2444961713Sgirish  */
2544961713Sgirish 
2644961713Sgirish 
2744961713Sgirish /*
2844961713Sgirish  *	Niagara2 Network Interface Unit (NIU) Nexus Driver
2944961713Sgirish  */
3044961713Sgirish 
3144961713Sgirish #include <sys/conf.h>
3244961713Sgirish #include <sys/modctl.h>
3344961713Sgirish #include <sys/ddi_impldefs.h>
3444961713Sgirish #include <sys/ddi_subrdefs.h>
3544961713Sgirish #include <sys/ddi.h>
3644961713Sgirish #include <sys/sunndi.h>
3744961713Sgirish #include <sys/sunddi.h>
3844961713Sgirish #include <sys/open.h>
3944961713Sgirish #include <sys/stat.h>
4044961713Sgirish #include <sys/file.h>
4144961713Sgirish #include <sys/machsystm.h>
4244961713Sgirish #include <sys/hsvc.h>
4344961713Sgirish #include <sys/sdt.h>
4444961713Sgirish #include <sys/hypervisor_api.h>
4544961713Sgirish #include "niumx_var.h"
4644961713Sgirish 
478fca0570Sjf static int niumx_fm_init_child(dev_info_t *, dev_info_t *, int,
488fca0570Sjf 	ddi_iblock_cookie_t *);
4944961713Sgirish static int niumx_intr_ops(dev_info_t *dip, dev_info_t *rdip,
5044961713Sgirish 	ddi_intr_op_t intr_op, ddi_intr_handle_impl_t *hdlp, void *result);
5144961713Sgirish static int niumx_attach(dev_info_t *devi, ddi_attach_cmd_t cmd);
5244961713Sgirish static int niumx_detach(dev_info_t *devi, ddi_detach_cmd_t cmd);
5344961713Sgirish static int niumx_set_intr(dev_info_t *dip, dev_info_t *rdip,
5444961713Sgirish 	ddi_intr_handle_impl_t *hdlp, int valid);
5544961713Sgirish static int niumx_add_intr(dev_info_t *dip, dev_info_t *rdip,
5644961713Sgirish 	ddi_intr_handle_impl_t *hdlp);
5744961713Sgirish static int niumx_rem_intr(dev_info_t *dip, dev_info_t *rdip,
5844961713Sgirish 	ddi_intr_handle_impl_t *hdlp);
5944961713Sgirish static uint_t niumx_intr_hdlr(void *arg);
6044961713Sgirish static int niumx_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
6144961713Sgirish 	off_t offset, off_t len, caddr_t *addrp);
6244961713Sgirish static int niumx_dma_allochdl(dev_info_t *dip, dev_info_t *rdip,
6344961713Sgirish 	ddi_dma_attr_t *attrp,
6444961713Sgirish 	int (*waitfp)(caddr_t), caddr_t arg, ddi_dma_handle_t *handlep);
6544961713Sgirish static int niumx_dma_freehdl(dev_info_t *dip, dev_info_t *rdip,
6644961713Sgirish 	ddi_dma_handle_t handlep);
6744961713Sgirish static int niumx_dma_bindhdl(dev_info_t *dip, dev_info_t *rdip,
6844961713Sgirish 	ddi_dma_handle_t handle, ddi_dma_req_t *dmareq,
6944961713Sgirish 	ddi_dma_cookie_t *cookiep, uint_t *ccountp);
7044961713Sgirish static int niumx_dma_unbindhdl(dev_info_t *dip, dev_info_t *rdip,
7144961713Sgirish 	ddi_dma_handle_t handle);
7244961713Sgirish static int niumx_ctlops(dev_info_t *dip, dev_info_t *rdip,
7344961713Sgirish 	ddi_ctl_enum_t op, void *arg, void *result);
7444961713Sgirish 
7544961713Sgirish static struct bus_ops niumx_bus_ops = {
7644961713Sgirish 	BUSO_REV,
7744961713Sgirish 	niumx_map,
7844961713Sgirish 	0,
7944961713Sgirish 	0,
8044961713Sgirish 	0,
8144961713Sgirish 	i_ddi_map_fault,
8244961713Sgirish 	0,
8344961713Sgirish 	niumx_dma_allochdl,
8444961713Sgirish 	niumx_dma_freehdl,
8544961713Sgirish 	niumx_dma_bindhdl,
8644961713Sgirish 	niumx_dma_unbindhdl,
8744961713Sgirish 	0,
8844961713Sgirish 	0,
8944961713Sgirish 	0,
9044961713Sgirish 	niumx_ctlops,
9144961713Sgirish 	ddi_bus_prop_op,
9244961713Sgirish 	0,				/* (*bus_get_eventcookie)();    */
9344961713Sgirish 	0,				/* (*bus_add_eventcall)();	*/
9444961713Sgirish 	0,				/* (*bus_remove_eventcall)();   */
9544961713Sgirish 	0,				/* (*bus_post_event)();		*/
9644961713Sgirish 	0,				/* (*bus_intr_ctl)();		*/
9744961713Sgirish 	0,				/* (*bus_config)(); 		*/
9844961713Sgirish 	0,				/* (*bus_unconfig)(); 		*/
998fca0570Sjf 	niumx_fm_init_child,		/* (*bus_fm_init)(); 		*/
10044961713Sgirish 	0,				/* (*bus_fm_fini)(); 		*/
10144961713Sgirish 	0,				/* (*bus_enter)()		*/
10244961713Sgirish 	0,				/* (*bus_exit)()		*/
10344961713Sgirish 	0,				/* (*bus_power)()		*/
10444961713Sgirish 	niumx_intr_ops			/* (*bus_intr_op)(); 		*/
10544961713Sgirish };
10644961713Sgirish 
10744961713Sgirish static struct dev_ops niumx_ops = {
10844961713Sgirish 	DEVO_REV,		/* devo_rev */
10944961713Sgirish 	0,			/* refcnt  */
11044961713Sgirish 	ddi_no_info,		/* info */
11144961713Sgirish 	nulldev,		/* identify */
11244961713Sgirish 	0,			/* probe */
11344961713Sgirish 	niumx_attach,		/* attach */
11444961713Sgirish 	niumx_detach,		/* detach */
11544961713Sgirish 	nulldev,		/* reset */
11644961713Sgirish 	(struct cb_ops *)0,	/* driver operations */
11744961713Sgirish 	&niumx_bus_ops,		/* bus operations */
11819397407SSherry Moore 	0,			/* power */
11919397407SSherry Moore 	ddi_quiesce_not_supported,	/* devo_quiesce */
12044961713Sgirish };
12144961713Sgirish 
12244961713Sgirish /* Module linkage information for the kernel. */
12344961713Sgirish static struct modldrv modldrv = {
12444961713Sgirish 	&mod_driverops, /* Type of module */
12519397407SSherry Moore 	"NIU Nexus Driver",
12644961713Sgirish 	&niumx_ops,	/* driver ops */
12744961713Sgirish };
12844961713Sgirish 
12944961713Sgirish static struct modlinkage modlinkage = {
13044961713Sgirish 	MODREV_1,
13144961713Sgirish 	(void *)&modldrv,
13244961713Sgirish 	NULL
13344961713Sgirish };
13444961713Sgirish 
13544961713Sgirish static void *niumx_state;
13644961713Sgirish 
13744961713Sgirish /*
13844961713Sgirish  * forward function declarations:
13944961713Sgirish  */
14044961713Sgirish static void niumx_removechild(dev_info_t *);
14144961713Sgirish static int niumx_initchild(dev_info_t *child);
14244961713Sgirish 
14344961713Sgirish int
14444961713Sgirish _init(void)
14544961713Sgirish {
14644961713Sgirish 	int e;
147d66f8315Sjb 	uint64_t mjrnum;
148d66f8315Sjb 	uint64_t mnrnum;
149d66f8315Sjb 
150d66f8315Sjb 	/*
151d66f8315Sjb 	 * Check HV intr group api versioning.
152d66f8315Sjb 	 * This driver uses the old interrupt routines which are supported
153d66f8315Sjb 	 * in old firmware in the CORE API group and in newer firmware in
154d66f8315Sjb 	 * the INTR API group.  Support for these calls will be dropped
155d66f8315Sjb 	 * once the INTR API group major goes to 2.
156d66f8315Sjb 	 */
157d66f8315Sjb 	if ((hsvc_version(HSVC_GROUP_INTR, &mjrnum, &mnrnum) == 0) &&
158d66f8315Sjb 	    (mjrnum > NIUMX_INTR_MAJOR_VER)) {
159d66f8315Sjb 		cmn_err(CE_WARN, "niumx: unsupported intr api group: "
160d66f8315Sjb 		    "maj:0x%lx, min:0x%lx", mjrnum, mnrnum);
161d66f8315Sjb 		return (ENOTSUP);
162d66f8315Sjb 	}
163d66f8315Sjb 
16444961713Sgirish 	if ((e = ddi_soft_state_init(&niumx_state, sizeof (niumx_devstate_t),
16544961713Sgirish 	    1)) == 0 && (e = mod_install(&modlinkage)) != 0)
16644961713Sgirish 		ddi_soft_state_fini(&niumx_state);
16744961713Sgirish 	return (e);
16844961713Sgirish }
16944961713Sgirish 
17044961713Sgirish int
17144961713Sgirish _fini(void)
17244961713Sgirish {
17344961713Sgirish 	int e;
17444961713Sgirish 	if ((e = mod_remove(&modlinkage)) == 0)
17544961713Sgirish 		ddi_soft_state_fini(&niumx_state);
17644961713Sgirish 	return (e);
17744961713Sgirish }
17844961713Sgirish 
17944961713Sgirish int
18044961713Sgirish _info(struct modinfo *modinfop)
18144961713Sgirish {
18244961713Sgirish 	return (mod_info(&modlinkage, modinfop));
18344961713Sgirish }
18444961713Sgirish 
185c165966dSjf 
186c165966dSjf hrtime_t niumx_intr_timeout = 2ull * NANOSEC; /* 2 seconds in nanoseconds */
187c165966dSjf 
1883266dff7Sjf void
1893266dff7Sjf niumx_intr_dist(void *arg)
1903266dff7Sjf {
191*4df55fdeSJanie Lu 	niumx_devstate_t	*niumxds_p = (niumx_devstate_t *)arg;
192*4df55fdeSJanie Lu 	kmutex_t 	*lock_p = &niumxds_p->niumx_mutex;
193e778ae44SRaghuram Kothakota 	int		i;
194*4df55fdeSJanie Lu 	niumx_ih_t	*ih_p = niumxds_p->niumx_ihtable;
1953266dff7Sjf 
1963266dff7Sjf 	DBG(DBG_A_INTX, NULL, "niumx_intr_dist entered\n");
1973266dff7Sjf 	mutex_enter(lock_p);
198e778ae44SRaghuram Kothakota 	for (i = 0; i < NIUMX_MAX_INTRS; i++, ih_p++) {
1993266dff7Sjf 		sysino_t sysino = ih_p->ih_sysino;
2003266dff7Sjf 		cpuid_t	cpuid;
201c165966dSjf 		int	intr_state, state;
202c165966dSjf 		hrtime_t	start;
203c165966dSjf 		dev_info_t	*dip = ih_p->ih_dip;
2043266dff7Sjf 		if (!sysino ||	/* sequence is significant */
2053266dff7Sjf 		    (hvio_intr_getvalid(sysino, &intr_state) != H_EOK) ||
2063266dff7Sjf 		    (intr_state == HV_INTR_NOTVALID) ||
2073266dff7Sjf 		    (cpuid = intr_dist_cpuid()) == ih_p->ih_cpuid)
2083266dff7Sjf 			continue;
2093266dff7Sjf 
2103266dff7Sjf 		(void) hvio_intr_setvalid(sysino, HV_INTR_NOTVALID);
211c165966dSjf 
212c165966dSjf 		/* check for pending interrupts, busy wait if so */
213c165966dSjf 		for (start = gethrtime(); !panicstr &&
214c165966dSjf 		    (hvio_intr_getstate(sysino, &state) == H_EOK) &&
215c165966dSjf 		    (state == HV_INTR_DELIVERED_STATE); /* */) {
216c165966dSjf 			if (gethrtime() - start > niumx_intr_timeout) {
217c165966dSjf 				cmn_err(CE_WARN, "%s%d: niumx_intr_dist: "
218c165966dSjf 				    "pending interrupt (%x,%lx) timedout\n",
219c165966dSjf 				    ddi_driver_name(dip), ddi_get_instance(dip),
220c165966dSjf 				    ih_p->ih_inum, sysino);
221c165966dSjf 				(void) hvio_intr_setstate(sysino,
222adf6c93bSjf 				    HV_INTR_IDLE_STATE);
223c165966dSjf 				break;
224c165966dSjf 			}
225c165966dSjf 		}
2263266dff7Sjf 		(void) hvio_intr_settarget(sysino, cpuid);
2273266dff7Sjf 		(void) hvio_intr_setvalid(sysino, HV_INTR_VALID);
2283266dff7Sjf 		ih_p->ih_cpuid = cpuid;
2293266dff7Sjf 	}
2303266dff7Sjf 	mutex_exit(lock_p);
2313266dff7Sjf }
23244961713Sgirish 
23344961713Sgirish static int
23444961713Sgirish niumx_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
23544961713Sgirish {
23644961713Sgirish 	int instance = ddi_get_instance(dip);
23744961713Sgirish 	niumx_devstate_t *niumxds_p;	/* devstate pointer */
23844961713Sgirish 	niu_regspec_t	*reg_p;
23944961713Sgirish 	uint_t		reglen;
24044961713Sgirish 	int		ret = DDI_SUCCESS;
24144961713Sgirish 
24244961713Sgirish 	switch (cmd) {
24344961713Sgirish 	case DDI_ATTACH:
24444961713Sgirish 		if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip,
245adf6c93bSjf 		    DDI_PROP_DONTPASS, "reg", (int **)&reg_p, &reglen)
246adf6c93bSjf 		    != DDI_PROP_SUCCESS) {
24744961713Sgirish 			DBG(DBG_ATTACH, dip, "reg lookup failed\n");
24844961713Sgirish 			ret = DDI_FAILURE;
24944961713Sgirish 			goto done;
25044961713Sgirish 		}
25144961713Sgirish 
25244961713Sgirish 		/*
25344961713Sgirish 		 * Allocate and get soft state structure.
25444961713Sgirish 		 */
25544961713Sgirish 		if (ddi_soft_state_zalloc(niumx_state, instance)
256adf6c93bSjf 		    != DDI_SUCCESS) {
25744961713Sgirish 			ret = DDI_FAILURE;
25844961713Sgirish 			goto prop_free;
25944961713Sgirish 		}
26044961713Sgirish 		niumxds_p = (niumx_devstate_t *)ddi_get_soft_state(niumx_state,
261adf6c93bSjf 		    instance);
26244961713Sgirish 		niumxds_p->dip = dip;
26344961713Sgirish 		mutex_init(&niumxds_p->niumx_mutex, NULL, MUTEX_DRIVER, NULL);
26444961713Sgirish 
26544961713Sgirish 		DBG(DBG_ATTACH, dip, "soft state alloc'd instance = %d, "
266adf6c93bSjf 		    "niumxds_p = %p\n", instance, niumxds_p);
26744961713Sgirish 
26844961713Sgirish 		/* hv devhdl: low 28-bit of 1st "reg" entry's addr.hi */
26944961713Sgirish 		niumxds_p->niumx_dev_hdl = (devhandle_t)(reg_p->addr_high &
270adf6c93bSjf 		    NIUMX_DEVHDLE_MASK);
27144961713Sgirish 
2723266dff7Sjf 		/* add interrupt redistribution callback */
273*4df55fdeSJanie Lu 		intr_dist_add(niumx_intr_dist, niumxds_p);
2743266dff7Sjf 
2758fca0570Sjf 		niumxds_p->niumx_fm_cap = DDI_FM_EREPORT_CAPABLE;
27614ea4bb7Ssd 
27714ea4bb7Ssd 		ddi_fm_init(niumxds_p->dip, &niumxds_p->niumx_fm_cap,
278adf6c93bSjf 		    &niumxds_p->niumx_fm_ibc);
27914ea4bb7Ssd 
28044961713Sgirish 		ret = DDI_SUCCESS;
28144961713Sgirish 		goto prop_free;
28244961713Sgirish cleanup:
28344961713Sgirish 		mutex_destroy(&niumxds_p->niumx_mutex);
28444961713Sgirish 		ddi_soft_state_free(niumx_state, ddi_get_instance(dip));
28544961713Sgirish prop_free:
28644961713Sgirish 		ddi_prop_free(reg_p);
28744961713Sgirish done:
28844961713Sgirish 		return (ret);
28944961713Sgirish 
29044961713Sgirish 	case DDI_RESUME:
29144961713Sgirish 	default:
29244961713Sgirish 		break;
29344961713Sgirish 	}
29444961713Sgirish 	return (ret);
29544961713Sgirish }
29644961713Sgirish 
29744961713Sgirish static int
29844961713Sgirish niumx_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
29944961713Sgirish {
30044961713Sgirish 	niumx_devstate_t *niumxds_p;
30144961713Sgirish 
30244961713Sgirish 	switch (cmd) {
30344961713Sgirish 	case DDI_DETACH:
30444961713Sgirish 
30544961713Sgirish 		niumxds_p = (niumx_devstate_t *)
30644961713Sgirish 		    ddi_get_soft_state(niumx_state, ddi_get_instance(dip));
30744961713Sgirish 
308*4df55fdeSJanie Lu 		intr_dist_rem(niumx_intr_dist, niumxds_p);
30914ea4bb7Ssd 		ddi_fm_fini(dip);
31044961713Sgirish 		mutex_destroy(&niumxds_p->niumx_mutex);
31144961713Sgirish 		ddi_soft_state_free(niumx_state, ddi_get_instance(dip));
31244961713Sgirish 		return (DDI_SUCCESS);
31344961713Sgirish 
31444961713Sgirish 	case DDI_SUSPEND:
31544961713Sgirish 	default:
31644961713Sgirish 		break;
31744961713Sgirish 	}
31844961713Sgirish 	return (DDI_FAILURE);
31944961713Sgirish }
32044961713Sgirish 
3218fca0570Sjf 
3228fca0570Sjf /*
3238fca0570Sjf  * Function used to initialize FMA for our children nodes. Called
3248fca0570Sjf  * through pci busops when child node calls ddi_fm_init.
3258fca0570Sjf  */
3268fca0570Sjf /*ARGSUSED*/
3278fca0570Sjf int
3288fca0570Sjf niumx_fm_init_child(dev_info_t *dip, dev_info_t *cdip, int cap,
3298fca0570Sjf     ddi_iblock_cookie_t *ibc_p)
3308fca0570Sjf {
3318fca0570Sjf 	niumx_devstate_t	*niumxds_p = DIP_TO_STATE(dip);
3328fca0570Sjf 
3338fca0570Sjf 	ASSERT(ibc_p != NULL);
3348fca0570Sjf 	*ibc_p = niumxds_p->niumx_fm_ibc;
3358fca0570Sjf 
3368fca0570Sjf 	return (niumxds_p->niumx_fm_cap);
3378fca0570Sjf }
3388fca0570Sjf 
3398fca0570Sjf 
34044961713Sgirish /*ARGSUSED*/
34144961713Sgirish int
34244961713Sgirish niumx_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
34344961713Sgirish 	off_t offset, off_t len, caddr_t *vaddrp)
34444961713Sgirish {
34544961713Sgirish 	struct regspec p_regspec;
34644961713Sgirish 	ddi_map_req_t p_mapreq;
34744961713Sgirish 	niu_regspec_t	*reg_p;
34844961713Sgirish 	int 	i, rn = mp->map_obj.rnumber, reglen, rnglen, rngnum, ret;
34944961713Sgirish 	niumx_ranges_t	*rng_p;
35044961713Sgirish 
35144961713Sgirish 	uint32_t	reg_begin, rng_begin;
35244961713Sgirish 
35344961713Sgirish 	DBG(DBG_MAP, dip, "%s%d: mapping %s%d reg %d\n", NAMEINST(dip),
354adf6c93bSjf 	    NAMEINST(rdip), rn);
35544961713Sgirish 
35644961713Sgirish 	if (ddi_getlongprop(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS,
357adf6c93bSjf 	    "reg", (caddr_t)&reg_p, &reglen) != DDI_SUCCESS)
35844961713Sgirish 		return (DDI_FAILURE);
35944961713Sgirish 
36044961713Sgirish 	if (rn < 0 || (rn >= reglen / sizeof (niu_regspec_t))) {
36144961713Sgirish 		DBG(DBG_MAP, dip,  "rnumber out of range: %d\n", rn);
36244961713Sgirish 		kmem_free(reg_p, reglen);
36344961713Sgirish 		return (DDI_ME_RNUMBER_RANGE);
36444961713Sgirish 	}
36544961713Sgirish 
36644961713Sgirish 	/* build regspec up for parent */
36744961713Sgirish 	p_mapreq = *mp;		/* dup the whole structure */
36844961713Sgirish 	p_mapreq.map_type = DDI_MT_REGSPEC;
36944961713Sgirish 	p_mapreq.map_obj.rp = &p_regspec;
37044961713Sgirish 
37144961713Sgirish 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "ranges",
372adf6c93bSjf 	    (caddr_t)&rng_p, &rnglen) != DDI_SUCCESS) {
37344961713Sgirish 			DBG(DBG_MAP,  dip, "%s%d: no ranges property\n",
374adf6c93bSjf 			    ddi_driver_name(dip), ddi_get_instance(dip));
37544961713Sgirish 			kmem_free(reg_p, reglen);
37644961713Sgirish 			return (DDI_FAILURE);
37744961713Sgirish 	}
37844961713Sgirish 
37944961713Sgirish 	/* locate matching ranges record */
38044961713Sgirish 	rngnum = rnglen / sizeof (niumx_ranges_t);
38144961713Sgirish 	for (i = 0, reg_p += rn; i < rngnum; rng_p++, i++) {
38244961713Sgirish 		if (reg_p->addr_high == rng_p->child_hi)
38344961713Sgirish 			break;
38444961713Sgirish 	}
38544961713Sgirish 
38644961713Sgirish 	if (i >= rngnum) {
38744961713Sgirish 		DBG(DBG_MAP, dip, "ranges record for reg[%d] not found.\n", rn);
38844961713Sgirish 		ret = DDI_ME_REGSPEC_RANGE;
38944961713Sgirish 		goto err;
39044961713Sgirish 	}
39144961713Sgirish 
39244961713Sgirish 	/*
39344961713Sgirish 	 * validate request has matching bus type and within 4G
39444961713Sgirish 	 * limit by comparing addr.hi of "ranges" and child "reg".
39544961713Sgirish 	 */
39644961713Sgirish 
39744961713Sgirish 	ASSERT(reg_p->size_high == 0);
39844961713Sgirish 
39944961713Sgirish 	rng_begin = rng_p->child_lo;
40044961713Sgirish 	reg_begin = reg_p->addr_low;
40144961713Sgirish 	/* check to verify reg bounds are within rng bounds */
40244961713Sgirish 	if (reg_begin < rng_begin || (reg_begin + (reg_p->size_low - 1)) >
403adf6c93bSjf 	    (rng_begin + (rng_p->size_lo - 1))) {
40444961713Sgirish 		DBG(DBG_MAP, dip, "size out of range for reg[%d].\n", rn);
40544961713Sgirish 		ret = DDI_ME_REGSPEC_RANGE;
40644961713Sgirish 		goto err;
40744961713Sgirish 	}
40844961713Sgirish 
40944961713Sgirish 	p_regspec.regspec_bustype = rng_p->parent_hi;
41044961713Sgirish 	p_regspec.regspec_addr = reg_begin - rng_begin + rng_p->parent_lo;
41144961713Sgirish 	p_regspec.regspec_size = reg_p->size_low;
41244961713Sgirish 	DBG(DBG_MAP, dip, "regspec:bus,addr,size = (%x,%x,%x)\n",
413adf6c93bSjf 	    p_regspec.regspec_bustype, p_regspec.regspec_addr,
414adf6c93bSjf 	    p_regspec.regspec_size);
41544961713Sgirish 	ret = ddi_map(dip, &p_mapreq, 0, 0, vaddrp);
41644961713Sgirish 	DBG(DBG_MAP, dip, "niumx_map: ret %d.\n", ret);
41744961713Sgirish err:
41844961713Sgirish 	kmem_free(rng_p - i, rnglen);
41944961713Sgirish 	kmem_free(reg_p - rn, reglen);
42044961713Sgirish 	return (ret);
42144961713Sgirish }
42244961713Sgirish 
42344961713Sgirish /*
42444961713Sgirish  * niumx_ctlops
42544961713Sgirish  */
42644961713Sgirish int
42744961713Sgirish niumx_ctlops(dev_info_t *dip, dev_info_t *rdip,
42844961713Sgirish 	ddi_ctl_enum_t ctlop, void *arg, void *result)
42944961713Sgirish {
43044961713Sgirish 	niu_regspec_t *reg_p;
43144961713Sgirish 	int	reglen, totreg;
43244961713Sgirish 
43344961713Sgirish 	DBG(DBG_CTLOPS, dip, "niumx_ctlops ctlop=%d.\n", ctlop);
43444961713Sgirish 	if (rdip == (dev_info_t *)0)
43544961713Sgirish 		return (DDI_FAILURE);
43644961713Sgirish 
43744961713Sgirish 	switch (ctlop) {
43844961713Sgirish 	case DDI_CTLOPS_REPORTDEV:
43944961713Sgirish 		cmn_err(CE_NOTE, "device: %s@%s, %s%d\n",
44044961713Sgirish 		    ddi_node_name(rdip), ddi_get_name_addr(rdip),
44144961713Sgirish 		    NAMEINST(rdip));
44244961713Sgirish 		return (DDI_SUCCESS);
44344961713Sgirish 
44444961713Sgirish 	case DDI_CTLOPS_INITCHILD:
44544961713Sgirish 		return (niumx_initchild((dev_info_t *)arg));
44644961713Sgirish 
44744961713Sgirish 	case DDI_CTLOPS_UNINITCHILD:
44844961713Sgirish 		niumx_removechild((dev_info_t *)arg);
44944961713Sgirish 		return (DDI_SUCCESS);
45044961713Sgirish 
45144961713Sgirish 	case DDI_CTLOPS_REGSIZE:
45244961713Sgirish 	case DDI_CTLOPS_NREGS:
45344961713Sgirish 		/* fall through */
45444961713Sgirish 		break;
45544961713Sgirish 	default:
45644961713Sgirish 		DBG(DBG_CTLOPS, dip, "just pass to ddi_cltops.\n");
45744961713Sgirish 		return (ddi_ctlops(dip, rdip, ctlop, arg, result));
45844961713Sgirish 	}
45944961713Sgirish 
46044961713Sgirish 	/* REGSIZE/NREGS */
46144961713Sgirish 
46244961713Sgirish 	*(int *)result = 0;
46344961713Sgirish 
46444961713Sgirish 	if (ddi_getlongprop(DDI_DEV_T_NONE, rdip, DDI_PROP_DONTPASS |
465adf6c93bSjf 	    DDI_PROP_CANSLEEP, "reg", (caddr_t)&reg_p, &reglen) != DDI_SUCCESS)
46644961713Sgirish 		return (DDI_FAILURE);
46744961713Sgirish 
46844961713Sgirish 	totreg = reglen / sizeof (niu_regspec_t);
46944961713Sgirish 	if (ctlop == DDI_CTLOPS_NREGS) {
47044961713Sgirish 		DBG(DBG_CTLOPS, (dev_info_t *)dip, "niumx_ctlops NREGS=%d.\n",
471adf6c93bSjf 		    totreg);
47244961713Sgirish 		*(int *)result = totreg;
47344961713Sgirish 	} else if (ctlop == DDI_CTLOPS_REGSIZE) {
47444961713Sgirish 		int	rn;
47544961713Sgirish 		rn = *(int *)arg;
47644961713Sgirish 		if (rn >= totreg) {
47744961713Sgirish 			kmem_free(reg_p, reglen);
47844961713Sgirish 			return (DDI_FAILURE);
47944961713Sgirish 		}
48044961713Sgirish 		*(off_t *)result = (reg_p + rn)->size_low;
48144961713Sgirish 		DBG(DBG_CTLOPS, (dev_info_t *)dip, "rn = %d, REGSIZE=%x.\n",
482adf6c93bSjf 		    rn, *(off_t *)result);
48344961713Sgirish 	}
48444961713Sgirish 
48544961713Sgirish 	kmem_free(reg_p, reglen);
48644961713Sgirish 	return (DDI_SUCCESS);
48744961713Sgirish }
48844961713Sgirish 
489adf6c93bSjf /*
490adf6c93bSjf  * niumx_name_child
491adf6c93bSjf  *
492adf6c93bSjf  * This function is called from init_child to name a node. It is
493adf6c93bSjf  * also passed as a callback for node merging functions.
494adf6c93bSjf  *
495adf6c93bSjf  * return value: DDI_SUCCESS, DDI_FAILURE
496adf6c93bSjf  */
49744961713Sgirish static int
498adf6c93bSjf niumx_name_child(dev_info_t *child, char *name, int namelen)
49944961713Sgirish {
50044961713Sgirish 	niu_regspec_t *r;
50144961713Sgirish 	uint_t n;
50244961713Sgirish 
503adf6c93bSjf 	DBG(DBG_CHK_MOD, (dev_info_t *)child, "==> niumx_name_child\n");
504adf6c93bSjf 
505adf6c93bSjf 	if (ndi_dev_is_persistent_node(child) == 0) {
506adf6c93bSjf 		char **unit_addr;
507adf6c93bSjf 
508adf6c93bSjf 		/* name .conf nodes by "unit-address" property */
509adf6c93bSjf 		if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, child,
510adf6c93bSjf 		    DDI_PROP_DONTPASS, "unit-address", &unit_addr, &n) !=
511adf6c93bSjf 		    DDI_PROP_SUCCESS) {
512adf6c93bSjf 			cmn_err(CE_WARN, "cannot name node from %s.conf",
513adf6c93bSjf 			    ddi_driver_name(child));
514adf6c93bSjf 			return (DDI_FAILURE);
515adf6c93bSjf 		}
516adf6c93bSjf 		if (n != 1 || *unit_addr == NULL || **unit_addr == 0) {
517adf6c93bSjf 			cmn_err(CE_WARN, "unit-address property in %s.conf"
518adf6c93bSjf 			    " not well-formed", ddi_driver_name(child));
519adf6c93bSjf 			ddi_prop_free(unit_addr);
520adf6c93bSjf 			return (DDI_FAILURE);
521adf6c93bSjf 		}
522adf6c93bSjf 
523adf6c93bSjf 		(void) snprintf(name, namelen, "%s", *unit_addr);
524adf6c93bSjf 		ddi_prop_free(unit_addr);
525adf6c93bSjf 		return (DDI_SUCCESS);
526adf6c93bSjf 	}
527adf6c93bSjf 
528adf6c93bSjf 	/* name hardware nodes by "reg" property */
52944961713Sgirish 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
53044961713Sgirish 	    "reg", (int **)&r, &n) != DDI_SUCCESS) {
531adf6c93bSjf 		cmn_err(CE_WARN, "reg property not well-formed");
53244961713Sgirish 		return (DDI_FAILURE);
53344961713Sgirish 	}
534678453a8Sspeer 	(void) snprintf(name, namelen, "%x", (r[0].addr_high));
53544961713Sgirish 	ddi_prop_free(r);
536adf6c93bSjf 	return (DDI_SUCCESS);
537adf6c93bSjf }
538adf6c93bSjf 
539adf6c93bSjf static int
540adf6c93bSjf niumx_initchild(dev_info_t *child)
541adf6c93bSjf {
542adf6c93bSjf 	char name[MAXNAMELEN];
543adf6c93bSjf 
544adf6c93bSjf 	DBG(DBG_CHK_MOD, (dev_info_t *)child, "==> niumx_initchild\n");
545adf6c93bSjf 	/*
546adf6c93bSjf 	 * Non-peristent nodes indicate a prototype node with per-instance
547adf6c93bSjf 	 * properties to be merged into the real h/w device node.
548adf6c93bSjf 	 */
549adf6c93bSjf 	if (ndi_dev_is_persistent_node(child) == 0) {
550adf6c93bSjf 		niu_regspec_t *r;
551adf6c93bSjf 		uint_t n;
552adf6c93bSjf 
553adf6c93bSjf 		if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child,
554adf6c93bSjf 		    DDI_PROP_DONTPASS, "reg", (int **)&r, &n) ==
555adf6c93bSjf 		    DDI_SUCCESS) {
556adf6c93bSjf 			cmn_err(CE_WARN,
557adf6c93bSjf 			    "cannot merge prototype from %s.conf",
558adf6c93bSjf 			    ddi_driver_name(child));
559adf6c93bSjf 			ddi_prop_free(r);
560adf6c93bSjf 			return (DDI_NOT_WELL_FORMED);
561adf6c93bSjf 		}
562adf6c93bSjf 
563adf6c93bSjf 		if (niumx_name_child(child, name, MAXNAMELEN) != DDI_SUCCESS)
564adf6c93bSjf 			return (DDI_NOT_WELL_FORMED);
565adf6c93bSjf 
566adf6c93bSjf 		ddi_set_name_addr(child, name);
567adf6c93bSjf 		ddi_set_parent_data(child, NULL);
568adf6c93bSjf 
569adf6c93bSjf 		/*
570adf6c93bSjf 		 * Try to merge the properties from this prototype
571adf6c93bSjf 		 * node into real h/w nodes.
572adf6c93bSjf 		 */
573adf6c93bSjf 		if (ndi_merge_node(child, niumx_name_child) == DDI_SUCCESS) {
574adf6c93bSjf 			/*
575adf6c93bSjf 			 * Merged ok - return failure to remove the node.
576adf6c93bSjf 			 */
577adf6c93bSjf 			ddi_set_name_addr(child, NULL);
578adf6c93bSjf 			return (DDI_FAILURE);
579adf6c93bSjf 		}
580adf6c93bSjf 
581adf6c93bSjf 		/*
582adf6c93bSjf 		 * The child was not merged into a h/w node,
583adf6c93bSjf 		 * but there's not much we can do with it other
584adf6c93bSjf 		 * than return failure to cause the node to be removed.
585adf6c93bSjf 		 */
586adf6c93bSjf 		cmn_err(CE_WARN, "!%s@%s: %s.conf properties not merged",
587adf6c93bSjf 		    ddi_driver_name(child), ddi_get_name_addr(child),
588adf6c93bSjf 		    ddi_driver_name(child));
589adf6c93bSjf 		ddi_set_name_addr(child, NULL);
590adf6c93bSjf 		return (DDI_NOT_WELL_FORMED);
591adf6c93bSjf 	}
592adf6c93bSjf 
593adf6c93bSjf 	/*
594adf6c93bSjf 	 * Initialize real h/w nodes
595adf6c93bSjf 	 */
596adf6c93bSjf 	if (niumx_name_child(child, name, MAXNAMELEN) != DDI_SUCCESS)
597adf6c93bSjf 		return (DDI_FAILURE);
598adf6c93bSjf 
59944961713Sgirish 	ddi_set_name_addr(child, name);
60044961713Sgirish 	return (DDI_SUCCESS);
60144961713Sgirish }
60244961713Sgirish 
60344961713Sgirish static void
60444961713Sgirish niumx_removechild(dev_info_t *dip)
60544961713Sgirish {
60644961713Sgirish 	ddi_set_name_addr(dip, NULL);
60744961713Sgirish 	ddi_remove_minor_node(dip, NULL);
60844961713Sgirish 	impl_rem_dev_props(dip);
60944961713Sgirish }
61044961713Sgirish 
61144961713Sgirish 
61244961713Sgirish 
61344961713Sgirish /*
61444961713Sgirish  * bus dma alloc handle entry point:
61544961713Sgirish  */
61644961713Sgirish /*ARGSUSED*/
61744961713Sgirish int
61844961713Sgirish niumx_dma_allochdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_attr_t *attrp,
61944961713Sgirish 	int (*waitfp)(caddr_t), caddr_t arg, ddi_dma_handle_t *handlep)
62044961713Sgirish {
62144961713Sgirish 	ddi_dma_impl_t *mp;
62244961713Sgirish 	int sleep = (waitfp == DDI_DMA_SLEEP) ? KM_SLEEP : KM_NOSLEEP;
62344961713Sgirish 
62444961713Sgirish 	DBG(DBG_DMA_ALLOCH, dip, "rdip=%s%d\n", NAMEINST(rdip));
62544961713Sgirish 
62644961713Sgirish 	if (attrp->dma_attr_version != DMA_ATTR_V0) {
62744961713Sgirish 		DBG(DBG_DMA_ALLOCH, (dev_info_t *)dip, "DDI_DMA_BADATTR\n");
62844961713Sgirish 		return (DDI_DMA_BADATTR);
62944961713Sgirish 	}
63044961713Sgirish 
63144961713Sgirish 	/* Caution: we don't use zalloc to enhance performance! */
63244961713Sgirish 	if ((mp = kmem_alloc(sizeof (ddi_dma_impl_t), sleep)) == 0) {
63344961713Sgirish 		DBG(DBG_DMA_ALLOCH, dip, "can't alloc ddi_dma_impl_t\n");
63444961713Sgirish 		return (DDI_FAILURE);
63544961713Sgirish 	}
63644961713Sgirish 	mp->dmai_rdip = rdip;
63744961713Sgirish 	mp->dmai_pfnlst = NULL;
63844961713Sgirish 	mp->dmai_cookie = NULL;
63944961713Sgirish 	mp->dmai_fault = 0;
64044961713Sgirish 	mp->dmai_fault_check = NULL;
64144961713Sgirish 	mp->dmai_fault_notify = NULL;
64244961713Sgirish 
64344961713Sgirish 	mp->dmai_attr = *attrp; 	/* set requestors attr info */
64444961713Sgirish 
64544961713Sgirish 	DBG(DBG_DMA_ALLOCH, dip, "mp=%p\n", mp);
64644961713Sgirish 
64744961713Sgirish 	*handlep = (ddi_dma_handle_t)mp;
64844961713Sgirish 	return (DDI_SUCCESS);
64944961713Sgirish }
65044961713Sgirish 
65144961713Sgirish 
65244961713Sgirish /*
65344961713Sgirish  * bus dma free handle entry point:
65444961713Sgirish  */
65544961713Sgirish /*ARGSUSED*/
65644961713Sgirish int
65744961713Sgirish niumx_dma_freehdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t handle)
65844961713Sgirish {
65944961713Sgirish 	ddi_dma_impl_t *mp = (ddi_dma_impl_t *)handle;
66044961713Sgirish 
66144961713Sgirish 	if (mp->dmai_cookie)
66244961713Sgirish 		kmem_free(mp->dmai_cookie, sizeof (ddi_dma_cookie_t));
66344961713Sgirish 	kmem_free(mp, sizeof (ddi_dma_impl_t));
66444961713Sgirish 
66544961713Sgirish 	return (DDI_SUCCESS);
66644961713Sgirish }
66744961713Sgirish 
66844961713Sgirish 
66944961713Sgirish /*
67044961713Sgirish  * bus dma bind handle entry point:
67144961713Sgirish  *
67244961713Sgirish  *	check/enforce DMA type, setup pfn0 and some other key pieces
67344961713Sgirish  *	of this dma request.
67444961713Sgirish  * Note: this only works with DMA_OTYP_VADDR, and makes use of the known
67544961713Sgirish  *	fact that only contiguous memory blocks will be passed in.
67644961713Sgirish  *	Therefore only one cookie will ever be returned.
67744961713Sgirish  *
67844961713Sgirish  *	return values:
67944961713Sgirish  *		DDI_DMA_NOMAPPING - can't get valid pfn0, or bad dma type
68044961713Sgirish  *		DDI_DMA_NORESOURCES
68144961713Sgirish  *		DDI_SUCCESS
68244961713Sgirish  *
68344961713Sgirish  *	dma handle members affected (set on exit):
68444961713Sgirish  *	mp->dmai_object		- dmareq->dmar_object
68544961713Sgirish  *	mp->dmai_rflags		- dmareq->dmar_flags
68644961713Sgirish  *	mp->dmai_pfn0   	- 1st page pfn (if va/size pair and not shadow)
68744961713Sgirish  *	mp->dmai_roffset 	- initialized to starting page offset
68844961713Sgirish  *	mp->dmai_size		- # of total pages of entire object
68944961713Sgirish  *	mp->dmai_cookie		- new cookie alloc'd
69044961713Sgirish  */
69144961713Sgirish /*ARGSUSED*/
69244961713Sgirish int
69344961713Sgirish niumx_dma_bindhdl(dev_info_t *dip, dev_info_t *rdip,
69444961713Sgirish 	ddi_dma_handle_t handle, ddi_dma_req_t *dmareq,
69544961713Sgirish 	ddi_dma_cookie_t *cookiep, uint_t *ccountp)
69644961713Sgirish {
69744961713Sgirish 	int (*waitfp)(caddr_t) = dmareq->dmar_fp;
69844961713Sgirish 	ddi_dma_impl_t *mp = (ddi_dma_impl_t *)handle;
69944961713Sgirish 	ddi_dma_obj_t *dobj_p = &dmareq->dmar_object;
70044961713Sgirish 	uint32_t offset;
70144961713Sgirish 	pfn_t pfn0;
70244961713Sgirish 	int ret;
70344961713Sgirish 
70444961713Sgirish 	DBG(DBG_DMA_BINDH, dip, "rdip=%s%d mp=%p dmareq=%p\n", NAMEINST(rdip),
705adf6c93bSjf 	    mp, dmareq);
70644961713Sgirish 
70744961713Sgirish 	/* first check dma type */
70844961713Sgirish 	mp->dmai_rflags = dmareq->dmar_flags & DMP_DDIFLAGS | DMP_NOSYNC;
70944961713Sgirish 	switch (dobj_p->dmao_type) {
71044961713Sgirish 	case DMA_OTYP_VADDR: {
71144961713Sgirish 		caddr_t vaddr = dobj_p->dmao_obj.virt_obj.v_addr;
71244961713Sgirish 		struct as *as_p = dobj_p->dmao_obj.virt_obj.v_as;
71344961713Sgirish 		struct hat *hat_p = as_p ? as_p->a_hat : kas.a_hat;
71444961713Sgirish 		offset = (ulong_t)vaddr & NIUMX_PAGE_OFFSET;
71544961713Sgirish 		pfn0 = hat_getpfnum(hat_p, vaddr);
71644961713Sgirish 		}
71744961713Sgirish 		break;
71844961713Sgirish 
71944961713Sgirish 	case DMA_OTYP_BUFVADDR:
72044961713Sgirish 	case DMA_OTYP_PAGES:
72144961713Sgirish 	case DMA_OTYP_PADDR:
72244961713Sgirish 	default:
72344961713Sgirish 		cmn_err(CE_WARN, "%s%d requested unsupported dma type %x",
724adf6c93bSjf 		    NAMEINST(mp->dmai_rdip), dobj_p->dmao_type);
72544961713Sgirish 		ret = DDI_DMA_NOMAPPING;
72644961713Sgirish 		goto err;
72744961713Sgirish 	}
72844961713Sgirish 	if (pfn0 == PFN_INVALID) {
72944961713Sgirish 		cmn_err(CE_WARN, "%s%d: invalid pfn0 for DMA object %p",
730adf6c93bSjf 		    NAMEINST(dip), (void *)dobj_p);
73144961713Sgirish 		ret = DDI_DMA_NOMAPPING;
73244961713Sgirish 		goto err;
73344961713Sgirish 	}
73444961713Sgirish 	mp->dmai_object	 = *dobj_p;			/* whole object */
73544961713Sgirish 	mp->dmai_pfn0	 = (void *)pfn0;		/* cache pfn0   */
73644961713Sgirish 	mp->dmai_roffset = offset;			/* pg0 offset   */
73744961713Sgirish 	mp->dmai_mapping = mp->dmai_roffset | NIUMX_PTOB(pfn0);
73844961713Sgirish 	mp->dmai_size = mp->dmai_object.dmao_size;
73944961713Sgirish 
74044961713Sgirish 	DBG(DBG_DMA_BINDH, dip, "check pfn: mp=%p pfn0=%x\n",
741adf6c93bSjf 	    mp, mp->dmai_pfn0);
74244961713Sgirish 	if (!(mp->dmai_cookie = kmem_zalloc(sizeof (ddi_dma_cookie_t),
743adf6c93bSjf 	    waitfp == DDI_DMA_SLEEP ? KM_SLEEP : KM_NOSLEEP))) {
74444961713Sgirish 			ret = DDI_DMA_NORESOURCES;
74544961713Sgirish 			goto err;
74644961713Sgirish 		}
74744961713Sgirish 	mp->dmai_cookie->dmac_laddress = mp->dmai_mapping;
74844961713Sgirish 	mp->dmai_cookie->dmac_size = mp->dmai_size;
74944961713Sgirish 	*ccountp = 1;
75044961713Sgirish 	*cookiep = *mp->dmai_cookie;
75144961713Sgirish 	DBG(DBG_DMA_BINDH, dip, "cookie %" PRIx64 "+%x, count=%d\n",
752adf6c93bSjf 	    cookiep->dmac_address, cookiep->dmac_size, *ccountp);
75344961713Sgirish 	return (DDI_DMA_MAPPED);
75444961713Sgirish 
75544961713Sgirish err:
75644961713Sgirish 	DBG(DBG_DMA_BINDH, (dev_info_t *)dip,
757adf6c93bSjf 	    "niumx_dma_bindhdl error ret=%d\n", ret);
75844961713Sgirish 	return (ret);
75944961713Sgirish }
76044961713Sgirish 
76144961713Sgirish /*
76244961713Sgirish  * bus dma unbind handle entry point:
76344961713Sgirish  */
76444961713Sgirish /*ARGSUSED*/
76544961713Sgirish int
76644961713Sgirish niumx_dma_unbindhdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t handle)
76744961713Sgirish {
76844961713Sgirish 	ddi_dma_impl_t *mp = (ddi_dma_impl_t *)handle;
76944961713Sgirish 
77044961713Sgirish 	DBG(DBG_DMA_UNBINDH, dip, "rdip=%s%d, mp=%p\n",
771adf6c93bSjf 	    ddi_driver_name(rdip), ddi_get_instance(rdip), handle);
77244961713Sgirish 	if (mp->dmai_cookie) {
77344961713Sgirish 		kmem_free(mp->dmai_cookie, sizeof (ddi_dma_cookie_t));
77444961713Sgirish 		mp->dmai_cookie = NULL;
77544961713Sgirish 	}
77644961713Sgirish 
77744961713Sgirish 	return (DDI_SUCCESS);
77844961713Sgirish }
77944961713Sgirish 
78044961713Sgirish /*ARGSUSED*/
78144961713Sgirish int
78244961713Sgirish niumx_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
78344961713Sgirish     ddi_intr_handle_impl_t *hdlp, void *result)
78444961713Sgirish {
78544961713Sgirish 
78644961713Sgirish 	int	ret = DDI_SUCCESS;
78744961713Sgirish 
78844961713Sgirish 	DBG(DBG_INTROPS, dip, "niumx_intr_ops: dip=%p rdip=%p intr_op=%x "
78944961713Sgirish 	    "handle=%p\n", dip, rdip, intr_op, hdlp);
79044961713Sgirish 
79144961713Sgirish 	switch (intr_op) {
79244961713Sgirish 
79344961713Sgirish 	case DDI_INTROP_SUPPORTED_TYPES:
79444961713Sgirish 		*(int *)result = DDI_INTR_TYPE_FIXED;
79544961713Sgirish 		break;
79644961713Sgirish 	case DDI_INTROP_GETCAP:
79744961713Sgirish 		*(int *)result =  DDI_INTR_FLAG_LEVEL;
79844961713Sgirish 		break;
79944961713Sgirish 	case DDI_INTROP_SETCAP:
80044961713Sgirish 		ret = DDI_ENOTSUP;
80144961713Sgirish 		break;
80244961713Sgirish 	case DDI_INTROP_ALLOC:
80344961713Sgirish 		/*  scratch1 = count,  # of intrs from DDI framework */
80444961713Sgirish 		*(int *)result = hdlp->ih_scratch1;
80544961713Sgirish 		break;
80644961713Sgirish 	case DDI_INTROP_FREE:
80744961713Sgirish 		/* Do we need to do anything here?  */
80844961713Sgirish 		break;
80944961713Sgirish 	case DDI_INTROP_GETPRI:
81044961713Sgirish 		*(int *)result = NIUMX_DEFAULT_PIL;
81144961713Sgirish 		break;
81244961713Sgirish 	case DDI_INTROP_SETPRI:
81344961713Sgirish 		ret = DDI_ENOTSUP;
81444961713Sgirish 		break;
81544961713Sgirish 	case DDI_INTROP_ADDISR:
81644961713Sgirish 		ret = niumx_add_intr(dip, rdip, hdlp);
81744961713Sgirish 		break;
81844961713Sgirish 	case DDI_INTROP_REMISR:
81944961713Sgirish 		ret = niumx_rem_intr(dip, rdip, hdlp);
82044961713Sgirish 		break;
82144961713Sgirish 	case DDI_INTROP_ENABLE:
82244961713Sgirish 		ret = niumx_set_intr(dip, rdip, hdlp, HV_INTR_VALID);
82344961713Sgirish 		break;
82444961713Sgirish 	case DDI_INTROP_DISABLE:
82544961713Sgirish 		ret = niumx_set_intr(dip, rdip, hdlp, HV_INTR_NOTVALID);
82644961713Sgirish 		break;
82744961713Sgirish 	case DDI_INTROP_SETMASK:
82844961713Sgirish 		ret = DDI_ENOTSUP;
82944961713Sgirish 		break;
83044961713Sgirish 	case DDI_INTROP_CLRMASK:
83144961713Sgirish 		ret = DDI_ENOTSUP;
83244961713Sgirish 		break;
83344961713Sgirish 	case DDI_INTROP_GETPENDING:
83444961713Sgirish 		ret = DDI_ENOTSUP;
83544961713Sgirish 		break;
83644961713Sgirish 	case DDI_INTROP_NINTRS:
83744961713Sgirish 	case DDI_INTROP_NAVAIL: {
83844961713Sgirish 		devino_t	*inos_p;
83944961713Sgirish 		int		inoslen;
84044961713Sgirish 		if (ddi_getlongprop(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS,
841adf6c93bSjf 		    "interrupts", (caddr_t)&inos_p, &inoslen)
842adf6c93bSjf 		    != DDI_SUCCESS) {
843adf6c93bSjf 			ret = DDI_FAILURE;
844adf6c93bSjf 			break;
84544961713Sgirish 			}
84644961713Sgirish 		*(int *)result = inoslen / sizeof (uint32_t);
84744961713Sgirish 		kmem_free(inos_p, inoslen);
84844961713Sgirish 		}
84944961713Sgirish 		break;
85044961713Sgirish 	default:
85144961713Sgirish 		ret = DDI_ENOTSUP;
85244961713Sgirish 		break;
85344961713Sgirish 	}
85444961713Sgirish 
85544961713Sgirish 	DBG(DBG_INTROPS, dip, "niumx_intr_ops: ret=%d\n", ret);
85644961713Sgirish 	return (ret);
85744961713Sgirish }
85844961713Sgirish 
85944961713Sgirish int
86044961713Sgirish niumx_set_intr(dev_info_t *dip, dev_info_t *rdip,
86144961713Sgirish     ddi_intr_handle_impl_t *hdlp, int valid)
86244961713Sgirish {
86344961713Sgirish 	niumx_ih_t	*ih_p;
86444961713Sgirish 	devino_t	*inos_p;
86544961713Sgirish 	int		inoslen, ret = DDI_SUCCESS;
86644961713Sgirish 	uint64_t	hvret;
867*4df55fdeSJanie Lu 	niumx_devstate_t	*niumxds_p;	/* devstate pointer */
868*4df55fdeSJanie Lu 	int 		instance = ddi_get_instance(dip);
869*4df55fdeSJanie Lu 
870*4df55fdeSJanie Lu 	niumxds_p = (niumx_devstate_t *)ddi_get_soft_state(niumx_state,
871*4df55fdeSJanie Lu 	    instance);
87244961713Sgirish 
87344961713Sgirish 	ASSERT(hdlp->ih_inum < NIUMX_MAX_INTRS);
87444961713Sgirish 
87544961713Sgirish 	/* find the appropriate slot from the fixed table */
87644961713Sgirish 	if (ddi_getlongprop(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS,
877adf6c93bSjf 	    "interrupts", (caddr_t)&inos_p, &inoslen) != DDI_SUCCESS) {
87844961713Sgirish 		ret = DDI_FAILURE;
87944961713Sgirish 		goto fail;
88044961713Sgirish 	}
881*4df55fdeSJanie Lu 
882*4df55fdeSJanie Lu 	ih_p = niumxds_p->niumx_ihtable + inos_p[hdlp->ih_inum];
8838fca0570Sjf 	DBG(DBG_A_INTX, dip, "niumx_set_intr: rdip=%s%d, valid=%d %s (%x,%x)\n",
884adf6c93bSjf 	    NAMEINST(rdip), valid, valid ? "enabling" : "disabling",
885adf6c93bSjf 	    ih_p->ih_inum, ih_p->ih_sysino);
88644961713Sgirish 
887cb343a2eSspeer 	if (valid == HV_INTR_VALID)
888cb343a2eSspeer 		(void) hvio_intr_setstate(ih_p->ih_sysino, HV_INTR_IDLE_STATE);
88944961713Sgirish 	if ((hvret = hvio_intr_setvalid(ih_p->ih_sysino, valid))
890adf6c93bSjf 	    != H_EOK) {
89144961713Sgirish 		DBG(DBG_A_INTX, dip, "hvio_intr_setvalid failed, ret 0x%x\n",
892adf6c93bSjf 		    hvret);
89344961713Sgirish 		ret = DDI_FAILURE;
89444961713Sgirish 	}
89544961713Sgirish 	kmem_free(inos_p, inoslen);
89644961713Sgirish fail:
89744961713Sgirish 	return (ret);
89844961713Sgirish }
89944961713Sgirish 
90044961713Sgirish 
90144961713Sgirish 
90244961713Sgirish /*
90344961713Sgirish  * niumx_add_intr:
90444961713Sgirish  *
905e778ae44SRaghuram Kothakota  * This function is called to register interrupts.
90644961713Sgirish  */
90744961713Sgirish int
90844961713Sgirish niumx_add_intr(dev_info_t *dip, dev_info_t *rdip,
90944961713Sgirish     ddi_intr_handle_impl_t *hdlp)
91044961713Sgirish {
91144961713Sgirish 	niumx_ih_t	*ih_p;
91244961713Sgirish 	int		inoslen, ret = DDI_SUCCESS;
91344961713Sgirish 	uint64_t	hvret;
9148fca0570Sjf 	devino_t	*inos_p, ino; /* INO numbers, from "interrupts" prop */
91544961713Sgirish 	sysino_t	sysino;
916*4df55fdeSJanie Lu 	niumx_devstate_t	*niumxds_p;	/* devstate pointer */
917*4df55fdeSJanie Lu 	int		instance = ddi_get_instance(dip);
918*4df55fdeSJanie Lu 
919*4df55fdeSJanie Lu 	niumxds_p = (niumx_devstate_t *)ddi_get_soft_state(niumx_state,
920*4df55fdeSJanie Lu 	    instance);
92144961713Sgirish 
92244961713Sgirish 	/* get new ino */
92344961713Sgirish 	if (hdlp->ih_inum >= NIUMX_MAX_INTRS) {
92444961713Sgirish 		DBG(DBG_INTR, dip, "error: inum %d out of range\n",
925adf6c93bSjf 		    hdlp->ih_inum);
92644961713Sgirish 		ret = DDI_FAILURE;
92744961713Sgirish 		goto done;
92844961713Sgirish 	}
92944961713Sgirish 	if (ddi_getlongprop(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS,
930adf6c93bSjf 	    "interrupts", (caddr_t)&inos_p, &inoslen) != DDI_SUCCESS) {
93144961713Sgirish 		ret = DDI_FAILURE;
93244961713Sgirish 		goto done;
93344961713Sgirish 	}
934*4df55fdeSJanie Lu 	ih_p = niumxds_p->niumx_ihtable + inos_p[hdlp->ih_inum];
9358fca0570Sjf 	ino = inos_p[hdlp->ih_inum];
93644961713Sgirish 	kmem_free(inos_p, inoslen);
9378fca0570Sjf 	if ((hvret = hvio_intr_devino_to_sysino(DIP_TO_HANDLE(dip), ino,
938adf6c93bSjf 	    &sysino)) != H_EOK) {
93944961713Sgirish 		DBG(DBG_INTR, dip, "hvio_intr_devino_to_sysino failed, "
940adf6c93bSjf 		    "ret 0x%x\n", hvret);
94144961713Sgirish 		ret = DDI_FAILURE;
94244961713Sgirish 		goto done;
94344961713Sgirish 	}
94444961713Sgirish 	ih_p->ih_sysino = sysino;
94544961713Sgirish 	ih_p->ih_dip = dip;
94644961713Sgirish 	ih_p->ih_inum = hdlp->ih_inum;
94744961713Sgirish 	ih_p->ih_hdlr = hdlp->ih_cb_func;
94844961713Sgirish 	ih_p->ih_arg1 = hdlp->ih_cb_arg1;
94944961713Sgirish 	ih_p->ih_arg2 = hdlp->ih_cb_arg2;
95044961713Sgirish 
95144961713Sgirish 	DBG(DBG_A_INTX, dip, "niumx_add_intr: rdip=%s%d inum=0x%x "
952adf6c93bSjf 	    "handler=%p arg1=%p arg2=%p, new ih_p = %p\n", NAMEINST(rdip),
953adf6c93bSjf 	    hdlp->ih_inum, hdlp->ih_cb_func, hdlp->ih_cb_arg1,
954adf6c93bSjf 	    hdlp->ih_cb_arg2, ih_p);
95544961713Sgirish 
95644961713Sgirish 	if (hdlp->ih_pri == 0)
95744961713Sgirish 		hdlp->ih_pri = NIUMX_DEFAULT_PIL;
95844961713Sgirish 
95944961713Sgirish 	/* Save sysino value in hdlp */
96044961713Sgirish 	hdlp->ih_vector = ih_p->ih_sysino;
96144961713Sgirish 
96244961713Sgirish 	/* swap in our handler & arg */
96344961713Sgirish 	DDI_INTR_ASSIGN_HDLR_N_ARGS(hdlp, (ddi_intr_handler_t *)niumx_intr_hdlr,
964adf6c93bSjf 	    (void *)ih_p, NULL);
96544961713Sgirish 
9668fca0570Sjf 	DBG(DBG_A_INTX, dip, "for ino %x adding (%x,%x)\n", ino, ih_p->ih_inum,
967adf6c93bSjf 	    ih_p->ih_sysino);
96844961713Sgirish 	ret = i_ddi_add_ivintr(hdlp);
96944961713Sgirish 
97044961713Sgirish 	/* Restore orig. interrupt handler & args in handle. */
97144961713Sgirish 	DDI_INTR_ASSIGN_HDLR_N_ARGS(hdlp, ih_p->ih_hdlr, ih_p->ih_arg1,
972adf6c93bSjf 	    ih_p->ih_arg2);
97344961713Sgirish 
97444961713Sgirish 	if (ret != DDI_SUCCESS) {
97544961713Sgirish 		DBG(DBG_A_INTX, dip, "i_ddi_add_ivintr error ret=%x\n", ret);
97644961713Sgirish 		goto done;
97744961713Sgirish 	}
97844961713Sgirish 
97944961713Sgirish 	/* select cpu, saving it for removal */
98044961713Sgirish 	ih_p->ih_cpuid = intr_dist_cpuid();
98144961713Sgirish 
98244961713Sgirish 	if ((hvret = hvio_intr_settarget(ih_p->ih_sysino, ih_p->ih_cpuid))
983adf6c93bSjf 	    != H_EOK) {
98444961713Sgirish 		DBG(DBG_A_INTX, dip, "hvio_intr_settarget failed, ret 0x%x\n",
985adf6c93bSjf 		    hvret);
98644961713Sgirish 		ret = DDI_FAILURE;
98744961713Sgirish 	}
98844961713Sgirish done:
98944961713Sgirish 	DBG(DBG_A_INTX, dip, "done, ret = %d, ih_p 0x%p, hdlp 0x%p\n", ih_p,
990adf6c93bSjf 	    hdlp, ret);
99144961713Sgirish 	return (ret);
99244961713Sgirish }
99344961713Sgirish 
99444961713Sgirish /*
99544961713Sgirish  * niumx_rem_intr:
99644961713Sgirish  *
99744961713Sgirish  * This function is called to unregister interrupts.
99844961713Sgirish  */
99944961713Sgirish int
100044961713Sgirish niumx_rem_intr(dev_info_t *dip, dev_info_t *rdip,
100144961713Sgirish     ddi_intr_handle_impl_t *hdlp)
100244961713Sgirish {
100344961713Sgirish 	niumx_ih_t	*ih_p;
100444961713Sgirish 	devino_t	*inos_p;
1005c165966dSjf 	int		inoslen, ret = DDI_SUCCESS, state;
1006c165966dSjf 	hrtime_t	start;
1007c165966dSjf 	sysino_t 	sysino;
1008*4df55fdeSJanie Lu 	niumx_devstate_t	*niumxds_p;	/* devstate pointer */
1009*4df55fdeSJanie Lu 	int		instance = ddi_get_instance(dip);
1010*4df55fdeSJanie Lu 
1011*4df55fdeSJanie Lu 	niumxds_p = (niumx_devstate_t *)ddi_get_soft_state(niumx_state,
1012*4df55fdeSJanie Lu 	    instance);
101344961713Sgirish 
101444961713Sgirish 	ASSERT(hdlp->ih_inum < NIUMX_MAX_INTRS);
101544961713Sgirish 
101644961713Sgirish 	/* find the appropriate slot from the fixed table */
101744961713Sgirish 	if (ddi_getlongprop(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS,
1018adf6c93bSjf 	    "interrupts", (caddr_t)&inos_p, &inoslen) != DDI_SUCCESS) {
101944961713Sgirish 		ret = DDI_FAILURE;
102044961713Sgirish 		goto fail1;
102144961713Sgirish 	}
1022*4df55fdeSJanie Lu 	ih_p = niumxds_p->niumx_ihtable + inos_p[hdlp->ih_inum];
1023c165966dSjf 	sysino = ih_p->ih_sysino;
1024c165966dSjf 	DBG(DBG_R_INTX, dip, "removing (%x,%x)\n", ih_p->ih_inum, sysino);
1025c165966dSjf 
1026c165966dSjf 	(void) hvio_intr_setvalid(sysino, HV_INTR_NOTVALID);
1027c165966dSjf 
1028c165966dSjf 	/* check for pending interrupts, busy wait if so */
1029c165966dSjf 	for (start = gethrtime(); !panicstr &&
1030c165966dSjf 	    (hvio_intr_getstate(sysino, &state) == H_EOK) &&
1031c165966dSjf 	    (state == HV_INTR_DELIVERED_STATE); /* */) {
1032c165966dSjf 		if (gethrtime() - start > niumx_intr_timeout) {
1033c165966dSjf 			cmn_err(CE_WARN, "%s%d: niumx_intr_dist: "
1034c165966dSjf 			    "pending interrupt (%x,%lx) timedout\n",
1035c165966dSjf 			    ddi_driver_name(dip), ddi_get_instance(dip),
1036c165966dSjf 			    ih_p->ih_inum, sysino);
1037c165966dSjf 			ret = DDI_FAILURE;
1038c165966dSjf 			goto fail2;
1039c165966dSjf 		}
104044961713Sgirish 	}
104144961713Sgirish 
1042678453a8Sspeer 	ih_p->ih_sysino = 0;
1043678453a8Sspeer 
1044c165966dSjf 	hdlp->ih_vector = (uint32_t)sysino;
104544961713Sgirish 	if (hdlp->ih_vector !=  NULL) i_ddi_rem_ivintr(hdlp);
104644961713Sgirish 
104744961713Sgirish fail2:
104844961713Sgirish 	kmem_free(inos_p, inoslen);
104944961713Sgirish fail1:
105044961713Sgirish 	return (ret);
105144961713Sgirish }
105244961713Sgirish 
105344961713Sgirish /*
105444961713Sgirish  * niumx_intr_hdlr (our interrupt handler)
105544961713Sgirish  */
105644961713Sgirish uint_t
105744961713Sgirish niumx_intr_hdlr(void *arg)
105844961713Sgirish {
105944961713Sgirish 	niumx_ih_t *ih_p = (niumx_ih_t *)arg;
106044961713Sgirish 	uint_t		r;
106144961713Sgirish 
106244961713Sgirish 	DTRACE_PROBE4(interrupt__start, dev_info_t, ih_p->ih_dip, void *,
1063adf6c93bSjf 	    ih_p->ih_hdlr, caddr_t, ih_p->ih_arg1, caddr_t, ih_p->ih_arg2);
106444961713Sgirish 
106544961713Sgirish 	r = (*ih_p->ih_hdlr)(ih_p->ih_arg1, ih_p->ih_arg2);
106644961713Sgirish 
106744961713Sgirish 	DTRACE_PROBE4(interrupt__complete, dev_info_t, ih_p->ih_dip, void *,
1068adf6c93bSjf 	    ih_p->ih_hdlr, caddr_t, ih_p->ih_arg1, int, r);
1069cb343a2eSspeer 
1070cb343a2eSspeer 	(void) hvio_intr_setstate(ih_p->ih_sysino, HV_INTR_IDLE_STATE);
107144961713Sgirish 	return (r);
107244961713Sgirish }
107344961713Sgirish 
107444961713Sgirish #ifdef	DEBUG
107544961713Sgirish uint64_t niumx_debug_flags = 0;
107644961713Sgirish 
107744961713Sgirish static char *niumx_debug_sym [] = {	/* same sequence as niumx_debug_bit */
107844961713Sgirish 	/*  0 */ "attach",
107944961713Sgirish 	/*  1 */ "map",
108044961713Sgirish 	/*  2 */ "nex-ctlops",
108144961713Sgirish 	/*  3 */ "introps",
108244961713Sgirish 	/*  4 */ "intr-add",
108344961713Sgirish 	/*  5 */ "intr-rem",
108444961713Sgirish 	/*  6 */ "intr",
108544961713Sgirish 	/*  7 */ "dma-alloc",
108644961713Sgirish 	/*  8 */ "dma-bind",
108744961713Sgirish 	/*  9 */ "dma-unbind",
108844961713Sgirish 	/* 10 */ "chk-dma-mode"
108944961713Sgirish };
109044961713Sgirish 
109144961713Sgirish /*ARGSUSED*/
109244961713Sgirish void
109344961713Sgirish niumx_dbg(niumx_debug_bit_t bit, dev_info_t *dip, char *fmt, ...)
109444961713Sgirish {
109544961713Sgirish 	va_list ap;
109644961713Sgirish 	char msgbuf[1024];
109744961713Sgirish 
109844961713Sgirish 	if (!(1ull << bit & niumx_debug_flags))
109944961713Sgirish 		return;
110044961713Sgirish 	va_start(ap, fmt);
110144961713Sgirish 	(void) vsprintf(msgbuf, fmt, ap);
110244961713Sgirish 	va_end(ap);
110344961713Sgirish 	cmn_err(CE_NOTE, "%s: %s", niumx_debug_sym[bit], msgbuf);
110444961713Sgirish }
110544961713Sgirish 
110644961713Sgirish #endif	/* DEBUG */
1107