xref: /titanic_53/usr/src/uts/sun4v/io/vnet.c (revision 9f26b864f51e1fcd02cc7c4f6f34034d7c80df85)
11ae08745Sheppo /*
21ae08745Sheppo  * CDDL HEADER START
31ae08745Sheppo  *
41ae08745Sheppo  * The contents of this file are subject to the terms of the
51ae08745Sheppo  * Common Development and Distribution License (the "License").
61ae08745Sheppo  * You may not use this file except in compliance with the License.
71ae08745Sheppo  *
81ae08745Sheppo  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91ae08745Sheppo  * or http://www.opensolaris.org/os/licensing.
101ae08745Sheppo  * See the License for the specific language governing permissions
111ae08745Sheppo  * and limitations under the License.
121ae08745Sheppo  *
131ae08745Sheppo  * When distributing Covered Code, include this CDDL HEADER in each
141ae08745Sheppo  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151ae08745Sheppo  * If applicable, add the following below this CDDL HEADER, with the
161ae08745Sheppo  * fields enclosed by brackets "[]" replaced with your own identifying
171ae08745Sheppo  * information: Portions Copyright [yyyy] [name of copyright owner]
181ae08745Sheppo  *
191ae08745Sheppo  * CDDL HEADER END
201ae08745Sheppo  */
211ae08745Sheppo 
221ae08745Sheppo /*
230c4606f0SWENTAO YANG  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
241ae08745Sheppo  * Use is subject to license terms.
251ae08745Sheppo  */
261ae08745Sheppo 
271ae08745Sheppo #include <sys/types.h>
281ae08745Sheppo #include <sys/errno.h>
291ae08745Sheppo #include <sys/param.h>
300dc2366fSVenugopal Iyer #include <sys/callb.h>
311ae08745Sheppo #include <sys/stream.h>
321ae08745Sheppo #include <sys/kmem.h>
331ae08745Sheppo #include <sys/conf.h>
341ae08745Sheppo #include <sys/devops.h>
351ae08745Sheppo #include <sys/ksynch.h>
361ae08745Sheppo #include <sys/stat.h>
371ae08745Sheppo #include <sys/modctl.h>
38c1c61f44Ssb155480 #include <sys/modhash.h>
391ae08745Sheppo #include <sys/debug.h>
401ae08745Sheppo #include <sys/ethernet.h>
411ae08745Sheppo #include <sys/dlpi.h>
421ae08745Sheppo #include <net/if.h>
43da14cebeSEric Cheng #include <sys/mac_provider.h>
4463f531d1SSriharsha Basavapatna #include <sys/mac_client.h>
4563f531d1SSriharsha Basavapatna #include <sys/mac_client_priv.h>
46ba2e4443Sseb #include <sys/mac_ether.h>
471ae08745Sheppo #include <sys/ddi.h>
481ae08745Sheppo #include <sys/sunddi.h>
491ae08745Sheppo #include <sys/strsun.h>
501ae08745Sheppo #include <sys/note.h>
51c1c61f44Ssb155480 #include <sys/atomic.h>
521ae08745Sheppo #include <sys/vnet.h>
53c1c61f44Ssb155480 #include <sys/vlan.h>
54678453a8Sspeer #include <sys/vnet_mailbox.h>
55678453a8Sspeer #include <sys/vnet_common.h>
56678453a8Sspeer #include <sys/dds.h>
57678453a8Sspeer #include <sys/strsubr.h>
58678453a8Sspeer #include <sys/taskq.h>
591ae08745Sheppo 
601ae08745Sheppo /*
611ae08745Sheppo  * Function prototypes.
621ae08745Sheppo  */
631ae08745Sheppo 
641ae08745Sheppo /* DDI entrypoints */
651ae08745Sheppo static int vnetdevinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
661ae08745Sheppo static int vnetattach(dev_info_t *, ddi_attach_cmd_t);
671ae08745Sheppo static int vnetdetach(dev_info_t *, ddi_detach_cmd_t);
681ae08745Sheppo 
691ae08745Sheppo /* MAC entrypoints  */
70ba2e4443Sseb static int vnet_m_stat(void *, uint_t, uint64_t *);
711ae08745Sheppo static int vnet_m_start(void *);
721ae08745Sheppo static void vnet_m_stop(void *);
731ae08745Sheppo static int vnet_m_promisc(void *, boolean_t);
741ae08745Sheppo static int vnet_m_multicst(void *, boolean_t, const uint8_t *);
751ae08745Sheppo static int vnet_m_unicst(void *, const uint8_t *);
761ae08745Sheppo mblk_t *vnet_m_tx(void *, mblk_t *);
771107ea93SSriharsha Basavapatna static void vnet_m_ioctl(void *arg, queue_t *q, mblk_t *mp);
781107ea93SSriharsha Basavapatna #ifdef	VNET_IOC_DEBUG
791107ea93SSriharsha Basavapatna static void vnet_force_link_state(vnet_t *vnetp, queue_t *q, mblk_t *mp);
801107ea93SSriharsha Basavapatna #endif
8163f531d1SSriharsha Basavapatna static boolean_t vnet_m_capab(void *arg, mac_capab_t cap, void *cap_data);
8263f531d1SSriharsha Basavapatna static void vnet_get_ring(void *arg, mac_ring_type_t rtype, const int g_index,
8363f531d1SSriharsha Basavapatna 	const int r_index, mac_ring_info_t *infop, mac_ring_handle_t r_handle);
8463f531d1SSriharsha Basavapatna static void vnet_get_group(void *arg, mac_ring_type_t type, const int index,
8563f531d1SSriharsha Basavapatna 	mac_group_info_t *infop, mac_group_handle_t handle);
8663f531d1SSriharsha Basavapatna static int vnet_rx_ring_start(mac_ring_driver_t rdriver, uint64_t mr_gen_num);
8763f531d1SSriharsha Basavapatna static void vnet_rx_ring_stop(mac_ring_driver_t rdriver);
880dc2366fSVenugopal Iyer static int vnet_rx_ring_stat(mac_ring_driver_t rdriver, uint_t stat,
890dc2366fSVenugopal Iyer 	uint64_t *val);
9063f531d1SSriharsha Basavapatna static int vnet_tx_ring_start(mac_ring_driver_t rdriver, uint64_t mr_gen_num);
9163f531d1SSriharsha Basavapatna static void vnet_tx_ring_stop(mac_ring_driver_t rdriver);
920dc2366fSVenugopal Iyer static int vnet_tx_ring_stat(mac_ring_driver_t rdriver, uint_t stat,
930dc2366fSVenugopal Iyer 	uint64_t *val);
9463f531d1SSriharsha Basavapatna static int vnet_ring_enable_intr(void *arg);
9563f531d1SSriharsha Basavapatna static int vnet_ring_disable_intr(void *arg);
9663f531d1SSriharsha Basavapatna static mblk_t *vnet_rx_poll(void *arg, int bytes_to_pickup);
9763f531d1SSriharsha Basavapatna static int vnet_addmac(void *arg, const uint8_t *mac_addr);
9863f531d1SSriharsha Basavapatna static int vnet_remmac(void *arg, const uint8_t *mac_addr);
991ae08745Sheppo 
1001ae08745Sheppo /* vnet internal functions */
1016f09f0feSWENTAO YANG static int vnet_unattach(vnet_t *vnetp);
10263f531d1SSriharsha Basavapatna static void vnet_ring_grp_init(vnet_t *vnetp);
10363f531d1SSriharsha Basavapatna static void vnet_ring_grp_uninit(vnet_t *vnetp);
1041ae08745Sheppo static int vnet_mac_register(vnet_t *);
1051ae08745Sheppo static int vnet_read_mac_address(vnet_t *vnetp);
10663f531d1SSriharsha Basavapatna static int vnet_bind_vgenring(vnet_res_t *vresp);
10763f531d1SSriharsha Basavapatna static void vnet_unbind_vgenring(vnet_res_t *vresp);
10863f531d1SSriharsha Basavapatna static int vnet_bind_hwrings(vnet_t *vnetp);
10963f531d1SSriharsha Basavapatna static void vnet_unbind_hwrings(vnet_t *vnetp);
11063f531d1SSriharsha Basavapatna static int vnet_bind_rings(vnet_res_t *vresp);
11163f531d1SSriharsha Basavapatna static void vnet_unbind_rings(vnet_res_t *vresp);
11263f531d1SSriharsha Basavapatna static int vnet_hio_stat(void *, uint_t, uint64_t *);
11363f531d1SSriharsha Basavapatna static int vnet_hio_start(void *);
11463f531d1SSriharsha Basavapatna static void vnet_hio_stop(void *);
11563f531d1SSriharsha Basavapatna mblk_t *vnet_hio_tx(void *, mblk_t *);
1161ae08745Sheppo 
117c1c61f44Ssb155480 /* Forwarding database (FDB) routines */
118c1c61f44Ssb155480 static void vnet_fdb_create(vnet_t *vnetp);
119c1c61f44Ssb155480 static void vnet_fdb_destroy(vnet_t *vnetp);
120678453a8Sspeer static vnet_res_t *vnet_fdbe_find(vnet_t *vnetp, struct ether_addr *addrp);
121c1c61f44Ssb155480 static void vnet_fdbe_find_cb(mod_hash_key_t key, mod_hash_val_t val);
122678453a8Sspeer void vnet_fdbe_add(vnet_t *vnetp, vnet_res_t *vresp);
123678453a8Sspeer static void vnet_fdbe_del(vnet_t *vnetp, vnet_res_t *vresp);
124c1c61f44Ssb155480 
1258c242ab0SSriharsha Basavapatna static void vnet_rx_frames_untag(uint16_t pvid, mblk_t **mp);
126678453a8Sspeer static void vnet_rx(vio_net_handle_t vrh, mblk_t *mp);
127678453a8Sspeer static void vnet_tx_update(vio_net_handle_t vrh);
128678453a8Sspeer static void vnet_res_start_task(void *arg);
129678453a8Sspeer static void vnet_start_resources(vnet_t *vnetp);
130678453a8Sspeer static void vnet_stop_resources(vnet_t *vnetp);
131678453a8Sspeer static void vnet_dispatch_res_task(vnet_t *vnetp);
132678453a8Sspeer static void vnet_res_start_task(void *arg);
133678453a8Sspeer static void vnet_handle_res_err(vio_net_handle_t vrh, vio_net_err_val_t err);
13463f531d1SSriharsha Basavapatna static void vnet_add_resource(vnet_t *vnetp, vnet_res_t *vresp);
13563f531d1SSriharsha Basavapatna static vnet_res_t *vnet_rem_resource(vnet_t *vnetp, vnet_res_t *vresp);
1360dc2366fSVenugopal Iyer static void vnet_tx_notify_thread(void *);
1371107ea93SSriharsha Basavapatna 
1381107ea93SSriharsha Basavapatna /* Exported to vnet_gen */
1397b1f684aSSriharsha Basavapatna int vnet_mtu_update(vnet_t *vnetp, uint32_t mtu);
1401107ea93SSriharsha Basavapatna void vnet_link_update(vnet_t *vnetp, link_state_t link_state);
1416d6de4eeSWENTAO YANG void vnet_dds_cleanup_hio(vnet_t *vnetp);
142678453a8Sspeer 
1436ab6cb20SWENTAO YANG static kstat_t *vnet_hio_setup_kstats(char *ks_mod, char *ks_name,
1446ab6cb20SWENTAO YANG     vnet_res_t *vresp);
1456ab6cb20SWENTAO YANG static int vnet_hio_update_kstats(kstat_t *ksp, int rw);
1466ab6cb20SWENTAO YANG static void vnet_hio_get_stats(vnet_res_t *vresp, vnet_hio_stats_t *statsp);
1476ab6cb20SWENTAO YANG static void vnet_hio_destroy_kstats(kstat_t *ksp);
1486ab6cb20SWENTAO YANG 
149678453a8Sspeer /* Exported to to vnet_dds */
150678453a8Sspeer int vnet_send_dds_msg(vnet_t *vnetp, void *dmsg);
15163f531d1SSriharsha Basavapatna int vnet_hio_mac_init(vnet_t *vnetp, char *ifname);
15263f531d1SSriharsha Basavapatna void vnet_hio_mac_cleanup(vnet_t *vnetp);
153678453a8Sspeer 
154678453a8Sspeer /* Externs that are imported from vnet_gen */
155678453a8Sspeer extern int vgen_init(void *vnetp, uint64_t regprop, dev_info_t *vnetdip,
156678453a8Sspeer     const uint8_t *macaddr, void **vgenhdl);
15763f531d1SSriharsha Basavapatna extern int vgen_init_mdeg(void *arg);
1583ab636deSWENTAO YANG extern void vgen_uninit(void *arg);
159678453a8Sspeer extern int vgen_dds_tx(void *arg, void *dmsg);
1606f09f0feSWENTAO YANG extern void vgen_mod_init(void);
1616f09f0feSWENTAO YANG extern int vgen_mod_cleanup(void);
1626f09f0feSWENTAO YANG extern void vgen_mod_fini(void);
16363f531d1SSriharsha Basavapatna extern int vgen_enable_intr(void *arg);
16463f531d1SSriharsha Basavapatna extern int vgen_disable_intr(void *arg);
16563f531d1SSriharsha Basavapatna extern mblk_t *vgen_poll(void *arg, int bytes_to_pickup);
166678453a8Sspeer 
167678453a8Sspeer /* Externs that are imported from vnet_dds */
168678453a8Sspeer extern void vdds_mod_init(void);
169678453a8Sspeer extern void vdds_mod_fini(void);
170678453a8Sspeer extern int vdds_init(vnet_t *vnetp);
171678453a8Sspeer extern void vdds_cleanup(vnet_t *vnetp);
172678453a8Sspeer extern void vdds_process_dds_msg(vnet_t *vnetp, vio_dds_msg_t *dmsg);
173d0288fccSRaghuram Kothakota extern void vdds_cleanup_hybrid_res(void *arg);
1746d6de4eeSWENTAO YANG extern void vdds_cleanup_hio(vnet_t *vnetp);
1751ae08745Sheppo 
1760dc2366fSVenugopal Iyer extern pri_t	minclsyspri;
17763f531d1SSriharsha Basavapatna 
1786ab6cb20SWENTAO YANG #define	DRV_NAME	"vnet"
179c1c61f44Ssb155480 #define	VNET_FDBE_REFHOLD(p)						\
180c1c61f44Ssb155480 {									\
181c1c61f44Ssb155480 	atomic_inc_32(&(p)->refcnt);					\
182c1c61f44Ssb155480 	ASSERT((p)->refcnt != 0);					\
183c1c61f44Ssb155480 }
184c1c61f44Ssb155480 
185c1c61f44Ssb155480 #define	VNET_FDBE_REFRELE(p)						\
186c1c61f44Ssb155480 {									\
187c1c61f44Ssb155480 	ASSERT((p)->refcnt != 0);					\
188c1c61f44Ssb155480 	atomic_dec_32(&(p)->refcnt);					\
189c1c61f44Ssb155480 }
190c1c61f44Ssb155480 
1911107ea93SSriharsha Basavapatna #ifdef	VNET_IOC_DEBUG
19263f531d1SSriharsha Basavapatna #define	VNET_M_CALLBACK_FLAGS	(MC_IOCTL | MC_GETCAPAB)
1931107ea93SSriharsha Basavapatna #else
19463f531d1SSriharsha Basavapatna #define	VNET_M_CALLBACK_FLAGS	(MC_GETCAPAB)
1951107ea93SSriharsha Basavapatna #endif
1961107ea93SSriharsha Basavapatna 
197ba2e4443Sseb static mac_callbacks_t vnet_m_callbacks = {
1981107ea93SSriharsha Basavapatna 	VNET_M_CALLBACK_FLAGS,
199ba2e4443Sseb 	vnet_m_stat,
200ba2e4443Sseb 	vnet_m_start,
201ba2e4443Sseb 	vnet_m_stop,
202ba2e4443Sseb 	vnet_m_promisc,
203ba2e4443Sseb 	vnet_m_multicst,
20463f531d1SSriharsha Basavapatna 	NULL,	/* m_unicst entry must be NULL while rx rings are exposed */
20563f531d1SSriharsha Basavapatna 	NULL,	/* m_tx entry must be NULL while tx rings are exposed */
2060dc2366fSVenugopal Iyer 	NULL,
2071107ea93SSriharsha Basavapatna 	vnet_m_ioctl,
20863f531d1SSriharsha Basavapatna 	vnet_m_capab,
20963f531d1SSriharsha Basavapatna 	NULL
21063f531d1SSriharsha Basavapatna };
21163f531d1SSriharsha Basavapatna 
21263f531d1SSriharsha Basavapatna static mac_callbacks_t vnet_hio_res_callbacks = {
21363f531d1SSriharsha Basavapatna 	0,
21463f531d1SSriharsha Basavapatna 	vnet_hio_stat,
21563f531d1SSriharsha Basavapatna 	vnet_hio_start,
21663f531d1SSriharsha Basavapatna 	vnet_hio_stop,
21763f531d1SSriharsha Basavapatna 	NULL,
21863f531d1SSriharsha Basavapatna 	NULL,
21963f531d1SSriharsha Basavapatna 	NULL,
22063f531d1SSriharsha Basavapatna 	vnet_hio_tx,
22163f531d1SSriharsha Basavapatna 	NULL,
222ba2e4443Sseb 	NULL,
223ba2e4443Sseb 	NULL
224ba2e4443Sseb };
225ba2e4443Sseb 
2261ae08745Sheppo /*
2271ae08745Sheppo  * Linked list of "vnet_t" structures - one per instance.
2281ae08745Sheppo  */
2291ae08745Sheppo static vnet_t	*vnet_headp = NULL;
2301ae08745Sheppo static krwlock_t vnet_rw;
2311ae08745Sheppo 
2321ae08745Sheppo /* Tunables */
2331ae08745Sheppo uint32_t vnet_ntxds = VNET_NTXDS;	/* power of 2 transmit descriptors */
2341ae08745Sheppo uint32_t vnet_ldcwd_interval = VNET_LDCWD_INTERVAL; /* watchdog freq in msec */
2351ae08745Sheppo uint32_t vnet_ldcwd_txtimeout = VNET_LDCWD_TXTIMEOUT;  /* tx timeout in msec */
236e1ebb9ecSlm66018 uint32_t vnet_ldc_mtu = VNET_LDC_MTU;		/* ldc mtu */
237c1c61f44Ssb155480 
23863f531d1SSriharsha Basavapatna /* Configure tx serialization in mac layer for the vnet device */
23963f531d1SSriharsha Basavapatna boolean_t vnet_mac_tx_serialize = B_TRUE;
2400dc2366fSVenugopal Iyer /* Configure enqueing at Rx soft rings in mac layer for the vnet device */
2410dc2366fSVenugopal Iyer boolean_t vnet_mac_rx_queuing = B_TRUE;
24263f531d1SSriharsha Basavapatna 
2437b1f684aSSriharsha Basavapatna /*
2447b1f684aSSriharsha Basavapatna  * Set this to non-zero to enable additional internal receive buffer pools
2457b1f684aSSriharsha Basavapatna  * based on the MTU of the device for better performance at the cost of more
2467b1f684aSSriharsha Basavapatna  * memory consumption. This is turned off by default, to use allocb(9F) for
2477b1f684aSSriharsha Basavapatna  * receive buffer allocations of sizes > 2K.
2487b1f684aSSriharsha Basavapatna  */
2497b1f684aSSriharsha Basavapatna boolean_t vnet_jumbo_rxpools = B_FALSE;
2507b1f684aSSriharsha Basavapatna 
251c1c61f44Ssb155480 /* # of chains in fdb hash table */
252c1c61f44Ssb155480 uint32_t	vnet_fdb_nchains = VNET_NFDB_HASH;
253c1c61f44Ssb155480 
254c1c61f44Ssb155480 /* Internal tunables */
255c1c61f44Ssb155480 uint32_t	vnet_ethermtu = 1500;	/* mtu of the device */
256c1c61f44Ssb155480 
257c1c61f44Ssb155480 /*
258c1c61f44Ssb155480  * Default vlan id. This is only used internally when the "default-vlan-id"
259c1c61f44Ssb155480  * property is not present in the MD device node. Therefore, this should not be
260c1c61f44Ssb155480  * used as a tunable; if this value is changed, the corresponding variable
261c1c61f44Ssb155480  * should be updated to the same value in vsw and also other vnets connected to
262c1c61f44Ssb155480  * the same vsw.
263c1c61f44Ssb155480  */
264c1c61f44Ssb155480 uint16_t	vnet_default_vlan_id = 1;
265c1c61f44Ssb155480 
266c1c61f44Ssb155480 /* delay in usec to wait for all references on a fdb entry to be dropped */
267c1c61f44Ssb155480 uint32_t vnet_fdbe_refcnt_delay = 10;
2681ae08745Sheppo 
269678453a8Sspeer static struct ether_addr etherbroadcastaddr = {
270678453a8Sspeer 	0xff, 0xff, 0xff, 0xff, 0xff, 0xff
271678453a8Sspeer };
272678453a8Sspeer 
27363f531d1SSriharsha Basavapatna /* mac_open() retry delay in usec */
27463f531d1SSriharsha Basavapatna uint32_t vnet_mac_open_delay = 100;	/* 0.1 ms */
27563f531d1SSriharsha Basavapatna 
27663f531d1SSriharsha Basavapatna /* max # of mac_open() retries */
27763f531d1SSriharsha Basavapatna uint32_t vnet_mac_open_retries = 100;
278678453a8Sspeer 
2791ae08745Sheppo /*
2801ae08745Sheppo  * Property names
2811ae08745Sheppo  */
2821ae08745Sheppo static char macaddr_propname[] = "local-mac-address";
2831ae08745Sheppo 
2841ae08745Sheppo /*
2851ae08745Sheppo  * This is the string displayed by modinfo(1m).
2861ae08745Sheppo  */
2877b1f684aSSriharsha Basavapatna static char vnet_ident[] = "vnet driver";
2881ae08745Sheppo extern struct mod_ops mod_driverops;
2891ae08745Sheppo static struct cb_ops cb_vnetops = {
2901ae08745Sheppo 	nulldev,		/* cb_open */
2911ae08745Sheppo 	nulldev,		/* cb_close */
2921ae08745Sheppo 	nodev,			/* cb_strategy */
2931ae08745Sheppo 	nodev,			/* cb_print */
2941ae08745Sheppo 	nodev,			/* cb_dump */
2951ae08745Sheppo 	nodev,			/* cb_read */
2961ae08745Sheppo 	nodev,			/* cb_write */
2971ae08745Sheppo 	nodev,			/* cb_ioctl */
2981ae08745Sheppo 	nodev,			/* cb_devmap */
2991ae08745Sheppo 	nodev,			/* cb_mmap */
3001ae08745Sheppo 	nodev,			/* cb_segmap */
3011ae08745Sheppo 	nochpoll,		/* cb_chpoll */
3021ae08745Sheppo 	ddi_prop_op,		/* cb_prop_op */
3031ae08745Sheppo 	NULL,			/* cb_stream */
3041ae08745Sheppo 	(int)(D_MP)		/* cb_flag */
3051ae08745Sheppo };
3061ae08745Sheppo 
3071ae08745Sheppo static struct dev_ops vnetops = {
3081ae08745Sheppo 	DEVO_REV,		/* devo_rev */
3091ae08745Sheppo 	0,			/* devo_refcnt */
3101ae08745Sheppo 	NULL,			/* devo_getinfo */
3111ae08745Sheppo 	nulldev,		/* devo_identify */
3121ae08745Sheppo 	nulldev,		/* devo_probe */
3131ae08745Sheppo 	vnetattach,		/* devo_attach */
3141ae08745Sheppo 	vnetdetach,		/* devo_detach */
3151ae08745Sheppo 	nodev,			/* devo_reset */
3161ae08745Sheppo 	&cb_vnetops,		/* devo_cb_ops */
31719397407SSherry Moore 	(struct bus_ops *)NULL,	/* devo_bus_ops */
31819397407SSherry Moore 	NULL,			/* devo_power */
31919397407SSherry Moore 	ddi_quiesce_not_supported,	/* devo_quiesce */
3201ae08745Sheppo };
3211ae08745Sheppo 
3221ae08745Sheppo static struct modldrv modldrv = {
3231ae08745Sheppo 	&mod_driverops,		/* Type of module.  This one is a driver */
3241ae08745Sheppo 	vnet_ident,		/* ID string */
3251ae08745Sheppo 	&vnetops		/* driver specific ops */
3261ae08745Sheppo };
3271ae08745Sheppo 
3281ae08745Sheppo static struct modlinkage modlinkage = {
3291ae08745Sheppo 	MODREV_1, (void *)&modldrv, NULL
3301ae08745Sheppo };
3311ae08745Sheppo 
332844e62a3Sraghuram #ifdef DEBUG
3331ae08745Sheppo 
3341ae08745Sheppo /*
3351ae08745Sheppo  * Print debug messages - set to 0xf to enable all msgs
3361ae08745Sheppo  */
337844e62a3Sraghuram int vnet_dbglevel = 0x8;
3381ae08745Sheppo 
339844e62a3Sraghuram static void
340844e62a3Sraghuram debug_printf(const char *fname, void *arg, const char *fmt, ...)
3411ae08745Sheppo {
3421ae08745Sheppo 	char    buf[512];
3431ae08745Sheppo 	va_list ap;
3441ae08745Sheppo 	vnet_t *vnetp = (vnet_t *)arg;
345844e62a3Sraghuram 	char    *bufp = buf;
3461ae08745Sheppo 
347844e62a3Sraghuram 	if (vnetp == NULL) {
348844e62a3Sraghuram 		(void) sprintf(bufp, "%s: ", fname);
349844e62a3Sraghuram 		bufp += strlen(bufp);
350844e62a3Sraghuram 	} else {
351844e62a3Sraghuram 		(void) sprintf(bufp, "vnet%d:%s: ", vnetp->instance, fname);
352844e62a3Sraghuram 		bufp += strlen(bufp);
3531ae08745Sheppo 	}
354844e62a3Sraghuram 	va_start(ap, fmt);
355844e62a3Sraghuram 	(void) vsprintf(bufp, fmt, ap);
356844e62a3Sraghuram 	va_end(ap);
357844e62a3Sraghuram 	cmn_err(CE_CONT, "%s\n", buf);
358844e62a3Sraghuram }
3591ae08745Sheppo 
3601ae08745Sheppo #endif
3611ae08745Sheppo 
3621ae08745Sheppo /* _init(9E): initialize the loadable module */
3631ae08745Sheppo int
3641ae08745Sheppo _init(void)
3651ae08745Sheppo {
3661ae08745Sheppo 	int status;
3671ae08745Sheppo 
368844e62a3Sraghuram 	DBG1(NULL, "enter\n");
3691ae08745Sheppo 
3701ae08745Sheppo 	mac_init_ops(&vnetops, "vnet");
3711ae08745Sheppo 	status = mod_install(&modlinkage);
3721ae08745Sheppo 	if (status != 0) {
3731ae08745Sheppo 		mac_fini_ops(&vnetops);
3741ae08745Sheppo 	}
375678453a8Sspeer 	vdds_mod_init();
3766f09f0feSWENTAO YANG 	vgen_mod_init();
377844e62a3Sraghuram 	DBG1(NULL, "exit(%d)\n", status);
3781ae08745Sheppo 	return (status);
3791ae08745Sheppo }
3801ae08745Sheppo 
3811ae08745Sheppo /* _fini(9E): prepare the module for unloading. */
3821ae08745Sheppo int
3831ae08745Sheppo _fini(void)
3841ae08745Sheppo {
3851ae08745Sheppo 	int		status;
3861ae08745Sheppo 
387844e62a3Sraghuram 	DBG1(NULL, "enter\n");
3881ae08745Sheppo 
3896f09f0feSWENTAO YANG 	status = vgen_mod_cleanup();
3906f09f0feSWENTAO YANG 	if (status != 0)
3916f09f0feSWENTAO YANG 		return (status);
3926f09f0feSWENTAO YANG 
3931ae08745Sheppo 	status = mod_remove(&modlinkage);
3941ae08745Sheppo 	if (status != 0)
3951ae08745Sheppo 		return (status);
3961ae08745Sheppo 	mac_fini_ops(&vnetops);
3976f09f0feSWENTAO YANG 	vgen_mod_fini();
398678453a8Sspeer 	vdds_mod_fini();
3991ae08745Sheppo 
400844e62a3Sraghuram 	DBG1(NULL, "exit(%d)\n", status);
4011ae08745Sheppo 	return (status);
4021ae08745Sheppo }
4031ae08745Sheppo 
4041ae08745Sheppo /* _info(9E): return information about the loadable module */
4051ae08745Sheppo int
4061ae08745Sheppo _info(struct modinfo *modinfop)
4071ae08745Sheppo {
4081ae08745Sheppo 	return (mod_info(&modlinkage, modinfop));
4091ae08745Sheppo }
4101ae08745Sheppo 
4111ae08745Sheppo /*
4121ae08745Sheppo  * attach(9E): attach a device to the system.
4131ae08745Sheppo  * called once for each instance of the device on the system.
4141ae08745Sheppo  */
4151ae08745Sheppo static int
4161ae08745Sheppo vnetattach(dev_info_t *dip, ddi_attach_cmd_t cmd)
4171ae08745Sheppo {
4181ae08745Sheppo 	vnet_t			*vnetp;
4191ae08745Sheppo 	int			status;
420678453a8Sspeer 	int			instance;
421678453a8Sspeer 	uint64_t		reg;
422678453a8Sspeer 	char			qname[TASKQ_NAMELEN];
4236f09f0feSWENTAO YANG 	vnet_attach_progress_t	attach_progress;
4241ae08745Sheppo 
4256f09f0feSWENTAO YANG 	attach_progress = AST_init;
4261ae08745Sheppo 
4271ae08745Sheppo 	switch (cmd) {
4281ae08745Sheppo 	case DDI_ATTACH:
4291ae08745Sheppo 		break;
4301ae08745Sheppo 	case DDI_RESUME:
4311ae08745Sheppo 	case DDI_PM_RESUME:
4321ae08745Sheppo 	default:
4331ae08745Sheppo 		goto vnet_attach_fail;
4341ae08745Sheppo 	}
4351ae08745Sheppo 
4361ae08745Sheppo 	instance = ddi_get_instance(dip);
437844e62a3Sraghuram 	DBG1(NULL, "instance(%d) enter\n", instance);
4381ae08745Sheppo 
4391ae08745Sheppo 	/* allocate vnet_t and mac_t structures */
4401ae08745Sheppo 	vnetp = kmem_zalloc(sizeof (vnet_t), KM_SLEEP);
441678453a8Sspeer 	vnetp->dip = dip;
442678453a8Sspeer 	vnetp->instance = instance;
443678453a8Sspeer 	rw_init(&vnetp->vrwlock, NULL, RW_DRIVER, NULL);
444678453a8Sspeer 	rw_init(&vnetp->vsw_fp_rw, NULL, RW_DRIVER, NULL);
4456f09f0feSWENTAO YANG 	attach_progress |= AST_vnet_alloc;
4461ae08745Sheppo 
44763f531d1SSriharsha Basavapatna 	vnet_ring_grp_init(vnetp);
44863f531d1SSriharsha Basavapatna 	attach_progress |= AST_ring_init;
44963f531d1SSriharsha Basavapatna 
450678453a8Sspeer 	status = vdds_init(vnetp);
451678453a8Sspeer 	if (status != 0) {
452678453a8Sspeer 		goto vnet_attach_fail;
453678453a8Sspeer 	}
4546f09f0feSWENTAO YANG 	attach_progress |= AST_vdds_init;
455678453a8Sspeer 
4561ae08745Sheppo 	/* setup links to vnet_t from both devinfo and mac_t */
4571ae08745Sheppo 	ddi_set_driver_private(dip, (caddr_t)vnetp);
4581ae08745Sheppo 
4591ae08745Sheppo 	/* read the mac address */
4601ae08745Sheppo 	status = vnet_read_mac_address(vnetp);
4611ae08745Sheppo 	if (status != DDI_SUCCESS) {
4621ae08745Sheppo 		goto vnet_attach_fail;
4631ae08745Sheppo 	}
4646f09f0feSWENTAO YANG 	attach_progress |= AST_read_macaddr;
4651ae08745Sheppo 
466678453a8Sspeer 	reg = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
467678453a8Sspeer 	    DDI_PROP_DONTPASS, "reg", -1);
468678453a8Sspeer 	if (reg == -1) {
4691ae08745Sheppo 		goto vnet_attach_fail;
4701ae08745Sheppo 	}
471678453a8Sspeer 	vnetp->reg = reg;
4721ae08745Sheppo 
473c1c61f44Ssb155480 	vnet_fdb_create(vnetp);
4746f09f0feSWENTAO YANG 	attach_progress |= AST_fdbh_alloc;
4751ae08745Sheppo 
476678453a8Sspeer 	(void) snprintf(qname, TASKQ_NAMELEN, "vnet_taskq%d", instance);
477678453a8Sspeer 	if ((vnetp->taskqp = ddi_taskq_create(dip, qname, 1,
478678453a8Sspeer 	    TASKQ_DEFAULTPRI, 0)) == NULL) {
479678453a8Sspeer 		cmn_err(CE_WARN, "!vnet%d: Unable to create task queue",
480678453a8Sspeer 		    instance);
4811ae08745Sheppo 		goto vnet_attach_fail;
4821ae08745Sheppo 	}
4836f09f0feSWENTAO YANG 	attach_progress |= AST_taskq_create;
4841ae08745Sheppo 
4851ae08745Sheppo 	/* add to the list of vnet devices */
4861ae08745Sheppo 	WRITE_ENTER(&vnet_rw);
4871ae08745Sheppo 	vnetp->nextp = vnet_headp;
4881ae08745Sheppo 	vnet_headp = vnetp;
4891ae08745Sheppo 	RW_EXIT(&vnet_rw);
4901ae08745Sheppo 
4916f09f0feSWENTAO YANG 	attach_progress |= AST_vnet_list;
492678453a8Sspeer 
493678453a8Sspeer 	/*
49463f531d1SSriharsha Basavapatna 	 * Initialize the generic vnet plugin which provides communication via
49563f531d1SSriharsha Basavapatna 	 * sun4v LDC (logical domain channel) based resources. This involves 2
49663f531d1SSriharsha Basavapatna 	 * steps; first, vgen_init() is invoked to read the various properties
49763f531d1SSriharsha Basavapatna 	 * of the vnet device from its MD node (including its mtu which is
49863f531d1SSriharsha Basavapatna 	 * needed to mac_register()) and obtain a handle to the vgen layer.
49963f531d1SSriharsha Basavapatna 	 * After mac_register() is done and we have a mac handle, we then
50063f531d1SSriharsha Basavapatna 	 * invoke vgen_init_mdeg() which registers with the the MD event
50163f531d1SSriharsha Basavapatna 	 * generator (mdeg) framework to allow LDC resource notifications.
50263f531d1SSriharsha Basavapatna 	 * Note: this sequence also allows us to report the correct default #
50363f531d1SSriharsha Basavapatna 	 * of pseudo rings (2TX and 3RX) in vnet_m_capab() which gets invoked
50463f531d1SSriharsha Basavapatna 	 * in the context of mac_register(); and avoids conflicting with
50563f531d1SSriharsha Basavapatna 	 * dynamic pseudo rx rings which get added/removed as a result of mdeg
50663f531d1SSriharsha Basavapatna 	 * events in vgen.
507678453a8Sspeer 	 */
508678453a8Sspeer 	status = vgen_init(vnetp, reg, vnetp->dip,
509678453a8Sspeer 	    (uint8_t *)vnetp->curr_macaddr, &vnetp->vgenhdl);
510678453a8Sspeer 	if (status != DDI_SUCCESS) {
511678453a8Sspeer 		DERR(vnetp, "vgen_init() failed\n");
512678453a8Sspeer 		goto vnet_attach_fail;
513678453a8Sspeer 	}
5146f09f0feSWENTAO YANG 	attach_progress |= AST_vgen_init;
515678453a8Sspeer 
516678453a8Sspeer 	status = vnet_mac_register(vnetp);
517678453a8Sspeer 	if (status != DDI_SUCCESS) {
518678453a8Sspeer 		goto vnet_attach_fail;
519678453a8Sspeer 	}
5201107ea93SSriharsha Basavapatna 	vnetp->link_state = LINK_STATE_UNKNOWN;
5216f09f0feSWENTAO YANG 	attach_progress |= AST_macreg;
5226f09f0feSWENTAO YANG 
52363f531d1SSriharsha Basavapatna 	status = vgen_init_mdeg(vnetp->vgenhdl);
52463f531d1SSriharsha Basavapatna 	if (status != DDI_SUCCESS) {
52563f531d1SSriharsha Basavapatna 		goto vnet_attach_fail;
52663f531d1SSriharsha Basavapatna 	}
52763f531d1SSriharsha Basavapatna 	attach_progress |= AST_init_mdeg;
52863f531d1SSriharsha Basavapatna 
5296f09f0feSWENTAO YANG 	vnetp->attach_progress = attach_progress;
5306f09f0feSWENTAO YANG 
531844e62a3Sraghuram 	DBG1(NULL, "instance(%d) exit\n", instance);
5321ae08745Sheppo 	return (DDI_SUCCESS);
5331ae08745Sheppo 
5341ae08745Sheppo vnet_attach_fail:
5356f09f0feSWENTAO YANG 	vnetp->attach_progress = attach_progress;
5363ab636deSWENTAO YANG 	status = vnet_unattach(vnetp);
5373ab636deSWENTAO YANG 	ASSERT(status == 0);
5381ae08745Sheppo 	return (DDI_FAILURE);
5391ae08745Sheppo }
5401ae08745Sheppo 
5411ae08745Sheppo /*
5421ae08745Sheppo  * detach(9E): detach a device from the system.
5431ae08745Sheppo  */
5441ae08745Sheppo static int
5451ae08745Sheppo vnetdetach(dev_info_t *dip, ddi_detach_cmd_t cmd)
5461ae08745Sheppo {
5471ae08745Sheppo 	vnet_t		*vnetp;
5481ae08745Sheppo 	int		instance;
5491ae08745Sheppo 
5501ae08745Sheppo 	instance = ddi_get_instance(dip);
551844e62a3Sraghuram 	DBG1(NULL, "instance(%d) enter\n", instance);
5521ae08745Sheppo 
5531ae08745Sheppo 	vnetp = ddi_get_driver_private(dip);
5541ae08745Sheppo 	if (vnetp == NULL) {
5551ae08745Sheppo 		goto vnet_detach_fail;
5561ae08745Sheppo 	}
5571ae08745Sheppo 
5581ae08745Sheppo 	switch (cmd) {
5591ae08745Sheppo 	case DDI_DETACH:
5601ae08745Sheppo 		break;
5611ae08745Sheppo 	case DDI_SUSPEND:
5621ae08745Sheppo 	case DDI_PM_SUSPEND:
5631ae08745Sheppo 	default:
5641ae08745Sheppo 		goto vnet_detach_fail;
5651ae08745Sheppo 	}
5661ae08745Sheppo 
5676f09f0feSWENTAO YANG 	if (vnet_unattach(vnetp) != 0) {
568d10e4ef2Snarayan 		goto vnet_detach_fail;
569d10e4ef2Snarayan 	}
570d10e4ef2Snarayan 
5716f09f0feSWENTAO YANG 	return (DDI_SUCCESS);
5721ae08745Sheppo 
5736f09f0feSWENTAO YANG vnet_detach_fail:
5746f09f0feSWENTAO YANG 	return (DDI_FAILURE);
5756f09f0feSWENTAO YANG }
5766f09f0feSWENTAO YANG 
5776f09f0feSWENTAO YANG /*
5786f09f0feSWENTAO YANG  * Common routine to handle vnetattach() failure and vnetdetach(). Note that
5796f09f0feSWENTAO YANG  * the only reason this function could fail is if mac_unregister() fails.
5806f09f0feSWENTAO YANG  * Otherwise, this function must ensure that all resources are freed and return
5816f09f0feSWENTAO YANG  * success.
5826f09f0feSWENTAO YANG  */
5836f09f0feSWENTAO YANG static int
5846f09f0feSWENTAO YANG vnet_unattach(vnet_t *vnetp)
5856f09f0feSWENTAO YANG {
5866f09f0feSWENTAO YANG 	vnet_attach_progress_t	attach_progress;
5876f09f0feSWENTAO YANG 
5886f09f0feSWENTAO YANG 	attach_progress = vnetp->attach_progress;
5896f09f0feSWENTAO YANG 
5906f09f0feSWENTAO YANG 	/*
59163f531d1SSriharsha Basavapatna 	 * Disable the mac device in the gldv3 subsystem. This can fail, in
59263f531d1SSriharsha Basavapatna 	 * particular if there are still any open references to this mac
59363f531d1SSriharsha Basavapatna 	 * device; in which case we just return failure without continuing to
59463f531d1SSriharsha Basavapatna 	 * detach further.
59563f531d1SSriharsha Basavapatna 	 * If it succeeds, we then invoke vgen_uninit() which should unregister
59663f531d1SSriharsha Basavapatna 	 * any pseudo rings registered with the mac layer. Note we keep the
59763f531d1SSriharsha Basavapatna 	 * AST_macreg flag on, so we can unregister with the mac layer at
59863f531d1SSriharsha Basavapatna 	 * the end of this routine.
5996f09f0feSWENTAO YANG 	 */
6006f09f0feSWENTAO YANG 	if (attach_progress & AST_macreg) {
60163f531d1SSriharsha Basavapatna 		if (mac_disable(vnetp->mh) != 0) {
6026f09f0feSWENTAO YANG 			return (1);
6036f09f0feSWENTAO YANG 		}
6046f09f0feSWENTAO YANG 	}
6056f09f0feSWENTAO YANG 
6066f09f0feSWENTAO YANG 	/*
60763f531d1SSriharsha Basavapatna 	 * Now that we have disabled the device, we must finish all other steps
60863f531d1SSriharsha Basavapatna 	 * and successfully return from this function; otherwise we will end up
60963f531d1SSriharsha Basavapatna 	 * leaving the device in a broken/unusable state.
6106f09f0feSWENTAO YANG 	 *
6116f09f0feSWENTAO YANG 	 * First, release any hybrid resources assigned to this vnet device.
6126f09f0feSWENTAO YANG 	 */
6136f09f0feSWENTAO YANG 	if (attach_progress & AST_vdds_init) {
6146f09f0feSWENTAO YANG 		vdds_cleanup(vnetp);
6156f09f0feSWENTAO YANG 		attach_progress &= ~AST_vdds_init;
6166f09f0feSWENTAO YANG 	}
6176f09f0feSWENTAO YANG 
6186f09f0feSWENTAO YANG 	/*
6196f09f0feSWENTAO YANG 	 * Uninit vgen. This stops further mdeg callbacks to this vnet
6206f09f0feSWENTAO YANG 	 * device and/or its ports; and detaches any existing ports.
6216f09f0feSWENTAO YANG 	 */
62263f531d1SSriharsha Basavapatna 	if (attach_progress & (AST_vgen_init|AST_init_mdeg)) {
6236f09f0feSWENTAO YANG 		vgen_uninit(vnetp->vgenhdl);
6246f09f0feSWENTAO YANG 		attach_progress &= ~AST_vgen_init;
62563f531d1SSriharsha Basavapatna 		attach_progress &= ~AST_init_mdeg;
6266f09f0feSWENTAO YANG 	}
6276f09f0feSWENTAO YANG 
6286f09f0feSWENTAO YANG 	/* Destroy the taskq. */
6296f09f0feSWENTAO YANG 	if (attach_progress & AST_taskq_create) {
6306f09f0feSWENTAO YANG 		ddi_taskq_destroy(vnetp->taskqp);
6316f09f0feSWENTAO YANG 		attach_progress &= ~AST_taskq_create;
6326f09f0feSWENTAO YANG 	}
6336f09f0feSWENTAO YANG 
6346f09f0feSWENTAO YANG 	/* Destroy fdb. */
6356f09f0feSWENTAO YANG 	if (attach_progress & AST_fdbh_alloc) {
6366f09f0feSWENTAO YANG 		vnet_fdb_destroy(vnetp);
6376f09f0feSWENTAO YANG 		attach_progress &= ~AST_fdbh_alloc;
6386f09f0feSWENTAO YANG 	}
6396f09f0feSWENTAO YANG 
6406f09f0feSWENTAO YANG 	/* Remove from the device list */
6416f09f0feSWENTAO YANG 	if (attach_progress & AST_vnet_list) {
6426f09f0feSWENTAO YANG 		vnet_t		**vnetpp;
6431ae08745Sheppo 		/* unlink from instance(vnet_t) list */
6441ae08745Sheppo 		WRITE_ENTER(&vnet_rw);
6456f09f0feSWENTAO YANG 		for (vnetpp = &vnet_headp; *vnetpp;
6466f09f0feSWENTAO YANG 		    vnetpp = &(*vnetpp)->nextp) {
6471ae08745Sheppo 			if (*vnetpp == vnetp) {
6481ae08745Sheppo 				*vnetpp = vnetp->nextp;
6491ae08745Sheppo 				break;
6501ae08745Sheppo 			}
6511ae08745Sheppo 		}
6521ae08745Sheppo 		RW_EXIT(&vnet_rw);
6536f09f0feSWENTAO YANG 		attach_progress &= ~AST_vnet_list;
6546f09f0feSWENTAO YANG 	}
6551ae08745Sheppo 
65663f531d1SSriharsha Basavapatna 	if (attach_progress & AST_ring_init) {
65763f531d1SSriharsha Basavapatna 		vnet_ring_grp_uninit(vnetp);
65863f531d1SSriharsha Basavapatna 		attach_progress &= ~AST_ring_init;
65963f531d1SSriharsha Basavapatna 	}
66063f531d1SSriharsha Basavapatna 
66163f531d1SSriharsha Basavapatna 	if (attach_progress & AST_macreg) {
66263f531d1SSriharsha Basavapatna 		VERIFY(mac_unregister(vnetp->mh) == 0);
66363f531d1SSriharsha Basavapatna 		vnetp->mh = NULL;
66463f531d1SSriharsha Basavapatna 		attach_progress &= ~AST_macreg;
66563f531d1SSriharsha Basavapatna 	}
66663f531d1SSriharsha Basavapatna 
6676f09f0feSWENTAO YANG 	if (attach_progress & AST_vnet_alloc) {
668678453a8Sspeer 		rw_destroy(&vnetp->vrwlock);
669678453a8Sspeer 		rw_destroy(&vnetp->vsw_fp_rw);
6706f09f0feSWENTAO YANG 		attach_progress &= ~AST_vnet_list;
6711ae08745Sheppo 		KMEM_FREE(vnetp);
6726f09f0feSWENTAO YANG 	}
6731ae08745Sheppo 
6746f09f0feSWENTAO YANG 	return (0);
6751ae08745Sheppo }
6761ae08745Sheppo 
6771ae08745Sheppo /* enable the device for transmit/receive */
6781ae08745Sheppo static int
6791ae08745Sheppo vnet_m_start(void *arg)
6801ae08745Sheppo {
6811ae08745Sheppo 	vnet_t		*vnetp = arg;
6821ae08745Sheppo 
683844e62a3Sraghuram 	DBG1(vnetp, "enter\n");
6841ae08745Sheppo 
685678453a8Sspeer 	WRITE_ENTER(&vnetp->vrwlock);
686678453a8Sspeer 	vnetp->flags |= VNET_STARTED;
687678453a8Sspeer 	vnet_start_resources(vnetp);
688678453a8Sspeer 	RW_EXIT(&vnetp->vrwlock);
6891ae08745Sheppo 
690844e62a3Sraghuram 	DBG1(vnetp, "exit\n");
6911ae08745Sheppo 	return (VNET_SUCCESS);
6921ae08745Sheppo 
6931ae08745Sheppo }
6941ae08745Sheppo 
6951ae08745Sheppo /* stop transmit/receive for the device */
6961ae08745Sheppo static void
6971ae08745Sheppo vnet_m_stop(void *arg)
6981ae08745Sheppo {
6991ae08745Sheppo 	vnet_t		*vnetp = arg;
7001ae08745Sheppo 
701844e62a3Sraghuram 	DBG1(vnetp, "enter\n");
7021ae08745Sheppo 
703678453a8Sspeer 	WRITE_ENTER(&vnetp->vrwlock);
704678453a8Sspeer 	if (vnetp->flags & VNET_STARTED) {
7055460ddbdSSriharsha Basavapatna 		/*
7065460ddbdSSriharsha Basavapatna 		 * Set the flags appropriately; this should prevent starting of
7075460ddbdSSriharsha Basavapatna 		 * any new resources that are added(see vnet_res_start_task()),
7085460ddbdSSriharsha Basavapatna 		 * while we release the vrwlock in vnet_stop_resources() before
7095460ddbdSSriharsha Basavapatna 		 * stopping each resource.
7105460ddbdSSriharsha Basavapatna 		 */
711678453a8Sspeer 		vnetp->flags &= ~VNET_STARTED;
7125460ddbdSSriharsha Basavapatna 		vnetp->flags |= VNET_STOPPING;
7135460ddbdSSriharsha Basavapatna 		vnet_stop_resources(vnetp);
7145460ddbdSSriharsha Basavapatna 		vnetp->flags &= ~VNET_STOPPING;
7151ae08745Sheppo 	}
716678453a8Sspeer 	RW_EXIT(&vnetp->vrwlock);
7171ae08745Sheppo 
718844e62a3Sraghuram 	DBG1(vnetp, "exit\n");
7191ae08745Sheppo }
7201ae08745Sheppo 
7211ae08745Sheppo /* set the unicast mac address of the device */
7221ae08745Sheppo static int
7231ae08745Sheppo vnet_m_unicst(void *arg, const uint8_t *macaddr)
7241ae08745Sheppo {
7251ae08745Sheppo 	_NOTE(ARGUNUSED(macaddr))
7261ae08745Sheppo 
7271ae08745Sheppo 	vnet_t *vnetp = arg;
7281ae08745Sheppo 
729844e62a3Sraghuram 	DBG1(vnetp, "enter\n");
7301ae08745Sheppo 	/*
7313af08d82Slm66018 	 * NOTE: setting mac address dynamically is not supported.
7321ae08745Sheppo 	 */
733844e62a3Sraghuram 	DBG1(vnetp, "exit\n");
7341ae08745Sheppo 
7358e6a2a04Slm66018 	return (VNET_FAILURE);
7361ae08745Sheppo }
7371ae08745Sheppo 
7381ae08745Sheppo /* enable/disable a multicast address */
7391ae08745Sheppo static int
7401ae08745Sheppo vnet_m_multicst(void *arg, boolean_t add, const uint8_t *mca)
7411ae08745Sheppo {
7421ae08745Sheppo 	_NOTE(ARGUNUSED(add, mca))
7431ae08745Sheppo 
7441ae08745Sheppo 	vnet_t		*vnetp = arg;
745678453a8Sspeer 	vnet_res_t	*vresp;
746678453a8Sspeer 	mac_register_t	*macp;
747ba2e4443Sseb 	mac_callbacks_t	*cbp;
7481ae08745Sheppo 	int		rv = VNET_SUCCESS;
7491ae08745Sheppo 
750844e62a3Sraghuram 	DBG1(vnetp, "enter\n");
751678453a8Sspeer 
7520c4606f0SWENTAO YANG 	READ_ENTER(&vnetp->vsw_fp_rw);
7530c4606f0SWENTAO YANG 	if (vnetp->vsw_fp == NULL) {
7540c4606f0SWENTAO YANG 		RW_EXIT(&vnetp->vsw_fp_rw);
7550c4606f0SWENTAO YANG 		return (EAGAIN);
7560c4606f0SWENTAO YANG 	}
7570c4606f0SWENTAO YANG 	VNET_FDBE_REFHOLD(vnetp->vsw_fp);
7580c4606f0SWENTAO YANG 	RW_EXIT(&vnetp->vsw_fp_rw);
7590c4606f0SWENTAO YANG 
7600c4606f0SWENTAO YANG 	vresp = vnetp->vsw_fp;
761678453a8Sspeer 	macp = &vresp->macreg;
762678453a8Sspeer 	cbp = macp->m_callbacks;
763678453a8Sspeer 	rv = cbp->mc_multicst(macp->m_driver, add, mca);
7640c4606f0SWENTAO YANG 
7650c4606f0SWENTAO YANG 	VNET_FDBE_REFRELE(vnetp->vsw_fp);
766678453a8Sspeer 
767844e62a3Sraghuram 	DBG1(vnetp, "exit(%d)\n", rv);
7681ae08745Sheppo 	return (rv);
7691ae08745Sheppo }
7701ae08745Sheppo 
7711ae08745Sheppo /* set or clear promiscuous mode on the device */
7721ae08745Sheppo static int
7731ae08745Sheppo vnet_m_promisc(void *arg, boolean_t on)
7741ae08745Sheppo {
7751ae08745Sheppo 	_NOTE(ARGUNUSED(on))
7761ae08745Sheppo 
7771ae08745Sheppo 	vnet_t *vnetp = arg;
778844e62a3Sraghuram 	DBG1(vnetp, "enter\n");
7791ae08745Sheppo 	/*
7803af08d82Slm66018 	 * NOTE: setting promiscuous mode is not supported, just return success.
7811ae08745Sheppo 	 */
782844e62a3Sraghuram 	DBG1(vnetp, "exit\n");
7831ae08745Sheppo 	return (VNET_SUCCESS);
7841ae08745Sheppo }
7851ae08745Sheppo 
7861ae08745Sheppo /*
7871ae08745Sheppo  * Transmit a chain of packets. This function provides switching functionality
7881ae08745Sheppo  * based on the destination mac address to reach other guests (within ldoms) or
7891ae08745Sheppo  * external hosts.
7901ae08745Sheppo  */
7911ae08745Sheppo mblk_t *
79263f531d1SSriharsha Basavapatna vnet_tx_ring_send(void *arg, mblk_t *mp)
7931ae08745Sheppo {
79463f531d1SSriharsha Basavapatna 	vnet_pseudo_tx_ring_t	*tx_ringp;
7950dc2366fSVenugopal Iyer 	vnet_tx_ring_stats_t	*statsp;
7961ae08745Sheppo 	vnet_t			*vnetp;
797678453a8Sspeer 	vnet_res_t		*vresp;
7981ae08745Sheppo 	mblk_t			*next;
7991ae08745Sheppo 	mblk_t			*resid_mp;
800678453a8Sspeer 	mac_register_t		*macp;
801c1c61f44Ssb155480 	struct ether_header	*ehp;
802678453a8Sspeer 	boolean_t		is_unicast;
8038c242ab0SSriharsha Basavapatna 	boolean_t		is_pvid;	/* non-default pvid ? */
8048c242ab0SSriharsha Basavapatna 	boolean_t		hres;		/* Hybrid resource ? */
80563f531d1SSriharsha Basavapatna 	void			*tx_arg;
8060dc2366fSVenugopal Iyer 	size_t			size;
8071ae08745Sheppo 
80863f531d1SSriharsha Basavapatna 	tx_ringp = (vnet_pseudo_tx_ring_t *)arg;
8090dc2366fSVenugopal Iyer 	statsp = &tx_ringp->tx_ring_stats;
81063f531d1SSriharsha Basavapatna 	vnetp = (vnet_t *)tx_ringp->vnetp;
811844e62a3Sraghuram 	DBG1(vnetp, "enter\n");
8121ae08745Sheppo 	ASSERT(mp != NULL);
8131ae08745Sheppo 
8148c242ab0SSriharsha Basavapatna 	is_pvid = (vnetp->pvid != vnetp->default_vlan_id) ? B_TRUE : B_FALSE;
8158c242ab0SSriharsha Basavapatna 
8161ae08745Sheppo 	while (mp != NULL) {
817c1c61f44Ssb155480 
8181ae08745Sheppo 		next = mp->b_next;
8191ae08745Sheppo 		mp->b_next = NULL;
8201ae08745Sheppo 
8210dc2366fSVenugopal Iyer 		/* update stats */
8220dc2366fSVenugopal Iyer 		size = msgsize(mp);
8230dc2366fSVenugopal Iyer 
8241ae08745Sheppo 		/*
825c1c61f44Ssb155480 		 * Find fdb entry for the destination
826c1c61f44Ssb155480 		 * and hold a reference to it.
8271ae08745Sheppo 		 */
828c1c61f44Ssb155480 		ehp = (struct ether_header *)mp->b_rptr;
829678453a8Sspeer 		vresp = vnet_fdbe_find(vnetp, &ehp->ether_dhost);
830678453a8Sspeer 		if (vresp != NULL) {
831c1c61f44Ssb155480 
832c1c61f44Ssb155480 			/*
833c1c61f44Ssb155480 			 * Destination found in FDB.
834c1c61f44Ssb155480 			 * The destination is a vnet device within ldoms
835c1c61f44Ssb155480 			 * and directly reachable, invoke the tx function
836c1c61f44Ssb155480 			 * in the fdb entry.
837c1c61f44Ssb155480 			 */
838678453a8Sspeer 			macp = &vresp->macreg;
839678453a8Sspeer 			resid_mp = macp->m_callbacks->mc_tx(macp->m_driver, mp);
840c1c61f44Ssb155480 
841c1c61f44Ssb155480 			/* tx done; now release ref on fdb entry */
842678453a8Sspeer 			VNET_FDBE_REFRELE(vresp);
843c1c61f44Ssb155480 
8441ae08745Sheppo 			if (resid_mp != NULL) {
8451ae08745Sheppo 				/* m_tx failed */
8461ae08745Sheppo 				mp->b_next = next;
8471ae08745Sheppo 				break;
8481ae08745Sheppo 			}
8491ae08745Sheppo 		} else {
850678453a8Sspeer 			is_unicast = !(IS_BROADCAST(ehp) ||
851678453a8Sspeer 			    (IS_MULTICAST(ehp)));
8521ae08745Sheppo 			/*
853c1c61f44Ssb155480 			 * Destination is not in FDB.
854678453a8Sspeer 			 * If the destination is broadcast or multicast,
855678453a8Sspeer 			 * then forward the packet to vswitch.
856678453a8Sspeer 			 * If a Hybrid resource avilable, then send the
857678453a8Sspeer 			 * unicast packet via hybrid resource, otherwise
858678453a8Sspeer 			 * forward it to vswitch.
8591ae08745Sheppo 			 */
860c1c61f44Ssb155480 			READ_ENTER(&vnetp->vsw_fp_rw);
861c1c61f44Ssb155480 
862678453a8Sspeer 			if ((is_unicast) && (vnetp->hio_fp != NULL)) {
863678453a8Sspeer 				vresp = vnetp->hio_fp;
8648c242ab0SSriharsha Basavapatna 				hres = B_TRUE;
865678453a8Sspeer 			} else {
866678453a8Sspeer 				vresp = vnetp->vsw_fp;
8678c242ab0SSriharsha Basavapatna 				hres = B_FALSE;
868678453a8Sspeer 			}
869678453a8Sspeer 			if (vresp == NULL) {
870c1c61f44Ssb155480 				/*
871c1c61f44Ssb155480 				 * no fdb entry to vsw? drop the packet.
872c1c61f44Ssb155480 				 */
873c1c61f44Ssb155480 				RW_EXIT(&vnetp->vsw_fp_rw);
874c1c61f44Ssb155480 				freemsg(mp);
875c1c61f44Ssb155480 				mp = next;
876c1c61f44Ssb155480 				continue;
877c1c61f44Ssb155480 			}
878c1c61f44Ssb155480 
879c1c61f44Ssb155480 			/* ref hold the fdb entry to vsw */
880678453a8Sspeer 			VNET_FDBE_REFHOLD(vresp);
881c1c61f44Ssb155480 
882c1c61f44Ssb155480 			RW_EXIT(&vnetp->vsw_fp_rw);
883c1c61f44Ssb155480 
8848c242ab0SSriharsha Basavapatna 			/*
8858c242ab0SSriharsha Basavapatna 			 * In the case of a hybrid resource we need to insert
8868c242ab0SSriharsha Basavapatna 			 * the tag for the pvid case here; unlike packets that
8878c242ab0SSriharsha Basavapatna 			 * are destined to a vnet/vsw in which case the vgen
8888c242ab0SSriharsha Basavapatna 			 * layer does the tagging before sending it over ldc.
8898c242ab0SSriharsha Basavapatna 			 */
8908c242ab0SSriharsha Basavapatna 			if (hres == B_TRUE) {
8918c242ab0SSriharsha Basavapatna 				/*
8928c242ab0SSriharsha Basavapatna 				 * Determine if the frame being transmitted
8938c242ab0SSriharsha Basavapatna 				 * over the hybrid resource is untagged. If so,
8948c242ab0SSriharsha Basavapatna 				 * insert the tag before transmitting.
8958c242ab0SSriharsha Basavapatna 				 */
8968c242ab0SSriharsha Basavapatna 				if (is_pvid == B_TRUE &&
8978c242ab0SSriharsha Basavapatna 				    ehp->ether_type != htons(ETHERTYPE_VLAN)) {
8988c242ab0SSriharsha Basavapatna 
8998c242ab0SSriharsha Basavapatna 					mp = vnet_vlan_insert_tag(mp,
9008c242ab0SSriharsha Basavapatna 					    vnetp->pvid);
9018c242ab0SSriharsha Basavapatna 					if (mp == NULL) {
9028c242ab0SSriharsha Basavapatna 						VNET_FDBE_REFRELE(vresp);
9038c242ab0SSriharsha Basavapatna 						mp = next;
9048c242ab0SSriharsha Basavapatna 						continue;
9058c242ab0SSriharsha Basavapatna 					}
9068c242ab0SSriharsha Basavapatna 
9078c242ab0SSriharsha Basavapatna 				}
9088c242ab0SSriharsha Basavapatna 
909678453a8Sspeer 				macp = &vresp->macreg;
91063f531d1SSriharsha Basavapatna 				tx_arg = tx_ringp;
91163f531d1SSriharsha Basavapatna 			} else {
91263f531d1SSriharsha Basavapatna 				macp = &vresp->macreg;
91363f531d1SSriharsha Basavapatna 				tx_arg = macp->m_driver;
91463f531d1SSriharsha Basavapatna 			}
91563f531d1SSriharsha Basavapatna 			resid_mp = macp->m_callbacks->mc_tx(tx_arg, mp);
916c1c61f44Ssb155480 
917c1c61f44Ssb155480 			/* tx done; now release ref on fdb entry */
918678453a8Sspeer 			VNET_FDBE_REFRELE(vresp);
919c1c61f44Ssb155480 
9201ae08745Sheppo 			if (resid_mp != NULL) {
9211ae08745Sheppo 				/* m_tx failed */
9221ae08745Sheppo 				mp->b_next = next;
9231ae08745Sheppo 				break;
9241ae08745Sheppo 			}
9251ae08745Sheppo 		}
9261ae08745Sheppo 
9270dc2366fSVenugopal Iyer 		statsp->obytes += size;
9280dc2366fSVenugopal Iyer 		statsp->opackets++;
9291ae08745Sheppo 		mp = next;
9301ae08745Sheppo 	}
9311ae08745Sheppo 
932844e62a3Sraghuram 	DBG1(vnetp, "exit\n");
9331ae08745Sheppo 	return (mp);
9341ae08745Sheppo }
9351ae08745Sheppo 
9361ae08745Sheppo /* get statistics from the device */
937ba2e4443Sseb int
938ba2e4443Sseb vnet_m_stat(void *arg, uint_t stat, uint64_t *val)
9391ae08745Sheppo {
9401ae08745Sheppo 	vnet_t *vnetp = arg;
941678453a8Sspeer 	vnet_res_t	*vresp;
942678453a8Sspeer 	mac_register_t	*macp;
943ba2e4443Sseb 	mac_callbacks_t	*cbp;
944ba2e4443Sseb 	uint64_t val_total = 0;
9451ae08745Sheppo 
946844e62a3Sraghuram 	DBG1(vnetp, "enter\n");
9471ae08745Sheppo 
9481ae08745Sheppo 	/*
949ba2e4443Sseb 	 * get the specified statistic from each transport and return the
950ba2e4443Sseb 	 * aggregate val.  This obviously only works for counters.
9511ae08745Sheppo 	 */
952ba2e4443Sseb 	if ((IS_MAC_STAT(stat) && !MAC_STAT_ISACOUNTER(stat)) ||
953ba2e4443Sseb 	    (IS_MACTYPE_STAT(stat) && !ETHER_STAT_ISACOUNTER(stat))) {
954ba2e4443Sseb 		return (ENOTSUP);
955ba2e4443Sseb 	}
956678453a8Sspeer 
957678453a8Sspeer 	READ_ENTER(&vnetp->vrwlock);
958678453a8Sspeer 	for (vresp = vnetp->vres_list; vresp != NULL; vresp = vresp->nextp) {
959678453a8Sspeer 		macp = &vresp->macreg;
960678453a8Sspeer 		cbp = macp->m_callbacks;
961678453a8Sspeer 		if (cbp->mc_getstat(macp->m_driver, stat, val) == 0)
962ba2e4443Sseb 			val_total += *val;
9631ae08745Sheppo 	}
964678453a8Sspeer 	RW_EXIT(&vnetp->vrwlock);
9651ae08745Sheppo 
966ba2e4443Sseb 	*val = val_total;
967ba2e4443Sseb 
968844e62a3Sraghuram 	DBG1(vnetp, "exit\n");
969ba2e4443Sseb 	return (0);
9701ae08745Sheppo }
9711ae08745Sheppo 
97263f531d1SSriharsha Basavapatna static void
97363f531d1SSriharsha Basavapatna vnet_ring_grp_init(vnet_t *vnetp)
97463f531d1SSriharsha Basavapatna {
97563f531d1SSriharsha Basavapatna 	vnet_pseudo_rx_group_t	*rx_grp;
97663f531d1SSriharsha Basavapatna 	vnet_pseudo_rx_ring_t	*rx_ringp;
97763f531d1SSriharsha Basavapatna 	vnet_pseudo_tx_group_t	*tx_grp;
97863f531d1SSriharsha Basavapatna 	vnet_pseudo_tx_ring_t	*tx_ringp;
97963f531d1SSriharsha Basavapatna 	int			i;
98063f531d1SSriharsha Basavapatna 
98163f531d1SSriharsha Basavapatna 	tx_grp = &vnetp->tx_grp[0];
98263f531d1SSriharsha Basavapatna 	tx_ringp = kmem_zalloc(sizeof (vnet_pseudo_tx_ring_t) *
98363f531d1SSriharsha Basavapatna 	    VNET_NUM_PSEUDO_TXRINGS, KM_SLEEP);
98463f531d1SSriharsha Basavapatna 	for (i = 0; i < VNET_NUM_PSEUDO_TXRINGS; i++) {
98563f531d1SSriharsha Basavapatna 		tx_ringp[i].state |= VNET_TXRING_SHARED;
98663f531d1SSriharsha Basavapatna 	}
98763f531d1SSriharsha Basavapatna 	tx_grp->rings = tx_ringp;
98863f531d1SSriharsha Basavapatna 	tx_grp->ring_cnt = VNET_NUM_PSEUDO_TXRINGS;
9890dc2366fSVenugopal Iyer 	mutex_init(&tx_grp->flowctl_lock, NULL, MUTEX_DRIVER, NULL);
9900dc2366fSVenugopal Iyer 	cv_init(&tx_grp->flowctl_cv, NULL, CV_DRIVER, NULL);
9910dc2366fSVenugopal Iyer 	tx_grp->flowctl_thread = thread_create(NULL, 0,
9920dc2366fSVenugopal Iyer 	    vnet_tx_notify_thread, tx_grp, 0, &p0, TS_RUN, minclsyspri);
99363f531d1SSriharsha Basavapatna 
99463f531d1SSriharsha Basavapatna 	rx_grp = &vnetp->rx_grp[0];
99563f531d1SSriharsha Basavapatna 	rx_grp->max_ring_cnt = MAX_RINGS_PER_GROUP;
99663f531d1SSriharsha Basavapatna 	rw_init(&rx_grp->lock, NULL, RW_DRIVER, NULL);
99763f531d1SSriharsha Basavapatna 	rx_ringp = kmem_zalloc(sizeof (vnet_pseudo_rx_ring_t) *
99863f531d1SSriharsha Basavapatna 	    rx_grp->max_ring_cnt, KM_SLEEP);
99963f531d1SSriharsha Basavapatna 
100063f531d1SSriharsha Basavapatna 	/*
100163f531d1SSriharsha Basavapatna 	 * Setup the first 3 Pseudo RX Rings that are reserved;
100263f531d1SSriharsha Basavapatna 	 * 1 for LDC resource to vswitch + 2 for RX rings of Hybrid resource.
100363f531d1SSriharsha Basavapatna 	 */
100463f531d1SSriharsha Basavapatna 	rx_ringp[0].state |= VNET_RXRING_INUSE|VNET_RXRING_LDC_SERVICE;
100563f531d1SSriharsha Basavapatna 	rx_ringp[0].index = 0;
100663f531d1SSriharsha Basavapatna 	rx_ringp[1].state |= VNET_RXRING_INUSE|VNET_RXRING_HYBRID;
100763f531d1SSriharsha Basavapatna 	rx_ringp[1].index = 1;
100863f531d1SSriharsha Basavapatna 	rx_ringp[2].state |= VNET_RXRING_INUSE|VNET_RXRING_HYBRID;
100963f531d1SSriharsha Basavapatna 	rx_ringp[2].index = 2;
101063f531d1SSriharsha Basavapatna 
101163f531d1SSriharsha Basavapatna 	rx_grp->ring_cnt = VNET_NUM_PSEUDO_RXRINGS_DEFAULT;
101263f531d1SSriharsha Basavapatna 	rx_grp->rings = rx_ringp;
101363f531d1SSriharsha Basavapatna 
101463f531d1SSriharsha Basavapatna 	for (i = VNET_NUM_PSEUDO_RXRINGS_DEFAULT;
101563f531d1SSriharsha Basavapatna 	    i < rx_grp->max_ring_cnt; i++) {
101663f531d1SSriharsha Basavapatna 		rx_ringp = &rx_grp->rings[i];
101763f531d1SSriharsha Basavapatna 		rx_ringp->state = VNET_RXRING_FREE;
101863f531d1SSriharsha Basavapatna 		rx_ringp->index = i;
101963f531d1SSriharsha Basavapatna 	}
102063f531d1SSriharsha Basavapatna }
102163f531d1SSriharsha Basavapatna 
102263f531d1SSriharsha Basavapatna static void
102363f531d1SSriharsha Basavapatna vnet_ring_grp_uninit(vnet_t *vnetp)
102463f531d1SSriharsha Basavapatna {
102563f531d1SSriharsha Basavapatna 	vnet_pseudo_rx_group_t	*rx_grp;
102663f531d1SSriharsha Basavapatna 	vnet_pseudo_tx_group_t	*tx_grp;
10270dc2366fSVenugopal Iyer 	kt_did_t		tid = 0;
102863f531d1SSriharsha Basavapatna 
102963f531d1SSriharsha Basavapatna 	tx_grp = &vnetp->tx_grp[0];
10300dc2366fSVenugopal Iyer 
10310dc2366fSVenugopal Iyer 	/* Inform tx_notify_thread to exit */
10320dc2366fSVenugopal Iyer 	mutex_enter(&tx_grp->flowctl_lock);
10330dc2366fSVenugopal Iyer 	if (tx_grp->flowctl_thread != NULL) {
10340dc2366fSVenugopal Iyer 		tid = tx_grp->flowctl_thread->t_did;
10350dc2366fSVenugopal Iyer 		tx_grp->flowctl_done = B_TRUE;
10360dc2366fSVenugopal Iyer 		cv_signal(&tx_grp->flowctl_cv);
10370dc2366fSVenugopal Iyer 	}
10380dc2366fSVenugopal Iyer 	mutex_exit(&tx_grp->flowctl_lock);
10390dc2366fSVenugopal Iyer 	if (tid != 0)
10400dc2366fSVenugopal Iyer 		thread_join(tid);
10410dc2366fSVenugopal Iyer 
104263f531d1SSriharsha Basavapatna 	if (tx_grp->rings != NULL) {
104363f531d1SSriharsha Basavapatna 		ASSERT(tx_grp->ring_cnt == VNET_NUM_PSEUDO_TXRINGS);
104463f531d1SSriharsha Basavapatna 		kmem_free(tx_grp->rings, sizeof (vnet_pseudo_tx_ring_t) *
104563f531d1SSriharsha Basavapatna 		    tx_grp->ring_cnt);
104663f531d1SSriharsha Basavapatna 		tx_grp->rings = NULL;
104763f531d1SSriharsha Basavapatna 	}
104863f531d1SSriharsha Basavapatna 
104963f531d1SSriharsha Basavapatna 	rx_grp = &vnetp->rx_grp[0];
105063f531d1SSriharsha Basavapatna 	if (rx_grp->rings != NULL) {
105163f531d1SSriharsha Basavapatna 		ASSERT(rx_grp->max_ring_cnt == MAX_RINGS_PER_GROUP);
105263f531d1SSriharsha Basavapatna 		ASSERT(rx_grp->ring_cnt == VNET_NUM_PSEUDO_RXRINGS_DEFAULT);
105363f531d1SSriharsha Basavapatna 		kmem_free(rx_grp->rings, sizeof (vnet_pseudo_rx_ring_t) *
105463f531d1SSriharsha Basavapatna 		    rx_grp->max_ring_cnt);
105563f531d1SSriharsha Basavapatna 		rx_grp->rings = NULL;
105663f531d1SSriharsha Basavapatna 	}
105763f531d1SSriharsha Basavapatna }
105863f531d1SSriharsha Basavapatna 
105963f531d1SSriharsha Basavapatna static vnet_pseudo_rx_ring_t *
106063f531d1SSriharsha Basavapatna vnet_alloc_pseudo_rx_ring(vnet_t *vnetp)
106163f531d1SSriharsha Basavapatna {
106263f531d1SSriharsha Basavapatna 	vnet_pseudo_rx_group_t  *rx_grp;
106363f531d1SSriharsha Basavapatna 	vnet_pseudo_rx_ring_t	*rx_ringp;
106463f531d1SSriharsha Basavapatna 	int			index;
106563f531d1SSriharsha Basavapatna 
106663f531d1SSriharsha Basavapatna 	rx_grp = &vnetp->rx_grp[0];
106763f531d1SSriharsha Basavapatna 	WRITE_ENTER(&rx_grp->lock);
106863f531d1SSriharsha Basavapatna 
106963f531d1SSriharsha Basavapatna 	if (rx_grp->ring_cnt == rx_grp->max_ring_cnt) {
107063f531d1SSriharsha Basavapatna 		/* no rings available */
107163f531d1SSriharsha Basavapatna 		RW_EXIT(&rx_grp->lock);
107263f531d1SSriharsha Basavapatna 		return (NULL);
107363f531d1SSriharsha Basavapatna 	}
107463f531d1SSriharsha Basavapatna 
107563f531d1SSriharsha Basavapatna 	for (index = VNET_NUM_PSEUDO_RXRINGS_DEFAULT;
107663f531d1SSriharsha Basavapatna 	    index < rx_grp->max_ring_cnt; index++) {
107763f531d1SSriharsha Basavapatna 		rx_ringp = &rx_grp->rings[index];
107863f531d1SSriharsha Basavapatna 		if (rx_ringp->state == VNET_RXRING_FREE) {
107963f531d1SSriharsha Basavapatna 			rx_ringp->state |= VNET_RXRING_INUSE;
108063f531d1SSriharsha Basavapatna 			rx_grp->ring_cnt++;
108163f531d1SSriharsha Basavapatna 			break;
108263f531d1SSriharsha Basavapatna 		}
108363f531d1SSriharsha Basavapatna 	}
108463f531d1SSriharsha Basavapatna 
108563f531d1SSriharsha Basavapatna 	RW_EXIT(&rx_grp->lock);
108663f531d1SSriharsha Basavapatna 	return (rx_ringp);
108763f531d1SSriharsha Basavapatna }
108863f531d1SSriharsha Basavapatna 
108963f531d1SSriharsha Basavapatna static void
109063f531d1SSriharsha Basavapatna vnet_free_pseudo_rx_ring(vnet_t *vnetp, vnet_pseudo_rx_ring_t *ringp)
109163f531d1SSriharsha Basavapatna {
109263f531d1SSriharsha Basavapatna 	vnet_pseudo_rx_group_t  *rx_grp;
109363f531d1SSriharsha Basavapatna 
109463f531d1SSriharsha Basavapatna 	ASSERT(ringp->index >= VNET_NUM_PSEUDO_RXRINGS_DEFAULT);
109563f531d1SSriharsha Basavapatna 	rx_grp = &vnetp->rx_grp[0];
109663f531d1SSriharsha Basavapatna 	WRITE_ENTER(&rx_grp->lock);
109763f531d1SSriharsha Basavapatna 
109863f531d1SSriharsha Basavapatna 	if (ringp->state != VNET_RXRING_FREE) {
109963f531d1SSriharsha Basavapatna 		ringp->state = VNET_RXRING_FREE;
110063f531d1SSriharsha Basavapatna 		ringp->handle = NULL;
110163f531d1SSriharsha Basavapatna 		rx_grp->ring_cnt--;
110263f531d1SSriharsha Basavapatna 	}
110363f531d1SSriharsha Basavapatna 
110463f531d1SSriharsha Basavapatna 	RW_EXIT(&rx_grp->lock);
110563f531d1SSriharsha Basavapatna }
110663f531d1SSriharsha Basavapatna 
11071ae08745Sheppo /* wrapper function for mac_register() */
11081ae08745Sheppo static int
11091ae08745Sheppo vnet_mac_register(vnet_t *vnetp)
11101ae08745Sheppo {
1111ba2e4443Sseb 	mac_register_t	*macp;
1112ba2e4443Sseb 	int		err;
11131ae08745Sheppo 
1114ba2e4443Sseb 	if ((macp = mac_alloc(MAC_VERSION)) == NULL)
1115ba2e4443Sseb 		return (DDI_FAILURE);
1116ba2e4443Sseb 	macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
1117ba2e4443Sseb 	macp->m_driver = vnetp;
11181ae08745Sheppo 	macp->m_dip = vnetp->dip;
1119ba2e4443Sseb 	macp->m_src_addr = vnetp->curr_macaddr;
1120ba2e4443Sseb 	macp->m_callbacks = &vnet_m_callbacks;
1121ba2e4443Sseb 	macp->m_min_sdu = 0;
11227b1f684aSSriharsha Basavapatna 	macp->m_max_sdu = vnetp->mtu;
1123c1c61f44Ssb155480 	macp->m_margin = VLAN_TAGSZ;
11241ae08745Sheppo 
112563f531d1SSriharsha Basavapatna 	macp->m_v12n = MAC_VIRT_LEVEL1;
112663f531d1SSriharsha Basavapatna 
112763f531d1SSriharsha Basavapatna 	/*
11281ae08745Sheppo 	 * Finally, we're ready to register ourselves with the MAC layer
11291ae08745Sheppo 	 * interface; if this succeeds, we're all ready to start()
11301ae08745Sheppo 	 */
1131ba2e4443Sseb 	err = mac_register(macp, &vnetp->mh);
1132ba2e4443Sseb 	mac_free(macp);
1133ba2e4443Sseb 	return (err == 0 ? DDI_SUCCESS : DDI_FAILURE);
11341ae08745Sheppo }
11351ae08745Sheppo 
11361ae08745Sheppo /* read the mac address of the device */
11371ae08745Sheppo static int
11381ae08745Sheppo vnet_read_mac_address(vnet_t *vnetp)
11391ae08745Sheppo {
11401ae08745Sheppo 	uchar_t 	*macaddr;
11411ae08745Sheppo 	uint32_t 	size;
11421ae08745Sheppo 	int 		rv;
11431ae08745Sheppo 
11441ae08745Sheppo 	rv = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, vnetp->dip,
11451ae08745Sheppo 	    DDI_PROP_DONTPASS, macaddr_propname, &macaddr, &size);
11461ae08745Sheppo 	if ((rv != DDI_PROP_SUCCESS) || (size != ETHERADDRL)) {
1147844e62a3Sraghuram 		DWARN(vnetp, "prop_lookup failed(%s) err(%d)\n",
1148844e62a3Sraghuram 		    macaddr_propname, rv);
11491ae08745Sheppo 		return (DDI_FAILURE);
11501ae08745Sheppo 	}
11511ae08745Sheppo 	bcopy(macaddr, (caddr_t)vnetp->vendor_addr, ETHERADDRL);
11521ae08745Sheppo 	bcopy(macaddr, (caddr_t)vnetp->curr_macaddr, ETHERADDRL);
11531ae08745Sheppo 	ddi_prop_free(macaddr);
11541ae08745Sheppo 
11551ae08745Sheppo 	return (DDI_SUCCESS);
11561ae08745Sheppo }
11571ae08745Sheppo 
115893b13a42Swentaoy static void
1159c1c61f44Ssb155480 vnet_fdb_create(vnet_t *vnetp)
116093b13a42Swentaoy {
1161c1c61f44Ssb155480 	char		hashname[MAXNAMELEN];
116293b13a42Swentaoy 
1163c1c61f44Ssb155480 	(void) snprintf(hashname, MAXNAMELEN, "vnet%d-fdbhash",
1164c1c61f44Ssb155480 	    vnetp->instance);
1165c1c61f44Ssb155480 	vnetp->fdb_nchains = vnet_fdb_nchains;
1166c1c61f44Ssb155480 	vnetp->fdb_hashp = mod_hash_create_ptrhash(hashname, vnetp->fdb_nchains,
1167c1c61f44Ssb155480 	    mod_hash_null_valdtor, sizeof (void *));
116893b13a42Swentaoy }
116993b13a42Swentaoy 
117093b13a42Swentaoy static void
1171c1c61f44Ssb155480 vnet_fdb_destroy(vnet_t *vnetp)
117293b13a42Swentaoy {
1173c1c61f44Ssb155480 	/* destroy fdb-hash-table */
1174c1c61f44Ssb155480 	if (vnetp->fdb_hashp != NULL) {
1175c1c61f44Ssb155480 		mod_hash_destroy_hash(vnetp->fdb_hashp);
1176c1c61f44Ssb155480 		vnetp->fdb_hashp = NULL;
1177c1c61f44Ssb155480 		vnetp->fdb_nchains = 0;
1178c1c61f44Ssb155480 	}
117993b13a42Swentaoy }
118093b13a42Swentaoy 
118193b13a42Swentaoy /*
1182c1c61f44Ssb155480  * Add an entry into the fdb.
118393b13a42Swentaoy  */
11841ae08745Sheppo void
1185678453a8Sspeer vnet_fdbe_add(vnet_t *vnetp, vnet_res_t *vresp)
11861ae08745Sheppo {
1187c1c61f44Ssb155480 	uint64_t	addr = 0;
1188c1c61f44Ssb155480 	int		rv;
1189c1c61f44Ssb155480 
1190678453a8Sspeer 	KEY_HASH(addr, vresp->rem_macaddr);
11911ae08745Sheppo 
11921ae08745Sheppo 	/*
1193678453a8Sspeer 	 * If the entry being added corresponds to LDC_SERVICE resource,
1194678453a8Sspeer 	 * that is, vswitch connection, it is added to the hash and also
1195678453a8Sspeer 	 * the entry is cached, an additional reference count reflects
1196678453a8Sspeer 	 * this. The HYBRID resource is not added to the hash, but only
1197678453a8Sspeer 	 * cached, as it is only used for sending out packets for unknown
1198678453a8Sspeer 	 * unicast destinations.
11991ae08745Sheppo 	 */
1200678453a8Sspeer 	(vresp->type == VIO_NET_RES_LDC_SERVICE) ?
1201678453a8Sspeer 	    (vresp->refcnt = 1) : (vresp->refcnt = 0);
12021ae08745Sheppo 
1203c1c61f44Ssb155480 	/*
1204c1c61f44Ssb155480 	 * Note: duplicate keys will be rejected by mod_hash.
1205c1c61f44Ssb155480 	 */
1206678453a8Sspeer 	if (vresp->type != VIO_NET_RES_HYBRID) {
1207c1c61f44Ssb155480 		rv = mod_hash_insert(vnetp->fdb_hashp, (mod_hash_key_t)addr,
1208678453a8Sspeer 		    (mod_hash_val_t)vresp);
1209c1c61f44Ssb155480 		if (rv != 0) {
1210c1c61f44Ssb155480 			DWARN(vnetp, "Duplicate macaddr key(%lx)\n", addr);
12111ae08745Sheppo 			return;
12121ae08745Sheppo 		}
1213678453a8Sspeer 	}
12141ae08745Sheppo 
1215678453a8Sspeer 	if (vresp->type == VIO_NET_RES_LDC_SERVICE) {
1216c1c61f44Ssb155480 		/* Cache the fdb entry to vsw-port */
1217c1c61f44Ssb155480 		WRITE_ENTER(&vnetp->vsw_fp_rw);
1218c1c61f44Ssb155480 		if (vnetp->vsw_fp == NULL)
1219678453a8Sspeer 			vnetp->vsw_fp = vresp;
1220678453a8Sspeer 		RW_EXIT(&vnetp->vsw_fp_rw);
1221678453a8Sspeer 	} else if (vresp->type == VIO_NET_RES_HYBRID) {
1222678453a8Sspeer 		/* Cache the fdb entry to hybrid resource */
1223678453a8Sspeer 		WRITE_ENTER(&vnetp->vsw_fp_rw);
1224678453a8Sspeer 		if (vnetp->hio_fp == NULL)
1225678453a8Sspeer 			vnetp->hio_fp = vresp;
1226c1c61f44Ssb155480 		RW_EXIT(&vnetp->vsw_fp_rw);
1227c1c61f44Ssb155480 	}
12281ae08745Sheppo }
12291ae08745Sheppo 
1230c1c61f44Ssb155480 /*
1231c1c61f44Ssb155480  * Remove an entry from fdb.
1232c1c61f44Ssb155480  */
1233678453a8Sspeer static void
1234678453a8Sspeer vnet_fdbe_del(vnet_t *vnetp, vnet_res_t *vresp)
12351ae08745Sheppo {
1236c1c61f44Ssb155480 	uint64_t	addr = 0;
1237c1c61f44Ssb155480 	int		rv;
1238c1c61f44Ssb155480 	uint32_t	refcnt;
1239678453a8Sspeer 	vnet_res_t	*tmp;
1240c1c61f44Ssb155480 
1241678453a8Sspeer 	KEY_HASH(addr, vresp->rem_macaddr);
12421ae08745Sheppo 
12431ae08745Sheppo 	/*
1244c1c61f44Ssb155480 	 * Remove the entry from fdb hash table.
1245c1c61f44Ssb155480 	 * This prevents further references to this fdb entry.
12461ae08745Sheppo 	 */
1247678453a8Sspeer 	if (vresp->type != VIO_NET_RES_HYBRID) {
1248c1c61f44Ssb155480 		rv = mod_hash_remove(vnetp->fdb_hashp, (mod_hash_key_t)addr,
1249678453a8Sspeer 		    (mod_hash_val_t *)&tmp);
1250678453a8Sspeer 		if (rv != 0) {
1251678453a8Sspeer 			/*
1252678453a8Sspeer 			 * As the resources are added to the hash only
1253678453a8Sspeer 			 * after they are started, this can occur if
1254678453a8Sspeer 			 * a resource unregisters before it is ever started.
1255678453a8Sspeer 			 */
1256678453a8Sspeer 			return;
1257678453a8Sspeer 		}
1258678453a8Sspeer 	}
12591ae08745Sheppo 
1260678453a8Sspeer 	if (vresp->type == VIO_NET_RES_LDC_SERVICE) {
1261c1c61f44Ssb155480 		WRITE_ENTER(&vnetp->vsw_fp_rw);
12621ae08745Sheppo 
1263678453a8Sspeer 		ASSERT(tmp == vnetp->vsw_fp);
1264c1c61f44Ssb155480 		vnetp->vsw_fp = NULL;
1265c1c61f44Ssb155480 
1266c1c61f44Ssb155480 		RW_EXIT(&vnetp->vsw_fp_rw);
1267678453a8Sspeer 	} else if (vresp->type == VIO_NET_RES_HYBRID) {
1268678453a8Sspeer 		WRITE_ENTER(&vnetp->vsw_fp_rw);
1269678453a8Sspeer 
1270678453a8Sspeer 		vnetp->hio_fp = NULL;
1271678453a8Sspeer 
1272678453a8Sspeer 		RW_EXIT(&vnetp->vsw_fp_rw);
12731ae08745Sheppo 	}
12741ae08745Sheppo 
1275c1c61f44Ssb155480 	/*
1276c1c61f44Ssb155480 	 * If there are threads already ref holding before the entry was
1277c1c61f44Ssb155480 	 * removed from hash table, then wait for ref count to drop to zero.
1278c1c61f44Ssb155480 	 */
1279678453a8Sspeer 	(vresp->type == VIO_NET_RES_LDC_SERVICE) ?
1280678453a8Sspeer 	    (refcnt = 1) : (refcnt = 0);
1281678453a8Sspeer 	while (vresp->refcnt > refcnt) {
1282c1c61f44Ssb155480 		delay(drv_usectohz(vnet_fdbe_refcnt_delay));
1283c1c61f44Ssb155480 	}
1284c1c61f44Ssb155480 }
1285c1c61f44Ssb155480 
1286c1c61f44Ssb155480 /*
1287c1c61f44Ssb155480  * Search fdb for a given mac address. If an entry is found, hold
1288c1c61f44Ssb155480  * a reference to it and return the entry; else returns NULL.
1289c1c61f44Ssb155480  */
1290678453a8Sspeer static vnet_res_t *
1291c1c61f44Ssb155480 vnet_fdbe_find(vnet_t *vnetp, struct ether_addr *addrp)
1292c1c61f44Ssb155480 {
1293c1c61f44Ssb155480 	uint64_t	key = 0;
1294678453a8Sspeer 	vnet_res_t	*vresp;
1295c1c61f44Ssb155480 	int		rv;
1296c1c61f44Ssb155480 
1297678453a8Sspeer 	KEY_HASH(key, addrp->ether_addr_octet);
1298c1c61f44Ssb155480 
1299c1c61f44Ssb155480 	rv = mod_hash_find_cb(vnetp->fdb_hashp, (mod_hash_key_t)key,
1300678453a8Sspeer 	    (mod_hash_val_t *)&vresp, vnet_fdbe_find_cb);
1301c1c61f44Ssb155480 
1302c1c61f44Ssb155480 	if (rv != 0)
1303c1c61f44Ssb155480 		return (NULL);
1304c1c61f44Ssb155480 
1305678453a8Sspeer 	return (vresp);
1306c1c61f44Ssb155480 }
1307c1c61f44Ssb155480 
1308c1c61f44Ssb155480 /*
1309c1c61f44Ssb155480  * Callback function provided to mod_hash_find_cb(). After finding the fdb
1310c1c61f44Ssb155480  * entry corresponding to the key (macaddr), this callback will be invoked by
1311c1c61f44Ssb155480  * mod_hash_find_cb() to atomically increment the reference count on the fdb
1312c1c61f44Ssb155480  * entry before returning the found entry.
1313c1c61f44Ssb155480  */
1314c1c61f44Ssb155480 static void
1315c1c61f44Ssb155480 vnet_fdbe_find_cb(mod_hash_key_t key, mod_hash_val_t val)
1316c1c61f44Ssb155480 {
1317c1c61f44Ssb155480 	_NOTE(ARGUNUSED(key))
1318678453a8Sspeer 	VNET_FDBE_REFHOLD((vnet_res_t *)val);
1319678453a8Sspeer }
1320678453a8Sspeer 
13218c242ab0SSriharsha Basavapatna /*
13228c242ab0SSriharsha Basavapatna  * Frames received that are tagged with the pvid of the vnet device must be
13238c242ab0SSriharsha Basavapatna  * untagged before sending up the stack. This function walks the chain of rx
13248c242ab0SSriharsha Basavapatna  * frames, untags any such frames and returns the updated chain.
13258c242ab0SSriharsha Basavapatna  *
13268c242ab0SSriharsha Basavapatna  * Arguments:
13278c242ab0SSriharsha Basavapatna  *    pvid:  pvid of the vnet device for which packets are being received
13288c242ab0SSriharsha Basavapatna  *    mp:    head of pkt chain to be validated and untagged
13298c242ab0SSriharsha Basavapatna  *
13308c242ab0SSriharsha Basavapatna  * Returns:
13318c242ab0SSriharsha Basavapatna  *    mp:    head of updated chain of packets
13328c242ab0SSriharsha Basavapatna  */
13338c242ab0SSriharsha Basavapatna static void
13348c242ab0SSriharsha Basavapatna vnet_rx_frames_untag(uint16_t pvid, mblk_t **mp)
13358c242ab0SSriharsha Basavapatna {
13368c242ab0SSriharsha Basavapatna 	struct ether_vlan_header	*evhp;
13378c242ab0SSriharsha Basavapatna 	mblk_t				*bp;
13388c242ab0SSriharsha Basavapatna 	mblk_t				*bpt;
13398c242ab0SSriharsha Basavapatna 	mblk_t				*bph;
13408c242ab0SSriharsha Basavapatna 	mblk_t				*bpn;
13418c242ab0SSriharsha Basavapatna 
13428c242ab0SSriharsha Basavapatna 	bpn = bph = bpt = NULL;
13438c242ab0SSriharsha Basavapatna 
13448c242ab0SSriharsha Basavapatna 	for (bp = *mp; bp != NULL; bp = bpn) {
13458c242ab0SSriharsha Basavapatna 
13468c242ab0SSriharsha Basavapatna 		bpn = bp->b_next;
13478c242ab0SSriharsha Basavapatna 		bp->b_next = bp->b_prev = NULL;
13488c242ab0SSriharsha Basavapatna 
13498c242ab0SSriharsha Basavapatna 		evhp = (struct ether_vlan_header *)bp->b_rptr;
13508c242ab0SSriharsha Basavapatna 
13518c242ab0SSriharsha Basavapatna 		if (ntohs(evhp->ether_tpid) == ETHERTYPE_VLAN &&
13528c242ab0SSriharsha Basavapatna 		    VLAN_ID(ntohs(evhp->ether_tci)) == pvid) {
13538c242ab0SSriharsha Basavapatna 
13548c242ab0SSriharsha Basavapatna 			bp = vnet_vlan_remove_tag(bp);
13558c242ab0SSriharsha Basavapatna 			if (bp == NULL) {
13568c242ab0SSriharsha Basavapatna 				continue;
13578c242ab0SSriharsha Basavapatna 			}
13588c242ab0SSriharsha Basavapatna 
13598c242ab0SSriharsha Basavapatna 		}
13608c242ab0SSriharsha Basavapatna 
13618c242ab0SSriharsha Basavapatna 		/* build a chain of processed packets */
13628c242ab0SSriharsha Basavapatna 		if (bph == NULL) {
13638c242ab0SSriharsha Basavapatna 			bph = bpt = bp;
13648c242ab0SSriharsha Basavapatna 		} else {
13658c242ab0SSriharsha Basavapatna 			bpt->b_next = bp;
13668c242ab0SSriharsha Basavapatna 			bpt = bp;
13678c242ab0SSriharsha Basavapatna 		}
13688c242ab0SSriharsha Basavapatna 
13698c242ab0SSriharsha Basavapatna 	}
13708c242ab0SSriharsha Basavapatna 
13718c242ab0SSriharsha Basavapatna 	*mp = bph;
13728c242ab0SSriharsha Basavapatna }
13738c242ab0SSriharsha Basavapatna 
1374678453a8Sspeer static void
1375678453a8Sspeer vnet_rx(vio_net_handle_t vrh, mblk_t *mp)
1376678453a8Sspeer {
1377678453a8Sspeer 	vnet_res_t		*vresp = (vnet_res_t *)vrh;
1378678453a8Sspeer 	vnet_t			*vnetp = vresp->vnetp;
137963f531d1SSriharsha Basavapatna 	vnet_pseudo_rx_ring_t	*ringp;
1380678453a8Sspeer 
13818c242ab0SSriharsha Basavapatna 	if ((vnetp == NULL) || (vnetp->mh == 0)) {
1382678453a8Sspeer 		freemsgchain(mp);
13838c242ab0SSriharsha Basavapatna 		return;
1384678453a8Sspeer 	}
13858c242ab0SSriharsha Basavapatna 
138663f531d1SSriharsha Basavapatna 	ringp = vresp->rx_ringp;
138763f531d1SSriharsha Basavapatna 	mac_rx_ring(vnetp->mh, ringp->handle, mp, ringp->gen_num);
13881ae08745Sheppo }
1389ba2e4443Sseb 
1390ba2e4443Sseb void
1391678453a8Sspeer vnet_tx_update(vio_net_handle_t vrh)
1392ba2e4443Sseb {
1393678453a8Sspeer 	vnet_res_t		*vresp = (vnet_res_t *)vrh;
1394678453a8Sspeer 	vnet_t			*vnetp = vresp->vnetp;
139563f531d1SSriharsha Basavapatna 	vnet_pseudo_tx_ring_t	*tx_ringp;
139663f531d1SSriharsha Basavapatna 	vnet_pseudo_tx_group_t	*tx_grp;
139763f531d1SSriharsha Basavapatna 	int			i;
1398ba2e4443Sseb 
139963f531d1SSriharsha Basavapatna 	if (vnetp == NULL || vnetp->mh == NULL) {
140063f531d1SSriharsha Basavapatna 		return;
140163f531d1SSriharsha Basavapatna 	}
140263f531d1SSriharsha Basavapatna 
140363f531d1SSriharsha Basavapatna 	/*
140463f531d1SSriharsha Basavapatna 	 * Currently, the tx hwring API (used to access rings that belong to
140563f531d1SSriharsha Basavapatna 	 * a Hybrid IO resource) does not provide us a per ring flow ctrl
140663f531d1SSriharsha Basavapatna 	 * update; also the pseudo rings are shared by the ports/ldcs in the
140763f531d1SSriharsha Basavapatna 	 * vgen layer. Thus we can't figure out which pseudo ring is being
140863f531d1SSriharsha Basavapatna 	 * re-enabled for transmits. To work around this, when we get a tx
140963f531d1SSriharsha Basavapatna 	 * restart notification from below, we simply propagate that to all
141063f531d1SSriharsha Basavapatna 	 * the tx pseudo rings registered with the mac layer above.
141163f531d1SSriharsha Basavapatna 	 *
141263f531d1SSriharsha Basavapatna 	 * There are a couple of side effects with this approach, but they are
141363f531d1SSriharsha Basavapatna 	 * not harmful, as outlined below:
141463f531d1SSriharsha Basavapatna 	 *
141563f531d1SSriharsha Basavapatna 	 * A) We might send an invalid ring_update() for a ring that is not
141663f531d1SSriharsha Basavapatna 	 * really flow controlled. This will not have any effect in the mac
141763f531d1SSriharsha Basavapatna 	 * layer and packets will continue to be transmitted on that ring.
141863f531d1SSriharsha Basavapatna 	 *
141963f531d1SSriharsha Basavapatna 	 * B) We might end up clearing the flow control in the mac layer for
142063f531d1SSriharsha Basavapatna 	 * a ring that is still flow controlled in the underlying resource.
142163f531d1SSriharsha Basavapatna 	 * This will result in the mac layer restarting	transmit, only to be
142263f531d1SSriharsha Basavapatna 	 * flow controlled again on that ring.
142363f531d1SSriharsha Basavapatna 	 */
142463f531d1SSriharsha Basavapatna 	tx_grp = &vnetp->tx_grp[0];
142563f531d1SSriharsha Basavapatna 	for (i = 0; i < tx_grp->ring_cnt; i++) {
142663f531d1SSriharsha Basavapatna 		tx_ringp = &tx_grp->rings[i];
142763f531d1SSriharsha Basavapatna 		mac_tx_ring_update(vnetp->mh, tx_ringp->handle);
1428ba2e4443Sseb 	}
1429678453a8Sspeer }
1430678453a8Sspeer 
1431678453a8Sspeer /*
14320dc2366fSVenugopal Iyer  * vnet_tx_notify_thread:
14330dc2366fSVenugopal Iyer  *
14340dc2366fSVenugopal Iyer  * vnet_tx_ring_update() callback function wakes up this thread when
14350dc2366fSVenugopal Iyer  * it gets called. This thread will call mac_tx_ring_update() to
14360dc2366fSVenugopal Iyer  * notify upper mac of flow control getting relieved. Note that
14370dc2366fSVenugopal Iyer  * vnet_tx_ring_update() cannot call mac_tx_ring_update() directly
14380dc2366fSVenugopal Iyer  * because vnet_tx_ring_update() is called from lower mac with
14390dc2366fSVenugopal Iyer  * mi_rw_lock held and mac_tx_ring_update() would also try to grab
14400dc2366fSVenugopal Iyer  * the same lock.
14410dc2366fSVenugopal Iyer  */
14420dc2366fSVenugopal Iyer static void
14430dc2366fSVenugopal Iyer vnet_tx_notify_thread(void *arg)
14440dc2366fSVenugopal Iyer {
14450dc2366fSVenugopal Iyer 	callb_cpr_t		cprinfo;
14460dc2366fSVenugopal Iyer 	vnet_pseudo_tx_group_t	*tx_grp = (vnet_pseudo_tx_group_t *)arg;
14470dc2366fSVenugopal Iyer 	vnet_pseudo_tx_ring_t	*tx_ringp;
14480dc2366fSVenugopal Iyer 	vnet_t			*vnetp;
14490dc2366fSVenugopal Iyer 	int			i;
14500dc2366fSVenugopal Iyer 
14510dc2366fSVenugopal Iyer 	CALLB_CPR_INIT(&cprinfo, &tx_grp->flowctl_lock, callb_generic_cpr,
14520dc2366fSVenugopal Iyer 	    "vnet_tx_notify_thread");
14530dc2366fSVenugopal Iyer 
14540dc2366fSVenugopal Iyer 	mutex_enter(&tx_grp->flowctl_lock);
14550dc2366fSVenugopal Iyer 	while (!tx_grp->flowctl_done) {
14560dc2366fSVenugopal Iyer 		CALLB_CPR_SAFE_BEGIN(&cprinfo);
14570dc2366fSVenugopal Iyer 		cv_wait(&tx_grp->flowctl_cv, &tx_grp->flowctl_lock);
14580dc2366fSVenugopal Iyer 		CALLB_CPR_SAFE_END(&cprinfo, &tx_grp->flowctl_lock);
14590dc2366fSVenugopal Iyer 
14600dc2366fSVenugopal Iyer 		for (i = 0; i < tx_grp->ring_cnt; i++) {
14610dc2366fSVenugopal Iyer 			tx_ringp = &tx_grp->rings[i];
14620dc2366fSVenugopal Iyer 			if (tx_ringp->woken_up) {
14630dc2366fSVenugopal Iyer 				tx_ringp->woken_up = B_FALSE;
14640dc2366fSVenugopal Iyer 				vnetp = tx_ringp->vnetp;
14650dc2366fSVenugopal Iyer 				mac_tx_ring_update(vnetp->mh, tx_ringp->handle);
14660dc2366fSVenugopal Iyer 			}
14670dc2366fSVenugopal Iyer 		}
14680dc2366fSVenugopal Iyer 	}
14690dc2366fSVenugopal Iyer 	/*
14700dc2366fSVenugopal Iyer 	 * The tx_grp is being destroyed, exit the thread.
14710dc2366fSVenugopal Iyer 	 */
14720dc2366fSVenugopal Iyer 	tx_grp->flowctl_thread = NULL;
14730dc2366fSVenugopal Iyer 	CALLB_CPR_EXIT(&cprinfo);
14740dc2366fSVenugopal Iyer 	thread_exit();
14750dc2366fSVenugopal Iyer }
14760dc2366fSVenugopal Iyer 
14770dc2366fSVenugopal Iyer void
14780dc2366fSVenugopal Iyer vnet_tx_ring_update(void *arg1, uintptr_t arg2)
14790dc2366fSVenugopal Iyer {
14800dc2366fSVenugopal Iyer 	vnet_t			*vnetp = (vnet_t *)arg1;
14810dc2366fSVenugopal Iyer 	vnet_pseudo_tx_group_t	*tx_grp;
14820dc2366fSVenugopal Iyer 	vnet_pseudo_tx_ring_t	*tx_ringp;
14830dc2366fSVenugopal Iyer 	int			i;
14840dc2366fSVenugopal Iyer 
14850dc2366fSVenugopal Iyer 	tx_grp = &vnetp->tx_grp[0];
14860dc2366fSVenugopal Iyer 	for (i = 0; i < tx_grp->ring_cnt; i++) {
14870dc2366fSVenugopal Iyer 		tx_ringp = &tx_grp->rings[i];
14880dc2366fSVenugopal Iyer 		if (tx_ringp->hw_rh == (mac_ring_handle_t)arg2) {
14890dc2366fSVenugopal Iyer 			mutex_enter(&tx_grp->flowctl_lock);
14900dc2366fSVenugopal Iyer 			tx_ringp->woken_up = B_TRUE;
14910dc2366fSVenugopal Iyer 			cv_signal(&tx_grp->flowctl_cv);
14920dc2366fSVenugopal Iyer 			mutex_exit(&tx_grp->flowctl_lock);
14930dc2366fSVenugopal Iyer 			break;
14940dc2366fSVenugopal Iyer 		}
14950dc2366fSVenugopal Iyer 	}
14960dc2366fSVenugopal Iyer }
14970dc2366fSVenugopal Iyer 
14980dc2366fSVenugopal Iyer /*
14997b1f684aSSriharsha Basavapatna  * Update the new mtu of vnet into the mac layer. First check if the device has
15007b1f684aSSriharsha Basavapatna  * been plumbed and if so fail the mtu update. Returns 0 on success.
15017b1f684aSSriharsha Basavapatna  */
15027b1f684aSSriharsha Basavapatna int
15037b1f684aSSriharsha Basavapatna vnet_mtu_update(vnet_t *vnetp, uint32_t mtu)
15047b1f684aSSriharsha Basavapatna {
15057b1f684aSSriharsha Basavapatna 	int	rv;
15067b1f684aSSriharsha Basavapatna 
15077b1f684aSSriharsha Basavapatna 	if (vnetp == NULL || vnetp->mh == NULL) {
15087b1f684aSSriharsha Basavapatna 		return (EINVAL);
15097b1f684aSSriharsha Basavapatna 	}
15107b1f684aSSriharsha Basavapatna 
15117b1f684aSSriharsha Basavapatna 	WRITE_ENTER(&vnetp->vrwlock);
15127b1f684aSSriharsha Basavapatna 
15137b1f684aSSriharsha Basavapatna 	if (vnetp->flags & VNET_STARTED) {
15147b1f684aSSriharsha Basavapatna 		RW_EXIT(&vnetp->vrwlock);
15157b1f684aSSriharsha Basavapatna 		cmn_err(CE_NOTE, "!vnet%d: Unable to process mtu "
15167b1f684aSSriharsha Basavapatna 		    "update as the device is plumbed\n",
15177b1f684aSSriharsha Basavapatna 		    vnetp->instance);
15187b1f684aSSriharsha Basavapatna 		return (EBUSY);
15197b1f684aSSriharsha Basavapatna 	}
15207b1f684aSSriharsha Basavapatna 
15217b1f684aSSriharsha Basavapatna 	/* update mtu in the mac layer */
15227b1f684aSSriharsha Basavapatna 	rv = mac_maxsdu_update(vnetp->mh, mtu);
15237b1f684aSSriharsha Basavapatna 	if (rv != 0) {
15247b1f684aSSriharsha Basavapatna 		RW_EXIT(&vnetp->vrwlock);
15257b1f684aSSriharsha Basavapatna 		cmn_err(CE_NOTE,
15267b1f684aSSriharsha Basavapatna 		    "!vnet%d: Unable to update mtu with mac layer\n",
15277b1f684aSSriharsha Basavapatna 		    vnetp->instance);
15287b1f684aSSriharsha Basavapatna 		return (EIO);
15297b1f684aSSriharsha Basavapatna 	}
15307b1f684aSSriharsha Basavapatna 
15317b1f684aSSriharsha Basavapatna 	vnetp->mtu = mtu;
15327b1f684aSSriharsha Basavapatna 
15337b1f684aSSriharsha Basavapatna 	RW_EXIT(&vnetp->vrwlock);
15347b1f684aSSriharsha Basavapatna 
15357b1f684aSSriharsha Basavapatna 	return (0);
15367b1f684aSSriharsha Basavapatna }
15377b1f684aSSriharsha Basavapatna 
15387b1f684aSSriharsha Basavapatna /*
15391107ea93SSriharsha Basavapatna  * Update the link state of vnet to the mac layer.
15401107ea93SSriharsha Basavapatna  */
15411107ea93SSriharsha Basavapatna void
15421107ea93SSriharsha Basavapatna vnet_link_update(vnet_t *vnetp, link_state_t link_state)
15431107ea93SSriharsha Basavapatna {
15441107ea93SSriharsha Basavapatna 	if (vnetp == NULL || vnetp->mh == NULL) {
15451107ea93SSriharsha Basavapatna 		return;
15461107ea93SSriharsha Basavapatna 	}
15471107ea93SSriharsha Basavapatna 
15481107ea93SSriharsha Basavapatna 	WRITE_ENTER(&vnetp->vrwlock);
15491107ea93SSriharsha Basavapatna 	if (vnetp->link_state == link_state) {
15501107ea93SSriharsha Basavapatna 		RW_EXIT(&vnetp->vrwlock);
15511107ea93SSriharsha Basavapatna 		return;
15521107ea93SSriharsha Basavapatna 	}
15531107ea93SSriharsha Basavapatna 	vnetp->link_state = link_state;
15541107ea93SSriharsha Basavapatna 	RW_EXIT(&vnetp->vrwlock);
15551107ea93SSriharsha Basavapatna 
15561107ea93SSriharsha Basavapatna 	mac_link_update(vnetp->mh, link_state);
15571107ea93SSriharsha Basavapatna }
15581107ea93SSriharsha Basavapatna 
15591107ea93SSriharsha Basavapatna /*
1560678453a8Sspeer  * vio_net_resource_reg -- An interface called to register a resource
1561678453a8Sspeer  *	with vnet.
1562678453a8Sspeer  *	macp -- a GLDv3 mac_register that has all the details of
1563678453a8Sspeer  *		a resource and its callbacks etc.
1564678453a8Sspeer  *	type -- resource type.
1565678453a8Sspeer  *	local_macaddr -- resource's MAC address. This is used to
1566678453a8Sspeer  *			 associate a resource with a corresponding vnet.
1567678453a8Sspeer  *	remote_macaddr -- remote side MAC address. This is ignored for
1568678453a8Sspeer  *			  the Hybrid resources.
1569678453a8Sspeer  *	vhp -- A handle returned to the caller.
1570678453a8Sspeer  *	vcb -- A set of callbacks provided to the callers.
1571678453a8Sspeer  */
1572678453a8Sspeer int vio_net_resource_reg(mac_register_t *macp, vio_net_res_type_t type,
1573678453a8Sspeer     ether_addr_t local_macaddr, ether_addr_t rem_macaddr, vio_net_handle_t *vhp,
1574678453a8Sspeer     vio_net_callbacks_t *vcb)
1575678453a8Sspeer {
1576678453a8Sspeer 	vnet_t		*vnetp;
1577678453a8Sspeer 	vnet_res_t	*vresp;
1578678453a8Sspeer 
1579678453a8Sspeer 	vresp = kmem_zalloc(sizeof (vnet_res_t), KM_SLEEP);
1580678453a8Sspeer 	ether_copy(local_macaddr, vresp->local_macaddr);
1581678453a8Sspeer 	ether_copy(rem_macaddr, vresp->rem_macaddr);
1582678453a8Sspeer 	vresp->type = type;
1583678453a8Sspeer 	bcopy(macp, &vresp->macreg, sizeof (mac_register_t));
1584678453a8Sspeer 
1585678453a8Sspeer 	DBG1(NULL, "Resource Registerig type=0%X\n", type);
1586678453a8Sspeer 
1587678453a8Sspeer 	READ_ENTER(&vnet_rw);
1588678453a8Sspeer 	vnetp = vnet_headp;
1589678453a8Sspeer 	while (vnetp != NULL) {
1590678453a8Sspeer 		if (VNET_MATCH_RES(vresp, vnetp)) {
1591678453a8Sspeer 			vresp->vnetp = vnetp;
15926b8fc343SWENTAO YANG 
15936b8fc343SWENTAO YANG 			/* Setup kstats for hio resource */
15946b8fc343SWENTAO YANG 			if (vresp->type == VIO_NET_RES_HYBRID) {
15956b8fc343SWENTAO YANG 				vresp->ksp = vnet_hio_setup_kstats(DRV_NAME,
15966b8fc343SWENTAO YANG 				    "hio", vresp);
15976b8fc343SWENTAO YANG 				if (vresp->ksp == NULL) {
15986b8fc343SWENTAO YANG 					cmn_err(CE_NOTE, "!vnet%d: Cannot "
15996b8fc343SWENTAO YANG 					    "create kstats for hio resource",
16006b8fc343SWENTAO YANG 					    vnetp->instance);
16016b8fc343SWENTAO YANG 				}
16026b8fc343SWENTAO YANG 			}
160363f531d1SSriharsha Basavapatna 			vnet_add_resource(vnetp, vresp);
1604678453a8Sspeer 			break;
1605678453a8Sspeer 		}
1606678453a8Sspeer 		vnetp = vnetp->nextp;
1607678453a8Sspeer 	}
1608678453a8Sspeer 	RW_EXIT(&vnet_rw);
1609678453a8Sspeer 	if (vresp->vnetp == NULL) {
1610678453a8Sspeer 		DWARN(NULL, "No vnet instance");
1611678453a8Sspeer 		kmem_free(vresp, sizeof (vnet_res_t));
1612678453a8Sspeer 		return (ENXIO);
1613678453a8Sspeer 	}
1614678453a8Sspeer 
1615678453a8Sspeer 	*vhp = vresp;
1616678453a8Sspeer 	vcb->vio_net_rx_cb = vnet_rx;
1617678453a8Sspeer 	vcb->vio_net_tx_update = vnet_tx_update;
1618678453a8Sspeer 	vcb->vio_net_report_err = vnet_handle_res_err;
1619678453a8Sspeer 
162063f531d1SSriharsha Basavapatna 	/* Bind the resource to pseudo ring(s) */
162163f531d1SSriharsha Basavapatna 	if (vnet_bind_rings(vresp) != 0) {
162263f531d1SSriharsha Basavapatna 		(void) vnet_rem_resource(vnetp, vresp);
162363f531d1SSriharsha Basavapatna 		vnet_hio_destroy_kstats(vresp->ksp);
162463f531d1SSriharsha Basavapatna 		KMEM_FREE(vresp);
162563f531d1SSriharsha Basavapatna 		return (1);
162663f531d1SSriharsha Basavapatna 	}
162763f531d1SSriharsha Basavapatna 
1628678453a8Sspeer 	/* Dispatch a task to start resources */
1629678453a8Sspeer 	vnet_dispatch_res_task(vnetp);
1630678453a8Sspeer 	return (0);
1631678453a8Sspeer }
1632678453a8Sspeer 
1633678453a8Sspeer /*
1634678453a8Sspeer  * vio_net_resource_unreg -- An interface to unregister a resource.
1635678453a8Sspeer  */
1636678453a8Sspeer void
1637678453a8Sspeer vio_net_resource_unreg(vio_net_handle_t vhp)
1638678453a8Sspeer {
1639678453a8Sspeer 	vnet_res_t	*vresp = (vnet_res_t *)vhp;
1640678453a8Sspeer 	vnet_t		*vnetp = vresp->vnetp;
1641678453a8Sspeer 
1642678453a8Sspeer 	DBG1(NULL, "Resource Registerig hdl=0x%p", vhp);
1643678453a8Sspeer 
1644678453a8Sspeer 	ASSERT(vnetp != NULL);
16455460ddbdSSriharsha Basavapatna 	/*
16465460ddbdSSriharsha Basavapatna 	 * Remove the resource from fdb; this ensures
16475460ddbdSSriharsha Basavapatna 	 * there are no references to the resource.
16485460ddbdSSriharsha Basavapatna 	 */
1649678453a8Sspeer 	vnet_fdbe_del(vnetp, vresp);
1650678453a8Sspeer 
165163f531d1SSriharsha Basavapatna 	vnet_unbind_rings(vresp);
165263f531d1SSriharsha Basavapatna 
16535460ddbdSSriharsha Basavapatna 	/* Now remove the resource from the list */
165463f531d1SSriharsha Basavapatna 	(void) vnet_rem_resource(vnetp, vresp);
165563f531d1SSriharsha Basavapatna 
165663f531d1SSriharsha Basavapatna 	vnet_hio_destroy_kstats(vresp->ksp);
165763f531d1SSriharsha Basavapatna 	KMEM_FREE(vresp);
165863f531d1SSriharsha Basavapatna }
165963f531d1SSriharsha Basavapatna 
166063f531d1SSriharsha Basavapatna static void
166163f531d1SSriharsha Basavapatna vnet_add_resource(vnet_t *vnetp, vnet_res_t *vresp)
166263f531d1SSriharsha Basavapatna {
166363f531d1SSriharsha Basavapatna 	WRITE_ENTER(&vnetp->vrwlock);
166463f531d1SSriharsha Basavapatna 	vresp->nextp = vnetp->vres_list;
166563f531d1SSriharsha Basavapatna 	vnetp->vres_list = vresp;
166663f531d1SSriharsha Basavapatna 	RW_EXIT(&vnetp->vrwlock);
166763f531d1SSriharsha Basavapatna }
166863f531d1SSriharsha Basavapatna 
166963f531d1SSriharsha Basavapatna static vnet_res_t *
167063f531d1SSriharsha Basavapatna vnet_rem_resource(vnet_t *vnetp, vnet_res_t *vresp)
167163f531d1SSriharsha Basavapatna {
167263f531d1SSriharsha Basavapatna 	vnet_res_t	*vrp;
167363f531d1SSriharsha Basavapatna 
1674678453a8Sspeer 	WRITE_ENTER(&vnetp->vrwlock);
1675678453a8Sspeer 	if (vresp == vnetp->vres_list) {
1676678453a8Sspeer 		vnetp->vres_list = vresp->nextp;
1677678453a8Sspeer 	} else {
1678678453a8Sspeer 		vrp = vnetp->vres_list;
1679678453a8Sspeer 		while (vrp->nextp != NULL) {
1680678453a8Sspeer 			if (vrp->nextp == vresp) {
1681678453a8Sspeer 				vrp->nextp = vresp->nextp;
1682678453a8Sspeer 				break;
1683678453a8Sspeer 			}
1684678453a8Sspeer 			vrp = vrp->nextp;
1685678453a8Sspeer 		}
1686678453a8Sspeer 	}
1687678453a8Sspeer 	vresp->vnetp = NULL;
1688678453a8Sspeer 	vresp->nextp = NULL;
168963f531d1SSriharsha Basavapatna 
1690678453a8Sspeer 	RW_EXIT(&vnetp->vrwlock);
169163f531d1SSriharsha Basavapatna 
169263f531d1SSriharsha Basavapatna 	return (vresp);
1693678453a8Sspeer }
1694678453a8Sspeer 
1695678453a8Sspeer /*
1696678453a8Sspeer  * vnet_dds_rx -- an interface called by vgen to DDS messages.
1697678453a8Sspeer  */
1698678453a8Sspeer void
1699678453a8Sspeer vnet_dds_rx(void *arg, void *dmsg)
1700678453a8Sspeer {
1701678453a8Sspeer 	vnet_t *vnetp = arg;
1702678453a8Sspeer 	vdds_process_dds_msg(vnetp, dmsg);
1703678453a8Sspeer }
1704678453a8Sspeer 
1705678453a8Sspeer /*
1706678453a8Sspeer  * vnet_send_dds_msg -- An interface provided to DDS to send
1707678453a8Sspeer  *	DDS messages. This simply sends meessages via vgen.
1708678453a8Sspeer  */
1709678453a8Sspeer int
1710678453a8Sspeer vnet_send_dds_msg(vnet_t *vnetp, void *dmsg)
1711678453a8Sspeer {
1712678453a8Sspeer 	int rv;
1713678453a8Sspeer 
1714678453a8Sspeer 	if (vnetp->vgenhdl != NULL) {
1715678453a8Sspeer 		rv = vgen_dds_tx(vnetp->vgenhdl, dmsg);
1716678453a8Sspeer 	}
1717678453a8Sspeer 	return (rv);
1718678453a8Sspeer }
1719678453a8Sspeer 
1720678453a8Sspeer /*
17216d6de4eeSWENTAO YANG  * vnet_cleanup_hio -- an interface called by vgen to cleanup hio resources.
17226d6de4eeSWENTAO YANG  */
17236d6de4eeSWENTAO YANG void
17246d6de4eeSWENTAO YANG vnet_dds_cleanup_hio(vnet_t *vnetp)
17256d6de4eeSWENTAO YANG {
17266d6de4eeSWENTAO YANG 	vdds_cleanup_hio(vnetp);
17276d6de4eeSWENTAO YANG }
17286d6de4eeSWENTAO YANG 
17296d6de4eeSWENTAO YANG /*
1730678453a8Sspeer  * vnet_handle_res_err -- A callback function called by a resource
1731678453a8Sspeer  *	to report an error. For example, vgen can call to report
1732678453a8Sspeer  *	an LDC down/reset event. This will trigger cleanup of associated
1733678453a8Sspeer  *	Hybrid resource.
1734678453a8Sspeer  */
1735678453a8Sspeer /* ARGSUSED */
1736678453a8Sspeer static void
1737678453a8Sspeer vnet_handle_res_err(vio_net_handle_t vrh, vio_net_err_val_t err)
1738678453a8Sspeer {
1739678453a8Sspeer 	vnet_res_t *vresp = (vnet_res_t *)vrh;
1740678453a8Sspeer 	vnet_t *vnetp = vresp->vnetp;
1741678453a8Sspeer 
1742678453a8Sspeer 	if (vnetp == NULL) {
1743678453a8Sspeer 		return;
1744678453a8Sspeer 	}
1745678453a8Sspeer 	if ((vresp->type != VIO_NET_RES_LDC_SERVICE) &&
1746678453a8Sspeer 	    (vresp->type != VIO_NET_RES_HYBRID)) {
1747678453a8Sspeer 		return;
1748678453a8Sspeer 	}
17496d6de4eeSWENTAO YANG 
17506d6de4eeSWENTAO YANG 	vdds_cleanup_hio(vnetp);
1751678453a8Sspeer }
1752678453a8Sspeer 
1753678453a8Sspeer /*
1754678453a8Sspeer  * vnet_dispatch_res_task -- A function to dispatch tasks start resources.
1755678453a8Sspeer  */
1756678453a8Sspeer static void
1757678453a8Sspeer vnet_dispatch_res_task(vnet_t *vnetp)
1758678453a8Sspeer {
1759678453a8Sspeer 	int rv;
1760678453a8Sspeer 
17618b923298SZach Kissel 	/*
17628b923298SZach Kissel 	 * Dispatch the task. It could be the case that vnetp->flags does
17638b923298SZach Kissel 	 * not have VNET_STARTED set. This is ok as vnet_rest_start_task()
17645460ddbdSSriharsha Basavapatna 	 * can abort the task when the task is started. See related comments
17655460ddbdSSriharsha Basavapatna 	 * in vnet_m_stop() and vnet_stop_resources().
17668b923298SZach Kissel 	 */
1767678453a8Sspeer 	rv = ddi_taskq_dispatch(vnetp->taskqp, vnet_res_start_task,
1768678453a8Sspeer 	    vnetp, DDI_NOSLEEP);
1769678453a8Sspeer 	if (rv != DDI_SUCCESS) {
1770678453a8Sspeer 		cmn_err(CE_WARN,
1771678453a8Sspeer 		    "vnet%d:Can't dispatch start resource task",
1772678453a8Sspeer 		    vnetp->instance);
1773678453a8Sspeer 	}
1774678453a8Sspeer }
1775678453a8Sspeer 
1776678453a8Sspeer /*
1777678453a8Sspeer  * vnet_res_start_task -- A taskq callback function that starts a resource.
1778678453a8Sspeer  */
1779678453a8Sspeer static void
1780678453a8Sspeer vnet_res_start_task(void *arg)
1781678453a8Sspeer {
1782678453a8Sspeer 	vnet_t *vnetp = arg;
1783678453a8Sspeer 
1784678453a8Sspeer 	WRITE_ENTER(&vnetp->vrwlock);
1785678453a8Sspeer 	if (vnetp->flags & VNET_STARTED) {
1786678453a8Sspeer 		vnet_start_resources(vnetp);
1787678453a8Sspeer 	}
1788678453a8Sspeer 	RW_EXIT(&vnetp->vrwlock);
1789678453a8Sspeer }
1790678453a8Sspeer 
1791678453a8Sspeer /*
1792678453a8Sspeer  * vnet_start_resources -- starts all resources associated with
1793678453a8Sspeer  *	a vnet.
1794678453a8Sspeer  */
1795678453a8Sspeer static void
1796678453a8Sspeer vnet_start_resources(vnet_t *vnetp)
1797678453a8Sspeer {
1798678453a8Sspeer 	mac_register_t	*macp;
1799678453a8Sspeer 	mac_callbacks_t	*cbp;
1800678453a8Sspeer 	vnet_res_t	*vresp;
1801678453a8Sspeer 	int rv;
1802678453a8Sspeer 
1803678453a8Sspeer 	DBG1(vnetp, "enter\n");
1804678453a8Sspeer 
18055460ddbdSSriharsha Basavapatna 	ASSERT(RW_WRITE_HELD(&vnetp->vrwlock));
18065460ddbdSSriharsha Basavapatna 
1807678453a8Sspeer 	for (vresp = vnetp->vres_list; vresp != NULL; vresp = vresp->nextp) {
1808678453a8Sspeer 		/* skip if it is already started */
1809678453a8Sspeer 		if (vresp->flags & VNET_STARTED) {
1810678453a8Sspeer 			continue;
1811678453a8Sspeer 		}
1812678453a8Sspeer 		macp = &vresp->macreg;
1813678453a8Sspeer 		cbp = macp->m_callbacks;
1814678453a8Sspeer 		rv = cbp->mc_start(macp->m_driver);
1815678453a8Sspeer 		if (rv == 0) {
1816678453a8Sspeer 			/*
1817678453a8Sspeer 			 * Successfully started the resource, so now
1818678453a8Sspeer 			 * add it to the fdb.
1819678453a8Sspeer 			 */
1820678453a8Sspeer 			vresp->flags |= VNET_STARTED;
1821678453a8Sspeer 			vnet_fdbe_add(vnetp, vresp);
1822678453a8Sspeer 		}
1823678453a8Sspeer 	}
1824678453a8Sspeer 
1825678453a8Sspeer 	DBG1(vnetp, "exit\n");
1826678453a8Sspeer 
1827678453a8Sspeer }
1828678453a8Sspeer 
1829678453a8Sspeer /*
1830678453a8Sspeer  * vnet_stop_resources -- stop all resources associated with a vnet.
1831678453a8Sspeer  */
1832678453a8Sspeer static void
1833678453a8Sspeer vnet_stop_resources(vnet_t *vnetp)
1834678453a8Sspeer {
1835678453a8Sspeer 	vnet_res_t	*vresp;
1836678453a8Sspeer 	mac_register_t	*macp;
1837678453a8Sspeer 	mac_callbacks_t	*cbp;
1838678453a8Sspeer 
1839678453a8Sspeer 	DBG1(vnetp, "enter\n");
1840678453a8Sspeer 
18415460ddbdSSriharsha Basavapatna 	ASSERT(RW_WRITE_HELD(&vnetp->vrwlock));
18425460ddbdSSriharsha Basavapatna 
1843678453a8Sspeer 	for (vresp = vnetp->vres_list; vresp != NULL; ) {
1844678453a8Sspeer 		if (vresp->flags & VNET_STARTED) {
18455460ddbdSSriharsha Basavapatna 			/*
18465460ddbdSSriharsha Basavapatna 			 * Release the lock while invoking mc_stop() of the
18475460ddbdSSriharsha Basavapatna 			 * underlying resource. We hold a reference to this
18485460ddbdSSriharsha Basavapatna 			 * resource to prevent being removed from the list in
18495460ddbdSSriharsha Basavapatna 			 * vio_net_resource_unreg(). Note that new resources
18505460ddbdSSriharsha Basavapatna 			 * can be added to the head of the list while the lock
18515460ddbdSSriharsha Basavapatna 			 * is released, but they won't be started, as
18525460ddbdSSriharsha Basavapatna 			 * VNET_STARTED flag has been cleared for the vnet
18535460ddbdSSriharsha Basavapatna 			 * device in vnet_m_stop(). Also, while the lock is
18545460ddbdSSriharsha Basavapatna 			 * released a resource could be removed from the list
18555460ddbdSSriharsha Basavapatna 			 * in vio_net_resource_unreg(); but that is ok, as we
18565460ddbdSSriharsha Basavapatna 			 * re-acquire the lock and only then access the forward
18575460ddbdSSriharsha Basavapatna 			 * link (vresp->nextp) to continue with the next
18585460ddbdSSriharsha Basavapatna 			 * resource.
18595460ddbdSSriharsha Basavapatna 			 */
18605460ddbdSSriharsha Basavapatna 			vresp->flags &= ~VNET_STARTED;
18615460ddbdSSriharsha Basavapatna 			vresp->flags |= VNET_STOPPING;
1862678453a8Sspeer 			macp = &vresp->macreg;
1863678453a8Sspeer 			cbp = macp->m_callbacks;
18645460ddbdSSriharsha Basavapatna 			VNET_FDBE_REFHOLD(vresp);
18655460ddbdSSriharsha Basavapatna 			RW_EXIT(&vnetp->vrwlock);
18665460ddbdSSriharsha Basavapatna 
1867678453a8Sspeer 			cbp->mc_stop(macp->m_driver);
18685460ddbdSSriharsha Basavapatna 
18695460ddbdSSriharsha Basavapatna 			WRITE_ENTER(&vnetp->vrwlock);
18705460ddbdSSriharsha Basavapatna 			vresp->flags &= ~VNET_STOPPING;
18715460ddbdSSriharsha Basavapatna 			VNET_FDBE_REFRELE(vresp);
1872678453a8Sspeer 		}
18735460ddbdSSriharsha Basavapatna 		vresp = vresp->nextp;
1874678453a8Sspeer 	}
1875678453a8Sspeer 	DBG1(vnetp, "exit\n");
1876678453a8Sspeer }
18776ab6cb20SWENTAO YANG 
18786ab6cb20SWENTAO YANG /*
18796ab6cb20SWENTAO YANG  * Setup kstats for the HIO statistics.
18806ab6cb20SWENTAO YANG  * NOTE: the synchronization for the statistics is the
18816ab6cb20SWENTAO YANG  * responsibility of the caller.
18826ab6cb20SWENTAO YANG  */
18836ab6cb20SWENTAO YANG kstat_t *
18846ab6cb20SWENTAO YANG vnet_hio_setup_kstats(char *ks_mod, char *ks_name, vnet_res_t *vresp)
18856ab6cb20SWENTAO YANG {
18866ab6cb20SWENTAO YANG 	kstat_t *ksp;
18876ab6cb20SWENTAO YANG 	vnet_t *vnetp = vresp->vnetp;
18886ab6cb20SWENTAO YANG 	vnet_hio_kstats_t *hiokp;
18896ab6cb20SWENTAO YANG 	size_t size;
18906ab6cb20SWENTAO YANG 
18916ab6cb20SWENTAO YANG 	ASSERT(vnetp != NULL);
18926ab6cb20SWENTAO YANG 	size = sizeof (vnet_hio_kstats_t) / sizeof (kstat_named_t);
18936ab6cb20SWENTAO YANG 	ksp = kstat_create(ks_mod, vnetp->instance, ks_name, "net",
18946ab6cb20SWENTAO YANG 	    KSTAT_TYPE_NAMED, size, 0);
18956ab6cb20SWENTAO YANG 	if (ksp == NULL) {
18966ab6cb20SWENTAO YANG 		return (NULL);
18976ab6cb20SWENTAO YANG 	}
18986ab6cb20SWENTAO YANG 
18996ab6cb20SWENTAO YANG 	hiokp = (vnet_hio_kstats_t *)ksp->ks_data;
19006ab6cb20SWENTAO YANG 	kstat_named_init(&hiokp->ipackets,		"ipackets",
19016ab6cb20SWENTAO YANG 	    KSTAT_DATA_ULONG);
19026ab6cb20SWENTAO YANG 	kstat_named_init(&hiokp->ierrors,		"ierrors",
19036ab6cb20SWENTAO YANG 	    KSTAT_DATA_ULONG);
19046ab6cb20SWENTAO YANG 	kstat_named_init(&hiokp->opackets,		"opackets",
19056ab6cb20SWENTAO YANG 	    KSTAT_DATA_ULONG);
19066ab6cb20SWENTAO YANG 	kstat_named_init(&hiokp->oerrors,		"oerrors",
19076ab6cb20SWENTAO YANG 	    KSTAT_DATA_ULONG);
19086ab6cb20SWENTAO YANG 
19096ab6cb20SWENTAO YANG 
19106ab6cb20SWENTAO YANG 	/* MIB II kstat variables */
19116ab6cb20SWENTAO YANG 	kstat_named_init(&hiokp->rbytes,		"rbytes",
19126ab6cb20SWENTAO YANG 	    KSTAT_DATA_ULONG);
19136ab6cb20SWENTAO YANG 	kstat_named_init(&hiokp->obytes,		"obytes",
19146ab6cb20SWENTAO YANG 	    KSTAT_DATA_ULONG);
19156ab6cb20SWENTAO YANG 	kstat_named_init(&hiokp->multircv,		"multircv",
19166ab6cb20SWENTAO YANG 	    KSTAT_DATA_ULONG);
19176ab6cb20SWENTAO YANG 	kstat_named_init(&hiokp->multixmt,		"multixmt",
19186ab6cb20SWENTAO YANG 	    KSTAT_DATA_ULONG);
19196ab6cb20SWENTAO YANG 	kstat_named_init(&hiokp->brdcstrcv,		"brdcstrcv",
19206ab6cb20SWENTAO YANG 	    KSTAT_DATA_ULONG);
19216ab6cb20SWENTAO YANG 	kstat_named_init(&hiokp->brdcstxmt,		"brdcstxmt",
19226ab6cb20SWENTAO YANG 	    KSTAT_DATA_ULONG);
19236ab6cb20SWENTAO YANG 	kstat_named_init(&hiokp->norcvbuf,		"norcvbuf",
19246ab6cb20SWENTAO YANG 	    KSTAT_DATA_ULONG);
19256ab6cb20SWENTAO YANG 	kstat_named_init(&hiokp->noxmtbuf,		"noxmtbuf",
19266ab6cb20SWENTAO YANG 	    KSTAT_DATA_ULONG);
19276ab6cb20SWENTAO YANG 
19286ab6cb20SWENTAO YANG 	ksp->ks_update = vnet_hio_update_kstats;
19296ab6cb20SWENTAO YANG 	ksp->ks_private = (void *)vresp;
19306ab6cb20SWENTAO YANG 	kstat_install(ksp);
19316ab6cb20SWENTAO YANG 	return (ksp);
19326ab6cb20SWENTAO YANG }
19336ab6cb20SWENTAO YANG 
19346ab6cb20SWENTAO YANG /*
19356ab6cb20SWENTAO YANG  * Destroy kstats.
19366ab6cb20SWENTAO YANG  */
19376ab6cb20SWENTAO YANG static void
19386ab6cb20SWENTAO YANG vnet_hio_destroy_kstats(kstat_t *ksp)
19396ab6cb20SWENTAO YANG {
19406ab6cb20SWENTAO YANG 	if (ksp != NULL)
19416ab6cb20SWENTAO YANG 		kstat_delete(ksp);
19426ab6cb20SWENTAO YANG }
19436ab6cb20SWENTAO YANG 
19446ab6cb20SWENTAO YANG /*
19456ab6cb20SWENTAO YANG  * Update the kstats.
19466ab6cb20SWENTAO YANG  */
19476ab6cb20SWENTAO YANG static int
19486ab6cb20SWENTAO YANG vnet_hio_update_kstats(kstat_t *ksp, int rw)
19496ab6cb20SWENTAO YANG {
19506ab6cb20SWENTAO YANG 	vnet_t *vnetp;
19516ab6cb20SWENTAO YANG 	vnet_res_t *vresp;
19526ab6cb20SWENTAO YANG 	vnet_hio_stats_t statsp;
19536ab6cb20SWENTAO YANG 	vnet_hio_kstats_t *hiokp;
19546ab6cb20SWENTAO YANG 
19556ab6cb20SWENTAO YANG 	vresp = (vnet_res_t *)ksp->ks_private;
19566ab6cb20SWENTAO YANG 	vnetp = vresp->vnetp;
19576ab6cb20SWENTAO YANG 
19586ab6cb20SWENTAO YANG 	bzero(&statsp, sizeof (vnet_hio_stats_t));
19596ab6cb20SWENTAO YANG 
19606ab6cb20SWENTAO YANG 	READ_ENTER(&vnetp->vsw_fp_rw);
19616ab6cb20SWENTAO YANG 	if (vnetp->hio_fp == NULL) {
19626ab6cb20SWENTAO YANG 		/* not using hio resources, just return */
19636ab6cb20SWENTAO YANG 		RW_EXIT(&vnetp->vsw_fp_rw);
19646ab6cb20SWENTAO YANG 		return (0);
19656ab6cb20SWENTAO YANG 	}
19666ab6cb20SWENTAO YANG 	VNET_FDBE_REFHOLD(vnetp->hio_fp);
19676ab6cb20SWENTAO YANG 	RW_EXIT(&vnetp->vsw_fp_rw);
19686ab6cb20SWENTAO YANG 	vnet_hio_get_stats(vnetp->hio_fp, &statsp);
19696ab6cb20SWENTAO YANG 	VNET_FDBE_REFRELE(vnetp->hio_fp);
19706ab6cb20SWENTAO YANG 
19716ab6cb20SWENTAO YANG 	hiokp = (vnet_hio_kstats_t *)ksp->ks_data;
19726ab6cb20SWENTAO YANG 
19736ab6cb20SWENTAO YANG 	if (rw == KSTAT_READ) {
19746ab6cb20SWENTAO YANG 		/* Link Input/Output stats */
19756ab6cb20SWENTAO YANG 		hiokp->ipackets.value.ul	= (uint32_t)statsp.ipackets;
19766ab6cb20SWENTAO YANG 		hiokp->ipackets64.value.ull	= statsp.ipackets;
19776ab6cb20SWENTAO YANG 		hiokp->ierrors.value.ul		= statsp.ierrors;
19786ab6cb20SWENTAO YANG 		hiokp->opackets.value.ul	= (uint32_t)statsp.opackets;
19796ab6cb20SWENTAO YANG 		hiokp->opackets64.value.ull	= statsp.opackets;
19806ab6cb20SWENTAO YANG 		hiokp->oerrors.value.ul		= statsp.oerrors;
19816ab6cb20SWENTAO YANG 
19826ab6cb20SWENTAO YANG 		/* MIB II kstat variables */
19836ab6cb20SWENTAO YANG 		hiokp->rbytes.value.ul		= (uint32_t)statsp.rbytes;
19846ab6cb20SWENTAO YANG 		hiokp->rbytes64.value.ull	= statsp.rbytes;
19856ab6cb20SWENTAO YANG 		hiokp->obytes.value.ul		= (uint32_t)statsp.obytes;
19866ab6cb20SWENTAO YANG 		hiokp->obytes64.value.ull	= statsp.obytes;
19876ab6cb20SWENTAO YANG 		hiokp->multircv.value.ul	= statsp.multircv;
19886ab6cb20SWENTAO YANG 		hiokp->multixmt.value.ul	= statsp.multixmt;
19896ab6cb20SWENTAO YANG 		hiokp->brdcstrcv.value.ul	= statsp.brdcstrcv;
19906ab6cb20SWENTAO YANG 		hiokp->brdcstxmt.value.ul	= statsp.brdcstxmt;
19916ab6cb20SWENTAO YANG 		hiokp->norcvbuf.value.ul	= statsp.norcvbuf;
19926ab6cb20SWENTAO YANG 		hiokp->noxmtbuf.value.ul	= statsp.noxmtbuf;
19936ab6cb20SWENTAO YANG 	} else {
19946ab6cb20SWENTAO YANG 		return (EACCES);
19956ab6cb20SWENTAO YANG 	}
19966ab6cb20SWENTAO YANG 
19976ab6cb20SWENTAO YANG 	return (0);
19986ab6cb20SWENTAO YANG }
19996ab6cb20SWENTAO YANG 
20006ab6cb20SWENTAO YANG static void
20016ab6cb20SWENTAO YANG vnet_hio_get_stats(vnet_res_t *vresp, vnet_hio_stats_t *statsp)
20026ab6cb20SWENTAO YANG {
20036ab6cb20SWENTAO YANG 	mac_register_t		*macp;
20046ab6cb20SWENTAO YANG 	mac_callbacks_t		*cbp;
20056ab6cb20SWENTAO YANG 	uint64_t		val;
20066ab6cb20SWENTAO YANG 	int			stat;
20076ab6cb20SWENTAO YANG 
20086ab6cb20SWENTAO YANG 	/*
20096ab6cb20SWENTAO YANG 	 * get the specified statistics from the underlying nxge.
20106ab6cb20SWENTAO YANG 	 */
20116ab6cb20SWENTAO YANG 	macp = &vresp->macreg;
20126ab6cb20SWENTAO YANG 	cbp = macp->m_callbacks;
20136ab6cb20SWENTAO YANG 	for (stat = MAC_STAT_MIN; stat < MAC_STAT_OVERFLOWS; stat++) {
20146ab6cb20SWENTAO YANG 		if (cbp->mc_getstat(macp->m_driver, stat, &val) == 0) {
20156ab6cb20SWENTAO YANG 			switch (stat) {
20166ab6cb20SWENTAO YANG 			case MAC_STAT_IPACKETS:
20176ab6cb20SWENTAO YANG 				statsp->ipackets = val;
20186ab6cb20SWENTAO YANG 				break;
20196ab6cb20SWENTAO YANG 
20206ab6cb20SWENTAO YANG 			case MAC_STAT_IERRORS:
20216ab6cb20SWENTAO YANG 				statsp->ierrors = val;
20226ab6cb20SWENTAO YANG 				break;
20236ab6cb20SWENTAO YANG 
20246ab6cb20SWENTAO YANG 			case MAC_STAT_OPACKETS:
20256ab6cb20SWENTAO YANG 				statsp->opackets = val;
20266ab6cb20SWENTAO YANG 				break;
20276ab6cb20SWENTAO YANG 
20286ab6cb20SWENTAO YANG 			case MAC_STAT_OERRORS:
20296ab6cb20SWENTAO YANG 				statsp->oerrors = val;
20306ab6cb20SWENTAO YANG 				break;
20316ab6cb20SWENTAO YANG 
20326ab6cb20SWENTAO YANG 			case MAC_STAT_RBYTES:
20336ab6cb20SWENTAO YANG 				statsp->rbytes = val;
20346ab6cb20SWENTAO YANG 				break;
20356ab6cb20SWENTAO YANG 
20366ab6cb20SWENTAO YANG 			case MAC_STAT_OBYTES:
20376ab6cb20SWENTAO YANG 				statsp->obytes = val;
20386ab6cb20SWENTAO YANG 				break;
20396ab6cb20SWENTAO YANG 
20406ab6cb20SWENTAO YANG 			case MAC_STAT_MULTIRCV:
20416ab6cb20SWENTAO YANG 				statsp->multircv = val;
20426ab6cb20SWENTAO YANG 				break;
20436ab6cb20SWENTAO YANG 
20446ab6cb20SWENTAO YANG 			case MAC_STAT_MULTIXMT:
20456ab6cb20SWENTAO YANG 				statsp->multixmt = val;
20466ab6cb20SWENTAO YANG 				break;
20476ab6cb20SWENTAO YANG 
20486ab6cb20SWENTAO YANG 			case MAC_STAT_BRDCSTRCV:
20496ab6cb20SWENTAO YANG 				statsp->brdcstrcv = val;
20506ab6cb20SWENTAO YANG 				break;
20516ab6cb20SWENTAO YANG 
20526ab6cb20SWENTAO YANG 			case MAC_STAT_BRDCSTXMT:
20536ab6cb20SWENTAO YANG 				statsp->brdcstxmt = val;
20546ab6cb20SWENTAO YANG 				break;
20556ab6cb20SWENTAO YANG 
20566ab6cb20SWENTAO YANG 			case MAC_STAT_NOXMTBUF:
20576ab6cb20SWENTAO YANG 				statsp->noxmtbuf = val;
20586ab6cb20SWENTAO YANG 				break;
20596ab6cb20SWENTAO YANG 
20606ab6cb20SWENTAO YANG 			case MAC_STAT_NORCVBUF:
20616ab6cb20SWENTAO YANG 				statsp->norcvbuf = val;
20626ab6cb20SWENTAO YANG 				break;
20636ab6cb20SWENTAO YANG 
20646ab6cb20SWENTAO YANG 			default:
20656ab6cb20SWENTAO YANG 				/*
20666ab6cb20SWENTAO YANG 				 * parameters not interested.
20676ab6cb20SWENTAO YANG 				 */
20686ab6cb20SWENTAO YANG 				break;
20696ab6cb20SWENTAO YANG 			}
20706ab6cb20SWENTAO YANG 		}
20716ab6cb20SWENTAO YANG 	}
20726ab6cb20SWENTAO YANG }
20731107ea93SSriharsha Basavapatna 
207463f531d1SSriharsha Basavapatna static boolean_t
207563f531d1SSriharsha Basavapatna vnet_m_capab(void *arg, mac_capab_t cap, void *cap_data)
207663f531d1SSriharsha Basavapatna {
207763f531d1SSriharsha Basavapatna 	vnet_t	*vnetp = (vnet_t *)arg;
207863f531d1SSriharsha Basavapatna 
207963f531d1SSriharsha Basavapatna 	if (vnetp == NULL) {
208063f531d1SSriharsha Basavapatna 		return (0);
208163f531d1SSriharsha Basavapatna 	}
208263f531d1SSriharsha Basavapatna 
208363f531d1SSriharsha Basavapatna 	switch (cap) {
208463f531d1SSriharsha Basavapatna 
208563f531d1SSriharsha Basavapatna 	case MAC_CAPAB_RINGS: {
208663f531d1SSriharsha Basavapatna 
208763f531d1SSriharsha Basavapatna 		mac_capab_rings_t *cap_rings = cap_data;
208863f531d1SSriharsha Basavapatna 		/*
208963f531d1SSriharsha Basavapatna 		 * Rings Capability Notes:
209063f531d1SSriharsha Basavapatna 		 * We advertise rings to make use of the rings framework in
209163f531d1SSriharsha Basavapatna 		 * gldv3 mac layer, to improve the performance. This is
209263f531d1SSriharsha Basavapatna 		 * specifically needed when a Hybrid resource (with multiple
209363f531d1SSriharsha Basavapatna 		 * tx/rx hardware rings) is assigned to a vnet device. We also
209463f531d1SSriharsha Basavapatna 		 * leverage this for the normal case when no Hybrid resource is
209563f531d1SSriharsha Basavapatna 		 * assigned.
209663f531d1SSriharsha Basavapatna 		 *
209763f531d1SSriharsha Basavapatna 		 * Ring Allocation:
209863f531d1SSriharsha Basavapatna 		 * - TX path:
209963f531d1SSriharsha Basavapatna 		 * We expose a pseudo ring group with 2 pseudo tx rings (as
210063f531d1SSriharsha Basavapatna 		 * currently HybridIO exports only 2 rings) In the normal case,
210163f531d1SSriharsha Basavapatna 		 * transmit traffic that comes down to the driver through the
210263f531d1SSriharsha Basavapatna 		 * mri_tx (vnet_tx_ring_send()) entry point goes through the
210363f531d1SSriharsha Basavapatna 		 * distributed switching algorithm in vnet and gets transmitted
210463f531d1SSriharsha Basavapatna 		 * over a port/LDC in the vgen layer to either the vswitch or a
210563f531d1SSriharsha Basavapatna 		 * peer vnet. If and when a Hybrid resource is assigned to the
210663f531d1SSriharsha Basavapatna 		 * vnet, we obtain the tx ring information of the Hybrid device
210763f531d1SSriharsha Basavapatna 		 * (nxge) and map the pseudo rings 1:1 to the 2 hw tx rings.
210863f531d1SSriharsha Basavapatna 		 * Traffic being sent over the Hybrid resource by the mac layer
210963f531d1SSriharsha Basavapatna 		 * gets spread across both hw rings, as they are mapped to the
211063f531d1SSriharsha Basavapatna 		 * 2 pseudo tx rings in vnet.
211163f531d1SSriharsha Basavapatna 		 *
211263f531d1SSriharsha Basavapatna 		 * - RX path:
211363f531d1SSriharsha Basavapatna 		 * We expose a pseudo ring group with 3 pseudo rx rings (static
211463f531d1SSriharsha Basavapatna 		 * rings) initially. The first (default) pseudo rx ring is
211563f531d1SSriharsha Basavapatna 		 * reserved for the resource that connects to the vswitch
211663f531d1SSriharsha Basavapatna 		 * service. The next 2 rings are reserved for a Hybrid resource
211763f531d1SSriharsha Basavapatna 		 * that may be assigned to the vnet device. If and when a
211863f531d1SSriharsha Basavapatna 		 * Hybrid resource is assigned to the vnet, we obtain the rx
211963f531d1SSriharsha Basavapatna 		 * ring information of the Hybrid device (nxge) and map these
212063f531d1SSriharsha Basavapatna 		 * pseudo rings 1:1 to the 2 hw rx rings. For each additional
212163f531d1SSriharsha Basavapatna 		 * resource that connects to a peer vnet, we dynamically
212263f531d1SSriharsha Basavapatna 		 * allocate a pseudo rx ring and map it to that resource, when
212363f531d1SSriharsha Basavapatna 		 * the resource gets added; and the pseudo rx ring is
212463f531d1SSriharsha Basavapatna 		 * dynamically registered with the upper mac layer. We do the
212563f531d1SSriharsha Basavapatna 		 * reverse and unregister the ring with the mac layer when
212663f531d1SSriharsha Basavapatna 		 * the resource gets removed.
212763f531d1SSriharsha Basavapatna 		 *
212863f531d1SSriharsha Basavapatna 		 * Synchronization notes:
212963f531d1SSriharsha Basavapatna 		 * We don't need any lock to protect members of ring structure,
213063f531d1SSriharsha Basavapatna 		 * specifically ringp->hw_rh, in either the TX or the RX ring,
213163f531d1SSriharsha Basavapatna 		 * as explained below.
213263f531d1SSriharsha Basavapatna 		 * - TX ring:
213363f531d1SSriharsha Basavapatna 		 * ring->hw_rh is initialized only when a Hybrid resource is
213463f531d1SSriharsha Basavapatna 		 * associated; and gets referenced only in vnet_hio_tx(). The
213563f531d1SSriharsha Basavapatna 		 * Hybrid resource itself is available in fdb only after tx
213663f531d1SSriharsha Basavapatna 		 * hwrings are found and mapped; i.e, in vio_net_resource_reg()
213763f531d1SSriharsha Basavapatna 		 * we call vnet_bind_rings() first and then call
213863f531d1SSriharsha Basavapatna 		 * vnet_start_resources() which adds an entry to fdb. For
213963f531d1SSriharsha Basavapatna 		 * traffic going over LDC resources, we don't reference
214063f531d1SSriharsha Basavapatna 		 * ring->hw_rh at all.
214163f531d1SSriharsha Basavapatna 		 * - RX ring:
214263f531d1SSriharsha Basavapatna 		 * For rings mapped to Hybrid resource ring->hw_rh is
214363f531d1SSriharsha Basavapatna 		 * initialized and only then do we add the rx callback for
214463f531d1SSriharsha Basavapatna 		 * the underlying Hybrid resource; we disable callbacks before
214563f531d1SSriharsha Basavapatna 		 * we unmap ring->hw_rh. For rings mapped to LDC resources, we
214663f531d1SSriharsha Basavapatna 		 * stop the rx callbacks (in vgen) before we remove ring->hw_rh
214763f531d1SSriharsha Basavapatna 		 * (vio_net_resource_unreg()).
21480dc2366fSVenugopal Iyer 		 * Also, we access ring->hw_rh in vnet_rx_ring_stat().
21490dc2366fSVenugopal Iyer 		 * Note that for rings mapped to Hybrid resource, though the
21500dc2366fSVenugopal Iyer 		 * rings are statically registered with the mac layer, its
21510dc2366fSVenugopal Iyer 		 * hardware ring mapping (ringp->hw_rh) can be torn down in
21520dc2366fSVenugopal Iyer 		 * vnet_unbind_hwrings() while the kstat operation is in
21530dc2366fSVenugopal Iyer 		 * progress. To protect against this, we hold a reference to
21540dc2366fSVenugopal Iyer 		 * the resource in FDB; this ensures that the thread in
21550dc2366fSVenugopal Iyer 		 * vio_net_resource_unreg() waits for the reference to be
21560dc2366fSVenugopal Iyer 		 * dropped before unbinding the ring.
21570dc2366fSVenugopal Iyer 		 *
21580dc2366fSVenugopal Iyer 		 * We don't need to do this for rings mapped to LDC resources.
21590dc2366fSVenugopal Iyer 		 * These rings are registered/unregistered dynamically with
21600dc2366fSVenugopal Iyer 		 * the mac layer and so any attempt to unregister the ring
21610dc2366fSVenugopal Iyer 		 * while kstat operation is in progress will block in
21620dc2366fSVenugopal Iyer 		 * mac_group_rem_ring(). Thus implicitly protects the
21630dc2366fSVenugopal Iyer 		 * resource (ringp->hw_rh) from disappearing.
216463f531d1SSriharsha Basavapatna 		 */
216563f531d1SSriharsha Basavapatna 
216663f531d1SSriharsha Basavapatna 		if (cap_rings->mr_type == MAC_RING_TYPE_RX) {
216763f531d1SSriharsha Basavapatna 			cap_rings->mr_group_type = MAC_GROUP_TYPE_STATIC;
216863f531d1SSriharsha Basavapatna 
216963f531d1SSriharsha Basavapatna 			/*
217063f531d1SSriharsha Basavapatna 			 * The ring_cnt for rx grp is initialized in
217163f531d1SSriharsha Basavapatna 			 * vnet_ring_grp_init(). Later, the ring_cnt gets
217263f531d1SSriharsha Basavapatna 			 * updated dynamically whenever LDC resources are added
217363f531d1SSriharsha Basavapatna 			 * or removed.
217463f531d1SSriharsha Basavapatna 			 */
217563f531d1SSriharsha Basavapatna 			cap_rings->mr_rnum = vnetp->rx_grp[0].ring_cnt;
217663f531d1SSriharsha Basavapatna 			cap_rings->mr_rget = vnet_get_ring;
217763f531d1SSriharsha Basavapatna 
217863f531d1SSriharsha Basavapatna 			cap_rings->mr_gnum = VNET_NUM_PSEUDO_GROUPS;
217963f531d1SSriharsha Basavapatna 			cap_rings->mr_gget = vnet_get_group;
218063f531d1SSriharsha Basavapatna 			cap_rings->mr_gaddring = NULL;
218163f531d1SSriharsha Basavapatna 			cap_rings->mr_gremring = NULL;
218263f531d1SSriharsha Basavapatna 		} else {
218363f531d1SSriharsha Basavapatna 			cap_rings->mr_group_type = MAC_GROUP_TYPE_STATIC;
218463f531d1SSriharsha Basavapatna 
218563f531d1SSriharsha Basavapatna 			/*
218663f531d1SSriharsha Basavapatna 			 * The ring_cnt for tx grp is initialized in
218763f531d1SSriharsha Basavapatna 			 * vnet_ring_grp_init() and remains constant, as we
218863f531d1SSriharsha Basavapatna 			 * do not support dymanic tx rings for now.
218963f531d1SSriharsha Basavapatna 			 */
219063f531d1SSriharsha Basavapatna 			cap_rings->mr_rnum = vnetp->tx_grp[0].ring_cnt;
219163f531d1SSriharsha Basavapatna 			cap_rings->mr_rget = vnet_get_ring;
219263f531d1SSriharsha Basavapatna 
219363f531d1SSriharsha Basavapatna 			/*
219463f531d1SSriharsha Basavapatna 			 * Transmit rings are not grouped; i.e, the number of
219563f531d1SSriharsha Basavapatna 			 * transmit ring groups advertised should be set to 0.
219663f531d1SSriharsha Basavapatna 			 */
219763f531d1SSriharsha Basavapatna 			cap_rings->mr_gnum = 0;
219863f531d1SSriharsha Basavapatna 
219963f531d1SSriharsha Basavapatna 			cap_rings->mr_gget = vnet_get_group;
220063f531d1SSriharsha Basavapatna 			cap_rings->mr_gaddring = NULL;
220163f531d1SSriharsha Basavapatna 			cap_rings->mr_gremring = NULL;
220263f531d1SSriharsha Basavapatna 		}
220363f531d1SSriharsha Basavapatna 		return (B_TRUE);
220463f531d1SSriharsha Basavapatna 
220563f531d1SSriharsha Basavapatna 	}
220663f531d1SSriharsha Basavapatna 
220763f531d1SSriharsha Basavapatna 	default:
220863f531d1SSriharsha Basavapatna 		break;
220963f531d1SSriharsha Basavapatna 
221063f531d1SSriharsha Basavapatna 	}
221163f531d1SSriharsha Basavapatna 
221263f531d1SSriharsha Basavapatna 	return (B_FALSE);
221363f531d1SSriharsha Basavapatna }
221463f531d1SSriharsha Basavapatna 
221563f531d1SSriharsha Basavapatna /*
221663f531d1SSriharsha Basavapatna  * Callback funtion for MAC layer to get ring information.
221763f531d1SSriharsha Basavapatna  */
221863f531d1SSriharsha Basavapatna static void
221963f531d1SSriharsha Basavapatna vnet_get_ring(void *arg, mac_ring_type_t rtype, const int g_index,
222063f531d1SSriharsha Basavapatna     const int r_index, mac_ring_info_t *infop, mac_ring_handle_t r_handle)
222163f531d1SSriharsha Basavapatna {
222263f531d1SSriharsha Basavapatna 	vnet_t	*vnetp = arg;
222363f531d1SSriharsha Basavapatna 
222463f531d1SSriharsha Basavapatna 	switch (rtype) {
222563f531d1SSriharsha Basavapatna 
222663f531d1SSriharsha Basavapatna 	case MAC_RING_TYPE_RX: {
222763f531d1SSriharsha Basavapatna 
222863f531d1SSriharsha Basavapatna 		vnet_pseudo_rx_group_t	*rx_grp;
222963f531d1SSriharsha Basavapatna 		vnet_pseudo_rx_ring_t	*rx_ringp;
223063f531d1SSriharsha Basavapatna 		mac_intr_t		*mintr;
223163f531d1SSriharsha Basavapatna 
223263f531d1SSriharsha Basavapatna 		/* We advertised only one RX group */
223363f531d1SSriharsha Basavapatna 		ASSERT(g_index == 0);
223463f531d1SSriharsha Basavapatna 		rx_grp = &vnetp->rx_grp[g_index];
223563f531d1SSriharsha Basavapatna 
223663f531d1SSriharsha Basavapatna 		/* Check the current # of rings in the rx group */
223763f531d1SSriharsha Basavapatna 		ASSERT((r_index >= 0) && (r_index < rx_grp->max_ring_cnt));
223863f531d1SSriharsha Basavapatna 
223963f531d1SSriharsha Basavapatna 		/* Get the ring based on the index */
224063f531d1SSriharsha Basavapatna 		rx_ringp = &rx_grp->rings[r_index];
224163f531d1SSriharsha Basavapatna 
224263f531d1SSriharsha Basavapatna 		rx_ringp->handle = r_handle;
224363f531d1SSriharsha Basavapatna 		/*
224463f531d1SSriharsha Basavapatna 		 * Note: we don't need to save the incoming r_index in rx_ring,
224563f531d1SSriharsha Basavapatna 		 * as vnet_ring_grp_init() would have initialized the index for
224663f531d1SSriharsha Basavapatna 		 * each ring in the array.
224763f531d1SSriharsha Basavapatna 		 */
224863f531d1SSriharsha Basavapatna 		rx_ringp->grp = rx_grp;
224963f531d1SSriharsha Basavapatna 		rx_ringp->vnetp = vnetp;
225063f531d1SSriharsha Basavapatna 
225163f531d1SSriharsha Basavapatna 		mintr = &infop->mri_intr;
225263f531d1SSriharsha Basavapatna 		mintr->mi_handle = (mac_intr_handle_t)rx_ringp;
225363f531d1SSriharsha Basavapatna 		mintr->mi_enable = (mac_intr_enable_t)vnet_ring_enable_intr;
225463f531d1SSriharsha Basavapatna 		mintr->mi_disable = (mac_intr_disable_t)vnet_ring_disable_intr;
225563f531d1SSriharsha Basavapatna 
225663f531d1SSriharsha Basavapatna 		infop->mri_driver = (mac_ring_driver_t)rx_ringp;
225763f531d1SSriharsha Basavapatna 		infop->mri_start = vnet_rx_ring_start;
225863f531d1SSriharsha Basavapatna 		infop->mri_stop = vnet_rx_ring_stop;
22590dc2366fSVenugopal Iyer 		infop->mri_stat = vnet_rx_ring_stat;
226063f531d1SSriharsha Basavapatna 
226163f531d1SSriharsha Basavapatna 		/* Set the poll function, as this is an rx ring */
226263f531d1SSriharsha Basavapatna 		infop->mri_poll = vnet_rx_poll;
22630dc2366fSVenugopal Iyer 		/*
22640dc2366fSVenugopal Iyer 		 * MAC_RING_RX_ENQUEUE bit needed to be set for nxge
22650dc2366fSVenugopal Iyer 		 * which was not sending packet chains in interrupt
22660dc2366fSVenugopal Iyer 		 * context. For such drivers, packets are queued in
22670dc2366fSVenugopal Iyer 		 * Rx soft rings so that we get a chance to switch
22680dc2366fSVenugopal Iyer 		 * into a polling mode under backlog. This bug (not
22690dc2366fSVenugopal Iyer 		 * sending packet chains) has now been fixed. Once
22700dc2366fSVenugopal Iyer 		 * the performance impact is measured, this change
22710dc2366fSVenugopal Iyer 		 * will be removed.
22720dc2366fSVenugopal Iyer 		 */
22730dc2366fSVenugopal Iyer 		infop->mri_flags = (vnet_mac_rx_queuing ?
22740dc2366fSVenugopal Iyer 		    MAC_RING_RX_ENQUEUE : 0);
227563f531d1SSriharsha Basavapatna 		break;
227663f531d1SSriharsha Basavapatna 	}
227763f531d1SSriharsha Basavapatna 
227863f531d1SSriharsha Basavapatna 	case MAC_RING_TYPE_TX: {
227963f531d1SSriharsha Basavapatna 		vnet_pseudo_tx_group_t	*tx_grp;
228063f531d1SSriharsha Basavapatna 		vnet_pseudo_tx_ring_t	*tx_ringp;
228163f531d1SSriharsha Basavapatna 
228263f531d1SSriharsha Basavapatna 		/*
228363f531d1SSriharsha Basavapatna 		 * No need to check grp index; mac layer passes -1 for it.
228463f531d1SSriharsha Basavapatna 		 */
228563f531d1SSriharsha Basavapatna 		tx_grp = &vnetp->tx_grp[0];
228663f531d1SSriharsha Basavapatna 
228763f531d1SSriharsha Basavapatna 		/* Check the # of rings in the tx group */
228863f531d1SSriharsha Basavapatna 		ASSERT((r_index >= 0) && (r_index < tx_grp->ring_cnt));
228963f531d1SSriharsha Basavapatna 
229063f531d1SSriharsha Basavapatna 		/* Get the ring based on the index */
229163f531d1SSriharsha Basavapatna 		tx_ringp = &tx_grp->rings[r_index];
229263f531d1SSriharsha Basavapatna 
229363f531d1SSriharsha Basavapatna 		tx_ringp->handle = r_handle;
229463f531d1SSriharsha Basavapatna 		tx_ringp->index = r_index;
229563f531d1SSriharsha Basavapatna 		tx_ringp->grp = tx_grp;
229663f531d1SSriharsha Basavapatna 		tx_ringp->vnetp = vnetp;
229763f531d1SSriharsha Basavapatna 
229863f531d1SSriharsha Basavapatna 		infop->mri_driver = (mac_ring_driver_t)tx_ringp;
229963f531d1SSriharsha Basavapatna 		infop->mri_start = vnet_tx_ring_start;
230063f531d1SSriharsha Basavapatna 		infop->mri_stop = vnet_tx_ring_stop;
23010dc2366fSVenugopal Iyer 		infop->mri_stat = vnet_tx_ring_stat;
230263f531d1SSriharsha Basavapatna 
230363f531d1SSriharsha Basavapatna 		/* Set the transmit function, as this is a tx ring */
230463f531d1SSriharsha Basavapatna 		infop->mri_tx = vnet_tx_ring_send;
23050dc2366fSVenugopal Iyer 		/*
23060dc2366fSVenugopal Iyer 		 * MAC_RING_TX_SERIALIZE bit needs to be set while
23070dc2366fSVenugopal Iyer 		 * hybridIO is enabled to workaround tx lock
23080dc2366fSVenugopal Iyer 		 * contention issues in nxge.
23090dc2366fSVenugopal Iyer 		 */
23100dc2366fSVenugopal Iyer 		infop->mri_flags = (vnet_mac_tx_serialize ?
23110dc2366fSVenugopal Iyer 		    MAC_RING_TX_SERIALIZE : 0);
231263f531d1SSriharsha Basavapatna 		break;
231363f531d1SSriharsha Basavapatna 	}
231463f531d1SSriharsha Basavapatna 
231563f531d1SSriharsha Basavapatna 	default:
231663f531d1SSriharsha Basavapatna 		break;
231763f531d1SSriharsha Basavapatna 	}
231863f531d1SSriharsha Basavapatna }
231963f531d1SSriharsha Basavapatna 
232063f531d1SSriharsha Basavapatna /*
232163f531d1SSriharsha Basavapatna  * Callback funtion for MAC layer to get group information.
232263f531d1SSriharsha Basavapatna  */
232363f531d1SSriharsha Basavapatna static void
232463f531d1SSriharsha Basavapatna vnet_get_group(void *arg, mac_ring_type_t type, const int index,
232563f531d1SSriharsha Basavapatna 	mac_group_info_t *infop, mac_group_handle_t handle)
232663f531d1SSriharsha Basavapatna {
232763f531d1SSriharsha Basavapatna 	vnet_t	*vnetp = (vnet_t *)arg;
232863f531d1SSriharsha Basavapatna 
232963f531d1SSriharsha Basavapatna 	switch (type) {
233063f531d1SSriharsha Basavapatna 
233163f531d1SSriharsha Basavapatna 	case MAC_RING_TYPE_RX:
233263f531d1SSriharsha Basavapatna 	{
233363f531d1SSriharsha Basavapatna 		vnet_pseudo_rx_group_t	*rx_grp;
233463f531d1SSriharsha Basavapatna 
233563f531d1SSriharsha Basavapatna 		/* We advertised only one RX group */
233663f531d1SSriharsha Basavapatna 		ASSERT(index == 0);
233763f531d1SSriharsha Basavapatna 
233863f531d1SSriharsha Basavapatna 		rx_grp = &vnetp->rx_grp[index];
233963f531d1SSriharsha Basavapatna 		rx_grp->handle = handle;
234063f531d1SSriharsha Basavapatna 		rx_grp->index = index;
234163f531d1SSriharsha Basavapatna 		rx_grp->vnetp = vnetp;
234263f531d1SSriharsha Basavapatna 
234363f531d1SSriharsha Basavapatna 		infop->mgi_driver = (mac_group_driver_t)rx_grp;
234463f531d1SSriharsha Basavapatna 		infop->mgi_start = NULL;
234563f531d1SSriharsha Basavapatna 		infop->mgi_stop = NULL;
234663f531d1SSriharsha Basavapatna 		infop->mgi_addmac = vnet_addmac;
234763f531d1SSriharsha Basavapatna 		infop->mgi_remmac = vnet_remmac;
234863f531d1SSriharsha Basavapatna 		infop->mgi_count = rx_grp->ring_cnt;
234963f531d1SSriharsha Basavapatna 
235063f531d1SSriharsha Basavapatna 		break;
235163f531d1SSriharsha Basavapatna 	}
235263f531d1SSriharsha Basavapatna 
235363f531d1SSriharsha Basavapatna 	case MAC_RING_TYPE_TX:
235463f531d1SSriharsha Basavapatna 	{
235563f531d1SSriharsha Basavapatna 		vnet_pseudo_tx_group_t	*tx_grp;
235663f531d1SSriharsha Basavapatna 
235763f531d1SSriharsha Basavapatna 		/* We advertised only one TX group */
235863f531d1SSriharsha Basavapatna 		ASSERT(index == 0);
235963f531d1SSriharsha Basavapatna 
236063f531d1SSriharsha Basavapatna 		tx_grp = &vnetp->tx_grp[index];
236163f531d1SSriharsha Basavapatna 		tx_grp->handle = handle;
236263f531d1SSriharsha Basavapatna 		tx_grp->index = index;
236363f531d1SSriharsha Basavapatna 		tx_grp->vnetp = vnetp;
236463f531d1SSriharsha Basavapatna 
236563f531d1SSriharsha Basavapatna 		infop->mgi_driver = (mac_group_driver_t)tx_grp;
236663f531d1SSriharsha Basavapatna 		infop->mgi_start = NULL;
236763f531d1SSriharsha Basavapatna 		infop->mgi_stop = NULL;
236863f531d1SSriharsha Basavapatna 		infop->mgi_addmac = NULL;
236963f531d1SSriharsha Basavapatna 		infop->mgi_remmac = NULL;
237063f531d1SSriharsha Basavapatna 		infop->mgi_count = VNET_NUM_PSEUDO_TXRINGS;
237163f531d1SSriharsha Basavapatna 
237263f531d1SSriharsha Basavapatna 		break;
237363f531d1SSriharsha Basavapatna 	}
237463f531d1SSriharsha Basavapatna 
237563f531d1SSriharsha Basavapatna 	default:
237663f531d1SSriharsha Basavapatna 		break;
237763f531d1SSriharsha Basavapatna 
237863f531d1SSriharsha Basavapatna 	}
237963f531d1SSriharsha Basavapatna }
238063f531d1SSriharsha Basavapatna 
238163f531d1SSriharsha Basavapatna static int
238263f531d1SSriharsha Basavapatna vnet_rx_ring_start(mac_ring_driver_t arg, uint64_t mr_gen_num)
238363f531d1SSriharsha Basavapatna {
238463f531d1SSriharsha Basavapatna 	vnet_pseudo_rx_ring_t	*rx_ringp = (vnet_pseudo_rx_ring_t *)arg;
238563f531d1SSriharsha Basavapatna 	int			err;
238663f531d1SSriharsha Basavapatna 
238763f531d1SSriharsha Basavapatna 	/*
238863f531d1SSriharsha Basavapatna 	 * If this ring is mapped to a LDC resource, simply mark the state to
238963f531d1SSriharsha Basavapatna 	 * indicate the ring is started and return.
239063f531d1SSriharsha Basavapatna 	 */
239163f531d1SSriharsha Basavapatna 	if ((rx_ringp->state &
239263f531d1SSriharsha Basavapatna 	    (VNET_RXRING_LDC_SERVICE|VNET_RXRING_LDC_GUEST)) != 0) {
239363f531d1SSriharsha Basavapatna 		rx_ringp->gen_num = mr_gen_num;
239463f531d1SSriharsha Basavapatna 		rx_ringp->state |= VNET_RXRING_STARTED;
239563f531d1SSriharsha Basavapatna 		return (0);
239663f531d1SSriharsha Basavapatna 	}
239763f531d1SSriharsha Basavapatna 
239863f531d1SSriharsha Basavapatna 	ASSERT((rx_ringp->state & VNET_RXRING_HYBRID) != 0);
239963f531d1SSriharsha Basavapatna 
240063f531d1SSriharsha Basavapatna 	/*
240163f531d1SSriharsha Basavapatna 	 * This must be a ring reserved for a hwring. If the hwring is not
240263f531d1SSriharsha Basavapatna 	 * bound yet, simply mark the state to indicate the ring is started and
240363f531d1SSriharsha Basavapatna 	 * return. If and when a hybrid resource is activated for this vnet
240463f531d1SSriharsha Basavapatna 	 * device, we will bind the hwring and start it then. If a hwring is
240563f531d1SSriharsha Basavapatna 	 * already bound, start it now.
240663f531d1SSriharsha Basavapatna 	 */
240763f531d1SSriharsha Basavapatna 	if (rx_ringp->hw_rh == NULL) {
240863f531d1SSriharsha Basavapatna 		rx_ringp->gen_num = mr_gen_num;
240963f531d1SSriharsha Basavapatna 		rx_ringp->state |= VNET_RXRING_STARTED;
241063f531d1SSriharsha Basavapatna 		return (0);
241163f531d1SSriharsha Basavapatna 	}
241263f531d1SSriharsha Basavapatna 
241363f531d1SSriharsha Basavapatna 	err = mac_hwring_start(rx_ringp->hw_rh);
241463f531d1SSriharsha Basavapatna 	if (err == 0) {
241563f531d1SSriharsha Basavapatna 		rx_ringp->gen_num = mr_gen_num;
241663f531d1SSriharsha Basavapatna 		rx_ringp->state |= VNET_RXRING_STARTED;
241763f531d1SSriharsha Basavapatna 	} else {
241863f531d1SSriharsha Basavapatna 		err = ENXIO;
241963f531d1SSriharsha Basavapatna 	}
242063f531d1SSriharsha Basavapatna 
242163f531d1SSriharsha Basavapatna 	return (err);
242263f531d1SSriharsha Basavapatna }
242363f531d1SSriharsha Basavapatna 
242463f531d1SSriharsha Basavapatna static void
242563f531d1SSriharsha Basavapatna vnet_rx_ring_stop(mac_ring_driver_t arg)
242663f531d1SSriharsha Basavapatna {
242763f531d1SSriharsha Basavapatna 	vnet_pseudo_rx_ring_t	*rx_ringp = (vnet_pseudo_rx_ring_t *)arg;
242863f531d1SSriharsha Basavapatna 
242963f531d1SSriharsha Basavapatna 	/*
243063f531d1SSriharsha Basavapatna 	 * If this ring is mapped to a LDC resource, simply mark the state to
243163f531d1SSriharsha Basavapatna 	 * indicate the ring is now stopped and return.
243263f531d1SSriharsha Basavapatna 	 */
243363f531d1SSriharsha Basavapatna 	if ((rx_ringp->state &
243463f531d1SSriharsha Basavapatna 	    (VNET_RXRING_LDC_SERVICE|VNET_RXRING_LDC_GUEST)) != 0) {
243563f531d1SSriharsha Basavapatna 		rx_ringp->state &= ~VNET_RXRING_STARTED;
2436e8c4ecbbSWENTAO YANG 		return;
243763f531d1SSriharsha Basavapatna 	}
243863f531d1SSriharsha Basavapatna 
243963f531d1SSriharsha Basavapatna 	ASSERT((rx_ringp->state & VNET_RXRING_HYBRID) != 0);
244063f531d1SSriharsha Basavapatna 
244163f531d1SSriharsha Basavapatna 	/*
244263f531d1SSriharsha Basavapatna 	 * This must be a ring reserved for a hwring. If the hwring is not
244363f531d1SSriharsha Basavapatna 	 * bound yet, simply mark the state to indicate the ring is stopped and
244463f531d1SSriharsha Basavapatna 	 * return. If a hwring is already bound, stop it now.
244563f531d1SSriharsha Basavapatna 	 */
244663f531d1SSriharsha Basavapatna 	if (rx_ringp->hw_rh == NULL) {
244763f531d1SSriharsha Basavapatna 		rx_ringp->state &= ~VNET_RXRING_STARTED;
244863f531d1SSriharsha Basavapatna 		return;
244963f531d1SSriharsha Basavapatna 	}
245063f531d1SSriharsha Basavapatna 
245163f531d1SSriharsha Basavapatna 	mac_hwring_stop(rx_ringp->hw_rh);
245263f531d1SSriharsha Basavapatna 	rx_ringp->state &= ~VNET_RXRING_STARTED;
245363f531d1SSriharsha Basavapatna }
245463f531d1SSriharsha Basavapatna 
24550dc2366fSVenugopal Iyer static int
24560dc2366fSVenugopal Iyer vnet_rx_ring_stat(mac_ring_driver_t rdriver, uint_t stat, uint64_t *val)
24570dc2366fSVenugopal Iyer {
24580dc2366fSVenugopal Iyer 	vnet_pseudo_rx_ring_t	*rx_ringp = (vnet_pseudo_rx_ring_t *)rdriver;
24590dc2366fSVenugopal Iyer 	vnet_t			*vnetp = (vnet_t *)rx_ringp->vnetp;
24600dc2366fSVenugopal Iyer 	vnet_res_t		*vresp;
24610dc2366fSVenugopal Iyer 	mac_register_t		*macp;
24620dc2366fSVenugopal Iyer 	mac_callbacks_t		*cbp;
24630dc2366fSVenugopal Iyer 
24640dc2366fSVenugopal Iyer 	/*
24650dc2366fSVenugopal Iyer 	 * Refer to vnet_m_capab() function for detailed comments on ring
24660dc2366fSVenugopal Iyer 	 * synchronization.
24670dc2366fSVenugopal Iyer 	 */
24680dc2366fSVenugopal Iyer 	if ((rx_ringp->state & VNET_RXRING_HYBRID) != 0) {
24690dc2366fSVenugopal Iyer 		READ_ENTER(&vnetp->vsw_fp_rw);
24700dc2366fSVenugopal Iyer 		if (vnetp->hio_fp == NULL) {
24710dc2366fSVenugopal Iyer 			RW_EXIT(&vnetp->vsw_fp_rw);
24720dc2366fSVenugopal Iyer 			return (0);
24730dc2366fSVenugopal Iyer 		}
24740dc2366fSVenugopal Iyer 
24750dc2366fSVenugopal Iyer 		VNET_FDBE_REFHOLD(vnetp->hio_fp);
24760dc2366fSVenugopal Iyer 		RW_EXIT(&vnetp->vsw_fp_rw);
2477*9f26b864SVenugopal Iyer 		(void) mac_hwring_getstat(rx_ringp->hw_rh, stat, val);
24780dc2366fSVenugopal Iyer 		VNET_FDBE_REFRELE(vnetp->hio_fp);
24790dc2366fSVenugopal Iyer 		return (0);
24800dc2366fSVenugopal Iyer 	}
24810dc2366fSVenugopal Iyer 
24820dc2366fSVenugopal Iyer 	ASSERT((rx_ringp->state &
24830dc2366fSVenugopal Iyer 	    (VNET_RXRING_LDC_SERVICE|VNET_RXRING_LDC_GUEST)) != 0);
24840dc2366fSVenugopal Iyer 	vresp = (vnet_res_t *)rx_ringp->hw_rh;
24850dc2366fSVenugopal Iyer 	macp = &vresp->macreg;
24860dc2366fSVenugopal Iyer 	cbp = macp->m_callbacks;
24870dc2366fSVenugopal Iyer 
24880dc2366fSVenugopal Iyer 	cbp->mc_getstat(macp->m_driver, stat, val);
24890dc2366fSVenugopal Iyer 
24900dc2366fSVenugopal Iyer 	return (0);
24910dc2366fSVenugopal Iyer }
24920dc2366fSVenugopal Iyer 
249363f531d1SSriharsha Basavapatna /* ARGSUSED */
249463f531d1SSriharsha Basavapatna static int
249563f531d1SSriharsha Basavapatna vnet_tx_ring_start(mac_ring_driver_t arg, uint64_t mr_gen_num)
249663f531d1SSriharsha Basavapatna {
249763f531d1SSriharsha Basavapatna 	vnet_pseudo_tx_ring_t	*tx_ringp = (vnet_pseudo_tx_ring_t *)arg;
249863f531d1SSriharsha Basavapatna 
249963f531d1SSriharsha Basavapatna 	tx_ringp->state |= VNET_TXRING_STARTED;
250063f531d1SSriharsha Basavapatna 	return (0);
250163f531d1SSriharsha Basavapatna }
250263f531d1SSriharsha Basavapatna 
250363f531d1SSriharsha Basavapatna static void
250463f531d1SSriharsha Basavapatna vnet_tx_ring_stop(mac_ring_driver_t arg)
250563f531d1SSriharsha Basavapatna {
250663f531d1SSriharsha Basavapatna 	vnet_pseudo_tx_ring_t	*tx_ringp = (vnet_pseudo_tx_ring_t *)arg;
250763f531d1SSriharsha Basavapatna 
250863f531d1SSriharsha Basavapatna 	tx_ringp->state &= ~VNET_TXRING_STARTED;
250963f531d1SSriharsha Basavapatna }
251063f531d1SSriharsha Basavapatna 
25110dc2366fSVenugopal Iyer static int
25120dc2366fSVenugopal Iyer vnet_tx_ring_stat(mac_ring_driver_t rdriver, uint_t stat, uint64_t *val)
25130dc2366fSVenugopal Iyer {
25140dc2366fSVenugopal Iyer 	vnet_pseudo_tx_ring_t	*tx_ringp = (vnet_pseudo_tx_ring_t *)rdriver;
25150dc2366fSVenugopal Iyer 	vnet_tx_ring_stats_t	*statsp;
25160dc2366fSVenugopal Iyer 
25170dc2366fSVenugopal Iyer 	statsp = &tx_ringp->tx_ring_stats;
25180dc2366fSVenugopal Iyer 
25190dc2366fSVenugopal Iyer 	switch (stat) {
25200dc2366fSVenugopal Iyer 	case MAC_STAT_OPACKETS:
25210dc2366fSVenugopal Iyer 		*val = statsp->opackets;
25220dc2366fSVenugopal Iyer 		break;
25230dc2366fSVenugopal Iyer 
25240dc2366fSVenugopal Iyer 	case MAC_STAT_OBYTES:
25250dc2366fSVenugopal Iyer 		*val = statsp->obytes;
25260dc2366fSVenugopal Iyer 		break;
25270dc2366fSVenugopal Iyer 
25280dc2366fSVenugopal Iyer 	default:
25290dc2366fSVenugopal Iyer 		*val = 0;
25300dc2366fSVenugopal Iyer 		return (ENOTSUP);
25310dc2366fSVenugopal Iyer 	}
25320dc2366fSVenugopal Iyer 
25330dc2366fSVenugopal Iyer 	return (0);
25340dc2366fSVenugopal Iyer }
25350dc2366fSVenugopal Iyer 
253663f531d1SSriharsha Basavapatna /*
253763f531d1SSriharsha Basavapatna  * Disable polling for a ring and enable its interrupt.
253863f531d1SSriharsha Basavapatna  */
253963f531d1SSriharsha Basavapatna static int
254063f531d1SSriharsha Basavapatna vnet_ring_enable_intr(void *arg)
254163f531d1SSriharsha Basavapatna {
254263f531d1SSriharsha Basavapatna 	vnet_pseudo_rx_ring_t	*rx_ringp = (vnet_pseudo_rx_ring_t *)arg;
254363f531d1SSriharsha Basavapatna 	vnet_res_t		*vresp;
254463f531d1SSriharsha Basavapatna 
254563f531d1SSriharsha Basavapatna 	if (rx_ringp->hw_rh == NULL) {
254663f531d1SSriharsha Basavapatna 		/*
254763f531d1SSriharsha Basavapatna 		 * Ring enable intr func is being invoked, but the ring is
254863f531d1SSriharsha Basavapatna 		 * not bound to any underlying resource ? This must be a ring
254963f531d1SSriharsha Basavapatna 		 * reserved for Hybrid resource and no such resource has been
255063f531d1SSriharsha Basavapatna 		 * assigned to this vnet device yet. We simply return success.
255163f531d1SSriharsha Basavapatna 		 */
255263f531d1SSriharsha Basavapatna 		ASSERT((rx_ringp->state & VNET_RXRING_HYBRID) != 0);
255363f531d1SSriharsha Basavapatna 		return (0);
255463f531d1SSriharsha Basavapatna 	}
255563f531d1SSriharsha Basavapatna 
255663f531d1SSriharsha Basavapatna 	/*
255763f531d1SSriharsha Basavapatna 	 * The rx ring has been bound to either a LDC or a Hybrid resource.
255863f531d1SSriharsha Basavapatna 	 * Call the appropriate function to enable interrupts for the ring.
255963f531d1SSriharsha Basavapatna 	 */
256063f531d1SSriharsha Basavapatna 	if (rx_ringp->state & VNET_RXRING_HYBRID) {
256163f531d1SSriharsha Basavapatna 		return (mac_hwring_enable_intr(rx_ringp->hw_rh));
256263f531d1SSriharsha Basavapatna 	} else {
256363f531d1SSriharsha Basavapatna 		vresp = (vnet_res_t *)rx_ringp->hw_rh;
256463f531d1SSriharsha Basavapatna 		return (vgen_enable_intr(vresp->macreg.m_driver));
256563f531d1SSriharsha Basavapatna 	}
256663f531d1SSriharsha Basavapatna }
256763f531d1SSriharsha Basavapatna 
256863f531d1SSriharsha Basavapatna /*
256963f531d1SSriharsha Basavapatna  * Enable polling for a ring and disable its interrupt.
257063f531d1SSriharsha Basavapatna  */
257163f531d1SSriharsha Basavapatna static int
257263f531d1SSriharsha Basavapatna vnet_ring_disable_intr(void *arg)
257363f531d1SSriharsha Basavapatna {
257463f531d1SSriharsha Basavapatna 	vnet_pseudo_rx_ring_t	*rx_ringp = (vnet_pseudo_rx_ring_t *)arg;
257563f531d1SSriharsha Basavapatna 	vnet_res_t		*vresp;
257663f531d1SSriharsha Basavapatna 
257763f531d1SSriharsha Basavapatna 	if (rx_ringp->hw_rh == NULL) {
257863f531d1SSriharsha Basavapatna 		/*
257963f531d1SSriharsha Basavapatna 		 * Ring disable intr func is being invoked, but the ring is
258063f531d1SSriharsha Basavapatna 		 * not bound to any underlying resource ? This must be a ring
258163f531d1SSriharsha Basavapatna 		 * reserved for Hybrid resource and no such resource has been
258263f531d1SSriharsha Basavapatna 		 * assigned to this vnet device yet. We simply return success.
258363f531d1SSriharsha Basavapatna 		 */
258463f531d1SSriharsha Basavapatna 		ASSERT((rx_ringp->state & VNET_RXRING_HYBRID) != 0);
258563f531d1SSriharsha Basavapatna 		return (0);
258663f531d1SSriharsha Basavapatna 	}
258763f531d1SSriharsha Basavapatna 
258863f531d1SSriharsha Basavapatna 	/*
258963f531d1SSriharsha Basavapatna 	 * The rx ring has been bound to either a LDC or a Hybrid resource.
259063f531d1SSriharsha Basavapatna 	 * Call the appropriate function to disable interrupts for the ring.
259163f531d1SSriharsha Basavapatna 	 */
259263f531d1SSriharsha Basavapatna 	if (rx_ringp->state & VNET_RXRING_HYBRID) {
259363f531d1SSriharsha Basavapatna 		return (mac_hwring_disable_intr(rx_ringp->hw_rh));
259463f531d1SSriharsha Basavapatna 	} else {
259563f531d1SSriharsha Basavapatna 		vresp = (vnet_res_t *)rx_ringp->hw_rh;
259663f531d1SSriharsha Basavapatna 		return (vgen_disable_intr(vresp->macreg.m_driver));
259763f531d1SSriharsha Basavapatna 	}
259863f531d1SSriharsha Basavapatna }
259963f531d1SSriharsha Basavapatna 
260063f531d1SSriharsha Basavapatna /*
260163f531d1SSriharsha Basavapatna  * Poll 'bytes_to_pickup' bytes of message from the rx ring.
260263f531d1SSriharsha Basavapatna  */
260363f531d1SSriharsha Basavapatna static mblk_t *
260463f531d1SSriharsha Basavapatna vnet_rx_poll(void *arg, int bytes_to_pickup)
260563f531d1SSriharsha Basavapatna {
260663f531d1SSriharsha Basavapatna 	vnet_pseudo_rx_ring_t	*rx_ringp = (vnet_pseudo_rx_ring_t *)arg;
260763f531d1SSriharsha Basavapatna 	mblk_t			*mp = NULL;
260863f531d1SSriharsha Basavapatna 	vnet_res_t		*vresp;
260963f531d1SSriharsha Basavapatna 	vnet_t			*vnetp = rx_ringp->vnetp;
261063f531d1SSriharsha Basavapatna 
261163f531d1SSriharsha Basavapatna 	if (rx_ringp->hw_rh == NULL) {
261263f531d1SSriharsha Basavapatna 		return (NULL);
261363f531d1SSriharsha Basavapatna 	}
261463f531d1SSriharsha Basavapatna 
261563f531d1SSriharsha Basavapatna 	if (rx_ringp->state & VNET_RXRING_HYBRID) {
261663f531d1SSriharsha Basavapatna 		mp = mac_hwring_poll(rx_ringp->hw_rh, bytes_to_pickup);
261763f531d1SSriharsha Basavapatna 		/*
261863f531d1SSriharsha Basavapatna 		 * Packets received over a hybrid resource need additional
261963f531d1SSriharsha Basavapatna 		 * processing to remove the tag, for the pvid case. The
262063f531d1SSriharsha Basavapatna 		 * underlying resource is not aware of the vnet's pvid and thus
262163f531d1SSriharsha Basavapatna 		 * packets are received with the vlan tag in the header; unlike
262263f531d1SSriharsha Basavapatna 		 * packets that are received over a ldc channel in which case
262363f531d1SSriharsha Basavapatna 		 * the peer vnet/vsw would have already removed the tag.
262463f531d1SSriharsha Basavapatna 		 */
262563f531d1SSriharsha Basavapatna 		if (vnetp->pvid != vnetp->default_vlan_id) {
262663f531d1SSriharsha Basavapatna 			vnet_rx_frames_untag(vnetp->pvid, &mp);
262763f531d1SSriharsha Basavapatna 		}
262863f531d1SSriharsha Basavapatna 	} else {
262963f531d1SSriharsha Basavapatna 		vresp = (vnet_res_t *)rx_ringp->hw_rh;
263063f531d1SSriharsha Basavapatna 		mp = vgen_poll(vresp->macreg.m_driver, bytes_to_pickup);
263163f531d1SSriharsha Basavapatna 	}
263263f531d1SSriharsha Basavapatna 	return (mp);
263363f531d1SSriharsha Basavapatna }
263463f531d1SSriharsha Basavapatna 
263563f531d1SSriharsha Basavapatna /* ARGSUSED */
263663f531d1SSriharsha Basavapatna void
263763f531d1SSriharsha Basavapatna vnet_hio_rx_cb(void *arg, mac_resource_handle_t mrh, mblk_t *mp,
263863f531d1SSriharsha Basavapatna 	boolean_t loopback)
263963f531d1SSriharsha Basavapatna {
264063f531d1SSriharsha Basavapatna 	vnet_t			*vnetp = (vnet_t *)arg;
264163f531d1SSriharsha Basavapatna 	vnet_pseudo_rx_ring_t	*ringp = (vnet_pseudo_rx_ring_t *)mrh;
264263f531d1SSriharsha Basavapatna 
264363f531d1SSriharsha Basavapatna 	/*
264463f531d1SSriharsha Basavapatna 	 * Packets received over a hybrid resource need additional processing
264563f531d1SSriharsha Basavapatna 	 * to remove the tag, for the pvid case. The underlying resource is
264663f531d1SSriharsha Basavapatna 	 * not aware of the vnet's pvid and thus packets are received with the
264763f531d1SSriharsha Basavapatna 	 * vlan tag in the header; unlike packets that are received over a ldc
264863f531d1SSriharsha Basavapatna 	 * channel in which case the peer vnet/vsw would have already removed
264963f531d1SSriharsha Basavapatna 	 * the tag.
265063f531d1SSriharsha Basavapatna 	 */
265163f531d1SSriharsha Basavapatna 	if (vnetp->pvid != vnetp->default_vlan_id) {
265263f531d1SSriharsha Basavapatna 		vnet_rx_frames_untag(vnetp->pvid, &mp);
265363f531d1SSriharsha Basavapatna 		if (mp == NULL) {
265463f531d1SSriharsha Basavapatna 			return;
265563f531d1SSriharsha Basavapatna 		}
265663f531d1SSriharsha Basavapatna 	}
265763f531d1SSriharsha Basavapatna 	mac_rx_ring(vnetp->mh, ringp->handle, mp, ringp->gen_num);
265863f531d1SSriharsha Basavapatna }
265963f531d1SSriharsha Basavapatna 
266063f531d1SSriharsha Basavapatna static int
266163f531d1SSriharsha Basavapatna vnet_addmac(void *arg, const uint8_t *mac_addr)
266263f531d1SSriharsha Basavapatna {
266363f531d1SSriharsha Basavapatna 	vnet_pseudo_rx_group_t  *rx_grp = (vnet_pseudo_rx_group_t *)arg;
266463f531d1SSriharsha Basavapatna 	vnet_t			*vnetp;
266563f531d1SSriharsha Basavapatna 
266663f531d1SSriharsha Basavapatna 	vnetp = rx_grp->vnetp;
266763f531d1SSriharsha Basavapatna 
266863f531d1SSriharsha Basavapatna 	if (bcmp(mac_addr, vnetp->curr_macaddr, ETHERADDRL) == 0) {
266963f531d1SSriharsha Basavapatna 		return (0);
267063f531d1SSriharsha Basavapatna 	}
267163f531d1SSriharsha Basavapatna 
267263f531d1SSriharsha Basavapatna 	cmn_err(CE_CONT, "!vnet%d: %s: Multiple macaddr unsupported\n",
267363f531d1SSriharsha Basavapatna 	    vnetp->instance, __func__);
267463f531d1SSriharsha Basavapatna 	return (EINVAL);
267563f531d1SSriharsha Basavapatna }
267663f531d1SSriharsha Basavapatna 
267763f531d1SSriharsha Basavapatna static int
267863f531d1SSriharsha Basavapatna vnet_remmac(void *arg, const uint8_t *mac_addr)
267963f531d1SSriharsha Basavapatna {
268063f531d1SSriharsha Basavapatna 	vnet_pseudo_rx_group_t  *rx_grp = (vnet_pseudo_rx_group_t *)arg;
268163f531d1SSriharsha Basavapatna 	vnet_t			*vnetp;
268263f531d1SSriharsha Basavapatna 
268363f531d1SSriharsha Basavapatna 	vnetp = rx_grp->vnetp;
268463f531d1SSriharsha Basavapatna 
268563f531d1SSriharsha Basavapatna 	if (bcmp(mac_addr, vnetp->curr_macaddr, ETHERADDRL) == 0) {
268663f531d1SSriharsha Basavapatna 		return (0);
268763f531d1SSriharsha Basavapatna 	}
268863f531d1SSriharsha Basavapatna 
268963f531d1SSriharsha Basavapatna 	cmn_err(CE_CONT, "!vnet%d: %s: Invalid macaddr: %s\n",
269063f531d1SSriharsha Basavapatna 	    vnetp->instance, __func__, ether_sprintf((void *)mac_addr));
269163f531d1SSriharsha Basavapatna 	return (EINVAL);
269263f531d1SSriharsha Basavapatna }
269363f531d1SSriharsha Basavapatna 
269463f531d1SSriharsha Basavapatna int
269563f531d1SSriharsha Basavapatna vnet_hio_mac_init(vnet_t *vnetp, char *ifname)
269663f531d1SSriharsha Basavapatna {
269763f531d1SSriharsha Basavapatna 	mac_handle_t		mh;
269863f531d1SSriharsha Basavapatna 	mac_client_handle_t	mch = NULL;
269963f531d1SSriharsha Basavapatna 	mac_unicast_handle_t	muh = NULL;
270063f531d1SSriharsha Basavapatna 	mac_diag_t		diag;
270163f531d1SSriharsha Basavapatna 	mac_register_t		*macp;
270263f531d1SSriharsha Basavapatna 	char			client_name[MAXNAMELEN];
270363f531d1SSriharsha Basavapatna 	int			rv;
270463f531d1SSriharsha Basavapatna 	uint16_t		mac_flags = MAC_UNICAST_TAG_DISABLE |
270563f531d1SSriharsha Basavapatna 	    MAC_UNICAST_STRIP_DISABLE | MAC_UNICAST_PRIMARY;
270663f531d1SSriharsha Basavapatna 	vio_net_callbacks_t	vcb;
270763f531d1SSriharsha Basavapatna 	ether_addr_t		rem_addr =
270863f531d1SSriharsha Basavapatna 		{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
270963f531d1SSriharsha Basavapatna 	uint32_t		retries = 0;
271063f531d1SSriharsha Basavapatna 
271163f531d1SSriharsha Basavapatna 	if ((macp = mac_alloc(MAC_VERSION)) == NULL) {
271263f531d1SSriharsha Basavapatna 		return (EAGAIN);
271363f531d1SSriharsha Basavapatna 	}
271463f531d1SSriharsha Basavapatna 
271563f531d1SSriharsha Basavapatna 	do {
271663f531d1SSriharsha Basavapatna 		rv = mac_open_by_linkname(ifname, &mh);
271763f531d1SSriharsha Basavapatna 		if (rv == 0) {
271863f531d1SSriharsha Basavapatna 			break;
271963f531d1SSriharsha Basavapatna 		}
272063f531d1SSriharsha Basavapatna 		if (rv != ENOENT || (retries++ >= vnet_mac_open_retries)) {
272163f531d1SSriharsha Basavapatna 			mac_free(macp);
272263f531d1SSriharsha Basavapatna 			return (rv);
272363f531d1SSriharsha Basavapatna 		}
272463f531d1SSriharsha Basavapatna 		drv_usecwait(vnet_mac_open_delay);
272563f531d1SSriharsha Basavapatna 	} while (rv == ENOENT);
272663f531d1SSriharsha Basavapatna 
272763f531d1SSriharsha Basavapatna 	vnetp->hio_mh = mh;
272863f531d1SSriharsha Basavapatna 
272963f531d1SSriharsha Basavapatna 	(void) snprintf(client_name, MAXNAMELEN, "vnet%d-%s", vnetp->instance,
273063f531d1SSriharsha Basavapatna 	    ifname);
273163f531d1SSriharsha Basavapatna 	rv = mac_client_open(mh, &mch, client_name, MAC_OPEN_FLAGS_EXCLUSIVE);
273263f531d1SSriharsha Basavapatna 	if (rv != 0) {
273363f531d1SSriharsha Basavapatna 		goto fail;
273463f531d1SSriharsha Basavapatna 	}
273563f531d1SSriharsha Basavapatna 	vnetp->hio_mch = mch;
273663f531d1SSriharsha Basavapatna 
273763f531d1SSriharsha Basavapatna 	rv = mac_unicast_add(mch, vnetp->curr_macaddr, mac_flags, &muh, 0,
273863f531d1SSriharsha Basavapatna 	    &diag);
273963f531d1SSriharsha Basavapatna 	if (rv != 0) {
274063f531d1SSriharsha Basavapatna 		goto fail;
274163f531d1SSriharsha Basavapatna 	}
274263f531d1SSriharsha Basavapatna 	vnetp->hio_muh = muh;
274363f531d1SSriharsha Basavapatna 
274463f531d1SSriharsha Basavapatna 	macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
274563f531d1SSriharsha Basavapatna 	macp->m_driver = vnetp;
274663f531d1SSriharsha Basavapatna 	macp->m_dip = NULL;
274763f531d1SSriharsha Basavapatna 	macp->m_src_addr = NULL;
274863f531d1SSriharsha Basavapatna 	macp->m_callbacks = &vnet_hio_res_callbacks;
274963f531d1SSriharsha Basavapatna 	macp->m_min_sdu = 0;
275063f531d1SSriharsha Basavapatna 	macp->m_max_sdu = ETHERMTU;
275163f531d1SSriharsha Basavapatna 
275263f531d1SSriharsha Basavapatna 	rv = vio_net_resource_reg(macp, VIO_NET_RES_HYBRID,
275363f531d1SSriharsha Basavapatna 	    vnetp->curr_macaddr, rem_addr, &vnetp->hio_vhp, &vcb);
275463f531d1SSriharsha Basavapatna 	if (rv != 0) {
275563f531d1SSriharsha Basavapatna 		goto fail;
275663f531d1SSriharsha Basavapatna 	}
275763f531d1SSriharsha Basavapatna 	mac_free(macp);
275863f531d1SSriharsha Basavapatna 
275963f531d1SSriharsha Basavapatna 	/* add the recv callback */
276063f531d1SSriharsha Basavapatna 	mac_rx_set(vnetp->hio_mch, vnet_hio_rx_cb, vnetp);
276163f531d1SSriharsha Basavapatna 
276263f531d1SSriharsha Basavapatna 	return (0);
276363f531d1SSriharsha Basavapatna 
276463f531d1SSriharsha Basavapatna fail:
276563f531d1SSriharsha Basavapatna 	mac_free(macp);
276663f531d1SSriharsha Basavapatna 	vnet_hio_mac_cleanup(vnetp);
276763f531d1SSriharsha Basavapatna 	return (1);
276863f531d1SSriharsha Basavapatna }
276963f531d1SSriharsha Basavapatna 
277063f531d1SSriharsha Basavapatna void
277163f531d1SSriharsha Basavapatna vnet_hio_mac_cleanup(vnet_t *vnetp)
277263f531d1SSriharsha Basavapatna {
277363f531d1SSriharsha Basavapatna 	if (vnetp->hio_vhp != NULL) {
277463f531d1SSriharsha Basavapatna 		vio_net_resource_unreg(vnetp->hio_vhp);
277563f531d1SSriharsha Basavapatna 		vnetp->hio_vhp = NULL;
277663f531d1SSriharsha Basavapatna 	}
277763f531d1SSriharsha Basavapatna 
277863f531d1SSriharsha Basavapatna 	if (vnetp->hio_muh != NULL) {
277907d06da5SSurya Prakki 		(void) mac_unicast_remove(vnetp->hio_mch, vnetp->hio_muh);
278063f531d1SSriharsha Basavapatna 		vnetp->hio_muh = NULL;
278163f531d1SSriharsha Basavapatna 	}
278263f531d1SSriharsha Basavapatna 
278363f531d1SSriharsha Basavapatna 	if (vnetp->hio_mch != NULL) {
278463f531d1SSriharsha Basavapatna 		mac_client_close(vnetp->hio_mch, 0);
278563f531d1SSriharsha Basavapatna 		vnetp->hio_mch = NULL;
278663f531d1SSriharsha Basavapatna 	}
278763f531d1SSriharsha Basavapatna 
278863f531d1SSriharsha Basavapatna 	if (vnetp->hio_mh != NULL) {
278963f531d1SSriharsha Basavapatna 		mac_close(vnetp->hio_mh);
279063f531d1SSriharsha Basavapatna 		vnetp->hio_mh = NULL;
279163f531d1SSriharsha Basavapatna 	}
279263f531d1SSriharsha Basavapatna }
279363f531d1SSriharsha Basavapatna 
279463f531d1SSriharsha Basavapatna /* Bind pseudo rings to hwrings */
279563f531d1SSriharsha Basavapatna static int
279663f531d1SSriharsha Basavapatna vnet_bind_hwrings(vnet_t *vnetp)
279763f531d1SSriharsha Basavapatna {
279863f531d1SSriharsha Basavapatna 	mac_ring_handle_t	hw_rh[VNET_NUM_HYBRID_RINGS];
279963f531d1SSriharsha Basavapatna 	mac_perim_handle_t	mph1;
280063f531d1SSriharsha Basavapatna 	vnet_pseudo_rx_group_t	*rx_grp;
280163f531d1SSriharsha Basavapatna 	vnet_pseudo_rx_ring_t	*rx_ringp;
280263f531d1SSriharsha Basavapatna 	vnet_pseudo_tx_group_t	*tx_grp;
280363f531d1SSriharsha Basavapatna 	vnet_pseudo_tx_ring_t	*tx_ringp;
280463f531d1SSriharsha Basavapatna 	int			hw_ring_cnt;
280563f531d1SSriharsha Basavapatna 	int			i;
280663f531d1SSriharsha Basavapatna 	int			rv;
280763f531d1SSriharsha Basavapatna 
280863f531d1SSriharsha Basavapatna 	mac_perim_enter_by_mh(vnetp->hio_mh, &mph1);
280963f531d1SSriharsha Basavapatna 
281063f531d1SSriharsha Basavapatna 	/* Get the list of the underlying RX rings. */
281163f531d1SSriharsha Basavapatna 	hw_ring_cnt = mac_hwrings_get(vnetp->hio_mch, &vnetp->rx_hwgh, hw_rh,
281263f531d1SSriharsha Basavapatna 	    MAC_RING_TYPE_RX);
281363f531d1SSriharsha Basavapatna 
281463f531d1SSriharsha Basavapatna 	/* We expect the the # of hw rx rings to match VNET_NUM_HYBRID_RINGS */
281563f531d1SSriharsha Basavapatna 	if (hw_ring_cnt != VNET_NUM_HYBRID_RINGS) {
281663f531d1SSriharsha Basavapatna 		cmn_err(CE_WARN,
281763f531d1SSriharsha Basavapatna 		    "!vnet%d: vnet_bind_hwrings: bad rx hw_ring_cnt(%d)\n",
281863f531d1SSriharsha Basavapatna 		    vnetp->instance, hw_ring_cnt);
281963f531d1SSriharsha Basavapatna 		goto fail;
282063f531d1SSriharsha Basavapatna 	}
282163f531d1SSriharsha Basavapatna 
282263f531d1SSriharsha Basavapatna 	if (vnetp->rx_hwgh != NULL) {
282363f531d1SSriharsha Basavapatna 		/*
282463f531d1SSriharsha Basavapatna 		 * Quiesce the HW ring and the mac srs on the ring. Note
282563f531d1SSriharsha Basavapatna 		 * that the HW ring will be restarted when the pseudo ring
282663f531d1SSriharsha Basavapatna 		 * is started. At that time all the packets will be
282763f531d1SSriharsha Basavapatna 		 * directly passed up to the pseudo RX ring and handled
282863f531d1SSriharsha Basavapatna 		 * by mac srs created over the pseudo RX ring.
282963f531d1SSriharsha Basavapatna 		 */
283063f531d1SSriharsha Basavapatna 		mac_rx_client_quiesce(vnetp->hio_mch);
283163f531d1SSriharsha Basavapatna 		mac_srs_perm_quiesce(vnetp->hio_mch, B_TRUE);
283263f531d1SSriharsha Basavapatna 	}
283363f531d1SSriharsha Basavapatna 
283463f531d1SSriharsha Basavapatna 	/*
283563f531d1SSriharsha Basavapatna 	 * Bind the pseudo rings to the hwrings and start the hwrings.
283663f531d1SSriharsha Basavapatna 	 * Note we don't need to register these with the upper mac, as we have
283763f531d1SSriharsha Basavapatna 	 * statically exported these pseudo rxrings which are reserved for
283863f531d1SSriharsha Basavapatna 	 * rxrings of Hybrid resource.
283963f531d1SSriharsha Basavapatna 	 */
284063f531d1SSriharsha Basavapatna 	rx_grp = &vnetp->rx_grp[0];
284163f531d1SSriharsha Basavapatna 	for (i = 0; i < VNET_NUM_HYBRID_RINGS; i++) {
284263f531d1SSriharsha Basavapatna 		/* Pick the rxrings reserved for Hybrid resource */
284363f531d1SSriharsha Basavapatna 		rx_ringp = &rx_grp->rings[i + VNET_HYBRID_RXRING_INDEX];
284463f531d1SSriharsha Basavapatna 
284563f531d1SSriharsha Basavapatna 		/* Store the hw ring handle */
284663f531d1SSriharsha Basavapatna 		rx_ringp->hw_rh = hw_rh[i];
284763f531d1SSriharsha Basavapatna 
284863f531d1SSriharsha Basavapatna 		/* Bind the pseudo ring to the underlying hwring */
284963f531d1SSriharsha Basavapatna 		mac_hwring_setup(rx_ringp->hw_rh,
28500dc2366fSVenugopal Iyer 		    (mac_resource_handle_t)rx_ringp, NULL);
285163f531d1SSriharsha Basavapatna 
285263f531d1SSriharsha Basavapatna 		/* Start the hwring if needed */
285363f531d1SSriharsha Basavapatna 		if (rx_ringp->state & VNET_RXRING_STARTED) {
285463f531d1SSriharsha Basavapatna 			rv = mac_hwring_start(rx_ringp->hw_rh);
285563f531d1SSriharsha Basavapatna 			if (rv != 0) {
285663f531d1SSriharsha Basavapatna 				mac_hwring_teardown(rx_ringp->hw_rh);
285763f531d1SSriharsha Basavapatna 				rx_ringp->hw_rh = NULL;
285863f531d1SSriharsha Basavapatna 				goto fail;
285963f531d1SSriharsha Basavapatna 			}
286063f531d1SSriharsha Basavapatna 		}
286163f531d1SSriharsha Basavapatna 	}
286263f531d1SSriharsha Basavapatna 
286363f531d1SSriharsha Basavapatna 	/* Get the list of the underlying TX rings. */
286463f531d1SSriharsha Basavapatna 	hw_ring_cnt = mac_hwrings_get(vnetp->hio_mch, &vnetp->tx_hwgh, hw_rh,
286563f531d1SSriharsha Basavapatna 	    MAC_RING_TYPE_TX);
286663f531d1SSriharsha Basavapatna 
286763f531d1SSriharsha Basavapatna 	/* We expect the # of hw tx rings to match VNET_NUM_HYBRID_RINGS */
286863f531d1SSriharsha Basavapatna 	if (hw_ring_cnt != VNET_NUM_HYBRID_RINGS) {
286963f531d1SSriharsha Basavapatna 		cmn_err(CE_WARN,
287063f531d1SSriharsha Basavapatna 		    "!vnet%d: vnet_bind_hwrings: bad tx hw_ring_cnt(%d)\n",
287163f531d1SSriharsha Basavapatna 		    vnetp->instance, hw_ring_cnt);
287263f531d1SSriharsha Basavapatna 		goto fail;
287363f531d1SSriharsha Basavapatna 	}
287463f531d1SSriharsha Basavapatna 
287563f531d1SSriharsha Basavapatna 	/*
287663f531d1SSriharsha Basavapatna 	 * Now map the pseudo txrings to the hw txrings. Note we don't need
287763f531d1SSriharsha Basavapatna 	 * to register these with the upper mac, as we have statically exported
287863f531d1SSriharsha Basavapatna 	 * these rings. Note that these rings will continue to be used for LDC
287963f531d1SSriharsha Basavapatna 	 * resources to peer vnets and vswitch (shared ring).
288063f531d1SSriharsha Basavapatna 	 */
288163f531d1SSriharsha Basavapatna 	tx_grp = &vnetp->tx_grp[0];
288263f531d1SSriharsha Basavapatna 	for (i = 0; i < tx_grp->ring_cnt; i++) {
288363f531d1SSriharsha Basavapatna 		tx_ringp = &tx_grp->rings[i];
288463f531d1SSriharsha Basavapatna 		tx_ringp->hw_rh = hw_rh[i];
288563f531d1SSriharsha Basavapatna 		tx_ringp->state |= VNET_TXRING_HYBRID;
288663f531d1SSriharsha Basavapatna 	}
28870dc2366fSVenugopal Iyer 	tx_grp->tx_notify_handle =
28880dc2366fSVenugopal Iyer 	    mac_client_tx_notify(vnetp->hio_mch, vnet_tx_ring_update, vnetp);
288963f531d1SSriharsha Basavapatna 
289063f531d1SSriharsha Basavapatna 	mac_perim_exit(mph1);
289163f531d1SSriharsha Basavapatna 	return (0);
289263f531d1SSriharsha Basavapatna 
289363f531d1SSriharsha Basavapatna fail:
289463f531d1SSriharsha Basavapatna 	mac_perim_exit(mph1);
289563f531d1SSriharsha Basavapatna 	vnet_unbind_hwrings(vnetp);
289663f531d1SSriharsha Basavapatna 	return (1);
289763f531d1SSriharsha Basavapatna }
289863f531d1SSriharsha Basavapatna 
289963f531d1SSriharsha Basavapatna /* Unbind pseudo rings from hwrings */
290063f531d1SSriharsha Basavapatna static void
290163f531d1SSriharsha Basavapatna vnet_unbind_hwrings(vnet_t *vnetp)
290263f531d1SSriharsha Basavapatna {
290363f531d1SSriharsha Basavapatna 	mac_perim_handle_t	mph1;
290463f531d1SSriharsha Basavapatna 	vnet_pseudo_rx_ring_t	*rx_ringp;
290563f531d1SSriharsha Basavapatna 	vnet_pseudo_rx_group_t	*rx_grp;
290663f531d1SSriharsha Basavapatna 	vnet_pseudo_tx_group_t	*tx_grp;
290763f531d1SSriharsha Basavapatna 	vnet_pseudo_tx_ring_t	*tx_ringp;
290863f531d1SSriharsha Basavapatna 	int			i;
290963f531d1SSriharsha Basavapatna 
291063f531d1SSriharsha Basavapatna 	mac_perim_enter_by_mh(vnetp->hio_mh, &mph1);
291163f531d1SSriharsha Basavapatna 
291263f531d1SSriharsha Basavapatna 	tx_grp = &vnetp->tx_grp[0];
291363f531d1SSriharsha Basavapatna 	for (i = 0; i < VNET_NUM_HYBRID_RINGS; i++) {
291463f531d1SSriharsha Basavapatna 		tx_ringp = &tx_grp->rings[i];
291563f531d1SSriharsha Basavapatna 		if (tx_ringp->state & VNET_TXRING_HYBRID) {
291663f531d1SSriharsha Basavapatna 			tx_ringp->state &= ~VNET_TXRING_HYBRID;
291763f531d1SSriharsha Basavapatna 			tx_ringp->hw_rh = NULL;
291863f531d1SSriharsha Basavapatna 		}
291963f531d1SSriharsha Basavapatna 	}
29200dc2366fSVenugopal Iyer 	(void) mac_client_tx_notify(vnetp->hio_mch, NULL,
29210dc2366fSVenugopal Iyer 	    tx_grp->tx_notify_handle);
292263f531d1SSriharsha Basavapatna 
292363f531d1SSriharsha Basavapatna 	rx_grp = &vnetp->rx_grp[0];
292463f531d1SSriharsha Basavapatna 	for (i = 0; i < VNET_NUM_HYBRID_RINGS; i++) {
292563f531d1SSriharsha Basavapatna 		rx_ringp = &rx_grp->rings[i + VNET_HYBRID_RXRING_INDEX];
292663f531d1SSriharsha Basavapatna 		if (rx_ringp->hw_rh != NULL) {
292763f531d1SSriharsha Basavapatna 			/* Stop the hwring */
292863f531d1SSriharsha Basavapatna 			mac_hwring_stop(rx_ringp->hw_rh);
292963f531d1SSriharsha Basavapatna 
293063f531d1SSriharsha Basavapatna 			/* Teardown the hwring */
293163f531d1SSriharsha Basavapatna 			mac_hwring_teardown(rx_ringp->hw_rh);
293263f531d1SSriharsha Basavapatna 			rx_ringp->hw_rh = NULL;
293363f531d1SSriharsha Basavapatna 		}
293463f531d1SSriharsha Basavapatna 	}
293563f531d1SSriharsha Basavapatna 
293663f531d1SSriharsha Basavapatna 	if (vnetp->rx_hwgh != NULL) {
293763f531d1SSriharsha Basavapatna 		vnetp->rx_hwgh = NULL;
293863f531d1SSriharsha Basavapatna 		/*
293963f531d1SSriharsha Basavapatna 		 * First clear the permanent-quiesced flag of the RX srs then
294063f531d1SSriharsha Basavapatna 		 * restart the HW ring and the mac srs on the ring.
294163f531d1SSriharsha Basavapatna 		 */
294263f531d1SSriharsha Basavapatna 		mac_srs_perm_quiesce(vnetp->hio_mch, B_FALSE);
294363f531d1SSriharsha Basavapatna 		mac_rx_client_restart(vnetp->hio_mch);
294463f531d1SSriharsha Basavapatna 	}
294563f531d1SSriharsha Basavapatna 
294663f531d1SSriharsha Basavapatna 	mac_perim_exit(mph1);
294763f531d1SSriharsha Basavapatna }
294863f531d1SSriharsha Basavapatna 
294963f531d1SSriharsha Basavapatna /* Bind pseudo ring to a LDC resource */
295063f531d1SSriharsha Basavapatna static int
295163f531d1SSriharsha Basavapatna vnet_bind_vgenring(vnet_res_t *vresp)
295263f531d1SSriharsha Basavapatna {
295363f531d1SSriharsha Basavapatna 	vnet_t			*vnetp;
295463f531d1SSriharsha Basavapatna 	vnet_pseudo_rx_group_t	*rx_grp;
295563f531d1SSriharsha Basavapatna 	vnet_pseudo_rx_ring_t	*rx_ringp;
295663f531d1SSriharsha Basavapatna 	mac_perim_handle_t	mph1;
295763f531d1SSriharsha Basavapatna 	int			rv;
295863f531d1SSriharsha Basavapatna 	int			type;
295963f531d1SSriharsha Basavapatna 
296063f531d1SSriharsha Basavapatna 	vnetp = vresp->vnetp;
296163f531d1SSriharsha Basavapatna 	type = vresp->type;
296263f531d1SSriharsha Basavapatna 	rx_grp = &vnetp->rx_grp[0];
296363f531d1SSriharsha Basavapatna 
296463f531d1SSriharsha Basavapatna 	if (type == VIO_NET_RES_LDC_SERVICE) {
296563f531d1SSriharsha Basavapatna 		/*
296663f531d1SSriharsha Basavapatna 		 * Ring Index 0 is the default ring in the group and is
296763f531d1SSriharsha Basavapatna 		 * reserved for LDC_SERVICE in vnet_ring_grp_init(). This ring
296863f531d1SSriharsha Basavapatna 		 * is allocated statically and is reported to the mac layer
296963f531d1SSriharsha Basavapatna 		 * in vnet_m_capab(). So, all we need to do here, is save a
297063f531d1SSriharsha Basavapatna 		 * reference to the associated vresp.
297163f531d1SSriharsha Basavapatna 		 */
297263f531d1SSriharsha Basavapatna 		rx_ringp = &rx_grp->rings[0];
297363f531d1SSriharsha Basavapatna 		rx_ringp->hw_rh = (mac_ring_handle_t)vresp;
297463f531d1SSriharsha Basavapatna 		vresp->rx_ringp = (void *)rx_ringp;
297563f531d1SSriharsha Basavapatna 		return (0);
297663f531d1SSriharsha Basavapatna 	}
297763f531d1SSriharsha Basavapatna 	ASSERT(type == VIO_NET_RES_LDC_GUEST);
297863f531d1SSriharsha Basavapatna 
297963f531d1SSriharsha Basavapatna 	mac_perim_enter_by_mh(vnetp->mh, &mph1);
298063f531d1SSriharsha Basavapatna 
298163f531d1SSriharsha Basavapatna 	rx_ringp = vnet_alloc_pseudo_rx_ring(vnetp);
298263f531d1SSriharsha Basavapatna 	if (rx_ringp == NULL) {
298363f531d1SSriharsha Basavapatna 		cmn_err(CE_WARN, "!vnet%d: Failed to allocate pseudo rx ring",
298463f531d1SSriharsha Basavapatna 		    vnetp->instance);
298563f531d1SSriharsha Basavapatna 		goto fail;
298663f531d1SSriharsha Basavapatna 	}
298763f531d1SSriharsha Basavapatna 
298863f531d1SSriharsha Basavapatna 	/* Store the LDC resource itself as the ring handle */
298963f531d1SSriharsha Basavapatna 	rx_ringp->hw_rh = (mac_ring_handle_t)vresp;
299063f531d1SSriharsha Basavapatna 
299163f531d1SSriharsha Basavapatna 	/*
299263f531d1SSriharsha Basavapatna 	 * Save a reference to the ring in the resource for lookup during
299363f531d1SSriharsha Basavapatna 	 * unbind. Note this is only done for LDC resources. We don't need this
299463f531d1SSriharsha Basavapatna 	 * in the case of a Hybrid resource (see vnet_bind_hwrings()), as its
299563f531d1SSriharsha Basavapatna 	 * rx rings are mapped to reserved pseudo rx rings (index 1 and 2).
299663f531d1SSriharsha Basavapatna 	 */
299763f531d1SSriharsha Basavapatna 	vresp->rx_ringp = (void *)rx_ringp;
299863f531d1SSriharsha Basavapatna 	rx_ringp->state |= VNET_RXRING_LDC_GUEST;
299963f531d1SSriharsha Basavapatna 
300063f531d1SSriharsha Basavapatna 	/* Register the pseudo ring with upper-mac */
300163f531d1SSriharsha Basavapatna 	rv = mac_group_add_ring(rx_grp->handle, rx_ringp->index);
300263f531d1SSriharsha Basavapatna 	if (rv != 0) {
300363f531d1SSriharsha Basavapatna 		rx_ringp->state &= ~VNET_RXRING_LDC_GUEST;
300463f531d1SSriharsha Basavapatna 		rx_ringp->hw_rh = NULL;
300563f531d1SSriharsha Basavapatna 		vnet_free_pseudo_rx_ring(vnetp, rx_ringp);
300663f531d1SSriharsha Basavapatna 		goto fail;
300763f531d1SSriharsha Basavapatna 	}
300863f531d1SSriharsha Basavapatna 
300963f531d1SSriharsha Basavapatna 	mac_perim_exit(mph1);
301063f531d1SSriharsha Basavapatna 	return (0);
301163f531d1SSriharsha Basavapatna fail:
301263f531d1SSriharsha Basavapatna 	mac_perim_exit(mph1);
301363f531d1SSriharsha Basavapatna 	return (1);
301463f531d1SSriharsha Basavapatna }
301563f531d1SSriharsha Basavapatna 
301663f531d1SSriharsha Basavapatna /* Unbind pseudo ring from a LDC resource */
301763f531d1SSriharsha Basavapatna static void
301863f531d1SSriharsha Basavapatna vnet_unbind_vgenring(vnet_res_t *vresp)
301963f531d1SSriharsha Basavapatna {
302063f531d1SSriharsha Basavapatna 	vnet_t			*vnetp;
302163f531d1SSriharsha Basavapatna 	vnet_pseudo_rx_group_t	*rx_grp;
302263f531d1SSriharsha Basavapatna 	vnet_pseudo_rx_ring_t	*rx_ringp;
302363f531d1SSriharsha Basavapatna 	mac_perim_handle_t	mph1;
302463f531d1SSriharsha Basavapatna 	int			type;
302563f531d1SSriharsha Basavapatna 
302663f531d1SSriharsha Basavapatna 	vnetp = vresp->vnetp;
302763f531d1SSriharsha Basavapatna 	type = vresp->type;
302863f531d1SSriharsha Basavapatna 	rx_grp = &vnetp->rx_grp[0];
302963f531d1SSriharsha Basavapatna 
303063f531d1SSriharsha Basavapatna 	if (vresp->rx_ringp == NULL) {
303163f531d1SSriharsha Basavapatna 		return;
303263f531d1SSriharsha Basavapatna 	}
303363f531d1SSriharsha Basavapatna 
303463f531d1SSriharsha Basavapatna 	if (type == VIO_NET_RES_LDC_SERVICE) {
303563f531d1SSriharsha Basavapatna 		/*
303663f531d1SSriharsha Basavapatna 		 * Ring Index 0 is the default ring in the group and is
303763f531d1SSriharsha Basavapatna 		 * reserved for LDC_SERVICE in vnet_ring_grp_init(). This ring
303863f531d1SSriharsha Basavapatna 		 * is allocated statically and is reported to the mac layer
303963f531d1SSriharsha Basavapatna 		 * in vnet_m_capab(). So, all we need to do here, is remove its
304063f531d1SSriharsha Basavapatna 		 * reference to the associated vresp.
304163f531d1SSriharsha Basavapatna 		 */
304263f531d1SSriharsha Basavapatna 		rx_ringp = &rx_grp->rings[0];
304363f531d1SSriharsha Basavapatna 		rx_ringp->hw_rh = NULL;
304463f531d1SSriharsha Basavapatna 		vresp->rx_ringp = NULL;
304563f531d1SSriharsha Basavapatna 		return;
304663f531d1SSriharsha Basavapatna 	}
304763f531d1SSriharsha Basavapatna 	ASSERT(type == VIO_NET_RES_LDC_GUEST);
304863f531d1SSriharsha Basavapatna 
304963f531d1SSriharsha Basavapatna 	mac_perim_enter_by_mh(vnetp->mh, &mph1);
305063f531d1SSriharsha Basavapatna 
305163f531d1SSriharsha Basavapatna 	rx_ringp = (vnet_pseudo_rx_ring_t *)vresp->rx_ringp;
305263f531d1SSriharsha Basavapatna 	vresp->rx_ringp = NULL;
305363f531d1SSriharsha Basavapatna 
305463f531d1SSriharsha Basavapatna 	if (rx_ringp != NULL && (rx_ringp->state & VNET_RXRING_LDC_GUEST)) {
305563f531d1SSriharsha Basavapatna 		/* Unregister the pseudo ring with upper-mac */
305663f531d1SSriharsha Basavapatna 		mac_group_rem_ring(rx_grp->handle, rx_ringp->handle);
305763f531d1SSriharsha Basavapatna 
305863f531d1SSriharsha Basavapatna 		rx_ringp->hw_rh = NULL;
305963f531d1SSriharsha Basavapatna 		rx_ringp->state &= ~VNET_RXRING_LDC_GUEST;
306063f531d1SSriharsha Basavapatna 
306163f531d1SSriharsha Basavapatna 		/* Free the pseudo rx ring */
306263f531d1SSriharsha Basavapatna 		vnet_free_pseudo_rx_ring(vnetp, rx_ringp);
306363f531d1SSriharsha Basavapatna 	}
306463f531d1SSriharsha Basavapatna 
306563f531d1SSriharsha Basavapatna 	mac_perim_exit(mph1);
306663f531d1SSriharsha Basavapatna }
306763f531d1SSriharsha Basavapatna 
306863f531d1SSriharsha Basavapatna static void
306963f531d1SSriharsha Basavapatna vnet_unbind_rings(vnet_res_t *vresp)
307063f531d1SSriharsha Basavapatna {
307163f531d1SSriharsha Basavapatna 	switch (vresp->type) {
307263f531d1SSriharsha Basavapatna 
307363f531d1SSriharsha Basavapatna 	case VIO_NET_RES_LDC_SERVICE:
307463f531d1SSriharsha Basavapatna 	case VIO_NET_RES_LDC_GUEST:
307563f531d1SSriharsha Basavapatna 		vnet_unbind_vgenring(vresp);
307663f531d1SSriharsha Basavapatna 		break;
307763f531d1SSriharsha Basavapatna 
307863f531d1SSriharsha Basavapatna 	case VIO_NET_RES_HYBRID:
307963f531d1SSriharsha Basavapatna 		vnet_unbind_hwrings(vresp->vnetp);
308063f531d1SSriharsha Basavapatna 		break;
308163f531d1SSriharsha Basavapatna 
308263f531d1SSriharsha Basavapatna 	default:
308363f531d1SSriharsha Basavapatna 		break;
308463f531d1SSriharsha Basavapatna 
308563f531d1SSriharsha Basavapatna 	}
308663f531d1SSriharsha Basavapatna }
308763f531d1SSriharsha Basavapatna 
308863f531d1SSriharsha Basavapatna static int
308963f531d1SSriharsha Basavapatna vnet_bind_rings(vnet_res_t *vresp)
309063f531d1SSriharsha Basavapatna {
309163f531d1SSriharsha Basavapatna 	int	rv;
309263f531d1SSriharsha Basavapatna 
309363f531d1SSriharsha Basavapatna 	switch (vresp->type) {
309463f531d1SSriharsha Basavapatna 
309563f531d1SSriharsha Basavapatna 	case VIO_NET_RES_LDC_SERVICE:
309663f531d1SSriharsha Basavapatna 	case VIO_NET_RES_LDC_GUEST:
309763f531d1SSriharsha Basavapatna 		rv = vnet_bind_vgenring(vresp);
309863f531d1SSriharsha Basavapatna 		break;
309963f531d1SSriharsha Basavapatna 
310063f531d1SSriharsha Basavapatna 	case VIO_NET_RES_HYBRID:
310163f531d1SSriharsha Basavapatna 		rv = vnet_bind_hwrings(vresp->vnetp);
310263f531d1SSriharsha Basavapatna 		break;
310363f531d1SSriharsha Basavapatna 
310463f531d1SSriharsha Basavapatna 	default:
310563f531d1SSriharsha Basavapatna 		rv = 1;
310663f531d1SSriharsha Basavapatna 		break;
310763f531d1SSriharsha Basavapatna 
310863f531d1SSriharsha Basavapatna 	}
310963f531d1SSriharsha Basavapatna 
311063f531d1SSriharsha Basavapatna 	return (rv);
311163f531d1SSriharsha Basavapatna }
311263f531d1SSriharsha Basavapatna 
311363f531d1SSriharsha Basavapatna /* ARGSUSED */
311463f531d1SSriharsha Basavapatna int
311563f531d1SSriharsha Basavapatna vnet_hio_stat(void *arg, uint_t stat, uint64_t *val)
311663f531d1SSriharsha Basavapatna {
311763f531d1SSriharsha Basavapatna 	vnet_t	*vnetp = (vnet_t *)arg;
311863f531d1SSriharsha Basavapatna 
311963f531d1SSriharsha Basavapatna 	*val = mac_stat_get(vnetp->hio_mh, stat);
312063f531d1SSriharsha Basavapatna 	return (0);
312163f531d1SSriharsha Basavapatna }
312263f531d1SSriharsha Basavapatna 
312363f531d1SSriharsha Basavapatna /*
312463f531d1SSriharsha Basavapatna  * The start() and stop() routines for the Hybrid resource below, are just
312563f531d1SSriharsha Basavapatna  * dummy functions. This is provided to avoid resource type specific code in
312663f531d1SSriharsha Basavapatna  * vnet_start_resources() and vnet_stop_resources(). The starting and stopping
312763f531d1SSriharsha Basavapatna  * of the Hybrid resource happens in the context of the mac_client interfaces
312863f531d1SSriharsha Basavapatna  * that are invoked in vnet_hio_mac_init() and vnet_hio_mac_cleanup().
312963f531d1SSriharsha Basavapatna  */
313063f531d1SSriharsha Basavapatna /* ARGSUSED */
313163f531d1SSriharsha Basavapatna static int
313263f531d1SSriharsha Basavapatna vnet_hio_start(void *arg)
313363f531d1SSriharsha Basavapatna {
313463f531d1SSriharsha Basavapatna 	return (0);
313563f531d1SSriharsha Basavapatna }
313663f531d1SSriharsha Basavapatna 
313763f531d1SSriharsha Basavapatna /* ARGSUSED */
313863f531d1SSriharsha Basavapatna static void
313963f531d1SSriharsha Basavapatna vnet_hio_stop(void *arg)
314063f531d1SSriharsha Basavapatna {
314163f531d1SSriharsha Basavapatna }
314263f531d1SSriharsha Basavapatna 
314363f531d1SSriharsha Basavapatna mblk_t *
314463f531d1SSriharsha Basavapatna vnet_hio_tx(void *arg, mblk_t *mp)
314563f531d1SSriharsha Basavapatna {
314663f531d1SSriharsha Basavapatna 	vnet_pseudo_tx_ring_t	*tx_ringp;
314763f531d1SSriharsha Basavapatna 	mblk_t			*nextp;
314863f531d1SSriharsha Basavapatna 	mblk_t			*ret_mp;
314963f531d1SSriharsha Basavapatna 
315063f531d1SSriharsha Basavapatna 	tx_ringp = (vnet_pseudo_tx_ring_t *)arg;
315163f531d1SSriharsha Basavapatna 	for (;;) {
315263f531d1SSriharsha Basavapatna 		nextp = mp->b_next;
315363f531d1SSriharsha Basavapatna 		mp->b_next = NULL;
315463f531d1SSriharsha Basavapatna 
315563f531d1SSriharsha Basavapatna 		ret_mp = mac_hwring_tx(tx_ringp->hw_rh, mp);
315663f531d1SSriharsha Basavapatna 		if (ret_mp != NULL) {
315763f531d1SSriharsha Basavapatna 			ret_mp->b_next = nextp;
315863f531d1SSriharsha Basavapatna 			mp = ret_mp;
315963f531d1SSriharsha Basavapatna 			break;
316063f531d1SSriharsha Basavapatna 		}
316163f531d1SSriharsha Basavapatna 
316263f531d1SSriharsha Basavapatna 		if ((mp = nextp) == NULL)
316363f531d1SSriharsha Basavapatna 			break;
316463f531d1SSriharsha Basavapatna 	}
316563f531d1SSriharsha Basavapatna 	return (mp);
316663f531d1SSriharsha Basavapatna }
316763f531d1SSriharsha Basavapatna 
31681107ea93SSriharsha Basavapatna #ifdef	VNET_IOC_DEBUG
31691107ea93SSriharsha Basavapatna 
31701107ea93SSriharsha Basavapatna /*
31711107ea93SSriharsha Basavapatna  * The ioctl entry point is used only for debugging for now. The ioctl commands
31721107ea93SSriharsha Basavapatna  * can be used to force the link state of the channel connected to vsw.
31731107ea93SSriharsha Basavapatna  */
31741107ea93SSriharsha Basavapatna static void
31751107ea93SSriharsha Basavapatna vnet_m_ioctl(void *arg, queue_t *q, mblk_t *mp)
31761107ea93SSriharsha Basavapatna {
31771107ea93SSriharsha Basavapatna 	struct iocblk	*iocp;
31781107ea93SSriharsha Basavapatna 	vnet_t		*vnetp;
31791107ea93SSriharsha Basavapatna 
31801107ea93SSriharsha Basavapatna 	iocp = (struct iocblk *)(uintptr_t)mp->b_rptr;
31811107ea93SSriharsha Basavapatna 	iocp->ioc_error = 0;
31821107ea93SSriharsha Basavapatna 	vnetp = (vnet_t *)arg;
31831107ea93SSriharsha Basavapatna 
31841107ea93SSriharsha Basavapatna 	if (vnetp == NULL) {
31851107ea93SSriharsha Basavapatna 		miocnak(q, mp, 0, EINVAL);
31861107ea93SSriharsha Basavapatna 		return;
31871107ea93SSriharsha Basavapatna 	}
31881107ea93SSriharsha Basavapatna 
31891107ea93SSriharsha Basavapatna 	switch (iocp->ioc_cmd) {
31901107ea93SSriharsha Basavapatna 
31911107ea93SSriharsha Basavapatna 	case VNET_FORCE_LINK_DOWN:
31921107ea93SSriharsha Basavapatna 	case VNET_FORCE_LINK_UP:
31931107ea93SSriharsha Basavapatna 		vnet_force_link_state(vnetp, q, mp);
31941107ea93SSriharsha Basavapatna 		break;
31951107ea93SSriharsha Basavapatna 
31961107ea93SSriharsha Basavapatna 	default:
31971107ea93SSriharsha Basavapatna 		iocp->ioc_error = EINVAL;
31981107ea93SSriharsha Basavapatna 		miocnak(q, mp, 0, iocp->ioc_error);
31991107ea93SSriharsha Basavapatna 		break;
32001107ea93SSriharsha Basavapatna 
32011107ea93SSriharsha Basavapatna 	}
32021107ea93SSriharsha Basavapatna }
32031107ea93SSriharsha Basavapatna 
32041107ea93SSriharsha Basavapatna static void
32051107ea93SSriharsha Basavapatna vnet_force_link_state(vnet_t *vnetp, queue_t *q, mblk_t *mp)
32061107ea93SSriharsha Basavapatna {
32071107ea93SSriharsha Basavapatna 	mac_register_t	*macp;
32081107ea93SSriharsha Basavapatna 	mac_callbacks_t	*cbp;
32091107ea93SSriharsha Basavapatna 	vnet_res_t	*vresp;
32101107ea93SSriharsha Basavapatna 
32111107ea93SSriharsha Basavapatna 	READ_ENTER(&vnetp->vsw_fp_rw);
32121107ea93SSriharsha Basavapatna 
32131107ea93SSriharsha Basavapatna 	vresp = vnetp->vsw_fp;
32141107ea93SSriharsha Basavapatna 	if (vresp == NULL) {
32151107ea93SSriharsha Basavapatna 		RW_EXIT(&vnetp->vsw_fp_rw);
32161107ea93SSriharsha Basavapatna 		return;
32171107ea93SSriharsha Basavapatna 	}
32181107ea93SSriharsha Basavapatna 
32191107ea93SSriharsha Basavapatna 	macp = &vresp->macreg;
32201107ea93SSriharsha Basavapatna 	cbp = macp->m_callbacks;
32211107ea93SSriharsha Basavapatna 	cbp->mc_ioctl(macp->m_driver, q, mp);
32221107ea93SSriharsha Basavapatna 
32231107ea93SSriharsha Basavapatna 	RW_EXIT(&vnetp->vsw_fp_rw);
32241107ea93SSriharsha Basavapatna }
32251107ea93SSriharsha Basavapatna 
32261107ea93SSriharsha Basavapatna #else
32271107ea93SSriharsha Basavapatna 
32281107ea93SSriharsha Basavapatna static void
32291107ea93SSriharsha Basavapatna vnet_m_ioctl(void *arg, queue_t *q, mblk_t *mp)
32301107ea93SSriharsha Basavapatna {
32311107ea93SSriharsha Basavapatna 	vnet_t		*vnetp;
32321107ea93SSriharsha Basavapatna 
32331107ea93SSriharsha Basavapatna 	vnetp = (vnet_t *)arg;
32341107ea93SSriharsha Basavapatna 
32351107ea93SSriharsha Basavapatna 	if (vnetp == NULL) {
32361107ea93SSriharsha Basavapatna 		miocnak(q, mp, 0, EINVAL);
32371107ea93SSriharsha Basavapatna 		return;
32381107ea93SSriharsha Basavapatna 	}
32391107ea93SSriharsha Basavapatna 
32401107ea93SSriharsha Basavapatna 	/* ioctl support only for debugging */
32411107ea93SSriharsha Basavapatna 	miocnak(q, mp, 0, ENOTSUP);
32421107ea93SSriharsha Basavapatna }
32431107ea93SSriharsha Basavapatna 
32441107ea93SSriharsha Basavapatna #endif
3245