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 /*
237bd3a2e2SSriharsha Basavapatna * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
24678453a8Sspeer * Use is subject to license terms.
25678453a8Sspeer */
26678453a8Sspeer
27*3fe80ca4SDan Cross /*
28*3fe80ca4SDan Cross * Copyright 2023 Oxide Computer Company
29*3fe80ca4SDan Cross */
30*3fe80ca4SDan Cross
31678453a8Sspeer #include <sys/modctl.h>
32678453a8Sspeer #include <sys/prom_plat.h>
33678453a8Sspeer #include <sys/ddi.h>
34678453a8Sspeer #include <sys/sunddi.h>
35678453a8Sspeer #include <sys/sunndi.h>
36678453a8Sspeer #include <sys/ndi_impldefs.h>
37678453a8Sspeer #include <sys/ddi_impldefs.h>
38678453a8Sspeer #include <sys/ethernet.h>
39678453a8Sspeer #include <sys/machsystm.h>
40678453a8Sspeer #include <sys/hypervisor_api.h>
41678453a8Sspeer #include <sys/mach_descrip.h>
42678453a8Sspeer #include <sys/drctl.h>
43678453a8Sspeer #include <sys/dr_util.h>
44678453a8Sspeer #include <sys/mac.h>
45678453a8Sspeer #include <sys/vnet.h>
46678453a8Sspeer #include <sys/vnet_mailbox.h>
47678453a8Sspeer #include <sys/vnet_common.h>
48678453a8Sspeer #include <sys/hsvc.h>
49678453a8Sspeer
50678453a8Sspeer
51678453a8Sspeer #define VDDS_MAX_RANGES 6 /* 6 possible VRs */
52678453a8Sspeer #define VDDS_MAX_VRINTRS 8 /* limited to 8 intrs/VR */
53678453a8Sspeer #define VDDS_MAX_INTR_NUM 64 /* 0-63 or valid */
54678453a8Sspeer
55678453a8Sspeer #define VDDS_INO_RANGE_START(x) (x * VDDS_MAX_VRINTRS)
56678453a8Sspeer #define HVCOOKIE(c) ((c) & 0xFFFFFFFFF)
57678453a8Sspeer #define NIUCFGHDL(c) ((c) >> 32)
58678453a8Sspeer
59678453a8Sspeer
60678453a8Sspeer /* For "ranges" property */
61678453a8Sspeer typedef struct vdds_ranges {
62678453a8Sspeer uint32_t child_hi;
63678453a8Sspeer uint32_t child_lo;
64678453a8Sspeer uint32_t parent_hi;
65678453a8Sspeer uint32_t parent_lo;
66678453a8Sspeer uint32_t size_hi;
67678453a8Sspeer uint32_t size_lo;
68678453a8Sspeer } vdds_ranges_t;
69678453a8Sspeer
70678453a8Sspeer /* For "reg" property */
71678453a8Sspeer typedef struct vdds_reg {
72678453a8Sspeer uint32_t addr_hi;
73678453a8Sspeer uint32_t addr_lo;
74678453a8Sspeer uint32_t size_hi;
75678453a8Sspeer uint32_t size_lo;
76678453a8Sspeer } vdds_reg_t;
77678453a8Sspeer
78678453a8Sspeer /* For ddi callback argument */
79678453a8Sspeer typedef struct vdds_cb_arg {
80678453a8Sspeer dev_info_t *dip;
81678453a8Sspeer uint64_t cookie;
82678453a8Sspeer uint64_t macaddr;
837b1f684aSSriharsha Basavapatna uint32_t max_frame_size;
84678453a8Sspeer } vdds_cb_arg_t;
85678453a8Sspeer
86678453a8Sspeer
87678453a8Sspeer /* Functions exported to other files */
88678453a8Sspeer void vdds_mod_init(void);
89678453a8Sspeer void vdds_mod_fini(void);
90678453a8Sspeer int vdds_init(vnet_t *vnetp);
91678453a8Sspeer void vdds_cleanup(vnet_t *vnetp);
92678453a8Sspeer void vdds_process_dds_msg(vnet_t *vnetp, vio_dds_msg_t *dmsg);
93d0288fccSRaghuram Kothakota void vdds_cleanup_hybrid_res(void *arg);
946d6de4eeSWENTAO YANG void vdds_cleanup_hio(vnet_t *vnetp);
95678453a8Sspeer
96678453a8Sspeer /* Support functions to create/destory Hybrid device */
977b1f684aSSriharsha Basavapatna static dev_info_t *vdds_create_niu_node(uint64_t cookie,
987b1f684aSSriharsha Basavapatna uint64_t macaddr, uint32_t max_frame_size);
99678453a8Sspeer static int vdds_destroy_niu_node(dev_info_t *niu_dip, uint64_t cookie);
1007b1f684aSSriharsha Basavapatna static dev_info_t *vdds_create_new_node(vdds_cb_arg_t *cba,
101678453a8Sspeer dev_info_t *pdip, int (*new_node_func)(dev_info_t *dip,
102678453a8Sspeer void *arg, uint_t flags));
103678453a8Sspeer static int vdds_new_nexus_node(dev_info_t *dip, void *arg, uint_t flags);
104678453a8Sspeer static int vdds_new_niu_node(dev_info_t *dip, void *arg, uint_t flags);
105678453a8Sspeer static dev_info_t *vdds_find_node(uint64_t cookie, dev_info_t *sdip,
106678453a8Sspeer int (*match_func)(dev_info_t *dip, void *arg));
107678453a8Sspeer static int vdds_match_niu_nexus(dev_info_t *dip, void *arg);
108678453a8Sspeer static int vdds_match_niu_node(dev_info_t *dip, void *arg);
109678453a8Sspeer static int vdds_get_interrupts(uint64_t cookie, int ino_range,
110678453a8Sspeer int *intrs, int *nintr);
111678453a8Sspeer
112678453a8Sspeer /* DDS message processing related functions */
113678453a8Sspeer static void vdds_process_dds_msg_task(void *arg);
114678453a8Sspeer static int vdds_send_dds_resp_msg(vnet_t *vnetp, vio_dds_msg_t *dmsg, int ack);
115678453a8Sspeer static int vdds_send_dds_rel_msg(vnet_t *vnetp);
116678453a8Sspeer static void vdds_release_range_prop(dev_info_t *nexus_dip, uint64_t cookie);
117678453a8Sspeer
118678453a8Sspeer /* Functions imported from other files */
119678453a8Sspeer extern int vnet_send_dds_msg(vnet_t *vnetp, void *dmsg);
12063f531d1SSriharsha Basavapatna extern int vnet_hio_mac_init(vnet_t *vnetp, char *ifname);
12163f531d1SSriharsha Basavapatna extern void vnet_hio_mac_cleanup(vnet_t *vnetp);
122678453a8Sspeer
123678453a8Sspeer /* HV functions that are used in this file */
124678453a8Sspeer extern uint64_t vdds_hv_niu_vr_getinfo(uint32_t hvcookie,
125678453a8Sspeer uint64_t *real_start, uint64_t *size);
126678453a8Sspeer extern uint64_t vdds_hv_niu_vr_get_txmap(uint32_t hvcookie, uint64_t *dma_map);
127678453a8Sspeer extern uint64_t vdds_hv_niu_vr_get_rxmap(uint32_t hvcookie, uint64_t *dma_map);
128678453a8Sspeer extern uint64_t vdds_hv_niu_vrtx_set_ino(uint32_t cookie, uint64_t vch_idx,
129678453a8Sspeer uint32_t ino);
130678453a8Sspeer extern uint64_t vdds_hv_niu_vrrx_set_ino(uint32_t cookie, uint64_t vch_idx,
131678453a8Sspeer uint32_t ino);
132678453a8Sspeer
133678453a8Sspeer
134678453a8Sspeer #ifdef DEBUG
135678453a8Sspeer
1367bd3a2e2SSriharsha Basavapatna #define DEBUG_PRINTF debug_printf
1377bd3a2e2SSriharsha Basavapatna
138678453a8Sspeer extern int vnet_dbglevel;
139678453a8Sspeer
140678453a8Sspeer static void
debug_printf(const char * fname,void * arg,const char * fmt,...)141678453a8Sspeer debug_printf(const char *fname, void *arg, const char *fmt, ...)
142678453a8Sspeer {
143678453a8Sspeer char buf[512];
144678453a8Sspeer va_list ap;
145678453a8Sspeer char *bufp = buf;
146678453a8Sspeer vnet_dds_info_t *vdds = arg;
147678453a8Sspeer
148678453a8Sspeer if (vdds != NULL) {
149678453a8Sspeer (void) sprintf(bufp, "vnet%d: %s: ",
150678453a8Sspeer vdds->vnetp->instance, fname);
151678453a8Sspeer } else {
152678453a8Sspeer (void) sprintf(bufp, "%s: ", fname);
153678453a8Sspeer }
154678453a8Sspeer bufp += strlen(bufp);
155678453a8Sspeer va_start(ap, fmt);
156678453a8Sspeer (void) vsprintf(bufp, fmt, ap);
157678453a8Sspeer va_end(ap);
158678453a8Sspeer cmn_err(CE_CONT, "%s\n", buf);
159678453a8Sspeer }
160678453a8Sspeer #endif
161678453a8Sspeer
162678453a8Sspeer /*
1634df55fdeSJanie Lu * Hypervisor N2/NIU services information:
1644df55fdeSJanie Lu *
1654df55fdeSJanie Lu * The list of HV versions that support NIU HybridIO. Note,
1664df55fdeSJanie Lu * the order is higher version to a lower version, as the
1674df55fdeSJanie Lu * registration is attempted in this order.
168678453a8Sspeer */
1694df55fdeSJanie Lu static hsvc_info_t niu_hsvc[] = {
1704df55fdeSJanie Lu {HSVC_REV_1, NULL, HSVC_GROUP_NIU, 2, 0, "vnet_dds"},
1714df55fdeSJanie Lu {HSVC_REV_1, NULL, HSVC_GROUP_NIU, 1, 1, "vnet_dds"}
172678453a8Sspeer };
173678453a8Sspeer
174d0288fccSRaghuram Kothakota /*
1754df55fdeSJanie Lu * Index that points to the successful HV version that
1764df55fdeSJanie Lu * is registered.
1774df55fdeSJanie Lu */
1784df55fdeSJanie Lu static int niu_hsvc_index = -1;
1794df55fdeSJanie Lu
1804df55fdeSJanie Lu /*
181d0288fccSRaghuram Kothakota * Lock to serialize the NIU device node related operations.
182d0288fccSRaghuram Kothakota */
183d0288fccSRaghuram Kothakota kmutex_t vdds_dev_lock;
184d0288fccSRaghuram Kothakota
185678453a8Sspeer boolean_t vdds_hv_hio_capable = B_FALSE;
186678453a8Sspeer
187678453a8Sspeer /*
188678453a8Sspeer * vdds_mod_init -- one time initialization.
189678453a8Sspeer */
190678453a8Sspeer void
vdds_mod_init(void)191678453a8Sspeer vdds_mod_init(void)
192678453a8Sspeer {
1934df55fdeSJanie Lu int i;
194678453a8Sspeer int rv;
1954df55fdeSJanie Lu uint64_t minor = 0;
196678453a8Sspeer
197678453a8Sspeer /*
1984df55fdeSJanie Lu * Try register one by one from niu_hsvc.
199678453a8Sspeer */
2004df55fdeSJanie Lu for (i = 0; i < (sizeof (niu_hsvc) / sizeof (hsvc_info_t)); i++) {
2014df55fdeSJanie Lu rv = hsvc_register(&niu_hsvc[i], &minor);
2024df55fdeSJanie Lu if (rv == 0) {
2034df55fdeSJanie Lu if (minor == niu_hsvc[i].hsvc_minor) {
204678453a8Sspeer vdds_hv_hio_capable = B_TRUE;
2054df55fdeSJanie Lu niu_hsvc_index = i;
2064df55fdeSJanie Lu break;
2074df55fdeSJanie Lu } else {
2084df55fdeSJanie Lu (void) hsvc_unregister(&niu_hsvc[i]);
2094df55fdeSJanie Lu }
2104df55fdeSJanie Lu }
211678453a8Sspeer }
212d0288fccSRaghuram Kothakota mutex_init(&vdds_dev_lock, NULL, MUTEX_DRIVER, NULL);
2134df55fdeSJanie Lu DBG2(NULL, "HV HIO capable=%d ver(%ld.%ld)", vdds_hv_hio_capable,
2144df55fdeSJanie Lu (niu_hsvc_index == -1) ? 0 : niu_hsvc[niu_hsvc_index].hsvc_major,
2154df55fdeSJanie Lu minor);
216678453a8Sspeer }
217678453a8Sspeer
218678453a8Sspeer /*
219678453a8Sspeer * vdds_mod_fini -- one time cleanup.
220678453a8Sspeer */
221678453a8Sspeer void
vdds_mod_fini(void)222678453a8Sspeer vdds_mod_fini(void)
223678453a8Sspeer {
2244df55fdeSJanie Lu if (niu_hsvc_index != -1) {
2254df55fdeSJanie Lu (void) hsvc_unregister(&niu_hsvc[niu_hsvc_index]);
2264df55fdeSJanie Lu }
227d0288fccSRaghuram Kothakota mutex_destroy(&vdds_dev_lock);
228678453a8Sspeer }
229678453a8Sspeer
230678453a8Sspeer /*
231678453a8Sspeer * vdds_init -- vnet instance related DDS related initialization.
232678453a8Sspeer */
233678453a8Sspeer int
vdds_init(vnet_t * vnetp)234678453a8Sspeer vdds_init(vnet_t *vnetp)
235678453a8Sspeer {
236678453a8Sspeer vnet_dds_info_t *vdds = &vnetp->vdds_info;
237678453a8Sspeer char qname[TASKQ_NAMELEN];
238678453a8Sspeer
239678453a8Sspeer vdds->vnetp = vnetp;
240678453a8Sspeer DBG1(vdds, "Initializing..");
241678453a8Sspeer (void) snprintf(qname, TASKQ_NAMELEN, "vdds_taskq%d", vnetp->instance);
242678453a8Sspeer if ((vdds->dds_taskqp = ddi_taskq_create(vnetp->dip, qname, 1,
243678453a8Sspeer TASKQ_DEFAULTPRI, 0)) == NULL) {
244678453a8Sspeer cmn_err(CE_WARN, "!vnet%d: Unable to create DDS task queue",
245678453a8Sspeer vnetp->instance);
246678453a8Sspeer return (ENOMEM);
247678453a8Sspeer }
248678453a8Sspeer mutex_init(&vdds->lock, NULL, MUTEX_DRIVER, NULL);
249678453a8Sspeer return (0);
250678453a8Sspeer }
251678453a8Sspeer
252678453a8Sspeer /*
253678453a8Sspeer * vdds_cleanup -- vnet instance related cleanup.
254678453a8Sspeer */
255678453a8Sspeer void
vdds_cleanup(vnet_t * vnetp)256678453a8Sspeer vdds_cleanup(vnet_t *vnetp)
257678453a8Sspeer {
258678453a8Sspeer vnet_dds_info_t *vdds = &vnetp->vdds_info;
259678453a8Sspeer
260678453a8Sspeer DBG1(vdds, "Cleanup...");
261678453a8Sspeer /* Cleanup/destroy any hybrid resouce that exists */
262678453a8Sspeer vdds_cleanup_hybrid_res(vnetp);
263678453a8Sspeer
264678453a8Sspeer /* taskq_destroy will wait for all taskqs to complete */
265678453a8Sspeer ddi_taskq_destroy(vdds->dds_taskqp);
266678453a8Sspeer vdds->dds_taskqp = NULL;
267678453a8Sspeer mutex_destroy(&vdds->lock);
268678453a8Sspeer DBG1(vdds, "Cleanup complete");
269678453a8Sspeer }
270678453a8Sspeer
271678453a8Sspeer /*
272678453a8Sspeer * vdds_cleanup_hybrid_res -- Cleanup Hybrid resource.
273678453a8Sspeer */
274678453a8Sspeer void
vdds_cleanup_hybrid_res(void * arg)275d0288fccSRaghuram Kothakota vdds_cleanup_hybrid_res(void *arg)
276678453a8Sspeer {
277d0288fccSRaghuram Kothakota vnet_t *vnetp = arg;
278678453a8Sspeer vnet_dds_info_t *vdds = &vnetp->vdds_info;
279678453a8Sspeer
280678453a8Sspeer DBG1(vdds, "Hybrid device cleanup...");
281678453a8Sspeer mutex_enter(&vdds->lock);
282678453a8Sspeer if (vdds->task_flags == VNET_DDS_TASK_ADD_SHARE) {
283678453a8Sspeer /*
284678453a8Sspeer * Task for ADD_SHARE is pending, simply
285678453a8Sspeer * cleanup the flags, the task will quit without
286678453a8Sspeer * any changes.
287678453a8Sspeer */
288678453a8Sspeer vdds->task_flags = 0;
289678453a8Sspeer DBG2(vdds, "Task for ADD is pending, clean flags only");
290678453a8Sspeer } else if ((vdds->hio_dip != NULL) && (vdds->task_flags == 0)) {
291678453a8Sspeer /*
292678453a8Sspeer * There is no task pending and a hybrid device
293678453a8Sspeer * is present, so dispatch a task to release the share.
294678453a8Sspeer */
295678453a8Sspeer vdds->task_flags = VNET_DDS_TASK_REL_SHARE;
296678453a8Sspeer (void) ddi_taskq_dispatch(vdds->dds_taskqp,
297678453a8Sspeer vdds_process_dds_msg_task, vnetp, DDI_NOSLEEP);
298678453a8Sspeer DBG2(vdds, "Dispatched a task to destroy HIO device");
299678453a8Sspeer }
300678453a8Sspeer /*
301678453a8Sspeer * Other possible cases include either DEL_SHARE or
302678453a8Sspeer * REL_SHARE as pending. In that case, there is nothing
303678453a8Sspeer * to do as a task is already pending to do the cleanup.
304678453a8Sspeer */
305678453a8Sspeer mutex_exit(&vdds->lock);
306678453a8Sspeer DBG1(vdds, "Hybrid device cleanup complete");
307678453a8Sspeer }
308678453a8Sspeer
309678453a8Sspeer /*
3106d6de4eeSWENTAO YANG * vdds_cleanup_hio -- An interface to cleanup the hio resources before
3116d6de4eeSWENTAO YANG * resetting the vswitch port.
3126d6de4eeSWENTAO YANG */
3136d6de4eeSWENTAO YANG void
vdds_cleanup_hio(vnet_t * vnetp)3146d6de4eeSWENTAO YANG vdds_cleanup_hio(vnet_t *vnetp)
3156d6de4eeSWENTAO YANG {
3166d6de4eeSWENTAO YANG vnet_dds_info_t *vdds = &vnetp->vdds_info;
3176d6de4eeSWENTAO YANG
3186d6de4eeSWENTAO YANG /* Wait for any pending vdds tasks to complete */
3196d6de4eeSWENTAO YANG ddi_taskq_wait(vdds->dds_taskqp);
3206d6de4eeSWENTAO YANG vdds_cleanup_hybrid_res(vnetp);
3216d6de4eeSWENTAO YANG /* Wait for the cleanup task to complete */
3226d6de4eeSWENTAO YANG ddi_taskq_wait(vdds->dds_taskqp);
3236d6de4eeSWENTAO YANG }
3246d6de4eeSWENTAO YANG
3256d6de4eeSWENTAO YANG /*
326678453a8Sspeer * vdds_process_dds_msg -- Process a DDS message.
327678453a8Sspeer */
328678453a8Sspeer void
vdds_process_dds_msg(vnet_t * vnetp,vio_dds_msg_t * dmsg)329678453a8Sspeer vdds_process_dds_msg(vnet_t *vnetp, vio_dds_msg_t *dmsg)
330678453a8Sspeer {
331678453a8Sspeer vnet_dds_info_t *vdds = &vnetp->vdds_info;
332678453a8Sspeer int rv;
333678453a8Sspeer
334678453a8Sspeer DBG1(vdds, "DDS message received...");
335678453a8Sspeer
336678453a8Sspeer if (dmsg->dds_class != DDS_VNET_NIU) {
337678453a8Sspeer DBG2(vdds, "Invalid class send NACK");
338678453a8Sspeer (void) vdds_send_dds_resp_msg(vnetp, dmsg, B_FALSE);
339678453a8Sspeer return;
340678453a8Sspeer }
341678453a8Sspeer mutex_enter(&vdds->lock);
342678453a8Sspeer switch (dmsg->dds_subclass) {
343678453a8Sspeer case DDS_VNET_ADD_SHARE:
344678453a8Sspeer DBG2(vdds, "DDS_VNET_ADD_SHARE message...");
345678453a8Sspeer if ((vdds->task_flags != 0) || (vdds->hio_dip != NULL)) {
346678453a8Sspeer /*
347678453a8Sspeer * Either a task is already pending or
348678453a8Sspeer * a hybrid device already exists.
349678453a8Sspeer */
350678453a8Sspeer DWARN(vdds, "NACK: Already pending DDS task");
351678453a8Sspeer (void) vdds_send_dds_resp_msg(vnetp, dmsg, B_FALSE);
352678453a8Sspeer mutex_exit(&vdds->lock);
353678453a8Sspeer return;
354678453a8Sspeer }
355678453a8Sspeer vdds->task_flags = VNET_DDS_TASK_ADD_SHARE;
356678453a8Sspeer bcopy(dmsg, &vnetp->vdds_info.dmsg, sizeof (vio_dds_msg_t));
357678453a8Sspeer DBG2(vdds, "Dispatching task for ADD_SHARE");
358678453a8Sspeer rv = ddi_taskq_dispatch(vdds->dds_taskqp,
359678453a8Sspeer vdds_process_dds_msg_task, vnetp, DDI_NOSLEEP);
360678453a8Sspeer if (rv != 0) {
361678453a8Sspeer /* Send NACK */
362678453a8Sspeer DBG2(vdds, "NACK: Failed to dispatch task");
363678453a8Sspeer (void) vdds_send_dds_resp_msg(vnetp, dmsg, B_FALSE);
364678453a8Sspeer vdds->task_flags = 0;
365678453a8Sspeer }
366678453a8Sspeer break;
367678453a8Sspeer
368678453a8Sspeer case DDS_VNET_DEL_SHARE:
369678453a8Sspeer DBG2(vdds, "DDS_VNET_DEL_SHARE message...");
370678453a8Sspeer if (vdds->task_flags == VNET_DDS_TASK_ADD_SHARE) {
371678453a8Sspeer /*
372678453a8Sspeer * ADD_SHARE task still pending, simply clear
373678453a8Sspeer * task falgs and ACK.
374678453a8Sspeer */
375678453a8Sspeer DBG2(vdds, "ACK:ADD_SHARE task still pending");
376678453a8Sspeer vdds->task_flags = 0;
377678453a8Sspeer (void) vdds_send_dds_resp_msg(vnetp, dmsg, B_TRUE);
378678453a8Sspeer mutex_exit(&vdds->lock);
379678453a8Sspeer return;
380678453a8Sspeer }
381678453a8Sspeer if ((vdds->task_flags == 0) && (vdds->hio_dip == NULL)) {
382678453a8Sspeer /* Send NACK */
383678453a8Sspeer DBG2(vdds, "NACK:No HIO device exists");
384678453a8Sspeer (void) vdds_send_dds_resp_msg(vnetp, dmsg, B_FALSE);
385678453a8Sspeer mutex_exit(&vdds->lock);
386678453a8Sspeer return;
387678453a8Sspeer }
388678453a8Sspeer vdds->task_flags = VNET_DDS_TASK_DEL_SHARE;
389678453a8Sspeer bcopy(dmsg, &vdds->dmsg, sizeof (vio_dds_msg_t));
390678453a8Sspeer DBG2(vdds, "Dispatching DEL_SHARE task");
391678453a8Sspeer rv = ddi_taskq_dispatch(vdds->dds_taskqp,
392678453a8Sspeer vdds_process_dds_msg_task, vnetp, DDI_NOSLEEP);
393678453a8Sspeer if (rv != 0) {
394678453a8Sspeer /* Send NACK */
395678453a8Sspeer DBG2(vdds, "NACK: failed to dispatch task");
396678453a8Sspeer (void) vdds_send_dds_resp_msg(vnetp, dmsg, B_FALSE);
397678453a8Sspeer vdds->task_flags = 0;
398678453a8Sspeer }
399678453a8Sspeer break;
400678453a8Sspeer case DDS_VNET_REL_SHARE:
401678453a8Sspeer DBG2(vdds, "Reply for REL_SHARE reply=%d",
402678453a8Sspeer dmsg->tag.vio_subtype);
403678453a8Sspeer break;
404678453a8Sspeer default:
405678453a8Sspeer DWARN(vdds, "Discarding Unknown DDS message");
406678453a8Sspeer break;
407678453a8Sspeer }
408678453a8Sspeer mutex_exit(&vdds->lock);
409678453a8Sspeer }
410678453a8Sspeer
411678453a8Sspeer /*
412678453a8Sspeer * vdds_process_dds_msg_task -- Called from a taskq to process the
413678453a8Sspeer * DDS message.
414678453a8Sspeer */
415678453a8Sspeer static void
vdds_process_dds_msg_task(void * arg)416678453a8Sspeer vdds_process_dds_msg_task(void *arg)
417678453a8Sspeer {
418678453a8Sspeer vnet_t *vnetp = arg;
419678453a8Sspeer vnet_dds_info_t *vdds = &vnetp->vdds_info;
420678453a8Sspeer vio_dds_msg_t *dmsg = &vdds->dmsg;
421678453a8Sspeer dev_info_t *dip;
4227b1f684aSSriharsha Basavapatna uint32_t max_frame_size;
423678453a8Sspeer uint64_t hio_cookie;
424678453a8Sspeer int rv;
425678453a8Sspeer
426678453a8Sspeer DBG1(vdds, "DDS task started...");
427678453a8Sspeer mutex_enter(&vdds->lock);
428678453a8Sspeer switch (vdds->task_flags) {
429678453a8Sspeer case VNET_DDS_TASK_ADD_SHARE:
430678453a8Sspeer DBG2(vdds, "ADD_SHARE task...");
431678453a8Sspeer hio_cookie = dmsg->msg.share_msg.cookie;
4327b1f684aSSriharsha Basavapatna /*
4337b1f684aSSriharsha Basavapatna * max-frame-size value need to be set to
4347b1f684aSSriharsha Basavapatna * the full ethernet frame size. That is,
4357b1f684aSSriharsha Basavapatna * header + payload + checksum.
4367b1f684aSSriharsha Basavapatna */
4377b1f684aSSriharsha Basavapatna max_frame_size = vnetp->mtu +
4387b1f684aSSriharsha Basavapatna sizeof (struct ether_vlan_header) + ETHERFCSL;
439678453a8Sspeer dip = vdds_create_niu_node(hio_cookie,
4407b1f684aSSriharsha Basavapatna dmsg->msg.share_msg.macaddr, max_frame_size);
441678453a8Sspeer if (dip == NULL) {
442678453a8Sspeer (void) vdds_send_dds_resp_msg(vnetp, dmsg, B_FALSE);
443678453a8Sspeer DERR(vdds, "Failed to create HIO node");
444678453a8Sspeer } else {
445678453a8Sspeer vdds->hio_dip = dip;
446678453a8Sspeer vdds->hio_cookie = hio_cookie;
4478a81408bSSriharsha Basavapatna (void) snprintf(vdds->hio_ifname,
4488a81408bSSriharsha Basavapatna sizeof (vdds->hio_ifname), "%s%d",
4498a81408bSSriharsha Basavapatna ddi_driver_name(dip), ddi_get_instance(dip));
45063f531d1SSriharsha Basavapatna
45163f531d1SSriharsha Basavapatna rv = vnet_hio_mac_init(vnetp, vdds->hio_ifname);
45263f531d1SSriharsha Basavapatna if (rv != 0) {
45363f531d1SSriharsha Basavapatna /* failed - cleanup, send failed DDS message */
45463f531d1SSriharsha Basavapatna DERR(vdds, "HIO mac init failed, cleaning up");
45563f531d1SSriharsha Basavapatna rv = vdds_destroy_niu_node(dip, hio_cookie);
45663f531d1SSriharsha Basavapatna if (rv == 0) {
45763f531d1SSriharsha Basavapatna /* use DERR to print by default */
45863f531d1SSriharsha Basavapatna DERR(vdds, "Successfully destroyed"
45963f531d1SSriharsha Basavapatna " Hybrid node");
46063f531d1SSriharsha Basavapatna } else {
46163f531d1SSriharsha Basavapatna cmn_err(CE_WARN, "vnet%d:Failed to "
46263f531d1SSriharsha Basavapatna "destroy Hybrid node",
46363f531d1SSriharsha Basavapatna vnetp->instance);
46463f531d1SSriharsha Basavapatna }
46563f531d1SSriharsha Basavapatna vdds->hio_dip = NULL;
46663f531d1SSriharsha Basavapatna vdds->hio_cookie = 0;
46763f531d1SSriharsha Basavapatna (void) vdds_send_dds_resp_msg(vnetp,
46863f531d1SSriharsha Basavapatna dmsg, B_FALSE);
46963f531d1SSriharsha Basavapatna } else {
47063f531d1SSriharsha Basavapatna (void) vdds_send_dds_resp_msg(vnetp,
47163f531d1SSriharsha Basavapatna dmsg, B_TRUE);
47263f531d1SSriharsha Basavapatna }
473678453a8Sspeer /* DERR used only print by default */
474678453a8Sspeer DERR(vdds, "Successfully created HIO node");
475678453a8Sspeer }
476678453a8Sspeer break;
477678453a8Sspeer
478678453a8Sspeer case VNET_DDS_TASK_DEL_SHARE:
479678453a8Sspeer DBG2(vdds, "DEL_SHARE task...");
480678453a8Sspeer if (vnetp->vdds_info.hio_dip == NULL) {
481678453a8Sspeer DBG2(vdds, "NACK: No HIO device destroy");
482678453a8Sspeer (void) vdds_send_dds_resp_msg(vnetp, dmsg, B_FALSE);
483678453a8Sspeer } else {
48463f531d1SSriharsha Basavapatna vnet_hio_mac_cleanup(vnetp);
485678453a8Sspeer rv = vdds_destroy_niu_node(vnetp->vdds_info.hio_dip,
486678453a8Sspeer vdds->hio_cookie);
487678453a8Sspeer if (rv == 0) {
488678453a8Sspeer /* use DERR to print by default */
489678453a8Sspeer DERR(vdds, "Successfully destroyed"
490678453a8Sspeer " Hybrid node");
491678453a8Sspeer } else {
492678453a8Sspeer cmn_err(CE_WARN, "vnet%d:Failed to "
493678453a8Sspeer "destroy Hybrid node", vnetp->instance);
494678453a8Sspeer }
495678453a8Sspeer /* TODO: send ACK even for failure? */
496678453a8Sspeer DBG2(vdds, "ACK: HIO device destroyed");
497678453a8Sspeer (void) vdds_send_dds_resp_msg(vnetp, dmsg, B_TRUE);
498678453a8Sspeer vdds->hio_dip = 0;
499678453a8Sspeer vdds->hio_cookie = 0;
500678453a8Sspeer }
501678453a8Sspeer break;
502678453a8Sspeer case VNET_DDS_TASK_REL_SHARE:
503678453a8Sspeer DBG2(vdds, "REL_SHARE task...");
504678453a8Sspeer if (vnetp->vdds_info.hio_dip != NULL) {
50563f531d1SSriharsha Basavapatna vnet_hio_mac_cleanup(vnetp);
506678453a8Sspeer rv = vdds_destroy_niu_node(vnetp->vdds_info.hio_dip,
507678453a8Sspeer vdds->hio_cookie);
508678453a8Sspeer if (rv == 0) {
509678453a8Sspeer DERR(vdds, "Successfully destroyed "
510678453a8Sspeer "Hybrid node");
511678453a8Sspeer } else {
512678453a8Sspeer cmn_err(CE_WARN, "vnet%d:Failed to "
513678453a8Sspeer "destroy HIO node", vnetp->instance);
514678453a8Sspeer }
515678453a8Sspeer /* TODO: failure case */
516678453a8Sspeer (void) vdds_send_dds_rel_msg(vnetp);
517678453a8Sspeer vdds->hio_dip = 0;
518678453a8Sspeer vdds->hio_cookie = 0;
519678453a8Sspeer }
520678453a8Sspeer break;
521678453a8Sspeer default:
522678453a8Sspeer break;
523678453a8Sspeer }
524678453a8Sspeer vdds->task_flags = 0;
525678453a8Sspeer mutex_exit(&vdds->lock);
526678453a8Sspeer }
527678453a8Sspeer
528678453a8Sspeer /*
529678453a8Sspeer * vdds_send_dds_rel_msg -- Send a DDS_REL_SHARE message.
530678453a8Sspeer */
531678453a8Sspeer static int
vdds_send_dds_rel_msg(vnet_t * vnetp)532678453a8Sspeer vdds_send_dds_rel_msg(vnet_t *vnetp)
533678453a8Sspeer {
534678453a8Sspeer vnet_dds_info_t *vdds = &vnetp->vdds_info;
535678453a8Sspeer vio_dds_msg_t vmsg;
536678453a8Sspeer dds_share_msg_t *smsg = &vmsg.msg.share_msg;
537678453a8Sspeer int rv;
538678453a8Sspeer
539678453a8Sspeer DBG1(vdds, "Sending DDS_VNET_REL_SHARE message");
540678453a8Sspeer vmsg.tag.vio_msgtype = VIO_TYPE_CTRL;
541678453a8Sspeer vmsg.tag.vio_subtype = VIO_SUBTYPE_INFO;
542678453a8Sspeer vmsg.tag.vio_subtype_env = VIO_DDS_INFO;
543678453a8Sspeer /* vio_sid filled by the LDC module */
544678453a8Sspeer vmsg.dds_class = DDS_VNET_NIU;
545678453a8Sspeer vmsg.dds_subclass = DDS_VNET_REL_SHARE;
546678453a8Sspeer vmsg.dds_req_id = (++vdds->dds_req_id);
547678453a8Sspeer smsg->macaddr = vnet_macaddr_strtoul(vnetp->curr_macaddr);
548678453a8Sspeer smsg->cookie = vdds->hio_cookie;
549678453a8Sspeer rv = vnet_send_dds_msg(vnetp, &vmsg);
550678453a8Sspeer return (rv);
551678453a8Sspeer }
552678453a8Sspeer
553678453a8Sspeer /*
554678453a8Sspeer * vdds_send_dds_resp_msg -- Send a DDS response message.
555678453a8Sspeer */
556678453a8Sspeer static int
vdds_send_dds_resp_msg(vnet_t * vnetp,vio_dds_msg_t * dmsg,int ack)557678453a8Sspeer vdds_send_dds_resp_msg(vnet_t *vnetp, vio_dds_msg_t *dmsg, int ack)
558678453a8Sspeer {
559678453a8Sspeer vnet_dds_info_t *vdds = &vnetp->vdds_info;
560678453a8Sspeer int rv;
561678453a8Sspeer
562678453a8Sspeer DBG1(vdds, "Sending a response mesage=%d", ack);
563678453a8Sspeer if (ack == B_TRUE) {
564678453a8Sspeer dmsg->tag.vio_subtype = VIO_SUBTYPE_ACK;
565678453a8Sspeer dmsg->msg.share_resp_msg.status = DDS_VNET_SUCCESS;
566678453a8Sspeer } else {
567678453a8Sspeer dmsg->tag.vio_subtype = VIO_SUBTYPE_NACK;
568678453a8Sspeer dmsg->msg.share_resp_msg.status = DDS_VNET_FAIL;
569678453a8Sspeer }
570678453a8Sspeer rv = vnet_send_dds_msg(vnetp, dmsg);
571678453a8Sspeer return (rv);
572678453a8Sspeer }
573678453a8Sspeer
574678453a8Sspeer /*
575678453a8Sspeer * vdds_create_niu_node -- Create NIU Hybrid node. The NIU nexus
576678453a8Sspeer * node also created if it doesn't exist already.
577678453a8Sspeer */
578678453a8Sspeer dev_info_t *
vdds_create_niu_node(uint64_t cookie,uint64_t macaddr,uint32_t max_frame_size)5797b1f684aSSriharsha Basavapatna vdds_create_niu_node(uint64_t cookie, uint64_t macaddr, uint32_t max_frame_size)
580678453a8Sspeer {
581678453a8Sspeer dev_info_t *nexus_dip;
582678453a8Sspeer dev_info_t *niu_dip;
5837b1f684aSSriharsha Basavapatna vdds_cb_arg_t cba;
584678453a8Sspeer
585678453a8Sspeer DBG1(NULL, "Called");
586678453a8Sspeer
587678453a8Sspeer if (vdds_hv_hio_capable == B_FALSE) {
588678453a8Sspeer return (NULL);
589678453a8Sspeer }
590d0288fccSRaghuram Kothakota mutex_enter(&vdds_dev_lock);
591678453a8Sspeer /* Check if the nexus node exists already */
592678453a8Sspeer nexus_dip = vdds_find_node(cookie, ddi_root_node(),
593678453a8Sspeer vdds_match_niu_nexus);
594678453a8Sspeer if (nexus_dip == NULL) {
595678453a8Sspeer /*
596678453a8Sspeer * NIU nexus node not found, so create it now.
597678453a8Sspeer */
5987b1f684aSSriharsha Basavapatna cba.dip = NULL;
5997b1f684aSSriharsha Basavapatna cba.cookie = cookie;
6007b1f684aSSriharsha Basavapatna cba.macaddr = macaddr;
6017b1f684aSSriharsha Basavapatna cba.max_frame_size = max_frame_size;
6027b1f684aSSriharsha Basavapatna nexus_dip = vdds_create_new_node(&cba, NULL,
603678453a8Sspeer vdds_new_nexus_node);
604678453a8Sspeer if (nexus_dip == NULL) {
605d0288fccSRaghuram Kothakota mutex_exit(&vdds_dev_lock);
606678453a8Sspeer return (NULL);
607678453a8Sspeer }
608678453a8Sspeer }
609678453a8Sspeer DBG2(NULL, "nexus_dip = 0x%p", nexus_dip);
610678453a8Sspeer
611678453a8Sspeer /* Check if NIU node exists already before creating one */
612678453a8Sspeer niu_dip = vdds_find_node(cookie, nexus_dip,
613678453a8Sspeer vdds_match_niu_node);
614678453a8Sspeer if (niu_dip == NULL) {
6157b1f684aSSriharsha Basavapatna cba.dip = NULL;
6167b1f684aSSriharsha Basavapatna cba.cookie = cookie;
6177b1f684aSSriharsha Basavapatna cba.macaddr = macaddr;
6187b1f684aSSriharsha Basavapatna cba.max_frame_size = max_frame_size;
6197b1f684aSSriharsha Basavapatna niu_dip = vdds_create_new_node(&cba, nexus_dip,
620678453a8Sspeer vdds_new_niu_node);
621678453a8Sspeer /*
622d0288fccSRaghuram Kothakota * Hold the niu_dip to prevent it from
623d0288fccSRaghuram Kothakota * detaching.
624678453a8Sspeer */
625d0288fccSRaghuram Kothakota if (niu_dip != NULL) {
626d0288fccSRaghuram Kothakota e_ddi_hold_devi(niu_dip);
627d0288fccSRaghuram Kothakota } else {
628d0288fccSRaghuram Kothakota DWARN(NULL, "niumx/network node creation failed");
629678453a8Sspeer }
630d0288fccSRaghuram Kothakota } else {
631d0288fccSRaghuram Kothakota DWARN(NULL, "niumx/network node already exists(dip=0x%p)",
632d0288fccSRaghuram Kothakota niu_dip);
633d0288fccSRaghuram Kothakota }
634d0288fccSRaghuram Kothakota /* release the hold that was done in find/create */
635d0288fccSRaghuram Kothakota if ((niu_dip != NULL) && (e_ddi_branch_held(niu_dip)))
636d0288fccSRaghuram Kothakota e_ddi_branch_rele(niu_dip);
637d0288fccSRaghuram Kothakota if (e_ddi_branch_held(nexus_dip))
638d0288fccSRaghuram Kothakota e_ddi_branch_rele(nexus_dip);
639d0288fccSRaghuram Kothakota mutex_exit(&vdds_dev_lock);
640d0288fccSRaghuram Kothakota DBG1(NULL, "returning niu_dip=0x%p", niu_dip);
641678453a8Sspeer return (niu_dip);
642678453a8Sspeer }
643678453a8Sspeer
644678453a8Sspeer /*
645678453a8Sspeer * vdds_destroy_niu_node -- Destroy the NIU node.
646678453a8Sspeer */
647678453a8Sspeer int
vdds_destroy_niu_node(dev_info_t * niu_dip,uint64_t cookie)648678453a8Sspeer vdds_destroy_niu_node(dev_info_t *niu_dip, uint64_t cookie)
649678453a8Sspeer {
650678453a8Sspeer int rv;
651678453a8Sspeer dev_info_t *fdip = NULL;
652678453a8Sspeer dev_info_t *nexus_dip = ddi_get_parent(niu_dip);
653678453a8Sspeer
654678453a8Sspeer
655678453a8Sspeer DBG1(NULL, "Called");
656d0288fccSRaghuram Kothakota ASSERT(nexus_dip != NULL);
657d0288fccSRaghuram Kothakota mutex_enter(&vdds_dev_lock);
658d0288fccSRaghuram Kothakota
659d0288fccSRaghuram Kothakota if (!e_ddi_branch_held(niu_dip))
660d0288fccSRaghuram Kothakota e_ddi_branch_hold(niu_dip);
661d0288fccSRaghuram Kothakota /*
662d0288fccSRaghuram Kothakota * As we are destroying now, release the
663d0288fccSRaghuram Kothakota * hold that was done in during the creation.
664d0288fccSRaghuram Kothakota */
665d0288fccSRaghuram Kothakota ddi_release_devi(niu_dip);
666678453a8Sspeer rv = e_ddi_branch_destroy(niu_dip, &fdip, 0);
667678453a8Sspeer if (rv != 0) {
668678453a8Sspeer DERR(NULL, "Failed to destroy niumx/network node dip=0x%p",
669678453a8Sspeer niu_dip);
670678453a8Sspeer if (fdip != NULL) {
671d0288fccSRaghuram Kothakota ddi_release_devi(fdip);
672678453a8Sspeer }
673d0288fccSRaghuram Kothakota rv = EBUSY;
674d0288fccSRaghuram Kothakota goto dest_exit;
675678453a8Sspeer }
676678453a8Sspeer /*
677678453a8Sspeer * Cleanup the parent's ranges property set
678678453a8Sspeer * for this Hybrid device.
679678453a8Sspeer */
680678453a8Sspeer vdds_release_range_prop(nexus_dip, cookie);
681d0288fccSRaghuram Kothakota
682d0288fccSRaghuram Kothakota dest_exit:
683d0288fccSRaghuram Kothakota mutex_exit(&vdds_dev_lock);
684d0288fccSRaghuram Kothakota DBG1(NULL, "returning rv=%d", rv);
685d0288fccSRaghuram Kothakota return (rv);
686678453a8Sspeer }
687678453a8Sspeer
688678453a8Sspeer /*
689678453a8Sspeer * vdds_match_niu_nexus -- callback function to verify a node is the
690678453a8Sspeer * NIU nexus node.
691678453a8Sspeer */
692678453a8Sspeer static int
vdds_match_niu_nexus(dev_info_t * dip,void * arg)693678453a8Sspeer vdds_match_niu_nexus(dev_info_t *dip, void *arg)
694678453a8Sspeer {
695678453a8Sspeer vdds_cb_arg_t *warg = (vdds_cb_arg_t *)arg;
696678453a8Sspeer vdds_reg_t *reg_p;
697678453a8Sspeer char *name;
698678453a8Sspeer uint64_t hdl;
699678453a8Sspeer uint_t reglen;
700678453a8Sspeer int rv;
701678453a8Sspeer
702678453a8Sspeer if (dip == ddi_root_node()) {
703678453a8Sspeer return (DDI_WALK_CONTINUE);
704678453a8Sspeer }
705678453a8Sspeer
706678453a8Sspeer name = ddi_node_name(dip);
707678453a8Sspeer if (strcmp(name, "niu") != 0) {
708678453a8Sspeer return (DDI_WALK_CONTINUE);
709678453a8Sspeer }
710678453a8Sspeer rv = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip,
711678453a8Sspeer DDI_PROP_DONTPASS, "reg", (int **)®_p, ®len);
712678453a8Sspeer if (rv != DDI_PROP_SUCCESS) {
713678453a8Sspeer DWARN(NULL, "Failed to get reg property dip=0x%p", dip);
714678453a8Sspeer return (DDI_WALK_CONTINUE);
715678453a8Sspeer }
716678453a8Sspeer
717678453a8Sspeer hdl = reg_p->addr_hi & 0x0FFFFFFF;
718678453a8Sspeer ddi_prop_free(reg_p);
719678453a8Sspeer
720678453a8Sspeer DBG2(NULL, "Handle = 0x%lx dip=0x%p", hdl, dip);
721678453a8Sspeer if (hdl == NIUCFGHDL(warg->cookie)) {
722678453a8Sspeer /* Hold before returning */
723d0288fccSRaghuram Kothakota if (!e_ddi_branch_held(dip))
724d0288fccSRaghuram Kothakota e_ddi_branch_hold(dip);
725678453a8Sspeer warg->dip = dip;
726678453a8Sspeer DBG2(NULL, "Found dip = 0x%p", dip);
727678453a8Sspeer return (DDI_WALK_TERMINATE);
728678453a8Sspeer }
729678453a8Sspeer return (DDI_WALK_CONTINUE);
730678453a8Sspeer }
731678453a8Sspeer
732678453a8Sspeer /*
733678453a8Sspeer * vdds_match_niu_node -- callback function to verify a node is the
734678453a8Sspeer * NIU Hybrid node.
735678453a8Sspeer */
736678453a8Sspeer static int
vdds_match_niu_node(dev_info_t * dip,void * arg)737678453a8Sspeer vdds_match_niu_node(dev_info_t *dip, void *arg)
738678453a8Sspeer {
739678453a8Sspeer vdds_cb_arg_t *warg = (vdds_cb_arg_t *)arg;
740678453a8Sspeer char *name;
741678453a8Sspeer vdds_reg_t *reg_p;
742678453a8Sspeer uint_t reglen;
743678453a8Sspeer int rv;
744678453a8Sspeer uint32_t addr_hi;
745678453a8Sspeer
746678453a8Sspeer name = ddi_node_name(dip);
747678453a8Sspeer if (strcmp(name, "network") != 0) {
748678453a8Sspeer return (DDI_WALK_CONTINUE);
749678453a8Sspeer }
750678453a8Sspeer rv = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip,
751678453a8Sspeer DDI_PROP_DONTPASS, "reg", (int **)®_p, ®len);
752678453a8Sspeer if (rv != DDI_PROP_SUCCESS) {
753678453a8Sspeer DWARN(NULL, "Failed to get reg property dip=0x%p", dip);
754678453a8Sspeer return (DDI_WALK_CONTINUE);
755678453a8Sspeer }
756678453a8Sspeer
757678453a8Sspeer addr_hi = reg_p->addr_hi;
758678453a8Sspeer DBG1(NULL, "addr_hi = 0x%x dip=0x%p", addr_hi, dip);
759678453a8Sspeer ddi_prop_free(reg_p);
760678453a8Sspeer if (addr_hi == HVCOOKIE(warg->cookie)) {
761678453a8Sspeer warg->dip = dip;
762d0288fccSRaghuram Kothakota if (!e_ddi_branch_held(dip))
763d0288fccSRaghuram Kothakota e_ddi_branch_hold(dip);
764678453a8Sspeer DBG1(NULL, "Found dip = 0x%p", dip);
765678453a8Sspeer return (DDI_WALK_TERMINATE);
766678453a8Sspeer }
767678453a8Sspeer return (DDI_WALK_CONTINUE);
768678453a8Sspeer }
769678453a8Sspeer
770678453a8Sspeer /*
771678453a8Sspeer * vdds_new_nexus_node -- callback function to set all the properties
772678453a8Sspeer * a new NIU nexus node.
773678453a8Sspeer */
774678453a8Sspeer static int
vdds_new_nexus_node(dev_info_t * dip,void * arg,uint_t flags)775678453a8Sspeer vdds_new_nexus_node(dev_info_t *dip, void *arg, uint_t flags)
776678453a8Sspeer {
777678453a8Sspeer vdds_cb_arg_t *cba = (vdds_cb_arg_t *)arg;
778678453a8Sspeer char *compat[] = { "SUNW,niumx" };
779678453a8Sspeer vdds_ranges_t *rangesp;
780678453a8Sspeer vdds_reg_t reg;
781678453a8Sspeer uint64_t nranges;
782678453a8Sspeer int n;
783678453a8Sspeer
784678453a8Sspeer DBG1(NULL, "Called dip=0x%p, flags=0x%X", dip, flags);
785678453a8Sspeer
786678453a8Sspeer /* create "niu" property */
787678453a8Sspeer if (ndi_prop_update_string(DDI_DEV_T_NONE, dip, "name", "niu") !=
788678453a8Sspeer DDI_SUCCESS) {
789678453a8Sspeer DERR(NULL, "Failed to create name property(dip=0x%p)", dip);
790678453a8Sspeer return (DDI_WALK_ERROR);
791678453a8Sspeer }
792678453a8Sspeer
793678453a8Sspeer /* create "compatible" property */
794678453a8Sspeer if (ndi_prop_update_string_array(DDI_DEV_T_NONE, dip, "compatible",
795678453a8Sspeer compat, 1) != DDI_SUCCESS) {
796678453a8Sspeer DERR(NULL, "Failed to create compatible property(dip=0x%p)",
797678453a8Sspeer dip);
798678453a8Sspeer return (DDI_WALK_ERROR);
799678453a8Sspeer }
800678453a8Sspeer
801678453a8Sspeer /* create "device_type" property */
802678453a8Sspeer if (ndi_prop_update_string(DDI_DEV_T_NONE, dip,
803678453a8Sspeer "device_type", "sun4v") != DDI_SUCCESS) {
804678453a8Sspeer DERR(NULL, "Failed to create device_type property(dip=0x%p)",
805678453a8Sspeer dip);
806678453a8Sspeer return (DDI_WALK_ERROR);
807678453a8Sspeer }
808678453a8Sspeer
809678453a8Sspeer /*
810678453a8Sspeer * create "reg" property. The first 28 bits of
811678453a8Sspeer * 'addr_hi' are NIU cfg_handle, the 0xc in 28-31 bits
812678453a8Sspeer * indicates non-cacheable config.
813678453a8Sspeer */
814678453a8Sspeer reg.addr_hi = 0xc0000000 | NIUCFGHDL(cba->cookie);
815678453a8Sspeer reg.addr_lo = 0;
816678453a8Sspeer reg.size_hi = 0;
817678453a8Sspeer reg.size_lo = 0;
818678453a8Sspeer if (ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
819678453a8Sspeer "reg", (int *)®, sizeof (reg)/sizeof (int)) != DDI_SUCCESS) {
820678453a8Sspeer DERR(NULL, "Failed to create reg property(dip=0x%p)", dip);
821678453a8Sspeer return (DDI_WALK_ERROR);
822678453a8Sspeer }
823678453a8Sspeer
824678453a8Sspeer /*
825678453a8Sspeer * Create VDDS_MAX_RANGES so that they are already in place
826678453a8Sspeer * before the children are created. While creating the child
827678453a8Sspeer * we just modify one of this ranges entries.
828678453a8Sspeer */
829678453a8Sspeer nranges = VDDS_MAX_RANGES; /* One range for each VR */
830678453a8Sspeer rangesp = (vdds_ranges_t *)kmem_zalloc(
831678453a8Sspeer (sizeof (vdds_ranges_t) * nranges), KM_SLEEP);
832678453a8Sspeer
833678453a8Sspeer for (n = 0; n < nranges; n++) {
834678453a8Sspeer /* zero all child_hi/lo */
835678453a8Sspeer rangesp[n].child_hi = 0;
836678453a8Sspeer rangesp[n].child_lo = 0;
837678453a8Sspeer }
838678453a8Sspeer
839678453a8Sspeer if (ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, "ranges",
840678453a8Sspeer (int *)rangesp, (nranges * 6)) != DDI_SUCCESS) {
841678453a8Sspeer DERR(NULL, "Failed to create ranges property(dip=0x%p)", dip);
842678453a8Sspeer kmem_free(rangesp, (sizeof (vdds_ranges_t) * nranges));
843678453a8Sspeer return (DDI_WALK_ERROR);
844678453a8Sspeer }
845678453a8Sspeer
846678453a8Sspeer /* create "#size-cells" property */
847678453a8Sspeer if (ndi_prop_update_int(DDI_DEV_T_NONE, dip,
848678453a8Sspeer "#size-cells", 2) != DDI_SUCCESS) {
849678453a8Sspeer DERR(NULL, "Failed to create #size-cells property(dip=0x%p)",
850678453a8Sspeer dip);
851678453a8Sspeer kmem_free(rangesp, (sizeof (vdds_ranges_t) * nranges));
852678453a8Sspeer return (DDI_WALK_ERROR);
853678453a8Sspeer }
854678453a8Sspeer
855678453a8Sspeer /* create "#address-cells" property */
856678453a8Sspeer if (ndi_prop_update_int(DDI_DEV_T_NONE, dip,
857678453a8Sspeer "#address-cells", 2) != DDI_SUCCESS) {
858678453a8Sspeer DERR(NULL, "Failed to create #address-cells prop(dip=0x%p)",
859678453a8Sspeer dip);
860678453a8Sspeer kmem_free(rangesp, (sizeof (vdds_ranges_t) * nranges));
861678453a8Sspeer return (DDI_WALK_ERROR);
862678453a8Sspeer }
863678453a8Sspeer
864678453a8Sspeer kmem_free(rangesp, (sizeof (vdds_ranges_t) * nranges));
865678453a8Sspeer cba->dip = dip;
866678453a8Sspeer DBG1(NULL, "Returning (dip=0x%p)", dip);
867678453a8Sspeer return (DDI_WALK_TERMINATE);
868678453a8Sspeer }
869678453a8Sspeer
870678453a8Sspeer /*
871678453a8Sspeer * vdds_new_niu_node -- callback function to create a new NIU Hybrid node.
872678453a8Sspeer */
873678453a8Sspeer static int
vdds_new_niu_node(dev_info_t * dip,void * arg,uint_t flags)874678453a8Sspeer vdds_new_niu_node(dev_info_t *dip, void *arg, uint_t flags)
875678453a8Sspeer {
876678453a8Sspeer vdds_cb_arg_t *cba = (vdds_cb_arg_t *)arg;
877678453a8Sspeer char *compat[] = { "SUNW,niusl" };
878678453a8Sspeer uint8_t macaddrbytes[ETHERADDRL];
879678453a8Sspeer int interrupts[VDDS_MAX_VRINTRS];
880678453a8Sspeer vdds_ranges_t *prng;
881678453a8Sspeer vdds_ranges_t *prp;
882678453a8Sspeer vdds_reg_t reg;
883678453a8Sspeer dev_info_t *pdip;
884678453a8Sspeer uint64_t start;
885678453a8Sspeer uint64_t size;
886678453a8Sspeer int prnglen;
887678453a8Sspeer int nintr = 0;
888678453a8Sspeer int nrng;
889678453a8Sspeer int rnum;
890678453a8Sspeer int rv;
891678453a8Sspeer
892678453a8Sspeer DBG1(NULL, "Called dip=0x%p flags=0x%X", dip, flags);
893678453a8Sspeer pdip = ddi_get_parent(dip);
894678453a8Sspeer
895678453a8Sspeer if (pdip == NULL) {
896678453a8Sspeer DWARN(NULL, "Failed to get parent dip(dip=0x%p)", dip);
897678453a8Sspeer return (DDI_WALK_ERROR);
898678453a8Sspeer }
899678453a8Sspeer
900678453a8Sspeer /* create "network" property */
901678453a8Sspeer if (ndi_prop_update_string(DDI_DEV_T_NONE, dip, "name", "network") !=
902678453a8Sspeer DDI_SUCCESS) {
903678453a8Sspeer DERR(NULL, "Failed to create name property(dip=0x%p)", dip);
904678453a8Sspeer return (DDI_WALK_ERROR);
905678453a8Sspeer }
906678453a8Sspeer
907678453a8Sspeer /*
908678453a8Sspeer * create "niutype" property, it is set to n2niu to
909678453a8Sspeer * indicate NIU Hybrid node.
910678453a8Sspeer */
911678453a8Sspeer if (ndi_prop_update_string(DDI_DEV_T_NONE, dip, "niutype",
912678453a8Sspeer "n2niu") != DDI_SUCCESS) {
913678453a8Sspeer DERR(NULL, "Failed to create niuopmode property(dip=0x%p)",
914678453a8Sspeer dip);
915678453a8Sspeer return (DDI_WALK_ERROR);
916678453a8Sspeer }
917678453a8Sspeer
918678453a8Sspeer /* create "compatible" property */
919678453a8Sspeer if (ndi_prop_update_string_array(DDI_DEV_T_NONE, dip, "compatible",
920678453a8Sspeer compat, 1) != DDI_SUCCESS) {
921678453a8Sspeer DERR(NULL, "Failed to create compatible property(dip=0x%p)",
922678453a8Sspeer dip);
923678453a8Sspeer return (DDI_WALK_ERROR);
924678453a8Sspeer }
925678453a8Sspeer
926678453a8Sspeer /* create "device_type" property */
927678453a8Sspeer if (ndi_prop_update_string(DDI_DEV_T_NONE, dip,
928678453a8Sspeer "device_type", "network") != DDI_SUCCESS) {
929678453a8Sspeer DERR(NULL, "Failed to create device_type property(dip=0x%p)",
930678453a8Sspeer dip);
931678453a8Sspeer return (DDI_WALK_ERROR);
932678453a8Sspeer }
933678453a8Sspeer
934678453a8Sspeer /* create "reg" property */
935678453a8Sspeer if (vdds_hv_niu_vr_getinfo(HVCOOKIE(cba->cookie),
936678453a8Sspeer &start, &size) != H_EOK) {
937678453a8Sspeer DERR(NULL, "Failed to get vrinfo for cookie(0x%lX)",
938678453a8Sspeer cba->cookie);
939678453a8Sspeer return (DDI_WALK_ERROR);
940678453a8Sspeer }
941678453a8Sspeer reg.addr_hi = HVCOOKIE(cba->cookie);
942678453a8Sspeer reg.addr_lo = 0;
943678453a8Sspeer reg.size_hi = 0;
944678453a8Sspeer reg.size_lo = size;
945678453a8Sspeer
946678453a8Sspeer if (ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, "reg",
947678453a8Sspeer (int *)®, sizeof (reg) / sizeof (int)) != DDI_SUCCESS) {
948678453a8Sspeer DERR(NULL, "Failed to create reg property(dip=0x%p)", dip);
949678453a8Sspeer return (DDI_WALK_ERROR);
950678453a8Sspeer }
951678453a8Sspeer
952678453a8Sspeer /*
953678453a8Sspeer * Modify the parent's ranges property to map the "reg" property
954678453a8Sspeer * of the new child.
955678453a8Sspeer */
956678453a8Sspeer if ((rv = ddi_getlongprop(DDI_DEV_T_ANY, pdip, DDI_PROP_DONTPASS,
957678453a8Sspeer "ranges", (caddr_t)&prng, &prnglen)) != DDI_SUCCESS) {
958678453a8Sspeer DERR(NULL,
959678453a8Sspeer "Failed to get parent's ranges property(pdip=0x%p) rv=%d",
960678453a8Sspeer pdip, rv);
961678453a8Sspeer return (DDI_WALK_ERROR);
962678453a8Sspeer }
963678453a8Sspeer nrng = prnglen/(sizeof (vdds_ranges_t));
964678453a8Sspeer /*
965678453a8Sspeer * First scan all ranges to see if a range corresponding
966678453a8Sspeer * to this virtual NIU exists already.
967678453a8Sspeer */
968678453a8Sspeer for (rnum = 0; rnum < nrng; rnum++) {
969678453a8Sspeer prp = &prng[rnum];
970678453a8Sspeer if (prp->child_hi == HVCOOKIE(cba->cookie)) {
971678453a8Sspeer break;
972678453a8Sspeer }
973678453a8Sspeer }
974678453a8Sspeer if (rnum == nrng) {
975678453a8Sspeer /* Now to try to find an empty range */
976678453a8Sspeer for (rnum = 0; rnum < nrng; rnum++) {
977678453a8Sspeer prp = &prng[rnum];
978678453a8Sspeer if (prp->child_hi == 0) {
979678453a8Sspeer break;
980678453a8Sspeer }
981678453a8Sspeer }
982678453a8Sspeer }
983678453a8Sspeer if (rnum == nrng) {
984678453a8Sspeer DERR(NULL, "No free ranges entry found");
985678453a8Sspeer return (DDI_WALK_ERROR);
986678453a8Sspeer }
987678453a8Sspeer
988678453a8Sspeer /*
989678453a8Sspeer * child_hi will have HV cookie as HV cookie is more like
990678453a8Sspeer * a port in the HybridIO.
991678453a8Sspeer */
992678453a8Sspeer prp->child_hi = HVCOOKIE(cba->cookie);
993678453a8Sspeer prp->child_lo = 0;
994678453a8Sspeer prp->parent_hi = 0x80000000 | (start >> 32);
995678453a8Sspeer prp->parent_lo = start & 0x00000000FFFFFFFF;
996678453a8Sspeer prp->size_hi = (size >> 32);
997678453a8Sspeer prp->size_lo = size & 0x00000000FFFFFFFF;
998678453a8Sspeer
999678453a8Sspeer if (ndi_prop_update_int_array(DDI_DEV_T_NONE, pdip, "ranges",
1000678453a8Sspeer (int *)prng, (nrng * 6)) != DDI_SUCCESS) {
1001678453a8Sspeer DERR(NULL, "Failed to update parent ranges prop(pdip=0x%p)",
1002678453a8Sspeer pdip);
1003678453a8Sspeer return (DDI_WALK_ERROR);
1004678453a8Sspeer }
1005678453a8Sspeer kmem_free((void *)prng, prnglen);
1006678453a8Sspeer
1007678453a8Sspeer vnet_macaddr_ultostr(cba->macaddr, macaddrbytes);
1008678453a8Sspeer
1009678453a8Sspeer /*
1010678453a8Sspeer * create "local-mac-address" property, this will be same as
1011678453a8Sspeer * the vnet's mac-address.
1012678453a8Sspeer */
1013678453a8Sspeer if (ndi_prop_update_byte_array(DDI_DEV_T_NONE, dip, "local-mac-address",
1014678453a8Sspeer macaddrbytes, ETHERADDRL) != DDI_SUCCESS) {
1015678453a8Sspeer DERR(NULL, "Failed to update mac-addresses property(dip=0x%p)",
1016678453a8Sspeer dip);
1017678453a8Sspeer return (DDI_WALK_ERROR);
1018678453a8Sspeer }
1019678453a8Sspeer
1020678453a8Sspeer rv = vdds_get_interrupts(cba->cookie, rnum, interrupts, &nintr);
1021678453a8Sspeer if (rv != 0) {
1022678453a8Sspeer DERR(NULL, "Failed to get interrupts for cookie=0x%lx",
1023678453a8Sspeer cba->cookie);
1024678453a8Sspeer return (DDI_WALK_ERROR);
1025678453a8Sspeer }
1026678453a8Sspeer
1027678453a8Sspeer /* create "interrupts" property */
1028678453a8Sspeer if (ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, "interrupts",
1029678453a8Sspeer interrupts, nintr) != DDI_SUCCESS) {
1030678453a8Sspeer DERR(NULL, "Failed to update interrupts property(dip=0x%p)",
1031678453a8Sspeer dip);
1032678453a8Sspeer return (DDI_WALK_ERROR);
1033678453a8Sspeer }
1034678453a8Sspeer
1035678453a8Sspeer
10367b1f684aSSriharsha Basavapatna /* create "max_frame_size" property */
10377b1f684aSSriharsha Basavapatna if (ndi_prop_update_int(DDI_DEV_T_NONE, dip, "max-frame-size",
10387b1f684aSSriharsha Basavapatna cba->max_frame_size) != DDI_SUCCESS) {
10397b1f684aSSriharsha Basavapatna DERR(NULL, "Failed to update max-frame-size property(dip=0x%p)",
10407b1f684aSSriharsha Basavapatna dip);
10417b1f684aSSriharsha Basavapatna return (DDI_WALK_ERROR);
10427b1f684aSSriharsha Basavapatna }
10437b1f684aSSriharsha Basavapatna
1044678453a8Sspeer cba->dip = dip;
1045678453a8Sspeer DBG1(NULL, "Returning dip=0x%p", dip);
1046678453a8Sspeer return (DDI_WALK_TERMINATE);
1047678453a8Sspeer }
1048678453a8Sspeer
1049678453a8Sspeer
1050678453a8Sspeer /*
1051678453a8Sspeer * vdds_find_node -- A common function to find a NIU nexus or NIU node.
1052678453a8Sspeer */
1053678453a8Sspeer static dev_info_t *
vdds_find_node(uint64_t cookie,dev_info_t * sdip,int (* match_func)(dev_info_t * dip,void * arg))1054678453a8Sspeer vdds_find_node(uint64_t cookie, dev_info_t *sdip,
1055678453a8Sspeer int (*match_func)(dev_info_t *dip, void *arg))
1056678453a8Sspeer {
1057678453a8Sspeer vdds_cb_arg_t arg;
1058678453a8Sspeer dev_info_t *pdip;
1059678453a8Sspeer
1060678453a8Sspeer DBG1(NULL, "Called cookie=%lx\n", cookie);
1061678453a8Sspeer
1062678453a8Sspeer arg.dip = NULL;
1063678453a8Sspeer arg.cookie = cookie;
1064678453a8Sspeer
1065678453a8Sspeer if (pdip = ddi_get_parent(sdip)) {
1066*3fe80ca4SDan Cross ndi_devi_enter(pdip);
1067678453a8Sspeer }
1068678453a8Sspeer
1069678453a8Sspeer ddi_walk_devs(sdip, match_func, (void *)&arg);
1070678453a8Sspeer if (pdip != NULL) {
1071*3fe80ca4SDan Cross ndi_devi_exit(pdip);
1072678453a8Sspeer }
1073678453a8Sspeer
1074678453a8Sspeer DBG1(NULL, "Returning dip=0x%p", arg.dip);
1075678453a8Sspeer return (arg.dip);
1076678453a8Sspeer }
1077678453a8Sspeer
1078678453a8Sspeer /*
1079678453a8Sspeer * vdds_create_new_node -- A common function to create NIU nexus/NIU node.
1080678453a8Sspeer */
1081678453a8Sspeer static dev_info_t *
vdds_create_new_node(vdds_cb_arg_t * cbap,dev_info_t * pdip,int (* new_node_func)(dev_info_t * dip,void * arg,uint_t flags))10827b1f684aSSriharsha Basavapatna vdds_create_new_node(vdds_cb_arg_t *cbap, dev_info_t *pdip,
1083678453a8Sspeer int (*new_node_func)(dev_info_t *dip, void *arg, uint_t flags))
1084678453a8Sspeer {
1085678453a8Sspeer devi_branch_t br;
1086d0288fccSRaghuram Kothakota int rv;
1087678453a8Sspeer
10887b1f684aSSriharsha Basavapatna DBG1(NULL, "Called cookie=0x%lx", cbap->cookie);
1089678453a8Sspeer
10907b1f684aSSriharsha Basavapatna br.arg = (void *)cbap;
1091678453a8Sspeer br.type = DEVI_BRANCH_SID;
1092678453a8Sspeer br.create.sid_branch_create = new_node_func;
1093678453a8Sspeer br.devi_branch_callback = NULL;
1094678453a8Sspeer
1095d0288fccSRaghuram Kothakota if (pdip == NULL) {
1096678453a8Sspeer pdip = ddi_root_node();
1097d0288fccSRaghuram Kothakota }
1098678453a8Sspeer DBG1(NULL, "calling e_ddi_branch_create");
1099678453a8Sspeer if ((rv = e_ddi_branch_create(pdip, &br, NULL,
1100678453a8Sspeer DEVI_BRANCH_CHILD | DEVI_BRANCH_CONFIGURE))) {
1101678453a8Sspeer DERR(NULL, "e_ddi_branch_create failed=%d", rv);
1102678453a8Sspeer return (NULL);
1103678453a8Sspeer }
11047b1f684aSSriharsha Basavapatna DBG1(NULL, "Returning(dip=0x%p", cbap->dip);
11057b1f684aSSriharsha Basavapatna return (cbap->dip);
1106678453a8Sspeer }
1107678453a8Sspeer
1108678453a8Sspeer /*
1109678453a8Sspeer * vdds_get_interrupts -- A function that binds ino's to channels and
1110678453a8Sspeer * then provides them to create interrupts property.
1111678453a8Sspeer */
1112678453a8Sspeer static int
vdds_get_interrupts(uint64_t cookie,int ino_range,int * intrs,int * nintr)1113678453a8Sspeer vdds_get_interrupts(uint64_t cookie, int ino_range, int *intrs, int *nintr)
1114678453a8Sspeer {
1115678453a8Sspeer uint32_t hvcookie = HVCOOKIE(cookie);
1116678453a8Sspeer uint64_t txmap;
1117678453a8Sspeer uint64_t rxmap;
1118678453a8Sspeer uint32_t ino = VDDS_INO_RANGE_START(ino_range);
1119678453a8Sspeer int rv;
1120678453a8Sspeer uint64_t i;
1121678453a8Sspeer
1122678453a8Sspeer *nintr = 0;
1123678453a8Sspeer rv = vdds_hv_niu_vr_get_txmap(hvcookie, &txmap);
1124678453a8Sspeer if (rv != H_EOK) {
1125678453a8Sspeer DWARN(NULL, "Failed to get txmap for hvcookie=0x%X rv=%d\n",
1126678453a8Sspeer hvcookie, rv);
1127678453a8Sspeer return (EIO);
1128678453a8Sspeer }
1129678453a8Sspeer rv = vdds_hv_niu_vr_get_rxmap(hvcookie, &rxmap);
1130678453a8Sspeer if (rv != H_EOK) {
1131678453a8Sspeer DWARN(NULL, "Failed to get rxmap for hvcookie=0x%X, rv=%d\n",
1132678453a8Sspeer hvcookie, rv);
1133678453a8Sspeer return (EIO);
1134678453a8Sspeer }
1135678453a8Sspeer /* Check if the number of total channels to be more than 8 */
1136678453a8Sspeer for (i = 0; i < 4; i++) {
1137678453a8Sspeer if (rxmap & (((uint64_t)0x1) << i)) {
1138678453a8Sspeer rv = vdds_hv_niu_vrrx_set_ino(hvcookie, i, ino);
1139678453a8Sspeer if (rv != H_EOK) {
1140678453a8Sspeer DWARN(NULL, "Failed to get Rx ino for "
1141678453a8Sspeer "hvcookie=0x%X vch_idx=0x%lx rv=%d\n",
1142678453a8Sspeer hvcookie, i, rv);
1143678453a8Sspeer return (EIO);
1144678453a8Sspeer }
1145678453a8Sspeer DWARN(NULL,
1146678453a8Sspeer "hvcookie=0x%X RX vch_idx=0x%lx ino=0x%X\n",
1147678453a8Sspeer hvcookie, i, ino);
1148678453a8Sspeer *intrs = ino;
1149678453a8Sspeer ino++;
1150678453a8Sspeer } else {
1151678453a8Sspeer *intrs = VDDS_MAX_INTR_NUM;
1152678453a8Sspeer }
1153678453a8Sspeer intrs++;
1154678453a8Sspeer *nintr += 1;
1155678453a8Sspeer }
1156678453a8Sspeer for (i = 0; i < 4; i++) {
1157678453a8Sspeer if (txmap & (((uint64_t)0x1) << i)) {
1158678453a8Sspeer rv = vdds_hv_niu_vrtx_set_ino(hvcookie, i, ino);
1159678453a8Sspeer if (rv != H_EOK) {
1160678453a8Sspeer DWARN(NULL, "Failed to get Tx ino for "
1161678453a8Sspeer "hvcookie=0x%X vch_idx=0x%lx rv=%d\n",
1162678453a8Sspeer hvcookie, i, rv);
1163678453a8Sspeer return (EIO);
1164678453a8Sspeer }
1165678453a8Sspeer DWARN(NULL, "hvcookie=0x%X TX vch_idx=0x%lx ino=0x%X\n",
1166678453a8Sspeer hvcookie, i, ino);
1167678453a8Sspeer *intrs = ino;
1168678453a8Sspeer ino++;
1169678453a8Sspeer } else {
1170678453a8Sspeer *intrs = VDDS_MAX_INTR_NUM;
1171678453a8Sspeer }
1172678453a8Sspeer intrs++;
1173678453a8Sspeer *nintr += 1;
1174678453a8Sspeer }
1175678453a8Sspeer return (0);
1176678453a8Sspeer }
1177678453a8Sspeer
1178678453a8Sspeer /*
1179678453a8Sspeer * vdds_release_range_prop -- cleanups an entry in the ranges property
1180678453a8Sspeer * corresponding to a cookie.
1181678453a8Sspeer */
1182678453a8Sspeer static void
vdds_release_range_prop(dev_info_t * nexus_dip,uint64_t cookie)1183678453a8Sspeer vdds_release_range_prop(dev_info_t *nexus_dip, uint64_t cookie)
1184678453a8Sspeer {
1185678453a8Sspeer vdds_ranges_t *prng;
1186678453a8Sspeer vdds_ranges_t *prp;
1187678453a8Sspeer int prnglen;
1188678453a8Sspeer int nrng;
1189678453a8Sspeer int rnum;
1190678453a8Sspeer boolean_t success = B_FALSE;
1191678453a8Sspeer int rv;
1192678453a8Sspeer
1193678453a8Sspeer if ((rv = ddi_getlongprop(DDI_DEV_T_ANY, nexus_dip, DDI_PROP_DONTPASS,
1194678453a8Sspeer "ranges", (caddr_t)&prng, &prnglen)) != DDI_SUCCESS) {
1195678453a8Sspeer DERR(NULL,
1196678453a8Sspeer "Failed to get nexus ranges property(dip=0x%p) rv=%d",
1197678453a8Sspeer nexus_dip, rv);
1198678453a8Sspeer return;
1199678453a8Sspeer }
1200678453a8Sspeer nrng = prnglen/(sizeof (vdds_ranges_t));
1201678453a8Sspeer for (rnum = 0; rnum < nrng; rnum++) {
1202678453a8Sspeer prp = &prng[rnum];
1203678453a8Sspeer if (prp->child_hi == HVCOOKIE(cookie)) {
1204678453a8Sspeer prp->child_hi = 0;
1205678453a8Sspeer success = B_TRUE;
1206678453a8Sspeer break;
1207678453a8Sspeer }
1208678453a8Sspeer }
1209678453a8Sspeer if (success) {
1210678453a8Sspeer if (ndi_prop_update_int_array(DDI_DEV_T_NONE, nexus_dip,
1211678453a8Sspeer "ranges", (int *)prng, (nrng * 6)) != DDI_SUCCESS) {
1212678453a8Sspeer DERR(NULL,
1213678453a8Sspeer "Failed to update nexus ranges prop(dip=0x%p)",
1214678453a8Sspeer nexus_dip);
1215678453a8Sspeer }
1216678453a8Sspeer }
1217678453a8Sspeer }
1218