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)
457