xref: /titanic_51/usr/src/uts/sun4v/io/niumx/niumx.c (revision 68c47f65208790c466e5e484f2293d3baed71c6a)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 
27 /*
28  *	Niagara2 Network Interface Unit (NIU) Nexus Driver
29  */
30 
31 #include <sys/conf.h>
32 #include <sys/modctl.h>
33 #include <sys/ddi_impldefs.h>
34 #include <sys/ddi_subrdefs.h>
35 #include <sys/ddi.h>
36 #include <sys/sunndi.h>
37 #include <sys/sunddi.h>
38 #include <sys/open.h>
39 #include <sys/stat.h>
40 #include <sys/file.h>
41 #include <sys/machsystm.h>
42 #include <sys/hsvc.h>
43 #include <sys/sdt.h>
44 #include <sys/hypervisor_api.h>
45 #include <sys/cpuvar.h>
46 #include "niumx_var.h"
47 
48 static int niumx_fm_init_child(dev_info_t *, dev_info_t *, int,
49 	ddi_iblock_cookie_t *);
50 static int niumx_intr_ops(dev_info_t *dip, dev_info_t *rdip,
51 	ddi_intr_op_t intr_op, ddi_intr_handle_impl_t *hdlp, void *result);
52 static int niumx_attach(dev_info_t *devi, ddi_attach_cmd_t cmd);
53 static int niumx_detach(dev_info_t *devi, ddi_detach_cmd_t cmd);
54 static int niumx_set_intr(dev_info_t *dip, dev_info_t *rdip,
55 	ddi_intr_handle_impl_t *hdlp, int valid);
56 static int niumx_add_intr(dev_info_t *dip, dev_info_t *rdip,
57 	ddi_intr_handle_impl_t *hdlp);
58 static int niumx_rem_intr(dev_info_t *dip, dev_info_t *rdip,
59 	ddi_intr_handle_impl_t *hdlp);
60 static uint_t niumx_intr_hdlr(void *arg);
61 static int niumx_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
62 	off_t offset, off_t len, caddr_t *addrp);
63 static int niumx_dma_allochdl(dev_info_t *dip, dev_info_t *rdip,
64 	ddi_dma_attr_t *attrp,
65 	int (*waitfp)(caddr_t), caddr_t arg, ddi_dma_handle_t *handlep);
66 static int niumx_dma_freehdl(dev_info_t *dip, dev_info_t *rdip,
67 	ddi_dma_handle_t handlep);
68 static int niumx_dma_bindhdl(dev_info_t *dip, dev_info_t *rdip,
69 	ddi_dma_handle_t handle, ddi_dma_req_t *dmareq,
70 	ddi_dma_cookie_t *cookiep, uint_t *ccountp);
71 static int niumx_dma_unbindhdl(dev_info_t *dip, dev_info_t *rdip,
72 	ddi_dma_handle_t handle);
73 static int niumx_ctlops(dev_info_t *dip, dev_info_t *rdip,
74 	ddi_ctl_enum_t op, void *arg, void *result);
75 
76 int niumxtool_init(dev_info_t *dip);
77 void niumxtool_uninit(dev_info_t *dip);
78 
79 int niumx_get_intr_target(niumx_devstate_t *niumxds_p, niudevino_t ino,
80     niucpuid_t *cpu_id);
81 int niumx_set_intr_target(niumx_devstate_t *niumxds_p, niudevino_t ino,
82     niucpuid_t cpu_id);
83 
84 static struct bus_ops niumx_bus_ops = {
85 	BUSO_REV,
86 	niumx_map,
87 	0,
88 	0,
89 	0,
90 	i_ddi_map_fault,
91 	0,
92 	niumx_dma_allochdl,
93 	niumx_dma_freehdl,
94 	niumx_dma_bindhdl,
95 	niumx_dma_unbindhdl,
96 	0,
97 	0,
98 	0,
99 	niumx_ctlops,
100 	ddi_bus_prop_op,
101 	0,				/* (*bus_get_eventcookie)();    */
102 	0,				/* (*bus_add_eventcall)();	*/
103 	0,				/* (*bus_remove_eventcall)();   */
104 	0,				/* (*bus_post_event)();		*/
105 	0,				/* (*bus_intr_ctl)();		*/
106 	0,				/* (*bus_config)(); 		*/
107 	0,				/* (*bus_unconfig)(); 		*/
108 	niumx_fm_init_child,		/* (*bus_fm_init)(); 		*/
109 	0,				/* (*bus_fm_fini)(); 		*/
110 	0,				/* (*bus_enter)()		*/
111 	0,				/* (*bus_exit)()		*/
112 	0,				/* (*bus_power)()		*/
113 	niumx_intr_ops			/* (*bus_intr_op)(); 		*/
114 };
115 
116 extern  struct cb_ops niumx_cb_ops;
117 
118 static struct dev_ops niumx_ops = {
119 	DEVO_REV,		/* devo_rev */
120 	0,			/* refcnt  */
121 	ddi_no_info,		/* info */
122 	nulldev,		/* identify */
123 	0,			/* probe */
124 	niumx_attach,		/* attach */
125 	niumx_detach,		/* detach */
126 	nulldev,		/* reset */
127 	&niumx_cb_ops,		/* driver operations */
128 	&niumx_bus_ops,		/* bus operations */
129 	0,			/* power */
130 	ddi_quiesce_not_supported,	/* devo_quiesce */
131 };
132 
133 /* Module linkage information for the kernel. */
134 static struct modldrv modldrv = {
135 	&mod_driverops, /* Type of module */
136 	"NIU Nexus Driver",
137 	&niumx_ops,	/* driver ops */
138 };
139 
140 static struct modlinkage modlinkage = {
141 	MODREV_1,
142 	(void *)&modldrv,
143 	NULL
144 };
145 
146 void *niumx_state;
147 
148 /*
149  * forward function declarations:
150  */
151 static void niumx_removechild(dev_info_t *);
152 static int niumx_initchild(dev_info_t *child);
153 
154 int
155 _init(void)
156 {
157 	int e;
158 	uint64_t mjrnum;
159 	uint64_t mnrnum;
160 
161 	/*
162 	 * Check HV intr group api versioning.
163 	 * This driver uses the old interrupt routines which are supported
164 	 * in old firmware in the CORE API group and in newer firmware in
165 	 * the INTR API group.  Support for these calls will be dropped
166 	 * once the INTR API group major goes to 2.
167 	 */
168 	if ((hsvc_version(HSVC_GROUP_INTR, &mjrnum, &mnrnum) == 0) &&
169 	    (mjrnum > NIUMX_INTR_MAJOR_VER)) {
170 		cmn_err(CE_WARN, "niumx: unsupported intr api group: "
171 		    "maj:0x%lx, min:0x%lx", mjrnum, mnrnum);
172 		return (ENOTSUP);
173 	}
174 
175 	if ((e = ddi_soft_state_init(&niumx_state, sizeof (niumx_devstate_t),
176 	    1)) == 0 && (e = mod_install(&modlinkage)) != 0)
177 		ddi_soft_state_fini(&niumx_state);
178 	return (e);
179 }
180 
181 int
182 _fini(void)
183 {
184 	int e;
185 	if ((e = mod_remove(&modlinkage)) == 0)
186 		ddi_soft_state_fini(&niumx_state);
187 	return (e);
188 }
189 
190 int
191 _info(struct modinfo *modinfop)
192 {
193 	return (mod_info(&modlinkage, modinfop));
194 }
195 
196 
197 hrtime_t niumx_intr_timeout = 2ull * NANOSEC; /* 2 seconds in nanoseconds */
198 
199 void
200 niumx_intr_dist(void *arg)
201 {
202 	niumx_devstate_t	*niumxds_p = (niumx_devstate_t *)arg;
203 	kmutex_t 	*lock_p = &niumxds_p->niumx_mutex;
204 	int		i;
205 	niumx_ih_t	*ih_p = niumxds_p->niumx_ihtable;
206 
207 	DBG(NIUMX_DBG_A_INTX, NULL, "niumx_intr_dist entered\n");
208 	mutex_enter(lock_p);
209 	for (i = 0; i < NIUMX_MAX_INTRS; i++, ih_p++) {
210 		niusysino_t sysino = ih_p->ih_sysino;
211 		niucpuid_t	cpuid;
212 		int		state;
213 		hrtime_t	start;
214 		dev_info_t	*dip = ih_p->ih_dip;
215 
216 		if (!sysino || (cpuid = intr_dist_cpuid()) == ih_p->ih_cpuid)
217 			continue;
218 
219 		(void) hvio_intr_setvalid(sysino, HV_INTR_NOTVALID);
220 
221 		/* check for pending interrupts, busy wait if so */
222 		for (start = gethrtime(); !panicstr &&
223 		    (hvio_intr_getstate(sysino, &state) == H_EOK) &&
224 		    (state == HV_INTR_DELIVERED_STATE); /* */) {
225 			if (gethrtime() - start > niumx_intr_timeout) {
226 				cmn_err(CE_WARN, "%s%d: niumx_intr_dist: "
227 				    "pending interrupt (%x,%lx) timedout\n",
228 				    ddi_driver_name(dip), ddi_get_instance(dip),
229 				    ih_p->ih_inum, sysino);
230 				(void) hvio_intr_setstate(sysino,
231 				    HV_INTR_IDLE_STATE);
232 				break;
233 			}
234 		}
235 		(void) hvio_intr_settarget(sysino, cpuid);
236 
237 		if (ih_p->ih_state == HV_INTR_VALID)
238 			(void) hvio_intr_setvalid(sysino, HV_INTR_VALID);
239 		else
240 			(void) hvio_intr_setvalid(sysino, HV_INTR_NOTVALID);
241 
242 		ih_p->ih_cpuid = cpuid;
243 	}
244 	mutex_exit(lock_p);
245 }
246 
247 static int
248 niumx_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
249 {
250 	int instance = ddi_get_instance(dip);
251 	niumx_devstate_t *niumxds_p;	/* devstate pointer */
252 	niu_regspec_t	*reg_p;
253 	niumx_ih_t	*ih_p;
254 	uint_t		reglen;
255 	int		i, ret = DDI_SUCCESS;
256 
257 	switch (cmd) {
258 	case DDI_ATTACH:
259 		if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip,
260 		    DDI_PROP_DONTPASS, "reg", (int **)&reg_p, &reglen)
261 		    != DDI_PROP_SUCCESS) {
262 			DBG(NIUMX_DBG_ATTACH, dip, "reg lookup failed\n");
263 			ret = DDI_FAILURE;
264 			goto done;
265 		}
266 
267 		/*
268 		 * Allocate and get soft state structure.
269 		 */
270 		if (ddi_soft_state_zalloc(niumx_state, instance)
271 		    != DDI_SUCCESS) {
272 			ret = DDI_FAILURE;
273 			goto prop_free;
274 		}
275 		niumxds_p = (niumx_devstate_t *)ddi_get_soft_state(niumx_state,
276 		    instance);
277 		niumxds_p->dip = dip;
278 		niumxds_p->niumx_open_count = 0;
279 		mutex_init(&niumxds_p->niumx_mutex, NULL, MUTEX_DRIVER, NULL);
280 
281 		DBG(NIUMX_DBG_ATTACH, dip, "soft state alloc'd instance = %d, "
282 		    "niumxds_p = %p\n", instance, niumxds_p);
283 
284 		/* hv devhdl: low 28-bit of 1st "reg" entry's addr.hi */
285 		niumxds_p->niumx_dev_hdl = (niudevhandle_t)(reg_p->addr_high &
286 		    NIUMX_DEVHDLE_MASK);
287 
288 		ih_p = niumxds_p->niumx_ihtable;
289 		for (i = 0; i < NIUMX_MAX_INTRS; i++, ih_p++) {
290 			ih_p->ih_sysino = 0;
291 			ih_p->ih_state = HV_INTR_NOTVALID;
292 		}
293 
294 		/* add interrupt redistribution callback */
295 		intr_dist_add(niumx_intr_dist, niumxds_p);
296 
297 		niumxds_p->niumx_fm_cap = DDI_FM_EREPORT_CAPABLE;
298 
299 		ddi_fm_init(niumxds_p->dip, &niumxds_p->niumx_fm_cap,
300 		    &niumxds_p->niumx_fm_ibc);
301 
302 		if (niumxtool_init(dip) != DDI_SUCCESS) {
303 			ret = DDI_FAILURE;
304 			goto cleanup;
305 		}
306 
307 		ret = DDI_SUCCESS;
308 		goto prop_free;
309 cleanup:
310 		mutex_destroy(&niumxds_p->niumx_mutex);
311 		ddi_soft_state_free(niumx_state, ddi_get_instance(dip));
312 prop_free:
313 		ddi_prop_free(reg_p);
314 done:
315 		return (ret);
316 
317 	case DDI_RESUME:
318 	default:
319 		break;
320 	}
321 	return (ret);
322 }
323 
324 static int
325 niumx_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
326 {
327 	niumx_devstate_t *niumxds_p;
328 
329 	switch (cmd) {
330 	case DDI_DETACH:
331 
332 		niumxds_p = (niumx_devstate_t *)
333 		    ddi_get_soft_state(niumx_state, ddi_get_instance(dip));
334 
335 		intr_dist_rem(niumx_intr_dist, niumxds_p);
336 		ddi_fm_fini(dip);
337 		niumxtool_uninit(dip);
338 		mutex_destroy(&niumxds_p->niumx_mutex);
339 		ddi_soft_state_free(niumx_state, ddi_get_instance(dip));
340 		return (DDI_SUCCESS);
341 
342 	case DDI_SUSPEND:
343 	default:
344 		break;
345 	}
346 	return (DDI_FAILURE);
347 }
348 
349 
350 /*
351  * Function used to initialize FMA for our children nodes. Called
352  * through pci busops when child node calls ddi_fm_init.
353  */
354 /*ARGSUSED*/
355 int
356 niumx_fm_init_child(dev_info_t *dip, dev_info_t *cdip, int cap,
357     ddi_iblock_cookie_t *ibc_p)
358 {
359 	niumx_devstate_t	*niumxds_p = NIUMX_DIP_TO_STATE(dip);
360 
361 	ASSERT(ibc_p != NULL);
362 	*ibc_p = niumxds_p->niumx_fm_ibc;
363 
364 	return (niumxds_p->niumx_fm_cap);
365 }
366 
367 
368 /*ARGSUSED*/
369 int
370 niumx_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
371 	off_t offset, off_t len, caddr_t *vaddrp)
372 {
373 	struct regspec p_regspec;
374 	ddi_map_req_t p_mapreq;
375 	niu_regspec_t	*reg_p;
376 	int 	i, rn = mp->map_obj.rnumber, reglen, rnglen, rngnum, ret;
377 	niumx_ranges_t	*rng_p;
378 
379 	uint32_t	reg_begin, rng_begin;
380 
381 	DBG(NIUMX_DBG_MAP, dip, "%s%d: mapping %s%d reg %d\n",
382 	    NIUMX_NAMEINST(dip), NIUMX_NAMEINST(rdip), rn);
383 
384 	if (ddi_getlongprop(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS,
385 	    "reg", (caddr_t)&reg_p, &reglen) != DDI_SUCCESS)
386 		return (DDI_FAILURE);
387 
388 	if (rn < 0 || (rn >= reglen / sizeof (niu_regspec_t))) {
389 		DBG(NIUMX_DBG_MAP, dip,  "rnumber out of range: %d\n", rn);
390 		kmem_free(reg_p, reglen);
391 		return (DDI_ME_RNUMBER_RANGE);
392 	}
393 
394 	/* build regspec up for parent */
395 	p_mapreq = *mp;		/* dup the whole structure */
396 	p_mapreq.map_type = DDI_MT_REGSPEC;
397 	p_mapreq.map_obj.rp = &p_regspec;
398 
399 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "ranges",
400 	    (caddr_t)&rng_p, &rnglen) != DDI_SUCCESS) {
401 			DBG(NIUMX_DBG_MAP,  dip, "%s%d: no ranges property\n",
402 			    ddi_driver_name(dip), ddi_get_instance(dip));
403 			kmem_free(reg_p, reglen);
404 			return (DDI_FAILURE);
405 	}
406 
407 	/* locate matching ranges record */
408 	rngnum = rnglen / sizeof (niumx_ranges_t);
409 	for (i = 0, reg_p += rn; i < rngnum; rng_p++, i++) {
410 		if (reg_p->addr_high == rng_p->child_hi)
411 			break;
412 	}
413 
414 	if (i >= rngnum) {
415 		DBG(NIUMX_DBG_MAP, dip, "ranges record for reg[%d] "
416 		    "not found.\n", rn);
417 		ret = DDI_ME_REGSPEC_RANGE;
418 		goto err;
419 	}
420 
421 	/*
422 	 * validate request has matching bus type and within 4G
423 	 * limit by comparing addr.hi of "ranges" and child "reg".
424 	 */
425 
426 	ASSERT(reg_p->size_high == 0);
427 
428 	rng_begin = rng_p->child_lo;
429 	reg_begin = reg_p->addr_low;
430 	/* check to verify reg bounds are within rng bounds */
431 	if (reg_begin < rng_begin || (reg_begin + (reg_p->size_low - 1)) >
432 	    (rng_begin + (rng_p->size_lo - 1))) {
433 		DBG(NIUMX_DBG_MAP, dip, "size out of range for reg[%d].\n", rn);
434 		ret = DDI_ME_REGSPEC_RANGE;
435 		goto err;
436 	}
437 
438 	p_regspec.regspec_bustype = rng_p->parent_hi;
439 	p_regspec.regspec_addr = reg_begin - rng_begin + rng_p->parent_lo;
440 	p_regspec.regspec_size = reg_p->size_low;
441 	DBG(NIUMX_DBG_MAP, dip, "regspec:bus,addr,size = (%x,%x,%x)\n",
442 	    p_regspec.regspec_bustype, p_regspec.regspec_addr,
443 	    p_regspec.regspec_size);
444 	ret = ddi_map(dip, &p_mapreq, 0, 0, vaddrp);
445 	DBG(NIUMX_DBG_MAP, dip, "niumx_map: ret %d.\n", ret);
446 err:
447 	kmem_free(rng_p - i, rnglen);
448 	kmem_free(reg_p - rn, reglen);
449 	return (ret);
450 }
451 
452 /*
453  * niumx_ctlops
454  */
455 int
456 niumx_ctlops(dev_info_t *dip, dev_info_t *rdip,
457 	ddi_ctl_enum_t ctlop, void *arg, void *result)
458 {
459 	niu_regspec_t *reg_p;
460 	int	reglen, totreg;
461 
462 	DBG(NIUMX_DBG_CTLOPS, dip, "niumx_ctlops ctlop=%d.\n", ctlop);
463 	if (rdip == (dev_info_t *)0)
464 		return (DDI_FAILURE);
465 
466 	switch (ctlop) {
467 	case DDI_CTLOPS_REPORTDEV:
468 		cmn_err(CE_NOTE, "device: %s@%s, %s%d\n",
469 		    ddi_node_name(rdip), ddi_get_name_addr(rdip),
470 		    NIUMX_NAMEINST(rdip));
471 		return (DDI_SUCCESS);
472 
473 	case DDI_CTLOPS_INITCHILD:
474 		return (niumx_initchild((dev_info_t *)arg));
475 
476 	case DDI_CTLOPS_UNINITCHILD:
477 		niumx_removechild((dev_info_t *)arg);
478 		return (DDI_SUCCESS);
479 
480 	case DDI_CTLOPS_REGSIZE:
481 	case DDI_CTLOPS_NREGS:
482 		/* fall through */
483 		break;
484 	default:
485 		DBG(NIUMX_DBG_CTLOPS, dip, "just pass to ddi_cltops.\n");
486 		return (ddi_ctlops(dip, rdip, ctlop, arg, result));
487 	}
488 
489 	/* REGSIZE/NREGS */
490 
491 	*(int *)result = 0;
492 
493 	if (ddi_getlongprop(DDI_DEV_T_NONE, rdip, DDI_PROP_DONTPASS |
494 	    DDI_PROP_CANSLEEP, "reg", (caddr_t)&reg_p, &reglen) != DDI_SUCCESS)
495 		return (DDI_FAILURE);
496 
497 	totreg = reglen / sizeof (niu_regspec_t);
498 	if (ctlop == DDI_CTLOPS_NREGS) {
499 		DBG(NIUMX_DBG_CTLOPS, (dev_info_t *)dip,
500 		    "niumx_ctlops NREGS=%d.\n", totreg);
501 		*(int *)result = totreg;
502 	} else if (ctlop == DDI_CTLOPS_REGSIZE) {
503 		int	rn;
504 		rn = *(int *)arg;
505 		if (rn >= totreg) {
506 			kmem_free(reg_p, reglen);
507 			return (DDI_FAILURE);
508 		}
509 		*(off_t *)result = (reg_p + rn)->size_low;
510 		DBG(NIUMX_DBG_CTLOPS, (dev_info_t *)dip,
511 		    "rn = %d, REGSIZE=%x.\n", rn, *(off_t *)result);
512 	}
513 
514 	kmem_free(reg_p, reglen);
515 	return (DDI_SUCCESS);
516 }
517 
518 /*
519  * niumx_name_child
520  *
521  * This function is called from init_child to name a node. It is
522  * also passed as a callback for node merging functions.
523  *
524  * return value: DDI_SUCCESS, DDI_FAILURE
525  */
526 static int
527 niumx_name_child(dev_info_t *child, char *name, int namelen)
528 {
529 	niu_regspec_t *r;
530 	uint_t n;
531 
532 	DBG(NIUMX_DBG_CHK_MOD, (dev_info_t *)child, "==> niumx_name_child\n");
533 
534 	if (ndi_dev_is_persistent_node(child) == 0) {
535 		char **unit_addr;
536 
537 		/* name .conf nodes by "unit-address" property */
538 		if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, child,
539 		    DDI_PROP_DONTPASS, "unit-address", &unit_addr, &n) !=
540 		    DDI_PROP_SUCCESS) {
541 			cmn_err(CE_WARN, "cannot name node from %s.conf",
542 			    ddi_driver_name(child));
543 			return (DDI_FAILURE);
544 		}
545 		if (n != 1 || *unit_addr == NULL || **unit_addr == 0) {
546 			cmn_err(CE_WARN, "unit-address property in %s.conf"
547 			    " not well-formed", ddi_driver_name(child));
548 			ddi_prop_free(unit_addr);
549 			return (DDI_FAILURE);
550 		}
551 
552 		(void) snprintf(name, namelen, "%s", *unit_addr);
553 		ddi_prop_free(unit_addr);
554 		return (DDI_SUCCESS);
555 	}
556 
557 	/* name hardware nodes by "reg" property */
558 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
559 	    "reg", (int **)&r, &n) != DDI_SUCCESS) {
560 		cmn_err(CE_WARN, "reg property not well-formed");
561 		return (DDI_FAILURE);
562 	}
563 	(void) snprintf(name, namelen, "%x", (r[0].addr_high));
564 	ddi_prop_free(r);
565 	return (DDI_SUCCESS);
566 }
567 
568 static int
569 niumx_initchild(dev_info_t *child)
570 {
571 	char name[MAXNAMELEN];
572 
573 	DBG(NIUMX_DBG_CHK_MOD, (dev_info_t *)child, "==> niumx_initchild\n");
574 	/*
575 	 * Non-peristent nodes indicate a prototype node with per-instance
576 	 * properties to be merged into the real h/w device node.
577 	 */
578 	if (ndi_dev_is_persistent_node(child) == 0) {
579 		niu_regspec_t *r;
580 		uint_t n;
581 
582 		if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child,
583 		    DDI_PROP_DONTPASS, "reg", (int **)&r, &n) ==
584 		    DDI_SUCCESS) {
585 			cmn_err(CE_WARN,
586 			    "cannot merge prototype from %s.conf",
587 			    ddi_driver_name(child));
588 			ddi_prop_free(r);
589 			return (DDI_NOT_WELL_FORMED);
590 		}
591 
592 		if (niumx_name_child(child, name, MAXNAMELEN) != DDI_SUCCESS)
593 			return (DDI_NOT_WELL_FORMED);
594 
595 		ddi_set_name_addr(child, name);
596 		ddi_set_parent_data(child, NULL);
597 
598 		/*
599 		 * Try to merge the properties from this prototype
600 		 * node into real h/w nodes.
601 		 */
602 		if (ndi_merge_node(child, niumx_name_child) == DDI_SUCCESS) {
603 			/*
604 			 * Merged ok - return failure to remove the node.
605 			 */
606 			ddi_set_name_addr(child, NULL);
607 			return (DDI_FAILURE);
608 		}
609 
610 		/*
611 		 * The child was not merged into a h/w node,
612 		 * but there's not much we can do with it other
613 		 * than return failure to cause the node to be removed.
614 		 */
615 		cmn_err(CE_WARN, "!%s@%s: %s.conf properties not merged",
616 		    ddi_driver_name(child), ddi_get_name_addr(child),
617 		    ddi_driver_name(child));
618 		ddi_set_name_addr(child, NULL);
619 		return (DDI_NOT_WELL_FORMED);
620 	}
621 
622 	/*
623 	 * Initialize real h/w nodes
624 	 */
625 	if (niumx_name_child(child, name, MAXNAMELEN) != DDI_SUCCESS)
626 		return (DDI_FAILURE);
627 
628 	ddi_set_name_addr(child, name);
629 	return (DDI_SUCCESS);
630 }
631 
632 static void
633 niumx_removechild(dev_info_t *dip)
634 {
635 	ddi_set_name_addr(dip, NULL);
636 	ddi_remove_minor_node(dip, NULL);
637 	impl_rem_dev_props(dip);
638 }
639 
640 
641 
642 /*
643  * bus dma alloc handle entry point:
644  */
645 /*ARGSUSED*/
646 int
647 niumx_dma_allochdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_attr_t *attrp,
648 	int (*waitfp)(caddr_t), caddr_t arg, ddi_dma_handle_t *handlep)
649 {
650 	ddi_dma_impl_t *mp;
651 	int sleep = (waitfp == DDI_DMA_SLEEP) ? KM_SLEEP : KM_NOSLEEP;
652 
653 	DBG(NIUMX_DBG_DMA_ALLOCH, dip, "rdip=%s%d\n", NIUMX_NAMEINST(rdip));
654 
655 	if (attrp->dma_attr_version != DMA_ATTR_V0) {
656 		DBG(NIUMX_DBG_DMA_ALLOCH,
657 		    (dev_info_t *)dip, "DDI_DMA_BADATTR\n");
658 		return (DDI_DMA_BADATTR);
659 	}
660 
661 	/* Caution: we don't use zalloc to enhance performance! */
662 	if ((mp = kmem_alloc(sizeof (ddi_dma_impl_t), sleep)) == 0) {
663 		DBG(NIUMX_DBG_DMA_ALLOCH, dip, "can't alloc ddi_dma_impl_t\n");
664 		return (DDI_FAILURE);
665 	}
666 	mp->dmai_rdip = rdip;
667 	mp->dmai_pfnlst = NULL;
668 	mp->dmai_cookie = NULL;
669 	mp->dmai_fault = 0;
670 	mp->dmai_fault_check = NULL;
671 	mp->dmai_fault_notify = NULL;
672 
673 	mp->dmai_attr = *attrp; 	/* set requestors attr info */
674 
675 	DBG(NIUMX_DBG_DMA_ALLOCH, dip, "mp=%p\n", mp);
676 
677 	*handlep = (ddi_dma_handle_t)mp;
678 	return (DDI_SUCCESS);
679 }
680 
681 
682 /*
683  * bus dma free handle entry point:
684  */
685 /*ARGSUSED*/
686 int
687 niumx_dma_freehdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t handle)
688 {
689 	ddi_dma_impl_t *mp = (ddi_dma_impl_t *)handle;
690 
691 	if (mp->dmai_cookie)
692 		kmem_free(mp->dmai_cookie, sizeof (ddi_dma_cookie_t));
693 	kmem_free(mp, sizeof (ddi_dma_impl_t));
694 
695 	return (DDI_SUCCESS);
696 }
697 
698 
699 /*
700  * bus dma bind handle entry point:
701  *
702  *	check/enforce DMA type, setup pfn0 and some other key pieces
703  *	of this dma request.
704  * Note: this only works with DMA_OTYP_VADDR, and makes use of the known
705  *	fact that only contiguous memory blocks will be passed in.
706  *	Therefore only one cookie will ever be returned.
707  *
708  *	return values:
709  *		DDI_DMA_NOMAPPING - can't get valid pfn0, or bad dma type
710  *		DDI_DMA_NORESOURCES
711  *		DDI_SUCCESS
712  *
713  *	dma handle members affected (set on exit):
714  *	mp->dmai_object		- dmareq->dmar_object
715  *	mp->dmai_rflags		- dmareq->dmar_flags
716  *	mp->dmai_pfn0   	- 1st page pfn (if va/size pair and not shadow)
717  *	mp->dmai_roffset 	- initialized to starting page offset
718  *	mp->dmai_size		- # of total pages of entire object
719  *	mp->dmai_cookie		- new cookie alloc'd
720  */
721 /*ARGSUSED*/
722 int
723 niumx_dma_bindhdl(dev_info_t *dip, dev_info_t *rdip,
724 	ddi_dma_handle_t handle, ddi_dma_req_t *dmareq,
725 	ddi_dma_cookie_t *cookiep, uint_t *ccountp)
726 {
727 	int (*waitfp)(caddr_t) = dmareq->dmar_fp;
728 	ddi_dma_impl_t *mp = (ddi_dma_impl_t *)handle;
729 	ddi_dma_obj_t *dobj_p = &dmareq->dmar_object;
730 	uint32_t offset;
731 	pfn_t pfn0;
732 	int ret;
733 
734 	DBG(NIUMX_DBG_DMA_BINDH, dip, "rdip=%s%d mp=%p dmareq=%p\n",
735 	    NIUMX_NAMEINST(rdip), mp, dmareq);
736 
737 	/* first check dma type */
738 	mp->dmai_rflags = dmareq->dmar_flags & DMP_DDIFLAGS | DMP_NOSYNC;
739 	switch (dobj_p->dmao_type) {
740 	case DMA_OTYP_VADDR: {
741 		caddr_t vaddr = dobj_p->dmao_obj.virt_obj.v_addr;
742 		struct as *as_p = dobj_p->dmao_obj.virt_obj.v_as;
743 		struct hat *hat_p = as_p ? as_p->a_hat : kas.a_hat;
744 		offset = (ulong_t)vaddr & NIUMX_PAGE_OFFSET;
745 		pfn0 = hat_getpfnum(hat_p, vaddr);
746 		}
747 		break;
748 
749 	case DMA_OTYP_BUFVADDR:
750 	case DMA_OTYP_PAGES:
751 	case DMA_OTYP_PADDR:
752 	default:
753 		cmn_err(CE_WARN, "%s%d requested unsupported dma type %x",
754 		    NIUMX_NAMEINST(mp->dmai_rdip), dobj_p->dmao_type);
755 		ret = DDI_DMA_NOMAPPING;
756 		goto err;
757 	}
758 	if (pfn0 == PFN_INVALID) {
759 		cmn_err(CE_WARN, "%s%d: invalid pfn0 for DMA object %p",
760 		    NIUMX_NAMEINST(dip), (void *)dobj_p);
761 		ret = DDI_DMA_NOMAPPING;
762 		goto err;
763 	}
764 	mp->dmai_object	 = *dobj_p;			/* whole object */
765 	mp->dmai_pfn0	 = (void *)pfn0;		/* cache pfn0   */
766 	mp->dmai_roffset = offset;			/* pg0 offset   */
767 	mp->dmai_mapping = mp->dmai_roffset | NIUMX_PTOB(pfn0);
768 	mp->dmai_size = mp->dmai_object.dmao_size;
769 
770 	DBG(NIUMX_DBG_DMA_BINDH, dip, "check pfn: mp=%p pfn0=%x\n",
771 	    mp, mp->dmai_pfn0);
772 	if (!(mp->dmai_cookie = kmem_zalloc(sizeof (ddi_dma_cookie_t),
773 	    waitfp == DDI_DMA_SLEEP ? KM_SLEEP : KM_NOSLEEP))) {
774 			ret = DDI_DMA_NORESOURCES;
775 			goto err;
776 		}
777 	mp->dmai_cookie->dmac_laddress = mp->dmai_mapping;
778 	mp->dmai_cookie->dmac_size = mp->dmai_size;
779 	*ccountp = 1;
780 	*cookiep = *mp->dmai_cookie;
781 	DBG(NIUMX_DBG_DMA_BINDH, dip, "cookie %" PRIx64 "+%x, count=%d\n",
782 	    cookiep->dmac_address, cookiep->dmac_size, *ccountp);
783 	return (DDI_DMA_MAPPED);
784 
785 err:
786 	DBG(NIUMX_DBG_DMA_BINDH, (dev_info_t *)dip,
787 	    "niumx_dma_bindhdl error ret=%d\n", ret);
788 	return (ret);
789 }
790 
791 /*
792  * bus dma unbind handle entry point:
793  */
794 /*ARGSUSED*/
795 int
796 niumx_dma_unbindhdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t handle)
797 {
798 	ddi_dma_impl_t *mp = (ddi_dma_impl_t *)handle;
799 
800 	DBG(NIUMX_DBG_DMA_UNBINDH, dip, "rdip=%s%d, mp=%p\n",
801 	    ddi_driver_name(rdip), ddi_get_instance(rdip), handle);
802 	if (mp->dmai_cookie) {
803 		kmem_free(mp->dmai_cookie, sizeof (ddi_dma_cookie_t));
804 		mp->dmai_cookie = NULL;
805 	}
806 
807 	return (DDI_SUCCESS);
808 }
809 
810 /*ARGSUSED*/
811 int
812 niumx_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
813     ddi_intr_handle_impl_t *hdlp, void *result)
814 {
815 
816 	int	ret = DDI_SUCCESS;
817 
818 	DBG(NIUMX_DBG_INTROPS, dip, "niumx_intr_ops: dip=%p rdip=%p intr_op=%x "
819 	    "handle=%p\n", dip, rdip, intr_op, hdlp);
820 
821 	switch (intr_op) {
822 
823 	case DDI_INTROP_SUPPORTED_TYPES:
824 		*(int *)result = DDI_INTR_TYPE_FIXED;
825 		break;
826 	case DDI_INTROP_GETCAP:
827 		*(int *)result =  DDI_INTR_FLAG_LEVEL |
828 		    DDI_INTR_FLAG_RETARGETABLE;
829 		break;
830 	case DDI_INTROP_SETCAP:
831 		ret = DDI_ENOTSUP;
832 		break;
833 	case DDI_INTROP_ALLOC:
834 		/*  scratch1 = count,  # of intrs from DDI framework */
835 		*(int *)result = hdlp->ih_scratch1;
836 		break;
837 	case DDI_INTROP_FREE:
838 		/* Do we need to do anything here?  */
839 		break;
840 	case DDI_INTROP_GETPRI:
841 		*(int *)result = NIUMX_DEFAULT_PIL;
842 		break;
843 	case DDI_INTROP_SETPRI:
844 		ret = DDI_ENOTSUP;
845 		break;
846 	case DDI_INTROP_ADDISR:
847 		ret = niumx_add_intr(dip, rdip, hdlp);
848 		break;
849 	case DDI_INTROP_REMISR:
850 		ret = niumx_rem_intr(dip, rdip, hdlp);
851 		break;
852 	case DDI_INTROP_ENABLE:
853 		ret = niumx_set_intr(dip, rdip, hdlp, HV_INTR_VALID);
854 		break;
855 	case DDI_INTROP_DISABLE:
856 		ret = niumx_set_intr(dip, rdip, hdlp, HV_INTR_NOTVALID);
857 		break;
858 	case DDI_INTROP_SETMASK:
859 		ret = DDI_ENOTSUP;
860 		break;
861 	case DDI_INTROP_CLRMASK:
862 		ret = DDI_ENOTSUP;
863 		break;
864 	case DDI_INTROP_GETPENDING:
865 		ret = DDI_ENOTSUP;
866 		break;
867 	case DDI_INTROP_NINTRS:
868 	case DDI_INTROP_NAVAIL: {
869 		niudevino_t	*inos_p;
870 		int		inoslen;
871 
872 		if (ddi_getlongprop(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS,
873 		    "interrupts", (caddr_t)&inos_p, &inoslen)
874 		    != DDI_SUCCESS) {
875 			ret = DDI_FAILURE;
876 			break;
877 			}
878 		*(int *)result = inoslen / sizeof (uint32_t);
879 		kmem_free(inos_p, inoslen);
880 		}
881 		break;
882 	case DDI_INTROP_GETTARGET: {
883 		niumx_devstate_t *niumxds_p;
884 
885 		niumxds_p = (niumx_devstate_t *)ddi_get_soft_state(niumx_state,
886 		    ddi_get_instance(dip));
887 
888 		ret = niumx_get_intr_target(niumxds_p, hdlp->ih_vector,
889 		    (niucpuid_t *)result);
890 
891 		}
892 		break;
893 	case DDI_INTROP_SETTARGET: {
894 		niumx_devstate_t *niumxds_p;
895 
896 		niumxds_p = (niumx_devstate_t *)ddi_get_soft_state(niumx_state,
897 		    ddi_get_instance(dip));
898 
899 		ret = niumx_set_intr_target(niumxds_p, hdlp->ih_vector,
900 		    *(niucpuid_t *)result);
901 
902 		}
903 		break;
904 	default:
905 		ret = DDI_ENOTSUP;
906 		break;
907 	}
908 
909 	DBG(NIUMX_DBG_INTROPS, dip, "niumx_intr_ops: ret=%d\n", ret);
910 	return (ret);
911 }
912 
913 int
914 niumx_set_intr(dev_info_t *dip, dev_info_t *rdip,
915     ddi_intr_handle_impl_t *hdlp, int valid)
916 {
917 	niumx_ih_t	*ih_p;
918 	int		ret = DDI_SUCCESS;
919 	uint64_t	hvret;
920 	niumx_devstate_t	*niumxds_p;	/* devstate pointer */
921 	int 		instance = ddi_get_instance(dip);
922 
923 	niumxds_p = (niumx_devstate_t *)ddi_get_soft_state(niumx_state,
924 	    instance);
925 
926 	ASSERT(hdlp->ih_inum < NIUMX_MAX_INTRS);
927 
928 	ih_p = niumxds_p->niumx_ihtable +  hdlp->ih_vector;
929 
930 	DBG(NIUMX_DBG_A_INTX, dip,
931 	    "niumx_set_intr: rdip=%s%d, valid=%d %s (%x,%x)\n",
932 	    NIUMX_NAMEINST(rdip), valid, valid ? "enabling" : "disabling",
933 	    ih_p->ih_inum, ih_p->ih_sysino);
934 
935 	if (valid == HV_INTR_VALID)
936 		(void) hvio_intr_setstate(ih_p->ih_sysino, HV_INTR_IDLE_STATE);
937 	if ((hvret = hvio_intr_setvalid(ih_p->ih_sysino, valid))
938 	    != H_EOK) {
939 		DBG(NIUMX_DBG_A_INTX, dip,
940 		    "hvio_intr_setvalid failed, ret 0x%x\n", hvret);
941 		ret = DDI_FAILURE;
942 	} else
943 		ih_p->ih_state = valid;
944 
945 	return (ret);
946 }
947 
948 int
949 niumx_get_intr_target(niumx_devstate_t *niumxds_p, niudevino_t ino,
950     niucpuid_t *cpu_id)
951 {
952 	niumx_ih_t *ih_p;
953 	niusysino_t sysino;
954 	int rval = DDI_SUCCESS;
955 
956 	ih_p = niumxds_p->niumx_ihtable + ino;
957 
958 	sysino = ih_p->ih_sysino;
959 
960 	if (sysino == 0) {
961 		rval = EINVAL;
962 		goto done;
963 	}
964 
965 	if (hvio_intr_gettarget(sysino, cpu_id) != H_EOK) {
966 		rval = EINVAL;
967 		goto done;
968 	}
969 
970 	if (ih_p->ih_cpuid != *cpu_id)
971 		rval = EIO;
972 
973 done:
974 	return (rval);
975 }
976 
977 int
978 niumx_set_intr_target(niumx_devstate_t *niumxds_p, niudevino_t ino,
979     niucpuid_t cpu_id)
980 {
981 	dev_info_t *dip = niumxds_p->dip;
982 	niumx_ih_t *ih_p;
983 	niucpuid_t old_cpu_id;
984 	niusysino_t sysino;
985 	int ret = DDI_SUCCESS;
986 	int state;
987 	hrtime_t start;
988 	extern const int _ncpu;
989 	extern cpu_t *cpu[];
990 
991 	mutex_enter(&cpu_lock);
992 
993 	ih_p = niumxds_p->niumx_ihtable + ino;
994 
995 	sysino = ih_p->ih_sysino;
996 	if (sysino == 0) {
997 		ret = EINVAL;
998 		goto done;
999 	}
1000 
1001 	if (hvio_intr_gettarget(sysino, &old_cpu_id) != H_EOK) {
1002 		ret = EINVAL;
1003 		goto done;
1004 	}
1005 	if ((cpu_id < _ncpu) && (cpu[cpu_id] && cpu_is_online(cpu[cpu_id]))) {
1006 		if (cpu_id == old_cpu_id)
1007 			goto done;
1008 
1009 		/* check for pending interrupts, busy wait if so */
1010 		for (start = gethrtime(); !panicstr &&
1011 		    (hvio_intr_getstate(sysino, &state) == H_EOK) &&
1012 		    (state == HV_INTR_DELIVERED_STATE); /* */) {
1013 			if (gethrtime() - start > niumx_intr_timeout) {
1014 				cmn_err(CE_WARN, "%s%d: niumx_intr_dist: "
1015 				    "pending interrupt (%x,%lx) timedout\n",
1016 				    ddi_driver_name(dip), ddi_get_instance(dip),
1017 				    ih_p->ih_inum, sysino);
1018 				(void) hvio_intr_setstate(sysino,
1019 				    HV_INTR_IDLE_STATE);
1020 				break;
1021 			}
1022 		}
1023 		(void) hvio_intr_settarget(sysino, cpu_id);
1024 		if (ih_p->ih_state == HV_INTR_VALID)
1025 			(void) hvio_intr_setvalid(sysino, HV_INTR_VALID);
1026 		else
1027 			(void) hvio_intr_setvalid(sysino, HV_INTR_NOTVALID);
1028 		ih_p->ih_cpuid = cpu_id;
1029 	} else {
1030 		ret = DDI_EINVAL;
1031 	}
1032 
1033 done:
1034 	mutex_exit(&cpu_lock);
1035 	return (ret);
1036 }
1037 
1038 
1039 /*
1040  * niumx_add_intr:
1041  *
1042  * This function is called to register interrupts.
1043  */
1044 int
1045 niumx_add_intr(dev_info_t *dip, dev_info_t *rdip,
1046     ddi_intr_handle_impl_t *hdlp)
1047 {
1048 	niumx_ih_t	*ih_p;
1049 	int		ret = DDI_SUCCESS;
1050 	uint64_t	hvret;
1051 	niusysino_t	sysino;
1052 	niumx_devstate_t	*niumxds_p;	/* devstate pointer */
1053 	int		instance = ddi_get_instance(dip);
1054 
1055 	niumxds_p = (niumx_devstate_t *)ddi_get_soft_state(niumx_state,
1056 	    instance);
1057 
1058 	/* get new ino */
1059 	if (hdlp->ih_inum >= NIUMX_MAX_INTRS) {
1060 		DBG(NIUMX_DBG_INTR, dip, "error: inum %d out of range\n",
1061 		    hdlp->ih_inum);
1062 		ret = DDI_FAILURE;
1063 		goto done;
1064 	}
1065 
1066 	ih_p = niumxds_p->niumx_ihtable + hdlp->ih_vector;
1067 
1068 	if ((hvret = hvio_intr_devino_to_sysino(NIUMX_DIP_TO_HANDLE(dip),
1069 	    hdlp->ih_vector, &sysino)) != H_EOK) {
1070 		DBG(NIUMX_DBG_INTR, dip, "hvio_intr_devino_to_sysino failed, "
1071 		    "ret 0x%x\n", hvret);
1072 		ret = DDI_FAILURE;
1073 		goto done;
1074 	}
1075 	ih_p->ih_sysino = sysino;
1076 	ih_p->ih_dip = rdip;
1077 	ih_p->ih_inum = hdlp->ih_inum;
1078 	ih_p->ih_hdlr = hdlp->ih_cb_func;
1079 	ih_p->ih_arg1 = hdlp->ih_cb_arg1;
1080 	ih_p->ih_arg2 = hdlp->ih_cb_arg2;
1081 
1082 	DBG(NIUMX_DBG_A_INTX, dip, "niumx_add_intr: rdip=%s%d inum=0x%x "
1083 	    "handler=%p arg1=%p arg2=%p, new ih_p = %p\n", NIUMX_NAMEINST(rdip),
1084 	    hdlp->ih_inum, hdlp->ih_cb_func, hdlp->ih_cb_arg1,
1085 	    hdlp->ih_cb_arg2, ih_p);
1086 
1087 	if (hdlp->ih_pri == 0)
1088 		hdlp->ih_pri = NIUMX_DEFAULT_PIL;
1089 
1090 	ih_p->ih_pri = hdlp->ih_pri;
1091 
1092 	DBG(NIUMX_DBG_A_INTX, dip, "for ino %x adding (%x,%x)\n",
1093 	    hdlp->ih_vector, ih_p->ih_inum, ih_p->ih_sysino);
1094 
1095 	/* Save sysino value in hdlp */
1096 	hdlp->ih_vector = ih_p->ih_sysino;
1097 
1098 	/* swap in our handler & arg */
1099 	DDI_INTR_ASSIGN_HDLR_N_ARGS(hdlp, (ddi_intr_handler_t *)niumx_intr_hdlr,
1100 	    (void *)ih_p, NULL);
1101 
1102 	ret = i_ddi_add_ivintr(hdlp);
1103 
1104 	/* Restore orig. interrupt handler & args in handle. */
1105 	DDI_INTR_ASSIGN_HDLR_N_ARGS(hdlp, ih_p->ih_hdlr, ih_p->ih_arg1,
1106 	    ih_p->ih_arg2);
1107 
1108 	if (ret != DDI_SUCCESS) {
1109 		DBG(NIUMX_DBG_A_INTX, dip, "i_ddi_add_ivintr error ret=%x\n",
1110 		    ret);
1111 		goto done;
1112 	}
1113 
1114 	/* select cpu, saving it for removal */
1115 	ih_p->ih_cpuid = intr_dist_cpuid();
1116 
1117 	if ((hvret = hvio_intr_settarget(ih_p->ih_sysino, ih_p->ih_cpuid))
1118 	    != H_EOK) {
1119 		DBG(NIUMX_DBG_A_INTX, dip,
1120 		    "hvio_intr_settarget failed, ret 0x%x\n", hvret);
1121 		ret = DDI_FAILURE;
1122 	}
1123 done:
1124 	DBG(NIUMX_DBG_A_INTX, dip, "done, ret = %d, ih_p 0x%p, hdlp 0x%p\n",
1125 	    ih_p, hdlp, ret);
1126 	return (ret);
1127 }
1128 
1129 /*
1130  * niumx_rem_intr:
1131  *
1132  * This function is called to unregister interrupts.
1133  */
1134 /*ARGSUSED*/
1135 int
1136 niumx_rem_intr(dev_info_t *dip, dev_info_t *rdip,
1137     ddi_intr_handle_impl_t *hdlp)
1138 {
1139 	niumx_ih_t	*ih_p;
1140 	int		ret = DDI_SUCCESS, state;
1141 	hrtime_t	start;
1142 	niusysino_t 	sysino;
1143 	niumx_devstate_t	*niumxds_p;	/* devstate pointer */
1144 	int		instance = ddi_get_instance(dip);
1145 
1146 	niumxds_p = (niumx_devstate_t *)ddi_get_soft_state(niumx_state,
1147 	    instance);
1148 
1149 	ASSERT(hdlp->ih_inum < NIUMX_MAX_INTRS);
1150 
1151 	ih_p = niumxds_p->niumx_ihtable +  hdlp->ih_vector;
1152 
1153 	sysino = ih_p->ih_sysino;
1154 	DBG(NIUMX_DBG_R_INTX, dip, "removing (%x,%x)\n", ih_p->ih_inum, sysino);
1155 
1156 	(void) hvio_intr_setvalid(sysino, HV_INTR_NOTVALID);
1157 
1158 	/* check for pending interrupts, busy wait if so */
1159 	for (start = gethrtime(); !panicstr &&
1160 	    (hvio_intr_getstate(sysino, &state) == H_EOK) &&
1161 	    (state == HV_INTR_DELIVERED_STATE); /* */) {
1162 		if (gethrtime() - start > niumx_intr_timeout) {
1163 			cmn_err(CE_WARN, "%s%d: niumx_intr_dist: "
1164 			    "pending interrupt (%x,%lx) timedout\n",
1165 			    ddi_driver_name(dip), ddi_get_instance(dip),
1166 			    ih_p->ih_inum, sysino);
1167 			ret = DDI_FAILURE;
1168 			goto fail;
1169 		}
1170 	}
1171 
1172 	ih_p->ih_sysino = 0;
1173 
1174 	hdlp->ih_vector = (uint32_t)sysino;
1175 	if (hdlp->ih_vector !=  NULL) i_ddi_rem_ivintr(hdlp);
1176 
1177 fail:
1178 	return (ret);
1179 }
1180 
1181 /*
1182  * niumx_intr_hdlr (our interrupt handler)
1183  */
1184 uint_t
1185 niumx_intr_hdlr(void *arg)
1186 {
1187 	niumx_ih_t *ih_p = (niumx_ih_t *)arg;
1188 	uint_t		r;
1189 
1190 	DTRACE_PROBE4(interrupt__start, dev_info_t, ih_p->ih_dip, void *,
1191 	    ih_p->ih_hdlr, caddr_t, ih_p->ih_arg1, caddr_t, ih_p->ih_arg2);
1192 
1193 	r = (*ih_p->ih_hdlr)(ih_p->ih_arg1, ih_p->ih_arg2);
1194 
1195 	DTRACE_PROBE4(interrupt__complete, dev_info_t, ih_p->ih_dip, void *,
1196 	    ih_p->ih_hdlr, caddr_t, ih_p->ih_arg1, int, r);
1197 
1198 	(void) hvio_intr_setstate(ih_p->ih_sysino, HV_INTR_IDLE_STATE);
1199 	return (r);
1200 }
1201 
1202 #ifdef	DEBUG
1203 uint64_t niumx_debug_flags = 0;
1204 
1205 static char *niumx_debug_sym [] = {	/* same sequence as niumx_debug_bit */
1206 	/*  0 */ "attach",
1207 	/*  1 */ "map",
1208 	/*  2 */ "nex-ctlops",
1209 	/*  3 */ "introps",
1210 	/*  4 */ "intr-add",
1211 	/*  5 */ "intr-rem",
1212 	/*  6 */ "intr",
1213 	/*  7 */ "dma-alloc",
1214 	/*  8 */ "dma-bind",
1215 	/*  9 */ "dma-unbind",
1216 	/* 10 */ "chk-dma-mode"
1217 };
1218 
1219 /*ARGSUSED*/
1220 void
1221 niumx_dbg(niumx_debug_bit_t bit, dev_info_t *dip, char *fmt, ...)
1222 {
1223 	va_list ap;
1224 	char msgbuf[1024];
1225 
1226 	if (!(1ull << bit & niumx_debug_flags))
1227 		return;
1228 	va_start(ap, fmt);
1229 	(void) vsprintf(msgbuf, fmt, ap);
1230 	va_end(ap);
1231 	cmn_err(CE_NOTE, "%s: %s", niumx_debug_sym[bit], msgbuf);
1232 }
1233 
1234 #endif	/* DEBUG */
1235