xref: /illumos-gate/usr/src/uts/sun4v/io/niumx/niumx.c (revision 1577b7ba)
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 /*
22657f87deSgongtian zhao - Sun Microsystems - Beijing China  * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
2344961713Sgirish  */
2444961713Sgirish 
2544961713Sgirish 
2644961713Sgirish /*
2744961713Sgirish  *	Niagara2 Network Interface Unit (NIU) Nexus Driver
2844961713Sgirish  */
2944961713Sgirish 
3044961713Sgirish #include <sys/conf.h>
3144961713Sgirish #include <sys/modctl.h>
3244961713Sgirish #include <sys/ddi_impldefs.h>
3344961713Sgirish #include <sys/ddi_subrdefs.h>
3444961713Sgirish #include <sys/ddi.h>
3544961713Sgirish #include <sys/sunndi.h>
3644961713Sgirish #include <sys/sunddi.h>
3744961713Sgirish #include <sys/open.h>
3844961713Sgirish #include <sys/stat.h>
3944961713Sgirish #include <sys/file.h>
4044961713Sgirish #include <sys/machsystm.h>
4144961713Sgirish #include <sys/hsvc.h>
4244961713Sgirish #include <sys/sdt.h>
4344961713Sgirish #include <sys/hypervisor_api.h>
44500b1e78SAlan Adamson, SD OSSD #include <sys/cpuvar.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 
75500b1e78SAlan Adamson, SD OSSD int niumxtool_init(dev_info_t *dip);
762de7adabSAlan Adamson, SD OSSD void niumxtool_uninit(dev_info_t *dip);
77500b1e78SAlan Adamson, SD OSSD 
78500b1e78SAlan Adamson, SD OSSD int niumx_get_intr_target(niumx_devstate_t *niumxds_p, niudevino_t ino,
79500b1e78SAlan Adamson, SD OSSD     niucpuid_t *cpu_id);
80500b1e78SAlan Adamson, SD OSSD int niumx_set_intr_target(niumx_devstate_t *niumxds_p, niudevino_t ino,
81500b1e78SAlan Adamson, SD OSSD     niucpuid_t cpu_id);
82500b1e78SAlan Adamson, SD OSSD 
8344961713Sgirish static struct bus_ops niumx_bus_ops = {
8444961713Sgirish 	BUSO_REV,
8544961713Sgirish 	niumx_map,
8644961713Sgirish 	0,
8744961713Sgirish 	0,
8844961713Sgirish 	0,
8944961713Sgirish 	i_ddi_map_fault,
9044961713Sgirish 	0,
9144961713Sgirish 	niumx_dma_allochdl,
9244961713Sgirish 	niumx_dma_freehdl,
9344961713Sgirish 	niumx_dma_bindhdl,
9444961713Sgirish 	niumx_dma_unbindhdl,
9544961713Sgirish 	0,
9644961713Sgirish 	0,
9744961713Sgirish 	0,
9844961713Sgirish 	niumx_ctlops,
9944961713Sgirish 	ddi_bus_prop_op,
100*1577b7baSToomas Soome 	0,				/* (*bus_get_eventcookie)();	*/
10144961713Sgirish 	0,				/* (*bus_add_eventcall)();	*/
102*1577b7baSToomas Soome 	0,				/* (*bus_remove_eventcall)();	*/
10344961713Sgirish 	0,				/* (*bus_post_event)();		*/
10444961713Sgirish 	0,				/* (*bus_intr_ctl)();		*/
105*1577b7baSToomas Soome 	0,				/* (*bus_config)();		*/
106*1577b7baSToomas Soome 	0,				/* (*bus_unconfig)();		*/
107*1577b7baSToomas Soome 	niumx_fm_init_child,		/* (*bus_fm_init)();		*/
108*1577b7baSToomas Soome 	0,				/* (*bus_fm_fini)();		*/
10944961713Sgirish 	0,				/* (*bus_enter)()		*/
11044961713Sgirish 	0,				/* (*bus_exit)()		*/
11144961713Sgirish 	0,				/* (*bus_power)()		*/
112*1577b7baSToomas Soome 	niumx_intr_ops			/* (*bus_intr_op)();		*/
11344961713Sgirish };
11444961713Sgirish 
115500b1e78SAlan Adamson, SD OSSD extern  struct cb_ops niumx_cb_ops;
116500b1e78SAlan Adamson, SD OSSD 
11744961713Sgirish static struct dev_ops niumx_ops = {
11844961713Sgirish 	DEVO_REV,		/* devo_rev */
11944961713Sgirish 	0,			/* refcnt  */
12044961713Sgirish 	ddi_no_info,		/* info */
12144961713Sgirish 	nulldev,		/* identify */
12244961713Sgirish 	0,			/* probe */
12344961713Sgirish 	niumx_attach,		/* attach */
12444961713Sgirish 	niumx_detach,		/* detach */
12544961713Sgirish 	nulldev,		/* reset */
126500b1e78SAlan Adamson, SD OSSD 	&niumx_cb_ops,		/* driver operations */
12744961713Sgirish 	&niumx_bus_ops,		/* bus operations */
12819397407SSherry Moore 	0,			/* power */
12919397407SSherry Moore 	ddi_quiesce_not_supported,	/* devo_quiesce */
13044961713Sgirish };
13144961713Sgirish 
13244961713Sgirish /* Module linkage information for the kernel. */
13344961713Sgirish static struct modldrv modldrv = {
13444961713Sgirish 	&mod_driverops, /* Type of module */
13519397407SSherry Moore 	"NIU Nexus Driver",
13644961713Sgirish 	&niumx_ops,	/* driver ops */
13744961713Sgirish };
13844961713Sgirish 
13944961713Sgirish static struct modlinkage modlinkage = {
14044961713Sgirish 	MODREV_1,
14144961713Sgirish 	(void *)&modldrv,
14244961713Sgirish 	NULL
14344961713Sgirish };
14444961713Sgirish 
145500b1e78SAlan Adamson, SD OSSD void *niumx_state;
14644961713Sgirish 
14744961713Sgirish /*
14844961713Sgirish  * forward function declarations:
14944961713Sgirish  */
15044961713Sgirish static void niumx_removechild(dev_info_t *);
15144961713Sgirish static int niumx_initchild(dev_info_t *child);
15244961713Sgirish 
15344961713Sgirish int
_init(void)15444961713Sgirish _init(void)
15544961713Sgirish {
15644961713Sgirish 	int e;
157d66f8315Sjb 	uint64_t mjrnum;
158d66f8315Sjb 	uint64_t mnrnum;
159d66f8315Sjb 
160d66f8315Sjb 	/*
161d66f8315Sjb 	 * Check HV intr group api versioning.
162d66f8315Sjb 	 * This driver uses the old interrupt routines which are supported
163d66f8315Sjb 	 * in old firmware in the CORE API group and in newer firmware in
164d66f8315Sjb 	 * the INTR API group.  Support for these calls will be dropped
165d66f8315Sjb 	 * once the INTR API group major goes to 2.
166d66f8315Sjb 	 */
167d66f8315Sjb 	if ((hsvc_version(HSVC_GROUP_INTR, &mjrnum, &mnrnum) == 0) &&
168d66f8315Sjb 	    (mjrnum > NIUMX_INTR_MAJOR_VER)) {
169d66f8315Sjb 		cmn_err(CE_WARN, "niumx: unsupported intr api group: "
170d66f8315Sjb 		    "maj:0x%lx, min:0x%lx", mjrnum, mnrnum);
171d66f8315Sjb 		return (ENOTSUP);
172d66f8315Sjb 	}
173d66f8315Sjb 
17444961713Sgirish 	if ((e = ddi_soft_state_init(&niumx_state, sizeof (niumx_devstate_t),
17544961713Sgirish 	    1)) == 0 && (e = mod_install(&modlinkage)) != 0)
17644961713Sgirish 		ddi_soft_state_fini(&niumx_state);
17744961713Sgirish 	return (e);
17844961713Sgirish }
17944961713Sgirish 
18044961713Sgirish int
_fini(void)18144961713Sgirish _fini(void)
18244961713Sgirish {
18344961713Sgirish 	int e;
18444961713Sgirish 	if ((e = mod_remove(&modlinkage)) == 0)
18544961713Sgirish 		ddi_soft_state_fini(&niumx_state);
18644961713Sgirish 	return (e);
18744961713Sgirish }
18844961713Sgirish 
18944961713Sgirish int
_info(struct modinfo * modinfop)19044961713Sgirish _info(struct modinfo *modinfop)
19144961713Sgirish {
19244961713Sgirish 	return (mod_info(&modlinkage, modinfop));
19344961713Sgirish }
19444961713Sgirish 
195c165966dSjf 
196c165966dSjf hrtime_t niumx_intr_timeout = 2ull * NANOSEC; /* 2 seconds in nanoseconds */
197c165966dSjf 
1983266dff7Sjf void
niumx_intr_dist(void * arg)1993266dff7Sjf niumx_intr_dist(void *arg)
2003266dff7Sjf {
2014df55fdeSJanie Lu 	niumx_devstate_t	*niumxds_p = (niumx_devstate_t *)arg;
202*1577b7baSToomas Soome 	kmutex_t	*lock_p = &niumxds_p->niumx_mutex;
203e778ae44SRaghuram Kothakota 	int		i;
2044df55fdeSJanie Lu 	niumx_ih_t	*ih_p = niumxds_p->niumx_ihtable;
2053266dff7Sjf 
206500b1e78SAlan Adamson, SD OSSD 	DBG(NIUMX_DBG_A_INTX, NULL, "niumx_intr_dist entered\n");
2073266dff7Sjf 	mutex_enter(lock_p);
208e778ae44SRaghuram Kothakota 	for (i = 0; i < NIUMX_MAX_INTRS; i++, ih_p++) {
209500b1e78SAlan Adamson, SD OSSD 		niusysino_t sysino = ih_p->ih_sysino;
210500b1e78SAlan Adamson, SD OSSD 		niucpuid_t	cpuid;
211500b1e78SAlan Adamson, SD OSSD 		int		state;
212c165966dSjf 		hrtime_t	start;
213c165966dSjf 		dev_info_t	*dip = ih_p->ih_dip;
214500b1e78SAlan Adamson, SD OSSD 
215500b1e78SAlan Adamson, SD OSSD 		if (!sysino || (cpuid = intr_dist_cpuid()) == ih_p->ih_cpuid)
2163266dff7Sjf 			continue;
2173266dff7Sjf 
2183266dff7Sjf 		(void) hvio_intr_setvalid(sysino, HV_INTR_NOTVALID);
219c165966dSjf 
220c165966dSjf 		/* check for pending interrupts, busy wait if so */
221c165966dSjf 		for (start = gethrtime(); !panicstr &&
222c165966dSjf 		    (hvio_intr_getstate(sysino, &state) == H_EOK) &&
223c165966dSjf 		    (state == HV_INTR_DELIVERED_STATE); /* */) {
224c165966dSjf 			if (gethrtime() - start > niumx_intr_timeout) {
225c165966dSjf 				cmn_err(CE_WARN, "%s%d: niumx_intr_dist: "
226c165966dSjf 				    "pending interrupt (%x,%lx) timedout\n",
227c165966dSjf 				    ddi_driver_name(dip), ddi_get_instance(dip),
228c165966dSjf 				    ih_p->ih_inum, sysino);
229c165966dSjf 				(void) hvio_intr_setstate(sysino,
230adf6c93bSjf 				    HV_INTR_IDLE_STATE);
231c165966dSjf 				break;
232c165966dSjf 			}
233c165966dSjf 		}
2343266dff7Sjf 		(void) hvio_intr_settarget(sysino, cpuid);
235500b1e78SAlan Adamson, SD OSSD 
236500b1e78SAlan Adamson, SD OSSD 		if (ih_p->ih_state == HV_INTR_VALID)
237500b1e78SAlan Adamson, SD OSSD 			(void) hvio_intr_setvalid(sysino, HV_INTR_VALID);
238500b1e78SAlan Adamson, SD OSSD 		else
239500b1e78SAlan Adamson, SD OSSD 			(void) hvio_intr_setvalid(sysino, HV_INTR_NOTVALID);
240500b1e78SAlan Adamson, SD OSSD 
2413266dff7Sjf 		ih_p->ih_cpuid = cpuid;
2423266dff7Sjf 	}
2433266dff7Sjf 	mutex_exit(lock_p);
2443266dff7Sjf }
24544961713Sgirish 
24644961713Sgirish static int
niumx_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)24744961713Sgirish niumx_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
24844961713Sgirish {
24944961713Sgirish 	int instance = ddi_get_instance(dip);
25044961713Sgirish 	niumx_devstate_t *niumxds_p;	/* devstate pointer */
25144961713Sgirish 	niu_regspec_t	*reg_p;
252500b1e78SAlan Adamson, SD OSSD 	niumx_ih_t	*ih_p;
25344961713Sgirish 	uint_t		reglen;
254500b1e78SAlan Adamson, SD OSSD 	int		i, ret = DDI_SUCCESS;
25544961713Sgirish 
25644961713Sgirish 	switch (cmd) {
25744961713Sgirish 	case DDI_ATTACH:
25844961713Sgirish 		if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip,
259adf6c93bSjf 		    DDI_PROP_DONTPASS, "reg", (int **)&reg_p, &reglen)
260adf6c93bSjf 		    != DDI_PROP_SUCCESS) {
261500b1e78SAlan Adamson, SD OSSD 			DBG(NIUMX_DBG_ATTACH, dip, "reg lookup failed\n");
26244961713Sgirish 			ret = DDI_FAILURE;
26344961713Sgirish 			goto done;
26444961713Sgirish 		}
26544961713Sgirish 
26644961713Sgirish 		/*
26744961713Sgirish 		 * Allocate and get soft state structure.
26844961713Sgirish 		 */
26944961713Sgirish 		if (ddi_soft_state_zalloc(niumx_state, instance)
270adf6c93bSjf 		    != DDI_SUCCESS) {
27144961713Sgirish 			ret = DDI_FAILURE;
27244961713Sgirish 			goto prop_free;
27344961713Sgirish 		}
27444961713Sgirish 		niumxds_p = (niumx_devstate_t *)ddi_get_soft_state(niumx_state,
275adf6c93bSjf 		    instance);
27644961713Sgirish 		niumxds_p->dip = dip;
277500b1e78SAlan Adamson, SD OSSD 		niumxds_p->niumx_open_count = 0;
27844961713Sgirish 		mutex_init(&niumxds_p->niumx_mutex, NULL, MUTEX_DRIVER, NULL);
27944961713Sgirish 
280500b1e78SAlan Adamson, SD OSSD 		DBG(NIUMX_DBG_ATTACH, dip, "soft state alloc'd instance = %d, "
281adf6c93bSjf 		    "niumxds_p = %p\n", instance, niumxds_p);
28244961713Sgirish 
28344961713Sgirish 		/* hv devhdl: low 28-bit of 1st "reg" entry's addr.hi */
284500b1e78SAlan Adamson, SD OSSD 		niumxds_p->niumx_dev_hdl = (niudevhandle_t)(reg_p->addr_high &
285adf6c93bSjf 		    NIUMX_DEVHDLE_MASK);
28644961713Sgirish 
287500b1e78SAlan Adamson, SD OSSD 		ih_p = niumxds_p->niumx_ihtable;
288500b1e78SAlan Adamson, SD OSSD 		for (i = 0; i < NIUMX_MAX_INTRS; i++, ih_p++) {
289500b1e78SAlan Adamson, SD OSSD 			ih_p->ih_sysino = 0;
290500b1e78SAlan Adamson, SD OSSD 			ih_p->ih_state = HV_INTR_NOTVALID;
291500b1e78SAlan Adamson, SD OSSD 		}
292500b1e78SAlan Adamson, SD OSSD 
2933266dff7Sjf 		/* add interrupt redistribution callback */
2944df55fdeSJanie Lu 		intr_dist_add(niumx_intr_dist, niumxds_p);
2953266dff7Sjf 
2968fca0570Sjf 		niumxds_p->niumx_fm_cap = DDI_FM_EREPORT_CAPABLE;
29714ea4bb7Ssd 
29814ea4bb7Ssd 		ddi_fm_init(niumxds_p->dip, &niumxds_p->niumx_fm_cap,
299adf6c93bSjf 		    &niumxds_p->niumx_fm_ibc);
30014ea4bb7Ssd 
301500b1e78SAlan Adamson, SD OSSD 		if (niumxtool_init(dip) != DDI_SUCCESS) {
302500b1e78SAlan Adamson, SD OSSD 			ret = DDI_FAILURE;
303500b1e78SAlan Adamson, SD OSSD 			goto cleanup;
304500b1e78SAlan Adamson, SD OSSD 		}
305500b1e78SAlan Adamson, SD OSSD 
30644961713Sgirish 		ret = DDI_SUCCESS;
30744961713Sgirish 		goto prop_free;
30844961713Sgirish cleanup:
30944961713Sgirish 		mutex_destroy(&niumxds_p->niumx_mutex);
31044961713Sgirish 		ddi_soft_state_free(niumx_state, ddi_get_instance(dip));
31144961713Sgirish prop_free:
31244961713Sgirish 		ddi_prop_free(reg_p);
31344961713Sgirish done:
31444961713Sgirish 		return (ret);
31544961713Sgirish 
31644961713Sgirish 	case DDI_RESUME:
31744961713Sgirish 	default:
31844961713Sgirish 		break;
31944961713Sgirish 	}
32044961713Sgirish 	return (ret);
32144961713Sgirish }
32244961713Sgirish 
32344961713Sgirish static int
niumx_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)32444961713Sgirish niumx_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
32544961713Sgirish {
32644961713Sgirish 	niumx_devstate_t *niumxds_p;
32744961713Sgirish 
32844961713Sgirish 	switch (cmd) {
32944961713Sgirish 	case DDI_DETACH:
33044961713Sgirish 
33144961713Sgirish 		niumxds_p = (niumx_devstate_t *)
33244961713Sgirish 		    ddi_get_soft_state(niumx_state, ddi_get_instance(dip));
33344961713Sgirish 
3344df55fdeSJanie Lu 		intr_dist_rem(niumx_intr_dist, niumxds_p);
33514ea4bb7Ssd 		ddi_fm_fini(dip);
336500b1e78SAlan Adamson, SD OSSD 		niumxtool_uninit(dip);
33744961713Sgirish 		mutex_destroy(&niumxds_p->niumx_mutex);
33844961713Sgirish 		ddi_soft_state_free(niumx_state, ddi_get_instance(dip));
33944961713Sgirish 		return (DDI_SUCCESS);
34044961713Sgirish 
34144961713Sgirish 	case DDI_SUSPEND:
34244961713Sgirish 	default:
34344961713Sgirish 		break;
34444961713Sgirish 	}
34544961713Sgirish 	return (DDI_FAILURE);
34644961713Sgirish }
34744961713Sgirish 
3488fca0570Sjf 
3498fca0570Sjf /*
3508fca0570Sjf  * Function used to initialize FMA for our children nodes. Called
3518fca0570Sjf  * through pci busops when child node calls ddi_fm_init.
3528fca0570Sjf  */
3538fca0570Sjf /*ARGSUSED*/
3548fca0570Sjf int
niumx_fm_init_child(dev_info_t * dip,dev_info_t * cdip,int cap,ddi_iblock_cookie_t * ibc_p)3558fca0570Sjf niumx_fm_init_child(dev_info_t *dip, dev_info_t *cdip, int cap,
3568fca0570Sjf     ddi_iblock_cookie_t *ibc_p)
3578fca0570Sjf {
358500b1e78SAlan Adamson, SD OSSD 	niumx_devstate_t	*niumxds_p = NIUMX_DIP_TO_STATE(dip);
3598fca0570Sjf 
3608fca0570Sjf 	ASSERT(ibc_p != NULL);
3618fca0570Sjf 	*ibc_p = niumxds_p->niumx_fm_ibc;
3628fca0570Sjf 
3638fca0570Sjf 	return (niumxds_p->niumx_fm_cap);
3648fca0570Sjf }
3658fca0570Sjf 
3668fca0570Sjf 
36744961713Sgirish /*ARGSUSED*/
36844961713Sgirish 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)36944961713Sgirish niumx_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
370*1577b7baSToomas Soome     off_t offset, off_t len, caddr_t *vaddrp)
37144961713Sgirish {
37244961713Sgirish 	struct regspec p_regspec;
37344961713Sgirish 	ddi_map_req_t p_mapreq;
374*1577b7baSToomas Soome 	niu_regspec_t *reg_p;
375*1577b7baSToomas Soome 	int i, rn = mp->map_obj.rnumber, reglen, rnglen, rngnum, ret;
376*1577b7baSToomas Soome 	niumx_ranges_t *rng_p;
37744961713Sgirish 
37844961713Sgirish 	uint32_t	reg_begin, rng_begin;
37944961713Sgirish 
380500b1e78SAlan Adamson, SD OSSD 	DBG(NIUMX_DBG_MAP, dip, "%s%d: mapping %s%d reg %d\n",
381500b1e78SAlan Adamson, SD OSSD 	    NIUMX_NAMEINST(dip), NIUMX_NAMEINST(rdip), rn);
38244961713Sgirish 
38344961713Sgirish 	if (ddi_getlongprop(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS,
384adf6c93bSjf 	    "reg", (caddr_t)&reg_p, &reglen) != DDI_SUCCESS)
38544961713Sgirish 		return (DDI_FAILURE);
38644961713Sgirish 
38744961713Sgirish 	if (rn < 0 || (rn >= reglen / sizeof (niu_regspec_t))) {
388500b1e78SAlan Adamson, SD OSSD 		DBG(NIUMX_DBG_MAP, dip,  "rnumber out of range: %d\n", rn);
38944961713Sgirish 		kmem_free(reg_p, reglen);
39044961713Sgirish 		return (DDI_ME_RNUMBER_RANGE);
39144961713Sgirish 	}
39244961713Sgirish 
39344961713Sgirish 	/* build regspec up for parent */
39444961713Sgirish 	p_mapreq = *mp;		/* dup the whole structure */
39544961713Sgirish 	p_mapreq.map_type = DDI_MT_REGSPEC;
39644961713Sgirish 	p_mapreq.map_obj.rp = &p_regspec;
39744961713Sgirish 
39844961713Sgirish 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "ranges",
399adf6c93bSjf 	    (caddr_t)&rng_p, &rnglen) != DDI_SUCCESS) {
400500b1e78SAlan Adamson, SD OSSD 			DBG(NIUMX_DBG_MAP,  dip, "%s%d: no ranges property\n",
401adf6c93bSjf 			    ddi_driver_name(dip), ddi_get_instance(dip));
40244961713Sgirish 			kmem_free(reg_p, reglen);
40344961713Sgirish 			return (DDI_FAILURE);
40444961713Sgirish 	}
40544961713Sgirish 
40644961713Sgirish 	/* locate matching ranges record */
40744961713Sgirish 	rngnum = rnglen / sizeof (niumx_ranges_t);
40844961713Sgirish 	for (i = 0, reg_p += rn; i < rngnum; rng_p++, i++) {
40944961713Sgirish 		if (reg_p->addr_high == rng_p->child_hi)
41044961713Sgirish 			break;
41144961713Sgirish 	}
41244961713Sgirish 
41344961713Sgirish 	if (i >= rngnum) {
414500b1e78SAlan Adamson, SD OSSD 		DBG(NIUMX_DBG_MAP, dip, "ranges record for reg[%d] "
415500b1e78SAlan Adamson, SD OSSD 		    "not found.\n", rn);
41644961713Sgirish 		ret = DDI_ME_REGSPEC_RANGE;
41744961713Sgirish 		goto err;
41844961713Sgirish 	}
41944961713Sgirish 
42044961713Sgirish 	/*
42144961713Sgirish 	 * validate request has matching bus type and within 4G
42244961713Sgirish 	 * limit by comparing addr.hi of "ranges" and child "reg".
42344961713Sgirish 	 */
42444961713Sgirish 
42544961713Sgirish 	ASSERT(reg_p->size_high == 0);
42644961713Sgirish 
42744961713Sgirish 	rng_begin = rng_p->child_lo;
42844961713Sgirish 	reg_begin = reg_p->addr_low;
42944961713Sgirish 	/* check to verify reg bounds are within rng bounds */
43044961713Sgirish 	if (reg_begin < rng_begin || (reg_begin + (reg_p->size_low - 1)) >
431adf6c93bSjf 	    (rng_begin + (rng_p->size_lo - 1))) {
432500b1e78SAlan Adamson, SD OSSD 		DBG(NIUMX_DBG_MAP, dip, "size out of range for reg[%d].\n", rn);
43344961713Sgirish 		ret = DDI_ME_REGSPEC_RANGE;
43444961713Sgirish 		goto err;
43544961713Sgirish 	}
43644961713Sgirish 
43744961713Sgirish 	p_regspec.regspec_bustype = rng_p->parent_hi;
43844961713Sgirish 	p_regspec.regspec_addr = reg_begin - rng_begin + rng_p->parent_lo;
43944961713Sgirish 	p_regspec.regspec_size = reg_p->size_low;
440500b1e78SAlan Adamson, SD OSSD 	DBG(NIUMX_DBG_MAP, dip, "regspec:bus,addr,size = (%x,%x,%x)\n",
441adf6c93bSjf 	    p_regspec.regspec_bustype, p_regspec.regspec_addr,
442adf6c93bSjf 	    p_regspec.regspec_size);
44344961713Sgirish 	ret = ddi_map(dip, &p_mapreq, 0, 0, vaddrp);
444500b1e78SAlan Adamson, SD OSSD 	DBG(NIUMX_DBG_MAP, dip, "niumx_map: ret %d.\n", ret);
44544961713Sgirish err:
44644961713Sgirish 	kmem_free(rng_p - i, rnglen);
44744961713Sgirish 	kmem_free(reg_p - rn, reglen);
44844961713Sgirish 	return (ret);
44944961713Sgirish }
45044961713Sgirish 
45144961713Sgirish /*
45244961713Sgirish  * niumx_ctlops
45344961713Sgirish  */
45444961713Sgirish int
niumx_ctlops(dev_info_t * dip,dev_info_t * rdip,ddi_ctl_enum_t ctlop,void * arg,void * result)45544961713Sgirish niumx_ctlops(dev_info_t *dip, dev_info_t *rdip,
456*1577b7baSToomas Soome     ddi_ctl_enum_t ctlop, void *arg, void *result)
45744961713Sgirish {
45844961713Sgirish 	niu_regspec_t *reg_p;
45944961713Sgirish 	int	reglen, totreg;
46044961713Sgirish 
461500b1e78SAlan Adamson, SD OSSD 	DBG(NIUMX_DBG_CTLOPS, dip, "niumx_ctlops ctlop=%d.\n", ctlop);
46244961713Sgirish 	if (rdip == (dev_info_t *)0)
46344961713Sgirish 		return (DDI_FAILURE);
46444961713Sgirish 
46544961713Sgirish 	switch (ctlop) {
46644961713Sgirish 	case DDI_CTLOPS_REPORTDEV:
46744961713Sgirish 		cmn_err(CE_NOTE, "device: %s@%s, %s%d\n",
46844961713Sgirish 		    ddi_node_name(rdip), ddi_get_name_addr(rdip),
469500b1e78SAlan Adamson, SD OSSD 		    NIUMX_NAMEINST(rdip));
47044961713Sgirish 		return (DDI_SUCCESS);
47144961713Sgirish 
47244961713Sgirish 	case DDI_CTLOPS_INITCHILD:
47344961713Sgirish 		return (niumx_initchild((dev_info_t *)arg));
47444961713Sgirish 
47544961713Sgirish 	case DDI_CTLOPS_UNINITCHILD:
47644961713Sgirish 		niumx_removechild((dev_info_t *)arg);
47744961713Sgirish 		return (DDI_SUCCESS);
47844961713Sgirish 
47944961713Sgirish 	case DDI_CTLOPS_REGSIZE:
48044961713Sgirish 	case DDI_CTLOPS_NREGS:
48144961713Sgirish 		/* fall through */
48244961713Sgirish 		break;
48344961713Sgirish 	default:
484500b1e78SAlan Adamson, SD OSSD 		DBG(NIUMX_DBG_CTLOPS, dip, "just pass to ddi_cltops.\n");
48544961713Sgirish 		return (ddi_ctlops(dip, rdip, ctlop, arg, result));
48644961713Sgirish 	}
48744961713Sgirish 
48844961713Sgirish 	/* REGSIZE/NREGS */
48944961713Sgirish 
49044961713Sgirish 	*(int *)result = 0;
49144961713Sgirish 
49244961713Sgirish 	if (ddi_getlongprop(DDI_DEV_T_NONE, rdip, DDI_PROP_DONTPASS |
493adf6c93bSjf 	    DDI_PROP_CANSLEEP, "reg", (caddr_t)&reg_p, &reglen) != DDI_SUCCESS)
49444961713Sgirish 		return (DDI_FAILURE);
49544961713Sgirish 
49644961713Sgirish 	totreg = reglen / sizeof (niu_regspec_t);
49744961713Sgirish 	if (ctlop == DDI_CTLOPS_NREGS) {
498500b1e78SAlan Adamson, SD OSSD 		DBG(NIUMX_DBG_CTLOPS, (dev_info_t *)dip,
499500b1e78SAlan Adamson, SD OSSD 		    "niumx_ctlops NREGS=%d.\n", totreg);
50044961713Sgirish 		*(int *)result = totreg;
50144961713Sgirish 	} else if (ctlop == DDI_CTLOPS_REGSIZE) {
50244961713Sgirish 		int	rn;
50344961713Sgirish 		rn = *(int *)arg;
50444961713Sgirish 		if (rn >= totreg) {
50544961713Sgirish 			kmem_free(reg_p, reglen);
50644961713Sgirish 			return (DDI_FAILURE);
50744961713Sgirish 		}
50844961713Sgirish 		*(off_t *)result = (reg_p + rn)->size_low;
509500b1e78SAlan Adamson, SD OSSD 		DBG(NIUMX_DBG_CTLOPS, (dev_info_t *)dip,
510500b1e78SAlan Adamson, SD OSSD 		    "rn = %d, REGSIZE=%x.\n", rn, *(off_t *)result);
51144961713Sgirish 	}
51244961713Sgirish 
51344961713Sgirish 	kmem_free(reg_p, reglen);
51444961713Sgirish 	return (DDI_SUCCESS);
51544961713Sgirish }
51644961713Sgirish 
517adf6c93bSjf /*
518adf6c93bSjf  * niumx_name_child
519adf6c93bSjf  *
520adf6c93bSjf  * This function is called from init_child to name a node. It is
521adf6c93bSjf  * also passed as a callback for node merging functions.
522adf6c93bSjf  *
523adf6c93bSjf  * return value: DDI_SUCCESS, DDI_FAILURE
524adf6c93bSjf  */
52544961713Sgirish static int
niumx_name_child(dev_info_t * child,char * name,int namelen)526adf6c93bSjf niumx_name_child(dev_info_t *child, char *name, int namelen)
52744961713Sgirish {
52844961713Sgirish 	niu_regspec_t *r;
52944961713Sgirish 	uint_t n;
53044961713Sgirish 
531500b1e78SAlan Adamson, SD OSSD 	DBG(NIUMX_DBG_CHK_MOD, (dev_info_t *)child, "==> niumx_name_child\n");
532adf6c93bSjf 
533adf6c93bSjf 	if (ndi_dev_is_persistent_node(child) == 0) {
534adf6c93bSjf 		char **unit_addr;
535adf6c93bSjf 
536adf6c93bSjf 		/* name .conf nodes by "unit-address" property */
537adf6c93bSjf 		if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, child,
538adf6c93bSjf 		    DDI_PROP_DONTPASS, "unit-address", &unit_addr, &n) !=
539adf6c93bSjf 		    DDI_PROP_SUCCESS) {
540adf6c93bSjf 			cmn_err(CE_WARN, "cannot name node from %s.conf",
541adf6c93bSjf 			    ddi_driver_name(child));
542adf6c93bSjf 			return (DDI_FAILURE);
543adf6c93bSjf 		}
544adf6c93bSjf 		if (n != 1 || *unit_addr == NULL || **unit_addr == 0) {
545adf6c93bSjf 			cmn_err(CE_WARN, "unit-address property in %s.conf"
546adf6c93bSjf 			    " not well-formed", ddi_driver_name(child));
547adf6c93bSjf 			ddi_prop_free(unit_addr);
548adf6c93bSjf 			return (DDI_FAILURE);
549adf6c93bSjf 		}
550adf6c93bSjf 
551adf6c93bSjf 		(void) snprintf(name, namelen, "%s", *unit_addr);
552adf6c93bSjf 		ddi_prop_free(unit_addr);
553adf6c93bSjf 		return (DDI_SUCCESS);
554adf6c93bSjf 	}
555adf6c93bSjf 
556adf6c93bSjf 	/* name hardware nodes by "reg" property */
55744961713Sgirish 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
55844961713Sgirish 	    "reg", (int **)&r, &n) != DDI_SUCCESS) {
559adf6c93bSjf 		cmn_err(CE_WARN, "reg property not well-formed");
56044961713Sgirish 		return (DDI_FAILURE);
56144961713Sgirish 	}
562678453a8Sspeer 	(void) snprintf(name, namelen, "%x", (r[0].addr_high));
56344961713Sgirish 	ddi_prop_free(r);
564adf6c93bSjf 	return (DDI_SUCCESS);
565adf6c93bSjf }
566adf6c93bSjf 
567adf6c93bSjf static int
niumx_initchild(dev_info_t * child)568adf6c93bSjf niumx_initchild(dev_info_t *child)
569adf6c93bSjf {
570adf6c93bSjf 	char name[MAXNAMELEN];
571adf6c93bSjf 
572500b1e78SAlan Adamson, SD OSSD 	DBG(NIUMX_DBG_CHK_MOD, (dev_info_t *)child, "==> niumx_initchild\n");
573adf6c93bSjf 	/*
574adf6c93bSjf 	 * Non-peristent nodes indicate a prototype node with per-instance
575adf6c93bSjf 	 * properties to be merged into the real h/w device node.
576adf6c93bSjf 	 */
577adf6c93bSjf 	if (ndi_dev_is_persistent_node(child) == 0) {
578adf6c93bSjf 		niu_regspec_t *r;
579adf6c93bSjf 		uint_t n;
580adf6c93bSjf 
581adf6c93bSjf 		if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child,
582adf6c93bSjf 		    DDI_PROP_DONTPASS, "reg", (int **)&r, &n) ==
583adf6c93bSjf 		    DDI_SUCCESS) {
584adf6c93bSjf 			cmn_err(CE_WARN,
585adf6c93bSjf 			    "cannot merge prototype from %s.conf",
586adf6c93bSjf 			    ddi_driver_name(child));
587adf6c93bSjf 			ddi_prop_free(r);
588adf6c93bSjf 			return (DDI_NOT_WELL_FORMED);
589adf6c93bSjf 		}
590adf6c93bSjf 
591adf6c93bSjf 		if (niumx_name_child(child, name, MAXNAMELEN) != DDI_SUCCESS)
592adf6c93bSjf 			return (DDI_NOT_WELL_FORMED);
593adf6c93bSjf 
594adf6c93bSjf 		ddi_set_name_addr(child, name);
595adf6c93bSjf 		ddi_set_parent_data(child, NULL);
596adf6c93bSjf 
597adf6c93bSjf 		/*
598adf6c93bSjf 		 * Try to merge the properties from this prototype
599adf6c93bSjf 		 * node into real h/w nodes.
600adf6c93bSjf 		 */
601adf6c93bSjf 		if (ndi_merge_node(child, niumx_name_child) == DDI_SUCCESS) {
602adf6c93bSjf 			/*
603adf6c93bSjf 			 * Merged ok - return failure to remove the node.
604adf6c93bSjf 			 */
605adf6c93bSjf 			ddi_set_name_addr(child, NULL);
606adf6c93bSjf 			return (DDI_FAILURE);
607adf6c93bSjf 		}
608adf6c93bSjf 
609adf6c93bSjf 		/*
610adf6c93bSjf 		 * The child was not merged into a h/w node,
611adf6c93bSjf 		 * but there's not much we can do with it other
612adf6c93bSjf 		 * than return failure to cause the node to be removed.
613adf6c93bSjf 		 */
614adf6c93bSjf 		cmn_err(CE_WARN, "!%s@%s: %s.conf properties not merged",
615adf6c93bSjf 		    ddi_driver_name(child), ddi_get_name_addr(child),
616adf6c93bSjf 		    ddi_driver_name(child));
617adf6c93bSjf 		ddi_set_name_addr(child, NULL);
618adf6c93bSjf 		return (DDI_NOT_WELL_FORMED);
619adf6c93bSjf 	}
620adf6c93bSjf 
621adf6c93bSjf 	/*
622adf6c93bSjf 	 * Initialize real h/w nodes
623adf6c93bSjf 	 */
624adf6c93bSjf 	if (niumx_name_child(child, name, MAXNAMELEN) != DDI_SUCCESS)
625adf6c93bSjf 		return (DDI_FAILURE);
626adf6c93bSjf 
62744961713Sgirish 	ddi_set_name_addr(child, name);
62844961713Sgirish 	return (DDI_SUCCESS);
62944961713Sgirish }
63044961713Sgirish 
63144961713Sgirish static void
niumx_removechild(dev_info_t * dip)63244961713Sgirish niumx_removechild(dev_info_t *dip)
63344961713Sgirish {
63444961713Sgirish 	ddi_set_name_addr(dip, NULL);
63544961713Sgirish 	ddi_remove_minor_node(dip, NULL);
63644961713Sgirish 	impl_rem_dev_props(dip);
63744961713Sgirish }
63844961713Sgirish 
63944961713Sgirish 
64044961713Sgirish 
64144961713Sgirish /*
64244961713Sgirish  * bus dma alloc handle entry point:
64344961713Sgirish  */
64444961713Sgirish /*ARGSUSED*/
64544961713Sgirish 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)64644961713Sgirish niumx_dma_allochdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_attr_t *attrp,
647*1577b7baSToomas Soome     int (*waitfp)(caddr_t), caddr_t arg, ddi_dma_handle_t *handlep)
64844961713Sgirish {
64944961713Sgirish 	ddi_dma_impl_t *mp;
65044961713Sgirish 	int sleep = (waitfp == DDI_DMA_SLEEP) ? KM_SLEEP : KM_NOSLEEP;
65144961713Sgirish 
652500b1e78SAlan Adamson, SD OSSD 	DBG(NIUMX_DBG_DMA_ALLOCH, dip, "rdip=%s%d\n", NIUMX_NAMEINST(rdip));
65344961713Sgirish 
65444961713Sgirish 	if (attrp->dma_attr_version != DMA_ATTR_V0) {
655500b1e78SAlan Adamson, SD OSSD 		DBG(NIUMX_DBG_DMA_ALLOCH,
656500b1e78SAlan Adamson, SD OSSD 		    (dev_info_t *)dip, "DDI_DMA_BADATTR\n");
65744961713Sgirish 		return (DDI_DMA_BADATTR);
65844961713Sgirish 	}
65944961713Sgirish 
66044961713Sgirish 	/* Caution: we don't use zalloc to enhance performance! */
66144961713Sgirish 	if ((mp = kmem_alloc(sizeof (ddi_dma_impl_t), sleep)) == 0) {
662500b1e78SAlan Adamson, SD OSSD 		DBG(NIUMX_DBG_DMA_ALLOCH, dip, "can't alloc ddi_dma_impl_t\n");
66344961713Sgirish 		return (DDI_FAILURE);
66444961713Sgirish 	}
66544961713Sgirish 	mp->dmai_rdip = rdip;
66644961713Sgirish 	mp->dmai_pfnlst = NULL;
66744961713Sgirish 	mp->dmai_cookie = NULL;
6689a63ec27SRobert Mustacchi 	mp->dmai_ncookies = 0;
6699a63ec27SRobert Mustacchi 	mp->dmai_curcookie = 0;
67044961713Sgirish 	mp->dmai_fault = 0;
67144961713Sgirish 	mp->dmai_fault_check = NULL;
67244961713Sgirish 	mp->dmai_fault_notify = NULL;
67344961713Sgirish 
674*1577b7baSToomas Soome 	mp->dmai_attr = *attrp;		/* set requestors attr info */
67544961713Sgirish 
676500b1e78SAlan Adamson, SD OSSD 	DBG(NIUMX_DBG_DMA_ALLOCH, dip, "mp=%p\n", mp);
67744961713Sgirish 
67844961713Sgirish 	*handlep = (ddi_dma_handle_t)mp;
67944961713Sgirish 	return (DDI_SUCCESS);
68044961713Sgirish }
68144961713Sgirish 
68244961713Sgirish 
68344961713Sgirish /*
68444961713Sgirish  * bus dma free handle entry point:
68544961713Sgirish  */
68644961713Sgirish /*ARGSUSED*/
68744961713Sgirish int
niumx_dma_freehdl(dev_info_t * dip,dev_info_t * rdip,ddi_dma_handle_t handle)68844961713Sgirish niumx_dma_freehdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t handle)
68944961713Sgirish {
69044961713Sgirish 	ddi_dma_impl_t *mp = (ddi_dma_impl_t *)handle;
69144961713Sgirish 
69244961713Sgirish 	if (mp->dmai_cookie)
69344961713Sgirish 		kmem_free(mp->dmai_cookie, sizeof (ddi_dma_cookie_t));
69444961713Sgirish 	kmem_free(mp, sizeof (ddi_dma_impl_t));
69544961713Sgirish 
69644961713Sgirish 	return (DDI_SUCCESS);
69744961713Sgirish }
69844961713Sgirish 
69944961713Sgirish 
70044961713Sgirish /*
70144961713Sgirish  * bus dma bind handle entry point:
70244961713Sgirish  *
70344961713Sgirish  *	check/enforce DMA type, setup pfn0 and some other key pieces
70444961713Sgirish  *	of this dma request.
70544961713Sgirish  * Note: this only works with DMA_OTYP_VADDR, and makes use of the known
70644961713Sgirish  *	fact that only contiguous memory blocks will be passed in.
70744961713Sgirish  *	Therefore only one cookie will ever be returned.
70844961713Sgirish  *
70944961713Sgirish  *	return values:
71044961713Sgirish  *		DDI_DMA_NOMAPPING - can't get valid pfn0, or bad dma type
71144961713Sgirish  *		DDI_DMA_NORESOURCES
71244961713Sgirish  *		DDI_SUCCESS
71344961713Sgirish  *
71444961713Sgirish  *	dma handle members affected (set on exit):
71544961713Sgirish  *	mp->dmai_object		- dmareq->dmar_object
71644961713Sgirish  *	mp->dmai_rflags		- dmareq->dmar_flags
717*1577b7baSToomas Soome  *	mp->dmai_pfn0		- 1st page pfn (if va/size pair and not shadow)
718*1577b7baSToomas Soome  *	mp->dmai_roffset	- initialized to starting page offset
71944961713Sgirish  *	mp->dmai_size		- # of total pages of entire object
72044961713Sgirish  *	mp->dmai_cookie		- new cookie alloc'd
72144961713Sgirish  */
72244961713Sgirish /*ARGSUSED*/
72344961713Sgirish 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)72444961713Sgirish niumx_dma_bindhdl(dev_info_t *dip, dev_info_t *rdip,
725*1577b7baSToomas Soome     ddi_dma_handle_t handle, ddi_dma_req_t *dmareq,
726*1577b7baSToomas Soome     ddi_dma_cookie_t *cookiep, uint_t *ccountp)
72744961713Sgirish {
72844961713Sgirish 	int (*waitfp)(caddr_t) = dmareq->dmar_fp;
72944961713Sgirish 	ddi_dma_impl_t *mp = (ddi_dma_impl_t *)handle;
73044961713Sgirish 	ddi_dma_obj_t *dobj_p = &dmareq->dmar_object;
73144961713Sgirish 	uint32_t offset;
73244961713Sgirish 	pfn_t pfn0;
73344961713Sgirish 	int ret;
73444961713Sgirish 
735500b1e78SAlan Adamson, SD OSSD 	DBG(NIUMX_DBG_DMA_BINDH, dip, "rdip=%s%d mp=%p dmareq=%p\n",
736500b1e78SAlan Adamson, SD OSSD 	    NIUMX_NAMEINST(rdip), mp, dmareq);
73744961713Sgirish 
73844961713Sgirish 	/* first check dma type */
73944961713Sgirish 	mp->dmai_rflags = dmareq->dmar_flags & DMP_DDIFLAGS | DMP_NOSYNC;
74044961713Sgirish 	switch (dobj_p->dmao_type) {
74144961713Sgirish 	case DMA_OTYP_VADDR: {
74244961713Sgirish 		caddr_t vaddr = dobj_p->dmao_obj.virt_obj.v_addr;
74344961713Sgirish 		struct as *as_p = dobj_p->dmao_obj.virt_obj.v_as;
74444961713Sgirish 		struct hat *hat_p = as_p ? as_p->a_hat : kas.a_hat;
74544961713Sgirish 		offset = (ulong_t)vaddr & NIUMX_PAGE_OFFSET;
74644961713Sgirish 		pfn0 = hat_getpfnum(hat_p, vaddr);
74744961713Sgirish 		}
74844961713Sgirish 		break;
74944961713Sgirish 
75044961713Sgirish 	case DMA_OTYP_BUFVADDR:
75144961713Sgirish 	case DMA_OTYP_PAGES:
75244961713Sgirish 	case DMA_OTYP_PADDR:
75344961713Sgirish 	default:
75444961713Sgirish 		cmn_err(CE_WARN, "%s%d requested unsupported dma type %x",
755500b1e78SAlan Adamson, SD OSSD 		    NIUMX_NAMEINST(mp->dmai_rdip), dobj_p->dmao_type);
75644961713Sgirish 		ret = DDI_DMA_NOMAPPING;
75744961713Sgirish 		goto err;
75844961713Sgirish 	}
75944961713Sgirish 	if (pfn0 == PFN_INVALID) {
76044961713Sgirish 		cmn_err(CE_WARN, "%s%d: invalid pfn0 for DMA object %p",
761500b1e78SAlan Adamson, SD OSSD 		    NIUMX_NAMEINST(dip), (void *)dobj_p);
76244961713Sgirish 		ret = DDI_DMA_NOMAPPING;
76344961713Sgirish 		goto err;
76444961713Sgirish 	}
76544961713Sgirish 	mp->dmai_object	 = *dobj_p;			/* whole object */
76644961713Sgirish 	mp->dmai_pfn0	 = (void *)pfn0;		/* cache pfn0   */
76744961713Sgirish 	mp->dmai_roffset = offset;			/* pg0 offset   */
76844961713Sgirish 	mp->dmai_mapping = mp->dmai_roffset | NIUMX_PTOB(pfn0);
76944961713Sgirish 	mp->dmai_size = mp->dmai_object.dmao_size;
77044961713Sgirish 
771500b1e78SAlan Adamson, SD OSSD 	DBG(NIUMX_DBG_DMA_BINDH, dip, "check pfn: mp=%p pfn0=%x\n",
772adf6c93bSjf 	    mp, mp->dmai_pfn0);
77344961713Sgirish 	if (!(mp->dmai_cookie = kmem_zalloc(sizeof (ddi_dma_cookie_t),
774adf6c93bSjf 	    waitfp == DDI_DMA_SLEEP ? KM_SLEEP : KM_NOSLEEP))) {
77544961713Sgirish 			ret = DDI_DMA_NORESOURCES;
77644961713Sgirish 			goto err;
77744961713Sgirish 		}
77844961713Sgirish 	mp->dmai_cookie->dmac_laddress = mp->dmai_mapping;
77944961713Sgirish 	mp->dmai_cookie->dmac_size = mp->dmai_size;
7809a63ec27SRobert Mustacchi 	mp->dmai_ncookies = 1;
7819a63ec27SRobert Mustacchi 	mp->dmai_curcookie = 0;
78244961713Sgirish 	*ccountp = 1;
78344961713Sgirish 	*cookiep = *mp->dmai_cookie;
784500b1e78SAlan Adamson, SD OSSD 	DBG(NIUMX_DBG_DMA_BINDH, dip, "cookie %" PRIx64 "+%x, count=%d\n",
785adf6c93bSjf 	    cookiep->dmac_address, cookiep->dmac_size, *ccountp);
78644961713Sgirish 	return (DDI_DMA_MAPPED);
78744961713Sgirish 
78844961713Sgirish err:
789500b1e78SAlan Adamson, SD OSSD 	DBG(NIUMX_DBG_DMA_BINDH, (dev_info_t *)dip,
790adf6c93bSjf 	    "niumx_dma_bindhdl error ret=%d\n", ret);
79144961713Sgirish 	return (ret);
79244961713Sgirish }
79344961713Sgirish 
79444961713Sgirish /*
79544961713Sgirish  * bus dma unbind handle entry point:
79644961713Sgirish  */
79744961713Sgirish /*ARGSUSED*/
79844961713Sgirish int
niumx_dma_unbindhdl(dev_info_t * dip,dev_info_t * rdip,ddi_dma_handle_t handle)79944961713Sgirish niumx_dma_unbindhdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t handle)
80044961713Sgirish {
80144961713Sgirish 	ddi_dma_impl_t *mp = (ddi_dma_impl_t *)handle;
80244961713Sgirish 
803500b1e78SAlan Adamson, SD OSSD 	DBG(NIUMX_DBG_DMA_UNBINDH, dip, "rdip=%s%d, mp=%p\n",
804adf6c93bSjf 	    ddi_driver_name(rdip), ddi_get_instance(rdip), handle);
80544961713Sgirish 	if (mp->dmai_cookie) {
80644961713Sgirish 		kmem_free(mp->dmai_cookie, sizeof (ddi_dma_cookie_t));
80744961713Sgirish 		mp->dmai_cookie = NULL;
8089a63ec27SRobert Mustacchi 		mp->dmai_ncookies = mp->dmai_curcookie = 0;
80944961713Sgirish 	}
81044961713Sgirish 
81144961713Sgirish 	return (DDI_SUCCESS);
81244961713Sgirish }
81344961713Sgirish 
81444961713Sgirish /*ARGSUSED*/
81544961713Sgirish 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)81644961713Sgirish niumx_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
81744961713Sgirish     ddi_intr_handle_impl_t *hdlp, void *result)
81844961713Sgirish {
81944961713Sgirish 
82044961713Sgirish 	int	ret = DDI_SUCCESS;
82144961713Sgirish 
822500b1e78SAlan Adamson, SD OSSD 	DBG(NIUMX_DBG_INTROPS, dip, "niumx_intr_ops: dip=%p rdip=%p intr_op=%x "
82344961713Sgirish 	    "handle=%p\n", dip, rdip, intr_op, hdlp);
82444961713Sgirish 
82544961713Sgirish 	switch (intr_op) {
82644961713Sgirish 
82744961713Sgirish 	case DDI_INTROP_SUPPORTED_TYPES:
82844961713Sgirish 		*(int *)result = DDI_INTR_TYPE_FIXED;
82944961713Sgirish 		break;
83044961713Sgirish 	case DDI_INTROP_GETCAP:
831657f87deSgongtian zhao - Sun Microsystems - Beijing China 		*(int *)result =  DDI_INTR_FLAG_LEVEL;
83244961713Sgirish 		break;
83344961713Sgirish 	case DDI_INTROP_SETCAP:
83444961713Sgirish 		ret = DDI_ENOTSUP;
83544961713Sgirish 		break;
83644961713Sgirish 	case DDI_INTROP_ALLOC:
83744961713Sgirish 		/*  scratch1 = count,  # of intrs from DDI framework */
83844961713Sgirish 		*(int *)result = hdlp->ih_scratch1;
83944961713Sgirish 		break;
84044961713Sgirish 	case DDI_INTROP_FREE:
84144961713Sgirish 		/* Do we need to do anything here?  */
84244961713Sgirish 		break;
84344961713Sgirish 	case DDI_INTROP_GETPRI:
84444961713Sgirish 		*(int *)result = NIUMX_DEFAULT_PIL;
84544961713Sgirish 		break;
84644961713Sgirish 	case DDI_INTROP_SETPRI:
84744961713Sgirish 		ret = DDI_ENOTSUP;
84844961713Sgirish 		break;
84944961713Sgirish 	case DDI_INTROP_ADDISR:
85044961713Sgirish 		ret = niumx_add_intr(dip, rdip, hdlp);
85144961713Sgirish 		break;
85244961713Sgirish 	case DDI_INTROP_REMISR:
85344961713Sgirish 		ret = niumx_rem_intr(dip, rdip, hdlp);
85444961713Sgirish 		break;
85544961713Sgirish 	case DDI_INTROP_ENABLE:
85644961713Sgirish 		ret = niumx_set_intr(dip, rdip, hdlp, HV_INTR_VALID);
85744961713Sgirish 		break;
85844961713Sgirish 	case DDI_INTROP_DISABLE:
85944961713Sgirish 		ret = niumx_set_intr(dip, rdip, hdlp, HV_INTR_NOTVALID);
86044961713Sgirish 		break;
86144961713Sgirish 	case DDI_INTROP_SETMASK:
86244961713Sgirish 		ret = DDI_ENOTSUP;
86344961713Sgirish 		break;
86444961713Sgirish 	case DDI_INTROP_CLRMASK:
86544961713Sgirish 		ret = DDI_ENOTSUP;
86644961713Sgirish 		break;
86744961713Sgirish 	case DDI_INTROP_GETPENDING:
86844961713Sgirish 		ret = DDI_ENOTSUP;
86944961713Sgirish 		break;
87044961713Sgirish 	case DDI_INTROP_NINTRS:
87144961713Sgirish 	case DDI_INTROP_NAVAIL: {
872500b1e78SAlan Adamson, SD OSSD 		niudevino_t	*inos_p;
87344961713Sgirish 		int		inoslen;
874500b1e78SAlan Adamson, SD OSSD 
87544961713Sgirish 		if (ddi_getlongprop(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS,
876adf6c93bSjf 		    "interrupts", (caddr_t)&inos_p, &inoslen)
877adf6c93bSjf 		    != DDI_SUCCESS) {
878adf6c93bSjf 			ret = DDI_FAILURE;
879adf6c93bSjf 			break;
88044961713Sgirish 			}
88144961713Sgirish 		*(int *)result = inoslen / sizeof (uint32_t);
88244961713Sgirish 		kmem_free(inos_p, inoslen);
883500b1e78SAlan Adamson, SD OSSD 		}
884500b1e78SAlan Adamson, SD OSSD 		break;
885500b1e78SAlan Adamson, SD OSSD 	case DDI_INTROP_GETTARGET: {
886500b1e78SAlan Adamson, SD OSSD 		niumx_devstate_t *niumxds_p;
887500b1e78SAlan Adamson, SD OSSD 
888500b1e78SAlan Adamson, SD OSSD 		niumxds_p = (niumx_devstate_t *)ddi_get_soft_state(niumx_state,
889500b1e78SAlan Adamson, SD OSSD 		    ddi_get_instance(dip));
890500b1e78SAlan Adamson, SD OSSD 
891500b1e78SAlan Adamson, SD OSSD 		ret = niumx_get_intr_target(niumxds_p, hdlp->ih_vector,
892500b1e78SAlan Adamson, SD OSSD 		    (niucpuid_t *)result);
893500b1e78SAlan Adamson, SD OSSD 
894500b1e78SAlan Adamson, SD OSSD 		}
895500b1e78SAlan Adamson, SD OSSD 		break;
896500b1e78SAlan Adamson, SD OSSD 	case DDI_INTROP_SETTARGET: {
897500b1e78SAlan Adamson, SD OSSD 		niumx_devstate_t *niumxds_p;
898500b1e78SAlan Adamson, SD OSSD 
899500b1e78SAlan Adamson, SD OSSD 		niumxds_p = (niumx_devstate_t *)ddi_get_soft_state(niumx_state,
900500b1e78SAlan Adamson, SD OSSD 		    ddi_get_instance(dip));
901500b1e78SAlan Adamson, SD OSSD 
902500b1e78SAlan Adamson, SD OSSD 		ret = niumx_set_intr_target(niumxds_p, hdlp->ih_vector,
903500b1e78SAlan Adamson, SD OSSD 		    *(niucpuid_t *)result);
904500b1e78SAlan Adamson, SD OSSD 
90544961713Sgirish 		}
90644961713Sgirish 		break;
90744961713Sgirish 	default:
90844961713Sgirish 		ret = DDI_ENOTSUP;
90944961713Sgirish 		break;
91044961713Sgirish 	}
91144961713Sgirish 
912500b1e78SAlan Adamson, SD OSSD 	DBG(NIUMX_DBG_INTROPS, dip, "niumx_intr_ops: ret=%d\n", ret);
91344961713Sgirish 	return (ret);
91444961713Sgirish }
91544961713Sgirish 
91644961713Sgirish int
niumx_set_intr(dev_info_t * dip,dev_info_t * rdip,ddi_intr_handle_impl_t * hdlp,int valid)91744961713Sgirish niumx_set_intr(dev_info_t *dip, dev_info_t *rdip,
91844961713Sgirish     ddi_intr_handle_impl_t *hdlp, int valid)
91944961713Sgirish {
92044961713Sgirish 	niumx_ih_t	*ih_p;
921500b1e78SAlan Adamson, SD OSSD 	int		ret = DDI_SUCCESS;
92244961713Sgirish 	uint64_t	hvret;
9234df55fdeSJanie Lu 	niumx_devstate_t	*niumxds_p;	/* devstate pointer */
924*1577b7baSToomas Soome 	int		instance = ddi_get_instance(dip);
9254df55fdeSJanie Lu 
9264df55fdeSJanie Lu 	niumxds_p = (niumx_devstate_t *)ddi_get_soft_state(niumx_state,
9274df55fdeSJanie Lu 	    instance);
92844961713Sgirish 
92944961713Sgirish 	ASSERT(hdlp->ih_inum < NIUMX_MAX_INTRS);
93044961713Sgirish 
931500b1e78SAlan Adamson, SD OSSD 	ih_p = niumxds_p->niumx_ihtable +  hdlp->ih_vector;
9324df55fdeSJanie Lu 
933500b1e78SAlan Adamson, SD OSSD 	DBG(NIUMX_DBG_A_INTX, dip,
934500b1e78SAlan Adamson, SD OSSD 	    "niumx_set_intr: rdip=%s%d, valid=%d %s (%x,%x)\n",
935500b1e78SAlan Adamson, SD OSSD 	    NIUMX_NAMEINST(rdip), valid, valid ? "enabling" : "disabling",
936adf6c93bSjf 	    ih_p->ih_inum, ih_p->ih_sysino);
93744961713Sgirish 
938cb343a2eSspeer 	if (valid == HV_INTR_VALID)
939cb343a2eSspeer 		(void) hvio_intr_setstate(ih_p->ih_sysino, HV_INTR_IDLE_STATE);
94044961713Sgirish 	if ((hvret = hvio_intr_setvalid(ih_p->ih_sysino, valid))
941adf6c93bSjf 	    != H_EOK) {
942500b1e78SAlan Adamson, SD OSSD 		DBG(NIUMX_DBG_A_INTX, dip,
943500b1e78SAlan Adamson, SD OSSD 		    "hvio_intr_setvalid failed, ret 0x%x\n", hvret);
94444961713Sgirish 		ret = DDI_FAILURE;
945500b1e78SAlan Adamson, SD OSSD 	} else
946500b1e78SAlan Adamson, SD OSSD 		ih_p->ih_state = valid;
947500b1e78SAlan Adamson, SD OSSD 
94844961713Sgirish 	return (ret);
94944961713Sgirish }
95044961713Sgirish 
951500b1e78SAlan Adamson, SD OSSD int
niumx_get_intr_target(niumx_devstate_t * niumxds_p,niudevino_t ino,niucpuid_t * cpu_id)952500b1e78SAlan Adamson, SD OSSD niumx_get_intr_target(niumx_devstate_t *niumxds_p, niudevino_t ino,
953500b1e78SAlan Adamson, SD OSSD     niucpuid_t *cpu_id)
954500b1e78SAlan Adamson, SD OSSD {
955500b1e78SAlan Adamson, SD OSSD 	niumx_ih_t *ih_p;
956500b1e78SAlan Adamson, SD OSSD 	niusysino_t sysino;
957500b1e78SAlan Adamson, SD OSSD 	int rval = DDI_SUCCESS;
958500b1e78SAlan Adamson, SD OSSD 
959500b1e78SAlan Adamson, SD OSSD 	ih_p = niumxds_p->niumx_ihtable + ino;
960500b1e78SAlan Adamson, SD OSSD 
961500b1e78SAlan Adamson, SD OSSD 	sysino = ih_p->ih_sysino;
962500b1e78SAlan Adamson, SD OSSD 
963500b1e78SAlan Adamson, SD OSSD 	if (sysino == 0) {
964500b1e78SAlan Adamson, SD OSSD 		rval = EINVAL;
965500b1e78SAlan Adamson, SD OSSD 		goto done;
966500b1e78SAlan Adamson, SD OSSD 	}
967500b1e78SAlan Adamson, SD OSSD 
968500b1e78SAlan Adamson, SD OSSD 	if (hvio_intr_gettarget(sysino, cpu_id) != H_EOK) {
969500b1e78SAlan Adamson, SD OSSD 		rval = EINVAL;
970500b1e78SAlan Adamson, SD OSSD 		goto done;
971500b1e78SAlan Adamson, SD OSSD 	}
972500b1e78SAlan Adamson, SD OSSD 
973500b1e78SAlan Adamson, SD OSSD 	if (ih_p->ih_cpuid != *cpu_id)
974500b1e78SAlan Adamson, SD OSSD 		rval = EIO;
975500b1e78SAlan Adamson, SD OSSD 
976500b1e78SAlan Adamson, SD OSSD done:
977500b1e78SAlan Adamson, SD OSSD 	return (rval);
978500b1e78SAlan Adamson, SD OSSD }
979500b1e78SAlan Adamson, SD OSSD 
980500b1e78SAlan Adamson, SD OSSD int
niumx_set_intr_target(niumx_devstate_t * niumxds_p,niudevino_t ino,niucpuid_t cpu_id)981500b1e78SAlan Adamson, SD OSSD niumx_set_intr_target(niumx_devstate_t *niumxds_p, niudevino_t ino,
982500b1e78SAlan Adamson, SD OSSD     niucpuid_t cpu_id)
983500b1e78SAlan Adamson, SD OSSD {
984500b1e78SAlan Adamson, SD OSSD 	dev_info_t *dip = niumxds_p->dip;
985500b1e78SAlan Adamson, SD OSSD 	niumx_ih_t *ih_p;
986500b1e78SAlan Adamson, SD OSSD 	niucpuid_t old_cpu_id;
987500b1e78SAlan Adamson, SD OSSD 	niusysino_t sysino;
988500b1e78SAlan Adamson, SD OSSD 	int ret = DDI_SUCCESS;
989500b1e78SAlan Adamson, SD OSSD 	int state;
990500b1e78SAlan Adamson, SD OSSD 	hrtime_t start;
991500b1e78SAlan Adamson, SD OSSD 	extern const int _ncpu;
992500b1e78SAlan Adamson, SD OSSD 	extern cpu_t *cpu[];
993500b1e78SAlan Adamson, SD OSSD 
994500b1e78SAlan Adamson, SD OSSD 	mutex_enter(&cpu_lock);
995500b1e78SAlan Adamson, SD OSSD 
996500b1e78SAlan Adamson, SD OSSD 	ih_p = niumxds_p->niumx_ihtable + ino;
997500b1e78SAlan Adamson, SD OSSD 
998500b1e78SAlan Adamson, SD OSSD 	sysino = ih_p->ih_sysino;
999500b1e78SAlan Adamson, SD OSSD 	if (sysino == 0) {
1000500b1e78SAlan Adamson, SD OSSD 		ret = EINVAL;
1001500b1e78SAlan Adamson, SD OSSD 		goto done;
1002500b1e78SAlan Adamson, SD OSSD 	}
1003500b1e78SAlan Adamson, SD OSSD 
1004500b1e78SAlan Adamson, SD OSSD 	if (hvio_intr_gettarget(sysino, &old_cpu_id) != H_EOK) {
1005500b1e78SAlan Adamson, SD OSSD 		ret = EINVAL;
1006500b1e78SAlan Adamson, SD OSSD 		goto done;
1007500b1e78SAlan Adamson, SD OSSD 	}
1008500b1e78SAlan Adamson, SD OSSD 	if ((cpu_id < _ncpu) && (cpu[cpu_id] && cpu_is_online(cpu[cpu_id]))) {
1009500b1e78SAlan Adamson, SD OSSD 		if (cpu_id == old_cpu_id)
1010500b1e78SAlan Adamson, SD OSSD 			goto done;
1011500b1e78SAlan Adamson, SD OSSD 
1012500b1e78SAlan Adamson, SD OSSD 		/* check for pending interrupts, busy wait if so */
1013500b1e78SAlan Adamson, SD OSSD 		for (start = gethrtime(); !panicstr &&
1014500b1e78SAlan Adamson, SD OSSD 		    (hvio_intr_getstate(sysino, &state) == H_EOK) &&
1015500b1e78SAlan Adamson, SD OSSD 		    (state == HV_INTR_DELIVERED_STATE); /* */) {
1016500b1e78SAlan Adamson, SD OSSD 			if (gethrtime() - start > niumx_intr_timeout) {
1017500b1e78SAlan Adamson, SD OSSD 				cmn_err(CE_WARN, "%s%d: niumx_intr_dist: "
1018500b1e78SAlan Adamson, SD OSSD 				    "pending interrupt (%x,%lx) timedout\n",
1019500b1e78SAlan Adamson, SD OSSD 				    ddi_driver_name(dip), ddi_get_instance(dip),
1020500b1e78SAlan Adamson, SD OSSD 				    ih_p->ih_inum, sysino);
1021500b1e78SAlan Adamson, SD OSSD 				(void) hvio_intr_setstate(sysino,
1022500b1e78SAlan Adamson, SD OSSD 				    HV_INTR_IDLE_STATE);
1023500b1e78SAlan Adamson, SD OSSD 				break;
1024500b1e78SAlan Adamson, SD OSSD 			}
1025500b1e78SAlan Adamson, SD OSSD 		}
1026500b1e78SAlan Adamson, SD OSSD 		(void) hvio_intr_settarget(sysino, cpu_id);
1027500b1e78SAlan Adamson, SD OSSD 		if (ih_p->ih_state == HV_INTR_VALID)
1028500b1e78SAlan Adamson, SD OSSD 			(void) hvio_intr_setvalid(sysino, HV_INTR_VALID);
1029500b1e78SAlan Adamson, SD OSSD 		else
1030500b1e78SAlan Adamson, SD OSSD 			(void) hvio_intr_setvalid(sysino, HV_INTR_NOTVALID);
1031500b1e78SAlan Adamson, SD OSSD 		ih_p->ih_cpuid = cpu_id;
1032500b1e78SAlan Adamson, SD OSSD 	} else {
1033500b1e78SAlan Adamson, SD OSSD 		ret = DDI_EINVAL;
1034500b1e78SAlan Adamson, SD OSSD 	}
1035500b1e78SAlan Adamson, SD OSSD 
1036500b1e78SAlan Adamson, SD OSSD done:
1037500b1e78SAlan Adamson, SD OSSD 	mutex_exit(&cpu_lock);
1038500b1e78SAlan Adamson, SD OSSD 	return (ret);
1039500b1e78SAlan Adamson, SD OSSD }
104044961713Sgirish 
104144961713Sgirish 
104244961713Sgirish /*
104344961713Sgirish  * niumx_add_intr:
104444961713Sgirish  *
1045e778ae44SRaghuram Kothakota  * This function is called to register interrupts.
104644961713Sgirish  */
104744961713Sgirish int
niumx_add_intr(dev_info_t * dip,dev_info_t * rdip,ddi_intr_handle_impl_t * hdlp)104844961713Sgirish niumx_add_intr(dev_info_t *dip, dev_info_t *rdip,
104944961713Sgirish     ddi_intr_handle_impl_t *hdlp)
105044961713Sgirish {
105144961713Sgirish 	niumx_ih_t	*ih_p;
1052500b1e78SAlan Adamson, SD OSSD 	int		ret = DDI_SUCCESS;
105344961713Sgirish 	uint64_t	hvret;
1054500b1e78SAlan Adamson, SD OSSD 	niusysino_t	sysino;
10554df55fdeSJanie Lu 	niumx_devstate_t	*niumxds_p;	/* devstate pointer */
10564df55fdeSJanie Lu 	int		instance = ddi_get_instance(dip);
10574df55fdeSJanie Lu 
10584df55fdeSJanie Lu 	niumxds_p = (niumx_devstate_t *)ddi_get_soft_state(niumx_state,
10594df55fdeSJanie Lu 	    instance);
106044961713Sgirish 
106144961713Sgirish 	/* get new ino */
106244961713Sgirish 	if (hdlp->ih_inum >= NIUMX_MAX_INTRS) {
1063500b1e78SAlan Adamson, SD OSSD 		DBG(NIUMX_DBG_INTR, dip, "error: inum %d out of range\n",
1064adf6c93bSjf 		    hdlp->ih_inum);
106544961713Sgirish 		ret = DDI_FAILURE;
106644961713Sgirish 		goto done;
106744961713Sgirish 	}
1068500b1e78SAlan Adamson, SD OSSD 
1069500b1e78SAlan Adamson, SD OSSD 	ih_p = niumxds_p->niumx_ihtable + hdlp->ih_vector;
1070500b1e78SAlan Adamson, SD OSSD 
1071500b1e78SAlan Adamson, SD OSSD 	if ((hvret = hvio_intr_devino_to_sysino(NIUMX_DIP_TO_HANDLE(dip),
1072500b1e78SAlan Adamson, SD OSSD 	    hdlp->ih_vector, &sysino)) != H_EOK) {
1073500b1e78SAlan Adamson, SD OSSD 		DBG(NIUMX_DBG_INTR, dip, "hvio_intr_devino_to_sysino failed, "
1074adf6c93bSjf 		    "ret 0x%x\n", hvret);
107544961713Sgirish 		ret = DDI_FAILURE;
107644961713Sgirish 		goto done;
107744961713Sgirish 	}
107844961713Sgirish 	ih_p->ih_sysino = sysino;
1079500b1e78SAlan Adamson, SD OSSD 	ih_p->ih_dip = rdip;
108044961713Sgirish 	ih_p->ih_inum = hdlp->ih_inum;
108144961713Sgirish 	ih_p->ih_hdlr = hdlp->ih_cb_func;
108244961713Sgirish 	ih_p->ih_arg1 = hdlp->ih_cb_arg1;
108344961713Sgirish 	ih_p->ih_arg2 = hdlp->ih_cb_arg2;
108444961713Sgirish 
1085500b1e78SAlan Adamson, SD OSSD 	DBG(NIUMX_DBG_A_INTX, dip, "niumx_add_intr: rdip=%s%d inum=0x%x "
1086500b1e78SAlan Adamson, SD OSSD 	    "handler=%p arg1=%p arg2=%p, new ih_p = %p\n", NIUMX_NAMEINST(rdip),
1087adf6c93bSjf 	    hdlp->ih_inum, hdlp->ih_cb_func, hdlp->ih_cb_arg1,
1088adf6c93bSjf 	    hdlp->ih_cb_arg2, ih_p);
108944961713Sgirish 
109044961713Sgirish 	if (hdlp->ih_pri == 0)
109144961713Sgirish 		hdlp->ih_pri = NIUMX_DEFAULT_PIL;
109244961713Sgirish 
1093500b1e78SAlan Adamson, SD OSSD 	ih_p->ih_pri = hdlp->ih_pri;
1094500b1e78SAlan Adamson, SD OSSD 
1095500b1e78SAlan Adamson, SD OSSD 	DBG(NIUMX_DBG_A_INTX, dip, "for ino %x adding (%x,%x)\n",
1096500b1e78SAlan Adamson, SD OSSD 	    hdlp->ih_vector, ih_p->ih_inum, ih_p->ih_sysino);
1097500b1e78SAlan Adamson, SD OSSD 
109844961713Sgirish 	/* Save sysino value in hdlp */
109944961713Sgirish 	hdlp->ih_vector = ih_p->ih_sysino;
110044961713Sgirish 
110144961713Sgirish 	/* swap in our handler & arg */
110244961713Sgirish 	DDI_INTR_ASSIGN_HDLR_N_ARGS(hdlp, (ddi_intr_handler_t *)niumx_intr_hdlr,
1103adf6c93bSjf 	    (void *)ih_p, NULL);
110444961713Sgirish 
110544961713Sgirish 	ret = i_ddi_add_ivintr(hdlp);
110644961713Sgirish 
110744961713Sgirish 	/* Restore orig. interrupt handler & args in handle. */
110844961713Sgirish 	DDI_INTR_ASSIGN_HDLR_N_ARGS(hdlp, ih_p->ih_hdlr, ih_p->ih_arg1,
1109adf6c93bSjf 	    ih_p->ih_arg2);
111044961713Sgirish 
111144961713Sgirish 	if (ret != DDI_SUCCESS) {
1112500b1e78SAlan Adamson, SD OSSD 		DBG(NIUMX_DBG_A_INTX, dip, "i_ddi_add_ivintr error ret=%x\n",
1113500b1e78SAlan Adamson, SD OSSD 		    ret);
111444961713Sgirish 		goto done;
111544961713Sgirish 	}
111644961713Sgirish 
111744961713Sgirish 	/* select cpu, saving it for removal */
111844961713Sgirish 	ih_p->ih_cpuid = intr_dist_cpuid();
111944961713Sgirish 
112044961713Sgirish 	if ((hvret = hvio_intr_settarget(ih_p->ih_sysino, ih_p->ih_cpuid))
1121adf6c93bSjf 	    != H_EOK) {
1122500b1e78SAlan Adamson, SD OSSD 		DBG(NIUMX_DBG_A_INTX, dip,
1123500b1e78SAlan Adamson, SD OSSD 		    "hvio_intr_settarget failed, ret 0x%x\n", hvret);
112444961713Sgirish 		ret = DDI_FAILURE;
112544961713Sgirish 	}
112644961713Sgirish done:
1127500b1e78SAlan Adamson, SD OSSD 	DBG(NIUMX_DBG_A_INTX, dip, "done, ret = %d, ih_p 0x%p, hdlp 0x%p\n",
1128500b1e78SAlan Adamson, SD OSSD 	    ih_p, hdlp, ret);
112944961713Sgirish 	return (ret);
113044961713Sgirish }
113144961713Sgirish 
113244961713Sgirish /*
113344961713Sgirish  * niumx_rem_intr:
113444961713Sgirish  *
113544961713Sgirish  * This function is called to unregister interrupts.
113644961713Sgirish  */
1137500b1e78SAlan Adamson, SD OSSD /*ARGSUSED*/
113844961713Sgirish int
niumx_rem_intr(dev_info_t * dip,dev_info_t * rdip,ddi_intr_handle_impl_t * hdlp)113944961713Sgirish niumx_rem_intr(dev_info_t *dip, dev_info_t *rdip,
114044961713Sgirish     ddi_intr_handle_impl_t *hdlp)
114144961713Sgirish {
114244961713Sgirish 	niumx_ih_t	*ih_p;
1143500b1e78SAlan Adamson, SD OSSD 	int		ret = DDI_SUCCESS, state;
1144c165966dSjf 	hrtime_t	start;
1145*1577b7baSToomas Soome 	niusysino_t	sysino;
11464df55fdeSJanie Lu 	niumx_devstate_t	*niumxds_p;	/* devstate pointer */
11474df55fdeSJanie Lu 	int		instance = ddi_get_instance(dip);
11484df55fdeSJanie Lu 
11494df55fdeSJanie Lu 	niumxds_p = (niumx_devstate_t *)ddi_get_soft_state(niumx_state,
11504df55fdeSJanie Lu 	    instance);
115144961713Sgirish 
115244961713Sgirish 	ASSERT(hdlp->ih_inum < NIUMX_MAX_INTRS);
115344961713Sgirish 
1154500b1e78SAlan Adamson, SD OSSD 	ih_p = niumxds_p->niumx_ihtable +  hdlp->ih_vector;
1155500b1e78SAlan Adamson, SD OSSD 
1156c165966dSjf 	sysino = ih_p->ih_sysino;
1157500b1e78SAlan Adamson, SD OSSD 	DBG(NIUMX_DBG_R_INTX, dip, "removing (%x,%x)\n", ih_p->ih_inum, sysino);
1158c165966dSjf 
1159c165966dSjf 	(void) hvio_intr_setvalid(sysino, HV_INTR_NOTVALID);
1160c165966dSjf 
1161c165966dSjf 	/* check for pending interrupts, busy wait if so */
1162c165966dSjf 	for (start = gethrtime(); !panicstr &&
1163c165966dSjf 	    (hvio_intr_getstate(sysino, &state) == H_EOK) &&
1164c165966dSjf 	    (state == HV_INTR_DELIVERED_STATE); /* */) {
1165c165966dSjf 		if (gethrtime() - start > niumx_intr_timeout) {
1166c165966dSjf 			cmn_err(CE_WARN, "%s%d: niumx_intr_dist: "
1167c165966dSjf 			    "pending interrupt (%x,%lx) timedout\n",
1168c165966dSjf 			    ddi_driver_name(dip), ddi_get_instance(dip),
1169c165966dSjf 			    ih_p->ih_inum, sysino);
1170c165966dSjf 			ret = DDI_FAILURE;
1171500b1e78SAlan Adamson, SD OSSD 			goto fail;
1172c165966dSjf 		}
117344961713Sgirish 	}
117444961713Sgirish 
1175678453a8Sspeer 	ih_p->ih_sysino = 0;
1176678453a8Sspeer 
1177c165966dSjf 	hdlp->ih_vector = (uint32_t)sysino;
1178*1577b7baSToomas Soome 	if (hdlp->ih_vector != 0)
1179*1577b7baSToomas Soome 		i_ddi_rem_ivintr(hdlp);
118044961713Sgirish 
1181500b1e78SAlan Adamson, SD OSSD fail:
118244961713Sgirish 	return (ret);
118344961713Sgirish }
118444961713Sgirish 
118544961713Sgirish /*
118644961713Sgirish  * niumx_intr_hdlr (our interrupt handler)
118744961713Sgirish  */
118844961713Sgirish uint_t
niumx_intr_hdlr(void * arg)118944961713Sgirish niumx_intr_hdlr(void *arg)
119044961713Sgirish {
119144961713Sgirish 	niumx_ih_t *ih_p = (niumx_ih_t *)arg;
119244961713Sgirish 	uint_t		r;
119344961713Sgirish 
119444961713Sgirish 	DTRACE_PROBE4(interrupt__start, dev_info_t, ih_p->ih_dip, void *,
1195adf6c93bSjf 	    ih_p->ih_hdlr, caddr_t, ih_p->ih_arg1, caddr_t, ih_p->ih_arg2);
119644961713Sgirish 
119744961713Sgirish 	r = (*ih_p->ih_hdlr)(ih_p->ih_arg1, ih_p->ih_arg2);
119844961713Sgirish 
119944961713Sgirish 	DTRACE_PROBE4(interrupt__complete, dev_info_t, ih_p->ih_dip, void *,
1200adf6c93bSjf 	    ih_p->ih_hdlr, caddr_t, ih_p->ih_arg1, int, r);
1201cb343a2eSspeer 
1202cb343a2eSspeer 	(void) hvio_intr_setstate(ih_p->ih_sysino, HV_INTR_IDLE_STATE);
120344961713Sgirish 	return (r);
120444961713Sgirish }
120544961713Sgirish 
120644961713Sgirish #ifdef	DEBUG
120744961713Sgirish uint64_t niumx_debug_flags = 0;
120844961713Sgirish 
120944961713Sgirish static char *niumx_debug_sym [] = {	/* same sequence as niumx_debug_bit */
121044961713Sgirish 	/*  0 */ "attach",
121144961713Sgirish 	/*  1 */ "map",
121244961713Sgirish 	/*  2 */ "nex-ctlops",
121344961713Sgirish 	/*  3 */ "introps",
121444961713Sgirish 	/*  4 */ "intr-add",
121544961713Sgirish 	/*  5 */ "intr-rem",
121644961713Sgirish 	/*  6 */ "intr",
121744961713Sgirish 	/*  7 */ "dma-alloc",
121844961713Sgirish 	/*  8 */ "dma-bind",
121944961713Sgirish 	/*  9 */ "dma-unbind",
122044961713Sgirish 	/* 10 */ "chk-dma-mode"
122144961713Sgirish };
122244961713Sgirish 
122344961713Sgirish /*ARGSUSED*/
122444961713Sgirish void
niumx_dbg(niumx_debug_bit_t bit,dev_info_t * dip,char * fmt,...)122544961713Sgirish niumx_dbg(niumx_debug_bit_t bit, dev_info_t *dip, char *fmt, ...)
122644961713Sgirish {
122744961713Sgirish 	va_list ap;
122844961713Sgirish 	char msgbuf[1024];
122944961713Sgirish 
123044961713Sgirish 	if (!(1ull << bit & niumx_debug_flags))
123144961713Sgirish 		return;
123244961713Sgirish 	va_start(ap, fmt);
123344961713Sgirish 	(void) vsprintf(msgbuf, fmt, ap);
123444961713Sgirish 	va_end(ap);
123544961713Sgirish 	cmn_err(CE_NOTE, "%s: %s", niumx_debug_sym[bit], msgbuf);
123644961713Sgirish }
123744961713Sgirish 
123844961713Sgirish #endif	/* DEBUG */
1239