11991Sheppo /*
21991Sheppo * CDDL HEADER START
31991Sheppo *
41991Sheppo * The contents of this file are subject to the terms of the
51991Sheppo * Common Development and Distribution License (the "License").
61991Sheppo * You may not use this file except in compliance with the License.
71991Sheppo *
81991Sheppo * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91991Sheppo * or http://www.opensolaris.org/os/licensing.
101991Sheppo * See the License for the specific language governing permissions
111991Sheppo * and limitations under the License.
121991Sheppo *
131991Sheppo * When distributing Covered Code, include this CDDL HEADER in each
141991Sheppo * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151991Sheppo * If applicable, add the following below this CDDL HEADER, with the
161991Sheppo * fields enclosed by brackets "[]" replaced with your own identifying
171991Sheppo * information: Portions Copyright [yyyy] [name of copyright owner]
181991Sheppo *
191991Sheppo * CDDL HEADER END
201991Sheppo */
211991Sheppo
221991Sheppo /*
2311543SWentao.Yang@Sun.COM * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
241991Sheppo * Use is subject to license terms.
251991Sheppo */
261991Sheppo
271991Sheppo #include <sys/types.h>
281991Sheppo #include <sys/errno.h>
291991Sheppo #include <sys/param.h>
3011878SVenu.Iyer@Sun.COM #include <sys/callb.h>
311991Sheppo #include <sys/stream.h>
321991Sheppo #include <sys/kmem.h>
331991Sheppo #include <sys/conf.h>
341991Sheppo #include <sys/devops.h>
351991Sheppo #include <sys/ksynch.h>
361991Sheppo #include <sys/stat.h>
371991Sheppo #include <sys/modctl.h>
386419Ssb155480 #include <sys/modhash.h>
391991Sheppo #include <sys/debug.h>
401991Sheppo #include <sys/ethernet.h>
411991Sheppo #include <sys/dlpi.h>
421991Sheppo #include <net/if.h>
438275SEric Cheng #include <sys/mac_provider.h>
4410309SSriharsha.Basavapatna@Sun.COM #include <sys/mac_client.h>
4510309SSriharsha.Basavapatna@Sun.COM #include <sys/mac_client_priv.h>
462311Sseb #include <sys/mac_ether.h>
471991Sheppo #include <sys/ddi.h>
481991Sheppo #include <sys/sunddi.h>
491991Sheppo #include <sys/strsun.h>
501991Sheppo #include <sys/note.h>
516419Ssb155480 #include <sys/atomic.h>
521991Sheppo #include <sys/vnet.h>
536419Ssb155480 #include <sys/vlan.h>
546495Sspeer #include <sys/vnet_mailbox.h>
556495Sspeer #include <sys/vnet_common.h>
566495Sspeer #include <sys/dds.h>
576495Sspeer #include <sys/strsubr.h>
586495Sspeer #include <sys/taskq.h>
591991Sheppo
601991Sheppo /*
611991Sheppo * Function prototypes.
621991Sheppo */
631991Sheppo
641991Sheppo /* DDI entrypoints */
651991Sheppo static int vnetdevinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
661991Sheppo static int vnetattach(dev_info_t *, ddi_attach_cmd_t);
671991Sheppo static int vnetdetach(dev_info_t *, ddi_detach_cmd_t);
681991Sheppo
691991Sheppo /* MAC entrypoints */
702311Sseb static int vnet_m_stat(void *, uint_t, uint64_t *);
711991Sheppo static int vnet_m_start(void *);
721991Sheppo static void vnet_m_stop(void *);
731991Sheppo static int vnet_m_promisc(void *, boolean_t);
741991Sheppo static int vnet_m_multicst(void *, boolean_t, const uint8_t *);
751991Sheppo static int vnet_m_unicst(void *, const uint8_t *);
761991Sheppo mblk_t *vnet_m_tx(void *, mblk_t *);
779336SSriharsha.Basavapatna@Sun.COM static void vnet_m_ioctl(void *arg, queue_t *q, mblk_t *mp);
789336SSriharsha.Basavapatna@Sun.COM #ifdef VNET_IOC_DEBUG
799336SSriharsha.Basavapatna@Sun.COM static void vnet_force_link_state(vnet_t *vnetp, queue_t *q, mblk_t *mp);
809336SSriharsha.Basavapatna@Sun.COM #endif
8110309SSriharsha.Basavapatna@Sun.COM static boolean_t vnet_m_capab(void *arg, mac_capab_t cap, void *cap_data);
8210309SSriharsha.Basavapatna@Sun.COM static void vnet_get_ring(void *arg, mac_ring_type_t rtype, const int g_index,
8310309SSriharsha.Basavapatna@Sun.COM const int r_index, mac_ring_info_t *infop, mac_ring_handle_t r_handle);
8410309SSriharsha.Basavapatna@Sun.COM static void vnet_get_group(void *arg, mac_ring_type_t type, const int index,
8510309SSriharsha.Basavapatna@Sun.COM mac_group_info_t *infop, mac_group_handle_t handle);
8610309SSriharsha.Basavapatna@Sun.COM static int vnet_rx_ring_start(mac_ring_driver_t rdriver, uint64_t mr_gen_num);
8710309SSriharsha.Basavapatna@Sun.COM static void vnet_rx_ring_stop(mac_ring_driver_t rdriver);
8811878SVenu.Iyer@Sun.COM static int vnet_rx_ring_stat(mac_ring_driver_t rdriver, uint_t stat,
8911878SVenu.Iyer@Sun.COM uint64_t *val);
9010309SSriharsha.Basavapatna@Sun.COM static int vnet_tx_ring_start(mac_ring_driver_t rdriver, uint64_t mr_gen_num);
9110309SSriharsha.Basavapatna@Sun.COM static void vnet_tx_ring_stop(mac_ring_driver_t rdriver);
9211878SVenu.Iyer@Sun.COM static int vnet_tx_ring_stat(mac_ring_driver_t rdriver, uint_t stat,
9311878SVenu.Iyer@Sun.COM uint64_t *val);
9410309SSriharsha.Basavapatna@Sun.COM static int vnet_ring_enable_intr(void *arg);
9510309SSriharsha.Basavapatna@Sun.COM static int vnet_ring_disable_intr(void *arg);
9610309SSriharsha.Basavapatna@Sun.COM static mblk_t *vnet_rx_poll(void *arg, int bytes_to_pickup);
9710309SSriharsha.Basavapatna@Sun.COM static int vnet_addmac(void *arg, const uint8_t *mac_addr);
9810309SSriharsha.Basavapatna@Sun.COM static int vnet_remmac(void *arg, const uint8_t *mac_addr);
991991Sheppo
1001991Sheppo /* vnet internal functions */
1019217SWentao.Yang@Sun.COM static int vnet_unattach(vnet_t *vnetp);
10210309SSriharsha.Basavapatna@Sun.COM static void vnet_ring_grp_init(vnet_t *vnetp);
10310309SSriharsha.Basavapatna@Sun.COM static void vnet_ring_grp_uninit(vnet_t *vnetp);
1041991Sheppo static int vnet_mac_register(vnet_t *);
1051991Sheppo static int vnet_read_mac_address(vnet_t *vnetp);
10610309SSriharsha.Basavapatna@Sun.COM static int vnet_bind_vgenring(vnet_res_t *vresp);
10710309SSriharsha.Basavapatna@Sun.COM static void vnet_unbind_vgenring(vnet_res_t *vresp);
10810309SSriharsha.Basavapatna@Sun.COM static int vnet_bind_hwrings(vnet_t *vnetp);
10910309SSriharsha.Basavapatna@Sun.COM static void vnet_unbind_hwrings(vnet_t *vnetp);
11010309SSriharsha.Basavapatna@Sun.COM static int vnet_bind_rings(vnet_res_t *vresp);
11110309SSriharsha.Basavapatna@Sun.COM static void vnet_unbind_rings(vnet_res_t *vresp);
11210309SSriharsha.Basavapatna@Sun.COM static int vnet_hio_stat(void *, uint_t, uint64_t *);
11310309SSriharsha.Basavapatna@Sun.COM static int vnet_hio_start(void *);
11410309SSriharsha.Basavapatna@Sun.COM static void vnet_hio_stop(void *);
11510309SSriharsha.Basavapatna@Sun.COM mblk_t *vnet_hio_tx(void *, mblk_t *);
1161991Sheppo
1176419Ssb155480 /* Forwarding database (FDB) routines */
1186419Ssb155480 static void vnet_fdb_create(vnet_t *vnetp);
1196419Ssb155480 static void vnet_fdb_destroy(vnet_t *vnetp);
1206495Sspeer static vnet_res_t *vnet_fdbe_find(vnet_t *vnetp, struct ether_addr *addrp);
1216419Ssb155480 static void vnet_fdbe_find_cb(mod_hash_key_t key, mod_hash_val_t val);
1226495Sspeer void vnet_fdbe_add(vnet_t *vnetp, vnet_res_t *vresp);
1236495Sspeer static void vnet_fdbe_del(vnet_t *vnetp, vnet_res_t *vresp);
1246495Sspeer
1257896SSriharsha.Basavapatna@Sun.COM static void vnet_rx_frames_untag(uint16_t pvid, mblk_t **mp);
1266495Sspeer static void vnet_rx(vio_net_handle_t vrh, mblk_t *mp);
1276495Sspeer static void vnet_tx_update(vio_net_handle_t vrh);
1286495Sspeer static void vnet_res_start_task(void *arg);
1296495Sspeer static void vnet_start_resources(vnet_t *vnetp);
1306495Sspeer static void vnet_stop_resources(vnet_t *vnetp);
1316495Sspeer static void vnet_dispatch_res_task(vnet_t *vnetp);
1326495Sspeer static void vnet_res_start_task(void *arg);
1336495Sspeer static void vnet_handle_res_err(vio_net_handle_t vrh, vio_net_err_val_t err);
13410309SSriharsha.Basavapatna@Sun.COM static void vnet_add_resource(vnet_t *vnetp, vnet_res_t *vresp);
13510309SSriharsha.Basavapatna@Sun.COM static vnet_res_t *vnet_rem_resource(vnet_t *vnetp, vnet_res_t *vresp);
13611878SVenu.Iyer@Sun.COM static void vnet_tx_notify_thread(void *);
1379336SSriharsha.Basavapatna@Sun.COM
1389336SSriharsha.Basavapatna@Sun.COM /* Exported to vnet_gen */
1397529SSriharsha.Basavapatna@Sun.COM int vnet_mtu_update(vnet_t *vnetp, uint32_t mtu);
1409336SSriharsha.Basavapatna@Sun.COM void vnet_link_update(vnet_t *vnetp, link_state_t link_state);
1419647SWentao.Yang@Sun.COM void vnet_dds_cleanup_hio(vnet_t *vnetp);
1426419Ssb155480
1438160SWentao.Yang@Sun.COM static kstat_t *vnet_hio_setup_kstats(char *ks_mod, char *ks_name,
1448160SWentao.Yang@Sun.COM vnet_res_t *vresp);
1458160SWentao.Yang@Sun.COM static int vnet_hio_update_kstats(kstat_t *ksp, int rw);
1468160SWentao.Yang@Sun.COM static void vnet_hio_get_stats(vnet_res_t *vresp, vnet_hio_stats_t *statsp);
1478160SWentao.Yang@Sun.COM static void vnet_hio_destroy_kstats(kstat_t *ksp);
1488160SWentao.Yang@Sun.COM
1496495Sspeer /* Exported to to vnet_dds */
1506495Sspeer int vnet_send_dds_msg(vnet_t *vnetp, void *dmsg);
15110309SSriharsha.Basavapatna@Sun.COM int vnet_hio_mac_init(vnet_t *vnetp, char *ifname);
15210309SSriharsha.Basavapatna@Sun.COM void vnet_hio_mac_cleanup(vnet_t *vnetp);
1531991Sheppo
1546495Sspeer /* Externs that are imported from vnet_gen */
1556495Sspeer extern int vgen_init(void *vnetp, uint64_t regprop, dev_info_t *vnetdip,
1566495Sspeer const uint8_t *macaddr, void **vgenhdl);
15710309SSriharsha.Basavapatna@Sun.COM extern int vgen_init_mdeg(void *arg);
1589235SWentao.Yang@Sun.COM extern void vgen_uninit(void *arg);
1596495Sspeer extern int vgen_dds_tx(void *arg, void *dmsg);
16010309SSriharsha.Basavapatna@Sun.COM extern int vgen_enable_intr(void *arg);
16110309SSriharsha.Basavapatna@Sun.COM extern int vgen_disable_intr(void *arg);
162*12011SSriharsha.Basavapatna@Sun.COM extern mblk_t *vgen_rx_poll(void *arg, int bytes_to_pickup);
1636495Sspeer
1646495Sspeer /* Externs that are imported from vnet_dds */
1656495Sspeer extern void vdds_mod_init(void);
1666495Sspeer extern void vdds_mod_fini(void);
1676495Sspeer extern int vdds_init(vnet_t *vnetp);
1686495Sspeer extern void vdds_cleanup(vnet_t *vnetp);
1696495Sspeer extern void vdds_process_dds_msg(vnet_t *vnetp, vio_dds_msg_t *dmsg);
1707819SRaghuram.Kothakota@Sun.COM extern void vdds_cleanup_hybrid_res(void *arg);
1719647SWentao.Yang@Sun.COM extern void vdds_cleanup_hio(vnet_t *vnetp);
1721991Sheppo
17311878SVenu.Iyer@Sun.COM extern pri_t minclsyspri;
17410309SSriharsha.Basavapatna@Sun.COM
1758160SWentao.Yang@Sun.COM #define DRV_NAME "vnet"
1766419Ssb155480 #define VNET_FDBE_REFHOLD(p) \
1776419Ssb155480 { \
1786419Ssb155480 atomic_inc_32(&(p)->refcnt); \
1796419Ssb155480 ASSERT((p)->refcnt != 0); \
1806419Ssb155480 }
1816419Ssb155480
1826419Ssb155480 #define VNET_FDBE_REFRELE(p) \
1836419Ssb155480 { \
1846419Ssb155480 ASSERT((p)->refcnt != 0); \
1856419Ssb155480 atomic_dec_32(&(p)->refcnt); \
1866419Ssb155480 }
1876419Ssb155480
1889336SSriharsha.Basavapatna@Sun.COM #ifdef VNET_IOC_DEBUG
18910309SSriharsha.Basavapatna@Sun.COM #define VNET_M_CALLBACK_FLAGS (MC_IOCTL | MC_GETCAPAB)
1909336SSriharsha.Basavapatna@Sun.COM #else
19110309SSriharsha.Basavapatna@Sun.COM #define VNET_M_CALLBACK_FLAGS (MC_GETCAPAB)
1929336SSriharsha.Basavapatna@Sun.COM #endif
1939336SSriharsha.Basavapatna@Sun.COM
1942311Sseb static mac_callbacks_t vnet_m_callbacks = {
1959336SSriharsha.Basavapatna@Sun.COM VNET_M_CALLBACK_FLAGS,
1962311Sseb vnet_m_stat,
1972311Sseb vnet_m_start,
1982311Sseb vnet_m_stop,
1992311Sseb vnet_m_promisc,
2002311Sseb vnet_m_multicst,
20110309SSriharsha.Basavapatna@Sun.COM NULL, /* m_unicst entry must be NULL while rx rings are exposed */
20210309SSriharsha.Basavapatna@Sun.COM NULL, /* m_tx entry must be NULL while tx rings are exposed */
20311878SVenu.Iyer@Sun.COM NULL,
2049336SSriharsha.Basavapatna@Sun.COM vnet_m_ioctl,
20510309SSriharsha.Basavapatna@Sun.COM vnet_m_capab,
20610309SSriharsha.Basavapatna@Sun.COM NULL
20710309SSriharsha.Basavapatna@Sun.COM };
20810309SSriharsha.Basavapatna@Sun.COM
20910309SSriharsha.Basavapatna@Sun.COM static mac_callbacks_t vnet_hio_res_callbacks = {
21010309SSriharsha.Basavapatna@Sun.COM 0,
21110309SSriharsha.Basavapatna@Sun.COM vnet_hio_stat,
21210309SSriharsha.Basavapatna@Sun.COM vnet_hio_start,
21310309SSriharsha.Basavapatna@Sun.COM vnet_hio_stop,
21410309SSriharsha.Basavapatna@Sun.COM NULL,
21510309SSriharsha.Basavapatna@Sun.COM NULL,
21610309SSriharsha.Basavapatna@Sun.COM NULL,
21710309SSriharsha.Basavapatna@Sun.COM vnet_hio_tx,
21810309SSriharsha.Basavapatna@Sun.COM NULL,
2192311Sseb NULL,
2202311Sseb NULL
2212311Sseb };
2222311Sseb
2231991Sheppo /*
2241991Sheppo * Linked list of "vnet_t" structures - one per instance.
2251991Sheppo */
2261991Sheppo static vnet_t *vnet_headp = NULL;
2271991Sheppo static krwlock_t vnet_rw;
2281991Sheppo
2291991Sheppo /* Tunables */
230*12011SSriharsha.Basavapatna@Sun.COM uint32_t vnet_num_descriptors = VNET_NUM_DESCRIPTORS;
231*12011SSriharsha.Basavapatna@Sun.COM
232*12011SSriharsha.Basavapatna@Sun.COM /*
233*12011SSriharsha.Basavapatna@Sun.COM * Configure tx serialization in mac layer for the vnet device. This tunable
234*12011SSriharsha.Basavapatna@Sun.COM * should be enabled to improve performance only if HybridIO is configured for
235*12011SSriharsha.Basavapatna@Sun.COM * the vnet device.
236*12011SSriharsha.Basavapatna@Sun.COM */
237*12011SSriharsha.Basavapatna@Sun.COM boolean_t vnet_mac_tx_serialize = B_FALSE;
238*12011SSriharsha.Basavapatna@Sun.COM
23911878SVenu.Iyer@Sun.COM /* Configure enqueing at Rx soft rings in mac layer for the vnet device */
24011878SVenu.Iyer@Sun.COM boolean_t vnet_mac_rx_queuing = B_TRUE;
24110309SSriharsha.Basavapatna@Sun.COM
2427529SSriharsha.Basavapatna@Sun.COM /*
2437529SSriharsha.Basavapatna@Sun.COM * Set this to non-zero to enable additional internal receive buffer pools
2447529SSriharsha.Basavapatna@Sun.COM * based on the MTU of the device for better performance at the cost of more
2457529SSriharsha.Basavapatna@Sun.COM * memory consumption. This is turned off by default, to use allocb(9F) for
2467529SSriharsha.Basavapatna@Sun.COM * receive buffer allocations of sizes > 2K.
2477529SSriharsha.Basavapatna@Sun.COM */
2487529SSriharsha.Basavapatna@Sun.COM boolean_t vnet_jumbo_rxpools = B_FALSE;
2497529SSriharsha.Basavapatna@Sun.COM
2506419Ssb155480 /* # of chains in fdb hash table */
2516419Ssb155480 uint32_t vnet_fdb_nchains = VNET_NFDB_HASH;
2526419Ssb155480
2536419Ssb155480 /* Internal tunables */
2546419Ssb155480 uint32_t vnet_ethermtu = 1500; /* mtu of the device */
2556419Ssb155480
2566419Ssb155480 /*
2576419Ssb155480 * Default vlan id. This is only used internally when the "default-vlan-id"
2586419Ssb155480 * property is not present in the MD device node. Therefore, this should not be
2596419Ssb155480 * used as a tunable; if this value is changed, the corresponding variable
2606419Ssb155480 * should be updated to the same value in vsw and also other vnets connected to
2616419Ssb155480 * the same vsw.
2626419Ssb155480 */
2636419Ssb155480 uint16_t vnet_default_vlan_id = 1;
2646419Ssb155480
2656419Ssb155480 /* delay in usec to wait for all references on a fdb entry to be dropped */
2666419Ssb155480 uint32_t vnet_fdbe_refcnt_delay = 10;
2671991Sheppo
2686495Sspeer static struct ether_addr etherbroadcastaddr = {
2696495Sspeer 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2706495Sspeer };
2716495Sspeer
27210309SSriharsha.Basavapatna@Sun.COM /* mac_open() retry delay in usec */
27310309SSriharsha.Basavapatna@Sun.COM uint32_t vnet_mac_open_delay = 100; /* 0.1 ms */
27410309SSriharsha.Basavapatna@Sun.COM
27510309SSriharsha.Basavapatna@Sun.COM /* max # of mac_open() retries */
27610309SSriharsha.Basavapatna@Sun.COM uint32_t vnet_mac_open_retries = 100;
2776495Sspeer
2781991Sheppo /*
2791991Sheppo * Property names
2801991Sheppo */
2811991Sheppo static char macaddr_propname[] = "local-mac-address";
2821991Sheppo
2831991Sheppo /*
2841991Sheppo * This is the string displayed by modinfo(1m).
2851991Sheppo */
2867529SSriharsha.Basavapatna@Sun.COM static char vnet_ident[] = "vnet driver";
2871991Sheppo extern struct mod_ops mod_driverops;
2881991Sheppo static struct cb_ops cb_vnetops = {
2891991Sheppo nulldev, /* cb_open */
2901991Sheppo nulldev, /* cb_close */
2911991Sheppo nodev, /* cb_strategy */
2921991Sheppo nodev, /* cb_print */
2931991Sheppo nodev, /* cb_dump */
2941991Sheppo nodev, /* cb_read */
2951991Sheppo nodev, /* cb_write */
2961991Sheppo nodev, /* cb_ioctl */
2971991Sheppo nodev, /* cb_devmap */
2981991Sheppo nodev, /* cb_mmap */
2991991Sheppo nodev, /* cb_segmap */
3001991Sheppo nochpoll, /* cb_chpoll */
3011991Sheppo ddi_prop_op, /* cb_prop_op */
3021991Sheppo NULL, /* cb_stream */
3031991Sheppo (int)(D_MP) /* cb_flag */
3041991Sheppo };
3051991Sheppo
3061991Sheppo static struct dev_ops vnetops = {
3071991Sheppo DEVO_REV, /* devo_rev */
3081991Sheppo 0, /* devo_refcnt */
3091991Sheppo NULL, /* devo_getinfo */
3101991Sheppo nulldev, /* devo_identify */
3111991Sheppo nulldev, /* devo_probe */
3121991Sheppo vnetattach, /* devo_attach */
3131991Sheppo vnetdetach, /* devo_detach */
3141991Sheppo nodev, /* devo_reset */
3151991Sheppo &cb_vnetops, /* devo_cb_ops */
3167656SSherry.Moore@Sun.COM (struct bus_ops *)NULL, /* devo_bus_ops */
3177656SSherry.Moore@Sun.COM NULL, /* devo_power */
3187656SSherry.Moore@Sun.COM ddi_quiesce_not_supported, /* devo_quiesce */
3191991Sheppo };
3201991Sheppo
3211991Sheppo static struct modldrv modldrv = {
3221991Sheppo &mod_driverops, /* Type of module. This one is a driver */
3231991Sheppo vnet_ident, /* ID string */
3241991Sheppo &vnetops /* driver specific ops */
3251991Sheppo };
3261991Sheppo
3271991Sheppo static struct modlinkage modlinkage = {
3281991Sheppo MODREV_1, (void *)&modldrv, NULL
3291991Sheppo };
3301991Sheppo
3314647Sraghuram #ifdef DEBUG
3321991Sheppo
333*12011SSriharsha.Basavapatna@Sun.COM #define DEBUG_PRINTF debug_printf
334*12011SSriharsha.Basavapatna@Sun.COM
3351991Sheppo /*
3361991Sheppo * Print debug messages - set to 0xf to enable all msgs
3371991Sheppo */
3384647Sraghuram int vnet_dbglevel = 0x8;
3391991Sheppo
3404647Sraghuram static void
debug_printf(const char * fname,void * arg,const char * fmt,...)3414647Sraghuram debug_printf(const char *fname, void *arg, const char *fmt, ...)
3421991Sheppo {
3431991Sheppo char buf[512];
3441991Sheppo va_list ap;
3451991Sheppo vnet_t *vnetp = (vnet_t *)arg;
3464647Sraghuram char *bufp = buf;
3471991Sheppo
3484647Sraghuram if (vnetp == NULL) {
3494647Sraghuram (void) sprintf(bufp, "%s: ", fname);
3504647Sraghuram bufp += strlen(bufp);
3514647Sraghuram } else {
3524647Sraghuram (void) sprintf(bufp, "vnet%d:%s: ", vnetp->instance, fname);
3534647Sraghuram bufp += strlen(bufp);
3544647Sraghuram }
3554647Sraghuram va_start(ap, fmt);
3564647Sraghuram (void) vsprintf(bufp, fmt, ap);
3574647Sraghuram va_end(ap);
3584647Sraghuram cmn_err(CE_CONT, "%s\n", buf);
3594647Sraghuram }
3601991Sheppo
3611991Sheppo #endif
3621991Sheppo
3631991Sheppo /* _init(9E): initialize the loadable module */
3641991Sheppo int
_init(void)3651991Sheppo _init(void)
3661991Sheppo {
3671991Sheppo int status;
3681991Sheppo
3694647Sraghuram DBG1(NULL, "enter\n");
3701991Sheppo
3711991Sheppo mac_init_ops(&vnetops, "vnet");
3721991Sheppo status = mod_install(&modlinkage);
3731991Sheppo if (status != 0) {
3741991Sheppo mac_fini_ops(&vnetops);
3751991Sheppo }
3766495Sspeer vdds_mod_init();
3774647Sraghuram DBG1(NULL, "exit(%d)\n", status);
3781991Sheppo return (status);
3791991Sheppo }
3801991Sheppo
3811991Sheppo /* _fini(9E): prepare the module for unloading. */
3821991Sheppo int
_fini(void)3831991Sheppo _fini(void)
3841991Sheppo {
3859217SWentao.Yang@Sun.COM int status;
3861991Sheppo
3874647Sraghuram DBG1(NULL, "enter\n");
3881991Sheppo
3891991Sheppo status = mod_remove(&modlinkage);
3901991Sheppo if (status != 0)
3911991Sheppo return (status);
3921991Sheppo mac_fini_ops(&vnetops);
3936495Sspeer vdds_mod_fini();
3941991Sheppo
3954647Sraghuram DBG1(NULL, "exit(%d)\n", status);
3961991Sheppo return (status);
3971991Sheppo }
3981991Sheppo
3991991Sheppo /* _info(9E): return information about the loadable module */
4001991Sheppo int
_info(struct modinfo * modinfop)4011991Sheppo _info(struct modinfo *modinfop)
4021991Sheppo {
4031991Sheppo return (mod_info(&modlinkage, modinfop));
4041991Sheppo }
4051991Sheppo
4061991Sheppo /*
4071991Sheppo * attach(9E): attach a device to the system.
4081991Sheppo * called once for each instance of the device on the system.
4091991Sheppo */
4101991Sheppo static int
vnetattach(dev_info_t * dip,ddi_attach_cmd_t cmd)4111991Sheppo vnetattach(dev_info_t *dip, ddi_attach_cmd_t cmd)
4121991Sheppo {
4139217SWentao.Yang@Sun.COM vnet_t *vnetp;
4149217SWentao.Yang@Sun.COM int status;
4159217SWentao.Yang@Sun.COM int instance;
4169217SWentao.Yang@Sun.COM uint64_t reg;
4179217SWentao.Yang@Sun.COM char qname[TASKQ_NAMELEN];
4189217SWentao.Yang@Sun.COM vnet_attach_progress_t attach_progress;
4191991Sheppo
4209217SWentao.Yang@Sun.COM attach_progress = AST_init;
4211991Sheppo
4221991Sheppo switch (cmd) {
4231991Sheppo case DDI_ATTACH:
4241991Sheppo break;
4251991Sheppo case DDI_RESUME:
4261991Sheppo case DDI_PM_RESUME:
4271991Sheppo default:
4281991Sheppo goto vnet_attach_fail;
4291991Sheppo }
4301991Sheppo
4311991Sheppo instance = ddi_get_instance(dip);
4324647Sraghuram DBG1(NULL, "instance(%d) enter\n", instance);
4331991Sheppo
4341991Sheppo /* allocate vnet_t and mac_t structures */
4351991Sheppo vnetp = kmem_zalloc(sizeof (vnet_t), KM_SLEEP);
4366495Sspeer vnetp->dip = dip;
4376495Sspeer vnetp->instance = instance;
4386495Sspeer rw_init(&vnetp->vrwlock, NULL, RW_DRIVER, NULL);
4396495Sspeer rw_init(&vnetp->vsw_fp_rw, NULL, RW_DRIVER, NULL);
4409217SWentao.Yang@Sun.COM attach_progress |= AST_vnet_alloc;
4411991Sheppo
44210309SSriharsha.Basavapatna@Sun.COM vnet_ring_grp_init(vnetp);
44310309SSriharsha.Basavapatna@Sun.COM attach_progress |= AST_ring_init;
44410309SSriharsha.Basavapatna@Sun.COM
4456495Sspeer status = vdds_init(vnetp);
4466495Sspeer if (status != 0) {
4476495Sspeer goto vnet_attach_fail;
4486495Sspeer }
4499217SWentao.Yang@Sun.COM attach_progress |= AST_vdds_init;
4506495Sspeer
4511991Sheppo /* setup links to vnet_t from both devinfo and mac_t */
4521991Sheppo ddi_set_driver_private(dip, (caddr_t)vnetp);
4531991Sheppo
4541991Sheppo /* read the mac address */
4551991Sheppo status = vnet_read_mac_address(vnetp);
4561991Sheppo if (status != DDI_SUCCESS) {
4571991Sheppo goto vnet_attach_fail;
4581991Sheppo }
4599217SWentao.Yang@Sun.COM attach_progress |= AST_read_macaddr;
4601991Sheppo
4616495Sspeer reg = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
4626495Sspeer DDI_PROP_DONTPASS, "reg", -1);
4636495Sspeer if (reg == -1) {
4646495Sspeer goto vnet_attach_fail;
4656495Sspeer }
4666495Sspeer vnetp->reg = reg;
4676495Sspeer
4686495Sspeer vnet_fdb_create(vnetp);
4699217SWentao.Yang@Sun.COM attach_progress |= AST_fdbh_alloc;
4706495Sspeer
471*12011SSriharsha.Basavapatna@Sun.COM (void) snprintf(qname, TASKQ_NAMELEN, "vres_taskq%d", instance);
4726495Sspeer if ((vnetp->taskqp = ddi_taskq_create(dip, qname, 1,
4736495Sspeer TASKQ_DEFAULTPRI, 0)) == NULL) {
4746495Sspeer cmn_err(CE_WARN, "!vnet%d: Unable to create task queue",
4756495Sspeer instance);
4766495Sspeer goto vnet_attach_fail;
4776495Sspeer }
4789217SWentao.Yang@Sun.COM attach_progress |= AST_taskq_create;
4796495Sspeer
4806495Sspeer /* add to the list of vnet devices */
4816495Sspeer WRITE_ENTER(&vnet_rw);
4826495Sspeer vnetp->nextp = vnet_headp;
4836495Sspeer vnet_headp = vnetp;
4846495Sspeer RW_EXIT(&vnet_rw);
4856495Sspeer
4869217SWentao.Yang@Sun.COM attach_progress |= AST_vnet_list;
4876495Sspeer
4881991Sheppo /*
48910309SSriharsha.Basavapatna@Sun.COM * Initialize the generic vnet plugin which provides communication via
49010309SSriharsha.Basavapatna@Sun.COM * sun4v LDC (logical domain channel) based resources. This involves 2
49110309SSriharsha.Basavapatna@Sun.COM * steps; first, vgen_init() is invoked to read the various properties
49210309SSriharsha.Basavapatna@Sun.COM * of the vnet device from its MD node (including its mtu which is
49310309SSriharsha.Basavapatna@Sun.COM * needed to mac_register()) and obtain a handle to the vgen layer.
49410309SSriharsha.Basavapatna@Sun.COM * After mac_register() is done and we have a mac handle, we then
49510309SSriharsha.Basavapatna@Sun.COM * invoke vgen_init_mdeg() which registers with the the MD event
49610309SSriharsha.Basavapatna@Sun.COM * generator (mdeg) framework to allow LDC resource notifications.
49710309SSriharsha.Basavapatna@Sun.COM * Note: this sequence also allows us to report the correct default #
49810309SSriharsha.Basavapatna@Sun.COM * of pseudo rings (2TX and 3RX) in vnet_m_capab() which gets invoked
49910309SSriharsha.Basavapatna@Sun.COM * in the context of mac_register(); and avoids conflicting with
50010309SSriharsha.Basavapatna@Sun.COM * dynamic pseudo rx rings which get added/removed as a result of mdeg
50110309SSriharsha.Basavapatna@Sun.COM * events in vgen.
5021991Sheppo */
5036495Sspeer status = vgen_init(vnetp, reg, vnetp->dip,
5046495Sspeer (uint8_t *)vnetp->curr_macaddr, &vnetp->vgenhdl);
5051991Sheppo if (status != DDI_SUCCESS) {
5064647Sraghuram DERR(vnetp, "vgen_init() failed\n");
5071991Sheppo goto vnet_attach_fail;
5081991Sheppo }
5099217SWentao.Yang@Sun.COM attach_progress |= AST_vgen_init;
5101991Sheppo
5111991Sheppo status = vnet_mac_register(vnetp);
5121991Sheppo if (status != DDI_SUCCESS) {
5131991Sheppo goto vnet_attach_fail;
5141991Sheppo }
5159336SSriharsha.Basavapatna@Sun.COM vnetp->link_state = LINK_STATE_UNKNOWN;
5169217SWentao.Yang@Sun.COM attach_progress |= AST_macreg;
5179217SWentao.Yang@Sun.COM
51810309SSriharsha.Basavapatna@Sun.COM status = vgen_init_mdeg(vnetp->vgenhdl);
51910309SSriharsha.Basavapatna@Sun.COM if (status != DDI_SUCCESS) {
52010309SSriharsha.Basavapatna@Sun.COM goto vnet_attach_fail;
52110309SSriharsha.Basavapatna@Sun.COM }
52210309SSriharsha.Basavapatna@Sun.COM attach_progress |= AST_init_mdeg;
52310309SSriharsha.Basavapatna@Sun.COM
5249217SWentao.Yang@Sun.COM vnetp->attach_progress = attach_progress;
5259217SWentao.Yang@Sun.COM
5264647Sraghuram DBG1(NULL, "instance(%d) exit\n", instance);
5271991Sheppo return (DDI_SUCCESS);
5281991Sheppo
5291991Sheppo vnet_attach_fail:
5309217SWentao.Yang@Sun.COM vnetp->attach_progress = attach_progress;
5319235SWentao.Yang@Sun.COM status = vnet_unattach(vnetp);
5329235SWentao.Yang@Sun.COM ASSERT(status == 0);
5331991Sheppo return (DDI_FAILURE);
5341991Sheppo }
5351991Sheppo
5361991Sheppo /*
5371991Sheppo * detach(9E): detach a device from the system.
5381991Sheppo */
5391991Sheppo static int
vnetdetach(dev_info_t * dip,ddi_detach_cmd_t cmd)5401991Sheppo vnetdetach(dev_info_t *dip, ddi_detach_cmd_t cmd)
5411991Sheppo {
5421991Sheppo vnet_t *vnetp;
5431991Sheppo int instance;
5441991Sheppo
5451991Sheppo instance = ddi_get_instance(dip);
5464647Sraghuram DBG1(NULL, "instance(%d) enter\n", instance);
5471991Sheppo
5481991Sheppo vnetp = ddi_get_driver_private(dip);
5491991Sheppo if (vnetp == NULL) {
5501991Sheppo goto vnet_detach_fail;
5511991Sheppo }
5521991Sheppo
5531991Sheppo switch (cmd) {
5541991Sheppo case DDI_DETACH:
5551991Sheppo break;
5561991Sheppo case DDI_SUSPEND:
5571991Sheppo case DDI_PM_SUSPEND:
5581991Sheppo default:
5591991Sheppo goto vnet_detach_fail;
5601991Sheppo }
5611991Sheppo
5629217SWentao.Yang@Sun.COM if (vnet_unattach(vnetp) != 0) {
5636495Sspeer goto vnet_detach_fail;
5642336Snarayan }
5652336Snarayan
5661991Sheppo return (DDI_SUCCESS);
5671991Sheppo
5681991Sheppo vnet_detach_fail:
5691991Sheppo return (DDI_FAILURE);
5701991Sheppo }
5711991Sheppo
5729217SWentao.Yang@Sun.COM /*
5739217SWentao.Yang@Sun.COM * Common routine to handle vnetattach() failure and vnetdetach(). Note that
5749217SWentao.Yang@Sun.COM * the only reason this function could fail is if mac_unregister() fails.
5759217SWentao.Yang@Sun.COM * Otherwise, this function must ensure that all resources are freed and return
5769217SWentao.Yang@Sun.COM * success.
5779217SWentao.Yang@Sun.COM */
5789217SWentao.Yang@Sun.COM static int
vnet_unattach(vnet_t * vnetp)5799217SWentao.Yang@Sun.COM vnet_unattach(vnet_t *vnetp)
5809217SWentao.Yang@Sun.COM {
5819217SWentao.Yang@Sun.COM vnet_attach_progress_t attach_progress;
5829217SWentao.Yang@Sun.COM
5839217SWentao.Yang@Sun.COM attach_progress = vnetp->attach_progress;
5849217SWentao.Yang@Sun.COM
5859217SWentao.Yang@Sun.COM /*
58610309SSriharsha.Basavapatna@Sun.COM * Disable the mac device in the gldv3 subsystem. This can fail, in
58710309SSriharsha.Basavapatna@Sun.COM * particular if there are still any open references to this mac
58810309SSriharsha.Basavapatna@Sun.COM * device; in which case we just return failure without continuing to
58910309SSriharsha.Basavapatna@Sun.COM * detach further.
59010309SSriharsha.Basavapatna@Sun.COM * If it succeeds, we then invoke vgen_uninit() which should unregister
59110309SSriharsha.Basavapatna@Sun.COM * any pseudo rings registered with the mac layer. Note we keep the
59210309SSriharsha.Basavapatna@Sun.COM * AST_macreg flag on, so we can unregister with the mac layer at
59310309SSriharsha.Basavapatna@Sun.COM * the end of this routine.
5949217SWentao.Yang@Sun.COM */
5959217SWentao.Yang@Sun.COM if (attach_progress & AST_macreg) {
59610309SSriharsha.Basavapatna@Sun.COM if (mac_disable(vnetp->mh) != 0) {
5979217SWentao.Yang@Sun.COM return (1);
5989217SWentao.Yang@Sun.COM }
5999217SWentao.Yang@Sun.COM }
6009217SWentao.Yang@Sun.COM
6019217SWentao.Yang@Sun.COM /*
60210309SSriharsha.Basavapatna@Sun.COM * Now that we have disabled the device, we must finish all other steps
60310309SSriharsha.Basavapatna@Sun.COM * and successfully return from this function; otherwise we will end up
60410309SSriharsha.Basavapatna@Sun.COM * leaving the device in a broken/unusable state.
6059217SWentao.Yang@Sun.COM *
6069217SWentao.Yang@Sun.COM * First, release any hybrid resources assigned to this vnet device.
6079217SWentao.Yang@Sun.COM */
6089217SWentao.Yang@Sun.COM if (attach_progress & AST_vdds_init) {
6099217SWentao.Yang@Sun.COM vdds_cleanup(vnetp);
6109217SWentao.Yang@Sun.COM attach_progress &= ~AST_vdds_init;
6119217SWentao.Yang@Sun.COM }
6129217SWentao.Yang@Sun.COM
6139217SWentao.Yang@Sun.COM /*
6149217SWentao.Yang@Sun.COM * Uninit vgen. This stops further mdeg callbacks to this vnet
6159217SWentao.Yang@Sun.COM * device and/or its ports; and detaches any existing ports.
6169217SWentao.Yang@Sun.COM */
61710309SSriharsha.Basavapatna@Sun.COM if (attach_progress & (AST_vgen_init|AST_init_mdeg)) {
6189217SWentao.Yang@Sun.COM vgen_uninit(vnetp->vgenhdl);
6199217SWentao.Yang@Sun.COM attach_progress &= ~AST_vgen_init;
62010309SSriharsha.Basavapatna@Sun.COM attach_progress &= ~AST_init_mdeg;
6219217SWentao.Yang@Sun.COM }
6229217SWentao.Yang@Sun.COM
6239217SWentao.Yang@Sun.COM /* Destroy the taskq. */
6249217SWentao.Yang@Sun.COM if (attach_progress & AST_taskq_create) {
6259217SWentao.Yang@Sun.COM ddi_taskq_destroy(vnetp->taskqp);
6269217SWentao.Yang@Sun.COM attach_progress &= ~AST_taskq_create;
6279217SWentao.Yang@Sun.COM }
6289217SWentao.Yang@Sun.COM
6299217SWentao.Yang@Sun.COM /* Destroy fdb. */
6309217SWentao.Yang@Sun.COM if (attach_progress & AST_fdbh_alloc) {
6319217SWentao.Yang@Sun.COM vnet_fdb_destroy(vnetp);
6329217SWentao.Yang@Sun.COM attach_progress &= ~AST_fdbh_alloc;
6339217SWentao.Yang@Sun.COM }
6349217SWentao.Yang@Sun.COM
6359217SWentao.Yang@Sun.COM /* Remove from the device list */
6369217SWentao.Yang@Sun.COM if (attach_progress & AST_vnet_list) {
6379217SWentao.Yang@Sun.COM vnet_t **vnetpp;
6389217SWentao.Yang@Sun.COM /* unlink from instance(vnet_t) list */
6399217SWentao.Yang@Sun.COM WRITE_ENTER(&vnet_rw);
6409217SWentao.Yang@Sun.COM for (vnetpp = &vnet_headp; *vnetpp;
6419217SWentao.Yang@Sun.COM vnetpp = &(*vnetpp)->nextp) {
6429217SWentao.Yang@Sun.COM if (*vnetpp == vnetp) {
6439217SWentao.Yang@Sun.COM *vnetpp = vnetp->nextp;
6449217SWentao.Yang@Sun.COM break;
6459217SWentao.Yang@Sun.COM }
6469217SWentao.Yang@Sun.COM }
6479217SWentao.Yang@Sun.COM RW_EXIT(&vnet_rw);
6489217SWentao.Yang@Sun.COM attach_progress &= ~AST_vnet_list;
6499217SWentao.Yang@Sun.COM }
6509217SWentao.Yang@Sun.COM
65110309SSriharsha.Basavapatna@Sun.COM if (attach_progress & AST_ring_init) {
65210309SSriharsha.Basavapatna@Sun.COM vnet_ring_grp_uninit(vnetp);
65310309SSriharsha.Basavapatna@Sun.COM attach_progress &= ~AST_ring_init;
65410309SSriharsha.Basavapatna@Sun.COM }
65510309SSriharsha.Basavapatna@Sun.COM
65610309SSriharsha.Basavapatna@Sun.COM if (attach_progress & AST_macreg) {
65710309SSriharsha.Basavapatna@Sun.COM VERIFY(mac_unregister(vnetp->mh) == 0);
65810309SSriharsha.Basavapatna@Sun.COM vnetp->mh = NULL;
65910309SSriharsha.Basavapatna@Sun.COM attach_progress &= ~AST_macreg;
66010309SSriharsha.Basavapatna@Sun.COM }
66110309SSriharsha.Basavapatna@Sun.COM
6629217SWentao.Yang@Sun.COM if (attach_progress & AST_vnet_alloc) {
6639217SWentao.Yang@Sun.COM rw_destroy(&vnetp->vrwlock);
6649217SWentao.Yang@Sun.COM rw_destroy(&vnetp->vsw_fp_rw);
6659217SWentao.Yang@Sun.COM attach_progress &= ~AST_vnet_list;
6669217SWentao.Yang@Sun.COM KMEM_FREE(vnetp);
6679217SWentao.Yang@Sun.COM }
6689217SWentao.Yang@Sun.COM
6699217SWentao.Yang@Sun.COM return (0);
6709217SWentao.Yang@Sun.COM }
6719217SWentao.Yang@Sun.COM
6721991Sheppo /* enable the device for transmit/receive */
6731991Sheppo static int
vnet_m_start(void * arg)6741991Sheppo vnet_m_start(void *arg)
6751991Sheppo {
6761991Sheppo vnet_t *vnetp = arg;
6771991Sheppo
6784647Sraghuram DBG1(vnetp, "enter\n");
6791991Sheppo
6806495Sspeer WRITE_ENTER(&vnetp->vrwlock);
6816495Sspeer vnetp->flags |= VNET_STARTED;
6826495Sspeer vnet_start_resources(vnetp);
6836495Sspeer RW_EXIT(&vnetp->vrwlock);
6841991Sheppo
6854647Sraghuram DBG1(vnetp, "exit\n");
6861991Sheppo return (VNET_SUCCESS);
6871991Sheppo
6881991Sheppo }
6891991Sheppo
6901991Sheppo /* stop transmit/receive for the device */
6911991Sheppo static void
vnet_m_stop(void * arg)6921991Sheppo vnet_m_stop(void *arg)
6931991Sheppo {
6941991Sheppo vnet_t *vnetp = arg;
6951991Sheppo
6964647Sraghuram DBG1(vnetp, "enter\n");
6971991Sheppo
6986495Sspeer WRITE_ENTER(&vnetp->vrwlock);
6996495Sspeer if (vnetp->flags & VNET_STARTED) {
7009805SSriharsha.Basavapatna@Sun.COM /*
7019805SSriharsha.Basavapatna@Sun.COM * Set the flags appropriately; this should prevent starting of
7029805SSriharsha.Basavapatna@Sun.COM * any new resources that are added(see vnet_res_start_task()),
7039805SSriharsha.Basavapatna@Sun.COM * while we release the vrwlock in vnet_stop_resources() before
7049805SSriharsha.Basavapatna@Sun.COM * stopping each resource.
7059805SSriharsha.Basavapatna@Sun.COM */
7069805SSriharsha.Basavapatna@Sun.COM vnetp->flags &= ~VNET_STARTED;
7079805SSriharsha.Basavapatna@Sun.COM vnetp->flags |= VNET_STOPPING;
7086495Sspeer vnet_stop_resources(vnetp);
7099805SSriharsha.Basavapatna@Sun.COM vnetp->flags &= ~VNET_STOPPING;
7101991Sheppo }
7116495Sspeer RW_EXIT(&vnetp->vrwlock);
7121991Sheppo
7134647Sraghuram DBG1(vnetp, "exit\n");
7141991Sheppo }
7151991Sheppo
7161991Sheppo /* set the unicast mac address of the device */
7171991Sheppo static int
vnet_m_unicst(void * arg,const uint8_t * macaddr)7181991Sheppo vnet_m_unicst(void *arg, const uint8_t *macaddr)
7191991Sheppo {
7201991Sheppo _NOTE(ARGUNUSED(macaddr))
7211991Sheppo
7221991Sheppo vnet_t *vnetp = arg;
7231991Sheppo
7244647Sraghuram DBG1(vnetp, "enter\n");
7251991Sheppo /*
7262793Slm66018 * NOTE: setting mac address dynamically is not supported.
7271991Sheppo */
7284647Sraghuram DBG1(vnetp, "exit\n");
7291991Sheppo
7302109Slm66018 return (VNET_FAILURE);
7311991Sheppo }
7321991Sheppo
7331991Sheppo /* enable/disable a multicast address */
7341991Sheppo static int
vnet_m_multicst(void * arg,boolean_t add,const uint8_t * mca)7351991Sheppo vnet_m_multicst(void *arg, boolean_t add, const uint8_t *mca)
7361991Sheppo {
7371991Sheppo _NOTE(ARGUNUSED(add, mca))
7381991Sheppo
73911543SWentao.Yang@Sun.COM vnet_t *vnetp = arg;
7406495Sspeer vnet_res_t *vresp;
7416495Sspeer mac_register_t *macp;
7422311Sseb mac_callbacks_t *cbp;
74311543SWentao.Yang@Sun.COM int rv = VNET_SUCCESS;
7441991Sheppo
7454647Sraghuram DBG1(vnetp, "enter\n");
7466495Sspeer
74711543SWentao.Yang@Sun.COM READ_ENTER(&vnetp->vsw_fp_rw);
74811543SWentao.Yang@Sun.COM if (vnetp->vsw_fp == NULL) {
74911543SWentao.Yang@Sun.COM RW_EXIT(&vnetp->vsw_fp_rw);
75011543SWentao.Yang@Sun.COM return (EAGAIN);
7511991Sheppo }
75211543SWentao.Yang@Sun.COM VNET_FDBE_REFHOLD(vnetp->vsw_fp);
75311543SWentao.Yang@Sun.COM RW_EXIT(&vnetp->vsw_fp_rw);
75411543SWentao.Yang@Sun.COM
75511543SWentao.Yang@Sun.COM vresp = vnetp->vsw_fp;
75611543SWentao.Yang@Sun.COM macp = &vresp->macreg;
75711543SWentao.Yang@Sun.COM cbp = macp->m_callbacks;
75811543SWentao.Yang@Sun.COM rv = cbp->mc_multicst(macp->m_driver, add, mca);
75911543SWentao.Yang@Sun.COM
76011543SWentao.Yang@Sun.COM VNET_FDBE_REFRELE(vnetp->vsw_fp);
7616495Sspeer
7624647Sraghuram DBG1(vnetp, "exit(%d)\n", rv);
7631991Sheppo return (rv);
7641991Sheppo }
7651991Sheppo
7661991Sheppo /* set or clear promiscuous mode on the device */
7671991Sheppo static int
vnet_m_promisc(void * arg,boolean_t on)7681991Sheppo vnet_m_promisc(void *arg, boolean_t on)
7691991Sheppo {
7701991Sheppo _NOTE(ARGUNUSED(on))
7711991Sheppo
7721991Sheppo vnet_t *vnetp = arg;
7734647Sraghuram DBG1(vnetp, "enter\n");
7741991Sheppo /*
7752793Slm66018 * NOTE: setting promiscuous mode is not supported, just return success.
7761991Sheppo */
7774647Sraghuram DBG1(vnetp, "exit\n");
7781991Sheppo return (VNET_SUCCESS);
7791991Sheppo }
7801991Sheppo
7811991Sheppo /*
7821991Sheppo * Transmit a chain of packets. This function provides switching functionality
7831991Sheppo * based on the destination mac address to reach other guests (within ldoms) or
7841991Sheppo * external hosts.
7851991Sheppo */
7861991Sheppo mblk_t *
vnet_tx_ring_send(void * arg,mblk_t * mp)78710309SSriharsha.Basavapatna@Sun.COM vnet_tx_ring_send(void *arg, mblk_t *mp)
7881991Sheppo {
78910309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_tx_ring_t *tx_ringp;
79011878SVenu.Iyer@Sun.COM vnet_tx_ring_stats_t *statsp;
7916419Ssb155480 vnet_t *vnetp;
7926495Sspeer vnet_res_t *vresp;
7936419Ssb155480 mblk_t *next;
7946495Sspeer mblk_t *resid_mp;
7956495Sspeer mac_register_t *macp;
7966495Sspeer struct ether_header *ehp;
7976495Sspeer boolean_t is_unicast;
7987896SSriharsha.Basavapatna@Sun.COM boolean_t is_pvid; /* non-default pvid ? */
7997896SSriharsha.Basavapatna@Sun.COM boolean_t hres; /* Hybrid resource ? */
80010309SSriharsha.Basavapatna@Sun.COM void *tx_arg;
80111878SVenu.Iyer@Sun.COM size_t size;
80210309SSriharsha.Basavapatna@Sun.COM
80310309SSriharsha.Basavapatna@Sun.COM tx_ringp = (vnet_pseudo_tx_ring_t *)arg;
80411878SVenu.Iyer@Sun.COM statsp = &tx_ringp->tx_ring_stats;
80510309SSriharsha.Basavapatna@Sun.COM vnetp = (vnet_t *)tx_ringp->vnetp;
8064647Sraghuram DBG1(vnetp, "enter\n");
8071991Sheppo ASSERT(mp != NULL);
8081991Sheppo
8097896SSriharsha.Basavapatna@Sun.COM is_pvid = (vnetp->pvid != vnetp->default_vlan_id) ? B_TRUE : B_FALSE;
8107896SSriharsha.Basavapatna@Sun.COM
8111991Sheppo while (mp != NULL) {
8126419Ssb155480
8131991Sheppo next = mp->b_next;
8141991Sheppo mp->b_next = NULL;
8151991Sheppo
81611878SVenu.Iyer@Sun.COM /* update stats */
81711878SVenu.Iyer@Sun.COM size = msgsize(mp);
81811878SVenu.Iyer@Sun.COM
8196419Ssb155480 /*
8206419Ssb155480 * Find fdb entry for the destination
8216419Ssb155480 * and hold a reference to it.
8226419Ssb155480 */
8231991Sheppo ehp = (struct ether_header *)mp->b_rptr;
8246495Sspeer vresp = vnet_fdbe_find(vnetp, &ehp->ether_dhost);
8256495Sspeer if (vresp != NULL) {
8261991Sheppo
8271991Sheppo /*
8286419Ssb155480 * Destination found in FDB.
8296419Ssb155480 * The destination is a vnet device within ldoms
8306419Ssb155480 * and directly reachable, invoke the tx function
8316419Ssb155480 * in the fdb entry.
8321991Sheppo */
8336495Sspeer macp = &vresp->macreg;
8346495Sspeer resid_mp = macp->m_callbacks->mc_tx(macp->m_driver, mp);
8356419Ssb155480
8366419Ssb155480 /* tx done; now release ref on fdb entry */
8376495Sspeer VNET_FDBE_REFRELE(vresp);
8386419Ssb155480
8391991Sheppo if (resid_mp != NULL) {
8401991Sheppo /* m_tx failed */
8411991Sheppo mp->b_next = next;
8421991Sheppo break;
8431991Sheppo }
8441991Sheppo } else {
8456495Sspeer is_unicast = !(IS_BROADCAST(ehp) ||
8466495Sspeer (IS_MULTICAST(ehp)));
8471991Sheppo /*
8486419Ssb155480 * Destination is not in FDB.
8496495Sspeer * If the destination is broadcast or multicast,
8506495Sspeer * then forward the packet to vswitch.
8516495Sspeer * If a Hybrid resource avilable, then send the
8526495Sspeer * unicast packet via hybrid resource, otherwise
8536495Sspeer * forward it to vswitch.
8541991Sheppo */
8556419Ssb155480 READ_ENTER(&vnetp->vsw_fp_rw);
8566419Ssb155480
8576495Sspeer if ((is_unicast) && (vnetp->hio_fp != NULL)) {
8586495Sspeer vresp = vnetp->hio_fp;
8597896SSriharsha.Basavapatna@Sun.COM hres = B_TRUE;
8606495Sspeer } else {
8616495Sspeer vresp = vnetp->vsw_fp;
8627896SSriharsha.Basavapatna@Sun.COM hres = B_FALSE;
8636495Sspeer }
8646495Sspeer if (vresp == NULL) {
8656419Ssb155480 /*
8666419Ssb155480 * no fdb entry to vsw? drop the packet.
8676419Ssb155480 */
8686419Ssb155480 RW_EXIT(&vnetp->vsw_fp_rw);
8691991Sheppo freemsg(mp);
8706419Ssb155480 mp = next;
8716419Ssb155480 continue;
8721991Sheppo }
8736419Ssb155480
8746419Ssb155480 /* ref hold the fdb entry to vsw */
8756495Sspeer VNET_FDBE_REFHOLD(vresp);
8766419Ssb155480
8776419Ssb155480 RW_EXIT(&vnetp->vsw_fp_rw);
8786419Ssb155480
8797896SSriharsha.Basavapatna@Sun.COM /*
8807896SSriharsha.Basavapatna@Sun.COM * In the case of a hybrid resource we need to insert
8817896SSriharsha.Basavapatna@Sun.COM * the tag for the pvid case here; unlike packets that
8827896SSriharsha.Basavapatna@Sun.COM * are destined to a vnet/vsw in which case the vgen
8837896SSriharsha.Basavapatna@Sun.COM * layer does the tagging before sending it over ldc.
8847896SSriharsha.Basavapatna@Sun.COM */
8857896SSriharsha.Basavapatna@Sun.COM if (hres == B_TRUE) {
8867896SSriharsha.Basavapatna@Sun.COM /*
8877896SSriharsha.Basavapatna@Sun.COM * Determine if the frame being transmitted
8887896SSriharsha.Basavapatna@Sun.COM * over the hybrid resource is untagged. If so,
8897896SSriharsha.Basavapatna@Sun.COM * insert the tag before transmitting.
8907896SSriharsha.Basavapatna@Sun.COM */
8917896SSriharsha.Basavapatna@Sun.COM if (is_pvid == B_TRUE &&
8927896SSriharsha.Basavapatna@Sun.COM ehp->ether_type != htons(ETHERTYPE_VLAN)) {
8937896SSriharsha.Basavapatna@Sun.COM
8947896SSriharsha.Basavapatna@Sun.COM mp = vnet_vlan_insert_tag(mp,
8957896SSriharsha.Basavapatna@Sun.COM vnetp->pvid);
8967896SSriharsha.Basavapatna@Sun.COM if (mp == NULL) {
8977896SSriharsha.Basavapatna@Sun.COM VNET_FDBE_REFRELE(vresp);
8987896SSriharsha.Basavapatna@Sun.COM mp = next;
8997896SSriharsha.Basavapatna@Sun.COM continue;
9007896SSriharsha.Basavapatna@Sun.COM }
9017896SSriharsha.Basavapatna@Sun.COM
9027896SSriharsha.Basavapatna@Sun.COM }
90310309SSriharsha.Basavapatna@Sun.COM
90410309SSriharsha.Basavapatna@Sun.COM macp = &vresp->macreg;
90510309SSriharsha.Basavapatna@Sun.COM tx_arg = tx_ringp;
90610309SSriharsha.Basavapatna@Sun.COM } else {
90710309SSriharsha.Basavapatna@Sun.COM macp = &vresp->macreg;
90810309SSriharsha.Basavapatna@Sun.COM tx_arg = macp->m_driver;
9097896SSriharsha.Basavapatna@Sun.COM }
91010309SSriharsha.Basavapatna@Sun.COM resid_mp = macp->m_callbacks->mc_tx(tx_arg, mp);
9116419Ssb155480
9126419Ssb155480 /* tx done; now release ref on fdb entry */
9136495Sspeer VNET_FDBE_REFRELE(vresp);
9146419Ssb155480
9156419Ssb155480 if (resid_mp != NULL) {
9166419Ssb155480 /* m_tx failed */
9176419Ssb155480 mp->b_next = next;
9186419Ssb155480 break;
9196419Ssb155480 }
9201991Sheppo }
9211991Sheppo
92211878SVenu.Iyer@Sun.COM statsp->obytes += size;
92311878SVenu.Iyer@Sun.COM statsp->opackets++;
9241991Sheppo mp = next;
9251991Sheppo }
9261991Sheppo
9274647Sraghuram DBG1(vnetp, "exit\n");
9281991Sheppo return (mp);
9291991Sheppo }
9301991Sheppo
9312311Sseb /* get statistics from the device */
9322311Sseb int
vnet_m_stat(void * arg,uint_t stat,uint64_t * val)9332311Sseb vnet_m_stat(void *arg, uint_t stat, uint64_t *val)
9341991Sheppo {
9351991Sheppo vnet_t *vnetp = arg;
9366495Sspeer vnet_res_t *vresp;
9376495Sspeer mac_register_t *macp;
9382311Sseb mac_callbacks_t *cbp;
9392311Sseb uint64_t val_total = 0;
9401991Sheppo
9414647Sraghuram DBG1(vnetp, "enter\n");
9421991Sheppo
9431991Sheppo /*
9442311Sseb * get the specified statistic from each transport and return the
9452311Sseb * aggregate val. This obviously only works for counters.
9461991Sheppo */
9472311Sseb if ((IS_MAC_STAT(stat) && !MAC_STAT_ISACOUNTER(stat)) ||
9482311Sseb (IS_MACTYPE_STAT(stat) && !ETHER_STAT_ISACOUNTER(stat))) {
9492311Sseb return (ENOTSUP);
9502311Sseb }
9516495Sspeer
9526495Sspeer READ_ENTER(&vnetp->vrwlock);
9536495Sspeer for (vresp = vnetp->vres_list; vresp != NULL; vresp = vresp->nextp) {
9546495Sspeer macp = &vresp->macreg;
9556495Sspeer cbp = macp->m_callbacks;
9566495Sspeer if (cbp->mc_getstat(macp->m_driver, stat, val) == 0)
9572311Sseb val_total += *val;
9581991Sheppo }
9596495Sspeer RW_EXIT(&vnetp->vrwlock);
9601991Sheppo
9612311Sseb *val = val_total;
9622311Sseb
9634647Sraghuram DBG1(vnetp, "exit\n");
9642311Sseb return (0);
9651991Sheppo }
9661991Sheppo
96710309SSriharsha.Basavapatna@Sun.COM static void
vnet_ring_grp_init(vnet_t * vnetp)96810309SSriharsha.Basavapatna@Sun.COM vnet_ring_grp_init(vnet_t *vnetp)
96910309SSriharsha.Basavapatna@Sun.COM {
97010309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_rx_group_t *rx_grp;
97110309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_rx_ring_t *rx_ringp;
97210309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_tx_group_t *tx_grp;
97310309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_tx_ring_t *tx_ringp;
97410309SSriharsha.Basavapatna@Sun.COM int i;
97510309SSriharsha.Basavapatna@Sun.COM
97610309SSriharsha.Basavapatna@Sun.COM tx_grp = &vnetp->tx_grp[0];
97710309SSriharsha.Basavapatna@Sun.COM tx_ringp = kmem_zalloc(sizeof (vnet_pseudo_tx_ring_t) *
97810309SSriharsha.Basavapatna@Sun.COM VNET_NUM_PSEUDO_TXRINGS, KM_SLEEP);
97910309SSriharsha.Basavapatna@Sun.COM for (i = 0; i < VNET_NUM_PSEUDO_TXRINGS; i++) {
98010309SSriharsha.Basavapatna@Sun.COM tx_ringp[i].state |= VNET_TXRING_SHARED;
98110309SSriharsha.Basavapatna@Sun.COM }
98210309SSriharsha.Basavapatna@Sun.COM tx_grp->rings = tx_ringp;
98310309SSriharsha.Basavapatna@Sun.COM tx_grp->ring_cnt = VNET_NUM_PSEUDO_TXRINGS;
98411878SVenu.Iyer@Sun.COM mutex_init(&tx_grp->flowctl_lock, NULL, MUTEX_DRIVER, NULL);
98511878SVenu.Iyer@Sun.COM cv_init(&tx_grp->flowctl_cv, NULL, CV_DRIVER, NULL);
98611878SVenu.Iyer@Sun.COM tx_grp->flowctl_thread = thread_create(NULL, 0,
98711878SVenu.Iyer@Sun.COM vnet_tx_notify_thread, tx_grp, 0, &p0, TS_RUN, minclsyspri);
98810309SSriharsha.Basavapatna@Sun.COM
98910309SSriharsha.Basavapatna@Sun.COM rx_grp = &vnetp->rx_grp[0];
99010309SSriharsha.Basavapatna@Sun.COM rx_grp->max_ring_cnt = MAX_RINGS_PER_GROUP;
99110309SSriharsha.Basavapatna@Sun.COM rw_init(&rx_grp->lock, NULL, RW_DRIVER, NULL);
99210309SSriharsha.Basavapatna@Sun.COM rx_ringp = kmem_zalloc(sizeof (vnet_pseudo_rx_ring_t) *
99310309SSriharsha.Basavapatna@Sun.COM rx_grp->max_ring_cnt, KM_SLEEP);
99410309SSriharsha.Basavapatna@Sun.COM
99510309SSriharsha.Basavapatna@Sun.COM /*
99610309SSriharsha.Basavapatna@Sun.COM * Setup the first 3 Pseudo RX Rings that are reserved;
99710309SSriharsha.Basavapatna@Sun.COM * 1 for LDC resource to vswitch + 2 for RX rings of Hybrid resource.
99810309SSriharsha.Basavapatna@Sun.COM */
99910309SSriharsha.Basavapatna@Sun.COM rx_ringp[0].state |= VNET_RXRING_INUSE|VNET_RXRING_LDC_SERVICE;
100010309SSriharsha.Basavapatna@Sun.COM rx_ringp[0].index = 0;
100110309SSriharsha.Basavapatna@Sun.COM rx_ringp[1].state |= VNET_RXRING_INUSE|VNET_RXRING_HYBRID;
100210309SSriharsha.Basavapatna@Sun.COM rx_ringp[1].index = 1;
100310309SSriharsha.Basavapatna@Sun.COM rx_ringp[2].state |= VNET_RXRING_INUSE|VNET_RXRING_HYBRID;
100410309SSriharsha.Basavapatna@Sun.COM rx_ringp[2].index = 2;
100510309SSriharsha.Basavapatna@Sun.COM
100610309SSriharsha.Basavapatna@Sun.COM rx_grp->ring_cnt = VNET_NUM_PSEUDO_RXRINGS_DEFAULT;
100710309SSriharsha.Basavapatna@Sun.COM rx_grp->rings = rx_ringp;
100810309SSriharsha.Basavapatna@Sun.COM
100910309SSriharsha.Basavapatna@Sun.COM for (i = VNET_NUM_PSEUDO_RXRINGS_DEFAULT;
101010309SSriharsha.Basavapatna@Sun.COM i < rx_grp->max_ring_cnt; i++) {
101110309SSriharsha.Basavapatna@Sun.COM rx_ringp = &rx_grp->rings[i];
101210309SSriharsha.Basavapatna@Sun.COM rx_ringp->state = VNET_RXRING_FREE;
101310309SSriharsha.Basavapatna@Sun.COM rx_ringp->index = i;
101410309SSriharsha.Basavapatna@Sun.COM }
101510309SSriharsha.Basavapatna@Sun.COM }
101610309SSriharsha.Basavapatna@Sun.COM
101710309SSriharsha.Basavapatna@Sun.COM static void
vnet_ring_grp_uninit(vnet_t * vnetp)101810309SSriharsha.Basavapatna@Sun.COM vnet_ring_grp_uninit(vnet_t *vnetp)
101910309SSriharsha.Basavapatna@Sun.COM {
102010309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_rx_group_t *rx_grp;
102110309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_tx_group_t *tx_grp;
102211878SVenu.Iyer@Sun.COM kt_did_t tid = 0;
102310309SSriharsha.Basavapatna@Sun.COM
102410309SSriharsha.Basavapatna@Sun.COM tx_grp = &vnetp->tx_grp[0];
102511878SVenu.Iyer@Sun.COM
102611878SVenu.Iyer@Sun.COM /* Inform tx_notify_thread to exit */
102711878SVenu.Iyer@Sun.COM mutex_enter(&tx_grp->flowctl_lock);
102811878SVenu.Iyer@Sun.COM if (tx_grp->flowctl_thread != NULL) {
102911878SVenu.Iyer@Sun.COM tid = tx_grp->flowctl_thread->t_did;
103011878SVenu.Iyer@Sun.COM tx_grp->flowctl_done = B_TRUE;
103111878SVenu.Iyer@Sun.COM cv_signal(&tx_grp->flowctl_cv);
103211878SVenu.Iyer@Sun.COM }
103311878SVenu.Iyer@Sun.COM mutex_exit(&tx_grp->flowctl_lock);
103411878SVenu.Iyer@Sun.COM if (tid != 0)
103511878SVenu.Iyer@Sun.COM thread_join(tid);
103611878SVenu.Iyer@Sun.COM
103710309SSriharsha.Basavapatna@Sun.COM if (tx_grp->rings != NULL) {
103810309SSriharsha.Basavapatna@Sun.COM ASSERT(tx_grp->ring_cnt == VNET_NUM_PSEUDO_TXRINGS);
103910309SSriharsha.Basavapatna@Sun.COM kmem_free(tx_grp->rings, sizeof (vnet_pseudo_tx_ring_t) *
104010309SSriharsha.Basavapatna@Sun.COM tx_grp->ring_cnt);
104110309SSriharsha.Basavapatna@Sun.COM tx_grp->rings = NULL;
104210309SSriharsha.Basavapatna@Sun.COM }
104310309SSriharsha.Basavapatna@Sun.COM
104410309SSriharsha.Basavapatna@Sun.COM rx_grp = &vnetp->rx_grp[0];
104510309SSriharsha.Basavapatna@Sun.COM if (rx_grp->rings != NULL) {
104610309SSriharsha.Basavapatna@Sun.COM ASSERT(rx_grp->max_ring_cnt == MAX_RINGS_PER_GROUP);
104710309SSriharsha.Basavapatna@Sun.COM ASSERT(rx_grp->ring_cnt == VNET_NUM_PSEUDO_RXRINGS_DEFAULT);
104810309SSriharsha.Basavapatna@Sun.COM kmem_free(rx_grp->rings, sizeof (vnet_pseudo_rx_ring_t) *
104910309SSriharsha.Basavapatna@Sun.COM rx_grp->max_ring_cnt);
105010309SSriharsha.Basavapatna@Sun.COM rx_grp->rings = NULL;
105110309SSriharsha.Basavapatna@Sun.COM }
105210309SSriharsha.Basavapatna@Sun.COM }
105310309SSriharsha.Basavapatna@Sun.COM
105410309SSriharsha.Basavapatna@Sun.COM static vnet_pseudo_rx_ring_t *
vnet_alloc_pseudo_rx_ring(vnet_t * vnetp)105510309SSriharsha.Basavapatna@Sun.COM vnet_alloc_pseudo_rx_ring(vnet_t *vnetp)
105610309SSriharsha.Basavapatna@Sun.COM {
105710309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_rx_group_t *rx_grp;
105810309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_rx_ring_t *rx_ringp;
105910309SSriharsha.Basavapatna@Sun.COM int index;
106010309SSriharsha.Basavapatna@Sun.COM
106110309SSriharsha.Basavapatna@Sun.COM rx_grp = &vnetp->rx_grp[0];
106210309SSriharsha.Basavapatna@Sun.COM WRITE_ENTER(&rx_grp->lock);
106310309SSriharsha.Basavapatna@Sun.COM
106410309SSriharsha.Basavapatna@Sun.COM if (rx_grp->ring_cnt == rx_grp->max_ring_cnt) {
106510309SSriharsha.Basavapatna@Sun.COM /* no rings available */
106610309SSriharsha.Basavapatna@Sun.COM RW_EXIT(&rx_grp->lock);
106710309SSriharsha.Basavapatna@Sun.COM return (NULL);
106810309SSriharsha.Basavapatna@Sun.COM }
106910309SSriharsha.Basavapatna@Sun.COM
107010309SSriharsha.Basavapatna@Sun.COM for (index = VNET_NUM_PSEUDO_RXRINGS_DEFAULT;
107110309SSriharsha.Basavapatna@Sun.COM index < rx_grp->max_ring_cnt; index++) {
107210309SSriharsha.Basavapatna@Sun.COM rx_ringp = &rx_grp->rings[index];
107310309SSriharsha.Basavapatna@Sun.COM if (rx_ringp->state == VNET_RXRING_FREE) {
107410309SSriharsha.Basavapatna@Sun.COM rx_ringp->state |= VNET_RXRING_INUSE;
107510309SSriharsha.Basavapatna@Sun.COM rx_grp->ring_cnt++;
107610309SSriharsha.Basavapatna@Sun.COM break;
107710309SSriharsha.Basavapatna@Sun.COM }
107810309SSriharsha.Basavapatna@Sun.COM }
107910309SSriharsha.Basavapatna@Sun.COM
108010309SSriharsha.Basavapatna@Sun.COM RW_EXIT(&rx_grp->lock);
108110309SSriharsha.Basavapatna@Sun.COM return (rx_ringp);
108210309SSriharsha.Basavapatna@Sun.COM }
108310309SSriharsha.Basavapatna@Sun.COM
108410309SSriharsha.Basavapatna@Sun.COM static void
vnet_free_pseudo_rx_ring(vnet_t * vnetp,vnet_pseudo_rx_ring_t * ringp)108510309SSriharsha.Basavapatna@Sun.COM vnet_free_pseudo_rx_ring(vnet_t *vnetp, vnet_pseudo_rx_ring_t *ringp)
108610309SSriharsha.Basavapatna@Sun.COM {
108710309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_rx_group_t *rx_grp;
108810309SSriharsha.Basavapatna@Sun.COM
108910309SSriharsha.Basavapatna@Sun.COM ASSERT(ringp->index >= VNET_NUM_PSEUDO_RXRINGS_DEFAULT);
109010309SSriharsha.Basavapatna@Sun.COM rx_grp = &vnetp->rx_grp[0];
109110309SSriharsha.Basavapatna@Sun.COM WRITE_ENTER(&rx_grp->lock);
109210309SSriharsha.Basavapatna@Sun.COM
109310309SSriharsha.Basavapatna@Sun.COM if (ringp->state != VNET_RXRING_FREE) {
109410309SSriharsha.Basavapatna@Sun.COM ringp->state = VNET_RXRING_FREE;
109510309SSriharsha.Basavapatna@Sun.COM ringp->handle = NULL;
109610309SSriharsha.Basavapatna@Sun.COM rx_grp->ring_cnt--;
109710309SSriharsha.Basavapatna@Sun.COM }
109810309SSriharsha.Basavapatna@Sun.COM
109910309SSriharsha.Basavapatna@Sun.COM RW_EXIT(&rx_grp->lock);
110010309SSriharsha.Basavapatna@Sun.COM }
110110309SSriharsha.Basavapatna@Sun.COM
11021991Sheppo /* wrapper function for mac_register() */
11031991Sheppo static int
vnet_mac_register(vnet_t * vnetp)11041991Sheppo vnet_mac_register(vnet_t *vnetp)
11051991Sheppo {
11062311Sseb mac_register_t *macp;
11072311Sseb int err;
11081991Sheppo
11092311Sseb if ((macp = mac_alloc(MAC_VERSION)) == NULL)
11102311Sseb return (DDI_FAILURE);
11112311Sseb macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
11122311Sseb macp->m_driver = vnetp;
11131991Sheppo macp->m_dip = vnetp->dip;
11142311Sseb macp->m_src_addr = vnetp->curr_macaddr;
11152311Sseb macp->m_callbacks = &vnet_m_callbacks;
11162311Sseb macp->m_min_sdu = 0;
11177529SSriharsha.Basavapatna@Sun.COM macp->m_max_sdu = vnetp->mtu;
11186419Ssb155480 macp->m_margin = VLAN_TAGSZ;
11191991Sheppo
112010309SSriharsha.Basavapatna@Sun.COM macp->m_v12n = MAC_VIRT_LEVEL1;
112110309SSriharsha.Basavapatna@Sun.COM
112210309SSriharsha.Basavapatna@Sun.COM /*
11231991Sheppo * Finally, we're ready to register ourselves with the MAC layer
11241991Sheppo * interface; if this succeeds, we're all ready to start()
11251991Sheppo */
11262311Sseb err = mac_register(macp, &vnetp->mh);
11272311Sseb mac_free(macp);
11282311Sseb return (err == 0 ? DDI_SUCCESS : DDI_FAILURE);
11291991Sheppo }
11301991Sheppo
11311991Sheppo /* read the mac address of the device */
11321991Sheppo static int
vnet_read_mac_address(vnet_t * vnetp)11331991Sheppo vnet_read_mac_address(vnet_t *vnetp)
11341991Sheppo {
11351991Sheppo uchar_t *macaddr;
11361991Sheppo uint32_t size;
11371991Sheppo int rv;
11381991Sheppo
11391991Sheppo rv = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, vnetp->dip,
11404650Sraghuram DDI_PROP_DONTPASS, macaddr_propname, &macaddr, &size);
11411991Sheppo if ((rv != DDI_PROP_SUCCESS) || (size != ETHERADDRL)) {
11424647Sraghuram DWARN(vnetp, "prop_lookup failed(%s) err(%d)\n",
11434647Sraghuram macaddr_propname, rv);
11441991Sheppo return (DDI_FAILURE);
11451991Sheppo }
11461991Sheppo bcopy(macaddr, (caddr_t)vnetp->vendor_addr, ETHERADDRL);
11471991Sheppo bcopy(macaddr, (caddr_t)vnetp->curr_macaddr, ETHERADDRL);
11481991Sheppo ddi_prop_free(macaddr);
11491991Sheppo
11501991Sheppo return (DDI_SUCCESS);
11511991Sheppo }
11521991Sheppo
11536419Ssb155480 static void
vnet_fdb_create(vnet_t * vnetp)11546419Ssb155480 vnet_fdb_create(vnet_t *vnetp)
11551991Sheppo {
11566419Ssb155480 char hashname[MAXNAMELEN];
11571991Sheppo
11586419Ssb155480 (void) snprintf(hashname, MAXNAMELEN, "vnet%d-fdbhash",
11596419Ssb155480 vnetp->instance);
11606419Ssb155480 vnetp->fdb_nchains = vnet_fdb_nchains;
11616419Ssb155480 vnetp->fdb_hashp = mod_hash_create_ptrhash(hashname, vnetp->fdb_nchains,
11626419Ssb155480 mod_hash_null_valdtor, sizeof (void *));
11636419Ssb155480 }
11641991Sheppo
11656419Ssb155480 static void
vnet_fdb_destroy(vnet_t * vnetp)11666419Ssb155480 vnet_fdb_destroy(vnet_t *vnetp)
11676419Ssb155480 {
11686419Ssb155480 /* destroy fdb-hash-table */
11696419Ssb155480 if (vnetp->fdb_hashp != NULL) {
11706419Ssb155480 mod_hash_destroy_hash(vnetp->fdb_hashp);
11716419Ssb155480 vnetp->fdb_hashp = NULL;
11726419Ssb155480 vnetp->fdb_nchains = 0;
11731991Sheppo }
11741991Sheppo }
11751991Sheppo
11766419Ssb155480 /*
11776419Ssb155480 * Add an entry into the fdb.
11786419Ssb155480 */
11791991Sheppo void
vnet_fdbe_add(vnet_t * vnetp,vnet_res_t * vresp)11806495Sspeer vnet_fdbe_add(vnet_t *vnetp, vnet_res_t *vresp)
11811991Sheppo {
11826419Ssb155480 uint64_t addr = 0;
11836419Ssb155480 int rv;
11846419Ssb155480
11856495Sspeer KEY_HASH(addr, vresp->rem_macaddr);
11861991Sheppo
11876419Ssb155480 /*
11886495Sspeer * If the entry being added corresponds to LDC_SERVICE resource,
11896495Sspeer * that is, vswitch connection, it is added to the hash and also
11906495Sspeer * the entry is cached, an additional reference count reflects
11916495Sspeer * this. The HYBRID resource is not added to the hash, but only
11926495Sspeer * cached, as it is only used for sending out packets for unknown
11936495Sspeer * unicast destinations.
11946419Ssb155480 */
11956495Sspeer (vresp->type == VIO_NET_RES_LDC_SERVICE) ?
11966495Sspeer (vresp->refcnt = 1) : (vresp->refcnt = 0);
11971991Sheppo
11986419Ssb155480 /*
11996419Ssb155480 * Note: duplicate keys will be rejected by mod_hash.
12006419Ssb155480 */
12016495Sspeer if (vresp->type != VIO_NET_RES_HYBRID) {
12026495Sspeer rv = mod_hash_insert(vnetp->fdb_hashp, (mod_hash_key_t)addr,
12036495Sspeer (mod_hash_val_t)vresp);
12046495Sspeer if (rv != 0) {
12056495Sspeer DWARN(vnetp, "Duplicate macaddr key(%lx)\n", addr);
12066495Sspeer return;
12076495Sspeer }
12081991Sheppo }
12091991Sheppo
12106495Sspeer if (vresp->type == VIO_NET_RES_LDC_SERVICE) {
12116419Ssb155480 /* Cache the fdb entry to vsw-port */
12126419Ssb155480 WRITE_ENTER(&vnetp->vsw_fp_rw);
12136419Ssb155480 if (vnetp->vsw_fp == NULL)
12146495Sspeer vnetp->vsw_fp = vresp;
12156495Sspeer RW_EXIT(&vnetp->vsw_fp_rw);
12166495Sspeer } else if (vresp->type == VIO_NET_RES_HYBRID) {
12176495Sspeer /* Cache the fdb entry to hybrid resource */
12186495Sspeer WRITE_ENTER(&vnetp->vsw_fp_rw);
12196495Sspeer if (vnetp->hio_fp == NULL)
12206495Sspeer vnetp->hio_fp = vresp;
12216419Ssb155480 RW_EXIT(&vnetp->vsw_fp_rw);
12222793Slm66018 }
12231991Sheppo }
12241991Sheppo
12256419Ssb155480 /*
12266419Ssb155480 * Remove an entry from fdb.
12276419Ssb155480 */
12286495Sspeer static void
vnet_fdbe_del(vnet_t * vnetp,vnet_res_t * vresp)12296495Sspeer vnet_fdbe_del(vnet_t *vnetp, vnet_res_t *vresp)
12305641Swentaoy {
12316419Ssb155480 uint64_t addr = 0;
12326419Ssb155480 int rv;
12336419Ssb155480 uint32_t refcnt;
12346495Sspeer vnet_res_t *tmp;
12355641Swentaoy
12366495Sspeer KEY_HASH(addr, vresp->rem_macaddr);
12375641Swentaoy
12386419Ssb155480 /*
12396419Ssb155480 * Remove the entry from fdb hash table.
12406419Ssb155480 * This prevents further references to this fdb entry.
12416419Ssb155480 */
12426495Sspeer if (vresp->type != VIO_NET_RES_HYBRID) {
12436495Sspeer rv = mod_hash_remove(vnetp->fdb_hashp, (mod_hash_key_t)addr,
12446495Sspeer (mod_hash_val_t *)&tmp);
12456495Sspeer if (rv != 0) {
12466495Sspeer /*
12476495Sspeer * As the resources are added to the hash only
12486495Sspeer * after they are started, this can occur if
12496495Sspeer * a resource unregisters before it is ever started.
12506495Sspeer */
12516495Sspeer return;
12526495Sspeer }
12536495Sspeer }
12545641Swentaoy
12556495Sspeer if (vresp->type == VIO_NET_RES_LDC_SERVICE) {
12566419Ssb155480 WRITE_ENTER(&vnetp->vsw_fp_rw);
12575641Swentaoy
12586495Sspeer ASSERT(tmp == vnetp->vsw_fp);
12596419Ssb155480 vnetp->vsw_fp = NULL;
12606419Ssb155480
12616419Ssb155480 RW_EXIT(&vnetp->vsw_fp_rw);
12626495Sspeer } else if (vresp->type == VIO_NET_RES_HYBRID) {
12636495Sspeer WRITE_ENTER(&vnetp->vsw_fp_rw);
12646495Sspeer
12656495Sspeer vnetp->hio_fp = NULL;
12666495Sspeer
12676495Sspeer RW_EXIT(&vnetp->vsw_fp_rw);
12685641Swentaoy }
12695641Swentaoy
12705641Swentaoy /*
12716419Ssb155480 * If there are threads already ref holding before the entry was
12726419Ssb155480 * removed from hash table, then wait for ref count to drop to zero.
12735641Swentaoy */
12746495Sspeer (vresp->type == VIO_NET_RES_LDC_SERVICE) ?
12756495Sspeer (refcnt = 1) : (refcnt = 0);
12766495Sspeer while (vresp->refcnt > refcnt) {
12776419Ssb155480 delay(drv_usectohz(vnet_fdbe_refcnt_delay));
12786419Ssb155480 }
12791991Sheppo }
12801991Sheppo
12816419Ssb155480 /*
12826419Ssb155480 * Search fdb for a given mac address. If an entry is found, hold
12836419Ssb155480 * a reference to it and return the entry; else returns NULL.
12846419Ssb155480 */
12856495Sspeer static vnet_res_t *
vnet_fdbe_find(vnet_t * vnetp,struct ether_addr * addrp)12866419Ssb155480 vnet_fdbe_find(vnet_t *vnetp, struct ether_addr *addrp)
12871991Sheppo {
12886419Ssb155480 uint64_t key = 0;
12896495Sspeer vnet_res_t *vresp;
12906419Ssb155480 int rv;
12916419Ssb155480
12926495Sspeer KEY_HASH(key, addrp->ether_addr_octet);
12936419Ssb155480
12946419Ssb155480 rv = mod_hash_find_cb(vnetp->fdb_hashp, (mod_hash_key_t)key,
12956495Sspeer (mod_hash_val_t *)&vresp, vnet_fdbe_find_cb);
12961991Sheppo
12976419Ssb155480 if (rv != 0)
12986419Ssb155480 return (NULL);
12991991Sheppo
13006495Sspeer return (vresp);
13016419Ssb155480 }
13021991Sheppo
13036419Ssb155480 /*
13046419Ssb155480 * Callback function provided to mod_hash_find_cb(). After finding the fdb
13056419Ssb155480 * entry corresponding to the key (macaddr), this callback will be invoked by
13066419Ssb155480 * mod_hash_find_cb() to atomically increment the reference count on the fdb
13076419Ssb155480 * entry before returning the found entry.
13086419Ssb155480 */
13096419Ssb155480 static void
vnet_fdbe_find_cb(mod_hash_key_t key,mod_hash_val_t val)13106419Ssb155480 vnet_fdbe_find_cb(mod_hash_key_t key, mod_hash_val_t val)
13116419Ssb155480 {
13126419Ssb155480 _NOTE(ARGUNUSED(key))
13136495Sspeer VNET_FDBE_REFHOLD((vnet_res_t *)val);
13146495Sspeer }
13156495Sspeer
13167896SSriharsha.Basavapatna@Sun.COM /*
13177896SSriharsha.Basavapatna@Sun.COM * Frames received that are tagged with the pvid of the vnet device must be
13187896SSriharsha.Basavapatna@Sun.COM * untagged before sending up the stack. This function walks the chain of rx
13197896SSriharsha.Basavapatna@Sun.COM * frames, untags any such frames and returns the updated chain.
13207896SSriharsha.Basavapatna@Sun.COM *
13217896SSriharsha.Basavapatna@Sun.COM * Arguments:
13227896SSriharsha.Basavapatna@Sun.COM * pvid: pvid of the vnet device for which packets are being received
13237896SSriharsha.Basavapatna@Sun.COM * mp: head of pkt chain to be validated and untagged
13247896SSriharsha.Basavapatna@Sun.COM *
13257896SSriharsha.Basavapatna@Sun.COM * Returns:
13267896SSriharsha.Basavapatna@Sun.COM * mp: head of updated chain of packets
13277896SSriharsha.Basavapatna@Sun.COM */
13287896SSriharsha.Basavapatna@Sun.COM static void
vnet_rx_frames_untag(uint16_t pvid,mblk_t ** mp)13297896SSriharsha.Basavapatna@Sun.COM vnet_rx_frames_untag(uint16_t pvid, mblk_t **mp)
13307896SSriharsha.Basavapatna@Sun.COM {
13317896SSriharsha.Basavapatna@Sun.COM struct ether_vlan_header *evhp;
13327896SSriharsha.Basavapatna@Sun.COM mblk_t *bp;
13337896SSriharsha.Basavapatna@Sun.COM mblk_t *bpt;
13347896SSriharsha.Basavapatna@Sun.COM mblk_t *bph;
13357896SSriharsha.Basavapatna@Sun.COM mblk_t *bpn;
13367896SSriharsha.Basavapatna@Sun.COM
13377896SSriharsha.Basavapatna@Sun.COM bpn = bph = bpt = NULL;
13387896SSriharsha.Basavapatna@Sun.COM
13397896SSriharsha.Basavapatna@Sun.COM for (bp = *mp; bp != NULL; bp = bpn) {
13407896SSriharsha.Basavapatna@Sun.COM
13417896SSriharsha.Basavapatna@Sun.COM bpn = bp->b_next;
13427896SSriharsha.Basavapatna@Sun.COM bp->b_next = bp->b_prev = NULL;
13437896SSriharsha.Basavapatna@Sun.COM
13447896SSriharsha.Basavapatna@Sun.COM evhp = (struct ether_vlan_header *)bp->b_rptr;
13457896SSriharsha.Basavapatna@Sun.COM
13467896SSriharsha.Basavapatna@Sun.COM if (ntohs(evhp->ether_tpid) == ETHERTYPE_VLAN &&
13477896SSriharsha.Basavapatna@Sun.COM VLAN_ID(ntohs(evhp->ether_tci)) == pvid) {
13487896SSriharsha.Basavapatna@Sun.COM
13497896SSriharsha.Basavapatna@Sun.COM bp = vnet_vlan_remove_tag(bp);
13507896SSriharsha.Basavapatna@Sun.COM if (bp == NULL) {
13517896SSriharsha.Basavapatna@Sun.COM continue;
13527896SSriharsha.Basavapatna@Sun.COM }
13537896SSriharsha.Basavapatna@Sun.COM
13547896SSriharsha.Basavapatna@Sun.COM }
13557896SSriharsha.Basavapatna@Sun.COM
13567896SSriharsha.Basavapatna@Sun.COM /* build a chain of processed packets */
13577896SSriharsha.Basavapatna@Sun.COM if (bph == NULL) {
13587896SSriharsha.Basavapatna@Sun.COM bph = bpt = bp;
13597896SSriharsha.Basavapatna@Sun.COM } else {
13607896SSriharsha.Basavapatna@Sun.COM bpt->b_next = bp;
13617896SSriharsha.Basavapatna@Sun.COM bpt = bp;
13627896SSriharsha.Basavapatna@Sun.COM }
13637896SSriharsha.Basavapatna@Sun.COM
13647896SSriharsha.Basavapatna@Sun.COM }
13657896SSriharsha.Basavapatna@Sun.COM
13667896SSriharsha.Basavapatna@Sun.COM *mp = bph;
13677896SSriharsha.Basavapatna@Sun.COM }
13687896SSriharsha.Basavapatna@Sun.COM
13696495Sspeer static void
vnet_rx(vio_net_handle_t vrh,mblk_t * mp)13706495Sspeer vnet_rx(vio_net_handle_t vrh, mblk_t *mp)
13716495Sspeer {
137210309SSriharsha.Basavapatna@Sun.COM vnet_res_t *vresp = (vnet_res_t *)vrh;
137310309SSriharsha.Basavapatna@Sun.COM vnet_t *vnetp = vresp->vnetp;
137410309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_rx_ring_t *ringp;
13757896SSriharsha.Basavapatna@Sun.COM
13767896SSriharsha.Basavapatna@Sun.COM if ((vnetp == NULL) || (vnetp->mh == 0)) {
13777896SSriharsha.Basavapatna@Sun.COM freemsgchain(mp);
13787896SSriharsha.Basavapatna@Sun.COM return;
13797896SSriharsha.Basavapatna@Sun.COM }
13806495Sspeer
138110309SSriharsha.Basavapatna@Sun.COM ringp = vresp->rx_ringp;
138210309SSriharsha.Basavapatna@Sun.COM mac_rx_ring(vnetp->mh, ringp->handle, mp, ringp->gen_num);
13831991Sheppo }
13842311Sseb
13852311Sseb void
vnet_tx_update(vio_net_handle_t vrh)13866495Sspeer vnet_tx_update(vio_net_handle_t vrh)
13876495Sspeer {
138810309SSriharsha.Basavapatna@Sun.COM vnet_res_t *vresp = (vnet_res_t *)vrh;
138910309SSriharsha.Basavapatna@Sun.COM vnet_t *vnetp = vresp->vnetp;
139010309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_tx_ring_t *tx_ringp;
139110309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_tx_group_t *tx_grp;
139210309SSriharsha.Basavapatna@Sun.COM int i;
139310309SSriharsha.Basavapatna@Sun.COM
139410309SSriharsha.Basavapatna@Sun.COM if (vnetp == NULL || vnetp->mh == NULL) {
139510309SSriharsha.Basavapatna@Sun.COM return;
139610309SSriharsha.Basavapatna@Sun.COM }
139710309SSriharsha.Basavapatna@Sun.COM
139810309SSriharsha.Basavapatna@Sun.COM /*
139910309SSriharsha.Basavapatna@Sun.COM * Currently, the tx hwring API (used to access rings that belong to
140010309SSriharsha.Basavapatna@Sun.COM * a Hybrid IO resource) does not provide us a per ring flow ctrl
140110309SSriharsha.Basavapatna@Sun.COM * update; also the pseudo rings are shared by the ports/ldcs in the
140210309SSriharsha.Basavapatna@Sun.COM * vgen layer. Thus we can't figure out which pseudo ring is being
140310309SSriharsha.Basavapatna@Sun.COM * re-enabled for transmits. To work around this, when we get a tx
140410309SSriharsha.Basavapatna@Sun.COM * restart notification from below, we simply propagate that to all
140510309SSriharsha.Basavapatna@Sun.COM * the tx pseudo rings registered with the mac layer above.
140610309SSriharsha.Basavapatna@Sun.COM *
140710309SSriharsha.Basavapatna@Sun.COM * There are a couple of side effects with this approach, but they are
140810309SSriharsha.Basavapatna@Sun.COM * not harmful, as outlined below:
140910309SSriharsha.Basavapatna@Sun.COM *
141010309SSriharsha.Basavapatna@Sun.COM * A) We might send an invalid ring_update() for a ring that is not
141110309SSriharsha.Basavapatna@Sun.COM * really flow controlled. This will not have any effect in the mac
141210309SSriharsha.Basavapatna@Sun.COM * layer and packets will continue to be transmitted on that ring.
141310309SSriharsha.Basavapatna@Sun.COM *
141410309SSriharsha.Basavapatna@Sun.COM * B) We might end up clearing the flow control in the mac layer for
141510309SSriharsha.Basavapatna@Sun.COM * a ring that is still flow controlled in the underlying resource.
141610309SSriharsha.Basavapatna@Sun.COM * This will result in the mac layer restarting transmit, only to be
141710309SSriharsha.Basavapatna@Sun.COM * flow controlled again on that ring.
141810309SSriharsha.Basavapatna@Sun.COM */
141910309SSriharsha.Basavapatna@Sun.COM tx_grp = &vnetp->tx_grp[0];
142010309SSriharsha.Basavapatna@Sun.COM for (i = 0; i < tx_grp->ring_cnt; i++) {
142110309SSriharsha.Basavapatna@Sun.COM tx_ringp = &tx_grp->rings[i];
142210309SSriharsha.Basavapatna@Sun.COM mac_tx_ring_update(vnetp->mh, tx_ringp->handle);
14236495Sspeer }
14246495Sspeer }
14256495Sspeer
14266495Sspeer /*
142711878SVenu.Iyer@Sun.COM * vnet_tx_notify_thread:
142811878SVenu.Iyer@Sun.COM *
142911878SVenu.Iyer@Sun.COM * vnet_tx_ring_update() callback function wakes up this thread when
143011878SVenu.Iyer@Sun.COM * it gets called. This thread will call mac_tx_ring_update() to
143111878SVenu.Iyer@Sun.COM * notify upper mac of flow control getting relieved. Note that
143211878SVenu.Iyer@Sun.COM * vnet_tx_ring_update() cannot call mac_tx_ring_update() directly
143311878SVenu.Iyer@Sun.COM * because vnet_tx_ring_update() is called from lower mac with
143411878SVenu.Iyer@Sun.COM * mi_rw_lock held and mac_tx_ring_update() would also try to grab
143511878SVenu.Iyer@Sun.COM * the same lock.
143611878SVenu.Iyer@Sun.COM */
143711878SVenu.Iyer@Sun.COM static void
vnet_tx_notify_thread(void * arg)143811878SVenu.Iyer@Sun.COM vnet_tx_notify_thread(void *arg)
143911878SVenu.Iyer@Sun.COM {
144011878SVenu.Iyer@Sun.COM callb_cpr_t cprinfo;
144111878SVenu.Iyer@Sun.COM vnet_pseudo_tx_group_t *tx_grp = (vnet_pseudo_tx_group_t *)arg;
144211878SVenu.Iyer@Sun.COM vnet_pseudo_tx_ring_t *tx_ringp;
144311878SVenu.Iyer@Sun.COM vnet_t *vnetp;
144411878SVenu.Iyer@Sun.COM int i;
144511878SVenu.Iyer@Sun.COM
144611878SVenu.Iyer@Sun.COM CALLB_CPR_INIT(&cprinfo, &tx_grp->flowctl_lock, callb_generic_cpr,
144711878SVenu.Iyer@Sun.COM "vnet_tx_notify_thread");
144811878SVenu.Iyer@Sun.COM
144911878SVenu.Iyer@Sun.COM mutex_enter(&tx_grp->flowctl_lock);
145011878SVenu.Iyer@Sun.COM while (!tx_grp->flowctl_done) {
145111878SVenu.Iyer@Sun.COM CALLB_CPR_SAFE_BEGIN(&cprinfo);
145211878SVenu.Iyer@Sun.COM cv_wait(&tx_grp->flowctl_cv, &tx_grp->flowctl_lock);
145311878SVenu.Iyer@Sun.COM CALLB_CPR_SAFE_END(&cprinfo, &tx_grp->flowctl_lock);
145411878SVenu.Iyer@Sun.COM
145511878SVenu.Iyer@Sun.COM for (i = 0; i < tx_grp->ring_cnt; i++) {
145611878SVenu.Iyer@Sun.COM tx_ringp = &tx_grp->rings[i];
145711878SVenu.Iyer@Sun.COM if (tx_ringp->woken_up) {
145811878SVenu.Iyer@Sun.COM tx_ringp->woken_up = B_FALSE;
145911878SVenu.Iyer@Sun.COM vnetp = tx_ringp->vnetp;
146011878SVenu.Iyer@Sun.COM mac_tx_ring_update(vnetp->mh, tx_ringp->handle);
146111878SVenu.Iyer@Sun.COM }
146211878SVenu.Iyer@Sun.COM }
146311878SVenu.Iyer@Sun.COM }
146411878SVenu.Iyer@Sun.COM /*
146511878SVenu.Iyer@Sun.COM * The tx_grp is being destroyed, exit the thread.
146611878SVenu.Iyer@Sun.COM */
146711878SVenu.Iyer@Sun.COM tx_grp->flowctl_thread = NULL;
146811878SVenu.Iyer@Sun.COM CALLB_CPR_EXIT(&cprinfo);
146911878SVenu.Iyer@Sun.COM thread_exit();
147011878SVenu.Iyer@Sun.COM }
147111878SVenu.Iyer@Sun.COM
147211878SVenu.Iyer@Sun.COM void
vnet_tx_ring_update(void * arg1,uintptr_t arg2)147311878SVenu.Iyer@Sun.COM vnet_tx_ring_update(void *arg1, uintptr_t arg2)
147411878SVenu.Iyer@Sun.COM {
147511878SVenu.Iyer@Sun.COM vnet_t *vnetp = (vnet_t *)arg1;
147611878SVenu.Iyer@Sun.COM vnet_pseudo_tx_group_t *tx_grp;
147711878SVenu.Iyer@Sun.COM vnet_pseudo_tx_ring_t *tx_ringp;
147811878SVenu.Iyer@Sun.COM int i;
147911878SVenu.Iyer@Sun.COM
148011878SVenu.Iyer@Sun.COM tx_grp = &vnetp->tx_grp[0];
148111878SVenu.Iyer@Sun.COM for (i = 0; i < tx_grp->ring_cnt; i++) {
148211878SVenu.Iyer@Sun.COM tx_ringp = &tx_grp->rings[i];
148311878SVenu.Iyer@Sun.COM if (tx_ringp->hw_rh == (mac_ring_handle_t)arg2) {
148411878SVenu.Iyer@Sun.COM mutex_enter(&tx_grp->flowctl_lock);
148511878SVenu.Iyer@Sun.COM tx_ringp->woken_up = B_TRUE;
148611878SVenu.Iyer@Sun.COM cv_signal(&tx_grp->flowctl_cv);
148711878SVenu.Iyer@Sun.COM mutex_exit(&tx_grp->flowctl_lock);
148811878SVenu.Iyer@Sun.COM break;
148911878SVenu.Iyer@Sun.COM }
149011878SVenu.Iyer@Sun.COM }
149111878SVenu.Iyer@Sun.COM }
149211878SVenu.Iyer@Sun.COM
149311878SVenu.Iyer@Sun.COM /*
14947529SSriharsha.Basavapatna@Sun.COM * Update the new mtu of vnet into the mac layer. First check if the device has
14957529SSriharsha.Basavapatna@Sun.COM * been plumbed and if so fail the mtu update. Returns 0 on success.
14967529SSriharsha.Basavapatna@Sun.COM */
14977529SSriharsha.Basavapatna@Sun.COM int
vnet_mtu_update(vnet_t * vnetp,uint32_t mtu)14987529SSriharsha.Basavapatna@Sun.COM vnet_mtu_update(vnet_t *vnetp, uint32_t mtu)
14997529SSriharsha.Basavapatna@Sun.COM {
15007529SSriharsha.Basavapatna@Sun.COM int rv;
15017529SSriharsha.Basavapatna@Sun.COM
15027529SSriharsha.Basavapatna@Sun.COM if (vnetp == NULL || vnetp->mh == NULL) {
15037529SSriharsha.Basavapatna@Sun.COM return (EINVAL);
15047529SSriharsha.Basavapatna@Sun.COM }
15057529SSriharsha.Basavapatna@Sun.COM
15067529SSriharsha.Basavapatna@Sun.COM WRITE_ENTER(&vnetp->vrwlock);
15077529SSriharsha.Basavapatna@Sun.COM
15087529SSriharsha.Basavapatna@Sun.COM if (vnetp->flags & VNET_STARTED) {
15097529SSriharsha.Basavapatna@Sun.COM RW_EXIT(&vnetp->vrwlock);
15107529SSriharsha.Basavapatna@Sun.COM cmn_err(CE_NOTE, "!vnet%d: Unable to process mtu "
15117529SSriharsha.Basavapatna@Sun.COM "update as the device is plumbed\n",
15127529SSriharsha.Basavapatna@Sun.COM vnetp->instance);
15137529SSriharsha.Basavapatna@Sun.COM return (EBUSY);
15147529SSriharsha.Basavapatna@Sun.COM }
15157529SSriharsha.Basavapatna@Sun.COM
15167529SSriharsha.Basavapatna@Sun.COM /* update mtu in the mac layer */
15177529SSriharsha.Basavapatna@Sun.COM rv = mac_maxsdu_update(vnetp->mh, mtu);
15187529SSriharsha.Basavapatna@Sun.COM if (rv != 0) {
15197529SSriharsha.Basavapatna@Sun.COM RW_EXIT(&vnetp->vrwlock);
15207529SSriharsha.Basavapatna@Sun.COM cmn_err(CE_NOTE,
15217529SSriharsha.Basavapatna@Sun.COM "!vnet%d: Unable to update mtu with mac layer\n",
15227529SSriharsha.Basavapatna@Sun.COM vnetp->instance);
15237529SSriharsha.Basavapatna@Sun.COM return (EIO);
15247529SSriharsha.Basavapatna@Sun.COM }
15257529SSriharsha.Basavapatna@Sun.COM
15267529SSriharsha.Basavapatna@Sun.COM vnetp->mtu = mtu;
15277529SSriharsha.Basavapatna@Sun.COM
15287529SSriharsha.Basavapatna@Sun.COM RW_EXIT(&vnetp->vrwlock);
15297529SSriharsha.Basavapatna@Sun.COM
15307529SSriharsha.Basavapatna@Sun.COM return (0);
15317529SSriharsha.Basavapatna@Sun.COM }
15327529SSriharsha.Basavapatna@Sun.COM
15337529SSriharsha.Basavapatna@Sun.COM /*
15349336SSriharsha.Basavapatna@Sun.COM * Update the link state of vnet to the mac layer.
15359336SSriharsha.Basavapatna@Sun.COM */
15369336SSriharsha.Basavapatna@Sun.COM void
vnet_link_update(vnet_t * vnetp,link_state_t link_state)15379336SSriharsha.Basavapatna@Sun.COM vnet_link_update(vnet_t *vnetp, link_state_t link_state)
15389336SSriharsha.Basavapatna@Sun.COM {
15399336SSriharsha.Basavapatna@Sun.COM if (vnetp == NULL || vnetp->mh == NULL) {
15409336SSriharsha.Basavapatna@Sun.COM return;
15419336SSriharsha.Basavapatna@Sun.COM }
15429336SSriharsha.Basavapatna@Sun.COM
15439336SSriharsha.Basavapatna@Sun.COM WRITE_ENTER(&vnetp->vrwlock);
15449336SSriharsha.Basavapatna@Sun.COM if (vnetp->link_state == link_state) {
15459336SSriharsha.Basavapatna@Sun.COM RW_EXIT(&vnetp->vrwlock);
15469336SSriharsha.Basavapatna@Sun.COM return;
15479336SSriharsha.Basavapatna@Sun.COM }
15489336SSriharsha.Basavapatna@Sun.COM vnetp->link_state = link_state;
15499336SSriharsha.Basavapatna@Sun.COM RW_EXIT(&vnetp->vrwlock);
15509336SSriharsha.Basavapatna@Sun.COM
15519336SSriharsha.Basavapatna@Sun.COM mac_link_update(vnetp->mh, link_state);
15529336SSriharsha.Basavapatna@Sun.COM }
15539336SSriharsha.Basavapatna@Sun.COM
15549336SSriharsha.Basavapatna@Sun.COM /*
15556495Sspeer * vio_net_resource_reg -- An interface called to register a resource
15566495Sspeer * with vnet.
15576495Sspeer * macp -- a GLDv3 mac_register that has all the details of
15586495Sspeer * a resource and its callbacks etc.
15596495Sspeer * type -- resource type.
15606495Sspeer * local_macaddr -- resource's MAC address. This is used to
15616495Sspeer * associate a resource with a corresponding vnet.
15626495Sspeer * remote_macaddr -- remote side MAC address. This is ignored for
15636495Sspeer * the Hybrid resources.
15646495Sspeer * vhp -- A handle returned to the caller.
15656495Sspeer * vcb -- A set of callbacks provided to the callers.
15666495Sspeer */
vio_net_resource_reg(mac_register_t * macp,vio_net_res_type_t type,ether_addr_t local_macaddr,ether_addr_t rem_macaddr,vio_net_handle_t * vhp,vio_net_callbacks_t * vcb)15676495Sspeer int vio_net_resource_reg(mac_register_t *macp, vio_net_res_type_t type,
15686495Sspeer ether_addr_t local_macaddr, ether_addr_t rem_macaddr, vio_net_handle_t *vhp,
15696495Sspeer vio_net_callbacks_t *vcb)
15706495Sspeer {
157110309SSriharsha.Basavapatna@Sun.COM vnet_t *vnetp;
157210309SSriharsha.Basavapatna@Sun.COM vnet_res_t *vresp;
15736495Sspeer
15746495Sspeer vresp = kmem_zalloc(sizeof (vnet_res_t), KM_SLEEP);
15756495Sspeer ether_copy(local_macaddr, vresp->local_macaddr);
15766495Sspeer ether_copy(rem_macaddr, vresp->rem_macaddr);
15776495Sspeer vresp->type = type;
15786495Sspeer bcopy(macp, &vresp->macreg, sizeof (mac_register_t));
15796495Sspeer
15806495Sspeer DBG1(NULL, "Resource Registerig type=0%X\n", type);
15816495Sspeer
15826495Sspeer READ_ENTER(&vnet_rw);
15836495Sspeer vnetp = vnet_headp;
15846495Sspeer while (vnetp != NULL) {
15856495Sspeer if (VNET_MATCH_RES(vresp, vnetp)) {
15868332SWentao.Yang@Sun.COM vresp->vnetp = vnetp;
15878332SWentao.Yang@Sun.COM
15888332SWentao.Yang@Sun.COM /* Setup kstats for hio resource */
15898332SWentao.Yang@Sun.COM if (vresp->type == VIO_NET_RES_HYBRID) {
15908332SWentao.Yang@Sun.COM vresp->ksp = vnet_hio_setup_kstats(DRV_NAME,
15918332SWentao.Yang@Sun.COM "hio", vresp);
15928332SWentao.Yang@Sun.COM if (vresp->ksp == NULL) {
15938332SWentao.Yang@Sun.COM cmn_err(CE_NOTE, "!vnet%d: Cannot "
15948332SWentao.Yang@Sun.COM "create kstats for hio resource",
15958332SWentao.Yang@Sun.COM vnetp->instance);
15968332SWentao.Yang@Sun.COM }
15978332SWentao.Yang@Sun.COM }
159810309SSriharsha.Basavapatna@Sun.COM vnet_add_resource(vnetp, vresp);
15996495Sspeer break;
16006495Sspeer }
16016495Sspeer vnetp = vnetp->nextp;
16026495Sspeer }
16036495Sspeer RW_EXIT(&vnet_rw);
16046495Sspeer if (vresp->vnetp == NULL) {
16056495Sspeer DWARN(NULL, "No vnet instance");
16066495Sspeer kmem_free(vresp, sizeof (vnet_res_t));
16076495Sspeer return (ENXIO);
16086495Sspeer }
16096495Sspeer
16106495Sspeer *vhp = vresp;
16116495Sspeer vcb->vio_net_rx_cb = vnet_rx;
16126495Sspeer vcb->vio_net_tx_update = vnet_tx_update;
16136495Sspeer vcb->vio_net_report_err = vnet_handle_res_err;
16146495Sspeer
161510309SSriharsha.Basavapatna@Sun.COM /* Bind the resource to pseudo ring(s) */
161610309SSriharsha.Basavapatna@Sun.COM if (vnet_bind_rings(vresp) != 0) {
161710309SSriharsha.Basavapatna@Sun.COM (void) vnet_rem_resource(vnetp, vresp);
161810309SSriharsha.Basavapatna@Sun.COM vnet_hio_destroy_kstats(vresp->ksp);
161910309SSriharsha.Basavapatna@Sun.COM KMEM_FREE(vresp);
162010309SSriharsha.Basavapatna@Sun.COM return (1);
162110309SSriharsha.Basavapatna@Sun.COM }
162210309SSriharsha.Basavapatna@Sun.COM
16236495Sspeer /* Dispatch a task to start resources */
16246495Sspeer vnet_dispatch_res_task(vnetp);
16256495Sspeer return (0);
16266495Sspeer }
16276495Sspeer
16286495Sspeer /*
16296495Sspeer * vio_net_resource_unreg -- An interface to unregister a resource.
16306495Sspeer */
16316495Sspeer void
vio_net_resource_unreg(vio_net_handle_t vhp)16326495Sspeer vio_net_resource_unreg(vio_net_handle_t vhp)
16336495Sspeer {
16349805SSriharsha.Basavapatna@Sun.COM vnet_res_t *vresp = (vnet_res_t *)vhp;
16359805SSriharsha.Basavapatna@Sun.COM vnet_t *vnetp = vresp->vnetp;
16366495Sspeer
16376495Sspeer DBG1(NULL, "Resource Registerig hdl=0x%p", vhp);
16386495Sspeer
16396495Sspeer ASSERT(vnetp != NULL);
16409805SSriharsha.Basavapatna@Sun.COM /*
16419805SSriharsha.Basavapatna@Sun.COM * Remove the resource from fdb; this ensures
16429805SSriharsha.Basavapatna@Sun.COM * there are no references to the resource.
16439805SSriharsha.Basavapatna@Sun.COM */
16446495Sspeer vnet_fdbe_del(vnetp, vresp);
16456495Sspeer
164610309SSriharsha.Basavapatna@Sun.COM vnet_unbind_rings(vresp);
164710309SSriharsha.Basavapatna@Sun.COM
16489805SSriharsha.Basavapatna@Sun.COM /* Now remove the resource from the list */
164910309SSriharsha.Basavapatna@Sun.COM (void) vnet_rem_resource(vnetp, vresp);
165010309SSriharsha.Basavapatna@Sun.COM
165110309SSriharsha.Basavapatna@Sun.COM vnet_hio_destroy_kstats(vresp->ksp);
165210309SSriharsha.Basavapatna@Sun.COM KMEM_FREE(vresp);
165310309SSriharsha.Basavapatna@Sun.COM }
165410309SSriharsha.Basavapatna@Sun.COM
165510309SSriharsha.Basavapatna@Sun.COM static void
vnet_add_resource(vnet_t * vnetp,vnet_res_t * vresp)165610309SSriharsha.Basavapatna@Sun.COM vnet_add_resource(vnet_t *vnetp, vnet_res_t *vresp)
165710309SSriharsha.Basavapatna@Sun.COM {
165810309SSriharsha.Basavapatna@Sun.COM WRITE_ENTER(&vnetp->vrwlock);
165910309SSriharsha.Basavapatna@Sun.COM vresp->nextp = vnetp->vres_list;
166010309SSriharsha.Basavapatna@Sun.COM vnetp->vres_list = vresp;
166110309SSriharsha.Basavapatna@Sun.COM RW_EXIT(&vnetp->vrwlock);
166210309SSriharsha.Basavapatna@Sun.COM }
166310309SSriharsha.Basavapatna@Sun.COM
166410309SSriharsha.Basavapatna@Sun.COM static vnet_res_t *
vnet_rem_resource(vnet_t * vnetp,vnet_res_t * vresp)166510309SSriharsha.Basavapatna@Sun.COM vnet_rem_resource(vnet_t *vnetp, vnet_res_t *vresp)
166610309SSriharsha.Basavapatna@Sun.COM {
166710309SSriharsha.Basavapatna@Sun.COM vnet_res_t *vrp;
166810309SSriharsha.Basavapatna@Sun.COM
16696495Sspeer WRITE_ENTER(&vnetp->vrwlock);
16706495Sspeer if (vresp == vnetp->vres_list) {
16716495Sspeer vnetp->vres_list = vresp->nextp;
16726495Sspeer } else {
16736495Sspeer vrp = vnetp->vres_list;
16746495Sspeer while (vrp->nextp != NULL) {
16756495Sspeer if (vrp->nextp == vresp) {
16766495Sspeer vrp->nextp = vresp->nextp;
16776495Sspeer break;
16786495Sspeer }
16796495Sspeer vrp = vrp->nextp;
16806495Sspeer }
16816495Sspeer }
16826495Sspeer vresp->vnetp = NULL;
16836495Sspeer vresp->nextp = NULL;
168410309SSriharsha.Basavapatna@Sun.COM
16856495Sspeer RW_EXIT(&vnetp->vrwlock);
168610309SSriharsha.Basavapatna@Sun.COM
168710309SSriharsha.Basavapatna@Sun.COM return (vresp);
16886495Sspeer }
16896495Sspeer
16906495Sspeer /*
16916495Sspeer * vnet_dds_rx -- an interface called by vgen to DDS messages.
16926495Sspeer */
16936495Sspeer void
vnet_dds_rx(void * arg,void * dmsg)16946495Sspeer vnet_dds_rx(void *arg, void *dmsg)
16952311Sseb {
16962311Sseb vnet_t *vnetp = arg;
16976495Sspeer vdds_process_dds_msg(vnetp, dmsg);
16982311Sseb }
16992311Sseb
17006495Sspeer /*
17016495Sspeer * vnet_send_dds_msg -- An interface provided to DDS to send
17026495Sspeer * DDS messages. This simply sends meessages via vgen.
17036495Sspeer */
17046495Sspeer int
vnet_send_dds_msg(vnet_t * vnetp,void * dmsg)17056495Sspeer vnet_send_dds_msg(vnet_t *vnetp, void *dmsg)
17066495Sspeer {
17076495Sspeer int rv;
17086495Sspeer
17096495Sspeer if (vnetp->vgenhdl != NULL) {
17106495Sspeer rv = vgen_dds_tx(vnetp->vgenhdl, dmsg);
17116495Sspeer }
17126495Sspeer return (rv);
17136495Sspeer }
17146495Sspeer
17156495Sspeer /*
17169647SWentao.Yang@Sun.COM * vnet_cleanup_hio -- an interface called by vgen to cleanup hio resources.
17179647SWentao.Yang@Sun.COM */
17189647SWentao.Yang@Sun.COM void
vnet_dds_cleanup_hio(vnet_t * vnetp)17199647SWentao.Yang@Sun.COM vnet_dds_cleanup_hio(vnet_t *vnetp)
17209647SWentao.Yang@Sun.COM {
17219647SWentao.Yang@Sun.COM vdds_cleanup_hio(vnetp);
17229647SWentao.Yang@Sun.COM }
17239647SWentao.Yang@Sun.COM
17249647SWentao.Yang@Sun.COM /*
17256495Sspeer * vnet_handle_res_err -- A callback function called by a resource
17266495Sspeer * to report an error. For example, vgen can call to report
17276495Sspeer * an LDC down/reset event. This will trigger cleanup of associated
17286495Sspeer * Hybrid resource.
17296495Sspeer */
17306495Sspeer /* ARGSUSED */
17316495Sspeer static void
vnet_handle_res_err(vio_net_handle_t vrh,vio_net_err_val_t err)17326495Sspeer vnet_handle_res_err(vio_net_handle_t vrh, vio_net_err_val_t err)
17336495Sspeer {
17346495Sspeer vnet_res_t *vresp = (vnet_res_t *)vrh;
17356495Sspeer vnet_t *vnetp = vresp->vnetp;
17366495Sspeer
17376495Sspeer if (vnetp == NULL) {
17386495Sspeer return;
17396495Sspeer }
17406495Sspeer if ((vresp->type != VIO_NET_RES_LDC_SERVICE) &&
17416495Sspeer (vresp->type != VIO_NET_RES_HYBRID)) {
17426495Sspeer return;
17436495Sspeer }
17449647SWentao.Yang@Sun.COM
17459647SWentao.Yang@Sun.COM vdds_cleanup_hio(vnetp);
17466495Sspeer }
17476495Sspeer
17486495Sspeer /*
17496495Sspeer * vnet_dispatch_res_task -- A function to dispatch tasks start resources.
17506495Sspeer */
17516495Sspeer static void
vnet_dispatch_res_task(vnet_t * vnetp)17526495Sspeer vnet_dispatch_res_task(vnet_t *vnetp)
17536495Sspeer {
17546495Sspeer int rv;
17556495Sspeer
17569677SZachary.Kissel@Sun.COM /*
17579677SZachary.Kissel@Sun.COM * Dispatch the task. It could be the case that vnetp->flags does
17589677SZachary.Kissel@Sun.COM * not have VNET_STARTED set. This is ok as vnet_rest_start_task()
17599805SSriharsha.Basavapatna@Sun.COM * can abort the task when the task is started. See related comments
17609805SSriharsha.Basavapatna@Sun.COM * in vnet_m_stop() and vnet_stop_resources().
17619677SZachary.Kissel@Sun.COM */
17629677SZachary.Kissel@Sun.COM rv = ddi_taskq_dispatch(vnetp->taskqp, vnet_res_start_task,
17639677SZachary.Kissel@Sun.COM vnetp, DDI_NOSLEEP);
17649677SZachary.Kissel@Sun.COM if (rv != DDI_SUCCESS) {
17659677SZachary.Kissel@Sun.COM cmn_err(CE_WARN,
17669677SZachary.Kissel@Sun.COM "vnet%d:Can't dispatch start resource task",
17679677SZachary.Kissel@Sun.COM vnetp->instance);
17686495Sspeer }
17696495Sspeer }
17706495Sspeer
17716495Sspeer /*
17726495Sspeer * vnet_res_start_task -- A taskq callback function that starts a resource.
17736495Sspeer */
17746495Sspeer static void
vnet_res_start_task(void * arg)17756495Sspeer vnet_res_start_task(void *arg)
17762311Sseb {
17772311Sseb vnet_t *vnetp = arg;
17786495Sspeer
17796495Sspeer WRITE_ENTER(&vnetp->vrwlock);
17806495Sspeer if (vnetp->flags & VNET_STARTED) {
17816495Sspeer vnet_start_resources(vnetp);
17826495Sspeer }
17836495Sspeer RW_EXIT(&vnetp->vrwlock);
17842311Sseb }
17856495Sspeer
17866495Sspeer /*
17876495Sspeer * vnet_start_resources -- starts all resources associated with
17886495Sspeer * a vnet.
17896495Sspeer */
17906495Sspeer static void
vnet_start_resources(vnet_t * vnetp)17916495Sspeer vnet_start_resources(vnet_t *vnetp)
17926495Sspeer {
17936495Sspeer mac_register_t *macp;
17946495Sspeer mac_callbacks_t *cbp;
17956495Sspeer vnet_res_t *vresp;
17966495Sspeer int rv;
17976495Sspeer
17986495Sspeer DBG1(vnetp, "enter\n");
17996495Sspeer
18009805SSriharsha.Basavapatna@Sun.COM ASSERT(RW_WRITE_HELD(&vnetp->vrwlock));
18019805SSriharsha.Basavapatna@Sun.COM
18026495Sspeer for (vresp = vnetp->vres_list; vresp != NULL; vresp = vresp->nextp) {
18036495Sspeer /* skip if it is already started */
18046495Sspeer if (vresp->flags & VNET_STARTED) {
18056495Sspeer continue;
18066495Sspeer }
18076495Sspeer macp = &vresp->macreg;
18086495Sspeer cbp = macp->m_callbacks;
18096495Sspeer rv = cbp->mc_start(macp->m_driver);
18106495Sspeer if (rv == 0) {
18116495Sspeer /*
18126495Sspeer * Successfully started the resource, so now
18136495Sspeer * add it to the fdb.
18146495Sspeer */
18156495Sspeer vresp->flags |= VNET_STARTED;
18166495Sspeer vnet_fdbe_add(vnetp, vresp);
18176495Sspeer }
18186495Sspeer }
18196495Sspeer
18206495Sspeer DBG1(vnetp, "exit\n");
18216495Sspeer
18226495Sspeer }
18236495Sspeer
18246495Sspeer /*
18256495Sspeer * vnet_stop_resources -- stop all resources associated with a vnet.
18266495Sspeer */
18276495Sspeer static void
vnet_stop_resources(vnet_t * vnetp)18286495Sspeer vnet_stop_resources(vnet_t *vnetp)
18296495Sspeer {
18306495Sspeer vnet_res_t *vresp;
18316495Sspeer mac_register_t *macp;
18326495Sspeer mac_callbacks_t *cbp;
18336495Sspeer
18346495Sspeer DBG1(vnetp, "enter\n");
18356495Sspeer
18369805SSriharsha.Basavapatna@Sun.COM ASSERT(RW_WRITE_HELD(&vnetp->vrwlock));
18379805SSriharsha.Basavapatna@Sun.COM
18386495Sspeer for (vresp = vnetp->vres_list; vresp != NULL; ) {
18396495Sspeer if (vresp->flags & VNET_STARTED) {
18409805SSriharsha.Basavapatna@Sun.COM /*
18419805SSriharsha.Basavapatna@Sun.COM * Release the lock while invoking mc_stop() of the
18429805SSriharsha.Basavapatna@Sun.COM * underlying resource. We hold a reference to this
18439805SSriharsha.Basavapatna@Sun.COM * resource to prevent being removed from the list in
18449805SSriharsha.Basavapatna@Sun.COM * vio_net_resource_unreg(). Note that new resources
18459805SSriharsha.Basavapatna@Sun.COM * can be added to the head of the list while the lock
18469805SSriharsha.Basavapatna@Sun.COM * is released, but they won't be started, as
18479805SSriharsha.Basavapatna@Sun.COM * VNET_STARTED flag has been cleared for the vnet
18489805SSriharsha.Basavapatna@Sun.COM * device in vnet_m_stop(). Also, while the lock is
18499805SSriharsha.Basavapatna@Sun.COM * released a resource could be removed from the list
18509805SSriharsha.Basavapatna@Sun.COM * in vio_net_resource_unreg(); but that is ok, as we
18519805SSriharsha.Basavapatna@Sun.COM * re-acquire the lock and only then access the forward
18529805SSriharsha.Basavapatna@Sun.COM * link (vresp->nextp) to continue with the next
18539805SSriharsha.Basavapatna@Sun.COM * resource.
18549805SSriharsha.Basavapatna@Sun.COM */
18559805SSriharsha.Basavapatna@Sun.COM vresp->flags &= ~VNET_STARTED;
18569805SSriharsha.Basavapatna@Sun.COM vresp->flags |= VNET_STOPPING;
18576495Sspeer macp = &vresp->macreg;
18586495Sspeer cbp = macp->m_callbacks;
18599805SSriharsha.Basavapatna@Sun.COM VNET_FDBE_REFHOLD(vresp);
18609805SSriharsha.Basavapatna@Sun.COM RW_EXIT(&vnetp->vrwlock);
18619805SSriharsha.Basavapatna@Sun.COM
18626495Sspeer cbp->mc_stop(macp->m_driver);
18639805SSriharsha.Basavapatna@Sun.COM
18649805SSriharsha.Basavapatna@Sun.COM WRITE_ENTER(&vnetp->vrwlock);
18659805SSriharsha.Basavapatna@Sun.COM vresp->flags &= ~VNET_STOPPING;
18669805SSriharsha.Basavapatna@Sun.COM VNET_FDBE_REFRELE(vresp);
18676495Sspeer }
18689805SSriharsha.Basavapatna@Sun.COM vresp = vresp->nextp;
18696495Sspeer }
18706495Sspeer DBG1(vnetp, "exit\n");
18716495Sspeer }
18728160SWentao.Yang@Sun.COM
18738160SWentao.Yang@Sun.COM /*
18748160SWentao.Yang@Sun.COM * Setup kstats for the HIO statistics.
18758160SWentao.Yang@Sun.COM * NOTE: the synchronization for the statistics is the
18768160SWentao.Yang@Sun.COM * responsibility of the caller.
18778160SWentao.Yang@Sun.COM */
18788160SWentao.Yang@Sun.COM kstat_t *
vnet_hio_setup_kstats(char * ks_mod,char * ks_name,vnet_res_t * vresp)18798160SWentao.Yang@Sun.COM vnet_hio_setup_kstats(char *ks_mod, char *ks_name, vnet_res_t *vresp)
18808160SWentao.Yang@Sun.COM {
18818160SWentao.Yang@Sun.COM kstat_t *ksp;
18828160SWentao.Yang@Sun.COM vnet_t *vnetp = vresp->vnetp;
18838160SWentao.Yang@Sun.COM vnet_hio_kstats_t *hiokp;
18848160SWentao.Yang@Sun.COM size_t size;
18858160SWentao.Yang@Sun.COM
18868160SWentao.Yang@Sun.COM ASSERT(vnetp != NULL);
18878160SWentao.Yang@Sun.COM size = sizeof (vnet_hio_kstats_t) / sizeof (kstat_named_t);
18888160SWentao.Yang@Sun.COM ksp = kstat_create(ks_mod, vnetp->instance, ks_name, "net",
18898160SWentao.Yang@Sun.COM KSTAT_TYPE_NAMED, size, 0);
18908160SWentao.Yang@Sun.COM if (ksp == NULL) {
18918160SWentao.Yang@Sun.COM return (NULL);
18928160SWentao.Yang@Sun.COM }
18938160SWentao.Yang@Sun.COM
18948160SWentao.Yang@Sun.COM hiokp = (vnet_hio_kstats_t *)ksp->ks_data;
18958160SWentao.Yang@Sun.COM kstat_named_init(&hiokp->ipackets, "ipackets",
18968160SWentao.Yang@Sun.COM KSTAT_DATA_ULONG);
18978160SWentao.Yang@Sun.COM kstat_named_init(&hiokp->ierrors, "ierrors",
18988160SWentao.Yang@Sun.COM KSTAT_DATA_ULONG);
18998160SWentao.Yang@Sun.COM kstat_named_init(&hiokp->opackets, "opackets",
19008160SWentao.Yang@Sun.COM KSTAT_DATA_ULONG);
19018160SWentao.Yang@Sun.COM kstat_named_init(&hiokp->oerrors, "oerrors",
19028160SWentao.Yang@Sun.COM KSTAT_DATA_ULONG);
19038160SWentao.Yang@Sun.COM
19048160SWentao.Yang@Sun.COM
19058160SWentao.Yang@Sun.COM /* MIB II kstat variables */
19068160SWentao.Yang@Sun.COM kstat_named_init(&hiokp->rbytes, "rbytes",
19078160SWentao.Yang@Sun.COM KSTAT_DATA_ULONG);
19088160SWentao.Yang@Sun.COM kstat_named_init(&hiokp->obytes, "obytes",
19098160SWentao.Yang@Sun.COM KSTAT_DATA_ULONG);
19108160SWentao.Yang@Sun.COM kstat_named_init(&hiokp->multircv, "multircv",
19118160SWentao.Yang@Sun.COM KSTAT_DATA_ULONG);
19128160SWentao.Yang@Sun.COM kstat_named_init(&hiokp->multixmt, "multixmt",
19138160SWentao.Yang@Sun.COM KSTAT_DATA_ULONG);
19148160SWentao.Yang@Sun.COM kstat_named_init(&hiokp->brdcstrcv, "brdcstrcv",
19158160SWentao.Yang@Sun.COM KSTAT_DATA_ULONG);
19168160SWentao.Yang@Sun.COM kstat_named_init(&hiokp->brdcstxmt, "brdcstxmt",
19178160SWentao.Yang@Sun.COM KSTAT_DATA_ULONG);
19188160SWentao.Yang@Sun.COM kstat_named_init(&hiokp->norcvbuf, "norcvbuf",
19198160SWentao.Yang@Sun.COM KSTAT_DATA_ULONG);
19208160SWentao.Yang@Sun.COM kstat_named_init(&hiokp->noxmtbuf, "noxmtbuf",
19218160SWentao.Yang@Sun.COM KSTAT_DATA_ULONG);
19228160SWentao.Yang@Sun.COM
19238160SWentao.Yang@Sun.COM ksp->ks_update = vnet_hio_update_kstats;
19248160SWentao.Yang@Sun.COM ksp->ks_private = (void *)vresp;
19258160SWentao.Yang@Sun.COM kstat_install(ksp);
19268160SWentao.Yang@Sun.COM return (ksp);
19278160SWentao.Yang@Sun.COM }
19288160SWentao.Yang@Sun.COM
19298160SWentao.Yang@Sun.COM /*
19308160SWentao.Yang@Sun.COM * Destroy kstats.
19318160SWentao.Yang@Sun.COM */
19328160SWentao.Yang@Sun.COM static void
vnet_hio_destroy_kstats(kstat_t * ksp)19338160SWentao.Yang@Sun.COM vnet_hio_destroy_kstats(kstat_t *ksp)
19348160SWentao.Yang@Sun.COM {
19358160SWentao.Yang@Sun.COM if (ksp != NULL)
19368160SWentao.Yang@Sun.COM kstat_delete(ksp);
19378160SWentao.Yang@Sun.COM }
19388160SWentao.Yang@Sun.COM
19398160SWentao.Yang@Sun.COM /*
19408160SWentao.Yang@Sun.COM * Update the kstats.
19418160SWentao.Yang@Sun.COM */
19428160SWentao.Yang@Sun.COM static int
vnet_hio_update_kstats(kstat_t * ksp,int rw)19438160SWentao.Yang@Sun.COM vnet_hio_update_kstats(kstat_t *ksp, int rw)
19448160SWentao.Yang@Sun.COM {
19458160SWentao.Yang@Sun.COM vnet_t *vnetp;
19468160SWentao.Yang@Sun.COM vnet_res_t *vresp;
19478160SWentao.Yang@Sun.COM vnet_hio_stats_t statsp;
19488160SWentao.Yang@Sun.COM vnet_hio_kstats_t *hiokp;
19498160SWentao.Yang@Sun.COM
19508160SWentao.Yang@Sun.COM vresp = (vnet_res_t *)ksp->ks_private;
19518160SWentao.Yang@Sun.COM vnetp = vresp->vnetp;
19528160SWentao.Yang@Sun.COM
19538160SWentao.Yang@Sun.COM bzero(&statsp, sizeof (vnet_hio_stats_t));
19548160SWentao.Yang@Sun.COM
19558160SWentao.Yang@Sun.COM READ_ENTER(&vnetp->vsw_fp_rw);
19568160SWentao.Yang@Sun.COM if (vnetp->hio_fp == NULL) {
19578160SWentao.Yang@Sun.COM /* not using hio resources, just return */
19588160SWentao.Yang@Sun.COM RW_EXIT(&vnetp->vsw_fp_rw);
19598160SWentao.Yang@Sun.COM return (0);
19608160SWentao.Yang@Sun.COM }
19618160SWentao.Yang@Sun.COM VNET_FDBE_REFHOLD(vnetp->hio_fp);
19628160SWentao.Yang@Sun.COM RW_EXIT(&vnetp->vsw_fp_rw);
19638160SWentao.Yang@Sun.COM vnet_hio_get_stats(vnetp->hio_fp, &statsp);
19648160SWentao.Yang@Sun.COM VNET_FDBE_REFRELE(vnetp->hio_fp);
19658160SWentao.Yang@Sun.COM
19668160SWentao.Yang@Sun.COM hiokp = (vnet_hio_kstats_t *)ksp->ks_data;
19678160SWentao.Yang@Sun.COM
19688160SWentao.Yang@Sun.COM if (rw == KSTAT_READ) {
19698160SWentao.Yang@Sun.COM /* Link Input/Output stats */
19708160SWentao.Yang@Sun.COM hiokp->ipackets.value.ul = (uint32_t)statsp.ipackets;
19718160SWentao.Yang@Sun.COM hiokp->ipackets64.value.ull = statsp.ipackets;
19728160SWentao.Yang@Sun.COM hiokp->ierrors.value.ul = statsp.ierrors;
19738160SWentao.Yang@Sun.COM hiokp->opackets.value.ul = (uint32_t)statsp.opackets;
19748160SWentao.Yang@Sun.COM hiokp->opackets64.value.ull = statsp.opackets;
19758160SWentao.Yang@Sun.COM hiokp->oerrors.value.ul = statsp.oerrors;
19768160SWentao.Yang@Sun.COM
19778160SWentao.Yang@Sun.COM /* MIB II kstat variables */
19788160SWentao.Yang@Sun.COM hiokp->rbytes.value.ul = (uint32_t)statsp.rbytes;
19798160SWentao.Yang@Sun.COM hiokp->rbytes64.value.ull = statsp.rbytes;
19808160SWentao.Yang@Sun.COM hiokp->obytes.value.ul = (uint32_t)statsp.obytes;
19818160SWentao.Yang@Sun.COM hiokp->obytes64.value.ull = statsp.obytes;
19828160SWentao.Yang@Sun.COM hiokp->multircv.value.ul = statsp.multircv;
19838160SWentao.Yang@Sun.COM hiokp->multixmt.value.ul = statsp.multixmt;
19848160SWentao.Yang@Sun.COM hiokp->brdcstrcv.value.ul = statsp.brdcstrcv;
19858160SWentao.Yang@Sun.COM hiokp->brdcstxmt.value.ul = statsp.brdcstxmt;
19868160SWentao.Yang@Sun.COM hiokp->norcvbuf.value.ul = statsp.norcvbuf;
19878160SWentao.Yang@Sun.COM hiokp->noxmtbuf.value.ul = statsp.noxmtbuf;
19888160SWentao.Yang@Sun.COM } else {
19898160SWentao.Yang@Sun.COM return (EACCES);
19908160SWentao.Yang@Sun.COM }
19918160SWentao.Yang@Sun.COM
19928160SWentao.Yang@Sun.COM return (0);
19938160SWentao.Yang@Sun.COM }
19948160SWentao.Yang@Sun.COM
19958160SWentao.Yang@Sun.COM static void
vnet_hio_get_stats(vnet_res_t * vresp,vnet_hio_stats_t * statsp)19968160SWentao.Yang@Sun.COM vnet_hio_get_stats(vnet_res_t *vresp, vnet_hio_stats_t *statsp)
19978160SWentao.Yang@Sun.COM {
19988160SWentao.Yang@Sun.COM mac_register_t *macp;
19998160SWentao.Yang@Sun.COM mac_callbacks_t *cbp;
20008160SWentao.Yang@Sun.COM uint64_t val;
20018160SWentao.Yang@Sun.COM int stat;
20028160SWentao.Yang@Sun.COM
20038160SWentao.Yang@Sun.COM /*
20048160SWentao.Yang@Sun.COM * get the specified statistics from the underlying nxge.
20058160SWentao.Yang@Sun.COM */
20068160SWentao.Yang@Sun.COM macp = &vresp->macreg;
20078160SWentao.Yang@Sun.COM cbp = macp->m_callbacks;
20088160SWentao.Yang@Sun.COM for (stat = MAC_STAT_MIN; stat < MAC_STAT_OVERFLOWS; stat++) {
20098160SWentao.Yang@Sun.COM if (cbp->mc_getstat(macp->m_driver, stat, &val) == 0) {
20108160SWentao.Yang@Sun.COM switch (stat) {
20118160SWentao.Yang@Sun.COM case MAC_STAT_IPACKETS:
20128160SWentao.Yang@Sun.COM statsp->ipackets = val;
20138160SWentao.Yang@Sun.COM break;
20148160SWentao.Yang@Sun.COM
20158160SWentao.Yang@Sun.COM case MAC_STAT_IERRORS:
20168160SWentao.Yang@Sun.COM statsp->ierrors = val;
20178160SWentao.Yang@Sun.COM break;
20188160SWentao.Yang@Sun.COM
20198160SWentao.Yang@Sun.COM case MAC_STAT_OPACKETS:
20208160SWentao.Yang@Sun.COM statsp->opackets = val;
20218160SWentao.Yang@Sun.COM break;
20228160SWentao.Yang@Sun.COM
20238160SWentao.Yang@Sun.COM case MAC_STAT_OERRORS:
20248160SWentao.Yang@Sun.COM statsp->oerrors = val;
20258160SWentao.Yang@Sun.COM break;
20268160SWentao.Yang@Sun.COM
20278160SWentao.Yang@Sun.COM case MAC_STAT_RBYTES:
20288160SWentao.Yang@Sun.COM statsp->rbytes = val;
20298160SWentao.Yang@Sun.COM break;
20308160SWentao.Yang@Sun.COM
20318160SWentao.Yang@Sun.COM case MAC_STAT_OBYTES:
20328160SWentao.Yang@Sun.COM statsp->obytes = val;
20338160SWentao.Yang@Sun.COM break;
20348160SWentao.Yang@Sun.COM
20358160SWentao.Yang@Sun.COM case MAC_STAT_MULTIRCV:
20368160SWentao.Yang@Sun.COM statsp->multircv = val;
20378160SWentao.Yang@Sun.COM break;
20388160SWentao.Yang@Sun.COM
20398160SWentao.Yang@Sun.COM case MAC_STAT_MULTIXMT:
20408160SWentao.Yang@Sun.COM statsp->multixmt = val;
20418160SWentao.Yang@Sun.COM break;
20428160SWentao.Yang@Sun.COM
20438160SWentao.Yang@Sun.COM case MAC_STAT_BRDCSTRCV:
20448160SWentao.Yang@Sun.COM statsp->brdcstrcv = val;
20458160SWentao.Yang@Sun.COM break;
20468160SWentao.Yang@Sun.COM
20478160SWentao.Yang@Sun.COM case MAC_STAT_BRDCSTXMT:
20488160SWentao.Yang@Sun.COM statsp->brdcstxmt = val;
20498160SWentao.Yang@Sun.COM break;
20508160SWentao.Yang@Sun.COM
20518160SWentao.Yang@Sun.COM case MAC_STAT_NOXMTBUF:
20528160SWentao.Yang@Sun.COM statsp->noxmtbuf = val;
20538160SWentao.Yang@Sun.COM break;
20548160SWentao.Yang@Sun.COM
20558160SWentao.Yang@Sun.COM case MAC_STAT_NORCVBUF:
20568160SWentao.Yang@Sun.COM statsp->norcvbuf = val;
20578160SWentao.Yang@Sun.COM break;
20588160SWentao.Yang@Sun.COM
20598160SWentao.Yang@Sun.COM default:
20608160SWentao.Yang@Sun.COM /*
20618160SWentao.Yang@Sun.COM * parameters not interested.
20628160SWentao.Yang@Sun.COM */
20638160SWentao.Yang@Sun.COM break;
20648160SWentao.Yang@Sun.COM }
20658160SWentao.Yang@Sun.COM }
20668160SWentao.Yang@Sun.COM }
20678160SWentao.Yang@Sun.COM }
20689336SSriharsha.Basavapatna@Sun.COM
206910309SSriharsha.Basavapatna@Sun.COM static boolean_t
vnet_m_capab(void * arg,mac_capab_t cap,void * cap_data)207010309SSriharsha.Basavapatna@Sun.COM vnet_m_capab(void *arg, mac_capab_t cap, void *cap_data)
207110309SSriharsha.Basavapatna@Sun.COM {
207210309SSriharsha.Basavapatna@Sun.COM vnet_t *vnetp = (vnet_t *)arg;
207310309SSriharsha.Basavapatna@Sun.COM
207410309SSriharsha.Basavapatna@Sun.COM if (vnetp == NULL) {
207510309SSriharsha.Basavapatna@Sun.COM return (0);
207610309SSriharsha.Basavapatna@Sun.COM }
207710309SSriharsha.Basavapatna@Sun.COM
207810309SSriharsha.Basavapatna@Sun.COM switch (cap) {
207910309SSriharsha.Basavapatna@Sun.COM
208010309SSriharsha.Basavapatna@Sun.COM case MAC_CAPAB_RINGS: {
208110309SSriharsha.Basavapatna@Sun.COM
208210309SSriharsha.Basavapatna@Sun.COM mac_capab_rings_t *cap_rings = cap_data;
208310309SSriharsha.Basavapatna@Sun.COM /*
208410309SSriharsha.Basavapatna@Sun.COM * Rings Capability Notes:
208510309SSriharsha.Basavapatna@Sun.COM * We advertise rings to make use of the rings framework in
208610309SSriharsha.Basavapatna@Sun.COM * gldv3 mac layer, to improve the performance. This is
208710309SSriharsha.Basavapatna@Sun.COM * specifically needed when a Hybrid resource (with multiple
208810309SSriharsha.Basavapatna@Sun.COM * tx/rx hardware rings) is assigned to a vnet device. We also
208910309SSriharsha.Basavapatna@Sun.COM * leverage this for the normal case when no Hybrid resource is
209010309SSriharsha.Basavapatna@Sun.COM * assigned.
209110309SSriharsha.Basavapatna@Sun.COM *
209210309SSriharsha.Basavapatna@Sun.COM * Ring Allocation:
209310309SSriharsha.Basavapatna@Sun.COM * - TX path:
209410309SSriharsha.Basavapatna@Sun.COM * We expose a pseudo ring group with 2 pseudo tx rings (as
209510309SSriharsha.Basavapatna@Sun.COM * currently HybridIO exports only 2 rings) In the normal case,
209610309SSriharsha.Basavapatna@Sun.COM * transmit traffic that comes down to the driver through the
209710309SSriharsha.Basavapatna@Sun.COM * mri_tx (vnet_tx_ring_send()) entry point goes through the
209810309SSriharsha.Basavapatna@Sun.COM * distributed switching algorithm in vnet and gets transmitted
209910309SSriharsha.Basavapatna@Sun.COM * over a port/LDC in the vgen layer to either the vswitch or a
210010309SSriharsha.Basavapatna@Sun.COM * peer vnet. If and when a Hybrid resource is assigned to the
210110309SSriharsha.Basavapatna@Sun.COM * vnet, we obtain the tx ring information of the Hybrid device
210210309SSriharsha.Basavapatna@Sun.COM * (nxge) and map the pseudo rings 1:1 to the 2 hw tx rings.
210310309SSriharsha.Basavapatna@Sun.COM * Traffic being sent over the Hybrid resource by the mac layer
210410309SSriharsha.Basavapatna@Sun.COM * gets spread across both hw rings, as they are mapped to the
210510309SSriharsha.Basavapatna@Sun.COM * 2 pseudo tx rings in vnet.
210610309SSriharsha.Basavapatna@Sun.COM *
210710309SSriharsha.Basavapatna@Sun.COM * - RX path:
210810309SSriharsha.Basavapatna@Sun.COM * We expose a pseudo ring group with 3 pseudo rx rings (static
210910309SSriharsha.Basavapatna@Sun.COM * rings) initially. The first (default) pseudo rx ring is
211010309SSriharsha.Basavapatna@Sun.COM * reserved for the resource that connects to the vswitch
211110309SSriharsha.Basavapatna@Sun.COM * service. The next 2 rings are reserved for a Hybrid resource
211210309SSriharsha.Basavapatna@Sun.COM * that may be assigned to the vnet device. If and when a
211310309SSriharsha.Basavapatna@Sun.COM * Hybrid resource is assigned to the vnet, we obtain the rx
211410309SSriharsha.Basavapatna@Sun.COM * ring information of the Hybrid device (nxge) and map these
211510309SSriharsha.Basavapatna@Sun.COM * pseudo rings 1:1 to the 2 hw rx rings. For each additional
211610309SSriharsha.Basavapatna@Sun.COM * resource that connects to a peer vnet, we dynamically
211710309SSriharsha.Basavapatna@Sun.COM * allocate a pseudo rx ring and map it to that resource, when
211810309SSriharsha.Basavapatna@Sun.COM * the resource gets added; and the pseudo rx ring is
211910309SSriharsha.Basavapatna@Sun.COM * dynamically registered with the upper mac layer. We do the
212010309SSriharsha.Basavapatna@Sun.COM * reverse and unregister the ring with the mac layer when
212110309SSriharsha.Basavapatna@Sun.COM * the resource gets removed.
212210309SSriharsha.Basavapatna@Sun.COM *
212310309SSriharsha.Basavapatna@Sun.COM * Synchronization notes:
212410309SSriharsha.Basavapatna@Sun.COM * We don't need any lock to protect members of ring structure,
212510309SSriharsha.Basavapatna@Sun.COM * specifically ringp->hw_rh, in either the TX or the RX ring,
212610309SSriharsha.Basavapatna@Sun.COM * as explained below.
212710309SSriharsha.Basavapatna@Sun.COM * - TX ring:
212810309SSriharsha.Basavapatna@Sun.COM * ring->hw_rh is initialized only when a Hybrid resource is
212910309SSriharsha.Basavapatna@Sun.COM * associated; and gets referenced only in vnet_hio_tx(). The
213010309SSriharsha.Basavapatna@Sun.COM * Hybrid resource itself is available in fdb only after tx
213110309SSriharsha.Basavapatna@Sun.COM * hwrings are found and mapped; i.e, in vio_net_resource_reg()
213210309SSriharsha.Basavapatna@Sun.COM * we call vnet_bind_rings() first and then call
213310309SSriharsha.Basavapatna@Sun.COM * vnet_start_resources() which adds an entry to fdb. For
213410309SSriharsha.Basavapatna@Sun.COM * traffic going over LDC resources, we don't reference
213510309SSriharsha.Basavapatna@Sun.COM * ring->hw_rh at all.
213610309SSriharsha.Basavapatna@Sun.COM * - RX ring:
213710309SSriharsha.Basavapatna@Sun.COM * For rings mapped to Hybrid resource ring->hw_rh is
213810309SSriharsha.Basavapatna@Sun.COM * initialized and only then do we add the rx callback for
213910309SSriharsha.Basavapatna@Sun.COM * the underlying Hybrid resource; we disable callbacks before
214010309SSriharsha.Basavapatna@Sun.COM * we unmap ring->hw_rh. For rings mapped to LDC resources, we
214110309SSriharsha.Basavapatna@Sun.COM * stop the rx callbacks (in vgen) before we remove ring->hw_rh
214210309SSriharsha.Basavapatna@Sun.COM * (vio_net_resource_unreg()).
214311878SVenu.Iyer@Sun.COM * Also, we access ring->hw_rh in vnet_rx_ring_stat().
214411878SVenu.Iyer@Sun.COM * Note that for rings mapped to Hybrid resource, though the
214511878SVenu.Iyer@Sun.COM * rings are statically registered with the mac layer, its
214611878SVenu.Iyer@Sun.COM * hardware ring mapping (ringp->hw_rh) can be torn down in
214711878SVenu.Iyer@Sun.COM * vnet_unbind_hwrings() while the kstat operation is in
214811878SVenu.Iyer@Sun.COM * progress. To protect against this, we hold a reference to
214911878SVenu.Iyer@Sun.COM * the resource in FDB; this ensures that the thread in
215011878SVenu.Iyer@Sun.COM * vio_net_resource_unreg() waits for the reference to be
215111878SVenu.Iyer@Sun.COM * dropped before unbinding the ring.
215211878SVenu.Iyer@Sun.COM *
215311878SVenu.Iyer@Sun.COM * We don't need to do this for rings mapped to LDC resources.
215411878SVenu.Iyer@Sun.COM * These rings are registered/unregistered dynamically with
215511878SVenu.Iyer@Sun.COM * the mac layer and so any attempt to unregister the ring
215611878SVenu.Iyer@Sun.COM * while kstat operation is in progress will block in
215711878SVenu.Iyer@Sun.COM * mac_group_rem_ring(). Thus implicitly protects the
215811878SVenu.Iyer@Sun.COM * resource (ringp->hw_rh) from disappearing.
215910309SSriharsha.Basavapatna@Sun.COM */
216010309SSriharsha.Basavapatna@Sun.COM
216110309SSriharsha.Basavapatna@Sun.COM if (cap_rings->mr_type == MAC_RING_TYPE_RX) {
216210309SSriharsha.Basavapatna@Sun.COM cap_rings->mr_group_type = MAC_GROUP_TYPE_STATIC;
216310309SSriharsha.Basavapatna@Sun.COM
216410309SSriharsha.Basavapatna@Sun.COM /*
216510309SSriharsha.Basavapatna@Sun.COM * The ring_cnt for rx grp is initialized in
216610309SSriharsha.Basavapatna@Sun.COM * vnet_ring_grp_init(). Later, the ring_cnt gets
216710309SSriharsha.Basavapatna@Sun.COM * updated dynamically whenever LDC resources are added
216810309SSriharsha.Basavapatna@Sun.COM * or removed.
216910309SSriharsha.Basavapatna@Sun.COM */
217010309SSriharsha.Basavapatna@Sun.COM cap_rings->mr_rnum = vnetp->rx_grp[0].ring_cnt;
217110309SSriharsha.Basavapatna@Sun.COM cap_rings->mr_rget = vnet_get_ring;
217210309SSriharsha.Basavapatna@Sun.COM
217310309SSriharsha.Basavapatna@Sun.COM cap_rings->mr_gnum = VNET_NUM_PSEUDO_GROUPS;
217410309SSriharsha.Basavapatna@Sun.COM cap_rings->mr_gget = vnet_get_group;
217510309SSriharsha.Basavapatna@Sun.COM cap_rings->mr_gaddring = NULL;
217610309SSriharsha.Basavapatna@Sun.COM cap_rings->mr_gremring = NULL;
217710309SSriharsha.Basavapatna@Sun.COM } else {
217810309SSriharsha.Basavapatna@Sun.COM cap_rings->mr_group_type = MAC_GROUP_TYPE_STATIC;
217910309SSriharsha.Basavapatna@Sun.COM
218010309SSriharsha.Basavapatna@Sun.COM /*
218110309SSriharsha.Basavapatna@Sun.COM * The ring_cnt for tx grp is initialized in
218210309SSriharsha.Basavapatna@Sun.COM * vnet_ring_grp_init() and remains constant, as we
218310309SSriharsha.Basavapatna@Sun.COM * do not support dymanic tx rings for now.
218410309SSriharsha.Basavapatna@Sun.COM */
218510309SSriharsha.Basavapatna@Sun.COM cap_rings->mr_rnum = vnetp->tx_grp[0].ring_cnt;
218610309SSriharsha.Basavapatna@Sun.COM cap_rings->mr_rget = vnet_get_ring;
218710309SSriharsha.Basavapatna@Sun.COM
218810309SSriharsha.Basavapatna@Sun.COM /*
218910309SSriharsha.Basavapatna@Sun.COM * Transmit rings are not grouped; i.e, the number of
219010309SSriharsha.Basavapatna@Sun.COM * transmit ring groups advertised should be set to 0.
219110309SSriharsha.Basavapatna@Sun.COM */
219210309SSriharsha.Basavapatna@Sun.COM cap_rings->mr_gnum = 0;
219310309SSriharsha.Basavapatna@Sun.COM
219410309SSriharsha.Basavapatna@Sun.COM cap_rings->mr_gget = vnet_get_group;
219510309SSriharsha.Basavapatna@Sun.COM cap_rings->mr_gaddring = NULL;
219610309SSriharsha.Basavapatna@Sun.COM cap_rings->mr_gremring = NULL;
219710309SSriharsha.Basavapatna@Sun.COM }
219810309SSriharsha.Basavapatna@Sun.COM return (B_TRUE);
219910309SSriharsha.Basavapatna@Sun.COM
220010309SSriharsha.Basavapatna@Sun.COM }
220110309SSriharsha.Basavapatna@Sun.COM
220210309SSriharsha.Basavapatna@Sun.COM default:
220310309SSriharsha.Basavapatna@Sun.COM break;
220410309SSriharsha.Basavapatna@Sun.COM
220510309SSriharsha.Basavapatna@Sun.COM }
220610309SSriharsha.Basavapatna@Sun.COM
220710309SSriharsha.Basavapatna@Sun.COM return (B_FALSE);
220810309SSriharsha.Basavapatna@Sun.COM }
220910309SSriharsha.Basavapatna@Sun.COM
221010309SSriharsha.Basavapatna@Sun.COM /*
221110309SSriharsha.Basavapatna@Sun.COM * Callback funtion for MAC layer to get ring information.
221210309SSriharsha.Basavapatna@Sun.COM */
221310309SSriharsha.Basavapatna@Sun.COM static void
vnet_get_ring(void * arg,mac_ring_type_t rtype,const int g_index,const int r_index,mac_ring_info_t * infop,mac_ring_handle_t r_handle)221410309SSriharsha.Basavapatna@Sun.COM vnet_get_ring(void *arg, mac_ring_type_t rtype, const int g_index,
221510309SSriharsha.Basavapatna@Sun.COM const int r_index, mac_ring_info_t *infop, mac_ring_handle_t r_handle)
221610309SSriharsha.Basavapatna@Sun.COM {
221710309SSriharsha.Basavapatna@Sun.COM vnet_t *vnetp = arg;
221810309SSriharsha.Basavapatna@Sun.COM
221910309SSriharsha.Basavapatna@Sun.COM switch (rtype) {
222010309SSriharsha.Basavapatna@Sun.COM
222110309SSriharsha.Basavapatna@Sun.COM case MAC_RING_TYPE_RX: {
222210309SSriharsha.Basavapatna@Sun.COM
222310309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_rx_group_t *rx_grp;
222410309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_rx_ring_t *rx_ringp;
222510309SSriharsha.Basavapatna@Sun.COM mac_intr_t *mintr;
222610309SSriharsha.Basavapatna@Sun.COM
222710309SSriharsha.Basavapatna@Sun.COM /* We advertised only one RX group */
222810309SSriharsha.Basavapatna@Sun.COM ASSERT(g_index == 0);
222910309SSriharsha.Basavapatna@Sun.COM rx_grp = &vnetp->rx_grp[g_index];
223010309SSriharsha.Basavapatna@Sun.COM
223110309SSriharsha.Basavapatna@Sun.COM /* Check the current # of rings in the rx group */
223210309SSriharsha.Basavapatna@Sun.COM ASSERT((r_index >= 0) && (r_index < rx_grp->max_ring_cnt));
223310309SSriharsha.Basavapatna@Sun.COM
223410309SSriharsha.Basavapatna@Sun.COM /* Get the ring based on the index */
223510309SSriharsha.Basavapatna@Sun.COM rx_ringp = &rx_grp->rings[r_index];
223610309SSriharsha.Basavapatna@Sun.COM
223710309SSriharsha.Basavapatna@Sun.COM rx_ringp->handle = r_handle;
223810309SSriharsha.Basavapatna@Sun.COM /*
223910309SSriharsha.Basavapatna@Sun.COM * Note: we don't need to save the incoming r_index in rx_ring,
224010309SSriharsha.Basavapatna@Sun.COM * as vnet_ring_grp_init() would have initialized the index for
224110309SSriharsha.Basavapatna@Sun.COM * each ring in the array.
224210309SSriharsha.Basavapatna@Sun.COM */
224310309SSriharsha.Basavapatna@Sun.COM rx_ringp->grp = rx_grp;
224410309SSriharsha.Basavapatna@Sun.COM rx_ringp->vnetp = vnetp;
224510309SSriharsha.Basavapatna@Sun.COM
224610309SSriharsha.Basavapatna@Sun.COM mintr = &infop->mri_intr;
224710309SSriharsha.Basavapatna@Sun.COM mintr->mi_handle = (mac_intr_handle_t)rx_ringp;
224810309SSriharsha.Basavapatna@Sun.COM mintr->mi_enable = (mac_intr_enable_t)vnet_ring_enable_intr;
224910309SSriharsha.Basavapatna@Sun.COM mintr->mi_disable = (mac_intr_disable_t)vnet_ring_disable_intr;
225010309SSriharsha.Basavapatna@Sun.COM
225110309SSriharsha.Basavapatna@Sun.COM infop->mri_driver = (mac_ring_driver_t)rx_ringp;
225210309SSriharsha.Basavapatna@Sun.COM infop->mri_start = vnet_rx_ring_start;
225310309SSriharsha.Basavapatna@Sun.COM infop->mri_stop = vnet_rx_ring_stop;
225411878SVenu.Iyer@Sun.COM infop->mri_stat = vnet_rx_ring_stat;
225510309SSriharsha.Basavapatna@Sun.COM
225610309SSriharsha.Basavapatna@Sun.COM /* Set the poll function, as this is an rx ring */
225710309SSriharsha.Basavapatna@Sun.COM infop->mri_poll = vnet_rx_poll;
225811878SVenu.Iyer@Sun.COM /*
225911878SVenu.Iyer@Sun.COM * MAC_RING_RX_ENQUEUE bit needed to be set for nxge
226011878SVenu.Iyer@Sun.COM * which was not sending packet chains in interrupt
226111878SVenu.Iyer@Sun.COM * context. For such drivers, packets are queued in
226211878SVenu.Iyer@Sun.COM * Rx soft rings so that we get a chance to switch
226311878SVenu.Iyer@Sun.COM * into a polling mode under backlog. This bug (not
226411878SVenu.Iyer@Sun.COM * sending packet chains) has now been fixed. Once
226511878SVenu.Iyer@Sun.COM * the performance impact is measured, this change
226611878SVenu.Iyer@Sun.COM * will be removed.
226711878SVenu.Iyer@Sun.COM */
226811878SVenu.Iyer@Sun.COM infop->mri_flags = (vnet_mac_rx_queuing ?
226911878SVenu.Iyer@Sun.COM MAC_RING_RX_ENQUEUE : 0);
227010309SSriharsha.Basavapatna@Sun.COM break;
227110309SSriharsha.Basavapatna@Sun.COM }
227210309SSriharsha.Basavapatna@Sun.COM
227310309SSriharsha.Basavapatna@Sun.COM case MAC_RING_TYPE_TX: {
227410309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_tx_group_t *tx_grp;
227510309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_tx_ring_t *tx_ringp;
227610309SSriharsha.Basavapatna@Sun.COM
227710309SSriharsha.Basavapatna@Sun.COM /*
227810309SSriharsha.Basavapatna@Sun.COM * No need to check grp index; mac layer passes -1 for it.
227910309SSriharsha.Basavapatna@Sun.COM */
228010309SSriharsha.Basavapatna@Sun.COM tx_grp = &vnetp->tx_grp[0];
228110309SSriharsha.Basavapatna@Sun.COM
228210309SSriharsha.Basavapatna@Sun.COM /* Check the # of rings in the tx group */
228310309SSriharsha.Basavapatna@Sun.COM ASSERT((r_index >= 0) && (r_index < tx_grp->ring_cnt));
228410309SSriharsha.Basavapatna@Sun.COM
228510309SSriharsha.Basavapatna@Sun.COM /* Get the ring based on the index */
228610309SSriharsha.Basavapatna@Sun.COM tx_ringp = &tx_grp->rings[r_index];
228710309SSriharsha.Basavapatna@Sun.COM
228810309SSriharsha.Basavapatna@Sun.COM tx_ringp->handle = r_handle;
228910309SSriharsha.Basavapatna@Sun.COM tx_ringp->index = r_index;
229010309SSriharsha.Basavapatna@Sun.COM tx_ringp->grp = tx_grp;
229110309SSriharsha.Basavapatna@Sun.COM tx_ringp->vnetp = vnetp;
229210309SSriharsha.Basavapatna@Sun.COM
229310309SSriharsha.Basavapatna@Sun.COM infop->mri_driver = (mac_ring_driver_t)tx_ringp;
229410309SSriharsha.Basavapatna@Sun.COM infop->mri_start = vnet_tx_ring_start;
229510309SSriharsha.Basavapatna@Sun.COM infop->mri_stop = vnet_tx_ring_stop;
229611878SVenu.Iyer@Sun.COM infop->mri_stat = vnet_tx_ring_stat;
229710309SSriharsha.Basavapatna@Sun.COM
229810309SSriharsha.Basavapatna@Sun.COM /* Set the transmit function, as this is a tx ring */
229910309SSriharsha.Basavapatna@Sun.COM infop->mri_tx = vnet_tx_ring_send;
230011878SVenu.Iyer@Sun.COM /*
230111878SVenu.Iyer@Sun.COM * MAC_RING_TX_SERIALIZE bit needs to be set while
230211878SVenu.Iyer@Sun.COM * hybridIO is enabled to workaround tx lock
230311878SVenu.Iyer@Sun.COM * contention issues in nxge.
230411878SVenu.Iyer@Sun.COM */
230511878SVenu.Iyer@Sun.COM infop->mri_flags = (vnet_mac_tx_serialize ?
230611878SVenu.Iyer@Sun.COM MAC_RING_TX_SERIALIZE : 0);
230710309SSriharsha.Basavapatna@Sun.COM break;
230810309SSriharsha.Basavapatna@Sun.COM }
230910309SSriharsha.Basavapatna@Sun.COM
231010309SSriharsha.Basavapatna@Sun.COM default:
231110309SSriharsha.Basavapatna@Sun.COM break;
231210309SSriharsha.Basavapatna@Sun.COM }
231310309SSriharsha.Basavapatna@Sun.COM }
231410309SSriharsha.Basavapatna@Sun.COM
231510309SSriharsha.Basavapatna@Sun.COM /*
231610309SSriharsha.Basavapatna@Sun.COM * Callback funtion for MAC layer to get group information.
231710309SSriharsha.Basavapatna@Sun.COM */
231810309SSriharsha.Basavapatna@Sun.COM static void
vnet_get_group(void * arg,mac_ring_type_t type,const int index,mac_group_info_t * infop,mac_group_handle_t handle)231910309SSriharsha.Basavapatna@Sun.COM vnet_get_group(void *arg, mac_ring_type_t type, const int index,
232010309SSriharsha.Basavapatna@Sun.COM mac_group_info_t *infop, mac_group_handle_t handle)
232110309SSriharsha.Basavapatna@Sun.COM {
232210309SSriharsha.Basavapatna@Sun.COM vnet_t *vnetp = (vnet_t *)arg;
232310309SSriharsha.Basavapatna@Sun.COM
232410309SSriharsha.Basavapatna@Sun.COM switch (type) {
232510309SSriharsha.Basavapatna@Sun.COM
232610309SSriharsha.Basavapatna@Sun.COM case MAC_RING_TYPE_RX:
232710309SSriharsha.Basavapatna@Sun.COM {
232810309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_rx_group_t *rx_grp;
232910309SSriharsha.Basavapatna@Sun.COM
233010309SSriharsha.Basavapatna@Sun.COM /* We advertised only one RX group */
233110309SSriharsha.Basavapatna@Sun.COM ASSERT(index == 0);
233210309SSriharsha.Basavapatna@Sun.COM
233310309SSriharsha.Basavapatna@Sun.COM rx_grp = &vnetp->rx_grp[index];
233410309SSriharsha.Basavapatna@Sun.COM rx_grp->handle = handle;
233510309SSriharsha.Basavapatna@Sun.COM rx_grp->index = index;
233610309SSriharsha.Basavapatna@Sun.COM rx_grp->vnetp = vnetp;
233710309SSriharsha.Basavapatna@Sun.COM
233810309SSriharsha.Basavapatna@Sun.COM infop->mgi_driver = (mac_group_driver_t)rx_grp;
233910309SSriharsha.Basavapatna@Sun.COM infop->mgi_start = NULL;
234010309SSriharsha.Basavapatna@Sun.COM infop->mgi_stop = NULL;
234110309SSriharsha.Basavapatna@Sun.COM infop->mgi_addmac = vnet_addmac;
234210309SSriharsha.Basavapatna@Sun.COM infop->mgi_remmac = vnet_remmac;
234310309SSriharsha.Basavapatna@Sun.COM infop->mgi_count = rx_grp->ring_cnt;
234410309SSriharsha.Basavapatna@Sun.COM
234510309SSriharsha.Basavapatna@Sun.COM break;
234610309SSriharsha.Basavapatna@Sun.COM }
234710309SSriharsha.Basavapatna@Sun.COM
234810309SSriharsha.Basavapatna@Sun.COM case MAC_RING_TYPE_TX:
234910309SSriharsha.Basavapatna@Sun.COM {
235010309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_tx_group_t *tx_grp;
235110309SSriharsha.Basavapatna@Sun.COM
235210309SSriharsha.Basavapatna@Sun.COM /* We advertised only one TX group */
235310309SSriharsha.Basavapatna@Sun.COM ASSERT(index == 0);
235410309SSriharsha.Basavapatna@Sun.COM
235510309SSriharsha.Basavapatna@Sun.COM tx_grp = &vnetp->tx_grp[index];
235610309SSriharsha.Basavapatna@Sun.COM tx_grp->handle = handle;
235710309SSriharsha.Basavapatna@Sun.COM tx_grp->index = index;
235810309SSriharsha.Basavapatna@Sun.COM tx_grp->vnetp = vnetp;
235910309SSriharsha.Basavapatna@Sun.COM
236010309SSriharsha.Basavapatna@Sun.COM infop->mgi_driver = (mac_group_driver_t)tx_grp;
236110309SSriharsha.Basavapatna@Sun.COM infop->mgi_start = NULL;
236210309SSriharsha.Basavapatna@Sun.COM infop->mgi_stop = NULL;
236310309SSriharsha.Basavapatna@Sun.COM infop->mgi_addmac = NULL;
236410309SSriharsha.Basavapatna@Sun.COM infop->mgi_remmac = NULL;
236510309SSriharsha.Basavapatna@Sun.COM infop->mgi_count = VNET_NUM_PSEUDO_TXRINGS;
236610309SSriharsha.Basavapatna@Sun.COM
236710309SSriharsha.Basavapatna@Sun.COM break;
236810309SSriharsha.Basavapatna@Sun.COM }
236910309SSriharsha.Basavapatna@Sun.COM
237010309SSriharsha.Basavapatna@Sun.COM default:
237110309SSriharsha.Basavapatna@Sun.COM break;
237210309SSriharsha.Basavapatna@Sun.COM
237310309SSriharsha.Basavapatna@Sun.COM }
237410309SSriharsha.Basavapatna@Sun.COM }
237510309SSriharsha.Basavapatna@Sun.COM
237610309SSriharsha.Basavapatna@Sun.COM static int
vnet_rx_ring_start(mac_ring_driver_t arg,uint64_t mr_gen_num)237710309SSriharsha.Basavapatna@Sun.COM vnet_rx_ring_start(mac_ring_driver_t arg, uint64_t mr_gen_num)
237810309SSriharsha.Basavapatna@Sun.COM {
237910309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_rx_ring_t *rx_ringp = (vnet_pseudo_rx_ring_t *)arg;
238010309SSriharsha.Basavapatna@Sun.COM int err;
238110309SSriharsha.Basavapatna@Sun.COM
238210309SSriharsha.Basavapatna@Sun.COM /*
238310309SSriharsha.Basavapatna@Sun.COM * If this ring is mapped to a LDC resource, simply mark the state to
238410309SSriharsha.Basavapatna@Sun.COM * indicate the ring is started and return.
238510309SSriharsha.Basavapatna@Sun.COM */
238610309SSriharsha.Basavapatna@Sun.COM if ((rx_ringp->state &
238710309SSriharsha.Basavapatna@Sun.COM (VNET_RXRING_LDC_SERVICE|VNET_RXRING_LDC_GUEST)) != 0) {
238810309SSriharsha.Basavapatna@Sun.COM rx_ringp->gen_num = mr_gen_num;
238910309SSriharsha.Basavapatna@Sun.COM rx_ringp->state |= VNET_RXRING_STARTED;
239010309SSriharsha.Basavapatna@Sun.COM return (0);
239110309SSriharsha.Basavapatna@Sun.COM }
239210309SSriharsha.Basavapatna@Sun.COM
239310309SSriharsha.Basavapatna@Sun.COM ASSERT((rx_ringp->state & VNET_RXRING_HYBRID) != 0);
239410309SSriharsha.Basavapatna@Sun.COM
239510309SSriharsha.Basavapatna@Sun.COM /*
239610309SSriharsha.Basavapatna@Sun.COM * This must be a ring reserved for a hwring. If the hwring is not
239710309SSriharsha.Basavapatna@Sun.COM * bound yet, simply mark the state to indicate the ring is started and
239810309SSriharsha.Basavapatna@Sun.COM * return. If and when a hybrid resource is activated for this vnet
239910309SSriharsha.Basavapatna@Sun.COM * device, we will bind the hwring and start it then. If a hwring is
240010309SSriharsha.Basavapatna@Sun.COM * already bound, start it now.
240110309SSriharsha.Basavapatna@Sun.COM */
240210309SSriharsha.Basavapatna@Sun.COM if (rx_ringp->hw_rh == NULL) {
240310309SSriharsha.Basavapatna@Sun.COM rx_ringp->gen_num = mr_gen_num;
240410309SSriharsha.Basavapatna@Sun.COM rx_ringp->state |= VNET_RXRING_STARTED;
240510309SSriharsha.Basavapatna@Sun.COM return (0);
240610309SSriharsha.Basavapatna@Sun.COM }
240710309SSriharsha.Basavapatna@Sun.COM
240810309SSriharsha.Basavapatna@Sun.COM err = mac_hwring_start(rx_ringp->hw_rh);
240910309SSriharsha.Basavapatna@Sun.COM if (err == 0) {
241010309SSriharsha.Basavapatna@Sun.COM rx_ringp->gen_num = mr_gen_num;
241110309SSriharsha.Basavapatna@Sun.COM rx_ringp->state |= VNET_RXRING_STARTED;
241210309SSriharsha.Basavapatna@Sun.COM } else {
241310309SSriharsha.Basavapatna@Sun.COM err = ENXIO;
241410309SSriharsha.Basavapatna@Sun.COM }
241510309SSriharsha.Basavapatna@Sun.COM
241610309SSriharsha.Basavapatna@Sun.COM return (err);
241710309SSriharsha.Basavapatna@Sun.COM }
241810309SSriharsha.Basavapatna@Sun.COM
241910309SSriharsha.Basavapatna@Sun.COM static void
vnet_rx_ring_stop(mac_ring_driver_t arg)242010309SSriharsha.Basavapatna@Sun.COM vnet_rx_ring_stop(mac_ring_driver_t arg)
242110309SSriharsha.Basavapatna@Sun.COM {
242210309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_rx_ring_t *rx_ringp = (vnet_pseudo_rx_ring_t *)arg;
242310309SSriharsha.Basavapatna@Sun.COM
242410309SSriharsha.Basavapatna@Sun.COM /*
242510309SSriharsha.Basavapatna@Sun.COM * If this ring is mapped to a LDC resource, simply mark the state to
242610309SSriharsha.Basavapatna@Sun.COM * indicate the ring is now stopped and return.
242710309SSriharsha.Basavapatna@Sun.COM */
242810309SSriharsha.Basavapatna@Sun.COM if ((rx_ringp->state &
242910309SSriharsha.Basavapatna@Sun.COM (VNET_RXRING_LDC_SERVICE|VNET_RXRING_LDC_GUEST)) != 0) {
243010309SSriharsha.Basavapatna@Sun.COM rx_ringp->state &= ~VNET_RXRING_STARTED;
243110439SWentao.Yang@Sun.COM return;
243210309SSriharsha.Basavapatna@Sun.COM }
243310309SSriharsha.Basavapatna@Sun.COM
243410309SSriharsha.Basavapatna@Sun.COM ASSERT((rx_ringp->state & VNET_RXRING_HYBRID) != 0);
243510309SSriharsha.Basavapatna@Sun.COM
243610309SSriharsha.Basavapatna@Sun.COM /*
243710309SSriharsha.Basavapatna@Sun.COM * This must be a ring reserved for a hwring. If the hwring is not
243810309SSriharsha.Basavapatna@Sun.COM * bound yet, simply mark the state to indicate the ring is stopped and
243910309SSriharsha.Basavapatna@Sun.COM * return. If a hwring is already bound, stop it now.
244010309SSriharsha.Basavapatna@Sun.COM */
244110309SSriharsha.Basavapatna@Sun.COM if (rx_ringp->hw_rh == NULL) {
244210309SSriharsha.Basavapatna@Sun.COM rx_ringp->state &= ~VNET_RXRING_STARTED;
244310309SSriharsha.Basavapatna@Sun.COM return;
244410309SSriharsha.Basavapatna@Sun.COM }
244510309SSriharsha.Basavapatna@Sun.COM
244610309SSriharsha.Basavapatna@Sun.COM mac_hwring_stop(rx_ringp->hw_rh);
244710309SSriharsha.Basavapatna@Sun.COM rx_ringp->state &= ~VNET_RXRING_STARTED;
244810309SSriharsha.Basavapatna@Sun.COM }
244910309SSriharsha.Basavapatna@Sun.COM
245011878SVenu.Iyer@Sun.COM static int
vnet_rx_ring_stat(mac_ring_driver_t rdriver,uint_t stat,uint64_t * val)245111878SVenu.Iyer@Sun.COM vnet_rx_ring_stat(mac_ring_driver_t rdriver, uint_t stat, uint64_t *val)
245211878SVenu.Iyer@Sun.COM {
245311878SVenu.Iyer@Sun.COM vnet_pseudo_rx_ring_t *rx_ringp = (vnet_pseudo_rx_ring_t *)rdriver;
245411878SVenu.Iyer@Sun.COM vnet_t *vnetp = (vnet_t *)rx_ringp->vnetp;
245511878SVenu.Iyer@Sun.COM vnet_res_t *vresp;
245611878SVenu.Iyer@Sun.COM mac_register_t *macp;
245711878SVenu.Iyer@Sun.COM mac_callbacks_t *cbp;
245811878SVenu.Iyer@Sun.COM
245911878SVenu.Iyer@Sun.COM /*
246011878SVenu.Iyer@Sun.COM * Refer to vnet_m_capab() function for detailed comments on ring
246111878SVenu.Iyer@Sun.COM * synchronization.
246211878SVenu.Iyer@Sun.COM */
246311878SVenu.Iyer@Sun.COM if ((rx_ringp->state & VNET_RXRING_HYBRID) != 0) {
246411878SVenu.Iyer@Sun.COM READ_ENTER(&vnetp->vsw_fp_rw);
246511878SVenu.Iyer@Sun.COM if (vnetp->hio_fp == NULL) {
246611878SVenu.Iyer@Sun.COM RW_EXIT(&vnetp->vsw_fp_rw);
246711878SVenu.Iyer@Sun.COM return (0);
246811878SVenu.Iyer@Sun.COM }
246911878SVenu.Iyer@Sun.COM
247011878SVenu.Iyer@Sun.COM VNET_FDBE_REFHOLD(vnetp->hio_fp);
247111878SVenu.Iyer@Sun.COM RW_EXIT(&vnetp->vsw_fp_rw);
247211881SVenu.Iyer@Sun.COM (void) mac_hwring_getstat(rx_ringp->hw_rh, stat, val);
247311878SVenu.Iyer@Sun.COM VNET_FDBE_REFRELE(vnetp->hio_fp);
247411878SVenu.Iyer@Sun.COM return (0);
247511878SVenu.Iyer@Sun.COM }
247611878SVenu.Iyer@Sun.COM
247711878SVenu.Iyer@Sun.COM ASSERT((rx_ringp->state &
247811878SVenu.Iyer@Sun.COM (VNET_RXRING_LDC_SERVICE|VNET_RXRING_LDC_GUEST)) != 0);
247911878SVenu.Iyer@Sun.COM vresp = (vnet_res_t *)rx_ringp->hw_rh;
248011878SVenu.Iyer@Sun.COM macp = &vresp->macreg;
248111878SVenu.Iyer@Sun.COM cbp = macp->m_callbacks;
248211878SVenu.Iyer@Sun.COM
248311878SVenu.Iyer@Sun.COM cbp->mc_getstat(macp->m_driver, stat, val);
248411878SVenu.Iyer@Sun.COM
248511878SVenu.Iyer@Sun.COM return (0);
248611878SVenu.Iyer@Sun.COM }
248711878SVenu.Iyer@Sun.COM
248810309SSriharsha.Basavapatna@Sun.COM /* ARGSUSED */
248910309SSriharsha.Basavapatna@Sun.COM static int
vnet_tx_ring_start(mac_ring_driver_t arg,uint64_t mr_gen_num)249010309SSriharsha.Basavapatna@Sun.COM vnet_tx_ring_start(mac_ring_driver_t arg, uint64_t mr_gen_num)
249110309SSriharsha.Basavapatna@Sun.COM {
249210309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_tx_ring_t *tx_ringp = (vnet_pseudo_tx_ring_t *)arg;
249310309SSriharsha.Basavapatna@Sun.COM
249410309SSriharsha.Basavapatna@Sun.COM tx_ringp->state |= VNET_TXRING_STARTED;
249510309SSriharsha.Basavapatna@Sun.COM return (0);
249610309SSriharsha.Basavapatna@Sun.COM }
249710309SSriharsha.Basavapatna@Sun.COM
249810309SSriharsha.Basavapatna@Sun.COM static void
vnet_tx_ring_stop(mac_ring_driver_t arg)249910309SSriharsha.Basavapatna@Sun.COM vnet_tx_ring_stop(mac_ring_driver_t arg)
250010309SSriharsha.Basavapatna@Sun.COM {
250110309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_tx_ring_t *tx_ringp = (vnet_pseudo_tx_ring_t *)arg;
250210309SSriharsha.Basavapatna@Sun.COM
250310309SSriharsha.Basavapatna@Sun.COM tx_ringp->state &= ~VNET_TXRING_STARTED;
250410309SSriharsha.Basavapatna@Sun.COM }
250510309SSriharsha.Basavapatna@Sun.COM
250611878SVenu.Iyer@Sun.COM static int
vnet_tx_ring_stat(mac_ring_driver_t rdriver,uint_t stat,uint64_t * val)250711878SVenu.Iyer@Sun.COM vnet_tx_ring_stat(mac_ring_driver_t rdriver, uint_t stat, uint64_t *val)
250811878SVenu.Iyer@Sun.COM {
250911878SVenu.Iyer@Sun.COM vnet_pseudo_tx_ring_t *tx_ringp = (vnet_pseudo_tx_ring_t *)rdriver;
251011878SVenu.Iyer@Sun.COM vnet_tx_ring_stats_t *statsp;
251111878SVenu.Iyer@Sun.COM
251211878SVenu.Iyer@Sun.COM statsp = &tx_ringp->tx_ring_stats;
251311878SVenu.Iyer@Sun.COM
251411878SVenu.Iyer@Sun.COM switch (stat) {
251511878SVenu.Iyer@Sun.COM case MAC_STAT_OPACKETS:
251611878SVenu.Iyer@Sun.COM *val = statsp->opackets;
251711878SVenu.Iyer@Sun.COM break;
251811878SVenu.Iyer@Sun.COM
251911878SVenu.Iyer@Sun.COM case MAC_STAT_OBYTES:
252011878SVenu.Iyer@Sun.COM *val = statsp->obytes;
252111878SVenu.Iyer@Sun.COM break;
252211878SVenu.Iyer@Sun.COM
252311878SVenu.Iyer@Sun.COM default:
252411878SVenu.Iyer@Sun.COM *val = 0;
252511878SVenu.Iyer@Sun.COM return (ENOTSUP);
252611878SVenu.Iyer@Sun.COM }
252711878SVenu.Iyer@Sun.COM
252811878SVenu.Iyer@Sun.COM return (0);
252911878SVenu.Iyer@Sun.COM }
253011878SVenu.Iyer@Sun.COM
253110309SSriharsha.Basavapatna@Sun.COM /*
253210309SSriharsha.Basavapatna@Sun.COM * Disable polling for a ring and enable its interrupt.
253310309SSriharsha.Basavapatna@Sun.COM */
253410309SSriharsha.Basavapatna@Sun.COM static int
vnet_ring_enable_intr(void * arg)253510309SSriharsha.Basavapatna@Sun.COM vnet_ring_enable_intr(void *arg)
253610309SSriharsha.Basavapatna@Sun.COM {
253710309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_rx_ring_t *rx_ringp = (vnet_pseudo_rx_ring_t *)arg;
253810309SSriharsha.Basavapatna@Sun.COM vnet_res_t *vresp;
253910309SSriharsha.Basavapatna@Sun.COM
254010309SSriharsha.Basavapatna@Sun.COM if (rx_ringp->hw_rh == NULL) {
254110309SSriharsha.Basavapatna@Sun.COM /*
254210309SSriharsha.Basavapatna@Sun.COM * Ring enable intr func is being invoked, but the ring is
254310309SSriharsha.Basavapatna@Sun.COM * not bound to any underlying resource ? This must be a ring
254410309SSriharsha.Basavapatna@Sun.COM * reserved for Hybrid resource and no such resource has been
254510309SSriharsha.Basavapatna@Sun.COM * assigned to this vnet device yet. We simply return success.
254610309SSriharsha.Basavapatna@Sun.COM */
254710309SSriharsha.Basavapatna@Sun.COM ASSERT((rx_ringp->state & VNET_RXRING_HYBRID) != 0);
254810309SSriharsha.Basavapatna@Sun.COM return (0);
254910309SSriharsha.Basavapatna@Sun.COM }
255010309SSriharsha.Basavapatna@Sun.COM
255110309SSriharsha.Basavapatna@Sun.COM /*
255210309SSriharsha.Basavapatna@Sun.COM * The rx ring has been bound to either a LDC or a Hybrid resource.
255310309SSriharsha.Basavapatna@Sun.COM * Call the appropriate function to enable interrupts for the ring.
255410309SSriharsha.Basavapatna@Sun.COM */
255510309SSriharsha.Basavapatna@Sun.COM if (rx_ringp->state & VNET_RXRING_HYBRID) {
255610309SSriharsha.Basavapatna@Sun.COM return (mac_hwring_enable_intr(rx_ringp->hw_rh));
255710309SSriharsha.Basavapatna@Sun.COM } else {
255810309SSriharsha.Basavapatna@Sun.COM vresp = (vnet_res_t *)rx_ringp->hw_rh;
255910309SSriharsha.Basavapatna@Sun.COM return (vgen_enable_intr(vresp->macreg.m_driver));
256010309SSriharsha.Basavapatna@Sun.COM }
256110309SSriharsha.Basavapatna@Sun.COM }
256210309SSriharsha.Basavapatna@Sun.COM
256310309SSriharsha.Basavapatna@Sun.COM /*
256410309SSriharsha.Basavapatna@Sun.COM * Enable polling for a ring and disable its interrupt.
256510309SSriharsha.Basavapatna@Sun.COM */
256610309SSriharsha.Basavapatna@Sun.COM static int
vnet_ring_disable_intr(void * arg)256710309SSriharsha.Basavapatna@Sun.COM vnet_ring_disable_intr(void *arg)
256810309SSriharsha.Basavapatna@Sun.COM {
256910309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_rx_ring_t *rx_ringp = (vnet_pseudo_rx_ring_t *)arg;
257010309SSriharsha.Basavapatna@Sun.COM vnet_res_t *vresp;
257110309SSriharsha.Basavapatna@Sun.COM
257210309SSriharsha.Basavapatna@Sun.COM if (rx_ringp->hw_rh == NULL) {
257310309SSriharsha.Basavapatna@Sun.COM /*
257410309SSriharsha.Basavapatna@Sun.COM * Ring disable intr func is being invoked, but the ring is
257510309SSriharsha.Basavapatna@Sun.COM * not bound to any underlying resource ? This must be a ring
257610309SSriharsha.Basavapatna@Sun.COM * reserved for Hybrid resource and no such resource has been
257710309SSriharsha.Basavapatna@Sun.COM * assigned to this vnet device yet. We simply return success.
257810309SSriharsha.Basavapatna@Sun.COM */
257910309SSriharsha.Basavapatna@Sun.COM ASSERT((rx_ringp->state & VNET_RXRING_HYBRID) != 0);
258010309SSriharsha.Basavapatna@Sun.COM return (0);
258110309SSriharsha.Basavapatna@Sun.COM }
258210309SSriharsha.Basavapatna@Sun.COM
258310309SSriharsha.Basavapatna@Sun.COM /*
258410309SSriharsha.Basavapatna@Sun.COM * The rx ring has been bound to either a LDC or a Hybrid resource.
258510309SSriharsha.Basavapatna@Sun.COM * Call the appropriate function to disable interrupts for the ring.
258610309SSriharsha.Basavapatna@Sun.COM */
258710309SSriharsha.Basavapatna@Sun.COM if (rx_ringp->state & VNET_RXRING_HYBRID) {
258810309SSriharsha.Basavapatna@Sun.COM return (mac_hwring_disable_intr(rx_ringp->hw_rh));
258910309SSriharsha.Basavapatna@Sun.COM } else {
259010309SSriharsha.Basavapatna@Sun.COM vresp = (vnet_res_t *)rx_ringp->hw_rh;
259110309SSriharsha.Basavapatna@Sun.COM return (vgen_disable_intr(vresp->macreg.m_driver));
259210309SSriharsha.Basavapatna@Sun.COM }
259310309SSriharsha.Basavapatna@Sun.COM }
259410309SSriharsha.Basavapatna@Sun.COM
259510309SSriharsha.Basavapatna@Sun.COM /*
259610309SSriharsha.Basavapatna@Sun.COM * Poll 'bytes_to_pickup' bytes of message from the rx ring.
259710309SSriharsha.Basavapatna@Sun.COM */
259810309SSriharsha.Basavapatna@Sun.COM static mblk_t *
vnet_rx_poll(void * arg,int bytes_to_pickup)259910309SSriharsha.Basavapatna@Sun.COM vnet_rx_poll(void *arg, int bytes_to_pickup)
260010309SSriharsha.Basavapatna@Sun.COM {
260110309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_rx_ring_t *rx_ringp = (vnet_pseudo_rx_ring_t *)arg;
260210309SSriharsha.Basavapatna@Sun.COM mblk_t *mp = NULL;
260310309SSriharsha.Basavapatna@Sun.COM vnet_res_t *vresp;
260410309SSriharsha.Basavapatna@Sun.COM vnet_t *vnetp = rx_ringp->vnetp;
260510309SSriharsha.Basavapatna@Sun.COM
260610309SSriharsha.Basavapatna@Sun.COM if (rx_ringp->hw_rh == NULL) {
260710309SSriharsha.Basavapatna@Sun.COM return (NULL);
260810309SSriharsha.Basavapatna@Sun.COM }
260910309SSriharsha.Basavapatna@Sun.COM
261010309SSriharsha.Basavapatna@Sun.COM if (rx_ringp->state & VNET_RXRING_HYBRID) {
261110309SSriharsha.Basavapatna@Sun.COM mp = mac_hwring_poll(rx_ringp->hw_rh, bytes_to_pickup);
261210309SSriharsha.Basavapatna@Sun.COM /*
261310309SSriharsha.Basavapatna@Sun.COM * Packets received over a hybrid resource need additional
261410309SSriharsha.Basavapatna@Sun.COM * processing to remove the tag, for the pvid case. The
261510309SSriharsha.Basavapatna@Sun.COM * underlying resource is not aware of the vnet's pvid and thus
261610309SSriharsha.Basavapatna@Sun.COM * packets are received with the vlan tag in the header; unlike
261710309SSriharsha.Basavapatna@Sun.COM * packets that are received over a ldc channel in which case
261810309SSriharsha.Basavapatna@Sun.COM * the peer vnet/vsw would have already removed the tag.
261910309SSriharsha.Basavapatna@Sun.COM */
262010309SSriharsha.Basavapatna@Sun.COM if (vnetp->pvid != vnetp->default_vlan_id) {
262110309SSriharsha.Basavapatna@Sun.COM vnet_rx_frames_untag(vnetp->pvid, &mp);
262210309SSriharsha.Basavapatna@Sun.COM }
262310309SSriharsha.Basavapatna@Sun.COM } else {
262410309SSriharsha.Basavapatna@Sun.COM vresp = (vnet_res_t *)rx_ringp->hw_rh;
2625*12011SSriharsha.Basavapatna@Sun.COM mp = vgen_rx_poll(vresp->macreg.m_driver, bytes_to_pickup);
262610309SSriharsha.Basavapatna@Sun.COM }
262710309SSriharsha.Basavapatna@Sun.COM return (mp);
262810309SSriharsha.Basavapatna@Sun.COM }
262910309SSriharsha.Basavapatna@Sun.COM
263010309SSriharsha.Basavapatna@Sun.COM /* ARGSUSED */
263110309SSriharsha.Basavapatna@Sun.COM void
vnet_hio_rx_cb(void * arg,mac_resource_handle_t mrh,mblk_t * mp,boolean_t loopback)263210309SSriharsha.Basavapatna@Sun.COM vnet_hio_rx_cb(void *arg, mac_resource_handle_t mrh, mblk_t *mp,
263310309SSriharsha.Basavapatna@Sun.COM boolean_t loopback)
263410309SSriharsha.Basavapatna@Sun.COM {
263510309SSriharsha.Basavapatna@Sun.COM vnet_t *vnetp = (vnet_t *)arg;
263610309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_rx_ring_t *ringp = (vnet_pseudo_rx_ring_t *)mrh;
263710309SSriharsha.Basavapatna@Sun.COM
263810309SSriharsha.Basavapatna@Sun.COM /*
263910309SSriharsha.Basavapatna@Sun.COM * Packets received over a hybrid resource need additional processing
264010309SSriharsha.Basavapatna@Sun.COM * to remove the tag, for the pvid case. The underlying resource is
264110309SSriharsha.Basavapatna@Sun.COM * not aware of the vnet's pvid and thus packets are received with the
264210309SSriharsha.Basavapatna@Sun.COM * vlan tag in the header; unlike packets that are received over a ldc
264310309SSriharsha.Basavapatna@Sun.COM * channel in which case the peer vnet/vsw would have already removed
264410309SSriharsha.Basavapatna@Sun.COM * the tag.
264510309SSriharsha.Basavapatna@Sun.COM */
264610309SSriharsha.Basavapatna@Sun.COM if (vnetp->pvid != vnetp->default_vlan_id) {
264710309SSriharsha.Basavapatna@Sun.COM vnet_rx_frames_untag(vnetp->pvid, &mp);
264810309SSriharsha.Basavapatna@Sun.COM if (mp == NULL) {
264910309SSriharsha.Basavapatna@Sun.COM return;
265010309SSriharsha.Basavapatna@Sun.COM }
265110309SSriharsha.Basavapatna@Sun.COM }
265210309SSriharsha.Basavapatna@Sun.COM mac_rx_ring(vnetp->mh, ringp->handle, mp, ringp->gen_num);
265310309SSriharsha.Basavapatna@Sun.COM }
265410309SSriharsha.Basavapatna@Sun.COM
265510309SSriharsha.Basavapatna@Sun.COM static int
vnet_addmac(void * arg,const uint8_t * mac_addr)265610309SSriharsha.Basavapatna@Sun.COM vnet_addmac(void *arg, const uint8_t *mac_addr)
265710309SSriharsha.Basavapatna@Sun.COM {
265810309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_rx_group_t *rx_grp = (vnet_pseudo_rx_group_t *)arg;
265910309SSriharsha.Basavapatna@Sun.COM vnet_t *vnetp;
266010309SSriharsha.Basavapatna@Sun.COM
266110309SSriharsha.Basavapatna@Sun.COM vnetp = rx_grp->vnetp;
266210309SSriharsha.Basavapatna@Sun.COM
266310309SSriharsha.Basavapatna@Sun.COM if (bcmp(mac_addr, vnetp->curr_macaddr, ETHERADDRL) == 0) {
266410309SSriharsha.Basavapatna@Sun.COM return (0);
266510309SSriharsha.Basavapatna@Sun.COM }
266610309SSriharsha.Basavapatna@Sun.COM
266710309SSriharsha.Basavapatna@Sun.COM cmn_err(CE_CONT, "!vnet%d: %s: Multiple macaddr unsupported\n",
266810309SSriharsha.Basavapatna@Sun.COM vnetp->instance, __func__);
266910309SSriharsha.Basavapatna@Sun.COM return (EINVAL);
267010309SSriharsha.Basavapatna@Sun.COM }
267110309SSriharsha.Basavapatna@Sun.COM
267210309SSriharsha.Basavapatna@Sun.COM static int
vnet_remmac(void * arg,const uint8_t * mac_addr)267310309SSriharsha.Basavapatna@Sun.COM vnet_remmac(void *arg, const uint8_t *mac_addr)
267410309SSriharsha.Basavapatna@Sun.COM {
267510309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_rx_group_t *rx_grp = (vnet_pseudo_rx_group_t *)arg;
267610309SSriharsha.Basavapatna@Sun.COM vnet_t *vnetp;
267710309SSriharsha.Basavapatna@Sun.COM
267810309SSriharsha.Basavapatna@Sun.COM vnetp = rx_grp->vnetp;
267910309SSriharsha.Basavapatna@Sun.COM
268010309SSriharsha.Basavapatna@Sun.COM if (bcmp(mac_addr, vnetp->curr_macaddr, ETHERADDRL) == 0) {
268110309SSriharsha.Basavapatna@Sun.COM return (0);
268210309SSriharsha.Basavapatna@Sun.COM }
268310309SSriharsha.Basavapatna@Sun.COM
268410309SSriharsha.Basavapatna@Sun.COM cmn_err(CE_CONT, "!vnet%d: %s: Invalid macaddr: %s\n",
268510309SSriharsha.Basavapatna@Sun.COM vnetp->instance, __func__, ether_sprintf((void *)mac_addr));
268610309SSriharsha.Basavapatna@Sun.COM return (EINVAL);
268710309SSriharsha.Basavapatna@Sun.COM }
268810309SSriharsha.Basavapatna@Sun.COM
268910309SSriharsha.Basavapatna@Sun.COM int
vnet_hio_mac_init(vnet_t * vnetp,char * ifname)269010309SSriharsha.Basavapatna@Sun.COM vnet_hio_mac_init(vnet_t *vnetp, char *ifname)
269110309SSriharsha.Basavapatna@Sun.COM {
269210309SSriharsha.Basavapatna@Sun.COM mac_handle_t mh;
269310309SSriharsha.Basavapatna@Sun.COM mac_client_handle_t mch = NULL;
269410309SSriharsha.Basavapatna@Sun.COM mac_unicast_handle_t muh = NULL;
269510309SSriharsha.Basavapatna@Sun.COM mac_diag_t diag;
269610309SSriharsha.Basavapatna@Sun.COM mac_register_t *macp;
269710309SSriharsha.Basavapatna@Sun.COM char client_name[MAXNAMELEN];
269810309SSriharsha.Basavapatna@Sun.COM int rv;
269910309SSriharsha.Basavapatna@Sun.COM uint16_t mac_flags = MAC_UNICAST_TAG_DISABLE |
270010309SSriharsha.Basavapatna@Sun.COM MAC_UNICAST_STRIP_DISABLE | MAC_UNICAST_PRIMARY;
270110309SSriharsha.Basavapatna@Sun.COM vio_net_callbacks_t vcb;
270210309SSriharsha.Basavapatna@Sun.COM ether_addr_t rem_addr =
270310309SSriharsha.Basavapatna@Sun.COM { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
270410309SSriharsha.Basavapatna@Sun.COM uint32_t retries = 0;
270510309SSriharsha.Basavapatna@Sun.COM
270610309SSriharsha.Basavapatna@Sun.COM if ((macp = mac_alloc(MAC_VERSION)) == NULL) {
270710309SSriharsha.Basavapatna@Sun.COM return (EAGAIN);
270810309SSriharsha.Basavapatna@Sun.COM }
270910309SSriharsha.Basavapatna@Sun.COM
271010309SSriharsha.Basavapatna@Sun.COM do {
271110309SSriharsha.Basavapatna@Sun.COM rv = mac_open_by_linkname(ifname, &mh);
271210309SSriharsha.Basavapatna@Sun.COM if (rv == 0) {
271310309SSriharsha.Basavapatna@Sun.COM break;
271410309SSriharsha.Basavapatna@Sun.COM }
271510309SSriharsha.Basavapatna@Sun.COM if (rv != ENOENT || (retries++ >= vnet_mac_open_retries)) {
271610309SSriharsha.Basavapatna@Sun.COM mac_free(macp);
271710309SSriharsha.Basavapatna@Sun.COM return (rv);
271810309SSriharsha.Basavapatna@Sun.COM }
271910309SSriharsha.Basavapatna@Sun.COM drv_usecwait(vnet_mac_open_delay);
272010309SSriharsha.Basavapatna@Sun.COM } while (rv == ENOENT);
272110309SSriharsha.Basavapatna@Sun.COM
272210309SSriharsha.Basavapatna@Sun.COM vnetp->hio_mh = mh;
272310309SSriharsha.Basavapatna@Sun.COM
272410309SSriharsha.Basavapatna@Sun.COM (void) snprintf(client_name, MAXNAMELEN, "vnet%d-%s", vnetp->instance,
272510309SSriharsha.Basavapatna@Sun.COM ifname);
272610309SSriharsha.Basavapatna@Sun.COM rv = mac_client_open(mh, &mch, client_name, MAC_OPEN_FLAGS_EXCLUSIVE);
272710309SSriharsha.Basavapatna@Sun.COM if (rv != 0) {
272810309SSriharsha.Basavapatna@Sun.COM goto fail;
272910309SSriharsha.Basavapatna@Sun.COM }
273010309SSriharsha.Basavapatna@Sun.COM vnetp->hio_mch = mch;
273110309SSriharsha.Basavapatna@Sun.COM
273210309SSriharsha.Basavapatna@Sun.COM rv = mac_unicast_add(mch, vnetp->curr_macaddr, mac_flags, &muh, 0,
273310309SSriharsha.Basavapatna@Sun.COM &diag);
273410309SSriharsha.Basavapatna@Sun.COM if (rv != 0) {
273510309SSriharsha.Basavapatna@Sun.COM goto fail;
273610309SSriharsha.Basavapatna@Sun.COM }
273710309SSriharsha.Basavapatna@Sun.COM vnetp->hio_muh = muh;
273810309SSriharsha.Basavapatna@Sun.COM
273910309SSriharsha.Basavapatna@Sun.COM macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
274010309SSriharsha.Basavapatna@Sun.COM macp->m_driver = vnetp;
274110309SSriharsha.Basavapatna@Sun.COM macp->m_dip = NULL;
274210309SSriharsha.Basavapatna@Sun.COM macp->m_src_addr = NULL;
274310309SSriharsha.Basavapatna@Sun.COM macp->m_callbacks = &vnet_hio_res_callbacks;
274410309SSriharsha.Basavapatna@Sun.COM macp->m_min_sdu = 0;
274510309SSriharsha.Basavapatna@Sun.COM macp->m_max_sdu = ETHERMTU;
274610309SSriharsha.Basavapatna@Sun.COM
274710309SSriharsha.Basavapatna@Sun.COM rv = vio_net_resource_reg(macp, VIO_NET_RES_HYBRID,
274810309SSriharsha.Basavapatna@Sun.COM vnetp->curr_macaddr, rem_addr, &vnetp->hio_vhp, &vcb);
274910309SSriharsha.Basavapatna@Sun.COM if (rv != 0) {
275010309SSriharsha.Basavapatna@Sun.COM goto fail;
275110309SSriharsha.Basavapatna@Sun.COM }
275210309SSriharsha.Basavapatna@Sun.COM mac_free(macp);
275310309SSriharsha.Basavapatna@Sun.COM
275410309SSriharsha.Basavapatna@Sun.COM /* add the recv callback */
275510309SSriharsha.Basavapatna@Sun.COM mac_rx_set(vnetp->hio_mch, vnet_hio_rx_cb, vnetp);
275610309SSriharsha.Basavapatna@Sun.COM
275710309SSriharsha.Basavapatna@Sun.COM return (0);
275810309SSriharsha.Basavapatna@Sun.COM
275910309SSriharsha.Basavapatna@Sun.COM fail:
276010309SSriharsha.Basavapatna@Sun.COM mac_free(macp);
276110309SSriharsha.Basavapatna@Sun.COM vnet_hio_mac_cleanup(vnetp);
276210309SSriharsha.Basavapatna@Sun.COM return (1);
276310309SSriharsha.Basavapatna@Sun.COM }
276410309SSriharsha.Basavapatna@Sun.COM
276510309SSriharsha.Basavapatna@Sun.COM void
vnet_hio_mac_cleanup(vnet_t * vnetp)276610309SSriharsha.Basavapatna@Sun.COM vnet_hio_mac_cleanup(vnet_t *vnetp)
276710309SSriharsha.Basavapatna@Sun.COM {
276810309SSriharsha.Basavapatna@Sun.COM if (vnetp->hio_vhp != NULL) {
276910309SSriharsha.Basavapatna@Sun.COM vio_net_resource_unreg(vnetp->hio_vhp);
277010309SSriharsha.Basavapatna@Sun.COM vnetp->hio_vhp = NULL;
277110309SSriharsha.Basavapatna@Sun.COM }
277210309SSriharsha.Basavapatna@Sun.COM
277310309SSriharsha.Basavapatna@Sun.COM if (vnetp->hio_muh != NULL) {
277411311SSurya.Prakki@Sun.COM (void) mac_unicast_remove(vnetp->hio_mch, vnetp->hio_muh);
277510309SSriharsha.Basavapatna@Sun.COM vnetp->hio_muh = NULL;
277610309SSriharsha.Basavapatna@Sun.COM }
277710309SSriharsha.Basavapatna@Sun.COM
277810309SSriharsha.Basavapatna@Sun.COM if (vnetp->hio_mch != NULL) {
277910309SSriharsha.Basavapatna@Sun.COM mac_client_close(vnetp->hio_mch, 0);
278010309SSriharsha.Basavapatna@Sun.COM vnetp->hio_mch = NULL;
278110309SSriharsha.Basavapatna@Sun.COM }
278210309SSriharsha.Basavapatna@Sun.COM
278310309SSriharsha.Basavapatna@Sun.COM if (vnetp->hio_mh != NULL) {
278410309SSriharsha.Basavapatna@Sun.COM mac_close(vnetp->hio_mh);
278510309SSriharsha.Basavapatna@Sun.COM vnetp->hio_mh = NULL;
278610309SSriharsha.Basavapatna@Sun.COM }
278710309SSriharsha.Basavapatna@Sun.COM }
278810309SSriharsha.Basavapatna@Sun.COM
278910309SSriharsha.Basavapatna@Sun.COM /* Bind pseudo rings to hwrings */
279010309SSriharsha.Basavapatna@Sun.COM static int
vnet_bind_hwrings(vnet_t * vnetp)279110309SSriharsha.Basavapatna@Sun.COM vnet_bind_hwrings(vnet_t *vnetp)
279210309SSriharsha.Basavapatna@Sun.COM {
279310309SSriharsha.Basavapatna@Sun.COM mac_ring_handle_t hw_rh[VNET_NUM_HYBRID_RINGS];
279410309SSriharsha.Basavapatna@Sun.COM mac_perim_handle_t mph1;
279510309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_rx_group_t *rx_grp;
279610309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_rx_ring_t *rx_ringp;
279710309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_tx_group_t *tx_grp;
279810309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_tx_ring_t *tx_ringp;
279910309SSriharsha.Basavapatna@Sun.COM int hw_ring_cnt;
280010309SSriharsha.Basavapatna@Sun.COM int i;
280110309SSriharsha.Basavapatna@Sun.COM int rv;
280210309SSriharsha.Basavapatna@Sun.COM
280310309SSriharsha.Basavapatna@Sun.COM mac_perim_enter_by_mh(vnetp->hio_mh, &mph1);
280410309SSriharsha.Basavapatna@Sun.COM
280510309SSriharsha.Basavapatna@Sun.COM /* Get the list of the underlying RX rings. */
280610309SSriharsha.Basavapatna@Sun.COM hw_ring_cnt = mac_hwrings_get(vnetp->hio_mch, &vnetp->rx_hwgh, hw_rh,
280710309SSriharsha.Basavapatna@Sun.COM MAC_RING_TYPE_RX);
280810309SSriharsha.Basavapatna@Sun.COM
280910309SSriharsha.Basavapatna@Sun.COM /* We expect the the # of hw rx rings to match VNET_NUM_HYBRID_RINGS */
281010309SSriharsha.Basavapatna@Sun.COM if (hw_ring_cnt != VNET_NUM_HYBRID_RINGS) {
281110309SSriharsha.Basavapatna@Sun.COM cmn_err(CE_WARN,
281210309SSriharsha.Basavapatna@Sun.COM "!vnet%d: vnet_bind_hwrings: bad rx hw_ring_cnt(%d)\n",
281310309SSriharsha.Basavapatna@Sun.COM vnetp->instance, hw_ring_cnt);
281410309SSriharsha.Basavapatna@Sun.COM goto fail;
281510309SSriharsha.Basavapatna@Sun.COM }
281610309SSriharsha.Basavapatna@Sun.COM
281710309SSriharsha.Basavapatna@Sun.COM if (vnetp->rx_hwgh != NULL) {
281810309SSriharsha.Basavapatna@Sun.COM /*
281910309SSriharsha.Basavapatna@Sun.COM * Quiesce the HW ring and the mac srs on the ring. Note
282010309SSriharsha.Basavapatna@Sun.COM * that the HW ring will be restarted when the pseudo ring
282110309SSriharsha.Basavapatna@Sun.COM * is started. At that time all the packets will be
282210309SSriharsha.Basavapatna@Sun.COM * directly passed up to the pseudo RX ring and handled
282310309SSriharsha.Basavapatna@Sun.COM * by mac srs created over the pseudo RX ring.
282410309SSriharsha.Basavapatna@Sun.COM */
282510309SSriharsha.Basavapatna@Sun.COM mac_rx_client_quiesce(vnetp->hio_mch);
282610309SSriharsha.Basavapatna@Sun.COM mac_srs_perm_quiesce(vnetp->hio_mch, B_TRUE);
282710309SSriharsha.Basavapatna@Sun.COM }
282810309SSriharsha.Basavapatna@Sun.COM
282910309SSriharsha.Basavapatna@Sun.COM /*
283010309SSriharsha.Basavapatna@Sun.COM * Bind the pseudo rings to the hwrings and start the hwrings.
283110309SSriharsha.Basavapatna@Sun.COM * Note we don't need to register these with the upper mac, as we have
283210309SSriharsha.Basavapatna@Sun.COM * statically exported these pseudo rxrings which are reserved for
283310309SSriharsha.Basavapatna@Sun.COM * rxrings of Hybrid resource.
283410309SSriharsha.Basavapatna@Sun.COM */
283510309SSriharsha.Basavapatna@Sun.COM rx_grp = &vnetp->rx_grp[0];
283610309SSriharsha.Basavapatna@Sun.COM for (i = 0; i < VNET_NUM_HYBRID_RINGS; i++) {
283710309SSriharsha.Basavapatna@Sun.COM /* Pick the rxrings reserved for Hybrid resource */
283810309SSriharsha.Basavapatna@Sun.COM rx_ringp = &rx_grp->rings[i + VNET_HYBRID_RXRING_INDEX];
283910309SSriharsha.Basavapatna@Sun.COM
284010309SSriharsha.Basavapatna@Sun.COM /* Store the hw ring handle */
284110309SSriharsha.Basavapatna@Sun.COM rx_ringp->hw_rh = hw_rh[i];
284210309SSriharsha.Basavapatna@Sun.COM
284310309SSriharsha.Basavapatna@Sun.COM /* Bind the pseudo ring to the underlying hwring */
284410309SSriharsha.Basavapatna@Sun.COM mac_hwring_setup(rx_ringp->hw_rh,
284511878SVenu.Iyer@Sun.COM (mac_resource_handle_t)rx_ringp, NULL);
284610309SSriharsha.Basavapatna@Sun.COM
284710309SSriharsha.Basavapatna@Sun.COM /* Start the hwring if needed */
284810309SSriharsha.Basavapatna@Sun.COM if (rx_ringp->state & VNET_RXRING_STARTED) {
284910309SSriharsha.Basavapatna@Sun.COM rv = mac_hwring_start(rx_ringp->hw_rh);
285010309SSriharsha.Basavapatna@Sun.COM if (rv != 0) {
285110309SSriharsha.Basavapatna@Sun.COM mac_hwring_teardown(rx_ringp->hw_rh);
285210309SSriharsha.Basavapatna@Sun.COM rx_ringp->hw_rh = NULL;
285310309SSriharsha.Basavapatna@Sun.COM goto fail;
285410309SSriharsha.Basavapatna@Sun.COM }
285510309SSriharsha.Basavapatna@Sun.COM }
285610309SSriharsha.Basavapatna@Sun.COM }
285710309SSriharsha.Basavapatna@Sun.COM
285810309SSriharsha.Basavapatna@Sun.COM /* Get the list of the underlying TX rings. */
285910309SSriharsha.Basavapatna@Sun.COM hw_ring_cnt = mac_hwrings_get(vnetp->hio_mch, &vnetp->tx_hwgh, hw_rh,
286010309SSriharsha.Basavapatna@Sun.COM MAC_RING_TYPE_TX);
286110309SSriharsha.Basavapatna@Sun.COM
286210309SSriharsha.Basavapatna@Sun.COM /* We expect the # of hw tx rings to match VNET_NUM_HYBRID_RINGS */
286310309SSriharsha.Basavapatna@Sun.COM if (hw_ring_cnt != VNET_NUM_HYBRID_RINGS) {
286410309SSriharsha.Basavapatna@Sun.COM cmn_err(CE_WARN,
286510309SSriharsha.Basavapatna@Sun.COM "!vnet%d: vnet_bind_hwrings: bad tx hw_ring_cnt(%d)\n",
286610309SSriharsha.Basavapatna@Sun.COM vnetp->instance, hw_ring_cnt);
286710309SSriharsha.Basavapatna@Sun.COM goto fail;
286810309SSriharsha.Basavapatna@Sun.COM }
286910309SSriharsha.Basavapatna@Sun.COM
287010309SSriharsha.Basavapatna@Sun.COM /*
287110309SSriharsha.Basavapatna@Sun.COM * Now map the pseudo txrings to the hw txrings. Note we don't need
287210309SSriharsha.Basavapatna@Sun.COM * to register these with the upper mac, as we have statically exported
287310309SSriharsha.Basavapatna@Sun.COM * these rings. Note that these rings will continue to be used for LDC
287410309SSriharsha.Basavapatna@Sun.COM * resources to peer vnets and vswitch (shared ring).
287510309SSriharsha.Basavapatna@Sun.COM */
287610309SSriharsha.Basavapatna@Sun.COM tx_grp = &vnetp->tx_grp[0];
287710309SSriharsha.Basavapatna@Sun.COM for (i = 0; i < tx_grp->ring_cnt; i++) {
287810309SSriharsha.Basavapatna@Sun.COM tx_ringp = &tx_grp->rings[i];
287910309SSriharsha.Basavapatna@Sun.COM tx_ringp->hw_rh = hw_rh[i];
288010309SSriharsha.Basavapatna@Sun.COM tx_ringp->state |= VNET_TXRING_HYBRID;
288110309SSriharsha.Basavapatna@Sun.COM }
288211878SVenu.Iyer@Sun.COM tx_grp->tx_notify_handle =
288311878SVenu.Iyer@Sun.COM mac_client_tx_notify(vnetp->hio_mch, vnet_tx_ring_update, vnetp);
288410309SSriharsha.Basavapatna@Sun.COM
288510309SSriharsha.Basavapatna@Sun.COM mac_perim_exit(mph1);
288610309SSriharsha.Basavapatna@Sun.COM return (0);
288710309SSriharsha.Basavapatna@Sun.COM
288810309SSriharsha.Basavapatna@Sun.COM fail:
288910309SSriharsha.Basavapatna@Sun.COM mac_perim_exit(mph1);
289010309SSriharsha.Basavapatna@Sun.COM vnet_unbind_hwrings(vnetp);
289110309SSriharsha.Basavapatna@Sun.COM return (1);
289210309SSriharsha.Basavapatna@Sun.COM }
289310309SSriharsha.Basavapatna@Sun.COM
289410309SSriharsha.Basavapatna@Sun.COM /* Unbind pseudo rings from hwrings */
289510309SSriharsha.Basavapatna@Sun.COM static void
vnet_unbind_hwrings(vnet_t * vnetp)289610309SSriharsha.Basavapatna@Sun.COM vnet_unbind_hwrings(vnet_t *vnetp)
289710309SSriharsha.Basavapatna@Sun.COM {
289810309SSriharsha.Basavapatna@Sun.COM mac_perim_handle_t mph1;
289910309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_rx_ring_t *rx_ringp;
290010309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_rx_group_t *rx_grp;
290110309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_tx_group_t *tx_grp;
290210309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_tx_ring_t *tx_ringp;
290310309SSriharsha.Basavapatna@Sun.COM int i;
290410309SSriharsha.Basavapatna@Sun.COM
290510309SSriharsha.Basavapatna@Sun.COM mac_perim_enter_by_mh(vnetp->hio_mh, &mph1);
290610309SSriharsha.Basavapatna@Sun.COM
290710309SSriharsha.Basavapatna@Sun.COM tx_grp = &vnetp->tx_grp[0];
290810309SSriharsha.Basavapatna@Sun.COM for (i = 0; i < VNET_NUM_HYBRID_RINGS; i++) {
290910309SSriharsha.Basavapatna@Sun.COM tx_ringp = &tx_grp->rings[i];
291010309SSriharsha.Basavapatna@Sun.COM if (tx_ringp->state & VNET_TXRING_HYBRID) {
291110309SSriharsha.Basavapatna@Sun.COM tx_ringp->state &= ~VNET_TXRING_HYBRID;
291210309SSriharsha.Basavapatna@Sun.COM tx_ringp->hw_rh = NULL;
291310309SSriharsha.Basavapatna@Sun.COM }
291410309SSriharsha.Basavapatna@Sun.COM }
291511878SVenu.Iyer@Sun.COM (void) mac_client_tx_notify(vnetp->hio_mch, NULL,
291611878SVenu.Iyer@Sun.COM tx_grp->tx_notify_handle);
291710309SSriharsha.Basavapatna@Sun.COM
291810309SSriharsha.Basavapatna@Sun.COM rx_grp = &vnetp->rx_grp[0];
291910309SSriharsha.Basavapatna@Sun.COM for (i = 0; i < VNET_NUM_HYBRID_RINGS; i++) {
292010309SSriharsha.Basavapatna@Sun.COM rx_ringp = &rx_grp->rings[i + VNET_HYBRID_RXRING_INDEX];
292110309SSriharsha.Basavapatna@Sun.COM if (rx_ringp->hw_rh != NULL) {
292210309SSriharsha.Basavapatna@Sun.COM /* Stop the hwring */
292310309SSriharsha.Basavapatna@Sun.COM mac_hwring_stop(rx_ringp->hw_rh);
292410309SSriharsha.Basavapatna@Sun.COM
292510309SSriharsha.Basavapatna@Sun.COM /* Teardown the hwring */
292610309SSriharsha.Basavapatna@Sun.COM mac_hwring_teardown(rx_ringp->hw_rh);
292710309SSriharsha.Basavapatna@Sun.COM rx_ringp->hw_rh = NULL;
292810309SSriharsha.Basavapatna@Sun.COM }
292910309SSriharsha.Basavapatna@Sun.COM }
293010309SSriharsha.Basavapatna@Sun.COM
293110309SSriharsha.Basavapatna@Sun.COM if (vnetp->rx_hwgh != NULL) {
293210309SSriharsha.Basavapatna@Sun.COM vnetp->rx_hwgh = NULL;
293310309SSriharsha.Basavapatna@Sun.COM /*
293410309SSriharsha.Basavapatna@Sun.COM * First clear the permanent-quiesced flag of the RX srs then
293510309SSriharsha.Basavapatna@Sun.COM * restart the HW ring and the mac srs on the ring.
293610309SSriharsha.Basavapatna@Sun.COM */
293710309SSriharsha.Basavapatna@Sun.COM mac_srs_perm_quiesce(vnetp->hio_mch, B_FALSE);
293810309SSriharsha.Basavapatna@Sun.COM mac_rx_client_restart(vnetp->hio_mch);
293910309SSriharsha.Basavapatna@Sun.COM }
294010309SSriharsha.Basavapatna@Sun.COM
294110309SSriharsha.Basavapatna@Sun.COM mac_perim_exit(mph1);
294210309SSriharsha.Basavapatna@Sun.COM }
294310309SSriharsha.Basavapatna@Sun.COM
294410309SSriharsha.Basavapatna@Sun.COM /* Bind pseudo ring to a LDC resource */
294510309SSriharsha.Basavapatna@Sun.COM static int
vnet_bind_vgenring(vnet_res_t * vresp)294610309SSriharsha.Basavapatna@Sun.COM vnet_bind_vgenring(vnet_res_t *vresp)
294710309SSriharsha.Basavapatna@Sun.COM {
294810309SSriharsha.Basavapatna@Sun.COM vnet_t *vnetp;
294910309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_rx_group_t *rx_grp;
295010309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_rx_ring_t *rx_ringp;
295110309SSriharsha.Basavapatna@Sun.COM mac_perim_handle_t mph1;
295210309SSriharsha.Basavapatna@Sun.COM int rv;
295310309SSriharsha.Basavapatna@Sun.COM int type;
295410309SSriharsha.Basavapatna@Sun.COM
295510309SSriharsha.Basavapatna@Sun.COM vnetp = vresp->vnetp;
295610309SSriharsha.Basavapatna@Sun.COM type = vresp->type;
295710309SSriharsha.Basavapatna@Sun.COM rx_grp = &vnetp->rx_grp[0];
295810309SSriharsha.Basavapatna@Sun.COM
295910309SSriharsha.Basavapatna@Sun.COM if (type == VIO_NET_RES_LDC_SERVICE) {
296010309SSriharsha.Basavapatna@Sun.COM /*
296110309SSriharsha.Basavapatna@Sun.COM * Ring Index 0 is the default ring in the group and is
296210309SSriharsha.Basavapatna@Sun.COM * reserved for LDC_SERVICE in vnet_ring_grp_init(). This ring
296310309SSriharsha.Basavapatna@Sun.COM * is allocated statically and is reported to the mac layer
296410309SSriharsha.Basavapatna@Sun.COM * in vnet_m_capab(). So, all we need to do here, is save a
296510309SSriharsha.Basavapatna@Sun.COM * reference to the associated vresp.
296610309SSriharsha.Basavapatna@Sun.COM */
296710309SSriharsha.Basavapatna@Sun.COM rx_ringp = &rx_grp->rings[0];
296810309SSriharsha.Basavapatna@Sun.COM rx_ringp->hw_rh = (mac_ring_handle_t)vresp;
296910309SSriharsha.Basavapatna@Sun.COM vresp->rx_ringp = (void *)rx_ringp;
297010309SSriharsha.Basavapatna@Sun.COM return (0);
297110309SSriharsha.Basavapatna@Sun.COM }
297210309SSriharsha.Basavapatna@Sun.COM ASSERT(type == VIO_NET_RES_LDC_GUEST);
297310309SSriharsha.Basavapatna@Sun.COM
297410309SSriharsha.Basavapatna@Sun.COM mac_perim_enter_by_mh(vnetp->mh, &mph1);
297510309SSriharsha.Basavapatna@Sun.COM
297610309SSriharsha.Basavapatna@Sun.COM rx_ringp = vnet_alloc_pseudo_rx_ring(vnetp);
297710309SSriharsha.Basavapatna@Sun.COM if (rx_ringp == NULL) {
297810309SSriharsha.Basavapatna@Sun.COM cmn_err(CE_WARN, "!vnet%d: Failed to allocate pseudo rx ring",
297910309SSriharsha.Basavapatna@Sun.COM vnetp->instance);
298010309SSriharsha.Basavapatna@Sun.COM goto fail;
298110309SSriharsha.Basavapatna@Sun.COM }
298210309SSriharsha.Basavapatna@Sun.COM
298310309SSriharsha.Basavapatna@Sun.COM /* Store the LDC resource itself as the ring handle */
298410309SSriharsha.Basavapatna@Sun.COM rx_ringp->hw_rh = (mac_ring_handle_t)vresp;
298510309SSriharsha.Basavapatna@Sun.COM
298610309SSriharsha.Basavapatna@Sun.COM /*
298710309SSriharsha.Basavapatna@Sun.COM * Save a reference to the ring in the resource for lookup during
298810309SSriharsha.Basavapatna@Sun.COM * unbind. Note this is only done for LDC resources. We don't need this
298910309SSriharsha.Basavapatna@Sun.COM * in the case of a Hybrid resource (see vnet_bind_hwrings()), as its
299010309SSriharsha.Basavapatna@Sun.COM * rx rings are mapped to reserved pseudo rx rings (index 1 and 2).
299110309SSriharsha.Basavapatna@Sun.COM */
299210309SSriharsha.Basavapatna@Sun.COM vresp->rx_ringp = (void *)rx_ringp;
299310309SSriharsha.Basavapatna@Sun.COM rx_ringp->state |= VNET_RXRING_LDC_GUEST;
299410309SSriharsha.Basavapatna@Sun.COM
299510309SSriharsha.Basavapatna@Sun.COM /* Register the pseudo ring with upper-mac */
299610309SSriharsha.Basavapatna@Sun.COM rv = mac_group_add_ring(rx_grp->handle, rx_ringp->index);
299710309SSriharsha.Basavapatna@Sun.COM if (rv != 0) {
299810309SSriharsha.Basavapatna@Sun.COM rx_ringp->state &= ~VNET_RXRING_LDC_GUEST;
299910309SSriharsha.Basavapatna@Sun.COM rx_ringp->hw_rh = NULL;
300010309SSriharsha.Basavapatna@Sun.COM vnet_free_pseudo_rx_ring(vnetp, rx_ringp);
300110309SSriharsha.Basavapatna@Sun.COM goto fail;
300210309SSriharsha.Basavapatna@Sun.COM }
300310309SSriharsha.Basavapatna@Sun.COM
300410309SSriharsha.Basavapatna@Sun.COM mac_perim_exit(mph1);
300510309SSriharsha.Basavapatna@Sun.COM return (0);
300610309SSriharsha.Basavapatna@Sun.COM fail:
300710309SSriharsha.Basavapatna@Sun.COM mac_perim_exit(mph1);
300810309SSriharsha.Basavapatna@Sun.COM return (1);
300910309SSriharsha.Basavapatna@Sun.COM }
301010309SSriharsha.Basavapatna@Sun.COM
301110309SSriharsha.Basavapatna@Sun.COM /* Unbind pseudo ring from a LDC resource */
301210309SSriharsha.Basavapatna@Sun.COM static void
vnet_unbind_vgenring(vnet_res_t * vresp)301310309SSriharsha.Basavapatna@Sun.COM vnet_unbind_vgenring(vnet_res_t *vresp)
301410309SSriharsha.Basavapatna@Sun.COM {
301510309SSriharsha.Basavapatna@Sun.COM vnet_t *vnetp;
301610309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_rx_group_t *rx_grp;
301710309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_rx_ring_t *rx_ringp;
301810309SSriharsha.Basavapatna@Sun.COM mac_perim_handle_t mph1;
301910309SSriharsha.Basavapatna@Sun.COM int type;
302010309SSriharsha.Basavapatna@Sun.COM
302110309SSriharsha.Basavapatna@Sun.COM vnetp = vresp->vnetp;
302210309SSriharsha.Basavapatna@Sun.COM type = vresp->type;
302310309SSriharsha.Basavapatna@Sun.COM rx_grp = &vnetp->rx_grp[0];
302410309SSriharsha.Basavapatna@Sun.COM
302510309SSriharsha.Basavapatna@Sun.COM if (vresp->rx_ringp == NULL) {
302610309SSriharsha.Basavapatna@Sun.COM return;
302710309SSriharsha.Basavapatna@Sun.COM }
302810309SSriharsha.Basavapatna@Sun.COM
302910309SSriharsha.Basavapatna@Sun.COM if (type == VIO_NET_RES_LDC_SERVICE) {
303010309SSriharsha.Basavapatna@Sun.COM /*
303110309SSriharsha.Basavapatna@Sun.COM * Ring Index 0 is the default ring in the group and is
303210309SSriharsha.Basavapatna@Sun.COM * reserved for LDC_SERVICE in vnet_ring_grp_init(). This ring
303310309SSriharsha.Basavapatna@Sun.COM * is allocated statically and is reported to the mac layer
303410309SSriharsha.Basavapatna@Sun.COM * in vnet_m_capab(). So, all we need to do here, is remove its
303510309SSriharsha.Basavapatna@Sun.COM * reference to the associated vresp.
303610309SSriharsha.Basavapatna@Sun.COM */
303710309SSriharsha.Basavapatna@Sun.COM rx_ringp = &rx_grp->rings[0];
303810309SSriharsha.Basavapatna@Sun.COM rx_ringp->hw_rh = NULL;
303910309SSriharsha.Basavapatna@Sun.COM vresp->rx_ringp = NULL;
304010309SSriharsha.Basavapatna@Sun.COM return;
304110309SSriharsha.Basavapatna@Sun.COM }
304210309SSriharsha.Basavapatna@Sun.COM ASSERT(type == VIO_NET_RES_LDC_GUEST);
304310309SSriharsha.Basavapatna@Sun.COM
304410309SSriharsha.Basavapatna@Sun.COM mac_perim_enter_by_mh(vnetp->mh, &mph1);
304510309SSriharsha.Basavapatna@Sun.COM
304610309SSriharsha.Basavapatna@Sun.COM rx_ringp = (vnet_pseudo_rx_ring_t *)vresp->rx_ringp;
304710309SSriharsha.Basavapatna@Sun.COM vresp->rx_ringp = NULL;
304810309SSriharsha.Basavapatna@Sun.COM
304910309SSriharsha.Basavapatna@Sun.COM if (rx_ringp != NULL && (rx_ringp->state & VNET_RXRING_LDC_GUEST)) {
305010309SSriharsha.Basavapatna@Sun.COM /* Unregister the pseudo ring with upper-mac */
305110309SSriharsha.Basavapatna@Sun.COM mac_group_rem_ring(rx_grp->handle, rx_ringp->handle);
305210309SSriharsha.Basavapatna@Sun.COM
305310309SSriharsha.Basavapatna@Sun.COM rx_ringp->hw_rh = NULL;
305410309SSriharsha.Basavapatna@Sun.COM rx_ringp->state &= ~VNET_RXRING_LDC_GUEST;
305510309SSriharsha.Basavapatna@Sun.COM
305610309SSriharsha.Basavapatna@Sun.COM /* Free the pseudo rx ring */
305710309SSriharsha.Basavapatna@Sun.COM vnet_free_pseudo_rx_ring(vnetp, rx_ringp);
305810309SSriharsha.Basavapatna@Sun.COM }
305910309SSriharsha.Basavapatna@Sun.COM
306010309SSriharsha.Basavapatna@Sun.COM mac_perim_exit(mph1);
306110309SSriharsha.Basavapatna@Sun.COM }
306210309SSriharsha.Basavapatna@Sun.COM
306310309SSriharsha.Basavapatna@Sun.COM static void
vnet_unbind_rings(vnet_res_t * vresp)306410309SSriharsha.Basavapatna@Sun.COM vnet_unbind_rings(vnet_res_t *vresp)
306510309SSriharsha.Basavapatna@Sun.COM {
306610309SSriharsha.Basavapatna@Sun.COM switch (vresp->type) {
306710309SSriharsha.Basavapatna@Sun.COM
306810309SSriharsha.Basavapatna@Sun.COM case VIO_NET_RES_LDC_SERVICE:
306910309SSriharsha.Basavapatna@Sun.COM case VIO_NET_RES_LDC_GUEST:
307010309SSriharsha.Basavapatna@Sun.COM vnet_unbind_vgenring(vresp);
307110309SSriharsha.Basavapatna@Sun.COM break;
307210309SSriharsha.Basavapatna@Sun.COM
307310309SSriharsha.Basavapatna@Sun.COM case VIO_NET_RES_HYBRID:
307410309SSriharsha.Basavapatna@Sun.COM vnet_unbind_hwrings(vresp->vnetp);
307510309SSriharsha.Basavapatna@Sun.COM break;
307610309SSriharsha.Basavapatna@Sun.COM
307710309SSriharsha.Basavapatna@Sun.COM default:
307810309SSriharsha.Basavapatna@Sun.COM break;
307910309SSriharsha.Basavapatna@Sun.COM
308010309SSriharsha.Basavapatna@Sun.COM }
308110309SSriharsha.Basavapatna@Sun.COM }
308210309SSriharsha.Basavapatna@Sun.COM
308310309SSriharsha.Basavapatna@Sun.COM static int
vnet_bind_rings(vnet_res_t * vresp)308410309SSriharsha.Basavapatna@Sun.COM vnet_bind_rings(vnet_res_t *vresp)
308510309SSriharsha.Basavapatna@Sun.COM {
308610309SSriharsha.Basavapatna@Sun.COM int rv;
308710309SSriharsha.Basavapatna@Sun.COM
308810309SSriharsha.Basavapatna@Sun.COM switch (vresp->type) {
308910309SSriharsha.Basavapatna@Sun.COM
309010309SSriharsha.Basavapatna@Sun.COM case VIO_NET_RES_LDC_SERVICE:
309110309SSriharsha.Basavapatna@Sun.COM case VIO_NET_RES_LDC_GUEST:
309210309SSriharsha.Basavapatna@Sun.COM rv = vnet_bind_vgenring(vresp);
309310309SSriharsha.Basavapatna@Sun.COM break;
309410309SSriharsha.Basavapatna@Sun.COM
309510309SSriharsha.Basavapatna@Sun.COM case VIO_NET_RES_HYBRID:
309610309SSriharsha.Basavapatna@Sun.COM rv = vnet_bind_hwrings(vresp->vnetp);
309710309SSriharsha.Basavapatna@Sun.COM break;
309810309SSriharsha.Basavapatna@Sun.COM
309910309SSriharsha.Basavapatna@Sun.COM default:
310010309SSriharsha.Basavapatna@Sun.COM rv = 1;
310110309SSriharsha.Basavapatna@Sun.COM break;
310210309SSriharsha.Basavapatna@Sun.COM
310310309SSriharsha.Basavapatna@Sun.COM }
310410309SSriharsha.Basavapatna@Sun.COM
310510309SSriharsha.Basavapatna@Sun.COM return (rv);
310610309SSriharsha.Basavapatna@Sun.COM }
310710309SSriharsha.Basavapatna@Sun.COM
310810309SSriharsha.Basavapatna@Sun.COM /* ARGSUSED */
310910309SSriharsha.Basavapatna@Sun.COM int
vnet_hio_stat(void * arg,uint_t stat,uint64_t * val)311010309SSriharsha.Basavapatna@Sun.COM vnet_hio_stat(void *arg, uint_t stat, uint64_t *val)
311110309SSriharsha.Basavapatna@Sun.COM {
311210309SSriharsha.Basavapatna@Sun.COM vnet_t *vnetp = (vnet_t *)arg;
311310309SSriharsha.Basavapatna@Sun.COM
311410309SSriharsha.Basavapatna@Sun.COM *val = mac_stat_get(vnetp->hio_mh, stat);
311510309SSriharsha.Basavapatna@Sun.COM return (0);
311610309SSriharsha.Basavapatna@Sun.COM }
311710309SSriharsha.Basavapatna@Sun.COM
311810309SSriharsha.Basavapatna@Sun.COM /*
311910309SSriharsha.Basavapatna@Sun.COM * The start() and stop() routines for the Hybrid resource below, are just
312010309SSriharsha.Basavapatna@Sun.COM * dummy functions. This is provided to avoid resource type specific code in
312110309SSriharsha.Basavapatna@Sun.COM * vnet_start_resources() and vnet_stop_resources(). The starting and stopping
312210309SSriharsha.Basavapatna@Sun.COM * of the Hybrid resource happens in the context of the mac_client interfaces
312310309SSriharsha.Basavapatna@Sun.COM * that are invoked in vnet_hio_mac_init() and vnet_hio_mac_cleanup().
312410309SSriharsha.Basavapatna@Sun.COM */
312510309SSriharsha.Basavapatna@Sun.COM /* ARGSUSED */
312610309SSriharsha.Basavapatna@Sun.COM static int
vnet_hio_start(void * arg)312710309SSriharsha.Basavapatna@Sun.COM vnet_hio_start(void *arg)
312810309SSriharsha.Basavapatna@Sun.COM {
312910309SSriharsha.Basavapatna@Sun.COM return (0);
313010309SSriharsha.Basavapatna@Sun.COM }
313110309SSriharsha.Basavapatna@Sun.COM
313210309SSriharsha.Basavapatna@Sun.COM /* ARGSUSED */
313310309SSriharsha.Basavapatna@Sun.COM static void
vnet_hio_stop(void * arg)313410309SSriharsha.Basavapatna@Sun.COM vnet_hio_stop(void *arg)
313510309SSriharsha.Basavapatna@Sun.COM {
313610309SSriharsha.Basavapatna@Sun.COM }
313710309SSriharsha.Basavapatna@Sun.COM
313810309SSriharsha.Basavapatna@Sun.COM mblk_t *
vnet_hio_tx(void * arg,mblk_t * mp)313910309SSriharsha.Basavapatna@Sun.COM vnet_hio_tx(void *arg, mblk_t *mp)
314010309SSriharsha.Basavapatna@Sun.COM {
314110309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_tx_ring_t *tx_ringp;
314210309SSriharsha.Basavapatna@Sun.COM mblk_t *nextp;
314310309SSriharsha.Basavapatna@Sun.COM mblk_t *ret_mp;
314410309SSriharsha.Basavapatna@Sun.COM
314510309SSriharsha.Basavapatna@Sun.COM tx_ringp = (vnet_pseudo_tx_ring_t *)arg;
314610309SSriharsha.Basavapatna@Sun.COM for (;;) {
314710309SSriharsha.Basavapatna@Sun.COM nextp = mp->b_next;
314810309SSriharsha.Basavapatna@Sun.COM mp->b_next = NULL;
314910309SSriharsha.Basavapatna@Sun.COM
315010309SSriharsha.Basavapatna@Sun.COM ret_mp = mac_hwring_tx(tx_ringp->hw_rh, mp);
315110309SSriharsha.Basavapatna@Sun.COM if (ret_mp != NULL) {
315210309SSriharsha.Basavapatna@Sun.COM ret_mp->b_next = nextp;
315310309SSriharsha.Basavapatna@Sun.COM mp = ret_mp;
315410309SSriharsha.Basavapatna@Sun.COM break;
315510309SSriharsha.Basavapatna@Sun.COM }
315610309SSriharsha.Basavapatna@Sun.COM
315710309SSriharsha.Basavapatna@Sun.COM if ((mp = nextp) == NULL)
315810309SSriharsha.Basavapatna@Sun.COM break;
315910309SSriharsha.Basavapatna@Sun.COM }
316010309SSriharsha.Basavapatna@Sun.COM return (mp);
316110309SSriharsha.Basavapatna@Sun.COM }
316210309SSriharsha.Basavapatna@Sun.COM
31639336SSriharsha.Basavapatna@Sun.COM #ifdef VNET_IOC_DEBUG
31649336SSriharsha.Basavapatna@Sun.COM
31659336SSriharsha.Basavapatna@Sun.COM /*
31669336SSriharsha.Basavapatna@Sun.COM * The ioctl entry point is used only for debugging for now. The ioctl commands
31679336SSriharsha.Basavapatna@Sun.COM * can be used to force the link state of the channel connected to vsw.
31689336SSriharsha.Basavapatna@Sun.COM */
31699336SSriharsha.Basavapatna@Sun.COM static void
vnet_m_ioctl(void * arg,queue_t * q,mblk_t * mp)31709336SSriharsha.Basavapatna@Sun.COM vnet_m_ioctl(void *arg, queue_t *q, mblk_t *mp)
31719336SSriharsha.Basavapatna@Sun.COM {
31729336SSriharsha.Basavapatna@Sun.COM struct iocblk *iocp;
31739336SSriharsha.Basavapatna@Sun.COM vnet_t *vnetp;
31749336SSriharsha.Basavapatna@Sun.COM
31759336SSriharsha.Basavapatna@Sun.COM iocp = (struct iocblk *)(uintptr_t)mp->b_rptr;
31769336SSriharsha.Basavapatna@Sun.COM iocp->ioc_error = 0;
31779336SSriharsha.Basavapatna@Sun.COM vnetp = (vnet_t *)arg;
31789336SSriharsha.Basavapatna@Sun.COM
31799336SSriharsha.Basavapatna@Sun.COM if (vnetp == NULL) {
31809336SSriharsha.Basavapatna@Sun.COM miocnak(q, mp, 0, EINVAL);
31819336SSriharsha.Basavapatna@Sun.COM return;
31829336SSriharsha.Basavapatna@Sun.COM }
31839336SSriharsha.Basavapatna@Sun.COM
31849336SSriharsha.Basavapatna@Sun.COM switch (iocp->ioc_cmd) {
31859336SSriharsha.Basavapatna@Sun.COM
31869336SSriharsha.Basavapatna@Sun.COM case VNET_FORCE_LINK_DOWN:
31879336SSriharsha.Basavapatna@Sun.COM case VNET_FORCE_LINK_UP:
31889336SSriharsha.Basavapatna@Sun.COM vnet_force_link_state(vnetp, q, mp);
31899336SSriharsha.Basavapatna@Sun.COM break;
31909336SSriharsha.Basavapatna@Sun.COM
31919336SSriharsha.Basavapatna@Sun.COM default:
31929336SSriharsha.Basavapatna@Sun.COM iocp->ioc_error = EINVAL;
31939336SSriharsha.Basavapatna@Sun.COM miocnak(q, mp, 0, iocp->ioc_error);
31949336SSriharsha.Basavapatna@Sun.COM break;
31959336SSriharsha.Basavapatna@Sun.COM
31969336SSriharsha.Basavapatna@Sun.COM }
31979336SSriharsha.Basavapatna@Sun.COM }
31989336SSriharsha.Basavapatna@Sun.COM
31999336SSriharsha.Basavapatna@Sun.COM static void
vnet_force_link_state(vnet_t * vnetp,queue_t * q,mblk_t * mp)32009336SSriharsha.Basavapatna@Sun.COM vnet_force_link_state(vnet_t *vnetp, queue_t *q, mblk_t *mp)
32019336SSriharsha.Basavapatna@Sun.COM {
32029336SSriharsha.Basavapatna@Sun.COM mac_register_t *macp;
32039336SSriharsha.Basavapatna@Sun.COM mac_callbacks_t *cbp;
32049336SSriharsha.Basavapatna@Sun.COM vnet_res_t *vresp;
32059336SSriharsha.Basavapatna@Sun.COM
32069336SSriharsha.Basavapatna@Sun.COM READ_ENTER(&vnetp->vsw_fp_rw);
32079336SSriharsha.Basavapatna@Sun.COM
32089336SSriharsha.Basavapatna@Sun.COM vresp = vnetp->vsw_fp;
32099336SSriharsha.Basavapatna@Sun.COM if (vresp == NULL) {
32109336SSriharsha.Basavapatna@Sun.COM RW_EXIT(&vnetp->vsw_fp_rw);
32119336SSriharsha.Basavapatna@Sun.COM return;
32129336SSriharsha.Basavapatna@Sun.COM }
32139336SSriharsha.Basavapatna@Sun.COM
32149336SSriharsha.Basavapatna@Sun.COM macp = &vresp->macreg;
32159336SSriharsha.Basavapatna@Sun.COM cbp = macp->m_callbacks;
32169336SSriharsha.Basavapatna@Sun.COM cbp->mc_ioctl(macp->m_driver, q, mp);
32179336SSriharsha.Basavapatna@Sun.COM
32189336SSriharsha.Basavapatna@Sun.COM RW_EXIT(&vnetp->vsw_fp_rw);
32199336SSriharsha.Basavapatna@Sun.COM }
32209336SSriharsha.Basavapatna@Sun.COM
32219336SSriharsha.Basavapatna@Sun.COM #else
32229336SSriharsha.Basavapatna@Sun.COM
32239336SSriharsha.Basavapatna@Sun.COM static void
vnet_m_ioctl(void * arg,queue_t * q,mblk_t * mp)32249336SSriharsha.Basavapatna@Sun.COM vnet_m_ioctl(void *arg, queue_t *q, mblk_t *mp)
32259336SSriharsha.Basavapatna@Sun.COM {
32269336SSriharsha.Basavapatna@Sun.COM vnet_t *vnetp;
32279336SSriharsha.Basavapatna@Sun.COM
32289336SSriharsha.Basavapatna@Sun.COM vnetp = (vnet_t *)arg;
32299336SSriharsha.Basavapatna@Sun.COM
32309336SSriharsha.Basavapatna@Sun.COM if (vnetp == NULL) {
32319336SSriharsha.Basavapatna@Sun.COM miocnak(q, mp, 0, EINVAL);
32329336SSriharsha.Basavapatna@Sun.COM return;
32339336SSriharsha.Basavapatna@Sun.COM }
32349336SSriharsha.Basavapatna@Sun.COM
32359336SSriharsha.Basavapatna@Sun.COM /* ioctl support only for debugging */
32369336SSriharsha.Basavapatna@Sun.COM miocnak(q, mp, 0, ENOTSUP);
32379336SSriharsha.Basavapatna@Sun.COM }
32389336SSriharsha.Basavapatna@Sun.COM
32399336SSriharsha.Basavapatna@Sun.COM #endif
3240