xref: /titanic_53/usr/src/uts/sun4v/io/vnet.c (revision 63f531d1cf94e7ff3e74e15ca709808d96e239f3)
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 /*
236f09f0feSWENTAO YANG  * Copyright 2009 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>
301ae08745Sheppo #include <sys/stream.h>
311ae08745Sheppo #include <sys/kmem.h>
321ae08745Sheppo #include <sys/conf.h>
331ae08745Sheppo #include <sys/devops.h>
341ae08745Sheppo #include <sys/ksynch.h>
351ae08745Sheppo #include <sys/stat.h>
361ae08745Sheppo #include <sys/modctl.h>
37c1c61f44Ssb155480 #include <sys/modhash.h>
381ae08745Sheppo #include <sys/debug.h>
391ae08745Sheppo #include <sys/ethernet.h>
401ae08745Sheppo #include <sys/dlpi.h>
411ae08745Sheppo #include <net/if.h>
42da14cebeSEric Cheng #include <sys/mac_provider.h>
43*63f531d1SSriharsha Basavapatna #include <sys/mac_client.h>
44*63f531d1SSriharsha Basavapatna #include <sys/mac_client_priv.h>
45ba2e4443Sseb #include <sys/mac_ether.h>
461ae08745Sheppo #include <sys/ddi.h>
471ae08745Sheppo #include <sys/sunddi.h>
481ae08745Sheppo #include <sys/strsun.h>
491ae08745Sheppo #include <sys/note.h>
50c1c61f44Ssb155480 #include <sys/atomic.h>
511ae08745Sheppo #include <sys/vnet.h>
52c1c61f44Ssb155480 #include <sys/vlan.h>
53678453a8Sspeer #include <sys/vnet_mailbox.h>
54678453a8Sspeer #include <sys/vnet_common.h>
55678453a8Sspeer #include <sys/dds.h>
56678453a8Sspeer #include <sys/strsubr.h>
57678453a8Sspeer #include <sys/taskq.h>
581ae08745Sheppo 
591ae08745Sheppo /*
601ae08745Sheppo  * Function prototypes.
611ae08745Sheppo  */
621ae08745Sheppo 
631ae08745Sheppo /* DDI entrypoints */
641ae08745Sheppo static int vnetdevinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
651ae08745Sheppo static int vnetattach(dev_info_t *, ddi_attach_cmd_t);
661ae08745Sheppo static int vnetdetach(dev_info_t *, ddi_detach_cmd_t);
671ae08745Sheppo 
681ae08745Sheppo /* MAC entrypoints  */
69ba2e4443Sseb static int vnet_m_stat(void *, uint_t, uint64_t *);
701ae08745Sheppo static int vnet_m_start(void *);
711ae08745Sheppo static void vnet_m_stop(void *);
721ae08745Sheppo static int vnet_m_promisc(void *, boolean_t);
731ae08745Sheppo static int vnet_m_multicst(void *, boolean_t, const uint8_t *);
741ae08745Sheppo static int vnet_m_unicst(void *, const uint8_t *);
751ae08745Sheppo mblk_t *vnet_m_tx(void *, mblk_t *);
761107ea93SSriharsha Basavapatna static void vnet_m_ioctl(void *arg, queue_t *q, mblk_t *mp);
771107ea93SSriharsha Basavapatna #ifdef	VNET_IOC_DEBUG
781107ea93SSriharsha Basavapatna static void vnet_force_link_state(vnet_t *vnetp, queue_t *q, mblk_t *mp);
791107ea93SSriharsha Basavapatna #endif
80*63f531d1SSriharsha Basavapatna static boolean_t vnet_m_capab(void *arg, mac_capab_t cap, void *cap_data);
81*63f531d1SSriharsha Basavapatna static void vnet_get_ring(void *arg, mac_ring_type_t rtype, const int g_index,
82*63f531d1SSriharsha Basavapatna 	const int r_index, mac_ring_info_t *infop, mac_ring_handle_t r_handle);
83*63f531d1SSriharsha Basavapatna static void vnet_get_group(void *arg, mac_ring_type_t type, const int index,
84*63f531d1SSriharsha Basavapatna 	mac_group_info_t *infop, mac_group_handle_t handle);
85*63f531d1SSriharsha Basavapatna static int vnet_rx_ring_start(mac_ring_driver_t rdriver, uint64_t mr_gen_num);
86*63f531d1SSriharsha Basavapatna static void vnet_rx_ring_stop(mac_ring_driver_t rdriver);
87*63f531d1SSriharsha Basavapatna static int vnet_tx_ring_start(mac_ring_driver_t rdriver, uint64_t mr_gen_num);
88*63f531d1SSriharsha Basavapatna static void vnet_tx_ring_stop(mac_ring_driver_t rdriver);
89*63f531d1SSriharsha Basavapatna static int vnet_ring_enable_intr(void *arg);
90*63f531d1SSriharsha Basavapatna static int vnet_ring_disable_intr(void *arg);
91*63f531d1SSriharsha Basavapatna static mblk_t *vnet_rx_poll(void *arg, int bytes_to_pickup);
92*63f531d1SSriharsha Basavapatna static int vnet_addmac(void *arg, const uint8_t *mac_addr);
93*63f531d1SSriharsha Basavapatna static int vnet_remmac(void *arg, const uint8_t *mac_addr);
941ae08745Sheppo 
951ae08745Sheppo /* vnet internal functions */
966f09f0feSWENTAO YANG static int vnet_unattach(vnet_t *vnetp);
97*63f531d1SSriharsha Basavapatna static void vnet_ring_grp_init(vnet_t *vnetp);
98*63f531d1SSriharsha Basavapatna static void vnet_ring_grp_uninit(vnet_t *vnetp);
991ae08745Sheppo static int vnet_mac_register(vnet_t *);
1001ae08745Sheppo static int vnet_read_mac_address(vnet_t *vnetp);
101*63f531d1SSriharsha Basavapatna static int vnet_bind_vgenring(vnet_res_t *vresp);
102*63f531d1SSriharsha Basavapatna static void vnet_unbind_vgenring(vnet_res_t *vresp);
103*63f531d1SSriharsha Basavapatna static int vnet_bind_hwrings(vnet_t *vnetp);
104*63f531d1SSriharsha Basavapatna static void vnet_unbind_hwrings(vnet_t *vnetp);
105*63f531d1SSriharsha Basavapatna static int vnet_bind_rings(vnet_res_t *vresp);
106*63f531d1SSriharsha Basavapatna static void vnet_unbind_rings(vnet_res_t *vresp);
107*63f531d1SSriharsha Basavapatna static int vnet_hio_stat(void *, uint_t, uint64_t *);
108*63f531d1SSriharsha Basavapatna static int vnet_hio_start(void *);
109*63f531d1SSriharsha Basavapatna static void vnet_hio_stop(void *);
110*63f531d1SSriharsha Basavapatna static void vnet_hio_notify_cb(void *arg, mac_notify_type_t type);
111*63f531d1SSriharsha Basavapatna mblk_t *vnet_hio_tx(void *, mblk_t *);
1121ae08745Sheppo 
113c1c61f44Ssb155480 /* Forwarding database (FDB) routines */
114c1c61f44Ssb155480 static void vnet_fdb_create(vnet_t *vnetp);
115c1c61f44Ssb155480 static void vnet_fdb_destroy(vnet_t *vnetp);
116678453a8Sspeer static vnet_res_t *vnet_fdbe_find(vnet_t *vnetp, struct ether_addr *addrp);
117c1c61f44Ssb155480 static void vnet_fdbe_find_cb(mod_hash_key_t key, mod_hash_val_t val);
118678453a8Sspeer void vnet_fdbe_add(vnet_t *vnetp, vnet_res_t *vresp);
119678453a8Sspeer static void vnet_fdbe_del(vnet_t *vnetp, vnet_res_t *vresp);
120c1c61f44Ssb155480 
1218c242ab0SSriharsha Basavapatna static void vnet_rx_frames_untag(uint16_t pvid, mblk_t **mp);
122678453a8Sspeer static void vnet_rx(vio_net_handle_t vrh, mblk_t *mp);
123678453a8Sspeer static void vnet_tx_update(vio_net_handle_t vrh);
124678453a8Sspeer static void vnet_res_start_task(void *arg);
125678453a8Sspeer static void vnet_start_resources(vnet_t *vnetp);
126678453a8Sspeer static void vnet_stop_resources(vnet_t *vnetp);
127678453a8Sspeer static void vnet_dispatch_res_task(vnet_t *vnetp);
128678453a8Sspeer static void vnet_res_start_task(void *arg);
129678453a8Sspeer static void vnet_handle_res_err(vio_net_handle_t vrh, vio_net_err_val_t err);
130*63f531d1SSriharsha Basavapatna static void vnet_add_resource(vnet_t *vnetp, vnet_res_t *vresp);
131*63f531d1SSriharsha Basavapatna static vnet_res_t *vnet_rem_resource(vnet_t *vnetp, vnet_res_t *vresp);
1321107ea93SSriharsha Basavapatna 
1331107ea93SSriharsha Basavapatna /* Exported to vnet_gen */
1347b1f684aSSriharsha Basavapatna int vnet_mtu_update(vnet_t *vnetp, uint32_t mtu);
1351107ea93SSriharsha Basavapatna void vnet_link_update(vnet_t *vnetp, link_state_t link_state);
1366d6de4eeSWENTAO YANG void vnet_dds_cleanup_hio(vnet_t *vnetp);
137678453a8Sspeer 
1386ab6cb20SWENTAO YANG static kstat_t *vnet_hio_setup_kstats(char *ks_mod, char *ks_name,
1396ab6cb20SWENTAO YANG     vnet_res_t *vresp);
1406ab6cb20SWENTAO YANG static int vnet_hio_update_kstats(kstat_t *ksp, int rw);
1416ab6cb20SWENTAO YANG static void vnet_hio_get_stats(vnet_res_t *vresp, vnet_hio_stats_t *statsp);
1426ab6cb20SWENTAO YANG static void vnet_hio_destroy_kstats(kstat_t *ksp);
1436ab6cb20SWENTAO YANG 
144678453a8Sspeer /* Exported to to vnet_dds */
145678453a8Sspeer int vnet_send_dds_msg(vnet_t *vnetp, void *dmsg);
146*63f531d1SSriharsha Basavapatna int vnet_hio_mac_init(vnet_t *vnetp, char *ifname);
147*63f531d1SSriharsha Basavapatna void vnet_hio_mac_cleanup(vnet_t *vnetp);
148678453a8Sspeer 
149678453a8Sspeer /* Externs that are imported from vnet_gen */
150678453a8Sspeer extern int vgen_init(void *vnetp, uint64_t regprop, dev_info_t *vnetdip,
151678453a8Sspeer     const uint8_t *macaddr, void **vgenhdl);
152*63f531d1SSriharsha Basavapatna extern int vgen_init_mdeg(void *arg);
1533ab636deSWENTAO YANG extern void vgen_uninit(void *arg);
154678453a8Sspeer extern int vgen_dds_tx(void *arg, void *dmsg);
1556f09f0feSWENTAO YANG extern void vgen_mod_init(void);
1566f09f0feSWENTAO YANG extern int vgen_mod_cleanup(void);
1576f09f0feSWENTAO YANG extern void vgen_mod_fini(void);
158*63f531d1SSriharsha Basavapatna extern int vgen_enable_intr(void *arg);
159*63f531d1SSriharsha Basavapatna extern int vgen_disable_intr(void *arg);
160*63f531d1SSriharsha Basavapatna extern mblk_t *vgen_poll(void *arg, int bytes_to_pickup);
161678453a8Sspeer 
162678453a8Sspeer /* Externs that are imported from vnet_dds */
163678453a8Sspeer extern void vdds_mod_init(void);
164678453a8Sspeer extern void vdds_mod_fini(void);
165678453a8Sspeer extern int vdds_init(vnet_t *vnetp);
166678453a8Sspeer extern void vdds_cleanup(vnet_t *vnetp);
167678453a8Sspeer extern void vdds_process_dds_msg(vnet_t *vnetp, vio_dds_msg_t *dmsg);
168d0288fccSRaghuram Kothakota extern void vdds_cleanup_hybrid_res(void *arg);
1696d6de4eeSWENTAO YANG extern void vdds_cleanup_hio(vnet_t *vnetp);
1701ae08745Sheppo 
171*63f531d1SSriharsha Basavapatna /* Externs imported from mac_impl */
172*63f531d1SSriharsha Basavapatna extern mblk_t *mac_hwring_tx(mac_ring_handle_t, mblk_t *);
173*63f531d1SSriharsha Basavapatna 
1746ab6cb20SWENTAO YANG #define	DRV_NAME	"vnet"
175c1c61f44Ssb155480 #define	VNET_FDBE_REFHOLD(p)						\
176c1c61f44Ssb155480 {									\
177c1c61f44Ssb155480 	atomic_inc_32(&(p)->refcnt);					\
178c1c61f44Ssb155480 	ASSERT((p)->refcnt != 0);					\
179c1c61f44Ssb155480 }
180c1c61f44Ssb155480 
181c1c61f44Ssb155480 #define	VNET_FDBE_REFRELE(p)						\
182c1c61f44Ssb155480 {									\
183c1c61f44Ssb155480 	ASSERT((p)->refcnt != 0);					\
184c1c61f44Ssb155480 	atomic_dec_32(&(p)->refcnt);					\
185c1c61f44Ssb155480 }
186c1c61f44Ssb155480 
1871107ea93SSriharsha Basavapatna #ifdef	VNET_IOC_DEBUG
188*63f531d1SSriharsha Basavapatna #define	VNET_M_CALLBACK_FLAGS	(MC_IOCTL | MC_GETCAPAB)
1891107ea93SSriharsha Basavapatna #else
190*63f531d1SSriharsha Basavapatna #define	VNET_M_CALLBACK_FLAGS	(MC_GETCAPAB)
1911107ea93SSriharsha Basavapatna #endif
1921107ea93SSriharsha Basavapatna 
193ba2e4443Sseb static mac_callbacks_t vnet_m_callbacks = {
1941107ea93SSriharsha Basavapatna 	VNET_M_CALLBACK_FLAGS,
195ba2e4443Sseb 	vnet_m_stat,
196ba2e4443Sseb 	vnet_m_start,
197ba2e4443Sseb 	vnet_m_stop,
198ba2e4443Sseb 	vnet_m_promisc,
199ba2e4443Sseb 	vnet_m_multicst,
200*63f531d1SSriharsha Basavapatna 	NULL,	/* m_unicst entry must be NULL while rx rings are exposed */
201*63f531d1SSriharsha Basavapatna 	NULL,	/* m_tx entry must be NULL while tx rings are exposed */
2021107ea93SSriharsha Basavapatna 	vnet_m_ioctl,
203*63f531d1SSriharsha Basavapatna 	vnet_m_capab,
204*63f531d1SSriharsha Basavapatna 	NULL
205*63f531d1SSriharsha Basavapatna };
206*63f531d1SSriharsha Basavapatna 
207*63f531d1SSriharsha Basavapatna static mac_callbacks_t vnet_hio_res_callbacks = {
208*63f531d1SSriharsha Basavapatna 	0,
209*63f531d1SSriharsha Basavapatna 	vnet_hio_stat,
210*63f531d1SSriharsha Basavapatna 	vnet_hio_start,
211*63f531d1SSriharsha Basavapatna 	vnet_hio_stop,
212*63f531d1SSriharsha Basavapatna 	NULL,
213*63f531d1SSriharsha Basavapatna 	NULL,
214*63f531d1SSriharsha Basavapatna 	NULL,
215*63f531d1SSriharsha Basavapatna 	vnet_hio_tx,
216*63f531d1SSriharsha Basavapatna 	NULL,
217ba2e4443Sseb 	NULL,
218ba2e4443Sseb 	NULL
219ba2e4443Sseb };
220ba2e4443Sseb 
2211ae08745Sheppo /*
2221ae08745Sheppo  * Linked list of "vnet_t" structures - one per instance.
2231ae08745Sheppo  */
2241ae08745Sheppo static vnet_t	*vnet_headp = NULL;
2251ae08745Sheppo static krwlock_t vnet_rw;
2261ae08745Sheppo 
2271ae08745Sheppo /* Tunables */
2281ae08745Sheppo uint32_t vnet_ntxds = VNET_NTXDS;	/* power of 2 transmit descriptors */
2291ae08745Sheppo uint32_t vnet_ldcwd_interval = VNET_LDCWD_INTERVAL; /* watchdog freq in msec */
2301ae08745Sheppo uint32_t vnet_ldcwd_txtimeout = VNET_LDCWD_TXTIMEOUT;  /* tx timeout in msec */
231e1ebb9ecSlm66018 uint32_t vnet_ldc_mtu = VNET_LDC_MTU;		/* ldc mtu */
232c1c61f44Ssb155480 
233*63f531d1SSriharsha Basavapatna /* Configure tx serialization in mac layer for the vnet device */
234*63f531d1SSriharsha Basavapatna boolean_t vnet_mac_tx_serialize = B_TRUE;
235*63f531d1SSriharsha Basavapatna 
2367b1f684aSSriharsha Basavapatna /*
2377b1f684aSSriharsha Basavapatna  * Set this to non-zero to enable additional internal receive buffer pools
2387b1f684aSSriharsha Basavapatna  * based on the MTU of the device for better performance at the cost of more
2397b1f684aSSriharsha Basavapatna  * memory consumption. This is turned off by default, to use allocb(9F) for
2407b1f684aSSriharsha Basavapatna  * receive buffer allocations of sizes > 2K.
2417b1f684aSSriharsha Basavapatna  */
2427b1f684aSSriharsha Basavapatna boolean_t vnet_jumbo_rxpools = B_FALSE;
2437b1f684aSSriharsha Basavapatna 
244c1c61f44Ssb155480 /* # of chains in fdb hash table */
245c1c61f44Ssb155480 uint32_t	vnet_fdb_nchains = VNET_NFDB_HASH;
246c1c61f44Ssb155480 
247c1c61f44Ssb155480 /* Internal tunables */
248c1c61f44Ssb155480 uint32_t	vnet_ethermtu = 1500;	/* mtu of the device */
249c1c61f44Ssb155480 
250c1c61f44Ssb155480 /*
251c1c61f44Ssb155480  * Default vlan id. This is only used internally when the "default-vlan-id"
252c1c61f44Ssb155480  * property is not present in the MD device node. Therefore, this should not be
253c1c61f44Ssb155480  * used as a tunable; if this value is changed, the corresponding variable
254c1c61f44Ssb155480  * should be updated to the same value in vsw and also other vnets connected to
255c1c61f44Ssb155480  * the same vsw.
256c1c61f44Ssb155480  */
257c1c61f44Ssb155480 uint16_t	vnet_default_vlan_id = 1;
258c1c61f44Ssb155480 
259c1c61f44Ssb155480 /* delay in usec to wait for all references on a fdb entry to be dropped */
260c1c61f44Ssb155480 uint32_t vnet_fdbe_refcnt_delay = 10;
2611ae08745Sheppo 
262678453a8Sspeer static struct ether_addr etherbroadcastaddr = {
263678453a8Sspeer 	0xff, 0xff, 0xff, 0xff, 0xff, 0xff
264678453a8Sspeer };
265678453a8Sspeer 
266*63f531d1SSriharsha Basavapatna /* mac_open() retry delay in usec */
267*63f531d1SSriharsha Basavapatna uint32_t vnet_mac_open_delay = 100;	/* 0.1 ms */
268*63f531d1SSriharsha Basavapatna 
269*63f531d1SSriharsha Basavapatna /* max # of mac_open() retries */
270*63f531d1SSriharsha Basavapatna uint32_t vnet_mac_open_retries = 100;
271678453a8Sspeer 
2721ae08745Sheppo /*
2731ae08745Sheppo  * Property names
2741ae08745Sheppo  */
2751ae08745Sheppo static char macaddr_propname[] = "local-mac-address";
2761ae08745Sheppo 
2771ae08745Sheppo /*
2781ae08745Sheppo  * This is the string displayed by modinfo(1m).
2791ae08745Sheppo  */
2807b1f684aSSriharsha Basavapatna static char vnet_ident[] = "vnet driver";
2811ae08745Sheppo extern struct mod_ops mod_driverops;
2821ae08745Sheppo static struct cb_ops cb_vnetops = {
2831ae08745Sheppo 	nulldev,		/* cb_open */
2841ae08745Sheppo 	nulldev,		/* cb_close */
2851ae08745Sheppo 	nodev,			/* cb_strategy */
2861ae08745Sheppo 	nodev,			/* cb_print */
2871ae08745Sheppo 	nodev,			/* cb_dump */
2881ae08745Sheppo 	nodev,			/* cb_read */
2891ae08745Sheppo 	nodev,			/* cb_write */
2901ae08745Sheppo 	nodev,			/* cb_ioctl */
2911ae08745Sheppo 	nodev,			/* cb_devmap */
2921ae08745Sheppo 	nodev,			/* cb_mmap */
2931ae08745Sheppo 	nodev,			/* cb_segmap */
2941ae08745Sheppo 	nochpoll,		/* cb_chpoll */
2951ae08745Sheppo 	ddi_prop_op,		/* cb_prop_op */
2961ae08745Sheppo 	NULL,			/* cb_stream */
2971ae08745Sheppo 	(int)(D_MP)		/* cb_flag */
2981ae08745Sheppo };
2991ae08745Sheppo 
3001ae08745Sheppo static struct dev_ops vnetops = {
3011ae08745Sheppo 	DEVO_REV,		/* devo_rev */
3021ae08745Sheppo 	0,			/* devo_refcnt */
3031ae08745Sheppo 	NULL,			/* devo_getinfo */
3041ae08745Sheppo 	nulldev,		/* devo_identify */
3051ae08745Sheppo 	nulldev,		/* devo_probe */
3061ae08745Sheppo 	vnetattach,		/* devo_attach */
3071ae08745Sheppo 	vnetdetach,		/* devo_detach */
3081ae08745Sheppo 	nodev,			/* devo_reset */
3091ae08745Sheppo 	&cb_vnetops,		/* devo_cb_ops */
31019397407SSherry Moore 	(struct bus_ops *)NULL,	/* devo_bus_ops */
31119397407SSherry Moore 	NULL,			/* devo_power */
31219397407SSherry Moore 	ddi_quiesce_not_supported,	/* devo_quiesce */
3131ae08745Sheppo };
3141ae08745Sheppo 
3151ae08745Sheppo static struct modldrv modldrv = {
3161ae08745Sheppo 	&mod_driverops,		/* Type of module.  This one is a driver */
3171ae08745Sheppo 	vnet_ident,		/* ID string */
3181ae08745Sheppo 	&vnetops		/* driver specific ops */
3191ae08745Sheppo };
3201ae08745Sheppo 
3211ae08745Sheppo static struct modlinkage modlinkage = {
3221ae08745Sheppo 	MODREV_1, (void *)&modldrv, NULL
3231ae08745Sheppo };
3241ae08745Sheppo 
325844e62a3Sraghuram #ifdef DEBUG
3261ae08745Sheppo 
3271ae08745Sheppo /*
3281ae08745Sheppo  * Print debug messages - set to 0xf to enable all msgs
3291ae08745Sheppo  */
330844e62a3Sraghuram int vnet_dbglevel = 0x8;
3311ae08745Sheppo 
332844e62a3Sraghuram static void
333844e62a3Sraghuram debug_printf(const char *fname, void *arg, const char *fmt, ...)
3341ae08745Sheppo {
3351ae08745Sheppo 	char    buf[512];
3361ae08745Sheppo 	va_list ap;
3371ae08745Sheppo 	vnet_t *vnetp = (vnet_t *)arg;
338844e62a3Sraghuram 	char    *bufp = buf;
3391ae08745Sheppo 
340844e62a3Sraghuram 	if (vnetp == NULL) {
341844e62a3Sraghuram 		(void) sprintf(bufp, "%s: ", fname);
342844e62a3Sraghuram 		bufp += strlen(bufp);
343844e62a3Sraghuram 	} else {
344844e62a3Sraghuram 		(void) sprintf(bufp, "vnet%d:%s: ", vnetp->instance, fname);
345844e62a3Sraghuram 		bufp += strlen(bufp);
3461ae08745Sheppo 	}
347844e62a3Sraghuram 	va_start(ap, fmt);
348844e62a3Sraghuram 	(void) vsprintf(bufp, fmt, ap);
349844e62a3Sraghuram 	va_end(ap);
350844e62a3Sraghuram 	cmn_err(CE_CONT, "%s\n", buf);
351844e62a3Sraghuram }
3521ae08745Sheppo 
3531ae08745Sheppo #endif
3541ae08745Sheppo 
3551ae08745Sheppo /* _init(9E): initialize the loadable module */
3561ae08745Sheppo int
3571ae08745Sheppo _init(void)
3581ae08745Sheppo {
3591ae08745Sheppo 	int status;
3601ae08745Sheppo 
361844e62a3Sraghuram 	DBG1(NULL, "enter\n");
3621ae08745Sheppo 
3631ae08745Sheppo 	mac_init_ops(&vnetops, "vnet");
3641ae08745Sheppo 	status = mod_install(&modlinkage);
3651ae08745Sheppo 	if (status != 0) {
3661ae08745Sheppo 		mac_fini_ops(&vnetops);
3671ae08745Sheppo 	}
368678453a8Sspeer 	vdds_mod_init();
3696f09f0feSWENTAO YANG 	vgen_mod_init();
370844e62a3Sraghuram 	DBG1(NULL, "exit(%d)\n", status);
3711ae08745Sheppo 	return (status);
3721ae08745Sheppo }
3731ae08745Sheppo 
3741ae08745Sheppo /* _fini(9E): prepare the module for unloading. */
3751ae08745Sheppo int
3761ae08745Sheppo _fini(void)
3771ae08745Sheppo {
3781ae08745Sheppo 	int		status;
3791ae08745Sheppo 
380844e62a3Sraghuram 	DBG1(NULL, "enter\n");
3811ae08745Sheppo 
3826f09f0feSWENTAO YANG 	status = vgen_mod_cleanup();
3836f09f0feSWENTAO YANG 	if (status != 0)
3846f09f0feSWENTAO YANG 		return (status);
3856f09f0feSWENTAO YANG 
3861ae08745Sheppo 	status = mod_remove(&modlinkage);
3871ae08745Sheppo 	if (status != 0)
3881ae08745Sheppo 		return (status);
3891ae08745Sheppo 	mac_fini_ops(&vnetops);
3906f09f0feSWENTAO YANG 	vgen_mod_fini();
391678453a8Sspeer 	vdds_mod_fini();
3921ae08745Sheppo 
393844e62a3Sraghuram 	DBG1(NULL, "exit(%d)\n", status);
3941ae08745Sheppo 	return (status);
3951ae08745Sheppo }
3961ae08745Sheppo 
3971ae08745Sheppo /* _info(9E): return information about the loadable module */
3981ae08745Sheppo int
3991ae08745Sheppo _info(struct modinfo *modinfop)
4001ae08745Sheppo {
4011ae08745Sheppo 	return (mod_info(&modlinkage, modinfop));
4021ae08745Sheppo }
4031ae08745Sheppo 
4041ae08745Sheppo /*
4051ae08745Sheppo  * attach(9E): attach a device to the system.
4061ae08745Sheppo  * called once for each instance of the device on the system.
4071ae08745Sheppo  */
4081ae08745Sheppo static int
4091ae08745Sheppo vnetattach(dev_info_t *dip, ddi_attach_cmd_t cmd)
4101ae08745Sheppo {
4111ae08745Sheppo 	vnet_t			*vnetp;
4121ae08745Sheppo 	int			status;
413678453a8Sspeer 	int			instance;
414678453a8Sspeer 	uint64_t		reg;
415678453a8Sspeer 	char			qname[TASKQ_NAMELEN];
4166f09f0feSWENTAO YANG 	vnet_attach_progress_t	attach_progress;
4171ae08745Sheppo 
4186f09f0feSWENTAO YANG 	attach_progress = AST_init;
4191ae08745Sheppo 
4201ae08745Sheppo 	switch (cmd) {
4211ae08745Sheppo 	case DDI_ATTACH:
4221ae08745Sheppo 		break;
4231ae08745Sheppo 	case DDI_RESUME:
4241ae08745Sheppo 	case DDI_PM_RESUME:
4251ae08745Sheppo 	default:
4261ae08745Sheppo 		goto vnet_attach_fail;
4271ae08745Sheppo 	}
4281ae08745Sheppo 
4291ae08745Sheppo 	instance = ddi_get_instance(dip);
430844e62a3Sraghuram 	DBG1(NULL, "instance(%d) enter\n", instance);
4311ae08745Sheppo 
4321ae08745Sheppo 	/* allocate vnet_t and mac_t structures */
4331ae08745Sheppo 	vnetp = kmem_zalloc(sizeof (vnet_t), KM_SLEEP);
434678453a8Sspeer 	vnetp->dip = dip;
435678453a8Sspeer 	vnetp->instance = instance;
436678453a8Sspeer 	rw_init(&vnetp->vrwlock, NULL, RW_DRIVER, NULL);
437678453a8Sspeer 	rw_init(&vnetp->vsw_fp_rw, NULL, RW_DRIVER, NULL);
4386f09f0feSWENTAO YANG 	attach_progress |= AST_vnet_alloc;
4391ae08745Sheppo 
440*63f531d1SSriharsha Basavapatna 	vnet_ring_grp_init(vnetp);
441*63f531d1SSriharsha Basavapatna 	attach_progress |= AST_ring_init;
442*63f531d1SSriharsha Basavapatna 
443678453a8Sspeer 	status = vdds_init(vnetp);
444678453a8Sspeer 	if (status != 0) {
445678453a8Sspeer 		goto vnet_attach_fail;
446678453a8Sspeer 	}
4476f09f0feSWENTAO YANG 	attach_progress |= AST_vdds_init;
448678453a8Sspeer 
4491ae08745Sheppo 	/* setup links to vnet_t from both devinfo and mac_t */
4501ae08745Sheppo 	ddi_set_driver_private(dip, (caddr_t)vnetp);
4511ae08745Sheppo 
4521ae08745Sheppo 	/* read the mac address */
4531ae08745Sheppo 	status = vnet_read_mac_address(vnetp);
4541ae08745Sheppo 	if (status != DDI_SUCCESS) {
4551ae08745Sheppo 		goto vnet_attach_fail;
4561ae08745Sheppo 	}
4576f09f0feSWENTAO YANG 	attach_progress |= AST_read_macaddr;
4581ae08745Sheppo 
459678453a8Sspeer 	reg = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
460678453a8Sspeer 	    DDI_PROP_DONTPASS, "reg", -1);
461678453a8Sspeer 	if (reg == -1) {
4621ae08745Sheppo 		goto vnet_attach_fail;
4631ae08745Sheppo 	}
464678453a8Sspeer 	vnetp->reg = reg;
4651ae08745Sheppo 
466c1c61f44Ssb155480 	vnet_fdb_create(vnetp);
4676f09f0feSWENTAO YANG 	attach_progress |= AST_fdbh_alloc;
4681ae08745Sheppo 
469678453a8Sspeer 	(void) snprintf(qname, TASKQ_NAMELEN, "vnet_taskq%d", instance);
470678453a8Sspeer 	if ((vnetp->taskqp = ddi_taskq_create(dip, qname, 1,
471678453a8Sspeer 	    TASKQ_DEFAULTPRI, 0)) == NULL) {
472678453a8Sspeer 		cmn_err(CE_WARN, "!vnet%d: Unable to create task queue",
473678453a8Sspeer 		    instance);
4741ae08745Sheppo 		goto vnet_attach_fail;
4751ae08745Sheppo 	}
4766f09f0feSWENTAO YANG 	attach_progress |= AST_taskq_create;
4771ae08745Sheppo 
4781ae08745Sheppo 	/* add to the list of vnet devices */
4791ae08745Sheppo 	WRITE_ENTER(&vnet_rw);
4801ae08745Sheppo 	vnetp->nextp = vnet_headp;
4811ae08745Sheppo 	vnet_headp = vnetp;
4821ae08745Sheppo 	RW_EXIT(&vnet_rw);
4831ae08745Sheppo 
4846f09f0feSWENTAO YANG 	attach_progress |= AST_vnet_list;
485678453a8Sspeer 
486678453a8Sspeer 	/*
487*63f531d1SSriharsha Basavapatna 	 * Initialize the generic vnet plugin which provides communication via
488*63f531d1SSriharsha Basavapatna 	 * sun4v LDC (logical domain channel) based resources. This involves 2
489*63f531d1SSriharsha Basavapatna 	 * steps; first, vgen_init() is invoked to read the various properties
490*63f531d1SSriharsha Basavapatna 	 * of the vnet device from its MD node (including its mtu which is
491*63f531d1SSriharsha Basavapatna 	 * needed to mac_register()) and obtain a handle to the vgen layer.
492*63f531d1SSriharsha Basavapatna 	 * After mac_register() is done and we have a mac handle, we then
493*63f531d1SSriharsha Basavapatna 	 * invoke vgen_init_mdeg() which registers with the the MD event
494*63f531d1SSriharsha Basavapatna 	 * generator (mdeg) framework to allow LDC resource notifications.
495*63f531d1SSriharsha Basavapatna 	 * Note: this sequence also allows us to report the correct default #
496*63f531d1SSriharsha Basavapatna 	 * of pseudo rings (2TX and 3RX) in vnet_m_capab() which gets invoked
497*63f531d1SSriharsha Basavapatna 	 * in the context of mac_register(); and avoids conflicting with
498*63f531d1SSriharsha Basavapatna 	 * dynamic pseudo rx rings which get added/removed as a result of mdeg
499*63f531d1SSriharsha Basavapatna 	 * events in vgen.
500678453a8Sspeer 	 */
501678453a8Sspeer 	status = vgen_init(vnetp, reg, vnetp->dip,
502678453a8Sspeer 	    (uint8_t *)vnetp->curr_macaddr, &vnetp->vgenhdl);
503678453a8Sspeer 	if (status != DDI_SUCCESS) {
504678453a8Sspeer 		DERR(vnetp, "vgen_init() failed\n");
505678453a8Sspeer 		goto vnet_attach_fail;
506678453a8Sspeer 	}
5076f09f0feSWENTAO YANG 	attach_progress |= AST_vgen_init;
508678453a8Sspeer 
509678453a8Sspeer 	status = vnet_mac_register(vnetp);
510678453a8Sspeer 	if (status != DDI_SUCCESS) {
511678453a8Sspeer 		goto vnet_attach_fail;
512678453a8Sspeer 	}
5131107ea93SSriharsha Basavapatna 	vnetp->link_state = LINK_STATE_UNKNOWN;
5146f09f0feSWENTAO YANG 	attach_progress |= AST_macreg;
5156f09f0feSWENTAO YANG 
516*63f531d1SSriharsha Basavapatna 	status = vgen_init_mdeg(vnetp->vgenhdl);
517*63f531d1SSriharsha Basavapatna 	if (status != DDI_SUCCESS) {
518*63f531d1SSriharsha Basavapatna 		goto vnet_attach_fail;
519*63f531d1SSriharsha Basavapatna 	}
520*63f531d1SSriharsha Basavapatna 	attach_progress |= AST_init_mdeg;
521*63f531d1SSriharsha Basavapatna 
5226f09f0feSWENTAO YANG 	vnetp->attach_progress = attach_progress;
5236f09f0feSWENTAO YANG 
524844e62a3Sraghuram 	DBG1(NULL, "instance(%d) exit\n", instance);
5251ae08745Sheppo 	return (DDI_SUCCESS);
5261ae08745Sheppo 
5271ae08745Sheppo vnet_attach_fail:
5286f09f0feSWENTAO YANG 	vnetp->attach_progress = attach_progress;
5293ab636deSWENTAO YANG 	status = vnet_unattach(vnetp);
5303ab636deSWENTAO YANG 	ASSERT(status == 0);
5311ae08745Sheppo 	return (DDI_FAILURE);
5321ae08745Sheppo }
5331ae08745Sheppo 
5341ae08745Sheppo /*
5351ae08745Sheppo  * detach(9E): detach a device from the system.
5361ae08745Sheppo  */
5371ae08745Sheppo static int
5381ae08745Sheppo vnetdetach(dev_info_t *dip, ddi_detach_cmd_t cmd)
5391ae08745Sheppo {
5401ae08745Sheppo 	vnet_t		*vnetp;
5411ae08745Sheppo 	int		instance;
5421ae08745Sheppo 
5431ae08745Sheppo 	instance = ddi_get_instance(dip);
544844e62a3Sraghuram 	DBG1(NULL, "instance(%d) enter\n", instance);
5451ae08745Sheppo 
5461ae08745Sheppo 	vnetp = ddi_get_driver_private(dip);
5471ae08745Sheppo 	if (vnetp == NULL) {
5481ae08745Sheppo 		goto vnet_detach_fail;
5491ae08745Sheppo 	}
5501ae08745Sheppo 
5511ae08745Sheppo 	switch (cmd) {
5521ae08745Sheppo 	case DDI_DETACH:
5531ae08745Sheppo 		break;
5541ae08745Sheppo 	case DDI_SUSPEND:
5551ae08745Sheppo 	case DDI_PM_SUSPEND:
5561ae08745Sheppo 	default:
5571ae08745Sheppo 		goto vnet_detach_fail;
5581ae08745Sheppo 	}
5591ae08745Sheppo 
5606f09f0feSWENTAO YANG 	if (vnet_unattach(vnetp) != 0) {
561d10e4ef2Snarayan 		goto vnet_detach_fail;
562d10e4ef2Snarayan 	}
563d10e4ef2Snarayan 
5646f09f0feSWENTAO YANG 	return (DDI_SUCCESS);
5651ae08745Sheppo 
5666f09f0feSWENTAO YANG vnet_detach_fail:
5676f09f0feSWENTAO YANG 	return (DDI_FAILURE);
5686f09f0feSWENTAO YANG }
5696f09f0feSWENTAO YANG 
5706f09f0feSWENTAO YANG /*
5716f09f0feSWENTAO YANG  * Common routine to handle vnetattach() failure and vnetdetach(). Note that
5726f09f0feSWENTAO YANG  * the only reason this function could fail is if mac_unregister() fails.
5736f09f0feSWENTAO YANG  * Otherwise, this function must ensure that all resources are freed and return
5746f09f0feSWENTAO YANG  * success.
5756f09f0feSWENTAO YANG  */
5766f09f0feSWENTAO YANG static int
5776f09f0feSWENTAO YANG vnet_unattach(vnet_t *vnetp)
5786f09f0feSWENTAO YANG {
5796f09f0feSWENTAO YANG 	vnet_attach_progress_t	attach_progress;
5806f09f0feSWENTAO YANG 
5816f09f0feSWENTAO YANG 	attach_progress = vnetp->attach_progress;
5826f09f0feSWENTAO YANG 
5836f09f0feSWENTAO YANG 	/*
584*63f531d1SSriharsha Basavapatna 	 * Disable the mac device in the gldv3 subsystem. This can fail, in
585*63f531d1SSriharsha Basavapatna 	 * particular if there are still any open references to this mac
586*63f531d1SSriharsha Basavapatna 	 * device; in which case we just return failure without continuing to
587*63f531d1SSriharsha Basavapatna 	 * detach further.
588*63f531d1SSriharsha Basavapatna 	 * If it succeeds, we then invoke vgen_uninit() which should unregister
589*63f531d1SSriharsha Basavapatna 	 * any pseudo rings registered with the mac layer. Note we keep the
590*63f531d1SSriharsha Basavapatna 	 * AST_macreg flag on, so we can unregister with the mac layer at
591*63f531d1SSriharsha Basavapatna 	 * the end of this routine.
5926f09f0feSWENTAO YANG 	 */
5936f09f0feSWENTAO YANG 	if (attach_progress & AST_macreg) {
594*63f531d1SSriharsha Basavapatna 		if (mac_disable(vnetp->mh) != 0) {
5956f09f0feSWENTAO YANG 			return (1);
5966f09f0feSWENTAO YANG 		}
5976f09f0feSWENTAO YANG 	}
5986f09f0feSWENTAO YANG 
5996f09f0feSWENTAO YANG 	/*
600*63f531d1SSriharsha Basavapatna 	 * Now that we have disabled the device, we must finish all other steps
601*63f531d1SSriharsha Basavapatna 	 * and successfully return from this function; otherwise we will end up
602*63f531d1SSriharsha Basavapatna 	 * leaving the device in a broken/unusable state.
6036f09f0feSWENTAO YANG 	 *
6046f09f0feSWENTAO YANG 	 * First, release any hybrid resources assigned to this vnet device.
6056f09f0feSWENTAO YANG 	 */
6066f09f0feSWENTAO YANG 	if (attach_progress & AST_vdds_init) {
6076f09f0feSWENTAO YANG 		vdds_cleanup(vnetp);
6086f09f0feSWENTAO YANG 		attach_progress &= ~AST_vdds_init;
6096f09f0feSWENTAO YANG 	}
6106f09f0feSWENTAO YANG 
6116f09f0feSWENTAO YANG 	/*
6126f09f0feSWENTAO YANG 	 * Uninit vgen. This stops further mdeg callbacks to this vnet
6136f09f0feSWENTAO YANG 	 * device and/or its ports; and detaches any existing ports.
6146f09f0feSWENTAO YANG 	 */
615*63f531d1SSriharsha Basavapatna 	if (attach_progress & (AST_vgen_init|AST_init_mdeg)) {
6166f09f0feSWENTAO YANG 		vgen_uninit(vnetp->vgenhdl);
6176f09f0feSWENTAO YANG 		attach_progress &= ~AST_vgen_init;
618*63f531d1SSriharsha Basavapatna 		attach_progress &= ~AST_init_mdeg;
6196f09f0feSWENTAO YANG 	}
6206f09f0feSWENTAO YANG 
6216f09f0feSWENTAO YANG 	/* Destroy the taskq. */
6226f09f0feSWENTAO YANG 	if (attach_progress & AST_taskq_create) {
6236f09f0feSWENTAO YANG 		ddi_taskq_destroy(vnetp->taskqp);
6246f09f0feSWENTAO YANG 		attach_progress &= ~AST_taskq_create;
6256f09f0feSWENTAO YANG 	}
6266f09f0feSWENTAO YANG 
6276f09f0feSWENTAO YANG 	/* Destroy fdb. */
6286f09f0feSWENTAO YANG 	if (attach_progress & AST_fdbh_alloc) {
6296f09f0feSWENTAO YANG 		vnet_fdb_destroy(vnetp);
6306f09f0feSWENTAO YANG 		attach_progress &= ~AST_fdbh_alloc;
6316f09f0feSWENTAO YANG 	}
6326f09f0feSWENTAO YANG 
6336f09f0feSWENTAO YANG 	/* Remove from the device list */
6346f09f0feSWENTAO YANG 	if (attach_progress & AST_vnet_list) {
6356f09f0feSWENTAO YANG 		vnet_t		**vnetpp;
6361ae08745Sheppo 		/* unlink from instance(vnet_t) list */
6371ae08745Sheppo 		WRITE_ENTER(&vnet_rw);
6386f09f0feSWENTAO YANG 		for (vnetpp = &vnet_headp; *vnetpp;
6396f09f0feSWENTAO YANG 		    vnetpp = &(*vnetpp)->nextp) {
6401ae08745Sheppo 			if (*vnetpp == vnetp) {
6411ae08745Sheppo 				*vnetpp = vnetp->nextp;
6421ae08745Sheppo 				break;
6431ae08745Sheppo 			}
6441ae08745Sheppo 		}
6451ae08745Sheppo 		RW_EXIT(&vnet_rw);
6466f09f0feSWENTAO YANG 		attach_progress &= ~AST_vnet_list;
6476f09f0feSWENTAO YANG 	}
6481ae08745Sheppo 
649*63f531d1SSriharsha Basavapatna 	if (attach_progress & AST_ring_init) {
650*63f531d1SSriharsha Basavapatna 		vnet_ring_grp_uninit(vnetp);
651*63f531d1SSriharsha Basavapatna 		attach_progress &= ~AST_ring_init;
652*63f531d1SSriharsha Basavapatna 	}
653*63f531d1SSriharsha Basavapatna 
654*63f531d1SSriharsha Basavapatna 	if (attach_progress & AST_macreg) {
655*63f531d1SSriharsha Basavapatna 		VERIFY(mac_unregister(vnetp->mh) == 0);
656*63f531d1SSriharsha Basavapatna 		vnetp->mh = NULL;
657*63f531d1SSriharsha Basavapatna 		attach_progress &= ~AST_macreg;
658*63f531d1SSriharsha Basavapatna 	}
659*63f531d1SSriharsha Basavapatna 
6606f09f0feSWENTAO YANG 	if (attach_progress & AST_vnet_alloc) {
661678453a8Sspeer 		rw_destroy(&vnetp->vrwlock);
662678453a8Sspeer 		rw_destroy(&vnetp->vsw_fp_rw);
6636f09f0feSWENTAO YANG 		attach_progress &= ~AST_vnet_list;
6641ae08745Sheppo 		KMEM_FREE(vnetp);
6656f09f0feSWENTAO YANG 	}
6661ae08745Sheppo 
6676f09f0feSWENTAO YANG 	return (0);
6681ae08745Sheppo }
6691ae08745Sheppo 
6701ae08745Sheppo /* enable the device for transmit/receive */
6711ae08745Sheppo static int
6721ae08745Sheppo vnet_m_start(void *arg)
6731ae08745Sheppo {
6741ae08745Sheppo 	vnet_t		*vnetp = arg;
6751ae08745Sheppo 
676844e62a3Sraghuram 	DBG1(vnetp, "enter\n");
6771ae08745Sheppo 
678678453a8Sspeer 	WRITE_ENTER(&vnetp->vrwlock);
679678453a8Sspeer 	vnetp->flags |= VNET_STARTED;
680678453a8Sspeer 	vnet_start_resources(vnetp);
681678453a8Sspeer 	RW_EXIT(&vnetp->vrwlock);
6821ae08745Sheppo 
683844e62a3Sraghuram 	DBG1(vnetp, "exit\n");
6841ae08745Sheppo 	return (VNET_SUCCESS);
6851ae08745Sheppo 
6861ae08745Sheppo }
6871ae08745Sheppo 
6881ae08745Sheppo /* stop transmit/receive for the device */
6891ae08745Sheppo static void
6901ae08745Sheppo vnet_m_stop(void *arg)
6911ae08745Sheppo {
6921ae08745Sheppo 	vnet_t		*vnetp = arg;
6931ae08745Sheppo 
694844e62a3Sraghuram 	DBG1(vnetp, "enter\n");
6951ae08745Sheppo 
696678453a8Sspeer 	WRITE_ENTER(&vnetp->vrwlock);
697678453a8Sspeer 	if (vnetp->flags & VNET_STARTED) {
6985460ddbdSSriharsha Basavapatna 		/*
6995460ddbdSSriharsha Basavapatna 		 * Set the flags appropriately; this should prevent starting of
7005460ddbdSSriharsha Basavapatna 		 * any new resources that are added(see vnet_res_start_task()),
7015460ddbdSSriharsha Basavapatna 		 * while we release the vrwlock in vnet_stop_resources() before
7025460ddbdSSriharsha Basavapatna 		 * stopping each resource.
7035460ddbdSSriharsha Basavapatna 		 */
704678453a8Sspeer 		vnetp->flags &= ~VNET_STARTED;
7055460ddbdSSriharsha Basavapatna 		vnetp->flags |= VNET_STOPPING;
7065460ddbdSSriharsha Basavapatna 		vnet_stop_resources(vnetp);
7075460ddbdSSriharsha Basavapatna 		vnetp->flags &= ~VNET_STOPPING;
7081ae08745Sheppo 	}
709678453a8Sspeer 	RW_EXIT(&vnetp->vrwlock);
7101ae08745Sheppo 
711844e62a3Sraghuram 	DBG1(vnetp, "exit\n");
7121ae08745Sheppo }
7131ae08745Sheppo 
7141ae08745Sheppo /* set the unicast mac address of the device */
7151ae08745Sheppo static int
7161ae08745Sheppo vnet_m_unicst(void *arg, const uint8_t *macaddr)
7171ae08745Sheppo {
7181ae08745Sheppo 	_NOTE(ARGUNUSED(macaddr))
7191ae08745Sheppo 
7201ae08745Sheppo 	vnet_t *vnetp = arg;
7211ae08745Sheppo 
722844e62a3Sraghuram 	DBG1(vnetp, "enter\n");
7231ae08745Sheppo 	/*
7243af08d82Slm66018 	 * NOTE: setting mac address dynamically is not supported.
7251ae08745Sheppo 	 */
726844e62a3Sraghuram 	DBG1(vnetp, "exit\n");
7271ae08745Sheppo 
7288e6a2a04Slm66018 	return (VNET_FAILURE);
7291ae08745Sheppo }
7301ae08745Sheppo 
7311ae08745Sheppo /* enable/disable a multicast address */
7321ae08745Sheppo static int
7331ae08745Sheppo vnet_m_multicst(void *arg, boolean_t add, const uint8_t *mca)
7341ae08745Sheppo {
7351ae08745Sheppo 	_NOTE(ARGUNUSED(add, mca))
7361ae08745Sheppo 
7371ae08745Sheppo 	vnet_t *vnetp = arg;
738678453a8Sspeer 	vnet_res_t	*vresp;
739678453a8Sspeer 	mac_register_t	*macp;
740ba2e4443Sseb 	mac_callbacks_t	*cbp;
7411ae08745Sheppo 	int rv = VNET_SUCCESS;
7421ae08745Sheppo 
743844e62a3Sraghuram 	DBG1(vnetp, "enter\n");
744678453a8Sspeer 
745678453a8Sspeer 	READ_ENTER(&vnetp->vrwlock);
746678453a8Sspeer 	for (vresp = vnetp->vres_list; vresp != NULL; vresp = vresp->nextp) {
747678453a8Sspeer 		if (vresp->type == VIO_NET_RES_LDC_SERVICE) {
748678453a8Sspeer 			macp = &vresp->macreg;
749678453a8Sspeer 			cbp = macp->m_callbacks;
750678453a8Sspeer 			rv = cbp->mc_multicst(macp->m_driver, add, mca);
7511ae08745Sheppo 		}
7521ae08745Sheppo 	}
753678453a8Sspeer 	RW_EXIT(&vnetp->vrwlock);
754678453a8Sspeer 
755844e62a3Sraghuram 	DBG1(vnetp, "exit(%d)\n", rv);
7561ae08745Sheppo 	return (rv);
7571ae08745Sheppo }
7581ae08745Sheppo 
7591ae08745Sheppo /* set or clear promiscuous mode on the device */
7601ae08745Sheppo static int
7611ae08745Sheppo vnet_m_promisc(void *arg, boolean_t on)
7621ae08745Sheppo {
7631ae08745Sheppo 	_NOTE(ARGUNUSED(on))
7641ae08745Sheppo 
7651ae08745Sheppo 	vnet_t *vnetp = arg;
766844e62a3Sraghuram 	DBG1(vnetp, "enter\n");
7671ae08745Sheppo 	/*
7683af08d82Slm66018 	 * NOTE: setting promiscuous mode is not supported, just return success.
7691ae08745Sheppo 	 */
770844e62a3Sraghuram 	DBG1(vnetp, "exit\n");
7711ae08745Sheppo 	return (VNET_SUCCESS);
7721ae08745Sheppo }
7731ae08745Sheppo 
7741ae08745Sheppo /*
7751ae08745Sheppo  * Transmit a chain of packets. This function provides switching functionality
7761ae08745Sheppo  * based on the destination mac address to reach other guests (within ldoms) or
7771ae08745Sheppo  * external hosts.
7781ae08745Sheppo  */
7791ae08745Sheppo mblk_t *
780*63f531d1SSriharsha Basavapatna vnet_tx_ring_send(void *arg, mblk_t *mp)
7811ae08745Sheppo {
782*63f531d1SSriharsha Basavapatna 	vnet_pseudo_tx_ring_t	*tx_ringp;
7831ae08745Sheppo 	vnet_t			*vnetp;
784678453a8Sspeer 	vnet_res_t		*vresp;
7851ae08745Sheppo 	mblk_t			*next;
7861ae08745Sheppo 	mblk_t			*resid_mp;
787678453a8Sspeer 	mac_register_t		*macp;
788c1c61f44Ssb155480 	struct ether_header	*ehp;
789678453a8Sspeer 	boolean_t		is_unicast;
7908c242ab0SSriharsha Basavapatna 	boolean_t		is_pvid;	/* non-default pvid ? */
7918c242ab0SSriharsha Basavapatna 	boolean_t		hres;		/* Hybrid resource ? */
792*63f531d1SSriharsha Basavapatna 	void			*tx_arg;
7931ae08745Sheppo 
794*63f531d1SSriharsha Basavapatna 	tx_ringp = (vnet_pseudo_tx_ring_t *)arg;
795*63f531d1SSriharsha Basavapatna 	vnetp = (vnet_t *)tx_ringp->vnetp;
796844e62a3Sraghuram 	DBG1(vnetp, "enter\n");
7971ae08745Sheppo 	ASSERT(mp != NULL);
7981ae08745Sheppo 
7998c242ab0SSriharsha Basavapatna 	is_pvid = (vnetp->pvid != vnetp->default_vlan_id) ? B_TRUE : B_FALSE;
8008c242ab0SSriharsha Basavapatna 
8011ae08745Sheppo 	while (mp != NULL) {
802c1c61f44Ssb155480 
8031ae08745Sheppo 		next = mp->b_next;
8041ae08745Sheppo 		mp->b_next = NULL;
8051ae08745Sheppo 
8061ae08745Sheppo 		/*
807c1c61f44Ssb155480 		 * Find fdb entry for the destination
808c1c61f44Ssb155480 		 * and hold a reference to it.
8091ae08745Sheppo 		 */
810c1c61f44Ssb155480 		ehp = (struct ether_header *)mp->b_rptr;
811678453a8Sspeer 		vresp = vnet_fdbe_find(vnetp, &ehp->ether_dhost);
812678453a8Sspeer 		if (vresp != NULL) {
813c1c61f44Ssb155480 
814c1c61f44Ssb155480 			/*
815c1c61f44Ssb155480 			 * Destination found in FDB.
816c1c61f44Ssb155480 			 * The destination is a vnet device within ldoms
817c1c61f44Ssb155480 			 * and directly reachable, invoke the tx function
818c1c61f44Ssb155480 			 * in the fdb entry.
819c1c61f44Ssb155480 			 */
820678453a8Sspeer 			macp = &vresp->macreg;
821678453a8Sspeer 			resid_mp = macp->m_callbacks->mc_tx(macp->m_driver, mp);
822c1c61f44Ssb155480 
823c1c61f44Ssb155480 			/* tx done; now release ref on fdb entry */
824678453a8Sspeer 			VNET_FDBE_REFRELE(vresp);
825c1c61f44Ssb155480 
8261ae08745Sheppo 			if (resid_mp != NULL) {
8271ae08745Sheppo 				/* m_tx failed */
8281ae08745Sheppo 				mp->b_next = next;
8291ae08745Sheppo 				break;
8301ae08745Sheppo 			}
8311ae08745Sheppo 		} else {
832678453a8Sspeer 			is_unicast = !(IS_BROADCAST(ehp) ||
833678453a8Sspeer 			    (IS_MULTICAST(ehp)));
8341ae08745Sheppo 			/*
835c1c61f44Ssb155480 			 * Destination is not in FDB.
836678453a8Sspeer 			 * If the destination is broadcast or multicast,
837678453a8Sspeer 			 * then forward the packet to vswitch.
838678453a8Sspeer 			 * If a Hybrid resource avilable, then send the
839678453a8Sspeer 			 * unicast packet via hybrid resource, otherwise
840678453a8Sspeer 			 * forward it to vswitch.
8411ae08745Sheppo 			 */
842c1c61f44Ssb155480 			READ_ENTER(&vnetp->vsw_fp_rw);
843c1c61f44Ssb155480 
844678453a8Sspeer 			if ((is_unicast) && (vnetp->hio_fp != NULL)) {
845678453a8Sspeer 				vresp = vnetp->hio_fp;
8468c242ab0SSriharsha Basavapatna 				hres = B_TRUE;
847678453a8Sspeer 			} else {
848678453a8Sspeer 				vresp = vnetp->vsw_fp;
8498c242ab0SSriharsha Basavapatna 				hres = B_FALSE;
850678453a8Sspeer 			}
851678453a8Sspeer 			if (vresp == NULL) {
852c1c61f44Ssb155480 				/*
853c1c61f44Ssb155480 				 * no fdb entry to vsw? drop the packet.
854c1c61f44Ssb155480 				 */
855c1c61f44Ssb155480 				RW_EXIT(&vnetp->vsw_fp_rw);
856c1c61f44Ssb155480 				freemsg(mp);
857c1c61f44Ssb155480 				mp = next;
858c1c61f44Ssb155480 				continue;
859c1c61f44Ssb155480 			}
860c1c61f44Ssb155480 
861c1c61f44Ssb155480 			/* ref hold the fdb entry to vsw */
862678453a8Sspeer 			VNET_FDBE_REFHOLD(vresp);
863c1c61f44Ssb155480 
864c1c61f44Ssb155480 			RW_EXIT(&vnetp->vsw_fp_rw);
865c1c61f44Ssb155480 
8668c242ab0SSriharsha Basavapatna 			/*
8678c242ab0SSriharsha Basavapatna 			 * In the case of a hybrid resource we need to insert
8688c242ab0SSriharsha Basavapatna 			 * the tag for the pvid case here; unlike packets that
8698c242ab0SSriharsha Basavapatna 			 * are destined to a vnet/vsw in which case the vgen
8708c242ab0SSriharsha Basavapatna 			 * layer does the tagging before sending it over ldc.
8718c242ab0SSriharsha Basavapatna 			 */
8728c242ab0SSriharsha Basavapatna 			if (hres == B_TRUE) {
8738c242ab0SSriharsha Basavapatna 				/*
8748c242ab0SSriharsha Basavapatna 				 * Determine if the frame being transmitted
8758c242ab0SSriharsha Basavapatna 				 * over the hybrid resource is untagged. If so,
8768c242ab0SSriharsha Basavapatna 				 * insert the tag before transmitting.
8778c242ab0SSriharsha Basavapatna 				 */
8788c242ab0SSriharsha Basavapatna 				if (is_pvid == B_TRUE &&
8798c242ab0SSriharsha Basavapatna 				    ehp->ether_type != htons(ETHERTYPE_VLAN)) {
8808c242ab0SSriharsha Basavapatna 
8818c242ab0SSriharsha Basavapatna 					mp = vnet_vlan_insert_tag(mp,
8828c242ab0SSriharsha Basavapatna 					    vnetp->pvid);
8838c242ab0SSriharsha Basavapatna 					if (mp == NULL) {
8848c242ab0SSriharsha Basavapatna 						VNET_FDBE_REFRELE(vresp);
8858c242ab0SSriharsha Basavapatna 						mp = next;
8868c242ab0SSriharsha Basavapatna 						continue;
8878c242ab0SSriharsha Basavapatna 					}
8888c242ab0SSriharsha Basavapatna 
8898c242ab0SSriharsha Basavapatna 				}
8908c242ab0SSriharsha Basavapatna 
891678453a8Sspeer 				macp = &vresp->macreg;
892*63f531d1SSriharsha Basavapatna 				tx_arg = tx_ringp;
893*63f531d1SSriharsha Basavapatna 			} else {
894*63f531d1SSriharsha Basavapatna 				macp = &vresp->macreg;
895*63f531d1SSriharsha Basavapatna 				tx_arg = macp->m_driver;
896*63f531d1SSriharsha Basavapatna 			}
897*63f531d1SSriharsha Basavapatna 			resid_mp = macp->m_callbacks->mc_tx(tx_arg, mp);
898c1c61f44Ssb155480 
899c1c61f44Ssb155480 			/* tx done; now release ref on fdb entry */
900678453a8Sspeer 			VNET_FDBE_REFRELE(vresp);
901c1c61f44Ssb155480 
9021ae08745Sheppo 			if (resid_mp != NULL) {
9031ae08745Sheppo 				/* m_tx failed */
9041ae08745Sheppo 				mp->b_next = next;
9051ae08745Sheppo 				break;
9061ae08745Sheppo 			}
9071ae08745Sheppo 		}
9081ae08745Sheppo 
9091ae08745Sheppo 		mp = next;
9101ae08745Sheppo 	}
9111ae08745Sheppo 
912844e62a3Sraghuram 	DBG1(vnetp, "exit\n");
9131ae08745Sheppo 	return (mp);
9141ae08745Sheppo }
9151ae08745Sheppo 
9161ae08745Sheppo /* get statistics from the device */
917ba2e4443Sseb int
918ba2e4443Sseb vnet_m_stat(void *arg, uint_t stat, uint64_t *val)
9191ae08745Sheppo {
9201ae08745Sheppo 	vnet_t *vnetp = arg;
921678453a8Sspeer 	vnet_res_t	*vresp;
922678453a8Sspeer 	mac_register_t	*macp;
923ba2e4443Sseb 	mac_callbacks_t	*cbp;
924ba2e4443Sseb 	uint64_t val_total = 0;
9251ae08745Sheppo 
926844e62a3Sraghuram 	DBG1(vnetp, "enter\n");
9271ae08745Sheppo 
9281ae08745Sheppo 	/*
929ba2e4443Sseb 	 * get the specified statistic from each transport and return the
930ba2e4443Sseb 	 * aggregate val.  This obviously only works for counters.
9311ae08745Sheppo 	 */
932ba2e4443Sseb 	if ((IS_MAC_STAT(stat) && !MAC_STAT_ISACOUNTER(stat)) ||
933ba2e4443Sseb 	    (IS_MACTYPE_STAT(stat) && !ETHER_STAT_ISACOUNTER(stat))) {
934ba2e4443Sseb 		return (ENOTSUP);
935ba2e4443Sseb 	}
936678453a8Sspeer 
937678453a8Sspeer 	READ_ENTER(&vnetp->vrwlock);
938678453a8Sspeer 	for (vresp = vnetp->vres_list; vresp != NULL; vresp = vresp->nextp) {
939678453a8Sspeer 		macp = &vresp->macreg;
940678453a8Sspeer 		cbp = macp->m_callbacks;
941678453a8Sspeer 		if (cbp->mc_getstat(macp->m_driver, stat, val) == 0)
942ba2e4443Sseb 			val_total += *val;
9431ae08745Sheppo 	}
944678453a8Sspeer 	RW_EXIT(&vnetp->vrwlock);
9451ae08745Sheppo 
946ba2e4443Sseb 	*val = val_total;
947ba2e4443Sseb 
948844e62a3Sraghuram 	DBG1(vnetp, "exit\n");
949ba2e4443Sseb 	return (0);
9501ae08745Sheppo }
9511ae08745Sheppo 
952*63f531d1SSriharsha Basavapatna static void
953*63f531d1SSriharsha Basavapatna vnet_ring_grp_init(vnet_t *vnetp)
954*63f531d1SSriharsha Basavapatna {
955*63f531d1SSriharsha Basavapatna 	vnet_pseudo_rx_group_t	*rx_grp;
956*63f531d1SSriharsha Basavapatna 	vnet_pseudo_rx_ring_t	*rx_ringp;
957*63f531d1SSriharsha Basavapatna 	vnet_pseudo_tx_group_t	*tx_grp;
958*63f531d1SSriharsha Basavapatna 	vnet_pseudo_tx_ring_t	*tx_ringp;
959*63f531d1SSriharsha Basavapatna 	int			i;
960*63f531d1SSriharsha Basavapatna 
961*63f531d1SSriharsha Basavapatna 	tx_grp = &vnetp->tx_grp[0];
962*63f531d1SSriharsha Basavapatna 	tx_ringp = kmem_zalloc(sizeof (vnet_pseudo_tx_ring_t) *
963*63f531d1SSriharsha Basavapatna 	    VNET_NUM_PSEUDO_TXRINGS, KM_SLEEP);
964*63f531d1SSriharsha Basavapatna 	for (i = 0; i < VNET_NUM_PSEUDO_TXRINGS; i++) {
965*63f531d1SSriharsha Basavapatna 		tx_ringp[i].state |= VNET_TXRING_SHARED;
966*63f531d1SSriharsha Basavapatna 	}
967*63f531d1SSriharsha Basavapatna 	tx_grp->rings = tx_ringp;
968*63f531d1SSriharsha Basavapatna 	tx_grp->ring_cnt = VNET_NUM_PSEUDO_TXRINGS;
969*63f531d1SSriharsha Basavapatna 
970*63f531d1SSriharsha Basavapatna 	rx_grp = &vnetp->rx_grp[0];
971*63f531d1SSriharsha Basavapatna 	rx_grp->max_ring_cnt = MAX_RINGS_PER_GROUP;
972*63f531d1SSriharsha Basavapatna 	rw_init(&rx_grp->lock, NULL, RW_DRIVER, NULL);
973*63f531d1SSriharsha Basavapatna 	rx_ringp = kmem_zalloc(sizeof (vnet_pseudo_rx_ring_t) *
974*63f531d1SSriharsha Basavapatna 	    rx_grp->max_ring_cnt, KM_SLEEP);
975*63f531d1SSriharsha Basavapatna 
976*63f531d1SSriharsha Basavapatna 	/*
977*63f531d1SSriharsha Basavapatna 	 * Setup the first 3 Pseudo RX Rings that are reserved;
978*63f531d1SSriharsha Basavapatna 	 * 1 for LDC resource to vswitch + 2 for RX rings of Hybrid resource.
979*63f531d1SSriharsha Basavapatna 	 */
980*63f531d1SSriharsha Basavapatna 	rx_ringp[0].state |= VNET_RXRING_INUSE|VNET_RXRING_LDC_SERVICE;
981*63f531d1SSriharsha Basavapatna 	rx_ringp[0].index = 0;
982*63f531d1SSriharsha Basavapatna 	rx_ringp[1].state |= VNET_RXRING_INUSE|VNET_RXRING_HYBRID;
983*63f531d1SSriharsha Basavapatna 	rx_ringp[1].index = 1;
984*63f531d1SSriharsha Basavapatna 	rx_ringp[2].state |= VNET_RXRING_INUSE|VNET_RXRING_HYBRID;
985*63f531d1SSriharsha Basavapatna 	rx_ringp[2].index = 2;
986*63f531d1SSriharsha Basavapatna 
987*63f531d1SSriharsha Basavapatna 	rx_grp->ring_cnt = VNET_NUM_PSEUDO_RXRINGS_DEFAULT;
988*63f531d1SSriharsha Basavapatna 	rx_grp->rings = rx_ringp;
989*63f531d1SSriharsha Basavapatna 
990*63f531d1SSriharsha Basavapatna 	for (i = VNET_NUM_PSEUDO_RXRINGS_DEFAULT;
991*63f531d1SSriharsha Basavapatna 	    i < rx_grp->max_ring_cnt; i++) {
992*63f531d1SSriharsha Basavapatna 		rx_ringp = &rx_grp->rings[i];
993*63f531d1SSriharsha Basavapatna 		rx_ringp->state = VNET_RXRING_FREE;
994*63f531d1SSriharsha Basavapatna 		rx_ringp->index = i;
995*63f531d1SSriharsha Basavapatna 	}
996*63f531d1SSriharsha Basavapatna }
997*63f531d1SSriharsha Basavapatna 
998*63f531d1SSriharsha Basavapatna static void
999*63f531d1SSriharsha Basavapatna vnet_ring_grp_uninit(vnet_t *vnetp)
1000*63f531d1SSriharsha Basavapatna {
1001*63f531d1SSriharsha Basavapatna 	vnet_pseudo_rx_group_t	*rx_grp;
1002*63f531d1SSriharsha Basavapatna 	vnet_pseudo_tx_group_t	*tx_grp;
1003*63f531d1SSriharsha Basavapatna 
1004*63f531d1SSriharsha Basavapatna 	tx_grp = &vnetp->tx_grp[0];
1005*63f531d1SSriharsha Basavapatna 	if (tx_grp->rings != NULL) {
1006*63f531d1SSriharsha Basavapatna 		ASSERT(tx_grp->ring_cnt == VNET_NUM_PSEUDO_TXRINGS);
1007*63f531d1SSriharsha Basavapatna 		kmem_free(tx_grp->rings, sizeof (vnet_pseudo_tx_ring_t) *
1008*63f531d1SSriharsha Basavapatna 		    tx_grp->ring_cnt);
1009*63f531d1SSriharsha Basavapatna 		tx_grp->rings = NULL;
1010*63f531d1SSriharsha Basavapatna 	}
1011*63f531d1SSriharsha Basavapatna 
1012*63f531d1SSriharsha Basavapatna 	rx_grp = &vnetp->rx_grp[0];
1013*63f531d1SSriharsha Basavapatna 	if (rx_grp->rings != NULL) {
1014*63f531d1SSriharsha Basavapatna 		ASSERT(rx_grp->max_ring_cnt == MAX_RINGS_PER_GROUP);
1015*63f531d1SSriharsha Basavapatna 		ASSERT(rx_grp->ring_cnt == VNET_NUM_PSEUDO_RXRINGS_DEFAULT);
1016*63f531d1SSriharsha Basavapatna 		kmem_free(rx_grp->rings, sizeof (vnet_pseudo_rx_ring_t) *
1017*63f531d1SSriharsha Basavapatna 		    rx_grp->max_ring_cnt);
1018*63f531d1SSriharsha Basavapatna 		rx_grp->rings = NULL;
1019*63f531d1SSriharsha Basavapatna 	}
1020*63f531d1SSriharsha Basavapatna }
1021*63f531d1SSriharsha Basavapatna 
1022*63f531d1SSriharsha Basavapatna static vnet_pseudo_rx_ring_t *
1023*63f531d1SSriharsha Basavapatna vnet_alloc_pseudo_rx_ring(vnet_t *vnetp)
1024*63f531d1SSriharsha Basavapatna {
1025*63f531d1SSriharsha Basavapatna 	vnet_pseudo_rx_group_t  *rx_grp;
1026*63f531d1SSriharsha Basavapatna 	vnet_pseudo_rx_ring_t	*rx_ringp;
1027*63f531d1SSriharsha Basavapatna 	int			index;
1028*63f531d1SSriharsha Basavapatna 
1029*63f531d1SSriharsha Basavapatna 	rx_grp = &vnetp->rx_grp[0];
1030*63f531d1SSriharsha Basavapatna 	WRITE_ENTER(&rx_grp->lock);
1031*63f531d1SSriharsha Basavapatna 
1032*63f531d1SSriharsha Basavapatna 	if (rx_grp->ring_cnt == rx_grp->max_ring_cnt) {
1033*63f531d1SSriharsha Basavapatna 		/* no rings available */
1034*63f531d1SSriharsha Basavapatna 		RW_EXIT(&rx_grp->lock);
1035*63f531d1SSriharsha Basavapatna 		return (NULL);
1036*63f531d1SSriharsha Basavapatna 	}
1037*63f531d1SSriharsha Basavapatna 
1038*63f531d1SSriharsha Basavapatna 	for (index = VNET_NUM_PSEUDO_RXRINGS_DEFAULT;
1039*63f531d1SSriharsha Basavapatna 	    index < rx_grp->max_ring_cnt; index++) {
1040*63f531d1SSriharsha Basavapatna 		rx_ringp = &rx_grp->rings[index];
1041*63f531d1SSriharsha Basavapatna 		if (rx_ringp->state == VNET_RXRING_FREE) {
1042*63f531d1SSriharsha Basavapatna 			rx_ringp->state |= VNET_RXRING_INUSE;
1043*63f531d1SSriharsha Basavapatna 			rx_grp->ring_cnt++;
1044*63f531d1SSriharsha Basavapatna 			break;
1045*63f531d1SSriharsha Basavapatna 		}
1046*63f531d1SSriharsha Basavapatna 	}
1047*63f531d1SSriharsha Basavapatna 
1048*63f531d1SSriharsha Basavapatna 	RW_EXIT(&rx_grp->lock);
1049*63f531d1SSriharsha Basavapatna 	return (rx_ringp);
1050*63f531d1SSriharsha Basavapatna }
1051*63f531d1SSriharsha Basavapatna 
1052*63f531d1SSriharsha Basavapatna static void
1053*63f531d1SSriharsha Basavapatna vnet_free_pseudo_rx_ring(vnet_t *vnetp, vnet_pseudo_rx_ring_t *ringp)
1054*63f531d1SSriharsha Basavapatna {
1055*63f531d1SSriharsha Basavapatna 	vnet_pseudo_rx_group_t  *rx_grp;
1056*63f531d1SSriharsha Basavapatna 
1057*63f531d1SSriharsha Basavapatna 	ASSERT(ringp->index >= VNET_NUM_PSEUDO_RXRINGS_DEFAULT);
1058*63f531d1SSriharsha Basavapatna 	rx_grp = &vnetp->rx_grp[0];
1059*63f531d1SSriharsha Basavapatna 	WRITE_ENTER(&rx_grp->lock);
1060*63f531d1SSriharsha Basavapatna 
1061*63f531d1SSriharsha Basavapatna 	if (ringp->state != VNET_RXRING_FREE) {
1062*63f531d1SSriharsha Basavapatna 		ringp->state = VNET_RXRING_FREE;
1063*63f531d1SSriharsha Basavapatna 		ringp->handle = NULL;
1064*63f531d1SSriharsha Basavapatna 		rx_grp->ring_cnt--;
1065*63f531d1SSriharsha Basavapatna 	}
1066*63f531d1SSriharsha Basavapatna 
1067*63f531d1SSriharsha Basavapatna 	RW_EXIT(&rx_grp->lock);
1068*63f531d1SSriharsha Basavapatna }
1069*63f531d1SSriharsha Basavapatna 
10701ae08745Sheppo /* wrapper function for mac_register() */
10711ae08745Sheppo static int
10721ae08745Sheppo vnet_mac_register(vnet_t *vnetp)
10731ae08745Sheppo {
1074ba2e4443Sseb 	mac_register_t	*macp;
1075ba2e4443Sseb 	int		err;
10761ae08745Sheppo 
1077ba2e4443Sseb 	if ((macp = mac_alloc(MAC_VERSION)) == NULL)
1078ba2e4443Sseb 		return (DDI_FAILURE);
1079ba2e4443Sseb 	macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
1080ba2e4443Sseb 	macp->m_driver = vnetp;
10811ae08745Sheppo 	macp->m_dip = vnetp->dip;
1082ba2e4443Sseb 	macp->m_src_addr = vnetp->curr_macaddr;
1083ba2e4443Sseb 	macp->m_callbacks = &vnet_m_callbacks;
1084ba2e4443Sseb 	macp->m_min_sdu = 0;
10857b1f684aSSriharsha Basavapatna 	macp->m_max_sdu = vnetp->mtu;
1086c1c61f44Ssb155480 	macp->m_margin = VLAN_TAGSZ;
10871ae08745Sheppo 
10881ae08745Sheppo 	/*
1089*63f531d1SSriharsha Basavapatna 	 * MAC_VIRT_SERIALIZE flag is needed while hybridIO is enabled to
1090*63f531d1SSriharsha Basavapatna 	 * workaround tx lock contention issues in nxge.
1091*63f531d1SSriharsha Basavapatna 	 */
1092*63f531d1SSriharsha Basavapatna 	macp->m_v12n = MAC_VIRT_LEVEL1;
1093*63f531d1SSriharsha Basavapatna 	if (vnet_mac_tx_serialize == B_TRUE) {
1094*63f531d1SSriharsha Basavapatna 		macp->m_v12n |= MAC_VIRT_SERIALIZE;
1095*63f531d1SSriharsha Basavapatna 	}
1096*63f531d1SSriharsha Basavapatna 
1097*63f531d1SSriharsha Basavapatna 	/*
10981ae08745Sheppo 	 * Finally, we're ready to register ourselves with the MAC layer
10991ae08745Sheppo 	 * interface; if this succeeds, we're all ready to start()
11001ae08745Sheppo 	 */
1101ba2e4443Sseb 	err = mac_register(macp, &vnetp->mh);
1102ba2e4443Sseb 	mac_free(macp);
1103ba2e4443Sseb 	return (err == 0 ? DDI_SUCCESS : DDI_FAILURE);
11041ae08745Sheppo }
11051ae08745Sheppo 
11061ae08745Sheppo /* read the mac address of the device */
11071ae08745Sheppo static int
11081ae08745Sheppo vnet_read_mac_address(vnet_t *vnetp)
11091ae08745Sheppo {
11101ae08745Sheppo 	uchar_t 	*macaddr;
11111ae08745Sheppo 	uint32_t 	size;
11121ae08745Sheppo 	int 		rv;
11131ae08745Sheppo 
11141ae08745Sheppo 	rv = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, vnetp->dip,
11151ae08745Sheppo 	    DDI_PROP_DONTPASS, macaddr_propname, &macaddr, &size);
11161ae08745Sheppo 	if ((rv != DDI_PROP_SUCCESS) || (size != ETHERADDRL)) {
1117844e62a3Sraghuram 		DWARN(vnetp, "prop_lookup failed(%s) err(%d)\n",
1118844e62a3Sraghuram 		    macaddr_propname, rv);
11191ae08745Sheppo 		return (DDI_FAILURE);
11201ae08745Sheppo 	}
11211ae08745Sheppo 	bcopy(macaddr, (caddr_t)vnetp->vendor_addr, ETHERADDRL);
11221ae08745Sheppo 	bcopy(macaddr, (caddr_t)vnetp->curr_macaddr, ETHERADDRL);
11231ae08745Sheppo 	ddi_prop_free(macaddr);
11241ae08745Sheppo 
11251ae08745Sheppo 	return (DDI_SUCCESS);
11261ae08745Sheppo }
11271ae08745Sheppo 
112893b13a42Swentaoy static void
1129c1c61f44Ssb155480 vnet_fdb_create(vnet_t *vnetp)
113093b13a42Swentaoy {
1131c1c61f44Ssb155480 	char		hashname[MAXNAMELEN];
113293b13a42Swentaoy 
1133c1c61f44Ssb155480 	(void) snprintf(hashname, MAXNAMELEN, "vnet%d-fdbhash",
1134c1c61f44Ssb155480 	    vnetp->instance);
1135c1c61f44Ssb155480 	vnetp->fdb_nchains = vnet_fdb_nchains;
1136c1c61f44Ssb155480 	vnetp->fdb_hashp = mod_hash_create_ptrhash(hashname, vnetp->fdb_nchains,
1137c1c61f44Ssb155480 	    mod_hash_null_valdtor, sizeof (void *));
113893b13a42Swentaoy }
113993b13a42Swentaoy 
114093b13a42Swentaoy static void
1141c1c61f44Ssb155480 vnet_fdb_destroy(vnet_t *vnetp)
114293b13a42Swentaoy {
1143c1c61f44Ssb155480 	/* destroy fdb-hash-table */
1144c1c61f44Ssb155480 	if (vnetp->fdb_hashp != NULL) {
1145c1c61f44Ssb155480 		mod_hash_destroy_hash(vnetp->fdb_hashp);
1146c1c61f44Ssb155480 		vnetp->fdb_hashp = NULL;
1147c1c61f44Ssb155480 		vnetp->fdb_nchains = 0;
1148c1c61f44Ssb155480 	}
114993b13a42Swentaoy }
115093b13a42Swentaoy 
115193b13a42Swentaoy /*
1152c1c61f44Ssb155480  * Add an entry into the fdb.
115393b13a42Swentaoy  */
11541ae08745Sheppo void
1155678453a8Sspeer vnet_fdbe_add(vnet_t *vnetp, vnet_res_t *vresp)
11561ae08745Sheppo {
1157c1c61f44Ssb155480 	uint64_t	addr = 0;
1158c1c61f44Ssb155480 	int		rv;
1159c1c61f44Ssb155480 
1160678453a8Sspeer 	KEY_HASH(addr, vresp->rem_macaddr);
11611ae08745Sheppo 
11621ae08745Sheppo 	/*
1163678453a8Sspeer 	 * If the entry being added corresponds to LDC_SERVICE resource,
1164678453a8Sspeer 	 * that is, vswitch connection, it is added to the hash and also
1165678453a8Sspeer 	 * the entry is cached, an additional reference count reflects
1166678453a8Sspeer 	 * this. The HYBRID resource is not added to the hash, but only
1167678453a8Sspeer 	 * cached, as it is only used for sending out packets for unknown
1168678453a8Sspeer 	 * unicast destinations.
11691ae08745Sheppo 	 */
1170678453a8Sspeer 	(vresp->type == VIO_NET_RES_LDC_SERVICE) ?
1171678453a8Sspeer 	    (vresp->refcnt = 1) : (vresp->refcnt = 0);
11721ae08745Sheppo 
1173c1c61f44Ssb155480 	/*
1174c1c61f44Ssb155480 	 * Note: duplicate keys will be rejected by mod_hash.
1175c1c61f44Ssb155480 	 */
1176678453a8Sspeer 	if (vresp->type != VIO_NET_RES_HYBRID) {
1177c1c61f44Ssb155480 		rv = mod_hash_insert(vnetp->fdb_hashp, (mod_hash_key_t)addr,
1178678453a8Sspeer 		    (mod_hash_val_t)vresp);
1179c1c61f44Ssb155480 		if (rv != 0) {
1180c1c61f44Ssb155480 			DWARN(vnetp, "Duplicate macaddr key(%lx)\n", addr);
11811ae08745Sheppo 			return;
11821ae08745Sheppo 		}
1183678453a8Sspeer 	}
11841ae08745Sheppo 
1185678453a8Sspeer 	if (vresp->type == VIO_NET_RES_LDC_SERVICE) {
1186c1c61f44Ssb155480 		/* Cache the fdb entry to vsw-port */
1187c1c61f44Ssb155480 		WRITE_ENTER(&vnetp->vsw_fp_rw);
1188c1c61f44Ssb155480 		if (vnetp->vsw_fp == NULL)
1189678453a8Sspeer 			vnetp->vsw_fp = vresp;
1190678453a8Sspeer 		RW_EXIT(&vnetp->vsw_fp_rw);
1191678453a8Sspeer 	} else if (vresp->type == VIO_NET_RES_HYBRID) {
1192678453a8Sspeer 		/* Cache the fdb entry to hybrid resource */
1193678453a8Sspeer 		WRITE_ENTER(&vnetp->vsw_fp_rw);
1194678453a8Sspeer 		if (vnetp->hio_fp == NULL)
1195678453a8Sspeer 			vnetp->hio_fp = vresp;
1196c1c61f44Ssb155480 		RW_EXIT(&vnetp->vsw_fp_rw);
1197c1c61f44Ssb155480 	}
11981ae08745Sheppo }
11991ae08745Sheppo 
1200c1c61f44Ssb155480 /*
1201c1c61f44Ssb155480  * Remove an entry from fdb.
1202c1c61f44Ssb155480  */
1203678453a8Sspeer static void
1204678453a8Sspeer vnet_fdbe_del(vnet_t *vnetp, vnet_res_t *vresp)
12051ae08745Sheppo {
1206c1c61f44Ssb155480 	uint64_t	addr = 0;
1207c1c61f44Ssb155480 	int		rv;
1208c1c61f44Ssb155480 	uint32_t	refcnt;
1209678453a8Sspeer 	vnet_res_t	*tmp;
1210c1c61f44Ssb155480 
1211678453a8Sspeer 	KEY_HASH(addr, vresp->rem_macaddr);
12121ae08745Sheppo 
12131ae08745Sheppo 	/*
1214c1c61f44Ssb155480 	 * Remove the entry from fdb hash table.
1215c1c61f44Ssb155480 	 * This prevents further references to this fdb entry.
12161ae08745Sheppo 	 */
1217678453a8Sspeer 	if (vresp->type != VIO_NET_RES_HYBRID) {
1218c1c61f44Ssb155480 		rv = mod_hash_remove(vnetp->fdb_hashp, (mod_hash_key_t)addr,
1219678453a8Sspeer 		    (mod_hash_val_t *)&tmp);
1220678453a8Sspeer 		if (rv != 0) {
1221678453a8Sspeer 			/*
1222678453a8Sspeer 			 * As the resources are added to the hash only
1223678453a8Sspeer 			 * after they are started, this can occur if
1224678453a8Sspeer 			 * a resource unregisters before it is ever started.
1225678453a8Sspeer 			 */
1226678453a8Sspeer 			return;
1227678453a8Sspeer 		}
1228678453a8Sspeer 	}
12291ae08745Sheppo 
1230678453a8Sspeer 	if (vresp->type == VIO_NET_RES_LDC_SERVICE) {
1231c1c61f44Ssb155480 		WRITE_ENTER(&vnetp->vsw_fp_rw);
12321ae08745Sheppo 
1233678453a8Sspeer 		ASSERT(tmp == vnetp->vsw_fp);
1234c1c61f44Ssb155480 		vnetp->vsw_fp = NULL;
1235c1c61f44Ssb155480 
1236c1c61f44Ssb155480 		RW_EXIT(&vnetp->vsw_fp_rw);
1237678453a8Sspeer 	} else if (vresp->type == VIO_NET_RES_HYBRID) {
1238678453a8Sspeer 		WRITE_ENTER(&vnetp->vsw_fp_rw);
1239678453a8Sspeer 
1240678453a8Sspeer 		vnetp->hio_fp = NULL;
1241678453a8Sspeer 
1242678453a8Sspeer 		RW_EXIT(&vnetp->vsw_fp_rw);
12431ae08745Sheppo 	}
12441ae08745Sheppo 
1245c1c61f44Ssb155480 	/*
1246c1c61f44Ssb155480 	 * If there are threads already ref holding before the entry was
1247c1c61f44Ssb155480 	 * removed from hash table, then wait for ref count to drop to zero.
1248c1c61f44Ssb155480 	 */
1249678453a8Sspeer 	(vresp->type == VIO_NET_RES_LDC_SERVICE) ?
1250678453a8Sspeer 	    (refcnt = 1) : (refcnt = 0);
1251678453a8Sspeer 	while (vresp->refcnt > refcnt) {
1252c1c61f44Ssb155480 		delay(drv_usectohz(vnet_fdbe_refcnt_delay));
1253c1c61f44Ssb155480 	}
1254c1c61f44Ssb155480 }
1255c1c61f44Ssb155480 
1256c1c61f44Ssb155480 /*
1257c1c61f44Ssb155480  * Search fdb for a given mac address. If an entry is found, hold
1258c1c61f44Ssb155480  * a reference to it and return the entry; else returns NULL.
1259c1c61f44Ssb155480  */
1260678453a8Sspeer static vnet_res_t *
1261c1c61f44Ssb155480 vnet_fdbe_find(vnet_t *vnetp, struct ether_addr *addrp)
1262c1c61f44Ssb155480 {
1263c1c61f44Ssb155480 	uint64_t	key = 0;
1264678453a8Sspeer 	vnet_res_t	*vresp;
1265c1c61f44Ssb155480 	int		rv;
1266c1c61f44Ssb155480 
1267678453a8Sspeer 	KEY_HASH(key, addrp->ether_addr_octet);
1268c1c61f44Ssb155480 
1269c1c61f44Ssb155480 	rv = mod_hash_find_cb(vnetp->fdb_hashp, (mod_hash_key_t)key,
1270678453a8Sspeer 	    (mod_hash_val_t *)&vresp, vnet_fdbe_find_cb);
1271c1c61f44Ssb155480 
1272c1c61f44Ssb155480 	if (rv != 0)
1273c1c61f44Ssb155480 		return (NULL);
1274c1c61f44Ssb155480 
1275678453a8Sspeer 	return (vresp);
1276c1c61f44Ssb155480 }
1277c1c61f44Ssb155480 
1278c1c61f44Ssb155480 /*
1279c1c61f44Ssb155480  * Callback function provided to mod_hash_find_cb(). After finding the fdb
1280c1c61f44Ssb155480  * entry corresponding to the key (macaddr), this callback will be invoked by
1281c1c61f44Ssb155480  * mod_hash_find_cb() to atomically increment the reference count on the fdb
1282c1c61f44Ssb155480  * entry before returning the found entry.
1283c1c61f44Ssb155480  */
1284c1c61f44Ssb155480 static void
1285c1c61f44Ssb155480 vnet_fdbe_find_cb(mod_hash_key_t key, mod_hash_val_t val)
1286c1c61f44Ssb155480 {
1287c1c61f44Ssb155480 	_NOTE(ARGUNUSED(key))
1288678453a8Sspeer 	VNET_FDBE_REFHOLD((vnet_res_t *)val);
1289678453a8Sspeer }
1290678453a8Sspeer 
12918c242ab0SSriharsha Basavapatna /*
12928c242ab0SSriharsha Basavapatna  * Frames received that are tagged with the pvid of the vnet device must be
12938c242ab0SSriharsha Basavapatna  * untagged before sending up the stack. This function walks the chain of rx
12948c242ab0SSriharsha Basavapatna  * frames, untags any such frames and returns the updated chain.
12958c242ab0SSriharsha Basavapatna  *
12968c242ab0SSriharsha Basavapatna  * Arguments:
12978c242ab0SSriharsha Basavapatna  *    pvid:  pvid of the vnet device for which packets are being received
12988c242ab0SSriharsha Basavapatna  *    mp:    head of pkt chain to be validated and untagged
12998c242ab0SSriharsha Basavapatna  *
13008c242ab0SSriharsha Basavapatna  * Returns:
13018c242ab0SSriharsha Basavapatna  *    mp:    head of updated chain of packets
13028c242ab0SSriharsha Basavapatna  */
13038c242ab0SSriharsha Basavapatna static void
13048c242ab0SSriharsha Basavapatna vnet_rx_frames_untag(uint16_t pvid, mblk_t **mp)
13058c242ab0SSriharsha Basavapatna {
13068c242ab0SSriharsha Basavapatna 	struct ether_vlan_header	*evhp;
13078c242ab0SSriharsha Basavapatna 	mblk_t				*bp;
13088c242ab0SSriharsha Basavapatna 	mblk_t				*bpt;
13098c242ab0SSriharsha Basavapatna 	mblk_t				*bph;
13108c242ab0SSriharsha Basavapatna 	mblk_t				*bpn;
13118c242ab0SSriharsha Basavapatna 
13128c242ab0SSriharsha Basavapatna 	bpn = bph = bpt = NULL;
13138c242ab0SSriharsha Basavapatna 
13148c242ab0SSriharsha Basavapatna 	for (bp = *mp; bp != NULL; bp = bpn) {
13158c242ab0SSriharsha Basavapatna 
13168c242ab0SSriharsha Basavapatna 		bpn = bp->b_next;
13178c242ab0SSriharsha Basavapatna 		bp->b_next = bp->b_prev = NULL;
13188c242ab0SSriharsha Basavapatna 
13198c242ab0SSriharsha Basavapatna 		evhp = (struct ether_vlan_header *)bp->b_rptr;
13208c242ab0SSriharsha Basavapatna 
13218c242ab0SSriharsha Basavapatna 		if (ntohs(evhp->ether_tpid) == ETHERTYPE_VLAN &&
13228c242ab0SSriharsha Basavapatna 		    VLAN_ID(ntohs(evhp->ether_tci)) == pvid) {
13238c242ab0SSriharsha Basavapatna 
13248c242ab0SSriharsha Basavapatna 			bp = vnet_vlan_remove_tag(bp);
13258c242ab0SSriharsha Basavapatna 			if (bp == NULL) {
13268c242ab0SSriharsha Basavapatna 				continue;
13278c242ab0SSriharsha Basavapatna 			}
13288c242ab0SSriharsha Basavapatna 
13298c242ab0SSriharsha Basavapatna 		}
13308c242ab0SSriharsha Basavapatna 
13318c242ab0SSriharsha Basavapatna 		/* build a chain of processed packets */
13328c242ab0SSriharsha Basavapatna 		if (bph == NULL) {
13338c242ab0SSriharsha Basavapatna 			bph = bpt = bp;
13348c242ab0SSriharsha Basavapatna 		} else {
13358c242ab0SSriharsha Basavapatna 			bpt->b_next = bp;
13368c242ab0SSriharsha Basavapatna 			bpt = bp;
13378c242ab0SSriharsha Basavapatna 		}
13388c242ab0SSriharsha Basavapatna 
13398c242ab0SSriharsha Basavapatna 	}
13408c242ab0SSriharsha Basavapatna 
13418c242ab0SSriharsha Basavapatna 	*mp = bph;
13428c242ab0SSriharsha Basavapatna }
13438c242ab0SSriharsha Basavapatna 
1344678453a8Sspeer static void
1345678453a8Sspeer vnet_rx(vio_net_handle_t vrh, mblk_t *mp)
1346678453a8Sspeer {
1347678453a8Sspeer 	vnet_res_t		*vresp = (vnet_res_t *)vrh;
1348678453a8Sspeer 	vnet_t			*vnetp = vresp->vnetp;
1349*63f531d1SSriharsha Basavapatna 	vnet_pseudo_rx_ring_t	*ringp;
1350678453a8Sspeer 
13518c242ab0SSriharsha Basavapatna 	if ((vnetp == NULL) || (vnetp->mh == 0)) {
1352678453a8Sspeer 		freemsgchain(mp);
13538c242ab0SSriharsha Basavapatna 		return;
1354678453a8Sspeer 	}
13558c242ab0SSriharsha Basavapatna 
1356*63f531d1SSriharsha Basavapatna 	ringp = vresp->rx_ringp;
1357*63f531d1SSriharsha Basavapatna 	mac_rx_ring(vnetp->mh, ringp->handle, mp, ringp->gen_num);
13581ae08745Sheppo }
1359ba2e4443Sseb 
1360ba2e4443Sseb void
1361678453a8Sspeer vnet_tx_update(vio_net_handle_t vrh)
1362ba2e4443Sseb {
1363678453a8Sspeer 	vnet_res_t		*vresp = (vnet_res_t *)vrh;
1364678453a8Sspeer 	vnet_t			*vnetp = vresp->vnetp;
1365*63f531d1SSriharsha Basavapatna 	vnet_pseudo_tx_ring_t	*tx_ringp;
1366*63f531d1SSriharsha Basavapatna 	vnet_pseudo_tx_group_t	*tx_grp;
1367*63f531d1SSriharsha Basavapatna 	int			i;
1368ba2e4443Sseb 
1369*63f531d1SSriharsha Basavapatna 	if (vnetp == NULL || vnetp->mh == NULL) {
1370*63f531d1SSriharsha Basavapatna 		return;
1371*63f531d1SSriharsha Basavapatna 	}
1372*63f531d1SSriharsha Basavapatna 
1373*63f531d1SSriharsha Basavapatna 	/*
1374*63f531d1SSriharsha Basavapatna 	 * Currently, the tx hwring API (used to access rings that belong to
1375*63f531d1SSriharsha Basavapatna 	 * a Hybrid IO resource) does not provide us a per ring flow ctrl
1376*63f531d1SSriharsha Basavapatna 	 * update; also the pseudo rings are shared by the ports/ldcs in the
1377*63f531d1SSriharsha Basavapatna 	 * vgen layer. Thus we can't figure out which pseudo ring is being
1378*63f531d1SSriharsha Basavapatna 	 * re-enabled for transmits. To work around this, when we get a tx
1379*63f531d1SSriharsha Basavapatna 	 * restart notification from below, we simply propagate that to all
1380*63f531d1SSriharsha Basavapatna 	 * the tx pseudo rings registered with the mac layer above.
1381*63f531d1SSriharsha Basavapatna 	 *
1382*63f531d1SSriharsha Basavapatna 	 * There are a couple of side effects with this approach, but they are
1383*63f531d1SSriharsha Basavapatna 	 * not harmful, as outlined below:
1384*63f531d1SSriharsha Basavapatna 	 *
1385*63f531d1SSriharsha Basavapatna 	 * A) We might send an invalid ring_update() for a ring that is not
1386*63f531d1SSriharsha Basavapatna 	 * really flow controlled. This will not have any effect in the mac
1387*63f531d1SSriharsha Basavapatna 	 * layer and packets will continue to be transmitted on that ring.
1388*63f531d1SSriharsha Basavapatna 	 *
1389*63f531d1SSriharsha Basavapatna 	 * B) We might end up clearing the flow control in the mac layer for
1390*63f531d1SSriharsha Basavapatna 	 * a ring that is still flow controlled in the underlying resource.
1391*63f531d1SSriharsha Basavapatna 	 * This will result in the mac layer restarting	transmit, only to be
1392*63f531d1SSriharsha Basavapatna 	 * flow controlled again on that ring.
1393*63f531d1SSriharsha Basavapatna 	 */
1394*63f531d1SSriharsha Basavapatna 	tx_grp = &vnetp->tx_grp[0];
1395*63f531d1SSriharsha Basavapatna 	for (i = 0; i < tx_grp->ring_cnt; i++) {
1396*63f531d1SSriharsha Basavapatna 		tx_ringp = &tx_grp->rings[i];
1397*63f531d1SSriharsha Basavapatna 		mac_tx_ring_update(vnetp->mh, tx_ringp->handle);
1398ba2e4443Sseb 	}
1399678453a8Sspeer }
1400678453a8Sspeer 
1401678453a8Sspeer /*
14027b1f684aSSriharsha Basavapatna  * Update the new mtu of vnet into the mac layer. First check if the device has
14037b1f684aSSriharsha Basavapatna  * been plumbed and if so fail the mtu update. Returns 0 on success.
14047b1f684aSSriharsha Basavapatna  */
14057b1f684aSSriharsha Basavapatna int
14067b1f684aSSriharsha Basavapatna vnet_mtu_update(vnet_t *vnetp, uint32_t mtu)
14077b1f684aSSriharsha Basavapatna {
14087b1f684aSSriharsha Basavapatna 	int	rv;
14097b1f684aSSriharsha Basavapatna 
14107b1f684aSSriharsha Basavapatna 	if (vnetp == NULL || vnetp->mh == NULL) {
14117b1f684aSSriharsha Basavapatna 		return (EINVAL);
14127b1f684aSSriharsha Basavapatna 	}
14137b1f684aSSriharsha Basavapatna 
14147b1f684aSSriharsha Basavapatna 	WRITE_ENTER(&vnetp->vrwlock);
14157b1f684aSSriharsha Basavapatna 
14167b1f684aSSriharsha Basavapatna 	if (vnetp->flags & VNET_STARTED) {
14177b1f684aSSriharsha Basavapatna 		RW_EXIT(&vnetp->vrwlock);
14187b1f684aSSriharsha Basavapatna 		cmn_err(CE_NOTE, "!vnet%d: Unable to process mtu "
14197b1f684aSSriharsha Basavapatna 		    "update as the device is plumbed\n",
14207b1f684aSSriharsha Basavapatna 		    vnetp->instance);
14217b1f684aSSriharsha Basavapatna 		return (EBUSY);
14227b1f684aSSriharsha Basavapatna 	}
14237b1f684aSSriharsha Basavapatna 
14247b1f684aSSriharsha Basavapatna 	/* update mtu in the mac layer */
14257b1f684aSSriharsha Basavapatna 	rv = mac_maxsdu_update(vnetp->mh, mtu);
14267b1f684aSSriharsha Basavapatna 	if (rv != 0) {
14277b1f684aSSriharsha Basavapatna 		RW_EXIT(&vnetp->vrwlock);
14287b1f684aSSriharsha Basavapatna 		cmn_err(CE_NOTE,
14297b1f684aSSriharsha Basavapatna 		    "!vnet%d: Unable to update mtu with mac layer\n",
14307b1f684aSSriharsha Basavapatna 		    vnetp->instance);
14317b1f684aSSriharsha Basavapatna 		return (EIO);
14327b1f684aSSriharsha Basavapatna 	}
14337b1f684aSSriharsha Basavapatna 
14347b1f684aSSriharsha Basavapatna 	vnetp->mtu = mtu;
14357b1f684aSSriharsha Basavapatna 
14367b1f684aSSriharsha Basavapatna 	RW_EXIT(&vnetp->vrwlock);
14377b1f684aSSriharsha Basavapatna 
14387b1f684aSSriharsha Basavapatna 	return (0);
14397b1f684aSSriharsha Basavapatna }
14407b1f684aSSriharsha Basavapatna 
14417b1f684aSSriharsha Basavapatna /*
14421107ea93SSriharsha Basavapatna  * Update the link state of vnet to the mac layer.
14431107ea93SSriharsha Basavapatna  */
14441107ea93SSriharsha Basavapatna void
14451107ea93SSriharsha Basavapatna vnet_link_update(vnet_t *vnetp, link_state_t link_state)
14461107ea93SSriharsha Basavapatna {
14471107ea93SSriharsha Basavapatna 	if (vnetp == NULL || vnetp->mh == NULL) {
14481107ea93SSriharsha Basavapatna 		return;
14491107ea93SSriharsha Basavapatna 	}
14501107ea93SSriharsha Basavapatna 
14511107ea93SSriharsha Basavapatna 	WRITE_ENTER(&vnetp->vrwlock);
14521107ea93SSriharsha Basavapatna 	if (vnetp->link_state == link_state) {
14531107ea93SSriharsha Basavapatna 		RW_EXIT(&vnetp->vrwlock);
14541107ea93SSriharsha Basavapatna 		return;
14551107ea93SSriharsha Basavapatna 	}
14561107ea93SSriharsha Basavapatna 	vnetp->link_state = link_state;
14571107ea93SSriharsha Basavapatna 	RW_EXIT(&vnetp->vrwlock);
14581107ea93SSriharsha Basavapatna 
14591107ea93SSriharsha Basavapatna 	mac_link_update(vnetp->mh, link_state);
14601107ea93SSriharsha Basavapatna }
14611107ea93SSriharsha Basavapatna 
14621107ea93SSriharsha Basavapatna /*
1463678453a8Sspeer  * vio_net_resource_reg -- An interface called to register a resource
1464678453a8Sspeer  *	with vnet.
1465678453a8Sspeer  *	macp -- a GLDv3 mac_register that has all the details of
1466678453a8Sspeer  *		a resource and its callbacks etc.
1467678453a8Sspeer  *	type -- resource type.
1468678453a8Sspeer  *	local_macaddr -- resource's MAC address. This is used to
1469678453a8Sspeer  *			 associate a resource with a corresponding vnet.
1470678453a8Sspeer  *	remote_macaddr -- remote side MAC address. This is ignored for
1471678453a8Sspeer  *			  the Hybrid resources.
1472678453a8Sspeer  *	vhp -- A handle returned to the caller.
1473678453a8Sspeer  *	vcb -- A set of callbacks provided to the callers.
1474678453a8Sspeer  */
1475678453a8Sspeer int vio_net_resource_reg(mac_register_t *macp, vio_net_res_type_t type,
1476678453a8Sspeer     ether_addr_t local_macaddr, ether_addr_t rem_macaddr, vio_net_handle_t *vhp,
1477678453a8Sspeer     vio_net_callbacks_t *vcb)
1478678453a8Sspeer {
1479678453a8Sspeer 	vnet_t		*vnetp;
1480678453a8Sspeer 	vnet_res_t	*vresp;
1481678453a8Sspeer 
1482678453a8Sspeer 	vresp = kmem_zalloc(sizeof (vnet_res_t), KM_SLEEP);
1483678453a8Sspeer 	ether_copy(local_macaddr, vresp->local_macaddr);
1484678453a8Sspeer 	ether_copy(rem_macaddr, vresp->rem_macaddr);
1485678453a8Sspeer 	vresp->type = type;
1486678453a8Sspeer 	bcopy(macp, &vresp->macreg, sizeof (mac_register_t));
1487678453a8Sspeer 
1488678453a8Sspeer 	DBG1(NULL, "Resource Registerig type=0%X\n", type);
1489678453a8Sspeer 
1490678453a8Sspeer 	READ_ENTER(&vnet_rw);
1491678453a8Sspeer 	vnetp = vnet_headp;
1492678453a8Sspeer 	while (vnetp != NULL) {
1493678453a8Sspeer 		if (VNET_MATCH_RES(vresp, vnetp)) {
1494678453a8Sspeer 			vresp->vnetp = vnetp;
14956b8fc343SWENTAO YANG 
14966b8fc343SWENTAO YANG 			/* Setup kstats for hio resource */
14976b8fc343SWENTAO YANG 			if (vresp->type == VIO_NET_RES_HYBRID) {
14986b8fc343SWENTAO YANG 				vresp->ksp = vnet_hio_setup_kstats(DRV_NAME,
14996b8fc343SWENTAO YANG 				    "hio", vresp);
15006b8fc343SWENTAO YANG 				if (vresp->ksp == NULL) {
15016b8fc343SWENTAO YANG 					cmn_err(CE_NOTE, "!vnet%d: Cannot "
15026b8fc343SWENTAO YANG 					    "create kstats for hio resource",
15036b8fc343SWENTAO YANG 					    vnetp->instance);
15046b8fc343SWENTAO YANG 				}
15056b8fc343SWENTAO YANG 			}
1506*63f531d1SSriharsha Basavapatna 			vnet_add_resource(vnetp, vresp);
1507678453a8Sspeer 			break;
1508678453a8Sspeer 		}
1509678453a8Sspeer 		vnetp = vnetp->nextp;
1510678453a8Sspeer 	}
1511678453a8Sspeer 	RW_EXIT(&vnet_rw);
1512678453a8Sspeer 	if (vresp->vnetp == NULL) {
1513678453a8Sspeer 		DWARN(NULL, "No vnet instance");
1514678453a8Sspeer 		kmem_free(vresp, sizeof (vnet_res_t));
1515678453a8Sspeer 		return (ENXIO);
1516678453a8Sspeer 	}
1517678453a8Sspeer 
1518678453a8Sspeer 	*vhp = vresp;
1519678453a8Sspeer 	vcb->vio_net_rx_cb = vnet_rx;
1520678453a8Sspeer 	vcb->vio_net_tx_update = vnet_tx_update;
1521678453a8Sspeer 	vcb->vio_net_report_err = vnet_handle_res_err;
1522678453a8Sspeer 
1523*63f531d1SSriharsha Basavapatna 	/* Bind the resource to pseudo ring(s) */
1524*63f531d1SSriharsha Basavapatna 	if (vnet_bind_rings(vresp) != 0) {
1525*63f531d1SSriharsha Basavapatna 		(void) vnet_rem_resource(vnetp, vresp);
1526*63f531d1SSriharsha Basavapatna 		vnet_hio_destroy_kstats(vresp->ksp);
1527*63f531d1SSriharsha Basavapatna 		KMEM_FREE(vresp);
1528*63f531d1SSriharsha Basavapatna 		return (1);
1529*63f531d1SSriharsha Basavapatna 	}
1530*63f531d1SSriharsha Basavapatna 
1531678453a8Sspeer 	/* Dispatch a task to start resources */
1532678453a8Sspeer 	vnet_dispatch_res_task(vnetp);
1533678453a8Sspeer 	return (0);
1534678453a8Sspeer }
1535678453a8Sspeer 
1536678453a8Sspeer /*
1537678453a8Sspeer  * vio_net_resource_unreg -- An interface to unregister a resource.
1538678453a8Sspeer  */
1539678453a8Sspeer void
1540678453a8Sspeer vio_net_resource_unreg(vio_net_handle_t vhp)
1541678453a8Sspeer {
1542678453a8Sspeer 	vnet_res_t	*vresp = (vnet_res_t *)vhp;
1543678453a8Sspeer 	vnet_t		*vnetp = vresp->vnetp;
1544678453a8Sspeer 
1545678453a8Sspeer 	DBG1(NULL, "Resource Registerig hdl=0x%p", vhp);
1546678453a8Sspeer 
1547678453a8Sspeer 	ASSERT(vnetp != NULL);
15485460ddbdSSriharsha Basavapatna 	/*
15495460ddbdSSriharsha Basavapatna 	 * Remove the resource from fdb; this ensures
15505460ddbdSSriharsha Basavapatna 	 * there are no references to the resource.
15515460ddbdSSriharsha Basavapatna 	 */
1552678453a8Sspeer 	vnet_fdbe_del(vnetp, vresp);
1553678453a8Sspeer 
1554*63f531d1SSriharsha Basavapatna 	vnet_unbind_rings(vresp);
1555*63f531d1SSriharsha Basavapatna 
15565460ddbdSSriharsha Basavapatna 	/* Now remove the resource from the list */
1557*63f531d1SSriharsha Basavapatna 	(void) vnet_rem_resource(vnetp, vresp);
1558*63f531d1SSriharsha Basavapatna 
1559*63f531d1SSriharsha Basavapatna 	vnet_hio_destroy_kstats(vresp->ksp);
1560*63f531d1SSriharsha Basavapatna 	KMEM_FREE(vresp);
1561*63f531d1SSriharsha Basavapatna }
1562*63f531d1SSriharsha Basavapatna 
1563*63f531d1SSriharsha Basavapatna static void
1564*63f531d1SSriharsha Basavapatna vnet_add_resource(vnet_t *vnetp, vnet_res_t *vresp)
1565*63f531d1SSriharsha Basavapatna {
1566*63f531d1SSriharsha Basavapatna 	WRITE_ENTER(&vnetp->vrwlock);
1567*63f531d1SSriharsha Basavapatna 	vresp->nextp = vnetp->vres_list;
1568*63f531d1SSriharsha Basavapatna 	vnetp->vres_list = vresp;
1569*63f531d1SSriharsha Basavapatna 	RW_EXIT(&vnetp->vrwlock);
1570*63f531d1SSriharsha Basavapatna }
1571*63f531d1SSriharsha Basavapatna 
1572*63f531d1SSriharsha Basavapatna static vnet_res_t *
1573*63f531d1SSriharsha Basavapatna vnet_rem_resource(vnet_t *vnetp, vnet_res_t *vresp)
1574*63f531d1SSriharsha Basavapatna {
1575*63f531d1SSriharsha Basavapatna 	vnet_res_t	*vrp;
1576*63f531d1SSriharsha Basavapatna 
1577678453a8Sspeer 	WRITE_ENTER(&vnetp->vrwlock);
1578678453a8Sspeer 	if (vresp == vnetp->vres_list) {
1579678453a8Sspeer 		vnetp->vres_list = vresp->nextp;
1580678453a8Sspeer 	} else {
1581678453a8Sspeer 		vrp = vnetp->vres_list;
1582678453a8Sspeer 		while (vrp->nextp != NULL) {
1583678453a8Sspeer 			if (vrp->nextp == vresp) {
1584678453a8Sspeer 				vrp->nextp = vresp->nextp;
1585678453a8Sspeer 				break;
1586678453a8Sspeer 			}
1587678453a8Sspeer 			vrp = vrp->nextp;
1588678453a8Sspeer 		}
1589678453a8Sspeer 	}
1590678453a8Sspeer 	vresp->vnetp = NULL;
1591678453a8Sspeer 	vresp->nextp = NULL;
1592*63f531d1SSriharsha Basavapatna 
1593678453a8Sspeer 	RW_EXIT(&vnetp->vrwlock);
1594*63f531d1SSriharsha Basavapatna 
1595*63f531d1SSriharsha Basavapatna 	return (vresp);
1596678453a8Sspeer }
1597678453a8Sspeer 
1598678453a8Sspeer /*
1599678453a8Sspeer  * vnet_dds_rx -- an interface called by vgen to DDS messages.
1600678453a8Sspeer  */
1601678453a8Sspeer void
1602678453a8Sspeer vnet_dds_rx(void *arg, void *dmsg)
1603678453a8Sspeer {
1604678453a8Sspeer 	vnet_t *vnetp = arg;
1605678453a8Sspeer 	vdds_process_dds_msg(vnetp, dmsg);
1606678453a8Sspeer }
1607678453a8Sspeer 
1608678453a8Sspeer /*
1609678453a8Sspeer  * vnet_send_dds_msg -- An interface provided to DDS to send
1610678453a8Sspeer  *	DDS messages. This simply sends meessages via vgen.
1611678453a8Sspeer  */
1612678453a8Sspeer int
1613678453a8Sspeer vnet_send_dds_msg(vnet_t *vnetp, void *dmsg)
1614678453a8Sspeer {
1615678453a8Sspeer 	int rv;
1616678453a8Sspeer 
1617678453a8Sspeer 	if (vnetp->vgenhdl != NULL) {
1618678453a8Sspeer 		rv = vgen_dds_tx(vnetp->vgenhdl, dmsg);
1619678453a8Sspeer 	}
1620678453a8Sspeer 	return (rv);
1621678453a8Sspeer }
1622678453a8Sspeer 
1623678453a8Sspeer /*
16246d6de4eeSWENTAO YANG  * vnet_cleanup_hio -- an interface called by vgen to cleanup hio resources.
16256d6de4eeSWENTAO YANG  */
16266d6de4eeSWENTAO YANG void
16276d6de4eeSWENTAO YANG vnet_dds_cleanup_hio(vnet_t *vnetp)
16286d6de4eeSWENTAO YANG {
16296d6de4eeSWENTAO YANG 	vdds_cleanup_hio(vnetp);
16306d6de4eeSWENTAO YANG }
16316d6de4eeSWENTAO YANG 
16326d6de4eeSWENTAO YANG /*
1633678453a8Sspeer  * vnet_handle_res_err -- A callback function called by a resource
1634678453a8Sspeer  *	to report an error. For example, vgen can call to report
1635678453a8Sspeer  *	an LDC down/reset event. This will trigger cleanup of associated
1636678453a8Sspeer  *	Hybrid resource.
1637678453a8Sspeer  */
1638678453a8Sspeer /* ARGSUSED */
1639678453a8Sspeer static void
1640678453a8Sspeer vnet_handle_res_err(vio_net_handle_t vrh, vio_net_err_val_t err)
1641678453a8Sspeer {
1642678453a8Sspeer 	vnet_res_t *vresp = (vnet_res_t *)vrh;
1643678453a8Sspeer 	vnet_t *vnetp = vresp->vnetp;
1644678453a8Sspeer 
1645678453a8Sspeer 	if (vnetp == NULL) {
1646678453a8Sspeer 		return;
1647678453a8Sspeer 	}
1648678453a8Sspeer 	if ((vresp->type != VIO_NET_RES_LDC_SERVICE) &&
1649678453a8Sspeer 	    (vresp->type != VIO_NET_RES_HYBRID)) {
1650678453a8Sspeer 		return;
1651678453a8Sspeer 	}
16526d6de4eeSWENTAO YANG 
16536d6de4eeSWENTAO YANG 	vdds_cleanup_hio(vnetp);
1654678453a8Sspeer }
1655678453a8Sspeer 
1656678453a8Sspeer /*
1657678453a8Sspeer  * vnet_dispatch_res_task -- A function to dispatch tasks start resources.
1658678453a8Sspeer  */
1659678453a8Sspeer static void
1660678453a8Sspeer vnet_dispatch_res_task(vnet_t *vnetp)
1661678453a8Sspeer {
1662678453a8Sspeer 	int rv;
1663678453a8Sspeer 
16648b923298SZach Kissel 	/*
16658b923298SZach Kissel 	 * Dispatch the task. It could be the case that vnetp->flags does
16668b923298SZach Kissel 	 * not have VNET_STARTED set. This is ok as vnet_rest_start_task()
16675460ddbdSSriharsha Basavapatna 	 * can abort the task when the task is started. See related comments
16685460ddbdSSriharsha Basavapatna 	 * in vnet_m_stop() and vnet_stop_resources().
16698b923298SZach Kissel 	 */
1670678453a8Sspeer 	rv = ddi_taskq_dispatch(vnetp->taskqp, vnet_res_start_task,
1671678453a8Sspeer 	    vnetp, DDI_NOSLEEP);
1672678453a8Sspeer 	if (rv != DDI_SUCCESS) {
1673678453a8Sspeer 		cmn_err(CE_WARN,
1674678453a8Sspeer 		    "vnet%d:Can't dispatch start resource task",
1675678453a8Sspeer 		    vnetp->instance);
1676678453a8Sspeer 	}
1677678453a8Sspeer }
1678678453a8Sspeer 
1679678453a8Sspeer /*
1680678453a8Sspeer  * vnet_res_start_task -- A taskq callback function that starts a resource.
1681678453a8Sspeer  */
1682678453a8Sspeer static void
1683678453a8Sspeer vnet_res_start_task(void *arg)
1684678453a8Sspeer {
1685678453a8Sspeer 	vnet_t *vnetp = arg;
1686678453a8Sspeer 
1687678453a8Sspeer 	WRITE_ENTER(&vnetp->vrwlock);
1688678453a8Sspeer 	if (vnetp->flags & VNET_STARTED) {
1689678453a8Sspeer 		vnet_start_resources(vnetp);
1690678453a8Sspeer 	}
1691678453a8Sspeer 	RW_EXIT(&vnetp->vrwlock);
1692678453a8Sspeer }
1693678453a8Sspeer 
1694678453a8Sspeer /*
1695678453a8Sspeer  * vnet_start_resources -- starts all resources associated with
1696678453a8Sspeer  *	a vnet.
1697678453a8Sspeer  */
1698678453a8Sspeer static void
1699678453a8Sspeer vnet_start_resources(vnet_t *vnetp)
1700678453a8Sspeer {
1701678453a8Sspeer 	mac_register_t	*macp;
1702678453a8Sspeer 	mac_callbacks_t	*cbp;
1703678453a8Sspeer 	vnet_res_t	*vresp;
1704678453a8Sspeer 	int rv;
1705678453a8Sspeer 
1706678453a8Sspeer 	DBG1(vnetp, "enter\n");
1707678453a8Sspeer 
17085460ddbdSSriharsha Basavapatna 	ASSERT(RW_WRITE_HELD(&vnetp->vrwlock));
17095460ddbdSSriharsha Basavapatna 
1710678453a8Sspeer 	for (vresp = vnetp->vres_list; vresp != NULL; vresp = vresp->nextp) {
1711678453a8Sspeer 		/* skip if it is already started */
1712678453a8Sspeer 		if (vresp->flags & VNET_STARTED) {
1713678453a8Sspeer 			continue;
1714678453a8Sspeer 		}
1715678453a8Sspeer 		macp = &vresp->macreg;
1716678453a8Sspeer 		cbp = macp->m_callbacks;
1717678453a8Sspeer 		rv = cbp->mc_start(macp->m_driver);
1718678453a8Sspeer 		if (rv == 0) {
1719678453a8Sspeer 			/*
1720678453a8Sspeer 			 * Successfully started the resource, so now
1721678453a8Sspeer 			 * add it to the fdb.
1722678453a8Sspeer 			 */
1723678453a8Sspeer 			vresp->flags |= VNET_STARTED;
1724678453a8Sspeer 			vnet_fdbe_add(vnetp, vresp);
1725678453a8Sspeer 		}
1726678453a8Sspeer 	}
1727678453a8Sspeer 
1728678453a8Sspeer 	DBG1(vnetp, "exit\n");
1729678453a8Sspeer 
1730678453a8Sspeer }
1731678453a8Sspeer 
1732678453a8Sspeer /*
1733678453a8Sspeer  * vnet_stop_resources -- stop all resources associated with a vnet.
1734678453a8Sspeer  */
1735678453a8Sspeer static void
1736678453a8Sspeer vnet_stop_resources(vnet_t *vnetp)
1737678453a8Sspeer {
1738678453a8Sspeer 	vnet_res_t	*vresp;
1739678453a8Sspeer 	mac_register_t	*macp;
1740678453a8Sspeer 	mac_callbacks_t	*cbp;
1741678453a8Sspeer 
1742678453a8Sspeer 	DBG1(vnetp, "enter\n");
1743678453a8Sspeer 
17445460ddbdSSriharsha Basavapatna 	ASSERT(RW_WRITE_HELD(&vnetp->vrwlock));
17455460ddbdSSriharsha Basavapatna 
1746678453a8Sspeer 	for (vresp = vnetp->vres_list; vresp != NULL; ) {
1747678453a8Sspeer 		if (vresp->flags & VNET_STARTED) {
17485460ddbdSSriharsha Basavapatna 			/*
17495460ddbdSSriharsha Basavapatna 			 * Release the lock while invoking mc_stop() of the
17505460ddbdSSriharsha Basavapatna 			 * underlying resource. We hold a reference to this
17515460ddbdSSriharsha Basavapatna 			 * resource to prevent being removed from the list in
17525460ddbdSSriharsha Basavapatna 			 * vio_net_resource_unreg(). Note that new resources
17535460ddbdSSriharsha Basavapatna 			 * can be added to the head of the list while the lock
17545460ddbdSSriharsha Basavapatna 			 * is released, but they won't be started, as
17555460ddbdSSriharsha Basavapatna 			 * VNET_STARTED flag has been cleared for the vnet
17565460ddbdSSriharsha Basavapatna 			 * device in vnet_m_stop(). Also, while the lock is
17575460ddbdSSriharsha Basavapatna 			 * released a resource could be removed from the list
17585460ddbdSSriharsha Basavapatna 			 * in vio_net_resource_unreg(); but that is ok, as we
17595460ddbdSSriharsha Basavapatna 			 * re-acquire the lock and only then access the forward
17605460ddbdSSriharsha Basavapatna 			 * link (vresp->nextp) to continue with the next
17615460ddbdSSriharsha Basavapatna 			 * resource.
17625460ddbdSSriharsha Basavapatna 			 */
17635460ddbdSSriharsha Basavapatna 			vresp->flags &= ~VNET_STARTED;
17645460ddbdSSriharsha Basavapatna 			vresp->flags |= VNET_STOPPING;
1765678453a8Sspeer 			macp = &vresp->macreg;
1766678453a8Sspeer 			cbp = macp->m_callbacks;
17675460ddbdSSriharsha Basavapatna 			VNET_FDBE_REFHOLD(vresp);
17685460ddbdSSriharsha Basavapatna 			RW_EXIT(&vnetp->vrwlock);
17695460ddbdSSriharsha Basavapatna 
1770678453a8Sspeer 			cbp->mc_stop(macp->m_driver);
17715460ddbdSSriharsha Basavapatna 
17725460ddbdSSriharsha Basavapatna 			WRITE_ENTER(&vnetp->vrwlock);
17735460ddbdSSriharsha Basavapatna 			vresp->flags &= ~VNET_STOPPING;
17745460ddbdSSriharsha Basavapatna 			VNET_FDBE_REFRELE(vresp);
1775678453a8Sspeer 		}
17765460ddbdSSriharsha Basavapatna 		vresp = vresp->nextp;
1777678453a8Sspeer 	}
1778678453a8Sspeer 	DBG1(vnetp, "exit\n");
1779678453a8Sspeer }
17806ab6cb20SWENTAO YANG 
17816ab6cb20SWENTAO YANG /*
17826ab6cb20SWENTAO YANG  * Setup kstats for the HIO statistics.
17836ab6cb20SWENTAO YANG  * NOTE: the synchronization for the statistics is the
17846ab6cb20SWENTAO YANG  * responsibility of the caller.
17856ab6cb20SWENTAO YANG  */
17866ab6cb20SWENTAO YANG kstat_t *
17876ab6cb20SWENTAO YANG vnet_hio_setup_kstats(char *ks_mod, char *ks_name, vnet_res_t *vresp)
17886ab6cb20SWENTAO YANG {
17896ab6cb20SWENTAO YANG 	kstat_t *ksp;
17906ab6cb20SWENTAO YANG 	vnet_t *vnetp = vresp->vnetp;
17916ab6cb20SWENTAO YANG 	vnet_hio_kstats_t *hiokp;
17926ab6cb20SWENTAO YANG 	size_t size;
17936ab6cb20SWENTAO YANG 
17946ab6cb20SWENTAO YANG 	ASSERT(vnetp != NULL);
17956ab6cb20SWENTAO YANG 	size = sizeof (vnet_hio_kstats_t) / sizeof (kstat_named_t);
17966ab6cb20SWENTAO YANG 	ksp = kstat_create(ks_mod, vnetp->instance, ks_name, "net",
17976ab6cb20SWENTAO YANG 	    KSTAT_TYPE_NAMED, size, 0);
17986ab6cb20SWENTAO YANG 	if (ksp == NULL) {
17996ab6cb20SWENTAO YANG 		return (NULL);
18006ab6cb20SWENTAO YANG 	}
18016ab6cb20SWENTAO YANG 
18026ab6cb20SWENTAO YANG 	hiokp = (vnet_hio_kstats_t *)ksp->ks_data;
18036ab6cb20SWENTAO YANG 	kstat_named_init(&hiokp->ipackets,		"ipackets",
18046ab6cb20SWENTAO YANG 	    KSTAT_DATA_ULONG);
18056ab6cb20SWENTAO YANG 	kstat_named_init(&hiokp->ierrors,		"ierrors",
18066ab6cb20SWENTAO YANG 	    KSTAT_DATA_ULONG);
18076ab6cb20SWENTAO YANG 	kstat_named_init(&hiokp->opackets,		"opackets",
18086ab6cb20SWENTAO YANG 	    KSTAT_DATA_ULONG);
18096ab6cb20SWENTAO YANG 	kstat_named_init(&hiokp->oerrors,		"oerrors",
18106ab6cb20SWENTAO YANG 	    KSTAT_DATA_ULONG);
18116ab6cb20SWENTAO YANG 
18126ab6cb20SWENTAO YANG 
18136ab6cb20SWENTAO YANG 	/* MIB II kstat variables */
18146ab6cb20SWENTAO YANG 	kstat_named_init(&hiokp->rbytes,		"rbytes",
18156ab6cb20SWENTAO YANG 	    KSTAT_DATA_ULONG);
18166ab6cb20SWENTAO YANG 	kstat_named_init(&hiokp->obytes,		"obytes",
18176ab6cb20SWENTAO YANG 	    KSTAT_DATA_ULONG);
18186ab6cb20SWENTAO YANG 	kstat_named_init(&hiokp->multircv,		"multircv",
18196ab6cb20SWENTAO YANG 	    KSTAT_DATA_ULONG);
18206ab6cb20SWENTAO YANG 	kstat_named_init(&hiokp->multixmt,		"multixmt",
18216ab6cb20SWENTAO YANG 	    KSTAT_DATA_ULONG);
18226ab6cb20SWENTAO YANG 	kstat_named_init(&hiokp->brdcstrcv,		"brdcstrcv",
18236ab6cb20SWENTAO YANG 	    KSTAT_DATA_ULONG);
18246ab6cb20SWENTAO YANG 	kstat_named_init(&hiokp->brdcstxmt,		"brdcstxmt",
18256ab6cb20SWENTAO YANG 	    KSTAT_DATA_ULONG);
18266ab6cb20SWENTAO YANG 	kstat_named_init(&hiokp->norcvbuf,		"norcvbuf",
18276ab6cb20SWENTAO YANG 	    KSTAT_DATA_ULONG);
18286ab6cb20SWENTAO YANG 	kstat_named_init(&hiokp->noxmtbuf,		"noxmtbuf",
18296ab6cb20SWENTAO YANG 	    KSTAT_DATA_ULONG);
18306ab6cb20SWENTAO YANG 
18316ab6cb20SWENTAO YANG 	ksp->ks_update = vnet_hio_update_kstats;
18326ab6cb20SWENTAO YANG 	ksp->ks_private = (void *)vresp;
18336ab6cb20SWENTAO YANG 	kstat_install(ksp);
18346ab6cb20SWENTAO YANG 	return (ksp);
18356ab6cb20SWENTAO YANG }
18366ab6cb20SWENTAO YANG 
18376ab6cb20SWENTAO YANG /*
18386ab6cb20SWENTAO YANG  * Destroy kstats.
18396ab6cb20SWENTAO YANG  */
18406ab6cb20SWENTAO YANG static void
18416ab6cb20SWENTAO YANG vnet_hio_destroy_kstats(kstat_t *ksp)
18426ab6cb20SWENTAO YANG {
18436ab6cb20SWENTAO YANG 	if (ksp != NULL)
18446ab6cb20SWENTAO YANG 		kstat_delete(ksp);
18456ab6cb20SWENTAO YANG }
18466ab6cb20SWENTAO YANG 
18476ab6cb20SWENTAO YANG /*
18486ab6cb20SWENTAO YANG  * Update the kstats.
18496ab6cb20SWENTAO YANG  */
18506ab6cb20SWENTAO YANG static int
18516ab6cb20SWENTAO YANG vnet_hio_update_kstats(kstat_t *ksp, int rw)
18526ab6cb20SWENTAO YANG {
18536ab6cb20SWENTAO YANG 	vnet_t *vnetp;
18546ab6cb20SWENTAO YANG 	vnet_res_t *vresp;
18556ab6cb20SWENTAO YANG 	vnet_hio_stats_t statsp;
18566ab6cb20SWENTAO YANG 	vnet_hio_kstats_t *hiokp;
18576ab6cb20SWENTAO YANG 
18586ab6cb20SWENTAO YANG 	vresp = (vnet_res_t *)ksp->ks_private;
18596ab6cb20SWENTAO YANG 	vnetp = vresp->vnetp;
18606ab6cb20SWENTAO YANG 
18616ab6cb20SWENTAO YANG 	bzero(&statsp, sizeof (vnet_hio_stats_t));
18626ab6cb20SWENTAO YANG 
18636ab6cb20SWENTAO YANG 	READ_ENTER(&vnetp->vsw_fp_rw);
18646ab6cb20SWENTAO YANG 	if (vnetp->hio_fp == NULL) {
18656ab6cb20SWENTAO YANG 		/* not using hio resources, just return */
18666ab6cb20SWENTAO YANG 		RW_EXIT(&vnetp->vsw_fp_rw);
18676ab6cb20SWENTAO YANG 		return (0);
18686ab6cb20SWENTAO YANG 	}
18696ab6cb20SWENTAO YANG 	VNET_FDBE_REFHOLD(vnetp->hio_fp);
18706ab6cb20SWENTAO YANG 	RW_EXIT(&vnetp->vsw_fp_rw);
18716ab6cb20SWENTAO YANG 	vnet_hio_get_stats(vnetp->hio_fp, &statsp);
18726ab6cb20SWENTAO YANG 	VNET_FDBE_REFRELE(vnetp->hio_fp);
18736ab6cb20SWENTAO YANG 
18746ab6cb20SWENTAO YANG 	hiokp = (vnet_hio_kstats_t *)ksp->ks_data;
18756ab6cb20SWENTAO YANG 
18766ab6cb20SWENTAO YANG 	if (rw == KSTAT_READ) {
18776ab6cb20SWENTAO YANG 		/* Link Input/Output stats */
18786ab6cb20SWENTAO YANG 		hiokp->ipackets.value.ul	= (uint32_t)statsp.ipackets;
18796ab6cb20SWENTAO YANG 		hiokp->ipackets64.value.ull	= statsp.ipackets;
18806ab6cb20SWENTAO YANG 		hiokp->ierrors.value.ul		= statsp.ierrors;
18816ab6cb20SWENTAO YANG 		hiokp->opackets.value.ul	= (uint32_t)statsp.opackets;
18826ab6cb20SWENTAO YANG 		hiokp->opackets64.value.ull	= statsp.opackets;
18836ab6cb20SWENTAO YANG 		hiokp->oerrors.value.ul		= statsp.oerrors;
18846ab6cb20SWENTAO YANG 
18856ab6cb20SWENTAO YANG 		/* MIB II kstat variables */
18866ab6cb20SWENTAO YANG 		hiokp->rbytes.value.ul		= (uint32_t)statsp.rbytes;
18876ab6cb20SWENTAO YANG 		hiokp->rbytes64.value.ull	= statsp.rbytes;
18886ab6cb20SWENTAO YANG 		hiokp->obytes.value.ul		= (uint32_t)statsp.obytes;
18896ab6cb20SWENTAO YANG 		hiokp->obytes64.value.ull	= statsp.obytes;
18906ab6cb20SWENTAO YANG 		hiokp->multircv.value.ul	= statsp.multircv;
18916ab6cb20SWENTAO YANG 		hiokp->multixmt.value.ul	= statsp.multixmt;
18926ab6cb20SWENTAO YANG 		hiokp->brdcstrcv.value.ul	= statsp.brdcstrcv;
18936ab6cb20SWENTAO YANG 		hiokp->brdcstxmt.value.ul	= statsp.brdcstxmt;
18946ab6cb20SWENTAO YANG 		hiokp->norcvbuf.value.ul	= statsp.norcvbuf;
18956ab6cb20SWENTAO YANG 		hiokp->noxmtbuf.value.ul	= statsp.noxmtbuf;
18966ab6cb20SWENTAO YANG 	} else {
18976ab6cb20SWENTAO YANG 		return (EACCES);
18986ab6cb20SWENTAO YANG 	}
18996ab6cb20SWENTAO YANG 
19006ab6cb20SWENTAO YANG 	return (0);
19016ab6cb20SWENTAO YANG }
19026ab6cb20SWENTAO YANG 
19036ab6cb20SWENTAO YANG static void
19046ab6cb20SWENTAO YANG vnet_hio_get_stats(vnet_res_t *vresp, vnet_hio_stats_t *statsp)
19056ab6cb20SWENTAO YANG {
19066ab6cb20SWENTAO YANG 	mac_register_t		*macp;
19076ab6cb20SWENTAO YANG 	mac_callbacks_t		*cbp;
19086ab6cb20SWENTAO YANG 	uint64_t		val;
19096ab6cb20SWENTAO YANG 	int			stat;
19106ab6cb20SWENTAO YANG 
19116ab6cb20SWENTAO YANG 	/*
19126ab6cb20SWENTAO YANG 	 * get the specified statistics from the underlying nxge.
19136ab6cb20SWENTAO YANG 	 */
19146ab6cb20SWENTAO YANG 	macp = &vresp->macreg;
19156ab6cb20SWENTAO YANG 	cbp = macp->m_callbacks;
19166ab6cb20SWENTAO YANG 	for (stat = MAC_STAT_MIN; stat < MAC_STAT_OVERFLOWS; stat++) {
19176ab6cb20SWENTAO YANG 		if (cbp->mc_getstat(macp->m_driver, stat, &val) == 0) {
19186ab6cb20SWENTAO YANG 			switch (stat) {
19196ab6cb20SWENTAO YANG 			case MAC_STAT_IPACKETS:
19206ab6cb20SWENTAO YANG 				statsp->ipackets = val;
19216ab6cb20SWENTAO YANG 				break;
19226ab6cb20SWENTAO YANG 
19236ab6cb20SWENTAO YANG 			case MAC_STAT_IERRORS:
19246ab6cb20SWENTAO YANG 				statsp->ierrors = val;
19256ab6cb20SWENTAO YANG 				break;
19266ab6cb20SWENTAO YANG 
19276ab6cb20SWENTAO YANG 			case MAC_STAT_OPACKETS:
19286ab6cb20SWENTAO YANG 				statsp->opackets = val;
19296ab6cb20SWENTAO YANG 				break;
19306ab6cb20SWENTAO YANG 
19316ab6cb20SWENTAO YANG 			case MAC_STAT_OERRORS:
19326ab6cb20SWENTAO YANG 				statsp->oerrors = val;
19336ab6cb20SWENTAO YANG 				break;
19346ab6cb20SWENTAO YANG 
19356ab6cb20SWENTAO YANG 			case MAC_STAT_RBYTES:
19366ab6cb20SWENTAO YANG 				statsp->rbytes = val;
19376ab6cb20SWENTAO YANG 				break;
19386ab6cb20SWENTAO YANG 
19396ab6cb20SWENTAO YANG 			case MAC_STAT_OBYTES:
19406ab6cb20SWENTAO YANG 				statsp->obytes = val;
19416ab6cb20SWENTAO YANG 				break;
19426ab6cb20SWENTAO YANG 
19436ab6cb20SWENTAO YANG 			case MAC_STAT_MULTIRCV:
19446ab6cb20SWENTAO YANG 				statsp->multircv = val;
19456ab6cb20SWENTAO YANG 				break;
19466ab6cb20SWENTAO YANG 
19476ab6cb20SWENTAO YANG 			case MAC_STAT_MULTIXMT:
19486ab6cb20SWENTAO YANG 				statsp->multixmt = val;
19496ab6cb20SWENTAO YANG 				break;
19506ab6cb20SWENTAO YANG 
19516ab6cb20SWENTAO YANG 			case MAC_STAT_BRDCSTRCV:
19526ab6cb20SWENTAO YANG 				statsp->brdcstrcv = val;
19536ab6cb20SWENTAO YANG 				break;
19546ab6cb20SWENTAO YANG 
19556ab6cb20SWENTAO YANG 			case MAC_STAT_BRDCSTXMT:
19566ab6cb20SWENTAO YANG 				statsp->brdcstxmt = val;
19576ab6cb20SWENTAO YANG 				break;
19586ab6cb20SWENTAO YANG 
19596ab6cb20SWENTAO YANG 			case MAC_STAT_NOXMTBUF:
19606ab6cb20SWENTAO YANG 				statsp->noxmtbuf = val;
19616ab6cb20SWENTAO YANG 				break;
19626ab6cb20SWENTAO YANG 
19636ab6cb20SWENTAO YANG 			case MAC_STAT_NORCVBUF:
19646ab6cb20SWENTAO YANG 				statsp->norcvbuf = val;
19656ab6cb20SWENTAO YANG 				break;
19666ab6cb20SWENTAO YANG 
19676ab6cb20SWENTAO YANG 			default:
19686ab6cb20SWENTAO YANG 				/*
19696ab6cb20SWENTAO YANG 				 * parameters not interested.
19706ab6cb20SWENTAO YANG 				 */
19716ab6cb20SWENTAO YANG 				break;
19726ab6cb20SWENTAO YANG 			}
19736ab6cb20SWENTAO YANG 		}
19746ab6cb20SWENTAO YANG 	}
19756ab6cb20SWENTAO YANG }
19761107ea93SSriharsha Basavapatna 
1977*63f531d1SSriharsha Basavapatna static boolean_t
1978*63f531d1SSriharsha Basavapatna vnet_m_capab(void *arg, mac_capab_t cap, void *cap_data)
1979*63f531d1SSriharsha Basavapatna {
1980*63f531d1SSriharsha Basavapatna 	vnet_t	*vnetp = (vnet_t *)arg;
1981*63f531d1SSriharsha Basavapatna 
1982*63f531d1SSriharsha Basavapatna 	if (vnetp == NULL) {
1983*63f531d1SSriharsha Basavapatna 		return (0);
1984*63f531d1SSriharsha Basavapatna 	}
1985*63f531d1SSriharsha Basavapatna 
1986*63f531d1SSriharsha Basavapatna 	switch (cap) {
1987*63f531d1SSriharsha Basavapatna 
1988*63f531d1SSriharsha Basavapatna 	case MAC_CAPAB_RINGS: {
1989*63f531d1SSriharsha Basavapatna 
1990*63f531d1SSriharsha Basavapatna 		mac_capab_rings_t *cap_rings = cap_data;
1991*63f531d1SSriharsha Basavapatna 		/*
1992*63f531d1SSriharsha Basavapatna 		 * Rings Capability Notes:
1993*63f531d1SSriharsha Basavapatna 		 * We advertise rings to make use of the rings framework in
1994*63f531d1SSriharsha Basavapatna 		 * gldv3 mac layer, to improve the performance. This is
1995*63f531d1SSriharsha Basavapatna 		 * specifically needed when a Hybrid resource (with multiple
1996*63f531d1SSriharsha Basavapatna 		 * tx/rx hardware rings) is assigned to a vnet device. We also
1997*63f531d1SSriharsha Basavapatna 		 * leverage this for the normal case when no Hybrid resource is
1998*63f531d1SSriharsha Basavapatna 		 * assigned.
1999*63f531d1SSriharsha Basavapatna 		 *
2000*63f531d1SSriharsha Basavapatna 		 * Ring Allocation:
2001*63f531d1SSriharsha Basavapatna 		 * - TX path:
2002*63f531d1SSriharsha Basavapatna 		 * We expose a pseudo ring group with 2 pseudo tx rings (as
2003*63f531d1SSriharsha Basavapatna 		 * currently HybridIO exports only 2 rings) In the normal case,
2004*63f531d1SSriharsha Basavapatna 		 * transmit traffic that comes down to the driver through the
2005*63f531d1SSriharsha Basavapatna 		 * mri_tx (vnet_tx_ring_send()) entry point goes through the
2006*63f531d1SSriharsha Basavapatna 		 * distributed switching algorithm in vnet and gets transmitted
2007*63f531d1SSriharsha Basavapatna 		 * over a port/LDC in the vgen layer to either the vswitch or a
2008*63f531d1SSriharsha Basavapatna 		 * peer vnet. If and when a Hybrid resource is assigned to the
2009*63f531d1SSriharsha Basavapatna 		 * vnet, we obtain the tx ring information of the Hybrid device
2010*63f531d1SSriharsha Basavapatna 		 * (nxge) and map the pseudo rings 1:1 to the 2 hw tx rings.
2011*63f531d1SSriharsha Basavapatna 		 * Traffic being sent over the Hybrid resource by the mac layer
2012*63f531d1SSriharsha Basavapatna 		 * gets spread across both hw rings, as they are mapped to the
2013*63f531d1SSriharsha Basavapatna 		 * 2 pseudo tx rings in vnet.
2014*63f531d1SSriharsha Basavapatna 		 *
2015*63f531d1SSriharsha Basavapatna 		 * - RX path:
2016*63f531d1SSriharsha Basavapatna 		 * We expose a pseudo ring group with 3 pseudo rx rings (static
2017*63f531d1SSriharsha Basavapatna 		 * rings) initially. The first (default) pseudo rx ring is
2018*63f531d1SSriharsha Basavapatna 		 * reserved for the resource that connects to the vswitch
2019*63f531d1SSriharsha Basavapatna 		 * service. The next 2 rings are reserved for a Hybrid resource
2020*63f531d1SSriharsha Basavapatna 		 * that may be assigned to the vnet device. If and when a
2021*63f531d1SSriharsha Basavapatna 		 * Hybrid resource is assigned to the vnet, we obtain the rx
2022*63f531d1SSriharsha Basavapatna 		 * ring information of the Hybrid device (nxge) and map these
2023*63f531d1SSriharsha Basavapatna 		 * pseudo rings 1:1 to the 2 hw rx rings. For each additional
2024*63f531d1SSriharsha Basavapatna 		 * resource that connects to a peer vnet, we dynamically
2025*63f531d1SSriharsha Basavapatna 		 * allocate a pseudo rx ring and map it to that resource, when
2026*63f531d1SSriharsha Basavapatna 		 * the resource gets added; and the pseudo rx ring is
2027*63f531d1SSriharsha Basavapatna 		 * dynamically registered with the upper mac layer. We do the
2028*63f531d1SSriharsha Basavapatna 		 * reverse and unregister the ring with the mac layer when
2029*63f531d1SSriharsha Basavapatna 		 * the resource gets removed.
2030*63f531d1SSriharsha Basavapatna 		 *
2031*63f531d1SSriharsha Basavapatna 		 * Synchronization notes:
2032*63f531d1SSriharsha Basavapatna 		 * We don't need any lock to protect members of ring structure,
2033*63f531d1SSriharsha Basavapatna 		 * specifically ringp->hw_rh, in either the TX or the RX ring,
2034*63f531d1SSriharsha Basavapatna 		 * as explained below.
2035*63f531d1SSriharsha Basavapatna 		 * - TX ring:
2036*63f531d1SSriharsha Basavapatna 		 * ring->hw_rh is initialized only when a Hybrid resource is
2037*63f531d1SSriharsha Basavapatna 		 * associated; and gets referenced only in vnet_hio_tx(). The
2038*63f531d1SSriharsha Basavapatna 		 * Hybrid resource itself is available in fdb only after tx
2039*63f531d1SSriharsha Basavapatna 		 * hwrings are found and mapped; i.e, in vio_net_resource_reg()
2040*63f531d1SSriharsha Basavapatna 		 * we call vnet_bind_rings() first and then call
2041*63f531d1SSriharsha Basavapatna 		 * vnet_start_resources() which adds an entry to fdb. For
2042*63f531d1SSriharsha Basavapatna 		 * traffic going over LDC resources, we don't reference
2043*63f531d1SSriharsha Basavapatna 		 * ring->hw_rh at all.
2044*63f531d1SSriharsha Basavapatna 		 * - RX ring:
2045*63f531d1SSriharsha Basavapatna 		 * For rings mapped to Hybrid resource ring->hw_rh is
2046*63f531d1SSriharsha Basavapatna 		 * initialized and only then do we add the rx callback for
2047*63f531d1SSriharsha Basavapatna 		 * the underlying Hybrid resource; we disable callbacks before
2048*63f531d1SSriharsha Basavapatna 		 * we unmap ring->hw_rh. For rings mapped to LDC resources, we
2049*63f531d1SSriharsha Basavapatna 		 * stop the rx callbacks (in vgen) before we remove ring->hw_rh
2050*63f531d1SSriharsha Basavapatna 		 * (vio_net_resource_unreg()).
2051*63f531d1SSriharsha Basavapatna 		 */
2052*63f531d1SSriharsha Basavapatna 
2053*63f531d1SSriharsha Basavapatna 		if (cap_rings->mr_type == MAC_RING_TYPE_RX) {
2054*63f531d1SSriharsha Basavapatna 			cap_rings->mr_group_type = MAC_GROUP_TYPE_STATIC;
2055*63f531d1SSriharsha Basavapatna 
2056*63f531d1SSriharsha Basavapatna 			/*
2057*63f531d1SSriharsha Basavapatna 			 * The ring_cnt for rx grp is initialized in
2058*63f531d1SSriharsha Basavapatna 			 * vnet_ring_grp_init(). Later, the ring_cnt gets
2059*63f531d1SSriharsha Basavapatna 			 * updated dynamically whenever LDC resources are added
2060*63f531d1SSriharsha Basavapatna 			 * or removed.
2061*63f531d1SSriharsha Basavapatna 			 */
2062*63f531d1SSriharsha Basavapatna 			cap_rings->mr_rnum = vnetp->rx_grp[0].ring_cnt;
2063*63f531d1SSriharsha Basavapatna 			cap_rings->mr_rget = vnet_get_ring;
2064*63f531d1SSriharsha Basavapatna 
2065*63f531d1SSriharsha Basavapatna 			cap_rings->mr_gnum = VNET_NUM_PSEUDO_GROUPS;
2066*63f531d1SSriharsha Basavapatna 			cap_rings->mr_gget = vnet_get_group;
2067*63f531d1SSriharsha Basavapatna 			cap_rings->mr_gaddring = NULL;
2068*63f531d1SSriharsha Basavapatna 			cap_rings->mr_gremring = NULL;
2069*63f531d1SSriharsha Basavapatna 		} else {
2070*63f531d1SSriharsha Basavapatna 			cap_rings->mr_group_type = MAC_GROUP_TYPE_STATIC;
2071*63f531d1SSriharsha Basavapatna 
2072*63f531d1SSriharsha Basavapatna 			/*
2073*63f531d1SSriharsha Basavapatna 			 * The ring_cnt for tx grp is initialized in
2074*63f531d1SSriharsha Basavapatna 			 * vnet_ring_grp_init() and remains constant, as we
2075*63f531d1SSriharsha Basavapatna 			 * do not support dymanic tx rings for now.
2076*63f531d1SSriharsha Basavapatna 			 */
2077*63f531d1SSriharsha Basavapatna 			cap_rings->mr_rnum = vnetp->tx_grp[0].ring_cnt;
2078*63f531d1SSriharsha Basavapatna 			cap_rings->mr_rget = vnet_get_ring;
2079*63f531d1SSriharsha Basavapatna 
2080*63f531d1SSriharsha Basavapatna 			/*
2081*63f531d1SSriharsha Basavapatna 			 * Transmit rings are not grouped; i.e, the number of
2082*63f531d1SSriharsha Basavapatna 			 * transmit ring groups advertised should be set to 0.
2083*63f531d1SSriharsha Basavapatna 			 */
2084*63f531d1SSriharsha Basavapatna 			cap_rings->mr_gnum = 0;
2085*63f531d1SSriharsha Basavapatna 
2086*63f531d1SSriharsha Basavapatna 			cap_rings->mr_gget = vnet_get_group;
2087*63f531d1SSriharsha Basavapatna 			cap_rings->mr_gaddring = NULL;
2088*63f531d1SSriharsha Basavapatna 			cap_rings->mr_gremring = NULL;
2089*63f531d1SSriharsha Basavapatna 		}
2090*63f531d1SSriharsha Basavapatna 		return (B_TRUE);
2091*63f531d1SSriharsha Basavapatna 
2092*63f531d1SSriharsha Basavapatna 	}
2093*63f531d1SSriharsha Basavapatna 
2094*63f531d1SSriharsha Basavapatna 	default:
2095*63f531d1SSriharsha Basavapatna 		break;
2096*63f531d1SSriharsha Basavapatna 
2097*63f531d1SSriharsha Basavapatna 	}
2098*63f531d1SSriharsha Basavapatna 
2099*63f531d1SSriharsha Basavapatna 	return (B_FALSE);
2100*63f531d1SSriharsha Basavapatna }
2101*63f531d1SSriharsha Basavapatna 
2102*63f531d1SSriharsha Basavapatna /*
2103*63f531d1SSriharsha Basavapatna  * Callback funtion for MAC layer to get ring information.
2104*63f531d1SSriharsha Basavapatna  */
2105*63f531d1SSriharsha Basavapatna static void
2106*63f531d1SSriharsha Basavapatna vnet_get_ring(void *arg, mac_ring_type_t rtype, const int g_index,
2107*63f531d1SSriharsha Basavapatna     const int r_index, mac_ring_info_t *infop, mac_ring_handle_t r_handle)
2108*63f531d1SSriharsha Basavapatna {
2109*63f531d1SSriharsha Basavapatna 	vnet_t	*vnetp = arg;
2110*63f531d1SSriharsha Basavapatna 
2111*63f531d1SSriharsha Basavapatna 	switch (rtype) {
2112*63f531d1SSriharsha Basavapatna 
2113*63f531d1SSriharsha Basavapatna 	case MAC_RING_TYPE_RX: {
2114*63f531d1SSriharsha Basavapatna 
2115*63f531d1SSriharsha Basavapatna 		vnet_pseudo_rx_group_t	*rx_grp;
2116*63f531d1SSriharsha Basavapatna 		vnet_pseudo_rx_ring_t	*rx_ringp;
2117*63f531d1SSriharsha Basavapatna 		mac_intr_t		*mintr;
2118*63f531d1SSriharsha Basavapatna 
2119*63f531d1SSriharsha Basavapatna 		/* We advertised only one RX group */
2120*63f531d1SSriharsha Basavapatna 		ASSERT(g_index == 0);
2121*63f531d1SSriharsha Basavapatna 		rx_grp = &vnetp->rx_grp[g_index];
2122*63f531d1SSriharsha Basavapatna 
2123*63f531d1SSriharsha Basavapatna 		/* Check the current # of rings in the rx group */
2124*63f531d1SSriharsha Basavapatna 		ASSERT((r_index >= 0) && (r_index < rx_grp->max_ring_cnt));
2125*63f531d1SSriharsha Basavapatna 
2126*63f531d1SSriharsha Basavapatna 		/* Get the ring based on the index */
2127*63f531d1SSriharsha Basavapatna 		rx_ringp = &rx_grp->rings[r_index];
2128*63f531d1SSriharsha Basavapatna 
2129*63f531d1SSriharsha Basavapatna 		rx_ringp->handle = r_handle;
2130*63f531d1SSriharsha Basavapatna 		/*
2131*63f531d1SSriharsha Basavapatna 		 * Note: we don't need to save the incoming r_index in rx_ring,
2132*63f531d1SSriharsha Basavapatna 		 * as vnet_ring_grp_init() would have initialized the index for
2133*63f531d1SSriharsha Basavapatna 		 * each ring in the array.
2134*63f531d1SSriharsha Basavapatna 		 */
2135*63f531d1SSriharsha Basavapatna 		rx_ringp->grp = rx_grp;
2136*63f531d1SSriharsha Basavapatna 		rx_ringp->vnetp = vnetp;
2137*63f531d1SSriharsha Basavapatna 
2138*63f531d1SSriharsha Basavapatna 		mintr = &infop->mri_intr;
2139*63f531d1SSriharsha Basavapatna 		mintr->mi_handle = (mac_intr_handle_t)rx_ringp;
2140*63f531d1SSriharsha Basavapatna 		mintr->mi_enable = (mac_intr_enable_t)vnet_ring_enable_intr;
2141*63f531d1SSriharsha Basavapatna 		mintr->mi_disable = (mac_intr_disable_t)vnet_ring_disable_intr;
2142*63f531d1SSriharsha Basavapatna 
2143*63f531d1SSriharsha Basavapatna 		infop->mri_driver = (mac_ring_driver_t)rx_ringp;
2144*63f531d1SSriharsha Basavapatna 		infop->mri_start = vnet_rx_ring_start;
2145*63f531d1SSriharsha Basavapatna 		infop->mri_stop = vnet_rx_ring_stop;
2146*63f531d1SSriharsha Basavapatna 
2147*63f531d1SSriharsha Basavapatna 		/* Set the poll function, as this is an rx ring */
2148*63f531d1SSriharsha Basavapatna 		infop->mri_poll = vnet_rx_poll;
2149*63f531d1SSriharsha Basavapatna 
2150*63f531d1SSriharsha Basavapatna 		break;
2151*63f531d1SSriharsha Basavapatna 	}
2152*63f531d1SSriharsha Basavapatna 
2153*63f531d1SSriharsha Basavapatna 	case MAC_RING_TYPE_TX: {
2154*63f531d1SSriharsha Basavapatna 		vnet_pseudo_tx_group_t	*tx_grp;
2155*63f531d1SSriharsha Basavapatna 		vnet_pseudo_tx_ring_t	*tx_ringp;
2156*63f531d1SSriharsha Basavapatna 
2157*63f531d1SSriharsha Basavapatna 		/*
2158*63f531d1SSriharsha Basavapatna 		 * No need to check grp index; mac layer passes -1 for it.
2159*63f531d1SSriharsha Basavapatna 		 */
2160*63f531d1SSriharsha Basavapatna 		tx_grp = &vnetp->tx_grp[0];
2161*63f531d1SSriharsha Basavapatna 
2162*63f531d1SSriharsha Basavapatna 		/* Check the # of rings in the tx group */
2163*63f531d1SSriharsha Basavapatna 		ASSERT((r_index >= 0) && (r_index < tx_grp->ring_cnt));
2164*63f531d1SSriharsha Basavapatna 
2165*63f531d1SSriharsha Basavapatna 		/* Get the ring based on the index */
2166*63f531d1SSriharsha Basavapatna 		tx_ringp = &tx_grp->rings[r_index];
2167*63f531d1SSriharsha Basavapatna 
2168*63f531d1SSriharsha Basavapatna 		tx_ringp->handle = r_handle;
2169*63f531d1SSriharsha Basavapatna 		tx_ringp->index = r_index;
2170*63f531d1SSriharsha Basavapatna 		tx_ringp->grp = tx_grp;
2171*63f531d1SSriharsha Basavapatna 		tx_ringp->vnetp = vnetp;
2172*63f531d1SSriharsha Basavapatna 
2173*63f531d1SSriharsha Basavapatna 		infop->mri_driver = (mac_ring_driver_t)tx_ringp;
2174*63f531d1SSriharsha Basavapatna 		infop->mri_start = vnet_tx_ring_start;
2175*63f531d1SSriharsha Basavapatna 		infop->mri_stop = vnet_tx_ring_stop;
2176*63f531d1SSriharsha Basavapatna 
2177*63f531d1SSriharsha Basavapatna 		/* Set the transmit function, as this is a tx ring */
2178*63f531d1SSriharsha Basavapatna 		infop->mri_tx = vnet_tx_ring_send;
2179*63f531d1SSriharsha Basavapatna 
2180*63f531d1SSriharsha Basavapatna 		break;
2181*63f531d1SSriharsha Basavapatna 	}
2182*63f531d1SSriharsha Basavapatna 
2183*63f531d1SSriharsha Basavapatna 	default:
2184*63f531d1SSriharsha Basavapatna 		break;
2185*63f531d1SSriharsha Basavapatna 	}
2186*63f531d1SSriharsha Basavapatna }
2187*63f531d1SSriharsha Basavapatna 
2188*63f531d1SSriharsha Basavapatna /*
2189*63f531d1SSriharsha Basavapatna  * Callback funtion for MAC layer to get group information.
2190*63f531d1SSriharsha Basavapatna  */
2191*63f531d1SSriharsha Basavapatna static void
2192*63f531d1SSriharsha Basavapatna vnet_get_group(void *arg, mac_ring_type_t type, const int index,
2193*63f531d1SSriharsha Basavapatna 	mac_group_info_t *infop, mac_group_handle_t handle)
2194*63f531d1SSriharsha Basavapatna {
2195*63f531d1SSriharsha Basavapatna 	vnet_t	*vnetp = (vnet_t *)arg;
2196*63f531d1SSriharsha Basavapatna 
2197*63f531d1SSriharsha Basavapatna 	switch (type) {
2198*63f531d1SSriharsha Basavapatna 
2199*63f531d1SSriharsha Basavapatna 	case MAC_RING_TYPE_RX:
2200*63f531d1SSriharsha Basavapatna 	{
2201*63f531d1SSriharsha Basavapatna 		vnet_pseudo_rx_group_t	*rx_grp;
2202*63f531d1SSriharsha Basavapatna 
2203*63f531d1SSriharsha Basavapatna 		/* We advertised only one RX group */
2204*63f531d1SSriharsha Basavapatna 		ASSERT(index == 0);
2205*63f531d1SSriharsha Basavapatna 
2206*63f531d1SSriharsha Basavapatna 		rx_grp = &vnetp->rx_grp[index];
2207*63f531d1SSriharsha Basavapatna 		rx_grp->handle = handle;
2208*63f531d1SSriharsha Basavapatna 		rx_grp->index = index;
2209*63f531d1SSriharsha Basavapatna 		rx_grp->vnetp = vnetp;
2210*63f531d1SSriharsha Basavapatna 
2211*63f531d1SSriharsha Basavapatna 		infop->mgi_driver = (mac_group_driver_t)rx_grp;
2212*63f531d1SSriharsha Basavapatna 		infop->mgi_start = NULL;
2213*63f531d1SSriharsha Basavapatna 		infop->mgi_stop = NULL;
2214*63f531d1SSriharsha Basavapatna 		infop->mgi_addmac = vnet_addmac;
2215*63f531d1SSriharsha Basavapatna 		infop->mgi_remmac = vnet_remmac;
2216*63f531d1SSriharsha Basavapatna 		infop->mgi_count = rx_grp->ring_cnt;
2217*63f531d1SSriharsha Basavapatna 
2218*63f531d1SSriharsha Basavapatna 		break;
2219*63f531d1SSriharsha Basavapatna 	}
2220*63f531d1SSriharsha Basavapatna 
2221*63f531d1SSriharsha Basavapatna 	case MAC_RING_TYPE_TX:
2222*63f531d1SSriharsha Basavapatna 	{
2223*63f531d1SSriharsha Basavapatna 		vnet_pseudo_tx_group_t	*tx_grp;
2224*63f531d1SSriharsha Basavapatna 
2225*63f531d1SSriharsha Basavapatna 		/* We advertised only one TX group */
2226*63f531d1SSriharsha Basavapatna 		ASSERT(index == 0);
2227*63f531d1SSriharsha Basavapatna 
2228*63f531d1SSriharsha Basavapatna 		tx_grp = &vnetp->tx_grp[index];
2229*63f531d1SSriharsha Basavapatna 		tx_grp->handle = handle;
2230*63f531d1SSriharsha Basavapatna 		tx_grp->index = index;
2231*63f531d1SSriharsha Basavapatna 		tx_grp->vnetp = vnetp;
2232*63f531d1SSriharsha Basavapatna 
2233*63f531d1SSriharsha Basavapatna 		infop->mgi_driver = (mac_group_driver_t)tx_grp;
2234*63f531d1SSriharsha Basavapatna 		infop->mgi_start = NULL;
2235*63f531d1SSriharsha Basavapatna 		infop->mgi_stop = NULL;
2236*63f531d1SSriharsha Basavapatna 		infop->mgi_addmac = NULL;
2237*63f531d1SSriharsha Basavapatna 		infop->mgi_remmac = NULL;
2238*63f531d1SSriharsha Basavapatna 		infop->mgi_count = VNET_NUM_PSEUDO_TXRINGS;
2239*63f531d1SSriharsha Basavapatna 
2240*63f531d1SSriharsha Basavapatna 		break;
2241*63f531d1SSriharsha Basavapatna 	}
2242*63f531d1SSriharsha Basavapatna 
2243*63f531d1SSriharsha Basavapatna 	default:
2244*63f531d1SSriharsha Basavapatna 		break;
2245*63f531d1SSriharsha Basavapatna 
2246*63f531d1SSriharsha Basavapatna 	}
2247*63f531d1SSriharsha Basavapatna }
2248*63f531d1SSriharsha Basavapatna 
2249*63f531d1SSriharsha Basavapatna static int
2250*63f531d1SSriharsha Basavapatna vnet_rx_ring_start(mac_ring_driver_t arg, uint64_t mr_gen_num)
2251*63f531d1SSriharsha Basavapatna {
2252*63f531d1SSriharsha Basavapatna 	vnet_pseudo_rx_ring_t	*rx_ringp = (vnet_pseudo_rx_ring_t *)arg;
2253*63f531d1SSriharsha Basavapatna 	int			err;
2254*63f531d1SSriharsha Basavapatna 
2255*63f531d1SSriharsha Basavapatna 	/*
2256*63f531d1SSriharsha Basavapatna 	 * If this ring is mapped to a LDC resource, simply mark the state to
2257*63f531d1SSriharsha Basavapatna 	 * indicate the ring is started and return.
2258*63f531d1SSriharsha Basavapatna 	 */
2259*63f531d1SSriharsha Basavapatna 	if ((rx_ringp->state &
2260*63f531d1SSriharsha Basavapatna 	    (VNET_RXRING_LDC_SERVICE|VNET_RXRING_LDC_GUEST)) != 0) {
2261*63f531d1SSriharsha Basavapatna 		rx_ringp->gen_num = mr_gen_num;
2262*63f531d1SSriharsha Basavapatna 		rx_ringp->state |= VNET_RXRING_STARTED;
2263*63f531d1SSriharsha Basavapatna 		return (0);
2264*63f531d1SSriharsha Basavapatna 	}
2265*63f531d1SSriharsha Basavapatna 
2266*63f531d1SSriharsha Basavapatna 	ASSERT((rx_ringp->state & VNET_RXRING_HYBRID) != 0);
2267*63f531d1SSriharsha Basavapatna 
2268*63f531d1SSriharsha Basavapatna 	/*
2269*63f531d1SSriharsha Basavapatna 	 * This must be a ring reserved for a hwring. If the hwring is not
2270*63f531d1SSriharsha Basavapatna 	 * bound yet, simply mark the state to indicate the ring is started and
2271*63f531d1SSriharsha Basavapatna 	 * return. If and when a hybrid resource is activated for this vnet
2272*63f531d1SSriharsha Basavapatna 	 * device, we will bind the hwring and start it then. If a hwring is
2273*63f531d1SSriharsha Basavapatna 	 * already bound, start it now.
2274*63f531d1SSriharsha Basavapatna 	 */
2275*63f531d1SSriharsha Basavapatna 	if (rx_ringp->hw_rh == NULL) {
2276*63f531d1SSriharsha Basavapatna 		rx_ringp->gen_num = mr_gen_num;
2277*63f531d1SSriharsha Basavapatna 		rx_ringp->state |= VNET_RXRING_STARTED;
2278*63f531d1SSriharsha Basavapatna 		return (0);
2279*63f531d1SSriharsha Basavapatna 	}
2280*63f531d1SSriharsha Basavapatna 
2281*63f531d1SSriharsha Basavapatna 	err = mac_hwring_start(rx_ringp->hw_rh);
2282*63f531d1SSriharsha Basavapatna 	if (err == 0) {
2283*63f531d1SSriharsha Basavapatna 		rx_ringp->gen_num = mr_gen_num;
2284*63f531d1SSriharsha Basavapatna 		rx_ringp->state |= VNET_RXRING_STARTED;
2285*63f531d1SSriharsha Basavapatna 	} else {
2286*63f531d1SSriharsha Basavapatna 		err = ENXIO;
2287*63f531d1SSriharsha Basavapatna 	}
2288*63f531d1SSriharsha Basavapatna 
2289*63f531d1SSriharsha Basavapatna 	return (err);
2290*63f531d1SSriharsha Basavapatna }
2291*63f531d1SSriharsha Basavapatna 
2292*63f531d1SSriharsha Basavapatna static void
2293*63f531d1SSriharsha Basavapatna vnet_rx_ring_stop(mac_ring_driver_t arg)
2294*63f531d1SSriharsha Basavapatna {
2295*63f531d1SSriharsha Basavapatna 	vnet_pseudo_rx_ring_t	*rx_ringp = (vnet_pseudo_rx_ring_t *)arg;
2296*63f531d1SSriharsha Basavapatna 
2297*63f531d1SSriharsha Basavapatna 	/*
2298*63f531d1SSriharsha Basavapatna 	 * If this ring is mapped to a LDC resource, simply mark the state to
2299*63f531d1SSriharsha Basavapatna 	 * indicate the ring is now stopped and return.
2300*63f531d1SSriharsha Basavapatna 	 */
2301*63f531d1SSriharsha Basavapatna 	if ((rx_ringp->state &
2302*63f531d1SSriharsha Basavapatna 	    (VNET_RXRING_LDC_SERVICE|VNET_RXRING_LDC_GUEST)) != 0) {
2303*63f531d1SSriharsha Basavapatna 		rx_ringp->state &= ~VNET_RXRING_STARTED;
2304*63f531d1SSriharsha Basavapatna 	}
2305*63f531d1SSriharsha Basavapatna 
2306*63f531d1SSriharsha Basavapatna 	ASSERT((rx_ringp->state & VNET_RXRING_HYBRID) != 0);
2307*63f531d1SSriharsha Basavapatna 
2308*63f531d1SSriharsha Basavapatna 	/*
2309*63f531d1SSriharsha Basavapatna 	 * This must be a ring reserved for a hwring. If the hwring is not
2310*63f531d1SSriharsha Basavapatna 	 * bound yet, simply mark the state to indicate the ring is stopped and
2311*63f531d1SSriharsha Basavapatna 	 * return. If a hwring is already bound, stop it now.
2312*63f531d1SSriharsha Basavapatna 	 */
2313*63f531d1SSriharsha Basavapatna 	if (rx_ringp->hw_rh == NULL) {
2314*63f531d1SSriharsha Basavapatna 		rx_ringp->state &= ~VNET_RXRING_STARTED;
2315*63f531d1SSriharsha Basavapatna 		return;
2316*63f531d1SSriharsha Basavapatna 	}
2317*63f531d1SSriharsha Basavapatna 
2318*63f531d1SSriharsha Basavapatna 	mac_hwring_stop(rx_ringp->hw_rh);
2319*63f531d1SSriharsha Basavapatna 	rx_ringp->state &= ~VNET_RXRING_STARTED;
2320*63f531d1SSriharsha Basavapatna }
2321*63f531d1SSriharsha Basavapatna 
2322*63f531d1SSriharsha Basavapatna /* ARGSUSED */
2323*63f531d1SSriharsha Basavapatna static int
2324*63f531d1SSriharsha Basavapatna vnet_tx_ring_start(mac_ring_driver_t arg, uint64_t mr_gen_num)
2325*63f531d1SSriharsha Basavapatna {
2326*63f531d1SSriharsha Basavapatna 	vnet_pseudo_tx_ring_t	*tx_ringp = (vnet_pseudo_tx_ring_t *)arg;
2327*63f531d1SSriharsha Basavapatna 
2328*63f531d1SSriharsha Basavapatna 	tx_ringp->state |= VNET_TXRING_STARTED;
2329*63f531d1SSriharsha Basavapatna 	return (0);
2330*63f531d1SSriharsha Basavapatna }
2331*63f531d1SSriharsha Basavapatna 
2332*63f531d1SSriharsha Basavapatna static void
2333*63f531d1SSriharsha Basavapatna vnet_tx_ring_stop(mac_ring_driver_t arg)
2334*63f531d1SSriharsha Basavapatna {
2335*63f531d1SSriharsha Basavapatna 	vnet_pseudo_tx_ring_t	*tx_ringp = (vnet_pseudo_tx_ring_t *)arg;
2336*63f531d1SSriharsha Basavapatna 
2337*63f531d1SSriharsha Basavapatna 	tx_ringp->state &= ~VNET_TXRING_STARTED;
2338*63f531d1SSriharsha Basavapatna }
2339*63f531d1SSriharsha Basavapatna 
2340*63f531d1SSriharsha Basavapatna /*
2341*63f531d1SSriharsha Basavapatna  * Disable polling for a ring and enable its interrupt.
2342*63f531d1SSriharsha Basavapatna  */
2343*63f531d1SSriharsha Basavapatna static int
2344*63f531d1SSriharsha Basavapatna vnet_ring_enable_intr(void *arg)
2345*63f531d1SSriharsha Basavapatna {
2346*63f531d1SSriharsha Basavapatna 	vnet_pseudo_rx_ring_t	*rx_ringp = (vnet_pseudo_rx_ring_t *)arg;
2347*63f531d1SSriharsha Basavapatna 	vnet_res_t		*vresp;
2348*63f531d1SSriharsha Basavapatna 
2349*63f531d1SSriharsha Basavapatna 	if (rx_ringp->hw_rh == NULL) {
2350*63f531d1SSriharsha Basavapatna 		/*
2351*63f531d1SSriharsha Basavapatna 		 * Ring enable intr func is being invoked, but the ring is
2352*63f531d1SSriharsha Basavapatna 		 * not bound to any underlying resource ? This must be a ring
2353*63f531d1SSriharsha Basavapatna 		 * reserved for Hybrid resource and no such resource has been
2354*63f531d1SSriharsha Basavapatna 		 * assigned to this vnet device yet. We simply return success.
2355*63f531d1SSriharsha Basavapatna 		 */
2356*63f531d1SSriharsha Basavapatna 		ASSERT((rx_ringp->state & VNET_RXRING_HYBRID) != 0);
2357*63f531d1SSriharsha Basavapatna 		return (0);
2358*63f531d1SSriharsha Basavapatna 	}
2359*63f531d1SSriharsha Basavapatna 
2360*63f531d1SSriharsha Basavapatna 	/*
2361*63f531d1SSriharsha Basavapatna 	 * The rx ring has been bound to either a LDC or a Hybrid resource.
2362*63f531d1SSriharsha Basavapatna 	 * Call the appropriate function to enable interrupts for the ring.
2363*63f531d1SSriharsha Basavapatna 	 */
2364*63f531d1SSriharsha Basavapatna 	if (rx_ringp->state & VNET_RXRING_HYBRID) {
2365*63f531d1SSriharsha Basavapatna 		return (mac_hwring_enable_intr(rx_ringp->hw_rh));
2366*63f531d1SSriharsha Basavapatna 	} else {
2367*63f531d1SSriharsha Basavapatna 		vresp = (vnet_res_t *)rx_ringp->hw_rh;
2368*63f531d1SSriharsha Basavapatna 		return (vgen_enable_intr(vresp->macreg.m_driver));
2369*63f531d1SSriharsha Basavapatna 	}
2370*63f531d1SSriharsha Basavapatna }
2371*63f531d1SSriharsha Basavapatna 
2372*63f531d1SSriharsha Basavapatna /*
2373*63f531d1SSriharsha Basavapatna  * Enable polling for a ring and disable its interrupt.
2374*63f531d1SSriharsha Basavapatna  */
2375*63f531d1SSriharsha Basavapatna static int
2376*63f531d1SSriharsha Basavapatna vnet_ring_disable_intr(void *arg)
2377*63f531d1SSriharsha Basavapatna {
2378*63f531d1SSriharsha Basavapatna 	vnet_pseudo_rx_ring_t	*rx_ringp = (vnet_pseudo_rx_ring_t *)arg;
2379*63f531d1SSriharsha Basavapatna 	vnet_res_t		*vresp;
2380*63f531d1SSriharsha Basavapatna 
2381*63f531d1SSriharsha Basavapatna 	if (rx_ringp->hw_rh == NULL) {
2382*63f531d1SSriharsha Basavapatna 		/*
2383*63f531d1SSriharsha Basavapatna 		 * Ring disable intr func is being invoked, but the ring is
2384*63f531d1SSriharsha Basavapatna 		 * not bound to any underlying resource ? This must be a ring
2385*63f531d1SSriharsha Basavapatna 		 * reserved for Hybrid resource and no such resource has been
2386*63f531d1SSriharsha Basavapatna 		 * assigned to this vnet device yet. We simply return success.
2387*63f531d1SSriharsha Basavapatna 		 */
2388*63f531d1SSriharsha Basavapatna 		ASSERT((rx_ringp->state & VNET_RXRING_HYBRID) != 0);
2389*63f531d1SSriharsha Basavapatna 		return (0);
2390*63f531d1SSriharsha Basavapatna 	}
2391*63f531d1SSriharsha Basavapatna 
2392*63f531d1SSriharsha Basavapatna 	/*
2393*63f531d1SSriharsha Basavapatna 	 * The rx ring has been bound to either a LDC or a Hybrid resource.
2394*63f531d1SSriharsha Basavapatna 	 * Call the appropriate function to disable interrupts for the ring.
2395*63f531d1SSriharsha Basavapatna 	 */
2396*63f531d1SSriharsha Basavapatna 	if (rx_ringp->state & VNET_RXRING_HYBRID) {
2397*63f531d1SSriharsha Basavapatna 		return (mac_hwring_disable_intr(rx_ringp->hw_rh));
2398*63f531d1SSriharsha Basavapatna 	} else {
2399*63f531d1SSriharsha Basavapatna 		vresp = (vnet_res_t *)rx_ringp->hw_rh;
2400*63f531d1SSriharsha Basavapatna 		return (vgen_disable_intr(vresp->macreg.m_driver));
2401*63f531d1SSriharsha Basavapatna 	}
2402*63f531d1SSriharsha Basavapatna }
2403*63f531d1SSriharsha Basavapatna 
2404*63f531d1SSriharsha Basavapatna /*
2405*63f531d1SSriharsha Basavapatna  * Poll 'bytes_to_pickup' bytes of message from the rx ring.
2406*63f531d1SSriharsha Basavapatna  */
2407*63f531d1SSriharsha Basavapatna static mblk_t *
2408*63f531d1SSriharsha Basavapatna vnet_rx_poll(void *arg, int bytes_to_pickup)
2409*63f531d1SSriharsha Basavapatna {
2410*63f531d1SSriharsha Basavapatna 	vnet_pseudo_rx_ring_t	*rx_ringp = (vnet_pseudo_rx_ring_t *)arg;
2411*63f531d1SSriharsha Basavapatna 	mblk_t			*mp = NULL;
2412*63f531d1SSriharsha Basavapatna 	vnet_res_t		*vresp;
2413*63f531d1SSriharsha Basavapatna 	vnet_t			*vnetp = rx_ringp->vnetp;
2414*63f531d1SSriharsha Basavapatna 
2415*63f531d1SSriharsha Basavapatna 	if (rx_ringp->hw_rh == NULL) {
2416*63f531d1SSriharsha Basavapatna 		return (NULL);
2417*63f531d1SSriharsha Basavapatna 	}
2418*63f531d1SSriharsha Basavapatna 
2419*63f531d1SSriharsha Basavapatna 	if (rx_ringp->state & VNET_RXRING_HYBRID) {
2420*63f531d1SSriharsha Basavapatna 		mp = mac_hwring_poll(rx_ringp->hw_rh, bytes_to_pickup);
2421*63f531d1SSriharsha Basavapatna 		/*
2422*63f531d1SSriharsha Basavapatna 		 * Packets received over a hybrid resource need additional
2423*63f531d1SSriharsha Basavapatna 		 * processing to remove the tag, for the pvid case. The
2424*63f531d1SSriharsha Basavapatna 		 * underlying resource is not aware of the vnet's pvid and thus
2425*63f531d1SSriharsha Basavapatna 		 * packets are received with the vlan tag in the header; unlike
2426*63f531d1SSriharsha Basavapatna 		 * packets that are received over a ldc channel in which case
2427*63f531d1SSriharsha Basavapatna 		 * the peer vnet/vsw would have already removed the tag.
2428*63f531d1SSriharsha Basavapatna 		 */
2429*63f531d1SSriharsha Basavapatna 		if (vnetp->pvid != vnetp->default_vlan_id) {
2430*63f531d1SSriharsha Basavapatna 			vnet_rx_frames_untag(vnetp->pvid, &mp);
2431*63f531d1SSriharsha Basavapatna 		}
2432*63f531d1SSriharsha Basavapatna 	} else {
2433*63f531d1SSriharsha Basavapatna 		vresp = (vnet_res_t *)rx_ringp->hw_rh;
2434*63f531d1SSriharsha Basavapatna 		mp = vgen_poll(vresp->macreg.m_driver, bytes_to_pickup);
2435*63f531d1SSriharsha Basavapatna 	}
2436*63f531d1SSriharsha Basavapatna 	return (mp);
2437*63f531d1SSriharsha Basavapatna }
2438*63f531d1SSriharsha Basavapatna 
2439*63f531d1SSriharsha Basavapatna /* ARGSUSED */
2440*63f531d1SSriharsha Basavapatna void
2441*63f531d1SSriharsha Basavapatna vnet_hio_rx_cb(void *arg, mac_resource_handle_t mrh, mblk_t *mp,
2442*63f531d1SSriharsha Basavapatna 	boolean_t loopback)
2443*63f531d1SSriharsha Basavapatna {
2444*63f531d1SSriharsha Basavapatna 	vnet_t			*vnetp = (vnet_t *)arg;
2445*63f531d1SSriharsha Basavapatna 	vnet_pseudo_rx_ring_t	*ringp = (vnet_pseudo_rx_ring_t *)mrh;
2446*63f531d1SSriharsha Basavapatna 
2447*63f531d1SSriharsha Basavapatna 	/*
2448*63f531d1SSriharsha Basavapatna 	 * Packets received over a hybrid resource need additional processing
2449*63f531d1SSriharsha Basavapatna 	 * to remove the tag, for the pvid case. The underlying resource is
2450*63f531d1SSriharsha Basavapatna 	 * not aware of the vnet's pvid and thus packets are received with the
2451*63f531d1SSriharsha Basavapatna 	 * vlan tag in the header; unlike packets that are received over a ldc
2452*63f531d1SSriharsha Basavapatna 	 * channel in which case the peer vnet/vsw would have already removed
2453*63f531d1SSriharsha Basavapatna 	 * the tag.
2454*63f531d1SSriharsha Basavapatna 	 */
2455*63f531d1SSriharsha Basavapatna 	if (vnetp->pvid != vnetp->default_vlan_id) {
2456*63f531d1SSriharsha Basavapatna 		vnet_rx_frames_untag(vnetp->pvid, &mp);
2457*63f531d1SSriharsha Basavapatna 		if (mp == NULL) {
2458*63f531d1SSriharsha Basavapatna 			return;
2459*63f531d1SSriharsha Basavapatna 		}
2460*63f531d1SSriharsha Basavapatna 	}
2461*63f531d1SSriharsha Basavapatna 	mac_rx_ring(vnetp->mh, ringp->handle, mp, ringp->gen_num);
2462*63f531d1SSriharsha Basavapatna }
2463*63f531d1SSriharsha Basavapatna 
2464*63f531d1SSriharsha Basavapatna static int
2465*63f531d1SSriharsha Basavapatna vnet_addmac(void *arg, const uint8_t *mac_addr)
2466*63f531d1SSriharsha Basavapatna {
2467*63f531d1SSriharsha Basavapatna 	vnet_pseudo_rx_group_t  *rx_grp = (vnet_pseudo_rx_group_t *)arg;
2468*63f531d1SSriharsha Basavapatna 	vnet_t			*vnetp;
2469*63f531d1SSriharsha Basavapatna 
2470*63f531d1SSriharsha Basavapatna 	vnetp = rx_grp->vnetp;
2471*63f531d1SSriharsha Basavapatna 
2472*63f531d1SSriharsha Basavapatna 	if (bcmp(mac_addr, vnetp->curr_macaddr, ETHERADDRL) == 0) {
2473*63f531d1SSriharsha Basavapatna 		return (0);
2474*63f531d1SSriharsha Basavapatna 	}
2475*63f531d1SSriharsha Basavapatna 
2476*63f531d1SSriharsha Basavapatna 	cmn_err(CE_CONT, "!vnet%d: %s: Multiple macaddr unsupported\n",
2477*63f531d1SSriharsha Basavapatna 	    vnetp->instance, __func__);
2478*63f531d1SSriharsha Basavapatna 	return (EINVAL);
2479*63f531d1SSriharsha Basavapatna }
2480*63f531d1SSriharsha Basavapatna 
2481*63f531d1SSriharsha Basavapatna static int
2482*63f531d1SSriharsha Basavapatna vnet_remmac(void *arg, const uint8_t *mac_addr)
2483*63f531d1SSriharsha Basavapatna {
2484*63f531d1SSriharsha Basavapatna 	vnet_pseudo_rx_group_t  *rx_grp = (vnet_pseudo_rx_group_t *)arg;
2485*63f531d1SSriharsha Basavapatna 	vnet_t			*vnetp;
2486*63f531d1SSriharsha Basavapatna 
2487*63f531d1SSriharsha Basavapatna 	vnetp = rx_grp->vnetp;
2488*63f531d1SSriharsha Basavapatna 
2489*63f531d1SSriharsha Basavapatna 	if (bcmp(mac_addr, vnetp->curr_macaddr, ETHERADDRL) == 0) {
2490*63f531d1SSriharsha Basavapatna 		return (0);
2491*63f531d1SSriharsha Basavapatna 	}
2492*63f531d1SSriharsha Basavapatna 
2493*63f531d1SSriharsha Basavapatna 	cmn_err(CE_CONT, "!vnet%d: %s: Invalid macaddr: %s\n",
2494*63f531d1SSriharsha Basavapatna 	    vnetp->instance, __func__, ether_sprintf((void *)mac_addr));
2495*63f531d1SSriharsha Basavapatna 	return (EINVAL);
2496*63f531d1SSriharsha Basavapatna }
2497*63f531d1SSriharsha Basavapatna 
2498*63f531d1SSriharsha Basavapatna int
2499*63f531d1SSriharsha Basavapatna vnet_hio_mac_init(vnet_t *vnetp, char *ifname)
2500*63f531d1SSriharsha Basavapatna {
2501*63f531d1SSriharsha Basavapatna 	mac_handle_t		mh;
2502*63f531d1SSriharsha Basavapatna 	mac_client_handle_t	mch = NULL;
2503*63f531d1SSriharsha Basavapatna 	mac_unicast_handle_t	muh = NULL;
2504*63f531d1SSriharsha Basavapatna 	mac_diag_t		diag;
2505*63f531d1SSriharsha Basavapatna 	mac_register_t		*macp;
2506*63f531d1SSriharsha Basavapatna 	char			client_name[MAXNAMELEN];
2507*63f531d1SSriharsha Basavapatna 	int			rv;
2508*63f531d1SSriharsha Basavapatna 	uint16_t		mac_flags = MAC_UNICAST_TAG_DISABLE |
2509*63f531d1SSriharsha Basavapatna 	    MAC_UNICAST_STRIP_DISABLE | MAC_UNICAST_PRIMARY;
2510*63f531d1SSriharsha Basavapatna 	vio_net_callbacks_t	vcb;
2511*63f531d1SSriharsha Basavapatna 	ether_addr_t		rem_addr =
2512*63f531d1SSriharsha Basavapatna 		{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
2513*63f531d1SSriharsha Basavapatna 	uint32_t		retries = 0;
2514*63f531d1SSriharsha Basavapatna 
2515*63f531d1SSriharsha Basavapatna 	if ((macp = mac_alloc(MAC_VERSION)) == NULL) {
2516*63f531d1SSriharsha Basavapatna 		return (EAGAIN);
2517*63f531d1SSriharsha Basavapatna 	}
2518*63f531d1SSriharsha Basavapatna 
2519*63f531d1SSriharsha Basavapatna 	do {
2520*63f531d1SSriharsha Basavapatna 		rv = mac_open_by_linkname(ifname, &mh);
2521*63f531d1SSriharsha Basavapatna 		if (rv == 0) {
2522*63f531d1SSriharsha Basavapatna 			break;
2523*63f531d1SSriharsha Basavapatna 		}
2524*63f531d1SSriharsha Basavapatna 		if (rv != ENOENT || (retries++ >= vnet_mac_open_retries)) {
2525*63f531d1SSriharsha Basavapatna 			mac_free(macp);
2526*63f531d1SSriharsha Basavapatna 			return (rv);
2527*63f531d1SSriharsha Basavapatna 		}
2528*63f531d1SSriharsha Basavapatna 		drv_usecwait(vnet_mac_open_delay);
2529*63f531d1SSriharsha Basavapatna 	} while (rv == ENOENT);
2530*63f531d1SSriharsha Basavapatna 
2531*63f531d1SSriharsha Basavapatna 	vnetp->hio_mh = mh;
2532*63f531d1SSriharsha Basavapatna 
2533*63f531d1SSriharsha Basavapatna 	(void) snprintf(client_name, MAXNAMELEN, "vnet%d-%s", vnetp->instance,
2534*63f531d1SSriharsha Basavapatna 	    ifname);
2535*63f531d1SSriharsha Basavapatna 	rv = mac_client_open(mh, &mch, client_name, MAC_OPEN_FLAGS_EXCLUSIVE);
2536*63f531d1SSriharsha Basavapatna 	if (rv != 0) {
2537*63f531d1SSriharsha Basavapatna 		goto fail;
2538*63f531d1SSriharsha Basavapatna 	}
2539*63f531d1SSriharsha Basavapatna 	vnetp->hio_mch = mch;
2540*63f531d1SSriharsha Basavapatna 
2541*63f531d1SSriharsha Basavapatna 	rv = mac_unicast_add(mch, vnetp->curr_macaddr, mac_flags, &muh, 0,
2542*63f531d1SSriharsha Basavapatna 	    &diag);
2543*63f531d1SSriharsha Basavapatna 	if (rv != 0) {
2544*63f531d1SSriharsha Basavapatna 		goto fail;
2545*63f531d1SSriharsha Basavapatna 	}
2546*63f531d1SSriharsha Basavapatna 	vnetp->hio_muh = muh;
2547*63f531d1SSriharsha Basavapatna 
2548*63f531d1SSriharsha Basavapatna 	macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
2549*63f531d1SSriharsha Basavapatna 	macp->m_driver = vnetp;
2550*63f531d1SSriharsha Basavapatna 	macp->m_dip = NULL;
2551*63f531d1SSriharsha Basavapatna 	macp->m_src_addr = NULL;
2552*63f531d1SSriharsha Basavapatna 	macp->m_callbacks = &vnet_hio_res_callbacks;
2553*63f531d1SSriharsha Basavapatna 	macp->m_min_sdu = 0;
2554*63f531d1SSriharsha Basavapatna 	macp->m_max_sdu = ETHERMTU;
2555*63f531d1SSriharsha Basavapatna 
2556*63f531d1SSriharsha Basavapatna 	rv = vio_net_resource_reg(macp, VIO_NET_RES_HYBRID,
2557*63f531d1SSriharsha Basavapatna 	    vnetp->curr_macaddr, rem_addr, &vnetp->hio_vhp, &vcb);
2558*63f531d1SSriharsha Basavapatna 	if (rv != 0) {
2559*63f531d1SSriharsha Basavapatna 		goto fail;
2560*63f531d1SSriharsha Basavapatna 	}
2561*63f531d1SSriharsha Basavapatna 	mac_free(macp);
2562*63f531d1SSriharsha Basavapatna 
2563*63f531d1SSriharsha Basavapatna 	/* add the recv callback */
2564*63f531d1SSriharsha Basavapatna 	mac_rx_set(vnetp->hio_mch, vnet_hio_rx_cb, vnetp);
2565*63f531d1SSriharsha Basavapatna 
2566*63f531d1SSriharsha Basavapatna 	/* add the notify callback - only tx updates for now */
2567*63f531d1SSriharsha Basavapatna 	vnetp->hio_mnh = mac_notify_add(vnetp->hio_mh, vnet_hio_notify_cb,
2568*63f531d1SSriharsha Basavapatna 	    vnetp);
2569*63f531d1SSriharsha Basavapatna 
2570*63f531d1SSriharsha Basavapatna 	return (0);
2571*63f531d1SSriharsha Basavapatna 
2572*63f531d1SSriharsha Basavapatna fail:
2573*63f531d1SSriharsha Basavapatna 	mac_free(macp);
2574*63f531d1SSriharsha Basavapatna 	vnet_hio_mac_cleanup(vnetp);
2575*63f531d1SSriharsha Basavapatna 	return (1);
2576*63f531d1SSriharsha Basavapatna }
2577*63f531d1SSriharsha Basavapatna 
2578*63f531d1SSriharsha Basavapatna void
2579*63f531d1SSriharsha Basavapatna vnet_hio_mac_cleanup(vnet_t *vnetp)
2580*63f531d1SSriharsha Basavapatna {
2581*63f531d1SSriharsha Basavapatna 	if (vnetp->hio_mnh != NULL) {
2582*63f531d1SSriharsha Basavapatna 		(void) mac_notify_remove(vnetp->hio_mnh, B_TRUE);
2583*63f531d1SSriharsha Basavapatna 		vnetp->hio_mnh = NULL;
2584*63f531d1SSriharsha Basavapatna 	}
2585*63f531d1SSriharsha Basavapatna 
2586*63f531d1SSriharsha Basavapatna 	if (vnetp->hio_vhp != NULL) {
2587*63f531d1SSriharsha Basavapatna 		vio_net_resource_unreg(vnetp->hio_vhp);
2588*63f531d1SSriharsha Basavapatna 		vnetp->hio_vhp = NULL;
2589*63f531d1SSriharsha Basavapatna 	}
2590*63f531d1SSriharsha Basavapatna 
2591*63f531d1SSriharsha Basavapatna 	if (vnetp->hio_muh != NULL) {
2592*63f531d1SSriharsha Basavapatna 		mac_unicast_remove(vnetp->hio_mch, vnetp->hio_muh);
2593*63f531d1SSriharsha Basavapatna 		vnetp->hio_muh = NULL;
2594*63f531d1SSriharsha Basavapatna 	}
2595*63f531d1SSriharsha Basavapatna 
2596*63f531d1SSriharsha Basavapatna 	if (vnetp->hio_mch != NULL) {
2597*63f531d1SSriharsha Basavapatna 		mac_client_close(vnetp->hio_mch, 0);
2598*63f531d1SSriharsha Basavapatna 		vnetp->hio_mch = NULL;
2599*63f531d1SSriharsha Basavapatna 	}
2600*63f531d1SSriharsha Basavapatna 
2601*63f531d1SSriharsha Basavapatna 	if (vnetp->hio_mh != NULL) {
2602*63f531d1SSriharsha Basavapatna 		mac_close(vnetp->hio_mh);
2603*63f531d1SSriharsha Basavapatna 		vnetp->hio_mh = NULL;
2604*63f531d1SSriharsha Basavapatna 	}
2605*63f531d1SSriharsha Basavapatna }
2606*63f531d1SSriharsha Basavapatna 
2607*63f531d1SSriharsha Basavapatna /* Bind pseudo rings to hwrings */
2608*63f531d1SSriharsha Basavapatna static int
2609*63f531d1SSriharsha Basavapatna vnet_bind_hwrings(vnet_t *vnetp)
2610*63f531d1SSriharsha Basavapatna {
2611*63f531d1SSriharsha Basavapatna 	mac_ring_handle_t	hw_rh[VNET_NUM_HYBRID_RINGS];
2612*63f531d1SSriharsha Basavapatna 	mac_perim_handle_t	mph1;
2613*63f531d1SSriharsha Basavapatna 	vnet_pseudo_rx_group_t	*rx_grp;
2614*63f531d1SSriharsha Basavapatna 	vnet_pseudo_rx_ring_t	*rx_ringp;
2615*63f531d1SSriharsha Basavapatna 	vnet_pseudo_tx_group_t	*tx_grp;
2616*63f531d1SSriharsha Basavapatna 	vnet_pseudo_tx_ring_t	*tx_ringp;
2617*63f531d1SSriharsha Basavapatna 	int			hw_ring_cnt;
2618*63f531d1SSriharsha Basavapatna 	int			i;
2619*63f531d1SSriharsha Basavapatna 	int			rv;
2620*63f531d1SSriharsha Basavapatna 
2621*63f531d1SSriharsha Basavapatna 	mac_perim_enter_by_mh(vnetp->hio_mh, &mph1);
2622*63f531d1SSriharsha Basavapatna 
2623*63f531d1SSriharsha Basavapatna 	/* Get the list of the underlying RX rings. */
2624*63f531d1SSriharsha Basavapatna 	hw_ring_cnt = mac_hwrings_get(vnetp->hio_mch, &vnetp->rx_hwgh, hw_rh,
2625*63f531d1SSriharsha Basavapatna 	    MAC_RING_TYPE_RX);
2626*63f531d1SSriharsha Basavapatna 
2627*63f531d1SSriharsha Basavapatna 	/* We expect the the # of hw rx rings to match VNET_NUM_HYBRID_RINGS */
2628*63f531d1SSriharsha Basavapatna 	if (hw_ring_cnt != VNET_NUM_HYBRID_RINGS) {
2629*63f531d1SSriharsha Basavapatna 		cmn_err(CE_WARN,
2630*63f531d1SSriharsha Basavapatna 		    "!vnet%d: vnet_bind_hwrings: bad rx hw_ring_cnt(%d)\n",
2631*63f531d1SSriharsha Basavapatna 		    vnetp->instance, hw_ring_cnt);
2632*63f531d1SSriharsha Basavapatna 		goto fail;
2633*63f531d1SSriharsha Basavapatna 	}
2634*63f531d1SSriharsha Basavapatna 
2635*63f531d1SSriharsha Basavapatna 	if (vnetp->rx_hwgh != NULL) {
2636*63f531d1SSriharsha Basavapatna 		/*
2637*63f531d1SSriharsha Basavapatna 		 * Quiesce the HW ring and the mac srs on the ring. Note
2638*63f531d1SSriharsha Basavapatna 		 * that the HW ring will be restarted when the pseudo ring
2639*63f531d1SSriharsha Basavapatna 		 * is started. At that time all the packets will be
2640*63f531d1SSriharsha Basavapatna 		 * directly passed up to the pseudo RX ring and handled
2641*63f531d1SSriharsha Basavapatna 		 * by mac srs created over the pseudo RX ring.
2642*63f531d1SSriharsha Basavapatna 		 */
2643*63f531d1SSriharsha Basavapatna 		mac_rx_client_quiesce(vnetp->hio_mch);
2644*63f531d1SSriharsha Basavapatna 		mac_srs_perm_quiesce(vnetp->hio_mch, B_TRUE);
2645*63f531d1SSriharsha Basavapatna 	}
2646*63f531d1SSriharsha Basavapatna 
2647*63f531d1SSriharsha Basavapatna 	/*
2648*63f531d1SSriharsha Basavapatna 	 * Bind the pseudo rings to the hwrings and start the hwrings.
2649*63f531d1SSriharsha Basavapatna 	 * Note we don't need to register these with the upper mac, as we have
2650*63f531d1SSriharsha Basavapatna 	 * statically exported these pseudo rxrings which are reserved for
2651*63f531d1SSriharsha Basavapatna 	 * rxrings of Hybrid resource.
2652*63f531d1SSriharsha Basavapatna 	 */
2653*63f531d1SSriharsha Basavapatna 	rx_grp = &vnetp->rx_grp[0];
2654*63f531d1SSriharsha Basavapatna 	for (i = 0; i < VNET_NUM_HYBRID_RINGS; i++) {
2655*63f531d1SSriharsha Basavapatna 		/* Pick the rxrings reserved for Hybrid resource */
2656*63f531d1SSriharsha Basavapatna 		rx_ringp = &rx_grp->rings[i + VNET_HYBRID_RXRING_INDEX];
2657*63f531d1SSriharsha Basavapatna 
2658*63f531d1SSriharsha Basavapatna 		/* Store the hw ring handle */
2659*63f531d1SSriharsha Basavapatna 		rx_ringp->hw_rh = hw_rh[i];
2660*63f531d1SSriharsha Basavapatna 
2661*63f531d1SSriharsha Basavapatna 		/* Bind the pseudo ring to the underlying hwring */
2662*63f531d1SSriharsha Basavapatna 		mac_hwring_setup(rx_ringp->hw_rh,
2663*63f531d1SSriharsha Basavapatna 		    (mac_resource_handle_t)rx_ringp);
2664*63f531d1SSriharsha Basavapatna 
2665*63f531d1SSriharsha Basavapatna 		/* Start the hwring if needed */
2666*63f531d1SSriharsha Basavapatna 		if (rx_ringp->state & VNET_RXRING_STARTED) {
2667*63f531d1SSriharsha Basavapatna 			rv = mac_hwring_start(rx_ringp->hw_rh);
2668*63f531d1SSriharsha Basavapatna 			if (rv != 0) {
2669*63f531d1SSriharsha Basavapatna 				mac_hwring_teardown(rx_ringp->hw_rh);
2670*63f531d1SSriharsha Basavapatna 				rx_ringp->hw_rh = NULL;
2671*63f531d1SSriharsha Basavapatna 				goto fail;
2672*63f531d1SSriharsha Basavapatna 			}
2673*63f531d1SSriharsha Basavapatna 		}
2674*63f531d1SSriharsha Basavapatna 	}
2675*63f531d1SSriharsha Basavapatna 
2676*63f531d1SSriharsha Basavapatna 	/* Get the list of the underlying TX rings. */
2677*63f531d1SSriharsha Basavapatna 	hw_ring_cnt = mac_hwrings_get(vnetp->hio_mch, &vnetp->tx_hwgh, hw_rh,
2678*63f531d1SSriharsha Basavapatna 	    MAC_RING_TYPE_TX);
2679*63f531d1SSriharsha Basavapatna 
2680*63f531d1SSriharsha Basavapatna 	/* We expect the # of hw tx rings to match VNET_NUM_HYBRID_RINGS */
2681*63f531d1SSriharsha Basavapatna 	if (hw_ring_cnt != VNET_NUM_HYBRID_RINGS) {
2682*63f531d1SSriharsha Basavapatna 		cmn_err(CE_WARN,
2683*63f531d1SSriharsha Basavapatna 		    "!vnet%d: vnet_bind_hwrings: bad tx hw_ring_cnt(%d)\n",
2684*63f531d1SSriharsha Basavapatna 		    vnetp->instance, hw_ring_cnt);
2685*63f531d1SSriharsha Basavapatna 		goto fail;
2686*63f531d1SSriharsha Basavapatna 	}
2687*63f531d1SSriharsha Basavapatna 
2688*63f531d1SSriharsha Basavapatna 	/*
2689*63f531d1SSriharsha Basavapatna 	 * Now map the pseudo txrings to the hw txrings. Note we don't need
2690*63f531d1SSriharsha Basavapatna 	 * to register these with the upper mac, as we have statically exported
2691*63f531d1SSriharsha Basavapatna 	 * these rings. Note that these rings will continue to be used for LDC
2692*63f531d1SSriharsha Basavapatna 	 * resources to peer vnets and vswitch (shared ring).
2693*63f531d1SSriharsha Basavapatna 	 */
2694*63f531d1SSriharsha Basavapatna 	tx_grp = &vnetp->tx_grp[0];
2695*63f531d1SSriharsha Basavapatna 	for (i = 0; i < tx_grp->ring_cnt; i++) {
2696*63f531d1SSriharsha Basavapatna 		tx_ringp = &tx_grp->rings[i];
2697*63f531d1SSriharsha Basavapatna 		tx_ringp->hw_rh = hw_rh[i];
2698*63f531d1SSriharsha Basavapatna 		tx_ringp->state |= VNET_TXRING_HYBRID;
2699*63f531d1SSriharsha Basavapatna 	}
2700*63f531d1SSriharsha Basavapatna 
2701*63f531d1SSriharsha Basavapatna 	mac_perim_exit(mph1);
2702*63f531d1SSriharsha Basavapatna 	return (0);
2703*63f531d1SSriharsha Basavapatna 
2704*63f531d1SSriharsha Basavapatna fail:
2705*63f531d1SSriharsha Basavapatna 	mac_perim_exit(mph1);
2706*63f531d1SSriharsha Basavapatna 	vnet_unbind_hwrings(vnetp);
2707*63f531d1SSriharsha Basavapatna 	return (1);
2708*63f531d1SSriharsha Basavapatna }
2709*63f531d1SSriharsha Basavapatna 
2710*63f531d1SSriharsha Basavapatna /* Unbind pseudo rings from hwrings */
2711*63f531d1SSriharsha Basavapatna static void
2712*63f531d1SSriharsha Basavapatna vnet_unbind_hwrings(vnet_t *vnetp)
2713*63f531d1SSriharsha Basavapatna {
2714*63f531d1SSriharsha Basavapatna 	mac_perim_handle_t	mph1;
2715*63f531d1SSriharsha Basavapatna 	vnet_pseudo_rx_ring_t	*rx_ringp;
2716*63f531d1SSriharsha Basavapatna 	vnet_pseudo_rx_group_t	*rx_grp;
2717*63f531d1SSriharsha Basavapatna 	vnet_pseudo_tx_group_t	*tx_grp;
2718*63f531d1SSriharsha Basavapatna 	vnet_pseudo_tx_ring_t	*tx_ringp;
2719*63f531d1SSriharsha Basavapatna 	int			i;
2720*63f531d1SSriharsha Basavapatna 
2721*63f531d1SSriharsha Basavapatna 	mac_perim_enter_by_mh(vnetp->hio_mh, &mph1);
2722*63f531d1SSriharsha Basavapatna 
2723*63f531d1SSriharsha Basavapatna 	tx_grp = &vnetp->tx_grp[0];
2724*63f531d1SSriharsha Basavapatna 	for (i = 0; i < VNET_NUM_HYBRID_RINGS; i++) {
2725*63f531d1SSriharsha Basavapatna 		tx_ringp = &tx_grp->rings[i];
2726*63f531d1SSriharsha Basavapatna 		if (tx_ringp->state & VNET_TXRING_HYBRID) {
2727*63f531d1SSriharsha Basavapatna 			tx_ringp->state &= ~VNET_TXRING_HYBRID;
2728*63f531d1SSriharsha Basavapatna 			tx_ringp->hw_rh = NULL;
2729*63f531d1SSriharsha Basavapatna 		}
2730*63f531d1SSriharsha Basavapatna 	}
2731*63f531d1SSriharsha Basavapatna 
2732*63f531d1SSriharsha Basavapatna 	rx_grp = &vnetp->rx_grp[0];
2733*63f531d1SSriharsha Basavapatna 	for (i = 0; i < VNET_NUM_HYBRID_RINGS; i++) {
2734*63f531d1SSriharsha Basavapatna 		rx_ringp = &rx_grp->rings[i + VNET_HYBRID_RXRING_INDEX];
2735*63f531d1SSriharsha Basavapatna 		if (rx_ringp->hw_rh != NULL) {
2736*63f531d1SSriharsha Basavapatna 			/* Stop the hwring */
2737*63f531d1SSriharsha Basavapatna 			mac_hwring_stop(rx_ringp->hw_rh);
2738*63f531d1SSriharsha Basavapatna 
2739*63f531d1SSriharsha Basavapatna 			/* Teardown the hwring */
2740*63f531d1SSriharsha Basavapatna 			mac_hwring_teardown(rx_ringp->hw_rh);
2741*63f531d1SSriharsha Basavapatna 			rx_ringp->hw_rh = NULL;
2742*63f531d1SSriharsha Basavapatna 		}
2743*63f531d1SSriharsha Basavapatna 	}
2744*63f531d1SSriharsha Basavapatna 
2745*63f531d1SSriharsha Basavapatna 	if (vnetp->rx_hwgh != NULL) {
2746*63f531d1SSriharsha Basavapatna 		vnetp->rx_hwgh = NULL;
2747*63f531d1SSriharsha Basavapatna 		/*
2748*63f531d1SSriharsha Basavapatna 		 * First clear the permanent-quiesced flag of the RX srs then
2749*63f531d1SSriharsha Basavapatna 		 * restart the HW ring and the mac srs on the ring.
2750*63f531d1SSriharsha Basavapatna 		 */
2751*63f531d1SSriharsha Basavapatna 		mac_srs_perm_quiesce(vnetp->hio_mch, B_FALSE);
2752*63f531d1SSriharsha Basavapatna 		mac_rx_client_restart(vnetp->hio_mch);
2753*63f531d1SSriharsha Basavapatna 	}
2754*63f531d1SSriharsha Basavapatna 
2755*63f531d1SSriharsha Basavapatna 	mac_perim_exit(mph1);
2756*63f531d1SSriharsha Basavapatna }
2757*63f531d1SSriharsha Basavapatna 
2758*63f531d1SSriharsha Basavapatna /* Bind pseudo ring to a LDC resource */
2759*63f531d1SSriharsha Basavapatna static int
2760*63f531d1SSriharsha Basavapatna vnet_bind_vgenring(vnet_res_t *vresp)
2761*63f531d1SSriharsha Basavapatna {
2762*63f531d1SSriharsha Basavapatna 	vnet_t			*vnetp;
2763*63f531d1SSriharsha Basavapatna 	vnet_pseudo_rx_group_t	*rx_grp;
2764*63f531d1SSriharsha Basavapatna 	vnet_pseudo_rx_ring_t	*rx_ringp;
2765*63f531d1SSriharsha Basavapatna 	mac_perim_handle_t	mph1;
2766*63f531d1SSriharsha Basavapatna 	int			rv;
2767*63f531d1SSriharsha Basavapatna 	int			type;
2768*63f531d1SSriharsha Basavapatna 
2769*63f531d1SSriharsha Basavapatna 	vnetp = vresp->vnetp;
2770*63f531d1SSriharsha Basavapatna 	type = vresp->type;
2771*63f531d1SSriharsha Basavapatna 	rx_grp = &vnetp->rx_grp[0];
2772*63f531d1SSriharsha Basavapatna 
2773*63f531d1SSriharsha Basavapatna 	if (type == VIO_NET_RES_LDC_SERVICE) {
2774*63f531d1SSriharsha Basavapatna 		/*
2775*63f531d1SSriharsha Basavapatna 		 * Ring Index 0 is the default ring in the group and is
2776*63f531d1SSriharsha Basavapatna 		 * reserved for LDC_SERVICE in vnet_ring_grp_init(). This ring
2777*63f531d1SSriharsha Basavapatna 		 * is allocated statically and is reported to the mac layer
2778*63f531d1SSriharsha Basavapatna 		 * in vnet_m_capab(). So, all we need to do here, is save a
2779*63f531d1SSriharsha Basavapatna 		 * reference to the associated vresp.
2780*63f531d1SSriharsha Basavapatna 		 */
2781*63f531d1SSriharsha Basavapatna 		rx_ringp = &rx_grp->rings[0];
2782*63f531d1SSriharsha Basavapatna 		rx_ringp->hw_rh = (mac_ring_handle_t)vresp;
2783*63f531d1SSriharsha Basavapatna 		vresp->rx_ringp = (void *)rx_ringp;
2784*63f531d1SSriharsha Basavapatna 		return (0);
2785*63f531d1SSriharsha Basavapatna 	}
2786*63f531d1SSriharsha Basavapatna 	ASSERT(type == VIO_NET_RES_LDC_GUEST);
2787*63f531d1SSriharsha Basavapatna 
2788*63f531d1SSriharsha Basavapatna 	mac_perim_enter_by_mh(vnetp->mh, &mph1);
2789*63f531d1SSriharsha Basavapatna 
2790*63f531d1SSriharsha Basavapatna 	rx_ringp = vnet_alloc_pseudo_rx_ring(vnetp);
2791*63f531d1SSriharsha Basavapatna 	if (rx_ringp == NULL) {
2792*63f531d1SSriharsha Basavapatna 		cmn_err(CE_WARN, "!vnet%d: Failed to allocate pseudo rx ring",
2793*63f531d1SSriharsha Basavapatna 		    vnetp->instance);
2794*63f531d1SSriharsha Basavapatna 		goto fail;
2795*63f531d1SSriharsha Basavapatna 	}
2796*63f531d1SSriharsha Basavapatna 
2797*63f531d1SSriharsha Basavapatna 	/* Store the LDC resource itself as the ring handle */
2798*63f531d1SSriharsha Basavapatna 	rx_ringp->hw_rh = (mac_ring_handle_t)vresp;
2799*63f531d1SSriharsha Basavapatna 
2800*63f531d1SSriharsha Basavapatna 	/*
2801*63f531d1SSriharsha Basavapatna 	 * Save a reference to the ring in the resource for lookup during
2802*63f531d1SSriharsha Basavapatna 	 * unbind. Note this is only done for LDC resources. We don't need this
2803*63f531d1SSriharsha Basavapatna 	 * in the case of a Hybrid resource (see vnet_bind_hwrings()), as its
2804*63f531d1SSriharsha Basavapatna 	 * rx rings are mapped to reserved pseudo rx rings (index 1 and 2).
2805*63f531d1SSriharsha Basavapatna 	 */
2806*63f531d1SSriharsha Basavapatna 	vresp->rx_ringp = (void *)rx_ringp;
2807*63f531d1SSriharsha Basavapatna 	rx_ringp->state |= VNET_RXRING_LDC_GUEST;
2808*63f531d1SSriharsha Basavapatna 
2809*63f531d1SSriharsha Basavapatna 	/* Register the pseudo ring with upper-mac */
2810*63f531d1SSriharsha Basavapatna 	rv = mac_group_add_ring(rx_grp->handle, rx_ringp->index);
2811*63f531d1SSriharsha Basavapatna 	if (rv != 0) {
2812*63f531d1SSriharsha Basavapatna 		rx_ringp->state &= ~VNET_RXRING_LDC_GUEST;
2813*63f531d1SSriharsha Basavapatna 		rx_ringp->hw_rh = NULL;
2814*63f531d1SSriharsha Basavapatna 		vnet_free_pseudo_rx_ring(vnetp, rx_ringp);
2815*63f531d1SSriharsha Basavapatna 		goto fail;
2816*63f531d1SSriharsha Basavapatna 	}
2817*63f531d1SSriharsha Basavapatna 
2818*63f531d1SSriharsha Basavapatna 	mac_perim_exit(mph1);
2819*63f531d1SSriharsha Basavapatna 	return (0);
2820*63f531d1SSriharsha Basavapatna fail:
2821*63f531d1SSriharsha Basavapatna 	mac_perim_exit(mph1);
2822*63f531d1SSriharsha Basavapatna 	return (1);
2823*63f531d1SSriharsha Basavapatna }
2824*63f531d1SSriharsha Basavapatna 
2825*63f531d1SSriharsha Basavapatna /* Unbind pseudo ring from a LDC resource */
2826*63f531d1SSriharsha Basavapatna static void
2827*63f531d1SSriharsha Basavapatna vnet_unbind_vgenring(vnet_res_t *vresp)
2828*63f531d1SSriharsha Basavapatna {
2829*63f531d1SSriharsha Basavapatna 	vnet_t			*vnetp;
2830*63f531d1SSriharsha Basavapatna 	vnet_pseudo_rx_group_t	*rx_grp;
2831*63f531d1SSriharsha Basavapatna 	vnet_pseudo_rx_ring_t	*rx_ringp;
2832*63f531d1SSriharsha Basavapatna 	mac_perim_handle_t	mph1;
2833*63f531d1SSriharsha Basavapatna 	int			type;
2834*63f531d1SSriharsha Basavapatna 
2835*63f531d1SSriharsha Basavapatna 	vnetp = vresp->vnetp;
2836*63f531d1SSriharsha Basavapatna 	type = vresp->type;
2837*63f531d1SSriharsha Basavapatna 	rx_grp = &vnetp->rx_grp[0];
2838*63f531d1SSriharsha Basavapatna 
2839*63f531d1SSriharsha Basavapatna 	if (vresp->rx_ringp == NULL) {
2840*63f531d1SSriharsha Basavapatna 		return;
2841*63f531d1SSriharsha Basavapatna 	}
2842*63f531d1SSriharsha Basavapatna 
2843*63f531d1SSriharsha Basavapatna 	if (type == VIO_NET_RES_LDC_SERVICE) {
2844*63f531d1SSriharsha Basavapatna 		/*
2845*63f531d1SSriharsha Basavapatna 		 * Ring Index 0 is the default ring in the group and is
2846*63f531d1SSriharsha Basavapatna 		 * reserved for LDC_SERVICE in vnet_ring_grp_init(). This ring
2847*63f531d1SSriharsha Basavapatna 		 * is allocated statically and is reported to the mac layer
2848*63f531d1SSriharsha Basavapatna 		 * in vnet_m_capab(). So, all we need to do here, is remove its
2849*63f531d1SSriharsha Basavapatna 		 * reference to the associated vresp.
2850*63f531d1SSriharsha Basavapatna 		 */
2851*63f531d1SSriharsha Basavapatna 		rx_ringp = &rx_grp->rings[0];
2852*63f531d1SSriharsha Basavapatna 		rx_ringp->hw_rh = NULL;
2853*63f531d1SSriharsha Basavapatna 		vresp->rx_ringp = NULL;
2854*63f531d1SSriharsha Basavapatna 		return;
2855*63f531d1SSriharsha Basavapatna 	}
2856*63f531d1SSriharsha Basavapatna 	ASSERT(type == VIO_NET_RES_LDC_GUEST);
2857*63f531d1SSriharsha Basavapatna 
2858*63f531d1SSriharsha Basavapatna 	mac_perim_enter_by_mh(vnetp->mh, &mph1);
2859*63f531d1SSriharsha Basavapatna 
2860*63f531d1SSriharsha Basavapatna 	rx_ringp = (vnet_pseudo_rx_ring_t *)vresp->rx_ringp;
2861*63f531d1SSriharsha Basavapatna 	vresp->rx_ringp = NULL;
2862*63f531d1SSriharsha Basavapatna 
2863*63f531d1SSriharsha Basavapatna 	if (rx_ringp != NULL && (rx_ringp->state & VNET_RXRING_LDC_GUEST)) {
2864*63f531d1SSriharsha Basavapatna 		/* Unregister the pseudo ring with upper-mac */
2865*63f531d1SSriharsha Basavapatna 		mac_group_rem_ring(rx_grp->handle, rx_ringp->handle);
2866*63f531d1SSriharsha Basavapatna 
2867*63f531d1SSriharsha Basavapatna 		rx_ringp->hw_rh = NULL;
2868*63f531d1SSriharsha Basavapatna 		rx_ringp->state &= ~VNET_RXRING_LDC_GUEST;
2869*63f531d1SSriharsha Basavapatna 
2870*63f531d1SSriharsha Basavapatna 		/* Free the pseudo rx ring */
2871*63f531d1SSriharsha Basavapatna 		vnet_free_pseudo_rx_ring(vnetp, rx_ringp);
2872*63f531d1SSriharsha Basavapatna 	}
2873*63f531d1SSriharsha Basavapatna 
2874*63f531d1SSriharsha Basavapatna 	mac_perim_exit(mph1);
2875*63f531d1SSriharsha Basavapatna }
2876*63f531d1SSriharsha Basavapatna 
2877*63f531d1SSriharsha Basavapatna static void
2878*63f531d1SSriharsha Basavapatna vnet_unbind_rings(vnet_res_t *vresp)
2879*63f531d1SSriharsha Basavapatna {
2880*63f531d1SSriharsha Basavapatna 	switch (vresp->type) {
2881*63f531d1SSriharsha Basavapatna 
2882*63f531d1SSriharsha Basavapatna 	case VIO_NET_RES_LDC_SERVICE:
2883*63f531d1SSriharsha Basavapatna 	case VIO_NET_RES_LDC_GUEST:
2884*63f531d1SSriharsha Basavapatna 		vnet_unbind_vgenring(vresp);
2885*63f531d1SSriharsha Basavapatna 		break;
2886*63f531d1SSriharsha Basavapatna 
2887*63f531d1SSriharsha Basavapatna 	case VIO_NET_RES_HYBRID:
2888*63f531d1SSriharsha Basavapatna 		vnet_unbind_hwrings(vresp->vnetp);
2889*63f531d1SSriharsha Basavapatna 		break;
2890*63f531d1SSriharsha Basavapatna 
2891*63f531d1SSriharsha Basavapatna 	default:
2892*63f531d1SSriharsha Basavapatna 		break;
2893*63f531d1SSriharsha Basavapatna 
2894*63f531d1SSriharsha Basavapatna 	}
2895*63f531d1SSriharsha Basavapatna }
2896*63f531d1SSriharsha Basavapatna 
2897*63f531d1SSriharsha Basavapatna static int
2898*63f531d1SSriharsha Basavapatna vnet_bind_rings(vnet_res_t *vresp)
2899*63f531d1SSriharsha Basavapatna {
2900*63f531d1SSriharsha Basavapatna 	int	rv;
2901*63f531d1SSriharsha Basavapatna 
2902*63f531d1SSriharsha Basavapatna 	switch (vresp->type) {
2903*63f531d1SSriharsha Basavapatna 
2904*63f531d1SSriharsha Basavapatna 	case VIO_NET_RES_LDC_SERVICE:
2905*63f531d1SSriharsha Basavapatna 	case VIO_NET_RES_LDC_GUEST:
2906*63f531d1SSriharsha Basavapatna 		rv = vnet_bind_vgenring(vresp);
2907*63f531d1SSriharsha Basavapatna 		break;
2908*63f531d1SSriharsha Basavapatna 
2909*63f531d1SSriharsha Basavapatna 	case VIO_NET_RES_HYBRID:
2910*63f531d1SSriharsha Basavapatna 		rv = vnet_bind_hwrings(vresp->vnetp);
2911*63f531d1SSriharsha Basavapatna 		break;
2912*63f531d1SSriharsha Basavapatna 
2913*63f531d1SSriharsha Basavapatna 	default:
2914*63f531d1SSriharsha Basavapatna 		rv = 1;
2915*63f531d1SSriharsha Basavapatna 		break;
2916*63f531d1SSriharsha Basavapatna 
2917*63f531d1SSriharsha Basavapatna 	}
2918*63f531d1SSriharsha Basavapatna 
2919*63f531d1SSriharsha Basavapatna 	return (rv);
2920*63f531d1SSriharsha Basavapatna }
2921*63f531d1SSriharsha Basavapatna 
2922*63f531d1SSriharsha Basavapatna /* ARGSUSED */
2923*63f531d1SSriharsha Basavapatna int
2924*63f531d1SSriharsha Basavapatna vnet_hio_stat(void *arg, uint_t stat, uint64_t *val)
2925*63f531d1SSriharsha Basavapatna {
2926*63f531d1SSriharsha Basavapatna 	vnet_t	*vnetp = (vnet_t *)arg;
2927*63f531d1SSriharsha Basavapatna 
2928*63f531d1SSriharsha Basavapatna 	*val = mac_stat_get(vnetp->hio_mh, stat);
2929*63f531d1SSriharsha Basavapatna 	return (0);
2930*63f531d1SSriharsha Basavapatna }
2931*63f531d1SSriharsha Basavapatna 
2932*63f531d1SSriharsha Basavapatna /*
2933*63f531d1SSriharsha Basavapatna  * The start() and stop() routines for the Hybrid resource below, are just
2934*63f531d1SSriharsha Basavapatna  * dummy functions. This is provided to avoid resource type specific code in
2935*63f531d1SSriharsha Basavapatna  * vnet_start_resources() and vnet_stop_resources(). The starting and stopping
2936*63f531d1SSriharsha Basavapatna  * of the Hybrid resource happens in the context of the mac_client interfaces
2937*63f531d1SSriharsha Basavapatna  * that are invoked in vnet_hio_mac_init() and vnet_hio_mac_cleanup().
2938*63f531d1SSriharsha Basavapatna  */
2939*63f531d1SSriharsha Basavapatna /* ARGSUSED */
2940*63f531d1SSriharsha Basavapatna static int
2941*63f531d1SSriharsha Basavapatna vnet_hio_start(void *arg)
2942*63f531d1SSriharsha Basavapatna {
2943*63f531d1SSriharsha Basavapatna 	return (0);
2944*63f531d1SSriharsha Basavapatna }
2945*63f531d1SSriharsha Basavapatna 
2946*63f531d1SSriharsha Basavapatna /* ARGSUSED */
2947*63f531d1SSriharsha Basavapatna static void
2948*63f531d1SSriharsha Basavapatna vnet_hio_stop(void *arg)
2949*63f531d1SSriharsha Basavapatna {
2950*63f531d1SSriharsha Basavapatna }
2951*63f531d1SSriharsha Basavapatna 
2952*63f531d1SSriharsha Basavapatna mblk_t *
2953*63f531d1SSriharsha Basavapatna vnet_hio_tx(void *arg, mblk_t *mp)
2954*63f531d1SSriharsha Basavapatna {
2955*63f531d1SSriharsha Basavapatna 	vnet_pseudo_tx_ring_t	*tx_ringp;
2956*63f531d1SSriharsha Basavapatna 	mblk_t			*nextp;
2957*63f531d1SSriharsha Basavapatna 	mblk_t			*ret_mp;
2958*63f531d1SSriharsha Basavapatna 
2959*63f531d1SSriharsha Basavapatna 	tx_ringp = (vnet_pseudo_tx_ring_t *)arg;
2960*63f531d1SSriharsha Basavapatna 	for (;;) {
2961*63f531d1SSriharsha Basavapatna 		nextp = mp->b_next;
2962*63f531d1SSriharsha Basavapatna 		mp->b_next = NULL;
2963*63f531d1SSriharsha Basavapatna 
2964*63f531d1SSriharsha Basavapatna 		ret_mp = mac_hwring_tx(tx_ringp->hw_rh, mp);
2965*63f531d1SSriharsha Basavapatna 		if (ret_mp != NULL) {
2966*63f531d1SSriharsha Basavapatna 			ret_mp->b_next = nextp;
2967*63f531d1SSriharsha Basavapatna 			mp = ret_mp;
2968*63f531d1SSriharsha Basavapatna 			break;
2969*63f531d1SSriharsha Basavapatna 		}
2970*63f531d1SSriharsha Basavapatna 
2971*63f531d1SSriharsha Basavapatna 		if ((mp = nextp) == NULL)
2972*63f531d1SSriharsha Basavapatna 			break;
2973*63f531d1SSriharsha Basavapatna 	}
2974*63f531d1SSriharsha Basavapatna 	return (mp);
2975*63f531d1SSriharsha Basavapatna }
2976*63f531d1SSriharsha Basavapatna 
2977*63f531d1SSriharsha Basavapatna static void
2978*63f531d1SSriharsha Basavapatna vnet_hio_notify_cb(void *arg, mac_notify_type_t type)
2979*63f531d1SSriharsha Basavapatna {
2980*63f531d1SSriharsha Basavapatna 	vnet_t			*vnetp = (vnet_t *)arg;
2981*63f531d1SSriharsha Basavapatna 	mac_perim_handle_t	mph;
2982*63f531d1SSriharsha Basavapatna 
2983*63f531d1SSriharsha Basavapatna 	mac_perim_enter_by_mh(vnetp->hio_mh, &mph);
2984*63f531d1SSriharsha Basavapatna 	switch (type) {
2985*63f531d1SSriharsha Basavapatna 	case MAC_NOTE_TX:
2986*63f531d1SSriharsha Basavapatna 		vnet_tx_update(vnetp->hio_vhp);
2987*63f531d1SSriharsha Basavapatna 		break;
2988*63f531d1SSriharsha Basavapatna 
2989*63f531d1SSriharsha Basavapatna 	default:
2990*63f531d1SSriharsha Basavapatna 		break;
2991*63f531d1SSriharsha Basavapatna 	}
2992*63f531d1SSriharsha Basavapatna 	mac_perim_exit(mph);
2993*63f531d1SSriharsha Basavapatna }
2994*63f531d1SSriharsha Basavapatna 
29951107ea93SSriharsha Basavapatna #ifdef	VNET_IOC_DEBUG
29961107ea93SSriharsha Basavapatna 
29971107ea93SSriharsha Basavapatna /*
29981107ea93SSriharsha Basavapatna  * The ioctl entry point is used only for debugging for now. The ioctl commands
29991107ea93SSriharsha Basavapatna  * can be used to force the link state of the channel connected to vsw.
30001107ea93SSriharsha Basavapatna  */
30011107ea93SSriharsha Basavapatna static void
30021107ea93SSriharsha Basavapatna vnet_m_ioctl(void *arg, queue_t *q, mblk_t *mp)
30031107ea93SSriharsha Basavapatna {
30041107ea93SSriharsha Basavapatna 	struct iocblk	*iocp;
30051107ea93SSriharsha Basavapatna 	vnet_t		*vnetp;
30061107ea93SSriharsha Basavapatna 
30071107ea93SSriharsha Basavapatna 	iocp = (struct iocblk *)(uintptr_t)mp->b_rptr;
30081107ea93SSriharsha Basavapatna 	iocp->ioc_error = 0;
30091107ea93SSriharsha Basavapatna 	vnetp = (vnet_t *)arg;
30101107ea93SSriharsha Basavapatna 
30111107ea93SSriharsha Basavapatna 	if (vnetp == NULL) {
30121107ea93SSriharsha Basavapatna 		miocnak(q, mp, 0, EINVAL);
30131107ea93SSriharsha Basavapatna 		return;
30141107ea93SSriharsha Basavapatna 	}
30151107ea93SSriharsha Basavapatna 
30161107ea93SSriharsha Basavapatna 	switch (iocp->ioc_cmd) {
30171107ea93SSriharsha Basavapatna 
30181107ea93SSriharsha Basavapatna 	case VNET_FORCE_LINK_DOWN:
30191107ea93SSriharsha Basavapatna 	case VNET_FORCE_LINK_UP:
30201107ea93SSriharsha Basavapatna 		vnet_force_link_state(vnetp, q, mp);
30211107ea93SSriharsha Basavapatna 		break;
30221107ea93SSriharsha Basavapatna 
30231107ea93SSriharsha Basavapatna 	default:
30241107ea93SSriharsha Basavapatna 		iocp->ioc_error = EINVAL;
30251107ea93SSriharsha Basavapatna 		miocnak(q, mp, 0, iocp->ioc_error);
30261107ea93SSriharsha Basavapatna 		break;
30271107ea93SSriharsha Basavapatna 
30281107ea93SSriharsha Basavapatna 	}
30291107ea93SSriharsha Basavapatna }
30301107ea93SSriharsha Basavapatna 
30311107ea93SSriharsha Basavapatna static void
30321107ea93SSriharsha Basavapatna vnet_force_link_state(vnet_t *vnetp, queue_t *q, mblk_t *mp)
30331107ea93SSriharsha Basavapatna {
30341107ea93SSriharsha Basavapatna 	mac_register_t	*macp;
30351107ea93SSriharsha Basavapatna 	mac_callbacks_t	*cbp;
30361107ea93SSriharsha Basavapatna 	vnet_res_t	*vresp;
30371107ea93SSriharsha Basavapatna 
30381107ea93SSriharsha Basavapatna 	READ_ENTER(&vnetp->vsw_fp_rw);
30391107ea93SSriharsha Basavapatna 
30401107ea93SSriharsha Basavapatna 	vresp = vnetp->vsw_fp;
30411107ea93SSriharsha Basavapatna 	if (vresp == NULL) {
30421107ea93SSriharsha Basavapatna 		RW_EXIT(&vnetp->vsw_fp_rw);
30431107ea93SSriharsha Basavapatna 		return;
30441107ea93SSriharsha Basavapatna 	}
30451107ea93SSriharsha Basavapatna 
30461107ea93SSriharsha Basavapatna 	macp = &vresp->macreg;
30471107ea93SSriharsha Basavapatna 	cbp = macp->m_callbacks;
30481107ea93SSriharsha Basavapatna 	cbp->mc_ioctl(macp->m_driver, q, mp);
30491107ea93SSriharsha Basavapatna 
30501107ea93SSriharsha Basavapatna 	RW_EXIT(&vnetp->vsw_fp_rw);
30511107ea93SSriharsha Basavapatna }
30521107ea93SSriharsha Basavapatna 
30531107ea93SSriharsha Basavapatna #else
30541107ea93SSriharsha Basavapatna 
30551107ea93SSriharsha Basavapatna static void
30561107ea93SSriharsha Basavapatna vnet_m_ioctl(void *arg, queue_t *q, mblk_t *mp)
30571107ea93SSriharsha Basavapatna {
30581107ea93SSriharsha Basavapatna 	vnet_t		*vnetp;
30591107ea93SSriharsha Basavapatna 
30601107ea93SSriharsha Basavapatna 	vnetp = (vnet_t *)arg;
30611107ea93SSriharsha Basavapatna 
30621107ea93SSriharsha Basavapatna 	if (vnetp == NULL) {
30631107ea93SSriharsha Basavapatna 		miocnak(q, mp, 0, EINVAL);
30641107ea93SSriharsha Basavapatna 		return;
30651107ea93SSriharsha Basavapatna 	}
30661107ea93SSriharsha Basavapatna 
30671107ea93SSriharsha Basavapatna 	/* ioctl support only for debugging */
30681107ea93SSriharsha Basavapatna 	miocnak(q, mp, 0, ENOTSUP);
30691107ea93SSriharsha Basavapatna }
30701107ea93SSriharsha Basavapatna 
30711107ea93SSriharsha Basavapatna #endif
3072