xref: /illumos-gate/usr/src/uts/sun4v/io/vnet_dds.c (revision 63f531d1)
1678453a8Sspeer /*
2678453a8Sspeer  * CDDL HEADER START
3678453a8Sspeer  *
4678453a8Sspeer  * The contents of this file are subject to the terms of the
5678453a8Sspeer  * Common Development and Distribution License (the "License").
6678453a8Sspeer  * You may not use this file except in compliance with the License.
7678453a8Sspeer  *
8678453a8Sspeer  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9678453a8Sspeer  * or http://www.opensolaris.org/os/licensing.
10678453a8Sspeer  * See the License for the specific language governing permissions
11678453a8Sspeer  * and limitations under the License.
12678453a8Sspeer  *
13678453a8Sspeer  * When distributing Covered Code, include this CDDL HEADER in each
14678453a8Sspeer  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15678453a8Sspeer  * If applicable, add the following below this CDDL HEADER, with the
16678453a8Sspeer  * fields enclosed by brackets "[]" replaced with your own identifying
17678453a8Sspeer  * information: Portions Copyright [yyyy] [name of copyright owner]
18678453a8Sspeer  *
19678453a8Sspeer  * CDDL HEADER END
20678453a8Sspeer  */
21678453a8Sspeer 
22678453a8Sspeer /*
236d6de4eeSWENTAO YANG  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24678453a8Sspeer  * Use is subject to license terms.
25678453a8Sspeer  */
26678453a8Sspeer 
27678453a8Sspeer #include <sys/modctl.h>
28678453a8Sspeer #include <sys/prom_plat.h>
29678453a8Sspeer #include <sys/ddi.h>
30678453a8Sspeer #include <sys/sunddi.h>
31678453a8Sspeer #include <sys/sunndi.h>
32678453a8Sspeer #include <sys/ndi_impldefs.h>
33678453a8Sspeer #include <sys/ddi_impldefs.h>
34678453a8Sspeer #include <sys/ethernet.h>
35678453a8Sspeer #include <sys/machsystm.h>
36678453a8Sspeer #include <sys/hypervisor_api.h>
37678453a8Sspeer #include <sys/mach_descrip.h>
38678453a8Sspeer #include <sys/drctl.h>
39678453a8Sspeer #include <sys/dr_util.h>
40678453a8Sspeer #include <sys/mac.h>
41678453a8Sspeer #include <sys/vnet.h>
42678453a8Sspeer #include <sys/vnet_mailbox.h>
43678453a8Sspeer #include <sys/vnet_common.h>
44678453a8Sspeer #include <sys/hsvc.h>
45678453a8Sspeer 
46678453a8Sspeer 
47678453a8Sspeer #define	VDDS_MAX_RANGES		6	/* 6 possible VRs */
48678453a8Sspeer #define	VDDS_MAX_VRINTRS	8	/* limited to 8 intrs/VR */
49678453a8Sspeer #define	VDDS_MAX_INTR_NUM	64	/* 0-63 or valid */
50678453a8Sspeer 
51678453a8Sspeer #define	VDDS_INO_RANGE_START(x) (x * VDDS_MAX_VRINTRS)
52678453a8Sspeer #define	HVCOOKIE(c)	((c) & 0xFFFFFFFFF)
53678453a8Sspeer #define	NIUCFGHDL(c)	((c) >> 32)
54678453a8Sspeer 
55678453a8Sspeer 
56678453a8Sspeer /* For "ranges" property */
57678453a8Sspeer typedef struct vdds_ranges {
58678453a8Sspeer 	uint32_t child_hi;
59678453a8Sspeer 	uint32_t child_lo;
60678453a8Sspeer 	uint32_t parent_hi;
61678453a8Sspeer 	uint32_t parent_lo;
62678453a8Sspeer 	uint32_t size_hi;
63678453a8Sspeer 	uint32_t size_lo;
64678453a8Sspeer } vdds_ranges_t;
65678453a8Sspeer 
66678453a8Sspeer /* For "reg" property */
67678453a8Sspeer typedef struct vdds_reg {
68678453a8Sspeer 	uint32_t addr_hi;
69678453a8Sspeer 	uint32_t addr_lo;
70678453a8Sspeer 	uint32_t size_hi;
71678453a8Sspeer 	uint32_t size_lo;
72678453a8Sspeer } vdds_reg_t;
73678453a8Sspeer 
74678453a8Sspeer /* For ddi callback argument */
75678453a8Sspeer typedef struct vdds_cb_arg {
76678453a8Sspeer 	dev_info_t *dip;
77678453a8Sspeer 	uint64_t cookie;
78678453a8Sspeer 	uint64_t macaddr;
797b1f684aSSriharsha Basavapatna 	uint32_t max_frame_size;
80678453a8Sspeer } vdds_cb_arg_t;
81678453a8Sspeer 
82678453a8Sspeer 
83678453a8Sspeer /* Functions exported to other files */
84678453a8Sspeer void vdds_mod_init(void);
85678453a8Sspeer void vdds_mod_fini(void);
86678453a8Sspeer int vdds_init(vnet_t *vnetp);
87678453a8Sspeer void vdds_cleanup(vnet_t *vnetp);
88678453a8Sspeer void vdds_process_dds_msg(vnet_t *vnetp, vio_dds_msg_t *dmsg);
89d0288fccSRaghuram Kothakota void vdds_cleanup_hybrid_res(void *arg);
906d6de4eeSWENTAO YANG void vdds_cleanup_hio(vnet_t *vnetp);
91678453a8Sspeer 
92678453a8Sspeer /* Support functions to create/destory Hybrid device */
937b1f684aSSriharsha Basavapatna static dev_info_t *vdds_create_niu_node(uint64_t cookie,
947b1f684aSSriharsha Basavapatna     uint64_t macaddr, uint32_t max_frame_size);
95678453a8Sspeer static int vdds_destroy_niu_node(dev_info_t *niu_dip, uint64_t cookie);
967b1f684aSSriharsha Basavapatna static dev_info_t *vdds_create_new_node(vdds_cb_arg_t *cba,
97678453a8Sspeer     dev_info_t *pdip, int (*new_node_func)(dev_info_t *dip,
98678453a8Sspeer     void *arg, uint_t flags));
99678453a8Sspeer static int vdds_new_nexus_node(dev_info_t *dip, void *arg, uint_t flags);
100678453a8Sspeer static int vdds_new_niu_node(dev_info_t *dip, void *arg, uint_t flags);
101678453a8Sspeer static dev_info_t *vdds_find_node(uint64_t cookie, dev_info_t *sdip,
102678453a8Sspeer 	int (*match_func)(dev_info_t *dip, void *arg));
103678453a8Sspeer static int vdds_match_niu_nexus(dev_info_t *dip, void *arg);
104678453a8Sspeer static int vdds_match_niu_node(dev_info_t *dip, void *arg);
105678453a8Sspeer static int vdds_get_interrupts(uint64_t cookie, int ino_range,
106678453a8Sspeer     int *intrs, int *nintr);
107678453a8Sspeer 
108678453a8Sspeer /* DDS message processing related functions */
109678453a8Sspeer static void vdds_process_dds_msg_task(void *arg);
110678453a8Sspeer static int vdds_send_dds_resp_msg(vnet_t *vnetp, vio_dds_msg_t *dmsg, int ack);
111678453a8Sspeer static int vdds_send_dds_rel_msg(vnet_t *vnetp);
112678453a8Sspeer static void vdds_release_range_prop(dev_info_t *nexus_dip, uint64_t cookie);
113678453a8Sspeer 
114678453a8Sspeer /* Functions imported from other files */
115678453a8Sspeer extern int vnet_send_dds_msg(vnet_t *vnetp, void *dmsg);
116*63f531d1SSriharsha Basavapatna extern int vnet_hio_mac_init(vnet_t *vnetp, char *ifname);
117*63f531d1SSriharsha Basavapatna extern void vnet_hio_mac_cleanup(vnet_t *vnetp);
118678453a8Sspeer 
119678453a8Sspeer /* HV functions that are used in this file */
120678453a8Sspeer extern uint64_t vdds_hv_niu_vr_getinfo(uint32_t hvcookie,
121678453a8Sspeer     uint64_t *real_start, uint64_t *size);
122678453a8Sspeer extern uint64_t vdds_hv_niu_vr_get_txmap(uint32_t hvcookie, uint64_t *dma_map);
123678453a8Sspeer extern uint64_t vdds_hv_niu_vr_get_rxmap(uint32_t hvcookie, uint64_t *dma_map);
124678453a8Sspeer extern uint64_t vdds_hv_niu_vrtx_set_ino(uint32_t cookie, uint64_t vch_idx,
125678453a8Sspeer     uint32_t ino);
126678453a8Sspeer extern uint64_t vdds_hv_niu_vrrx_set_ino(uint32_t cookie, uint64_t vch_idx,
127678453a8Sspeer     uint32_t ino);
128678453a8Sspeer 
129678453a8Sspeer 
130678453a8Sspeer #ifdef DEBUG
131678453a8Sspeer 
132678453a8Sspeer extern int vnet_dbglevel;
133678453a8Sspeer 
134678453a8Sspeer static void
135678453a8Sspeer debug_printf(const char *fname, void *arg,  const char *fmt, ...)
136678453a8Sspeer {
137678453a8Sspeer 	char    buf[512];
138678453a8Sspeer 	va_list ap;
139678453a8Sspeer 	char    *bufp = buf;
140678453a8Sspeer 	vnet_dds_info_t *vdds = arg;
141678453a8Sspeer 
142678453a8Sspeer 	if (vdds != NULL) {
143678453a8Sspeer 		(void) sprintf(bufp, "vnet%d: %s: ",
144678453a8Sspeer 		    vdds->vnetp->instance, fname);
145678453a8Sspeer 	} else {
146678453a8Sspeer 		(void) sprintf(bufp, "%s: ", fname);
147678453a8Sspeer 	}
148678453a8Sspeer 	bufp += strlen(bufp);
149678453a8Sspeer 	va_start(ap, fmt);
150678453a8Sspeer 	(void) vsprintf(bufp, fmt, ap);
151678453a8Sspeer 	va_end(ap);
152678453a8Sspeer 	cmn_err(CE_CONT, "%s\n", buf);
153678453a8Sspeer }
154678453a8Sspeer #endif
155678453a8Sspeer 
156678453a8Sspeer /*
157678453a8Sspeer  * Hypervisor N2/NIU services information.
158678453a8Sspeer  */
159678453a8Sspeer static hsvc_info_t niu_hsvc = {
160678453a8Sspeer 	HSVC_REV_1, NULL, HSVC_GROUP_NIU, 1, 1, "vnet_dds"
161678453a8Sspeer };
162678453a8Sspeer 
163d0288fccSRaghuram Kothakota /*
164d0288fccSRaghuram Kothakota  * Lock to serialize the NIU device node related operations.
165d0288fccSRaghuram Kothakota  */
166d0288fccSRaghuram Kothakota kmutex_t vdds_dev_lock;
167d0288fccSRaghuram Kothakota 
168678453a8Sspeer boolean_t vdds_hv_hio_capable = B_FALSE;
169678453a8Sspeer 
170678453a8Sspeer /*
171678453a8Sspeer  * vdds_mod_init -- one time initialization.
172678453a8Sspeer  */
173678453a8Sspeer void
174678453a8Sspeer vdds_mod_init(void)
175678453a8Sspeer {
176678453a8Sspeer 	int rv;
177678453a8Sspeer 	uint64_t minor;
178678453a8Sspeer 
179678453a8Sspeer 	rv = hsvc_register(&niu_hsvc, &minor);
180678453a8Sspeer 	/*
181678453a8Sspeer 	 * Only HV version 1.1 is capable of NIU Hybrid IO.
182678453a8Sspeer 	 */
183678453a8Sspeer 	if ((rv == 0) && (minor == 1)) {
184678453a8Sspeer 		vdds_hv_hio_capable = B_TRUE;
185678453a8Sspeer 	}
186d0288fccSRaghuram Kothakota 	mutex_init(&vdds_dev_lock, NULL, MUTEX_DRIVER, NULL);
187678453a8Sspeer 	DBG1(NULL, "HV HIO capable");
188678453a8Sspeer }
189678453a8Sspeer 
190678453a8Sspeer /*
191678453a8Sspeer  * vdds_mod_fini -- one time cleanup.
192678453a8Sspeer  */
193678453a8Sspeer void
194678453a8Sspeer vdds_mod_fini(void)
195678453a8Sspeer {
196678453a8Sspeer 	(void) hsvc_unregister(&niu_hsvc);
197d0288fccSRaghuram Kothakota 	mutex_destroy(&vdds_dev_lock);
198678453a8Sspeer }
199678453a8Sspeer 
200678453a8Sspeer /*
201678453a8Sspeer  * vdds_init -- vnet instance related DDS related initialization.
202678453a8Sspeer  */
203678453a8Sspeer int
204678453a8Sspeer vdds_init(vnet_t *vnetp)
205678453a8Sspeer {
206678453a8Sspeer 	vnet_dds_info_t *vdds = &vnetp->vdds_info;
207678453a8Sspeer 	char		qname[TASKQ_NAMELEN];
208678453a8Sspeer 
209678453a8Sspeer 	vdds->vnetp = vnetp;
210678453a8Sspeer 	DBG1(vdds, "Initializing..");
211678453a8Sspeer 	(void) snprintf(qname, TASKQ_NAMELEN, "vdds_taskq%d", vnetp->instance);
212678453a8Sspeer 	if ((vdds->dds_taskqp = ddi_taskq_create(vnetp->dip, qname, 1,
213678453a8Sspeer 	    TASKQ_DEFAULTPRI, 0)) == NULL) {
214678453a8Sspeer 		cmn_err(CE_WARN, "!vnet%d: Unable to create DDS task queue",
215678453a8Sspeer 		    vnetp->instance);
216678453a8Sspeer 		return (ENOMEM);
217678453a8Sspeer 	}
218678453a8Sspeer 	mutex_init(&vdds->lock, NULL, MUTEX_DRIVER, NULL);
219678453a8Sspeer 	return (0);
220678453a8Sspeer }
221678453a8Sspeer 
222678453a8Sspeer /*
223678453a8Sspeer  * vdds_cleanup -- vnet instance related cleanup.
224678453a8Sspeer  */
225678453a8Sspeer void
226678453a8Sspeer vdds_cleanup(vnet_t *vnetp)
227678453a8Sspeer {
228678453a8Sspeer 	vnet_dds_info_t *vdds = &vnetp->vdds_info;
229678453a8Sspeer 
230678453a8Sspeer 	DBG1(vdds, "Cleanup...");
231678453a8Sspeer 	/* Cleanup/destroy any hybrid resouce that exists */
232678453a8Sspeer 	vdds_cleanup_hybrid_res(vnetp);
233678453a8Sspeer 
234678453a8Sspeer 	/* taskq_destroy will wait for all taskqs to complete */
235678453a8Sspeer 	ddi_taskq_destroy(vdds->dds_taskqp);
236678453a8Sspeer 	vdds->dds_taskqp = NULL;
237678453a8Sspeer 	mutex_destroy(&vdds->lock);
238678453a8Sspeer 	DBG1(vdds, "Cleanup complete");
239678453a8Sspeer }
240678453a8Sspeer 
241678453a8Sspeer /*
242678453a8Sspeer  * vdds_cleanup_hybrid_res -- Cleanup Hybrid resource.
243678453a8Sspeer  */
244678453a8Sspeer void
245d0288fccSRaghuram Kothakota vdds_cleanup_hybrid_res(void *arg)
246678453a8Sspeer {
247d0288fccSRaghuram Kothakota 	vnet_t *vnetp = arg;
248678453a8Sspeer 	vnet_dds_info_t *vdds = &vnetp->vdds_info;
249678453a8Sspeer 
250678453a8Sspeer 	DBG1(vdds, "Hybrid device cleanup...");
251678453a8Sspeer 	mutex_enter(&vdds->lock);
252678453a8Sspeer 	if (vdds->task_flags == VNET_DDS_TASK_ADD_SHARE) {
253678453a8Sspeer 		/*
254678453a8Sspeer 		 * Task for ADD_SHARE is pending, simply
255678453a8Sspeer 		 * cleanup the flags, the task will quit without
256678453a8Sspeer 		 * any changes.
257678453a8Sspeer 		 */
258678453a8Sspeer 		vdds->task_flags = 0;
259678453a8Sspeer 		DBG2(vdds, "Task for ADD is pending, clean flags only");
260678453a8Sspeer 	} else if ((vdds->hio_dip != NULL) && (vdds->task_flags == 0)) {
261678453a8Sspeer 		/*
262678453a8Sspeer 		 * There is no task pending and a hybrid device
263678453a8Sspeer 		 * is present, so dispatch a task to release the share.
264678453a8Sspeer 		 */
265678453a8Sspeer 		vdds->task_flags = VNET_DDS_TASK_REL_SHARE;
266678453a8Sspeer 		(void) ddi_taskq_dispatch(vdds->dds_taskqp,
267678453a8Sspeer 		    vdds_process_dds_msg_task, vnetp, DDI_NOSLEEP);
268678453a8Sspeer 		DBG2(vdds, "Dispatched a task to destroy HIO device");
269678453a8Sspeer 	}
270678453a8Sspeer 	/*
271678453a8Sspeer 	 * Other possible cases include either DEL_SHARE or
272678453a8Sspeer 	 * REL_SHARE as pending. In that case, there is nothing
273678453a8Sspeer 	 * to do as a task is already pending to do the cleanup.
274678453a8Sspeer 	 */
275678453a8Sspeer 	mutex_exit(&vdds->lock);
276678453a8Sspeer 	DBG1(vdds, "Hybrid device cleanup complete");
277678453a8Sspeer }
278678453a8Sspeer 
2796d6de4eeSWENTAO YANG /*
2806d6de4eeSWENTAO YANG  * vdds_cleanup_hio -- An interface to cleanup the hio resources before
2816d6de4eeSWENTAO YANG  *	resetting the vswitch port.
2826d6de4eeSWENTAO YANG  */
2836d6de4eeSWENTAO YANG void
2846d6de4eeSWENTAO YANG vdds_cleanup_hio(vnet_t *vnetp)
2856d6de4eeSWENTAO YANG {
2866d6de4eeSWENTAO YANG 	vnet_dds_info_t *vdds = &vnetp->vdds_info;
2876d6de4eeSWENTAO YANG 
2886d6de4eeSWENTAO YANG 	/* Wait for any pending vdds tasks to complete */
2896d6de4eeSWENTAO YANG 	ddi_taskq_wait(vdds->dds_taskqp);
2906d6de4eeSWENTAO YANG 	vdds_cleanup_hybrid_res(vnetp);
2916d6de4eeSWENTAO YANG 	/* Wait for the cleanup task to complete */
2926d6de4eeSWENTAO YANG 	ddi_taskq_wait(vdds->dds_taskqp);
2936d6de4eeSWENTAO YANG }
2946d6de4eeSWENTAO YANG 
295678453a8Sspeer /*
296678453a8Sspeer  * vdds_process_dds_msg -- Process a DDS message.
297678453a8Sspeer  */
298678453a8Sspeer void
299678453a8Sspeer vdds_process_dds_msg(vnet_t *vnetp, vio_dds_msg_t *dmsg)
300678453a8Sspeer {
301678453a8Sspeer 	vnet_dds_info_t *vdds = &vnetp->vdds_info;
302678453a8Sspeer 	int rv;
303678453a8Sspeer 
304678453a8Sspeer 	DBG1(vdds, "DDS message received...");
305678453a8Sspeer 
306678453a8Sspeer 	if (dmsg->dds_class != DDS_VNET_NIU) {
307678453a8Sspeer 		DBG2(vdds, "Invalid class send NACK");
308678453a8Sspeer 		(void) vdds_send_dds_resp_msg(vnetp, dmsg, B_FALSE);
309678453a8Sspeer 		return;
310678453a8Sspeer 	}
311678453a8Sspeer 	mutex_enter(&vdds->lock);
312678453a8Sspeer 	switch (dmsg->dds_subclass) {
313678453a8Sspeer 	case DDS_VNET_ADD_SHARE:
314678453a8Sspeer 		DBG2(vdds, "DDS_VNET_ADD_SHARE message...");
315678453a8Sspeer 		if ((vdds->task_flags != 0) || (vdds->hio_dip != NULL)) {
316678453a8Sspeer 			/*
317678453a8Sspeer 			 * Either a task is already pending or
318678453a8Sspeer 			 * a hybrid device already exists.
319678453a8Sspeer 			 */
320678453a8Sspeer 			DWARN(vdds, "NACK: Already pending DDS task");
321678453a8Sspeer 			(void) vdds_send_dds_resp_msg(vnetp, dmsg, B_FALSE);
322678453a8Sspeer 			mutex_exit(&vdds->lock);
323678453a8Sspeer 			return;
324678453a8Sspeer 		}
325678453a8Sspeer 		vdds->task_flags = VNET_DDS_TASK_ADD_SHARE;
326678453a8Sspeer 		bcopy(dmsg, &vnetp->vdds_info.dmsg, sizeof (vio_dds_msg_t));
327678453a8Sspeer 		DBG2(vdds, "Dispatching task for ADD_SHARE");
328678453a8Sspeer 		rv = ddi_taskq_dispatch(vdds->dds_taskqp,
329678453a8Sspeer 		    vdds_process_dds_msg_task, vnetp, DDI_NOSLEEP);
330678453a8Sspeer 		if (rv != 0) {
331678453a8Sspeer 			/* Send NACK */
332678453a8Sspeer 			DBG2(vdds, "NACK: Failed to dispatch task");
333678453a8Sspeer 			(void) vdds_send_dds_resp_msg(vnetp, dmsg, B_FALSE);
334678453a8Sspeer 			vdds->task_flags = 0;
335678453a8Sspeer 		}
336678453a8Sspeer 		break;
337678453a8Sspeer 
338678453a8Sspeer 	case DDS_VNET_DEL_SHARE:
339678453a8Sspeer 		DBG2(vdds, "DDS_VNET_DEL_SHARE message...");
340678453a8Sspeer 		if (vdds->task_flags == VNET_DDS_TASK_ADD_SHARE) {
341678453a8Sspeer 			/*
342678453a8Sspeer 			 * ADD_SHARE task still pending, simply clear
343678453a8Sspeer 			 * task falgs and ACK.
344678453a8Sspeer 			 */
345678453a8Sspeer 			DBG2(vdds, "ACK:ADD_SHARE task still pending");
346678453a8Sspeer 			vdds->task_flags = 0;
347678453a8Sspeer 			(void) vdds_send_dds_resp_msg(vnetp, dmsg, B_TRUE);
348678453a8Sspeer 			mutex_exit(&vdds->lock);
349678453a8Sspeer 			return;
350678453a8Sspeer 		}
351678453a8Sspeer 		if ((vdds->task_flags == 0) && (vdds->hio_dip == NULL)) {
352678453a8Sspeer 			/* Send NACK */
353678453a8Sspeer 			DBG2(vdds, "NACK:No HIO device exists");
354678453a8Sspeer 			(void) vdds_send_dds_resp_msg(vnetp, dmsg, B_FALSE);
355678453a8Sspeer 			mutex_exit(&vdds->lock);
356678453a8Sspeer 			return;
357678453a8Sspeer 		}
358678453a8Sspeer 		vdds->task_flags = VNET_DDS_TASK_DEL_SHARE;
359678453a8Sspeer 		bcopy(dmsg, &vdds->dmsg, sizeof (vio_dds_msg_t));
360678453a8Sspeer 		DBG2(vdds, "Dispatching DEL_SHARE task");
361678453a8Sspeer 		rv = ddi_taskq_dispatch(vdds->dds_taskqp,
362678453a8Sspeer 		    vdds_process_dds_msg_task, vnetp, DDI_NOSLEEP);
363678453a8Sspeer 		if (rv != 0) {
364678453a8Sspeer 			/* Send NACK */
365678453a8Sspeer 			DBG2(vdds, "NACK: failed to dispatch task");
366678453a8Sspeer 			(void) vdds_send_dds_resp_msg(vnetp, dmsg, B_FALSE);
367678453a8Sspeer 			vdds->task_flags = 0;
368678453a8Sspeer 		}
369678453a8Sspeer 		break;
370678453a8Sspeer 	case DDS_VNET_REL_SHARE:
371678453a8Sspeer 		DBG2(vdds, "Reply for REL_SHARE reply=%d",
372678453a8Sspeer 		    dmsg->tag.vio_subtype);
373678453a8Sspeer 		break;
374678453a8Sspeer 	default:
375678453a8Sspeer 		DWARN(vdds, "Discarding Unknown DDS message");
376678453a8Sspeer 		break;
377678453a8Sspeer 	}
378678453a8Sspeer 	mutex_exit(&vdds->lock);
379678453a8Sspeer }
380678453a8Sspeer 
381678453a8Sspeer /*
382678453a8Sspeer  * vdds_process_dds_msg_task -- Called from a taskq to process the
383678453a8Sspeer  *	DDS message.
384678453a8Sspeer  */
385678453a8Sspeer static void
386678453a8Sspeer vdds_process_dds_msg_task(void *arg)
387678453a8Sspeer {
388678453a8Sspeer 	vnet_t		*vnetp = arg;
389678453a8Sspeer 	vnet_dds_info_t	*vdds = &vnetp->vdds_info;
390678453a8Sspeer 	vio_dds_msg_t	*dmsg = &vdds->dmsg;
391678453a8Sspeer 	dev_info_t	*dip;
3927b1f684aSSriharsha Basavapatna 	uint32_t	max_frame_size;
393678453a8Sspeer 	uint64_t	hio_cookie;
394678453a8Sspeer 	int		rv;
395678453a8Sspeer 
396678453a8Sspeer 	DBG1(vdds, "DDS task started...");
397678453a8Sspeer 	mutex_enter(&vdds->lock);
398678453a8Sspeer 	switch (vdds->task_flags) {
399678453a8Sspeer 	case VNET_DDS_TASK_ADD_SHARE:
400678453a8Sspeer 		DBG2(vdds, "ADD_SHARE task...");
401678453a8Sspeer 		hio_cookie = dmsg->msg.share_msg.cookie;
4027b1f684aSSriharsha Basavapatna 		/*
4037b1f684aSSriharsha Basavapatna 		 * max-frame-size value need to be set to
4047b1f684aSSriharsha Basavapatna 		 * the full ethernet frame size. That is,
4057b1f684aSSriharsha Basavapatna 		 * header + payload + checksum.
4067b1f684aSSriharsha Basavapatna 		 */
4077b1f684aSSriharsha Basavapatna 		max_frame_size = vnetp->mtu +
4087b1f684aSSriharsha Basavapatna 		    sizeof (struct  ether_vlan_header) + ETHERFCSL;
409678453a8Sspeer 		dip = vdds_create_niu_node(hio_cookie,
4107b1f684aSSriharsha Basavapatna 		    dmsg->msg.share_msg.macaddr, max_frame_size);
411678453a8Sspeer 		if (dip == NULL) {
412678453a8Sspeer 			(void) vdds_send_dds_resp_msg(vnetp, dmsg, B_FALSE);
413678453a8Sspeer 			DERR(vdds, "Failed to create HIO node");
414678453a8Sspeer 		} else {
415678453a8Sspeer 			vdds->hio_dip = dip;
416678453a8Sspeer 			vdds->hio_cookie = hio_cookie;
417*63f531d1SSriharsha Basavapatna 			sprintf(vdds->hio_ifname, "%s%d", ddi_driver_name(dip),
418*63f531d1SSriharsha Basavapatna 			    ddi_get_instance(dip));
419*63f531d1SSriharsha Basavapatna 
420*63f531d1SSriharsha Basavapatna 			rv = vnet_hio_mac_init(vnetp, vdds->hio_ifname);
421*63f531d1SSriharsha Basavapatna 			if (rv != 0) {
422*63f531d1SSriharsha Basavapatna 				/* failed - cleanup, send failed DDS message */
423*63f531d1SSriharsha Basavapatna 				DERR(vdds, "HIO mac init failed, cleaning up");
424*63f531d1SSriharsha Basavapatna 				rv = vdds_destroy_niu_node(dip, hio_cookie);
425*63f531d1SSriharsha Basavapatna 				if (rv == 0) {
426*63f531d1SSriharsha Basavapatna 					/* use DERR to print by default */
427*63f531d1SSriharsha Basavapatna 					DERR(vdds, "Successfully destroyed"
428*63f531d1SSriharsha Basavapatna 					    " Hybrid node");
429*63f531d1SSriharsha Basavapatna 				} else {
430*63f531d1SSriharsha Basavapatna 					cmn_err(CE_WARN, "vnet%d:Failed to "
431*63f531d1SSriharsha Basavapatna 					    "destroy Hybrid node",
432*63f531d1SSriharsha Basavapatna 					    vnetp->instance);
433*63f531d1SSriharsha Basavapatna 				}
434*63f531d1SSriharsha Basavapatna 				vdds->hio_dip = NULL;
435*63f531d1SSriharsha Basavapatna 				vdds->hio_cookie = 0;
436*63f531d1SSriharsha Basavapatna 				(void) vdds_send_dds_resp_msg(vnetp,
437*63f531d1SSriharsha Basavapatna 				    dmsg, B_FALSE);
438*63f531d1SSriharsha Basavapatna 			} else {
439*63f531d1SSriharsha Basavapatna 				(void) vdds_send_dds_resp_msg(vnetp,
440*63f531d1SSriharsha Basavapatna 				    dmsg, B_TRUE);
441*63f531d1SSriharsha Basavapatna 			}
442678453a8Sspeer 			/* DERR used only print by default */
443678453a8Sspeer 			DERR(vdds, "Successfully created HIO node");
444678453a8Sspeer 		}
445678453a8Sspeer 		break;
446678453a8Sspeer 
447678453a8Sspeer 	case VNET_DDS_TASK_DEL_SHARE:
448678453a8Sspeer 		DBG2(vdds, "DEL_SHARE task...");
449678453a8Sspeer 		if (vnetp->vdds_info.hio_dip == NULL) {
450678453a8Sspeer 			DBG2(vdds, "NACK: No HIO device destroy");
451678453a8Sspeer 			(void) vdds_send_dds_resp_msg(vnetp, dmsg, B_FALSE);
452678453a8Sspeer 		} else {
453*63f531d1SSriharsha Basavapatna 			vnet_hio_mac_cleanup(vnetp);
454678453a8Sspeer 			rv = vdds_destroy_niu_node(vnetp->vdds_info.hio_dip,
455678453a8Sspeer 			    vdds->hio_cookie);
456678453a8Sspeer 			if (rv == 0) {
457678453a8Sspeer 				/* use DERR to print by default */
458678453a8Sspeer 				DERR(vdds, "Successfully destroyed"
459678453a8Sspeer 				    " Hybrid node");
460678453a8Sspeer 			} else {
461678453a8Sspeer 				cmn_err(CE_WARN, "vnet%d:Failed to "
462678453a8Sspeer 				    "destroy Hybrid node", vnetp->instance);
463678453a8Sspeer 			}
464678453a8Sspeer 			/* TODO: send ACK even for failure? */
465678453a8Sspeer 			DBG2(vdds, "ACK: HIO device destroyed");
466678453a8Sspeer 			(void) vdds_send_dds_resp_msg(vnetp, dmsg, B_TRUE);
467678453a8Sspeer 			vdds->hio_dip = 0;
468678453a8Sspeer 			vdds->hio_cookie = 0;
469678453a8Sspeer 		}
470678453a8Sspeer 		break;
471678453a8Sspeer 	case VNET_DDS_TASK_REL_SHARE:
472678453a8Sspeer 		DBG2(vdds, "REL_SHARE task...");
473678453a8Sspeer 		if (vnetp->vdds_info.hio_dip != NULL) {
474*63f531d1SSriharsha Basavapatna 			vnet_hio_mac_cleanup(vnetp);
475678453a8Sspeer 			rv = vdds_destroy_niu_node(vnetp->vdds_info.hio_dip,
476678453a8Sspeer 			    vdds->hio_cookie);
477678453a8Sspeer 			if (rv == 0) {
478678453a8Sspeer 				DERR(vdds, "Successfully destroyed "
479678453a8Sspeer 				    "Hybrid node");
480678453a8Sspeer 			} else {
481678453a8Sspeer 				cmn_err(CE_WARN, "vnet%d:Failed to "
482678453a8Sspeer 				    "destroy HIO node", vnetp->instance);
483678453a8Sspeer 			}
484678453a8Sspeer 			/* TODO: failure case */
485678453a8Sspeer 			(void) vdds_send_dds_rel_msg(vnetp);
486678453a8Sspeer 			vdds->hio_dip = 0;
487678453a8Sspeer 			vdds->hio_cookie = 0;
488678453a8Sspeer 		}
489678453a8Sspeer 		break;
490678453a8Sspeer 	default:
491678453a8Sspeer 		break;
492678453a8Sspeer 	}
493678453a8Sspeer 	vdds->task_flags = 0;
494678453a8Sspeer 	mutex_exit(&vdds->lock);
495678453a8Sspeer }
496678453a8Sspeer 
497678453a8Sspeer /*
498678453a8Sspeer  * vdds_send_dds_rel_msg -- Send a DDS_REL_SHARE message.
499678453a8Sspeer  */
500678453a8Sspeer static int
501678453a8Sspeer vdds_send_dds_rel_msg(vnet_t *vnetp)
502678453a8Sspeer {
503678453a8Sspeer 	vnet_dds_info_t *vdds = &vnetp->vdds_info;
504678453a8Sspeer 	vio_dds_msg_t	vmsg;
505678453a8Sspeer 	dds_share_msg_t	*smsg = &vmsg.msg.share_msg;
506678453a8Sspeer 	int rv;
507678453a8Sspeer 
508678453a8Sspeer 	DBG1(vdds, "Sending DDS_VNET_REL_SHARE message");
509678453a8Sspeer 	vmsg.tag.vio_msgtype = VIO_TYPE_CTRL;
510678453a8Sspeer 	vmsg.tag.vio_subtype = VIO_SUBTYPE_INFO;
511678453a8Sspeer 	vmsg.tag.vio_subtype_env = VIO_DDS_INFO;
512678453a8Sspeer 	/* vio_sid filled by the LDC module */
513678453a8Sspeer 	vmsg.dds_class = DDS_VNET_NIU;
514678453a8Sspeer 	vmsg.dds_subclass = DDS_VNET_REL_SHARE;
515678453a8Sspeer 	vmsg.dds_req_id = (++vdds->dds_req_id);
516678453a8Sspeer 	smsg->macaddr = vnet_macaddr_strtoul(vnetp->curr_macaddr);
517678453a8Sspeer 	smsg->cookie = vdds->hio_cookie;
518678453a8Sspeer 	rv = vnet_send_dds_msg(vnetp, &vmsg);
519678453a8Sspeer 	return (rv);
520678453a8Sspeer }
521678453a8Sspeer 
522678453a8Sspeer /*
523678453a8Sspeer  * vdds_send_dds_resp_msg -- Send a DDS response message.
524678453a8Sspeer  */
525678453a8Sspeer static int
526678453a8Sspeer vdds_send_dds_resp_msg(vnet_t *vnetp, vio_dds_msg_t *dmsg, int ack)
527678453a8Sspeer {
528678453a8Sspeer 	vnet_dds_info_t *vdds = &vnetp->vdds_info;
529678453a8Sspeer 	int rv;
530678453a8Sspeer 
531678453a8Sspeer 	DBG1(vdds, "Sending a response mesage=%d", ack);
532678453a8Sspeer 	if (ack == B_TRUE) {
533678453a8Sspeer 		dmsg->tag.vio_subtype = VIO_SUBTYPE_ACK;
534678453a8Sspeer 		dmsg->msg.share_resp_msg.status = DDS_VNET_SUCCESS;
535678453a8Sspeer 	} else {
536678453a8Sspeer 		dmsg->tag.vio_subtype = VIO_SUBTYPE_NACK;
537678453a8Sspeer 		dmsg->msg.share_resp_msg.status = DDS_VNET_FAIL;
538678453a8Sspeer 	}
539678453a8Sspeer 	rv = vnet_send_dds_msg(vnetp, dmsg);
540678453a8Sspeer 	return (rv);
541678453a8Sspeer }
542678453a8Sspeer 
543678453a8Sspeer /*
544678453a8Sspeer  * vdds_create_niu_node -- Create NIU Hybrid node. The NIU nexus
545678453a8Sspeer  *	node also created if it doesn't exist already.
546678453a8Sspeer  */
547678453a8Sspeer dev_info_t *
5487b1f684aSSriharsha Basavapatna vdds_create_niu_node(uint64_t cookie, uint64_t macaddr, uint32_t max_frame_size)
549678453a8Sspeer {
550678453a8Sspeer 	dev_info_t *nexus_dip;
551678453a8Sspeer 	dev_info_t *niu_dip;
5527b1f684aSSriharsha Basavapatna 	vdds_cb_arg_t cba;
553678453a8Sspeer 
554678453a8Sspeer 	DBG1(NULL, "Called");
555678453a8Sspeer 
556678453a8Sspeer 	if (vdds_hv_hio_capable == B_FALSE) {
557678453a8Sspeer 		return (NULL);
558678453a8Sspeer 	}
559d0288fccSRaghuram Kothakota 	mutex_enter(&vdds_dev_lock);
560678453a8Sspeer 	/* Check if the nexus node exists already */
561678453a8Sspeer 	nexus_dip = vdds_find_node(cookie, ddi_root_node(),
562678453a8Sspeer 	    vdds_match_niu_nexus);
563678453a8Sspeer 	if (nexus_dip == NULL) {
564678453a8Sspeer 		/*
565678453a8Sspeer 		 * NIU nexus node not found, so create it now.
566678453a8Sspeer 		 */
5677b1f684aSSriharsha Basavapatna 		cba.dip = NULL;
5687b1f684aSSriharsha Basavapatna 		cba.cookie = cookie;
5697b1f684aSSriharsha Basavapatna 		cba.macaddr = macaddr;
5707b1f684aSSriharsha Basavapatna 		cba.max_frame_size = max_frame_size;
5717b1f684aSSriharsha Basavapatna 		nexus_dip = vdds_create_new_node(&cba, NULL,
572678453a8Sspeer 		    vdds_new_nexus_node);
573678453a8Sspeer 		if (nexus_dip == NULL) {
574d0288fccSRaghuram Kothakota 			mutex_exit(&vdds_dev_lock);
575678453a8Sspeer 			return (NULL);
576678453a8Sspeer 		}
577678453a8Sspeer 	}
578678453a8Sspeer 	DBG2(NULL, "nexus_dip = 0x%p", nexus_dip);
579678453a8Sspeer 
580678453a8Sspeer 	/* Check if NIU node exists already before creating one */
581678453a8Sspeer 	niu_dip = vdds_find_node(cookie, nexus_dip,
582678453a8Sspeer 	    vdds_match_niu_node);
583678453a8Sspeer 	if (niu_dip == NULL) {
5847b1f684aSSriharsha Basavapatna 		cba.dip = NULL;
5857b1f684aSSriharsha Basavapatna 		cba.cookie = cookie;
5867b1f684aSSriharsha Basavapatna 		cba.macaddr = macaddr;
5877b1f684aSSriharsha Basavapatna 		cba.max_frame_size = max_frame_size;
5887b1f684aSSriharsha Basavapatna 		niu_dip = vdds_create_new_node(&cba, nexus_dip,
589678453a8Sspeer 		    vdds_new_niu_node);
590678453a8Sspeer 		/*
591d0288fccSRaghuram Kothakota 		 * Hold the niu_dip to prevent it from
592d0288fccSRaghuram Kothakota 		 * detaching.
593678453a8Sspeer 		 */
594d0288fccSRaghuram Kothakota 		if (niu_dip != NULL) {
595d0288fccSRaghuram Kothakota 			e_ddi_hold_devi(niu_dip);
596d0288fccSRaghuram Kothakota 		} else {
597d0288fccSRaghuram Kothakota 			DWARN(NULL, "niumx/network node creation failed");
598d0288fccSRaghuram Kothakota 		}
599d0288fccSRaghuram Kothakota 	} else {
600d0288fccSRaghuram Kothakota 		DWARN(NULL, "niumx/network node already exists(dip=0x%p)",
601d0288fccSRaghuram Kothakota 		    niu_dip);
602678453a8Sspeer 	}
603d0288fccSRaghuram Kothakota 	/* release the hold that was done in find/create */
604d0288fccSRaghuram Kothakota 	if ((niu_dip != NULL) && (e_ddi_branch_held(niu_dip)))
605d0288fccSRaghuram Kothakota 		e_ddi_branch_rele(niu_dip);
606d0288fccSRaghuram Kothakota 	if (e_ddi_branch_held(nexus_dip))
607d0288fccSRaghuram Kothakota 		e_ddi_branch_rele(nexus_dip);
608d0288fccSRaghuram Kothakota 	mutex_exit(&vdds_dev_lock);
609d0288fccSRaghuram Kothakota 	DBG1(NULL, "returning niu_dip=0x%p", niu_dip);
610678453a8Sspeer 	return (niu_dip);
611678453a8Sspeer }
612678453a8Sspeer 
613678453a8Sspeer /*
614678453a8Sspeer  * vdds_destroy_niu_node -- Destroy the NIU node.
615678453a8Sspeer  */
616678453a8Sspeer int
617678453a8Sspeer vdds_destroy_niu_node(dev_info_t *niu_dip, uint64_t cookie)
618678453a8Sspeer {
619678453a8Sspeer 	int rv;
620678453a8Sspeer 	dev_info_t *fdip = NULL;
621678453a8Sspeer 	dev_info_t *nexus_dip = ddi_get_parent(niu_dip);
622678453a8Sspeer 
623678453a8Sspeer 
624678453a8Sspeer 	DBG1(NULL, "Called");
625d0288fccSRaghuram Kothakota 	ASSERT(nexus_dip != NULL);
626d0288fccSRaghuram Kothakota 	mutex_enter(&vdds_dev_lock);
627d0288fccSRaghuram Kothakota 
628d0288fccSRaghuram Kothakota 	if (!e_ddi_branch_held(niu_dip))
629d0288fccSRaghuram Kothakota 		e_ddi_branch_hold(niu_dip);
630d0288fccSRaghuram Kothakota 	/*
631d0288fccSRaghuram Kothakota 	 * As we are destroying now, release the
632d0288fccSRaghuram Kothakota 	 * hold that was done in during the creation.
633d0288fccSRaghuram Kothakota 	 */
634d0288fccSRaghuram Kothakota 	ddi_release_devi(niu_dip);
635678453a8Sspeer 	rv = e_ddi_branch_destroy(niu_dip, &fdip, 0);
636678453a8Sspeer 	if (rv != 0) {
637678453a8Sspeer 		DERR(NULL, "Failed to destroy niumx/network node dip=0x%p",
638678453a8Sspeer 		    niu_dip);
639678453a8Sspeer 		if (fdip != NULL) {
640d0288fccSRaghuram Kothakota 			ddi_release_devi(fdip);
641678453a8Sspeer 		}
642d0288fccSRaghuram Kothakota 		rv = EBUSY;
643d0288fccSRaghuram Kothakota 		goto dest_exit;
644678453a8Sspeer 	}
645678453a8Sspeer 	/*
646678453a8Sspeer 	 * Cleanup the parent's ranges property set
647678453a8Sspeer 	 * for this Hybrid device.
648678453a8Sspeer 	 */
649678453a8Sspeer 	vdds_release_range_prop(nexus_dip, cookie);
650d0288fccSRaghuram Kothakota 
651d0288fccSRaghuram Kothakota dest_exit:
652d0288fccSRaghuram Kothakota 	mutex_exit(&vdds_dev_lock);
653d0288fccSRaghuram Kothakota 	DBG1(NULL, "returning rv=%d", rv);
654d0288fccSRaghuram Kothakota 	return (rv);
655678453a8Sspeer }
656678453a8Sspeer 
657678453a8Sspeer /*
658678453a8Sspeer  * vdds_match_niu_nexus -- callback function to verify a node is the
659678453a8Sspeer  *	NIU nexus node.
660678453a8Sspeer  */
661678453a8Sspeer static int
662678453a8Sspeer vdds_match_niu_nexus(dev_info_t *dip, void *arg)
663678453a8Sspeer {
664678453a8Sspeer 	vdds_cb_arg_t	*warg = (vdds_cb_arg_t *)arg;
665678453a8Sspeer 	vdds_reg_t	*reg_p;
666678453a8Sspeer 	char		*name;
667678453a8Sspeer 	uint64_t	hdl;
668678453a8Sspeer 	uint_t		reglen;
669678453a8Sspeer 	int		rv;
670678453a8Sspeer 
671678453a8Sspeer 	if (dip == ddi_root_node()) {
672678453a8Sspeer 		return (DDI_WALK_CONTINUE);
673678453a8Sspeer 	}
674678453a8Sspeer 
675678453a8Sspeer 	name = ddi_node_name(dip);
676678453a8Sspeer 	if (strcmp(name, "niu")  != 0) {
677678453a8Sspeer 		return (DDI_WALK_CONTINUE);
678678453a8Sspeer 	}
679678453a8Sspeer 	rv = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip,
680678453a8Sspeer 	    DDI_PROP_DONTPASS, "reg", (int **)&reg_p, &reglen);
681678453a8Sspeer 	if (rv != DDI_PROP_SUCCESS) {
682678453a8Sspeer 		DWARN(NULL, "Failed to get reg property dip=0x%p", dip);
683678453a8Sspeer 		return (DDI_WALK_CONTINUE);
684678453a8Sspeer 	}
685678453a8Sspeer 
686678453a8Sspeer 	hdl =  reg_p->addr_hi & 0x0FFFFFFF;
687678453a8Sspeer 	ddi_prop_free(reg_p);
688678453a8Sspeer 
689678453a8Sspeer 	DBG2(NULL, "Handle = 0x%lx dip=0x%p", hdl, dip);
690678453a8Sspeer 	if (hdl == NIUCFGHDL(warg->cookie)) {
691678453a8Sspeer 		/* Hold before returning */
692d0288fccSRaghuram Kothakota 		if (!e_ddi_branch_held(dip))
693d0288fccSRaghuram Kothakota 			e_ddi_branch_hold(dip);
694678453a8Sspeer 		warg->dip = dip;
695678453a8Sspeer 		DBG2(NULL, "Found dip = 0x%p", dip);
696678453a8Sspeer 		return (DDI_WALK_TERMINATE);
697678453a8Sspeer 	}
698678453a8Sspeer 	return (DDI_WALK_CONTINUE);
699678453a8Sspeer }
700678453a8Sspeer 
701678453a8Sspeer /*
702678453a8Sspeer  * vdds_match_niu_node -- callback function to verify a node is the
703678453a8Sspeer  *	NIU Hybrid node.
704678453a8Sspeer  */
705678453a8Sspeer static int
706678453a8Sspeer vdds_match_niu_node(dev_info_t *dip, void *arg)
707678453a8Sspeer {
708678453a8Sspeer 	vdds_cb_arg_t	*warg = (vdds_cb_arg_t *)arg;
709678453a8Sspeer 	char		*name;
710678453a8Sspeer 	vdds_reg_t	*reg_p;
711678453a8Sspeer 	uint_t		reglen;
712678453a8Sspeer 	int		rv;
713678453a8Sspeer 	uint32_t	addr_hi;
714678453a8Sspeer 
715678453a8Sspeer 	name = ddi_node_name(dip);
716678453a8Sspeer 	if (strcmp(name, "network")  != 0) {
717678453a8Sspeer 		return (DDI_WALK_CONTINUE);
718678453a8Sspeer 	}
719678453a8Sspeer 	rv = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip,
720678453a8Sspeer 	    DDI_PROP_DONTPASS, "reg", (int **)&reg_p, &reglen);
721678453a8Sspeer 	if (rv != DDI_PROP_SUCCESS) {
722678453a8Sspeer 		DWARN(NULL, "Failed to get reg property dip=0x%p", dip);
723678453a8Sspeer 		return (DDI_WALK_CONTINUE);
724678453a8Sspeer 	}
725678453a8Sspeer 
726678453a8Sspeer 	addr_hi = reg_p->addr_hi;
727678453a8Sspeer 	DBG1(NULL, "addr_hi = 0x%x dip=0x%p", addr_hi, dip);
728678453a8Sspeer 	ddi_prop_free(reg_p);
729678453a8Sspeer 	if (addr_hi == HVCOOKIE(warg->cookie)) {
730678453a8Sspeer 		warg->dip = dip;
731d0288fccSRaghuram Kothakota 		if (!e_ddi_branch_held(dip))
732d0288fccSRaghuram Kothakota 			e_ddi_branch_hold(dip);
733678453a8Sspeer 		DBG1(NULL, "Found dip = 0x%p", dip);
734678453a8Sspeer 		return (DDI_WALK_TERMINATE);
735678453a8Sspeer 	}
736678453a8Sspeer 	return (DDI_WALK_CONTINUE);
737678453a8Sspeer }
738678453a8Sspeer 
739678453a8Sspeer /*
740678453a8Sspeer  * vdds_new_nexus_node -- callback function to set all the properties
741678453a8Sspeer  *	a new NIU nexus node.
742678453a8Sspeer  */
743678453a8Sspeer static int
744678453a8Sspeer vdds_new_nexus_node(dev_info_t *dip, void *arg, uint_t flags)
745678453a8Sspeer {
746678453a8Sspeer 	vdds_cb_arg_t	*cba = (vdds_cb_arg_t *)arg;
747678453a8Sspeer 	char		*compat[] = { "SUNW,niumx" };
748678453a8Sspeer 	vdds_ranges_t	*rangesp;
749678453a8Sspeer 	vdds_reg_t	reg;
750678453a8Sspeer 	uint64_t	nranges;
751678453a8Sspeer 	int		n;
752678453a8Sspeer 
753678453a8Sspeer 	DBG1(NULL, "Called dip=0x%p, flags=0x%X", dip, flags);
754678453a8Sspeer 
755678453a8Sspeer 	/* create "niu" property */
756678453a8Sspeer 	if (ndi_prop_update_string(DDI_DEV_T_NONE, dip, "name", "niu") !=
757678453a8Sspeer 	    DDI_SUCCESS) {
758678453a8Sspeer 		DERR(NULL, "Failed to create name property(dip=0x%p)", dip);
759678453a8Sspeer 		return (DDI_WALK_ERROR);
760678453a8Sspeer 	}
761678453a8Sspeer 
762678453a8Sspeer 	/* create "compatible" property */
763678453a8Sspeer 	if (ndi_prop_update_string_array(DDI_DEV_T_NONE, dip, "compatible",
764678453a8Sspeer 	    compat, 1) != DDI_SUCCESS) {
765678453a8Sspeer 		DERR(NULL, "Failed to create compatible property(dip=0x%p)",
766678453a8Sspeer 		    dip);
767678453a8Sspeer 		return (DDI_WALK_ERROR);
768678453a8Sspeer 	}
769678453a8Sspeer 
770678453a8Sspeer 	/* create "device_type" property */
771678453a8Sspeer 	if (ndi_prop_update_string(DDI_DEV_T_NONE, dip,
772678453a8Sspeer 	    "device_type", "sun4v") != DDI_SUCCESS) {
773678453a8Sspeer 		DERR(NULL, "Failed to create device_type property(dip=0x%p)",
774678453a8Sspeer 		    dip);
775678453a8Sspeer 		return (DDI_WALK_ERROR);
776678453a8Sspeer 	}
777678453a8Sspeer 
778678453a8Sspeer 	/*
779678453a8Sspeer 	 * create "reg" property. The first 28 bits of
780678453a8Sspeer 	 * 'addr_hi'  are NIU cfg_handle, the 0xc in 28-31 bits
781678453a8Sspeer 	 * indicates non-cacheable config.
782678453a8Sspeer 	 */
783678453a8Sspeer 	reg.addr_hi = 0xc0000000 | NIUCFGHDL(cba->cookie);
784678453a8Sspeer 	reg.addr_lo = 0;
785678453a8Sspeer 	reg.size_hi = 0;
786678453a8Sspeer 	reg.size_lo = 0;
787678453a8Sspeer 	if (ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
788678453a8Sspeer 	    "reg", (int *)&reg, sizeof (reg)/sizeof (int)) != DDI_SUCCESS) {
789678453a8Sspeer 		DERR(NULL, "Failed to create reg property(dip=0x%p)", dip);
790678453a8Sspeer 		return (DDI_WALK_ERROR);
791678453a8Sspeer 	}
792678453a8Sspeer 
793678453a8Sspeer 	/*
794678453a8Sspeer 	 * Create VDDS_MAX_RANGES so that they are already in place
795678453a8Sspeer 	 * before the children are created. While creating the child
796678453a8Sspeer 	 * we just modify one of this ranges entries.
797678453a8Sspeer 	 */
798678453a8Sspeer 	nranges = VDDS_MAX_RANGES;  /* One range for each VR */
799678453a8Sspeer 	rangesp = (vdds_ranges_t *)kmem_zalloc(
800678453a8Sspeer 	    (sizeof (vdds_ranges_t) * nranges), KM_SLEEP);
801678453a8Sspeer 
802678453a8Sspeer 	for (n = 0; n < nranges; n++) {
803678453a8Sspeer 		/* zero all child_hi/lo */
804678453a8Sspeer 		rangesp[n].child_hi = 0;
805678453a8Sspeer 		rangesp[n].child_lo = 0;
806678453a8Sspeer 	}
807678453a8Sspeer 
808678453a8Sspeer 	if (ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, "ranges",
809678453a8Sspeer 	    (int *)rangesp, (nranges * 6)) != DDI_SUCCESS) {
810678453a8Sspeer 		DERR(NULL, "Failed to create ranges property(dip=0x%p)", dip);
811678453a8Sspeer 		kmem_free(rangesp, (sizeof (vdds_ranges_t) * nranges));
812678453a8Sspeer 		return (DDI_WALK_ERROR);
813678453a8Sspeer 	}
814678453a8Sspeer 
815678453a8Sspeer 	/* create "#size-cells" property */
816678453a8Sspeer 	if (ndi_prop_update_int(DDI_DEV_T_NONE, dip,
817678453a8Sspeer 	    "#size-cells", 2) != DDI_SUCCESS) {
818678453a8Sspeer 		DERR(NULL, "Failed to create #size-cells property(dip=0x%p)",
819678453a8Sspeer 		    dip);
820678453a8Sspeer 		kmem_free(rangesp, (sizeof (vdds_ranges_t) * nranges));
821678453a8Sspeer 		return (DDI_WALK_ERROR);
822678453a8Sspeer 	}
823678453a8Sspeer 
824678453a8Sspeer 	/* create "#address-cells" property */
825678453a8Sspeer 	if (ndi_prop_update_int(DDI_DEV_T_NONE, dip,
826678453a8Sspeer 	    "#address-cells", 2) != DDI_SUCCESS) {
827678453a8Sspeer 		DERR(NULL, "Failed to create #address-cells prop(dip=0x%p)",
828678453a8Sspeer 		    dip);
829678453a8Sspeer 		kmem_free(rangesp, (sizeof (vdds_ranges_t) * nranges));
830678453a8Sspeer 		return (DDI_WALK_ERROR);
831678453a8Sspeer 	}
832678453a8Sspeer 
833678453a8Sspeer 	kmem_free(rangesp, (sizeof (vdds_ranges_t) * nranges));
834678453a8Sspeer 	cba->dip = dip;
835678453a8Sspeer 	DBG1(NULL, "Returning (dip=0x%p)", dip);
836678453a8Sspeer 	return (DDI_WALK_TERMINATE);
837678453a8Sspeer }
838678453a8Sspeer 
839678453a8Sspeer /*
840678453a8Sspeer  * vdds_new_niu_node -- callback function to create a new NIU Hybrid node.
841678453a8Sspeer  */
842678453a8Sspeer static int
843678453a8Sspeer vdds_new_niu_node(dev_info_t *dip, void *arg, uint_t flags)
844678453a8Sspeer {
845678453a8Sspeer 	vdds_cb_arg_t *cba = (vdds_cb_arg_t *)arg;
846678453a8Sspeer 	char *compat[] = { "SUNW,niusl" };
847678453a8Sspeer 	uint8_t macaddrbytes[ETHERADDRL];
848678453a8Sspeer 	int interrupts[VDDS_MAX_VRINTRS];
849678453a8Sspeer 	vdds_ranges_t	*prng;
850678453a8Sspeer 	vdds_ranges_t	*prp;
851678453a8Sspeer 	vdds_reg_t	reg;
852678453a8Sspeer 	dev_info_t	*pdip;
853678453a8Sspeer 	uint64_t	start;
854678453a8Sspeer 	uint64_t	size;
855678453a8Sspeer 	int		prnglen;
856678453a8Sspeer 	int		nintr = 0;
857678453a8Sspeer 	int		nrng;
858678453a8Sspeer 	int		rnum;
859678453a8Sspeer 	int		rv;
860678453a8Sspeer 
861678453a8Sspeer 	DBG1(NULL, "Called dip=0x%p flags=0x%X", dip, flags);
862678453a8Sspeer 	pdip = ddi_get_parent(dip);
863678453a8Sspeer 
864678453a8Sspeer 	if (pdip == NULL) {
865678453a8Sspeer 		DWARN(NULL, "Failed to get parent dip(dip=0x%p)", dip);
866678453a8Sspeer 		return (DDI_WALK_ERROR);
867678453a8Sspeer 	}
868678453a8Sspeer 
869678453a8Sspeer 	/* create "network" property */
870678453a8Sspeer 	if (ndi_prop_update_string(DDI_DEV_T_NONE, dip, "name", "network") !=
871678453a8Sspeer 	    DDI_SUCCESS) {
872678453a8Sspeer 		DERR(NULL, "Failed to create name property(dip=0x%p)", dip);
873678453a8Sspeer 		return (DDI_WALK_ERROR);
874678453a8Sspeer 	}
875678453a8Sspeer 
876678453a8Sspeer 	/*
877678453a8Sspeer 	 * create "niutype" property, it is set to n2niu to
878678453a8Sspeer 	 * indicate NIU Hybrid node.
879678453a8Sspeer 	 */
880678453a8Sspeer 	if (ndi_prop_update_string(DDI_DEV_T_NONE, dip, "niutype",
881678453a8Sspeer 	    "n2niu") != DDI_SUCCESS) {
882678453a8Sspeer 		DERR(NULL, "Failed to create niuopmode property(dip=0x%p)",
883678453a8Sspeer 		    dip);
884678453a8Sspeer 		return (DDI_WALK_ERROR);
885678453a8Sspeer 	}
886678453a8Sspeer 
887678453a8Sspeer 	/* create "compatible" property */
888678453a8Sspeer 	if (ndi_prop_update_string_array(DDI_DEV_T_NONE, dip, "compatible",
889678453a8Sspeer 	    compat, 1) != DDI_SUCCESS) {
890678453a8Sspeer 		DERR(NULL, "Failed to create compatible property(dip=0x%p)",
891678453a8Sspeer 		    dip);
892678453a8Sspeer 		return (DDI_WALK_ERROR);
893678453a8Sspeer 	}
894678453a8Sspeer 
895678453a8Sspeer 	/* create "device_type" property */
896678453a8Sspeer 	if (ndi_prop_update_string(DDI_DEV_T_NONE, dip,
897678453a8Sspeer 	    "device_type", "network") != DDI_SUCCESS) {
898678453a8Sspeer 		DERR(NULL, "Failed to create device_type property(dip=0x%p)",
899678453a8Sspeer 		    dip);
900678453a8Sspeer 		return (DDI_WALK_ERROR);
901678453a8Sspeer 	}
902678453a8Sspeer 
903678453a8Sspeer 	/* create "reg" property */
904678453a8Sspeer 	if (vdds_hv_niu_vr_getinfo(HVCOOKIE(cba->cookie),
905678453a8Sspeer 	    &start, &size) != H_EOK) {
906678453a8Sspeer 		DERR(NULL, "Failed to get vrinfo for cookie(0x%lX)",
907678453a8Sspeer 		    cba->cookie);
908678453a8Sspeer 			return (DDI_WALK_ERROR);
909678453a8Sspeer 	}
910678453a8Sspeer 	reg.addr_hi = HVCOOKIE(cba->cookie);
911678453a8Sspeer 	reg.addr_lo = 0;
912678453a8Sspeer 	reg.size_hi = 0;
913678453a8Sspeer 	reg.size_lo = size;
914678453a8Sspeer 
915678453a8Sspeer 	if (ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, "reg",
916678453a8Sspeer 	    (int *)&reg, sizeof (reg) / sizeof (int)) != DDI_SUCCESS) {
917678453a8Sspeer 		DERR(NULL, "Failed to create reg property(dip=0x%p)", dip);
918678453a8Sspeer 		return (DDI_WALK_ERROR);
919678453a8Sspeer 	}
920678453a8Sspeer 
921678453a8Sspeer 	/*
922678453a8Sspeer 	 * Modify the parent's ranges property to map the "reg" property
923678453a8Sspeer 	 * of the new child.
924678453a8Sspeer 	 */
925678453a8Sspeer 	if ((rv = ddi_getlongprop(DDI_DEV_T_ANY, pdip, DDI_PROP_DONTPASS,
926678453a8Sspeer 	    "ranges", (caddr_t)&prng, &prnglen)) != DDI_SUCCESS) {
927678453a8Sspeer 		DERR(NULL,
928678453a8Sspeer 		    "Failed to get parent's ranges property(pdip=0x%p) rv=%d",
929678453a8Sspeer 		    pdip, rv);
930678453a8Sspeer 		return (DDI_WALK_ERROR);
931678453a8Sspeer 	}
932678453a8Sspeer 	nrng = prnglen/(sizeof (vdds_ranges_t));
933678453a8Sspeer 	/*
934678453a8Sspeer 	 * First scan all ranges to see if a range corresponding
935678453a8Sspeer 	 * to this virtual NIU exists already.
936678453a8Sspeer 	 */
937678453a8Sspeer 	for (rnum = 0; rnum < nrng; rnum++) {
938678453a8Sspeer 		prp = &prng[rnum];
939678453a8Sspeer 		if (prp->child_hi == HVCOOKIE(cba->cookie)) {
940678453a8Sspeer 			break;
941678453a8Sspeer 		}
942678453a8Sspeer 	}
943678453a8Sspeer 	if (rnum == nrng) {
944678453a8Sspeer 		/* Now to try to find an empty range */
945678453a8Sspeer 		for (rnum = 0; rnum < nrng; rnum++) {
946678453a8Sspeer 			prp = &prng[rnum];
947678453a8Sspeer 			if (prp->child_hi == 0) {
948678453a8Sspeer 				break;
949678453a8Sspeer 			}
950678453a8Sspeer 		}
951678453a8Sspeer 	}
952678453a8Sspeer 	if (rnum == nrng) {
953678453a8Sspeer 		DERR(NULL, "No free ranges entry found");
954678453a8Sspeer 		return (DDI_WALK_ERROR);
955678453a8Sspeer 	}
956678453a8Sspeer 
957678453a8Sspeer 	/*
958678453a8Sspeer 	 * child_hi will have HV cookie as HV cookie is more like
959678453a8Sspeer 	 * a port in the HybridIO.
960678453a8Sspeer 	 */
961678453a8Sspeer 	prp->child_hi = HVCOOKIE(cba->cookie);
962678453a8Sspeer 	prp->child_lo = 0;
963678453a8Sspeer 	prp->parent_hi = 0x80000000 | (start >> 32);
964678453a8Sspeer 	prp->parent_lo = start & 0x00000000FFFFFFFF;
965678453a8Sspeer 	prp->size_hi = (size >> 32);
966678453a8Sspeer 	prp->size_lo = size & 0x00000000FFFFFFFF;
967678453a8Sspeer 
968678453a8Sspeer 	if (ndi_prop_update_int_array(DDI_DEV_T_NONE, pdip, "ranges",
969678453a8Sspeer 	    (int *)prng, (nrng * 6)) != DDI_SUCCESS) {
970678453a8Sspeer 		DERR(NULL, "Failed to update parent ranges prop(pdip=0x%p)",
971678453a8Sspeer 		    pdip);
972678453a8Sspeer 		return (DDI_WALK_ERROR);
973678453a8Sspeer 	}
974678453a8Sspeer 	kmem_free((void *)prng, prnglen);
975678453a8Sspeer 
976678453a8Sspeer 	vnet_macaddr_ultostr(cba->macaddr, macaddrbytes);
977678453a8Sspeer 
978678453a8Sspeer 	/*
979678453a8Sspeer 	 * create "local-mac-address" property, this will be same as
980678453a8Sspeer 	 * the vnet's mac-address.
981678453a8Sspeer 	 */
982678453a8Sspeer 	if (ndi_prop_update_byte_array(DDI_DEV_T_NONE, dip, "local-mac-address",
983678453a8Sspeer 	    macaddrbytes, ETHERADDRL) != DDI_SUCCESS) {
984678453a8Sspeer 		DERR(NULL, "Failed to update mac-addresses property(dip=0x%p)",
985678453a8Sspeer 		    dip);
986678453a8Sspeer 		return (DDI_WALK_ERROR);
987678453a8Sspeer 	}
988678453a8Sspeer 
989678453a8Sspeer 	rv = vdds_get_interrupts(cba->cookie, rnum, interrupts, &nintr);
990678453a8Sspeer 	if (rv != 0) {
991678453a8Sspeer 		DERR(NULL, "Failed to get interrupts for cookie=0x%lx",
992678453a8Sspeer 		    cba->cookie);
993678453a8Sspeer 		return (DDI_WALK_ERROR);
994678453a8Sspeer 	}
995678453a8Sspeer 
996678453a8Sspeer 	/* create "interrupts" property */
997678453a8Sspeer 	if (ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, "interrupts",
998678453a8Sspeer 	    interrupts, nintr) != DDI_SUCCESS) {
999678453a8Sspeer 		DERR(NULL, "Failed to update interrupts property(dip=0x%p)",
1000678453a8Sspeer 		    dip);
1001678453a8Sspeer 		return (DDI_WALK_ERROR);
1002678453a8Sspeer 	}
1003678453a8Sspeer 
1004678453a8Sspeer 
10057b1f684aSSriharsha Basavapatna 	/* create "max_frame_size" property */
10067b1f684aSSriharsha Basavapatna 	if (ndi_prop_update_int(DDI_DEV_T_NONE, dip, "max-frame-size",
10077b1f684aSSriharsha Basavapatna 	    cba->max_frame_size) != DDI_SUCCESS) {
10087b1f684aSSriharsha Basavapatna 		DERR(NULL, "Failed to update max-frame-size property(dip=0x%p)",
10097b1f684aSSriharsha Basavapatna 		    dip);
10107b1f684aSSriharsha Basavapatna 		return (DDI_WALK_ERROR);
10117b1f684aSSriharsha Basavapatna 	}
10127b1f684aSSriharsha Basavapatna 
1013678453a8Sspeer 	cba->dip = dip;
1014678453a8Sspeer 	DBG1(NULL, "Returning dip=0x%p", dip);
1015678453a8Sspeer 	return (DDI_WALK_TERMINATE);
1016678453a8Sspeer }
1017678453a8Sspeer 
1018678453a8Sspeer 
1019678453a8Sspeer /*
1020678453a8Sspeer  * vdds_find_node -- A common function to find a NIU nexus or NIU node.
1021678453a8Sspeer  */
1022678453a8Sspeer static dev_info_t *
1023678453a8Sspeer vdds_find_node(uint64_t cookie, dev_info_t *sdip,
1024678453a8Sspeer 	int (*match_func)(dev_info_t *dip, void *arg))
1025678453a8Sspeer {
1026678453a8Sspeer 	vdds_cb_arg_t arg;
1027678453a8Sspeer 	dev_info_t *pdip;
1028678453a8Sspeer 	int circ;
1029678453a8Sspeer 
1030678453a8Sspeer 	DBG1(NULL, "Called cookie=%lx\n", cookie);
1031678453a8Sspeer 
1032678453a8Sspeer 	arg.dip = NULL;
1033678453a8Sspeer 	arg.cookie = cookie;
1034678453a8Sspeer 
1035678453a8Sspeer 	if (pdip = ddi_get_parent(sdip)) {
1036678453a8Sspeer 		ndi_devi_enter(pdip, &circ);
1037678453a8Sspeer 	}
1038678453a8Sspeer 
1039678453a8Sspeer 	ddi_walk_devs(sdip, match_func, (void *)&arg);
1040678453a8Sspeer 	if (pdip != NULL) {
1041678453a8Sspeer 		ndi_devi_exit(pdip, circ);
1042678453a8Sspeer 	}
1043678453a8Sspeer 
1044678453a8Sspeer 	DBG1(NULL, "Returning dip=0x%p", arg.dip);
1045678453a8Sspeer 	return (arg.dip);
1046678453a8Sspeer }
1047678453a8Sspeer 
1048678453a8Sspeer /*
1049678453a8Sspeer  * vdds_create_new_node -- A common function to create NIU nexus/NIU node.
1050678453a8Sspeer  */
1051678453a8Sspeer static dev_info_t *
10527b1f684aSSriharsha Basavapatna vdds_create_new_node(vdds_cb_arg_t *cbap, dev_info_t *pdip,
1053678453a8Sspeer     int (*new_node_func)(dev_info_t *dip, void *arg, uint_t flags))
1054678453a8Sspeer {
1055678453a8Sspeer 	devi_branch_t br;
1056d0288fccSRaghuram Kothakota 	int rv;
1057678453a8Sspeer 
10587b1f684aSSriharsha Basavapatna 	DBG1(NULL, "Called cookie=0x%lx", cbap->cookie);
1059678453a8Sspeer 
10607b1f684aSSriharsha Basavapatna 	br.arg = (void *)cbap;
1061678453a8Sspeer 	br.type = DEVI_BRANCH_SID;
1062678453a8Sspeer 	br.create.sid_branch_create = new_node_func;
1063678453a8Sspeer 	br.devi_branch_callback = NULL;
1064678453a8Sspeer 
1065d0288fccSRaghuram Kothakota 	if (pdip == NULL) {
1066678453a8Sspeer 		pdip = ddi_root_node();
1067d0288fccSRaghuram Kothakota 	}
1068678453a8Sspeer 	DBG1(NULL, "calling e_ddi_branch_create");
1069678453a8Sspeer 	if ((rv = e_ddi_branch_create(pdip, &br, NULL,
1070678453a8Sspeer 	    DEVI_BRANCH_CHILD | DEVI_BRANCH_CONFIGURE))) {
1071678453a8Sspeer 		DERR(NULL, "e_ddi_branch_create failed=%d", rv);
1072678453a8Sspeer 		return (NULL);
1073678453a8Sspeer 	}
10747b1f684aSSriharsha Basavapatna 	DBG1(NULL, "Returning(dip=0x%p", cbap->dip);
10757b1f684aSSriharsha Basavapatna 	return (cbap->dip);
1076678453a8Sspeer }
1077678453a8Sspeer 
1078678453a8Sspeer /*
1079678453a8Sspeer  * vdds_get_interrupts -- A function that binds ino's to channels and
1080678453a8Sspeer  *	then provides them to create interrupts property.
1081678453a8Sspeer  */
1082678453a8Sspeer static int
1083678453a8Sspeer vdds_get_interrupts(uint64_t cookie, int ino_range, int *intrs, int *nintr)
1084678453a8Sspeer {
1085678453a8Sspeer 	uint32_t hvcookie = HVCOOKIE(cookie);
1086678453a8Sspeer 	uint64_t txmap;
1087678453a8Sspeer 	uint64_t rxmap;
1088678453a8Sspeer 	uint32_t ino = VDDS_INO_RANGE_START(ino_range);
1089678453a8Sspeer 	int rv;
1090678453a8Sspeer 	uint64_t i;
1091678453a8Sspeer 
1092678453a8Sspeer 	*nintr = 0;
1093678453a8Sspeer 	rv = vdds_hv_niu_vr_get_txmap(hvcookie, &txmap);
1094678453a8Sspeer 	if (rv != H_EOK) {
1095678453a8Sspeer 		DWARN(NULL, "Failed to get txmap for hvcookie=0x%X rv=%d\n",
1096678453a8Sspeer 		    hvcookie, rv);
1097678453a8Sspeer 		return (EIO);
1098678453a8Sspeer 	}
1099678453a8Sspeer 	rv = vdds_hv_niu_vr_get_rxmap(hvcookie, &rxmap);
1100678453a8Sspeer 	if (rv != H_EOK) {
1101678453a8Sspeer 		DWARN(NULL, "Failed to get rxmap for hvcookie=0x%X, rv=%d\n",
1102678453a8Sspeer 		    hvcookie, rv);
1103678453a8Sspeer 		return (EIO);
1104678453a8Sspeer 	}
1105678453a8Sspeer 	/* Check if the number of total channels to be more than 8 */
1106678453a8Sspeer 	for (i = 0; i < 4; i++) {
1107678453a8Sspeer 		if (rxmap & (((uint64_t)0x1) << i)) {
1108678453a8Sspeer 			rv = vdds_hv_niu_vrrx_set_ino(hvcookie, i, ino);
1109678453a8Sspeer 			if (rv != H_EOK) {
1110678453a8Sspeer 				DWARN(NULL, "Failed to get Rx ino for "
1111678453a8Sspeer 				    "hvcookie=0x%X vch_idx=0x%lx rv=%d\n",
1112678453a8Sspeer 				    hvcookie, i, rv);
1113678453a8Sspeer 				return (EIO);
1114678453a8Sspeer 			}
1115678453a8Sspeer 			DWARN(NULL,
1116678453a8Sspeer 			    "hvcookie=0x%X RX vch_idx=0x%lx ino=0x%X\n",
1117678453a8Sspeer 			    hvcookie, i, ino);
1118678453a8Sspeer 			*intrs = ino;
1119678453a8Sspeer 			ino++;
1120678453a8Sspeer 		} else {
1121678453a8Sspeer 			*intrs = VDDS_MAX_INTR_NUM;
1122678453a8Sspeer 		}
1123678453a8Sspeer 		intrs++;
1124678453a8Sspeer 		*nintr += 1;
1125678453a8Sspeer 	}
1126678453a8Sspeer 	for (i = 0; i < 4; i++) {
1127678453a8Sspeer 		if (txmap & (((uint64_t)0x1) << i)) {
1128678453a8Sspeer 			rv = vdds_hv_niu_vrtx_set_ino(hvcookie, i, ino);
1129678453a8Sspeer 			if (rv != H_EOK) {
1130678453a8Sspeer 				DWARN(NULL, "Failed to get Tx ino for "
1131678453a8Sspeer 				    "hvcookie=0x%X vch_idx=0x%lx rv=%d\n",
1132678453a8Sspeer 				    hvcookie, i, rv);
1133678453a8Sspeer 				return (EIO);
1134678453a8Sspeer 			}
1135678453a8Sspeer 			DWARN(NULL, "hvcookie=0x%X TX vch_idx=0x%lx ino=0x%X\n",
1136678453a8Sspeer 			    hvcookie, i, ino);
1137678453a8Sspeer 			*intrs = ino;
1138678453a8Sspeer 			ino++;
1139678453a8Sspeer 		} else {
1140678453a8Sspeer 			*intrs = VDDS_MAX_INTR_NUM;
1141678453a8Sspeer 		}
1142678453a8Sspeer 		intrs++;
1143678453a8Sspeer 		*nintr += 1;
1144678453a8Sspeer 	}
1145678453a8Sspeer 	return (0);
1146678453a8Sspeer }
1147678453a8Sspeer 
1148678453a8Sspeer /*
1149678453a8Sspeer  * vdds_release_range_prop -- cleanups an entry in the ranges property
1150678453a8Sspeer  *	corresponding to a cookie.
1151678453a8Sspeer  */
1152678453a8Sspeer static void
1153678453a8Sspeer vdds_release_range_prop(dev_info_t *nexus_dip, uint64_t cookie)
1154678453a8Sspeer {
1155678453a8Sspeer 	vdds_ranges_t *prng;
1156678453a8Sspeer 	vdds_ranges_t *prp;
1157678453a8Sspeer 	int prnglen;
1158678453a8Sspeer 	int nrng;
1159678453a8Sspeer 	int rnum;
1160678453a8Sspeer 	boolean_t success = B_FALSE;
1161678453a8Sspeer 	int rv;
1162678453a8Sspeer 
1163678453a8Sspeer 	if ((rv = ddi_getlongprop(DDI_DEV_T_ANY, nexus_dip, DDI_PROP_DONTPASS,
1164678453a8Sspeer 	    "ranges", (caddr_t)&prng, &prnglen)) != DDI_SUCCESS) {
1165678453a8Sspeer 		DERR(NULL,
1166678453a8Sspeer 		    "Failed to get nexus ranges property(dip=0x%p) rv=%d",
1167678453a8Sspeer 		    nexus_dip, rv);
1168678453a8Sspeer 		return;
1169678453a8Sspeer 	}
1170678453a8Sspeer 	nrng = prnglen/(sizeof (vdds_ranges_t));
1171678453a8Sspeer 	for (rnum = 0; rnum < nrng; rnum++) {
1172678453a8Sspeer 		prp = &prng[rnum];
1173678453a8Sspeer 		if (prp->child_hi == HVCOOKIE(cookie)) {
1174678453a8Sspeer 			prp->child_hi = 0;
1175678453a8Sspeer 			success = B_TRUE;
1176678453a8Sspeer 			break;
1177678453a8Sspeer 		}
1178678453a8Sspeer 	}
1179678453a8Sspeer 	if (success) {
1180678453a8Sspeer 		if (ndi_prop_update_int_array(DDI_DEV_T_NONE, nexus_dip,
1181678453a8Sspeer 		    "ranges", (int *)prng, (nrng * 6)) != DDI_SUCCESS) {
1182678453a8Sspeer 			DERR(NULL,
1183678453a8Sspeer 			    "Failed to update nexus ranges prop(dip=0x%p)",
1184678453a8Sspeer 			    nexus_dip);
1185678453a8Sspeer 		}
1186678453a8Sspeer 	}
1187678453a8Sspeer }
1188