xref: /titanic_44/usr/src/uts/sun4v/io/niumx/niumx.c (revision 657f87de670449e1422db4f51fb2880a7cb69d5a)
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*657f87deSgongtian 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 
478fca0570Sjf137018 static int niumx_fm_init_child(dev_info_t *, dev_info_t *, int,
488fca0570Sjf137018 	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,
10044961713Sgirish 	0,				/* (*bus_get_eventcookie)();    */
10144961713Sgirish 	0,				/* (*bus_add_eventcall)();	*/
10244961713Sgirish 	0,				/* (*bus_remove_eventcall)();   */
10344961713Sgirish 	0,				/* (*bus_post_event)();		*/
10444961713Sgirish 	0,				/* (*bus_intr_ctl)();		*/
10544961713Sgirish 	0,				/* (*bus_config)(); 		*/
10644961713Sgirish 	0,				/* (*bus_unconfig)(); 		*/
1078fca0570Sjf137018 	niumx_fm_init_child,		/* (*bus_fm_init)(); 		*/
10844961713Sgirish 	0,				/* (*bus_fm_fini)(); 		*/
10944961713Sgirish 	0,				/* (*bus_enter)()		*/
11044961713Sgirish 	0,				/* (*bus_exit)()		*/
11144961713Sgirish 	0,				/* (*bus_power)()		*/
11244961713Sgirish 	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;
157d66f8315Sjb145095 	uint64_t mjrnum;
158d66f8315Sjb145095 	uint64_t mnrnum;
159d66f8315Sjb145095 
160d66f8315Sjb145095 	/*
161d66f8315Sjb145095 	 * Check HV intr group api versioning.
162d66f8315Sjb145095 	 * This driver uses the old interrupt routines which are supported
163d66f8315Sjb145095 	 * in old firmware in the CORE API group and in newer firmware in
164d66f8315Sjb145095 	 * the INTR API group.  Support for these calls will be dropped
165d66f8315Sjb145095 	 * once the INTR API group major goes to 2.
166d66f8315Sjb145095 	 */
167d66f8315Sjb145095 	if ((hsvc_version(HSVC_GROUP_INTR, &mjrnum, &mnrnum) == 0) &&
168d66f8315Sjb145095 	    (mjrnum > NIUMX_INTR_MAJOR_VER)) {
169d66f8315Sjb145095 		cmn_err(CE_WARN, "niumx: unsupported intr api group: "
170d66f8315Sjb145095 		    "maj:0x%lx, min:0x%lx", mjrnum, mnrnum);
171d66f8315Sjb145095 		return (ENOTSUP);
172d66f8315Sjb145095 	}
173d66f8315Sjb145095 
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 
195c165966dSjf137018 
196c165966dSjf137018 hrtime_t niumx_intr_timeout = 2ull * NANOSEC; /* 2 seconds in nanoseconds */
197c165966dSjf137018 
1983266dff7Sjf137018 void
niumx_intr_dist(void * arg)1993266dff7Sjf137018 niumx_intr_dist(void *arg)
2003266dff7Sjf137018 {
2014df55fdeSJanie Lu 	niumx_devstate_t	*niumxds_p = (niumx_devstate_t *)arg;
2024df55fdeSJanie Lu 	kmutex_t 	*lock_p = &niumxds_p->niumx_mutex;
203e778ae44SRaghuram Kothakota 	int		i;
2044df55fdeSJanie Lu 	niumx_ih_t	*ih_p = niumxds_p->niumx_ihtable;
2053266dff7Sjf137018 
206500b1e78SAlan Adamson, SD OSSD 	DBG(NIUMX_DBG_A_INTX, NULL, "niumx_intr_dist entered\n");
2073266dff7Sjf137018 	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;
212c165966dSjf137018 		hrtime_t	start;
213c165966dSjf137018 		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)
2163266dff7Sjf137018 			continue;
2173266dff7Sjf137018 
2183266dff7Sjf137018 		(void) hvio_intr_setvalid(sysino, HV_INTR_NOTVALID);
219c165966dSjf137018 
220c165966dSjf137018 		/* check for pending interrupts, busy wait if so */
221c165966dSjf137018 		for (start = gethrtime(); !panicstr &&
222c165966dSjf137018 		    (hvio_intr_getstate(sysino, &state) == H_EOK) &&
223c165966dSjf137018 		    (state == HV_INTR_DELIVERED_STATE); /* */) {
224c165966dSjf137018 			if (gethrtime() - start > niumx_intr_timeout) {
225c165966dSjf137018 				cmn_err(CE_WARN, "%s%d: niumx_intr_dist: "
226c165966dSjf137018 				    "pending interrupt (%x,%lx) timedout\n",
227c165966dSjf137018 				    ddi_driver_name(dip), ddi_get_instance(dip),
228c165966dSjf137018 				    ih_p->ih_inum, sysino);
229c165966dSjf137018 				(void) hvio_intr_setstate(sysino,
230c165966dSjf137018 				    HV_INTR_IDLE_STATE);
231c165966dSjf137018 				break;
232c165966dSjf137018 			}
233c165966dSjf137018 		}
2343266dff7Sjf137018 		(void) hvio_intr_settarget(sysino, cpuid);
235500b1e78SAlan Adamson, SD OSSD 
236500b1e78SAlan Adamson, SD OSSD 		if (ih_p->ih_state == HV_INTR_VALID)
2373266dff7Sjf137018 			(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 
2413266dff7Sjf137018 		ih_p->ih_cpuid = cpuid;
2423266dff7Sjf137018 	}
2433266dff7Sjf137018 	mutex_exit(lock_p);
2443266dff7Sjf137018 }
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,
25944961713Sgirish 		    DDI_PROP_DONTPASS, "reg", (int **)&reg_p, &reglen)
26044961713Sgirish 		    != 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)
27044961713Sgirish 		    != DDI_SUCCESS) {
27144961713Sgirish 			ret = DDI_FAILURE;
27244961713Sgirish 			goto prop_free;
27344961713Sgirish 		}
27444961713Sgirish 		niumxds_p = (niumx_devstate_t *)ddi_get_soft_state(niumx_state,
27544961713Sgirish 		    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, "
28144961713Sgirish 		    "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 &
28544961713Sgirish 		    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 
2933266dff7Sjf137018 		/* add interrupt redistribution callback */
2944df55fdeSJanie Lu 		intr_dist_add(niumx_intr_dist, niumxds_p);
2953266dff7Sjf137018 
2968fca0570Sjf137018 		niumxds_p->niumx_fm_cap = DDI_FM_EREPORT_CAPABLE;
29714ea4bb7Ssd77468 
29814ea4bb7Ssd77468 		ddi_fm_init(niumxds_p->dip, &niumxds_p->niumx_fm_cap,
29914ea4bb7Ssd77468 		    &niumxds_p->niumx_fm_ibc);
30014ea4bb7Ssd77468 
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);
33514ea4bb7Ssd77468 		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 
3488fca0570Sjf137018 
3498fca0570Sjf137018 /*
3508fca0570Sjf137018  * Function used to initialize FMA for our children nodes. Called
3518fca0570Sjf137018  * through pci busops when child node calls ddi_fm_init.
3528fca0570Sjf137018  */
3538fca0570Sjf137018 /*ARGSUSED*/
3548fca0570Sjf137018 int
niumx_fm_init_child(dev_info_t * dip,dev_info_t * cdip,int cap,ddi_iblock_cookie_t * ibc_p)3558fca0570Sjf137018 niumx_fm_init_child(dev_info_t *dip, dev_info_t *cdip, int cap,
3568fca0570Sjf137018     ddi_iblock_cookie_t *ibc_p)
3578fca0570Sjf137018 {
358500b1e78SAlan Adamson, SD OSSD 	niumx_devstate_t	*niumxds_p = NIUMX_DIP_TO_STATE(dip);
3598fca0570Sjf137018 
3608fca0570Sjf137018 	ASSERT(ibc_p != NULL);
3618fca0570Sjf137018 	*ibc_p = niumxds_p->niumx_fm_ibc;
3628fca0570Sjf137018 
3638fca0570Sjf137018 	return (niumxds_p->niumx_fm_cap);
3648fca0570Sjf137018 }
3658fca0570Sjf137018 
3668fca0570Sjf137018 
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,
37044961713Sgirish 	off_t offset, off_t len, caddr_t *vaddrp)
37144961713Sgirish {
37244961713Sgirish 	struct regspec p_regspec;
37344961713Sgirish 	ddi_map_req_t p_mapreq;
37444961713Sgirish 	niu_regspec_t	*reg_p;
37544961713Sgirish 	int 	i, rn = mp->map_obj.rnumber, reglen, rnglen, rngnum, ret;
37644961713Sgirish 	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,
38444961713Sgirish 	    "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",
39944961713Sgirish 	    (caddr_t)&rng_p, &rnglen) != DDI_SUCCESS) {
400500b1e78SAlan Adamson, SD OSSD 			DBG(NIUMX_DBG_MAP,  dip, "%s%d: no ranges property\n",
40144961713Sgirish 			    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)) >
43144961713Sgirish 	    (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",
44144961713Sgirish 	    p_regspec.regspec_bustype, p_regspec.regspec_addr,
44244961713Sgirish 	    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,
45644961713Sgirish 	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 |
493adf6c93bSjf137018 	    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 
517adf6c93bSjf137018 /*
518adf6c93bSjf137018  * niumx_name_child
519adf6c93bSjf137018  *
520adf6c93bSjf137018  * This function is called from init_child to name a node. It is
521adf6c93bSjf137018  * also passed as a callback for node merging functions.
522adf6c93bSjf137018  *
523adf6c93bSjf137018  * return value: DDI_SUCCESS, DDI_FAILURE
524adf6c93bSjf137018  */
525adf6c93bSjf137018 static int
niumx_name_child(dev_info_t * child,char * name,int namelen)526adf6c93bSjf137018 niumx_name_child(dev_info_t *child, char *name, int namelen)
527adf6c93bSjf137018 {
528adf6c93bSjf137018 	niu_regspec_t *r;
529adf6c93bSjf137018 	uint_t n;
530adf6c93bSjf137018 
531500b1e78SAlan Adamson, SD OSSD 	DBG(NIUMX_DBG_CHK_MOD, (dev_info_t *)child, "==> niumx_name_child\n");
532adf6c93bSjf137018 
533adf6c93bSjf137018 	if (ndi_dev_is_persistent_node(child) == 0) {
534adf6c93bSjf137018 		char **unit_addr;
535adf6c93bSjf137018 
536adf6c93bSjf137018 		/* name .conf nodes by "unit-address" property */
537adf6c93bSjf137018 		if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, child,
538adf6c93bSjf137018 		    DDI_PROP_DONTPASS, "unit-address", &unit_addr, &n) !=
539adf6c93bSjf137018 		    DDI_PROP_SUCCESS) {
540adf6c93bSjf137018 			cmn_err(CE_WARN, "cannot name node from %s.conf",
541adf6c93bSjf137018 			    ddi_driver_name(child));
542adf6c93bSjf137018 			return (DDI_FAILURE);
543adf6c93bSjf137018 		}
544adf6c93bSjf137018 		if (n != 1 || *unit_addr == NULL || **unit_addr == 0) {
545adf6c93bSjf137018 			cmn_err(CE_WARN, "unit-address property in %s.conf"
546adf6c93bSjf137018 			    " not well-formed", ddi_driver_name(child));
547adf6c93bSjf137018 			ddi_prop_free(unit_addr);
548adf6c93bSjf137018 			return (DDI_FAILURE);
549adf6c93bSjf137018 		}
550adf6c93bSjf137018 
551adf6c93bSjf137018 		(void) snprintf(name, namelen, "%s", *unit_addr);
552adf6c93bSjf137018 		ddi_prop_free(unit_addr);
553adf6c93bSjf137018 		return (DDI_SUCCESS);
554adf6c93bSjf137018 	}
555adf6c93bSjf137018 
556adf6c93bSjf137018 	/* name hardware nodes by "reg" property */
557adf6c93bSjf137018 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
558adf6c93bSjf137018 	    "reg", (int **)&r, &n) != DDI_SUCCESS) {
559adf6c93bSjf137018 		cmn_err(CE_WARN, "reg property not well-formed");
560adf6c93bSjf137018 		return (DDI_FAILURE);
561adf6c93bSjf137018 	}
562678453a8Sspeer 	(void) snprintf(name, namelen, "%x", (r[0].addr_high));
563adf6c93bSjf137018 	ddi_prop_free(r);
564adf6c93bSjf137018 	return (DDI_SUCCESS);
565adf6c93bSjf137018 }
566adf6c93bSjf137018 
56744961713Sgirish static int
niumx_initchild(dev_info_t * child)56844961713Sgirish niumx_initchild(dev_info_t *child)
56944961713Sgirish {
57044961713Sgirish 	char name[MAXNAMELEN];
571adf6c93bSjf137018 
572500b1e78SAlan Adamson, SD OSSD 	DBG(NIUMX_DBG_CHK_MOD, (dev_info_t *)child, "==> niumx_initchild\n");
573adf6c93bSjf137018 	/*
574adf6c93bSjf137018 	 * Non-peristent nodes indicate a prototype node with per-instance
575adf6c93bSjf137018 	 * properties to be merged into the real h/w device node.
576adf6c93bSjf137018 	 */
577adf6c93bSjf137018 	if (ndi_dev_is_persistent_node(child) == 0) {
57844961713Sgirish 		niu_regspec_t *r;
57944961713Sgirish 		uint_t n;
58044961713Sgirish 
581adf6c93bSjf137018 		if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child,
582adf6c93bSjf137018 		    DDI_PROP_DONTPASS, "reg", (int **)&r, &n) ==
583adf6c93bSjf137018 		    DDI_SUCCESS) {
584adf6c93bSjf137018 			cmn_err(CE_WARN,
585adf6c93bSjf137018 			    "cannot merge prototype from %s.conf",
586adf6c93bSjf137018 			    ddi_driver_name(child));
587adf6c93bSjf137018 			ddi_prop_free(r);
588adf6c93bSjf137018 			return (DDI_NOT_WELL_FORMED);
589adf6c93bSjf137018 		}
590adf6c93bSjf137018 
591adf6c93bSjf137018 		if (niumx_name_child(child, name, MAXNAMELEN) != DDI_SUCCESS)
592adf6c93bSjf137018 			return (DDI_NOT_WELL_FORMED);
593adf6c93bSjf137018 
594adf6c93bSjf137018 		ddi_set_name_addr(child, name);
595adf6c93bSjf137018 		ddi_set_parent_data(child, NULL);
596adf6c93bSjf137018 
597adf6c93bSjf137018 		/*
598adf6c93bSjf137018 		 * Try to merge the properties from this prototype
599adf6c93bSjf137018 		 * node into real h/w nodes.
600adf6c93bSjf137018 		 */
601adf6c93bSjf137018 		if (ndi_merge_node(child, niumx_name_child) == DDI_SUCCESS) {
602adf6c93bSjf137018 			/*
603adf6c93bSjf137018 			 * Merged ok - return failure to remove the node.
604adf6c93bSjf137018 			 */
605adf6c93bSjf137018 			ddi_set_name_addr(child, NULL);
60644961713Sgirish 			return (DDI_FAILURE);
60744961713Sgirish 		}
608adf6c93bSjf137018 
609adf6c93bSjf137018 		/*
610adf6c93bSjf137018 		 * The child was not merged into a h/w node,
611adf6c93bSjf137018 		 * but there's not much we can do with it other
612adf6c93bSjf137018 		 * than return failure to cause the node to be removed.
613adf6c93bSjf137018 		 */
614adf6c93bSjf137018 		cmn_err(CE_WARN, "!%s@%s: %s.conf properties not merged",
615adf6c93bSjf137018 		    ddi_driver_name(child), ddi_get_name_addr(child),
616adf6c93bSjf137018 		    ddi_driver_name(child));
617adf6c93bSjf137018 		ddi_set_name_addr(child, NULL);
618adf6c93bSjf137018 		return (DDI_NOT_WELL_FORMED);
619adf6c93bSjf137018 	}
620adf6c93bSjf137018 
621adf6c93bSjf137018 	/*
622adf6c93bSjf137018 	 * Initialize real h/w nodes
623adf6c93bSjf137018 	 */
624adf6c93bSjf137018 	if (niumx_name_child(child, name, MAXNAMELEN) != DDI_SUCCESS)
625adf6c93bSjf137018 		return (DDI_FAILURE);
626adf6c93bSjf137018 
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,
64744961713Sgirish 	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;
66844961713Sgirish 	mp->dmai_fault = 0;
66944961713Sgirish 	mp->dmai_fault_check = NULL;
67044961713Sgirish 	mp->dmai_fault_notify = NULL;
67144961713Sgirish 
67244961713Sgirish 	mp->dmai_attr = *attrp; 	/* set requestors attr info */
67344961713Sgirish 
674500b1e78SAlan Adamson, SD OSSD 	DBG(NIUMX_DBG_DMA_ALLOCH, dip, "mp=%p\n", mp);
67544961713Sgirish 
67644961713Sgirish 	*handlep = (ddi_dma_handle_t)mp;
67744961713Sgirish 	return (DDI_SUCCESS);
67844961713Sgirish }
67944961713Sgirish 
68044961713Sgirish 
68144961713Sgirish /*
68244961713Sgirish  * bus dma free handle entry point:
68344961713Sgirish  */
68444961713Sgirish /*ARGSUSED*/
68544961713Sgirish int
niumx_dma_freehdl(dev_info_t * dip,dev_info_t * rdip,ddi_dma_handle_t handle)68644961713Sgirish niumx_dma_freehdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t handle)
68744961713Sgirish {
68844961713Sgirish 	ddi_dma_impl_t *mp = (ddi_dma_impl_t *)handle;
68944961713Sgirish 
69044961713Sgirish 	if (mp->dmai_cookie)
69144961713Sgirish 		kmem_free(mp->dmai_cookie, sizeof (ddi_dma_cookie_t));
69244961713Sgirish 	kmem_free(mp, sizeof (ddi_dma_impl_t));
69344961713Sgirish 
69444961713Sgirish 	return (DDI_SUCCESS);
69544961713Sgirish }
69644961713Sgirish 
69744961713Sgirish 
69844961713Sgirish /*
69944961713Sgirish  * bus dma bind handle entry point:
70044961713Sgirish  *
70144961713Sgirish  *	check/enforce DMA type, setup pfn0 and some other key pieces
70244961713Sgirish  *	of this dma request.
70344961713Sgirish  * Note: this only works with DMA_OTYP_VADDR, and makes use of the known
70444961713Sgirish  *	fact that only contiguous memory blocks will be passed in.
70544961713Sgirish  *	Therefore only one cookie will ever be returned.
70644961713Sgirish  *
70744961713Sgirish  *	return values:
70844961713Sgirish  *		DDI_DMA_NOMAPPING - can't get valid pfn0, or bad dma type
70944961713Sgirish  *		DDI_DMA_NORESOURCES
71044961713Sgirish  *		DDI_SUCCESS
71144961713Sgirish  *
71244961713Sgirish  *	dma handle members affected (set on exit):
71344961713Sgirish  *	mp->dmai_object		- dmareq->dmar_object
71444961713Sgirish  *	mp->dmai_rflags		- dmareq->dmar_flags
71544961713Sgirish  *	mp->dmai_pfn0   	- 1st page pfn (if va/size pair and not shadow)
71644961713Sgirish  *	mp->dmai_roffset 	- initialized to starting page offset
71744961713Sgirish  *	mp->dmai_size		- # of total pages of entire object
71844961713Sgirish  *	mp->dmai_cookie		- new cookie alloc'd
71944961713Sgirish  */
72044961713Sgirish /*ARGSUSED*/
72144961713Sgirish 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)72244961713Sgirish niumx_dma_bindhdl(dev_info_t *dip, dev_info_t *rdip,
72344961713Sgirish 	ddi_dma_handle_t handle, ddi_dma_req_t *dmareq,
72444961713Sgirish 	ddi_dma_cookie_t *cookiep, uint_t *ccountp)
72544961713Sgirish {
72644961713Sgirish 	int (*waitfp)(caddr_t) = dmareq->dmar_fp;
72744961713Sgirish 	ddi_dma_impl_t *mp = (ddi_dma_impl_t *)handle;
72844961713Sgirish 	ddi_dma_obj_t *dobj_p = &dmareq->dmar_object;
72944961713Sgirish 	uint32_t offset;
73044961713Sgirish 	pfn_t pfn0;
73144961713Sgirish 	int ret;
73244961713Sgirish 
733500b1e78SAlan Adamson, SD OSSD 	DBG(NIUMX_DBG_DMA_BINDH, dip, "rdip=%s%d mp=%p dmareq=%p\n",
734500b1e78SAlan Adamson, SD OSSD 	    NIUMX_NAMEINST(rdip), mp, dmareq);
73544961713Sgirish 
73644961713Sgirish 	/* first check dma type */
73744961713Sgirish 	mp->dmai_rflags = dmareq->dmar_flags & DMP_DDIFLAGS | DMP_NOSYNC;
73844961713Sgirish 	switch (dobj_p->dmao_type) {
73944961713Sgirish 	case DMA_OTYP_VADDR: {
74044961713Sgirish 		caddr_t vaddr = dobj_p->dmao_obj.virt_obj.v_addr;
74144961713Sgirish 		struct as *as_p = dobj_p->dmao_obj.virt_obj.v_as;
74244961713Sgirish 		struct hat *hat_p = as_p ? as_p->a_hat : kas.a_hat;
74344961713Sgirish 		offset = (ulong_t)vaddr & NIUMX_PAGE_OFFSET;
74444961713Sgirish 		pfn0 = hat_getpfnum(hat_p, vaddr);
74544961713Sgirish 		}
74644961713Sgirish 		break;
74744961713Sgirish 
74844961713Sgirish 	case DMA_OTYP_BUFVADDR:
74944961713Sgirish 	case DMA_OTYP_PAGES:
75044961713Sgirish 	case DMA_OTYP_PADDR:
75144961713Sgirish 	default:
75244961713Sgirish 		cmn_err(CE_WARN, "%s%d requested unsupported dma type %x",
753500b1e78SAlan Adamson, SD OSSD 		    NIUMX_NAMEINST(mp->dmai_rdip), dobj_p->dmao_type);
75444961713Sgirish 		ret = DDI_DMA_NOMAPPING;
75544961713Sgirish 		goto err;
75644961713Sgirish 	}
75744961713Sgirish 	if (pfn0 == PFN_INVALID) {
75844961713Sgirish 		cmn_err(CE_WARN, "%s%d: invalid pfn0 for DMA object %p",
759500b1e78SAlan Adamson, SD OSSD 		    NIUMX_NAMEINST(dip), (void *)dobj_p);
76044961713Sgirish 		ret = DDI_DMA_NOMAPPING;
76144961713Sgirish 		goto err;
76244961713Sgirish 	}
76344961713Sgirish 	mp->dmai_object	 = *dobj_p;			/* whole object */
76444961713Sgirish 	mp->dmai_pfn0	 = (void *)pfn0;		/* cache pfn0   */
76544961713Sgirish 	mp->dmai_roffset = offset;			/* pg0 offset   */
76644961713Sgirish 	mp->dmai_mapping = mp->dmai_roffset | NIUMX_PTOB(pfn0);
76744961713Sgirish 	mp->dmai_size = mp->dmai_object.dmao_size;
76844961713Sgirish 
769500b1e78SAlan Adamson, SD OSSD 	DBG(NIUMX_DBG_DMA_BINDH, dip, "check pfn: mp=%p pfn0=%x\n",
77044961713Sgirish 	    mp, mp->dmai_pfn0);
77144961713Sgirish 	if (!(mp->dmai_cookie = kmem_zalloc(sizeof (ddi_dma_cookie_t),
77244961713Sgirish 	    waitfp == DDI_DMA_SLEEP ? KM_SLEEP : KM_NOSLEEP))) {
77344961713Sgirish 			ret = DDI_DMA_NORESOURCES;
77444961713Sgirish 			goto err;
77544961713Sgirish 		}
77644961713Sgirish 	mp->dmai_cookie->dmac_laddress = mp->dmai_mapping;
77744961713Sgirish 	mp->dmai_cookie->dmac_size = mp->dmai_size;
77844961713Sgirish 	*ccountp = 1;
77944961713Sgirish 	*cookiep = *mp->dmai_cookie;
780500b1e78SAlan Adamson, SD OSSD 	DBG(NIUMX_DBG_DMA_BINDH, dip, "cookie %" PRIx64 "+%x, count=%d\n",
78144961713Sgirish 	    cookiep->dmac_address, cookiep->dmac_size, *ccountp);
78244961713Sgirish 	return (DDI_DMA_MAPPED);
78344961713Sgirish 
78444961713Sgirish err:
785500b1e78SAlan Adamson, SD OSSD 	DBG(NIUMX_DBG_DMA_BINDH, (dev_info_t *)dip,
78644961713Sgirish 	    "niumx_dma_bindhdl error ret=%d\n", ret);
78744961713Sgirish 	return (ret);
78844961713Sgirish }
78944961713Sgirish 
79044961713Sgirish /*
79144961713Sgirish  * bus dma unbind handle entry point:
79244961713Sgirish  */
79344961713Sgirish /*ARGSUSED*/
79444961713Sgirish int
niumx_dma_unbindhdl(dev_info_t * dip,dev_info_t * rdip,ddi_dma_handle_t handle)79544961713Sgirish niumx_dma_unbindhdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t handle)
79644961713Sgirish {
79744961713Sgirish 	ddi_dma_impl_t *mp = (ddi_dma_impl_t *)handle;
79844961713Sgirish 
799500b1e78SAlan Adamson, SD OSSD 	DBG(NIUMX_DBG_DMA_UNBINDH, dip, "rdip=%s%d, mp=%p\n",
80044961713Sgirish 	    ddi_driver_name(rdip), ddi_get_instance(rdip), handle);
80144961713Sgirish 	if (mp->dmai_cookie) {
80244961713Sgirish 		kmem_free(mp->dmai_cookie, sizeof (ddi_dma_cookie_t));
80344961713Sgirish 		mp->dmai_cookie = NULL;
80444961713Sgirish 	}
80544961713Sgirish 
80644961713Sgirish 	return (DDI_SUCCESS);
80744961713Sgirish }
80844961713Sgirish 
80944961713Sgirish /*ARGSUSED*/
81044961713Sgirish 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)81144961713Sgirish niumx_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
81244961713Sgirish     ddi_intr_handle_impl_t *hdlp, void *result)
81344961713Sgirish {
81444961713Sgirish 
81544961713Sgirish 	int	ret = DDI_SUCCESS;
81644961713Sgirish 
817500b1e78SAlan Adamson, SD OSSD 	DBG(NIUMX_DBG_INTROPS, dip, "niumx_intr_ops: dip=%p rdip=%p intr_op=%x "
81844961713Sgirish 	    "handle=%p\n", dip, rdip, intr_op, hdlp);
81944961713Sgirish 
82044961713Sgirish 	switch (intr_op) {
82144961713Sgirish 
82244961713Sgirish 	case DDI_INTROP_SUPPORTED_TYPES:
82344961713Sgirish 		*(int *)result = DDI_INTR_TYPE_FIXED;
82444961713Sgirish 		break;
82544961713Sgirish 	case DDI_INTROP_GETCAP:
826*657f87deSgongtian zhao - Sun Microsystems - Beijing China 		*(int *)result =  DDI_INTR_FLAG_LEVEL;
82744961713Sgirish 		break;
82844961713Sgirish 	case DDI_INTROP_SETCAP:
82944961713Sgirish 		ret = DDI_ENOTSUP;
83044961713Sgirish 		break;
83144961713Sgirish 	case DDI_INTROP_ALLOC:
83244961713Sgirish 		/*  scratch1 = count,  # of intrs from DDI framework */
83344961713Sgirish 		*(int *)result = hdlp->ih_scratch1;
83444961713Sgirish 		break;
83544961713Sgirish 	case DDI_INTROP_FREE:
83644961713Sgirish 		/* Do we need to do anything here?  */
83744961713Sgirish 		break;
83844961713Sgirish 	case DDI_INTROP_GETPRI:
83944961713Sgirish 		*(int *)result = NIUMX_DEFAULT_PIL;
84044961713Sgirish 		break;
84144961713Sgirish 	case DDI_INTROP_SETPRI:
84244961713Sgirish 		ret = DDI_ENOTSUP;
84344961713Sgirish 		break;
84444961713Sgirish 	case DDI_INTROP_ADDISR:
84544961713Sgirish 		ret = niumx_add_intr(dip, rdip, hdlp);
84644961713Sgirish 		break;
84744961713Sgirish 	case DDI_INTROP_REMISR:
84844961713Sgirish 		ret = niumx_rem_intr(dip, rdip, hdlp);
84944961713Sgirish 		break;
85044961713Sgirish 	case DDI_INTROP_ENABLE:
85144961713Sgirish 		ret = niumx_set_intr(dip, rdip, hdlp, HV_INTR_VALID);
85244961713Sgirish 		break;
85344961713Sgirish 	case DDI_INTROP_DISABLE:
85444961713Sgirish 		ret = niumx_set_intr(dip, rdip, hdlp, HV_INTR_NOTVALID);
85544961713Sgirish 		break;
85644961713Sgirish 	case DDI_INTROP_SETMASK:
85744961713Sgirish 		ret = DDI_ENOTSUP;
85844961713Sgirish 		break;
85944961713Sgirish 	case DDI_INTROP_CLRMASK:
86044961713Sgirish 		ret = DDI_ENOTSUP;
86144961713Sgirish 		break;
86244961713Sgirish 	case DDI_INTROP_GETPENDING:
86344961713Sgirish 		ret = DDI_ENOTSUP;
86444961713Sgirish 		break;
86544961713Sgirish 	case DDI_INTROP_NINTRS:
86644961713Sgirish 	case DDI_INTROP_NAVAIL: {
867500b1e78SAlan Adamson, SD OSSD 		niudevino_t	*inos_p;
86844961713Sgirish 		int		inoslen;
869500b1e78SAlan Adamson, SD OSSD 
87044961713Sgirish 		if (ddi_getlongprop(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS,
87144961713Sgirish 		    "interrupts", (caddr_t)&inos_p, &inoslen)
87244961713Sgirish 		    != DDI_SUCCESS) {
87344961713Sgirish 			ret = DDI_FAILURE;
87444961713Sgirish 			break;
87544961713Sgirish 			}
87644961713Sgirish 		*(int *)result = inoslen / sizeof (uint32_t);
87744961713Sgirish 		kmem_free(inos_p, inoslen);
87844961713Sgirish 		}
87944961713Sgirish 		break;
880500b1e78SAlan Adamson, SD OSSD 	case DDI_INTROP_GETTARGET: {
881500b1e78SAlan Adamson, SD OSSD 		niumx_devstate_t *niumxds_p;
882500b1e78SAlan Adamson, SD OSSD 
883500b1e78SAlan Adamson, SD OSSD 		niumxds_p = (niumx_devstate_t *)ddi_get_soft_state(niumx_state,
884500b1e78SAlan Adamson, SD OSSD 		    ddi_get_instance(dip));
885500b1e78SAlan Adamson, SD OSSD 
886500b1e78SAlan Adamson, SD OSSD 		ret = niumx_get_intr_target(niumxds_p, hdlp->ih_vector,
887500b1e78SAlan Adamson, SD OSSD 		    (niucpuid_t *)result);
888500b1e78SAlan Adamson, SD OSSD 
889500b1e78SAlan Adamson, SD OSSD 		}
890500b1e78SAlan Adamson, SD OSSD 		break;
891500b1e78SAlan Adamson, SD OSSD 	case DDI_INTROP_SETTARGET: {
892500b1e78SAlan Adamson, SD OSSD 		niumx_devstate_t *niumxds_p;
893500b1e78SAlan Adamson, SD OSSD 
894500b1e78SAlan Adamson, SD OSSD 		niumxds_p = (niumx_devstate_t *)ddi_get_soft_state(niumx_state,
895500b1e78SAlan Adamson, SD OSSD 		    ddi_get_instance(dip));
896500b1e78SAlan Adamson, SD OSSD 
897500b1e78SAlan Adamson, SD OSSD 		ret = niumx_set_intr_target(niumxds_p, hdlp->ih_vector,
898500b1e78SAlan Adamson, SD OSSD 		    *(niucpuid_t *)result);
899500b1e78SAlan Adamson, SD OSSD 
900500b1e78SAlan Adamson, SD OSSD 		}
901500b1e78SAlan Adamson, SD OSSD 		break;
90244961713Sgirish 	default:
90344961713Sgirish 		ret = DDI_ENOTSUP;
90444961713Sgirish 		break;
90544961713Sgirish 	}
90644961713Sgirish 
907500b1e78SAlan Adamson, SD OSSD 	DBG(NIUMX_DBG_INTROPS, dip, "niumx_intr_ops: ret=%d\n", ret);
90844961713Sgirish 	return (ret);
90944961713Sgirish }
91044961713Sgirish 
91144961713Sgirish int
niumx_set_intr(dev_info_t * dip,dev_info_t * rdip,ddi_intr_handle_impl_t * hdlp,int valid)91244961713Sgirish niumx_set_intr(dev_info_t *dip, dev_info_t *rdip,
91344961713Sgirish     ddi_intr_handle_impl_t *hdlp, int valid)
91444961713Sgirish {
91544961713Sgirish 	niumx_ih_t	*ih_p;
916500b1e78SAlan Adamson, SD OSSD 	int		ret = DDI_SUCCESS;
91744961713Sgirish 	uint64_t	hvret;
9184df55fdeSJanie Lu 	niumx_devstate_t	*niumxds_p;	/* devstate pointer */
9194df55fdeSJanie Lu 	int 		instance = ddi_get_instance(dip);
9204df55fdeSJanie Lu 
9214df55fdeSJanie Lu 	niumxds_p = (niumx_devstate_t *)ddi_get_soft_state(niumx_state,
9224df55fdeSJanie Lu 	    instance);
92344961713Sgirish 
92444961713Sgirish 	ASSERT(hdlp->ih_inum < NIUMX_MAX_INTRS);
92544961713Sgirish 
926500b1e78SAlan Adamson, SD OSSD 	ih_p = niumxds_p->niumx_ihtable +  hdlp->ih_vector;
9274df55fdeSJanie Lu 
928500b1e78SAlan Adamson, SD OSSD 	DBG(NIUMX_DBG_A_INTX, dip,
929500b1e78SAlan Adamson, SD OSSD 	    "niumx_set_intr: rdip=%s%d, valid=%d %s (%x,%x)\n",
930500b1e78SAlan Adamson, SD OSSD 	    NIUMX_NAMEINST(rdip), valid, valid ? "enabling" : "disabling",
9318fca0570Sjf137018 	    ih_p->ih_inum, ih_p->ih_sysino);
93244961713Sgirish 
933cb343a2eSspeer 	if (valid == HV_INTR_VALID)
934cb343a2eSspeer 		(void) hvio_intr_setstate(ih_p->ih_sysino, HV_INTR_IDLE_STATE);
93544961713Sgirish 	if ((hvret = hvio_intr_setvalid(ih_p->ih_sysino, valid))
93644961713Sgirish 	    != H_EOK) {
937500b1e78SAlan Adamson, SD OSSD 		DBG(NIUMX_DBG_A_INTX, dip,
938500b1e78SAlan Adamson, SD OSSD 		    "hvio_intr_setvalid failed, ret 0x%x\n", hvret);
93944961713Sgirish 		ret = DDI_FAILURE;
940500b1e78SAlan Adamson, SD OSSD 	} else
941500b1e78SAlan Adamson, SD OSSD 		ih_p->ih_state = valid;
942500b1e78SAlan Adamson, SD OSSD 
94344961713Sgirish 	return (ret);
94444961713Sgirish }
94544961713Sgirish 
946500b1e78SAlan Adamson, SD OSSD int
niumx_get_intr_target(niumx_devstate_t * niumxds_p,niudevino_t ino,niucpuid_t * cpu_id)947500b1e78SAlan Adamson, SD OSSD niumx_get_intr_target(niumx_devstate_t *niumxds_p, niudevino_t ino,
948500b1e78SAlan Adamson, SD OSSD     niucpuid_t *cpu_id)
949500b1e78SAlan Adamson, SD OSSD {
950500b1e78SAlan Adamson, SD OSSD 	niumx_ih_t *ih_p;
951500b1e78SAlan Adamson, SD OSSD 	niusysino_t sysino;
952500b1e78SAlan Adamson, SD OSSD 	int rval = DDI_SUCCESS;
953500b1e78SAlan Adamson, SD OSSD 
954500b1e78SAlan Adamson, SD OSSD 	ih_p = niumxds_p->niumx_ihtable + ino;
955500b1e78SAlan Adamson, SD OSSD 
956500b1e78SAlan Adamson, SD OSSD 	sysino = ih_p->ih_sysino;
957500b1e78SAlan Adamson, SD OSSD 
958500b1e78SAlan Adamson, SD OSSD 	if (sysino == 0) {
959500b1e78SAlan Adamson, SD OSSD 		rval = EINVAL;
960500b1e78SAlan Adamson, SD OSSD 		goto done;
961500b1e78SAlan Adamson, SD OSSD 	}
962500b1e78SAlan Adamson, SD OSSD 
963500b1e78SAlan Adamson, SD OSSD 	if (hvio_intr_gettarget(sysino, cpu_id) != H_EOK) {
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 (ih_p->ih_cpuid != *cpu_id)
969500b1e78SAlan Adamson, SD OSSD 		rval = EIO;
970500b1e78SAlan Adamson, SD OSSD 
971500b1e78SAlan Adamson, SD OSSD done:
972500b1e78SAlan Adamson, SD OSSD 	return (rval);
973500b1e78SAlan Adamson, SD OSSD }
974500b1e78SAlan Adamson, SD OSSD 
975500b1e78SAlan Adamson, SD OSSD int
niumx_set_intr_target(niumx_devstate_t * niumxds_p,niudevino_t ino,niucpuid_t cpu_id)976500b1e78SAlan Adamson, SD OSSD niumx_set_intr_target(niumx_devstate_t *niumxds_p, niudevino_t ino,
977500b1e78SAlan Adamson, SD OSSD     niucpuid_t cpu_id)
978500b1e78SAlan Adamson, SD OSSD {
979500b1e78SAlan Adamson, SD OSSD 	dev_info_t *dip = niumxds_p->dip;
980500b1e78SAlan Adamson, SD OSSD 	niumx_ih_t *ih_p;
981500b1e78SAlan Adamson, SD OSSD 	niucpuid_t old_cpu_id;
982500b1e78SAlan Adamson, SD OSSD 	niusysino_t sysino;
983500b1e78SAlan Adamson, SD OSSD 	int ret = DDI_SUCCESS;
984500b1e78SAlan Adamson, SD OSSD 	int state;
985500b1e78SAlan Adamson, SD OSSD 	hrtime_t start;
986500b1e78SAlan Adamson, SD OSSD 	extern const int _ncpu;
987500b1e78SAlan Adamson, SD OSSD 	extern cpu_t *cpu[];
988500b1e78SAlan Adamson, SD OSSD 
989500b1e78SAlan Adamson, SD OSSD 	mutex_enter(&cpu_lock);
990500b1e78SAlan Adamson, SD OSSD 
991500b1e78SAlan Adamson, SD OSSD 	ih_p = niumxds_p->niumx_ihtable + ino;
992500b1e78SAlan Adamson, SD OSSD 
993500b1e78SAlan Adamson, SD OSSD 	sysino = ih_p->ih_sysino;
994500b1e78SAlan Adamson, SD OSSD 	if (sysino == 0) {
995500b1e78SAlan Adamson, SD OSSD 		ret = EINVAL;
996500b1e78SAlan Adamson, SD OSSD 		goto done;
997500b1e78SAlan Adamson, SD OSSD 	}
998500b1e78SAlan Adamson, SD OSSD 
999500b1e78SAlan Adamson, SD OSSD 	if (hvio_intr_gettarget(sysino, &old_cpu_id) != H_EOK) {
1000500b1e78SAlan Adamson, SD OSSD 		ret = EINVAL;
1001500b1e78SAlan Adamson, SD OSSD 		goto done;
1002500b1e78SAlan Adamson, SD OSSD 	}
1003500b1e78SAlan Adamson, SD OSSD 	if ((cpu_id < _ncpu) && (cpu[cpu_id] && cpu_is_online(cpu[cpu_id]))) {
1004500b1e78SAlan Adamson, SD OSSD 		if (cpu_id == old_cpu_id)
1005500b1e78SAlan Adamson, SD OSSD 			goto done;
1006500b1e78SAlan Adamson, SD OSSD 
1007500b1e78SAlan Adamson, SD OSSD 		/* check for pending interrupts, busy wait if so */
1008500b1e78SAlan Adamson, SD OSSD 		for (start = gethrtime(); !panicstr &&
1009500b1e78SAlan Adamson, SD OSSD 		    (hvio_intr_getstate(sysino, &state) == H_EOK) &&
1010500b1e78SAlan Adamson, SD OSSD 		    (state == HV_INTR_DELIVERED_STATE); /* */) {
1011500b1e78SAlan Adamson, SD OSSD 			if (gethrtime() - start > niumx_intr_timeout) {
1012500b1e78SAlan Adamson, SD OSSD 				cmn_err(CE_WARN, "%s%d: niumx_intr_dist: "
1013500b1e78SAlan Adamson, SD OSSD 				    "pending interrupt (%x,%lx) timedout\n",
1014500b1e78SAlan Adamson, SD OSSD 				    ddi_driver_name(dip), ddi_get_instance(dip),
1015500b1e78SAlan Adamson, SD OSSD 				    ih_p->ih_inum, sysino);
1016500b1e78SAlan Adamson, SD OSSD 				(void) hvio_intr_setstate(sysino,
1017500b1e78SAlan Adamson, SD OSSD 				    HV_INTR_IDLE_STATE);
1018500b1e78SAlan Adamson, SD OSSD 				break;
1019500b1e78SAlan Adamson, SD OSSD 			}
1020500b1e78SAlan Adamson, SD OSSD 		}
1021500b1e78SAlan Adamson, SD OSSD 		(void) hvio_intr_settarget(sysino, cpu_id);
1022500b1e78SAlan Adamson, SD OSSD 		if (ih_p->ih_state == HV_INTR_VALID)
1023500b1e78SAlan Adamson, SD OSSD 			(void) hvio_intr_setvalid(sysino, HV_INTR_VALID);
1024500b1e78SAlan Adamson, SD OSSD 		else
1025500b1e78SAlan Adamson, SD OSSD 			(void) hvio_intr_setvalid(sysino, HV_INTR_NOTVALID);
1026500b1e78SAlan Adamson, SD OSSD 		ih_p->ih_cpuid = cpu_id;
1027500b1e78SAlan Adamson, SD OSSD 	} else {
1028500b1e78SAlan Adamson, SD OSSD 		ret = DDI_EINVAL;
1029500b1e78SAlan Adamson, SD OSSD 	}
1030500b1e78SAlan Adamson, SD OSSD 
1031500b1e78SAlan Adamson, SD OSSD done:
1032500b1e78SAlan Adamson, SD OSSD 	mutex_exit(&cpu_lock);
1033500b1e78SAlan Adamson, SD OSSD 	return (ret);
1034500b1e78SAlan Adamson, SD OSSD }
103544961713Sgirish 
103644961713Sgirish 
103744961713Sgirish /*
103844961713Sgirish  * niumx_add_intr:
103944961713Sgirish  *
1040e778ae44SRaghuram Kothakota  * This function is called to register interrupts.
104144961713Sgirish  */
104244961713Sgirish int
niumx_add_intr(dev_info_t * dip,dev_info_t * rdip,ddi_intr_handle_impl_t * hdlp)104344961713Sgirish niumx_add_intr(dev_info_t *dip, dev_info_t *rdip,
104444961713Sgirish     ddi_intr_handle_impl_t *hdlp)
104544961713Sgirish {
104644961713Sgirish 	niumx_ih_t	*ih_p;
1047500b1e78SAlan Adamson, SD OSSD 	int		ret = DDI_SUCCESS;
104844961713Sgirish 	uint64_t	hvret;
1049500b1e78SAlan Adamson, SD OSSD 	niusysino_t	sysino;
10504df55fdeSJanie Lu 	niumx_devstate_t	*niumxds_p;	/* devstate pointer */
10514df55fdeSJanie Lu 	int		instance = ddi_get_instance(dip);
10524df55fdeSJanie Lu 
10534df55fdeSJanie Lu 	niumxds_p = (niumx_devstate_t *)ddi_get_soft_state(niumx_state,
10544df55fdeSJanie Lu 	    instance);
105544961713Sgirish 
105644961713Sgirish 	/* get new ino */
105744961713Sgirish 	if (hdlp->ih_inum >= NIUMX_MAX_INTRS) {
1058500b1e78SAlan Adamson, SD OSSD 		DBG(NIUMX_DBG_INTR, dip, "error: inum %d out of range\n",
105944961713Sgirish 		    hdlp->ih_inum);
106044961713Sgirish 		ret = DDI_FAILURE;
106144961713Sgirish 		goto done;
106244961713Sgirish 	}
1063500b1e78SAlan Adamson, SD OSSD 
1064500b1e78SAlan Adamson, SD OSSD 	ih_p = niumxds_p->niumx_ihtable + hdlp->ih_vector;
1065500b1e78SAlan Adamson, SD OSSD 
1066500b1e78SAlan Adamson, SD OSSD 	if ((hvret = hvio_intr_devino_to_sysino(NIUMX_DIP_TO_HANDLE(dip),
1067500b1e78SAlan Adamson, SD OSSD 	    hdlp->ih_vector, &sysino)) != H_EOK) {
1068500b1e78SAlan Adamson, SD OSSD 		DBG(NIUMX_DBG_INTR, dip, "hvio_intr_devino_to_sysino failed, "
106944961713Sgirish 		    "ret 0x%x\n", hvret);
107044961713Sgirish 		ret = DDI_FAILURE;
107144961713Sgirish 		goto done;
107244961713Sgirish 	}
107344961713Sgirish 	ih_p->ih_sysino = sysino;
1074500b1e78SAlan Adamson, SD OSSD 	ih_p->ih_dip = rdip;
107544961713Sgirish 	ih_p->ih_inum = hdlp->ih_inum;
107644961713Sgirish 	ih_p->ih_hdlr = hdlp->ih_cb_func;
107744961713Sgirish 	ih_p->ih_arg1 = hdlp->ih_cb_arg1;
107844961713Sgirish 	ih_p->ih_arg2 = hdlp->ih_cb_arg2;
107944961713Sgirish 
1080500b1e78SAlan Adamson, SD OSSD 	DBG(NIUMX_DBG_A_INTX, dip, "niumx_add_intr: rdip=%s%d inum=0x%x "
1081500b1e78SAlan Adamson, SD OSSD 	    "handler=%p arg1=%p arg2=%p, new ih_p = %p\n", NIUMX_NAMEINST(rdip),
108244961713Sgirish 	    hdlp->ih_inum, hdlp->ih_cb_func, hdlp->ih_cb_arg1,
108344961713Sgirish 	    hdlp->ih_cb_arg2, ih_p);
108444961713Sgirish 
108544961713Sgirish 	if (hdlp->ih_pri == 0)
108644961713Sgirish 		hdlp->ih_pri = NIUMX_DEFAULT_PIL;
108744961713Sgirish 
1088500b1e78SAlan Adamson, SD OSSD 	ih_p->ih_pri = hdlp->ih_pri;
1089500b1e78SAlan Adamson, SD OSSD 
1090500b1e78SAlan Adamson, SD OSSD 	DBG(NIUMX_DBG_A_INTX, dip, "for ino %x adding (%x,%x)\n",
1091500b1e78SAlan Adamson, SD OSSD 	    hdlp->ih_vector, ih_p->ih_inum, ih_p->ih_sysino);
1092500b1e78SAlan Adamson, SD OSSD 
109344961713Sgirish 	/* Save sysino value in hdlp */
109444961713Sgirish 	hdlp->ih_vector = ih_p->ih_sysino;
109544961713Sgirish 
109644961713Sgirish 	/* swap in our handler & arg */
109744961713Sgirish 	DDI_INTR_ASSIGN_HDLR_N_ARGS(hdlp, (ddi_intr_handler_t *)niumx_intr_hdlr,
109844961713Sgirish 	    (void *)ih_p, NULL);
109944961713Sgirish 
110044961713Sgirish 	ret = i_ddi_add_ivintr(hdlp);
110144961713Sgirish 
110244961713Sgirish 	/* Restore orig. interrupt handler & args in handle. */
110344961713Sgirish 	DDI_INTR_ASSIGN_HDLR_N_ARGS(hdlp, ih_p->ih_hdlr, ih_p->ih_arg1,
110444961713Sgirish 	    ih_p->ih_arg2);
110544961713Sgirish 
110644961713Sgirish 	if (ret != DDI_SUCCESS) {
1107500b1e78SAlan Adamson, SD OSSD 		DBG(NIUMX_DBG_A_INTX, dip, "i_ddi_add_ivintr error ret=%x\n",
1108500b1e78SAlan Adamson, SD OSSD 		    ret);
110944961713Sgirish 		goto done;
111044961713Sgirish 	}
111144961713Sgirish 
111244961713Sgirish 	/* select cpu, saving it for removal */
111344961713Sgirish 	ih_p->ih_cpuid = intr_dist_cpuid();
111444961713Sgirish 
111544961713Sgirish 	if ((hvret = hvio_intr_settarget(ih_p->ih_sysino, ih_p->ih_cpuid))
111644961713Sgirish 	    != H_EOK) {
1117500b1e78SAlan Adamson, SD OSSD 		DBG(NIUMX_DBG_A_INTX, dip,
1118500b1e78SAlan Adamson, SD OSSD 		    "hvio_intr_settarget failed, ret 0x%x\n", hvret);
111944961713Sgirish 		ret = DDI_FAILURE;
112044961713Sgirish 	}
112144961713Sgirish done:
1122500b1e78SAlan Adamson, SD OSSD 	DBG(NIUMX_DBG_A_INTX, dip, "done, ret = %d, ih_p 0x%p, hdlp 0x%p\n",
1123500b1e78SAlan Adamson, SD OSSD 	    ih_p, hdlp, ret);
112444961713Sgirish 	return (ret);
112544961713Sgirish }
112644961713Sgirish 
112744961713Sgirish /*
112844961713Sgirish  * niumx_rem_intr:
112944961713Sgirish  *
113044961713Sgirish  * This function is called to unregister interrupts.
113144961713Sgirish  */
1132500b1e78SAlan Adamson, SD OSSD /*ARGSUSED*/
113344961713Sgirish int
niumx_rem_intr(dev_info_t * dip,dev_info_t * rdip,ddi_intr_handle_impl_t * hdlp)113444961713Sgirish niumx_rem_intr(dev_info_t *dip, dev_info_t *rdip,
113544961713Sgirish     ddi_intr_handle_impl_t *hdlp)
113644961713Sgirish {
113744961713Sgirish 	niumx_ih_t	*ih_p;
1138500b1e78SAlan Adamson, SD OSSD 	int		ret = DDI_SUCCESS, state;
1139c165966dSjf137018 	hrtime_t	start;
1140500b1e78SAlan Adamson, SD OSSD 	niusysino_t 	sysino;
11414df55fdeSJanie Lu 	niumx_devstate_t	*niumxds_p;	/* devstate pointer */
11424df55fdeSJanie Lu 	int		instance = ddi_get_instance(dip);
11434df55fdeSJanie Lu 
11444df55fdeSJanie Lu 	niumxds_p = (niumx_devstate_t *)ddi_get_soft_state(niumx_state,
11454df55fdeSJanie Lu 	    instance);
114644961713Sgirish 
114744961713Sgirish 	ASSERT(hdlp->ih_inum < NIUMX_MAX_INTRS);
114844961713Sgirish 
1149500b1e78SAlan Adamson, SD OSSD 	ih_p = niumxds_p->niumx_ihtable +  hdlp->ih_vector;
1150500b1e78SAlan Adamson, SD OSSD 
1151c165966dSjf137018 	sysino = ih_p->ih_sysino;
1152500b1e78SAlan Adamson, SD OSSD 	DBG(NIUMX_DBG_R_INTX, dip, "removing (%x,%x)\n", ih_p->ih_inum, sysino);
115344961713Sgirish 
1154c165966dSjf137018 	(void) hvio_intr_setvalid(sysino, HV_INTR_NOTVALID);
1155c165966dSjf137018 
1156c165966dSjf137018 	/* check for pending interrupts, busy wait if so */
1157c165966dSjf137018 	for (start = gethrtime(); !panicstr &&
1158c165966dSjf137018 	    (hvio_intr_getstate(sysino, &state) == H_EOK) &&
1159c165966dSjf137018 	    (state == HV_INTR_DELIVERED_STATE); /* */) {
1160c165966dSjf137018 		if (gethrtime() - start > niumx_intr_timeout) {
1161c165966dSjf137018 			cmn_err(CE_WARN, "%s%d: niumx_intr_dist: "
1162c165966dSjf137018 			    "pending interrupt (%x,%lx) timedout\n",
1163c165966dSjf137018 			    ddi_driver_name(dip), ddi_get_instance(dip),
1164c165966dSjf137018 			    ih_p->ih_inum, sysino);
116544961713Sgirish 			ret = DDI_FAILURE;
1166500b1e78SAlan Adamson, SD OSSD 			goto fail;
116744961713Sgirish 		}
1168c165966dSjf137018 	}
116944961713Sgirish 
1170678453a8Sspeer 	ih_p->ih_sysino = 0;
1171678453a8Sspeer 
1172c165966dSjf137018 	hdlp->ih_vector = (uint32_t)sysino;
117344961713Sgirish 	if (hdlp->ih_vector !=  NULL) i_ddi_rem_ivintr(hdlp);
117444961713Sgirish 
1175500b1e78SAlan Adamson, SD OSSD fail:
117644961713Sgirish 	return (ret);
117744961713Sgirish }
117844961713Sgirish 
117944961713Sgirish /*
118044961713Sgirish  * niumx_intr_hdlr (our interrupt handler)
118144961713Sgirish  */
118244961713Sgirish uint_t
niumx_intr_hdlr(void * arg)118344961713Sgirish niumx_intr_hdlr(void *arg)
118444961713Sgirish {
118544961713Sgirish 	niumx_ih_t *ih_p = (niumx_ih_t *)arg;
118644961713Sgirish 	uint_t		r;
118744961713Sgirish 
118844961713Sgirish 	DTRACE_PROBE4(interrupt__start, dev_info_t, ih_p->ih_dip, void *,
118944961713Sgirish 	    ih_p->ih_hdlr, caddr_t, ih_p->ih_arg1, caddr_t, ih_p->ih_arg2);
119044961713Sgirish 
119144961713Sgirish 	r = (*ih_p->ih_hdlr)(ih_p->ih_arg1, ih_p->ih_arg2);
119244961713Sgirish 
119344961713Sgirish 	DTRACE_PROBE4(interrupt__complete, dev_info_t, ih_p->ih_dip, void *,
119444961713Sgirish 	    ih_p->ih_hdlr, caddr_t, ih_p->ih_arg1, int, r);
1195cb343a2eSspeer 
1196cb343a2eSspeer 	(void) hvio_intr_setstate(ih_p->ih_sysino, HV_INTR_IDLE_STATE);
119744961713Sgirish 	return (r);
119844961713Sgirish }
119944961713Sgirish 
120044961713Sgirish #ifdef	DEBUG
120144961713Sgirish uint64_t niumx_debug_flags = 0;
120244961713Sgirish 
120344961713Sgirish static char *niumx_debug_sym [] = {	/* same sequence as niumx_debug_bit */
120444961713Sgirish 	/*  0 */ "attach",
120544961713Sgirish 	/*  1 */ "map",
120644961713Sgirish 	/*  2 */ "nex-ctlops",
120744961713Sgirish 	/*  3 */ "introps",
120844961713Sgirish 	/*  4 */ "intr-add",
120944961713Sgirish 	/*  5 */ "intr-rem",
121044961713Sgirish 	/*  6 */ "intr",
121144961713Sgirish 	/*  7 */ "dma-alloc",
121244961713Sgirish 	/*  8 */ "dma-bind",
121344961713Sgirish 	/*  9 */ "dma-unbind",
121444961713Sgirish 	/* 10 */ "chk-dma-mode"
121544961713Sgirish };
121644961713Sgirish 
121744961713Sgirish /*ARGSUSED*/
121844961713Sgirish void
niumx_dbg(niumx_debug_bit_t bit,dev_info_t * dip,char * fmt,...)121944961713Sgirish niumx_dbg(niumx_debug_bit_t bit, dev_info_t *dip, char *fmt, ...)
122044961713Sgirish {
122144961713Sgirish 	va_list ap;
122244961713Sgirish 	char msgbuf[1024];
122344961713Sgirish 
122444961713Sgirish 	if (!(1ull << bit & niumx_debug_flags))
122544961713Sgirish 		return;
122644961713Sgirish 	va_start(ap, fmt);
122744961713Sgirish 	(void) vsprintf(msgbuf, fmt, ap);
122844961713Sgirish 	va_end(ap);
122944961713Sgirish 	cmn_err(CE_NOTE, "%s: %s", niumx_debug_sym[bit], msgbuf);
123044961713Sgirish }
123144961713Sgirish 
123244961713Sgirish #endif	/* DEBUG */
1233