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); 1609217SWentao.Yang@Sun.COM extern void vgen_mod_init(void); 1619217SWentao.Yang@Sun.COM extern int vgen_mod_cleanup(void); 1629217SWentao.Yang@Sun.COM extern void vgen_mod_fini(void); 16310309SSriharsha.Basavapatna@Sun.COM extern int vgen_enable_intr(void *arg); 16410309SSriharsha.Basavapatna@Sun.COM extern int vgen_disable_intr(void *arg); 16510309SSriharsha.Basavapatna@Sun.COM extern mblk_t *vgen_poll(void *arg, int bytes_to_pickup); 1666495Sspeer 1676495Sspeer /* Externs that are imported from vnet_dds */ 1686495Sspeer extern void vdds_mod_init(void); 1696495Sspeer extern void vdds_mod_fini(void); 1706495Sspeer extern int vdds_init(vnet_t *vnetp); 1716495Sspeer extern void vdds_cleanup(vnet_t *vnetp); 1726495Sspeer extern void vdds_process_dds_msg(vnet_t *vnetp, vio_dds_msg_t *dmsg); 1737819SRaghuram.Kothakota@Sun.COM extern void vdds_cleanup_hybrid_res(void *arg); 1749647SWentao.Yang@Sun.COM extern void vdds_cleanup_hio(vnet_t *vnetp); 1751991Sheppo 17611878SVenu.Iyer@Sun.COM extern pri_t minclsyspri; 17710309SSriharsha.Basavapatna@Sun.COM 1788160SWentao.Yang@Sun.COM #define DRV_NAME "vnet" 1796419Ssb155480 #define VNET_FDBE_REFHOLD(p) \ 1806419Ssb155480 { \ 1816419Ssb155480 atomic_inc_32(&(p)->refcnt); \ 1826419Ssb155480 ASSERT((p)->refcnt != 0); \ 1836419Ssb155480 } 1846419Ssb155480 1856419Ssb155480 #define VNET_FDBE_REFRELE(p) \ 1866419Ssb155480 { \ 1876419Ssb155480 ASSERT((p)->refcnt != 0); \ 1886419Ssb155480 atomic_dec_32(&(p)->refcnt); \ 1896419Ssb155480 } 1906419Ssb155480 1919336SSriharsha.Basavapatna@Sun.COM #ifdef VNET_IOC_DEBUG 19210309SSriharsha.Basavapatna@Sun.COM #define VNET_M_CALLBACK_FLAGS (MC_IOCTL | MC_GETCAPAB) 1939336SSriharsha.Basavapatna@Sun.COM #else 19410309SSriharsha.Basavapatna@Sun.COM #define VNET_M_CALLBACK_FLAGS (MC_GETCAPAB) 1959336SSriharsha.Basavapatna@Sun.COM #endif 1969336SSriharsha.Basavapatna@Sun.COM 1972311Sseb static mac_callbacks_t vnet_m_callbacks = { 1989336SSriharsha.Basavapatna@Sun.COM VNET_M_CALLBACK_FLAGS, 1992311Sseb vnet_m_stat, 2002311Sseb vnet_m_start, 2012311Sseb vnet_m_stop, 2022311Sseb vnet_m_promisc, 2032311Sseb vnet_m_multicst, 20410309SSriharsha.Basavapatna@Sun.COM NULL, /* m_unicst entry must be NULL while rx rings are exposed */ 20510309SSriharsha.Basavapatna@Sun.COM NULL, /* m_tx entry must be NULL while tx rings are exposed */ 20611878SVenu.Iyer@Sun.COM NULL, 2079336SSriharsha.Basavapatna@Sun.COM vnet_m_ioctl, 20810309SSriharsha.Basavapatna@Sun.COM vnet_m_capab, 20910309SSriharsha.Basavapatna@Sun.COM NULL 21010309SSriharsha.Basavapatna@Sun.COM }; 21110309SSriharsha.Basavapatna@Sun.COM 21210309SSriharsha.Basavapatna@Sun.COM static mac_callbacks_t vnet_hio_res_callbacks = { 21310309SSriharsha.Basavapatna@Sun.COM 0, 21410309SSriharsha.Basavapatna@Sun.COM vnet_hio_stat, 21510309SSriharsha.Basavapatna@Sun.COM vnet_hio_start, 21610309SSriharsha.Basavapatna@Sun.COM vnet_hio_stop, 21710309SSriharsha.Basavapatna@Sun.COM NULL, 21810309SSriharsha.Basavapatna@Sun.COM NULL, 21910309SSriharsha.Basavapatna@Sun.COM NULL, 22010309SSriharsha.Basavapatna@Sun.COM vnet_hio_tx, 22110309SSriharsha.Basavapatna@Sun.COM NULL, 2222311Sseb NULL, 2232311Sseb NULL 2242311Sseb }; 2252311Sseb 2261991Sheppo /* 2271991Sheppo * Linked list of "vnet_t" structures - one per instance. 2281991Sheppo */ 2291991Sheppo static vnet_t *vnet_headp = NULL; 2301991Sheppo static krwlock_t vnet_rw; 2311991Sheppo 2321991Sheppo /* Tunables */ 2331991Sheppo uint32_t vnet_ntxds = VNET_NTXDS; /* power of 2 transmit descriptors */ 2341991Sheppo uint32_t vnet_ldcwd_interval = VNET_LDCWD_INTERVAL; /* watchdog freq in msec */ 2351991Sheppo uint32_t vnet_ldcwd_txtimeout = VNET_LDCWD_TXTIMEOUT; /* tx timeout in msec */ 2362410Slm66018 uint32_t vnet_ldc_mtu = VNET_LDC_MTU; /* ldc mtu */ 2376419Ssb155480 23810309SSriharsha.Basavapatna@Sun.COM /* Configure tx serialization in mac layer for the vnet device */ 23910309SSriharsha.Basavapatna@Sun.COM boolean_t vnet_mac_tx_serialize = B_TRUE; 24011878SVenu.Iyer@Sun.COM /* Configure enqueing at Rx soft rings in mac layer for the vnet device */ 24111878SVenu.Iyer@Sun.COM boolean_t vnet_mac_rx_queuing = B_TRUE; 24210309SSriharsha.Basavapatna@Sun.COM 2437529SSriharsha.Basavapatna@Sun.COM /* 2447529SSriharsha.Basavapatna@Sun.COM * Set this to non-zero to enable additional internal receive buffer pools 2457529SSriharsha.Basavapatna@Sun.COM * based on the MTU of the device for better performance at the cost of more 2467529SSriharsha.Basavapatna@Sun.COM * memory consumption. This is turned off by default, to use allocb(9F) for 2477529SSriharsha.Basavapatna@Sun.COM * receive buffer allocations of sizes > 2K. 2487529SSriharsha.Basavapatna@Sun.COM */ 2497529SSriharsha.Basavapatna@Sun.COM boolean_t vnet_jumbo_rxpools = B_FALSE; 2507529SSriharsha.Basavapatna@Sun.COM 2516419Ssb155480 /* # of chains in fdb hash table */ 2526419Ssb155480 uint32_t vnet_fdb_nchains = VNET_NFDB_HASH; 2536419Ssb155480 2546419Ssb155480 /* Internal tunables */ 2556419Ssb155480 uint32_t vnet_ethermtu = 1500; /* mtu of the device */ 2566419Ssb155480 2576419Ssb155480 /* 2586419Ssb155480 * Default vlan id. This is only used internally when the "default-vlan-id" 2596419Ssb155480 * property is not present in the MD device node. Therefore, this should not be 2606419Ssb155480 * used as a tunable; if this value is changed, the corresponding variable 2616419Ssb155480 * should be updated to the same value in vsw and also other vnets connected to 2626419Ssb155480 * the same vsw. 2636419Ssb155480 */ 2646419Ssb155480 uint16_t vnet_default_vlan_id = 1; 2656419Ssb155480 2666419Ssb155480 /* delay in usec to wait for all references on a fdb entry to be dropped */ 2676419Ssb155480 uint32_t vnet_fdbe_refcnt_delay = 10; 2681991Sheppo 2696495Sspeer static struct ether_addr etherbroadcastaddr = { 2706495Sspeer 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 2716495Sspeer }; 2726495Sspeer 27310309SSriharsha.Basavapatna@Sun.COM /* mac_open() retry delay in usec */ 27410309SSriharsha.Basavapatna@Sun.COM uint32_t vnet_mac_open_delay = 100; /* 0.1 ms */ 27510309SSriharsha.Basavapatna@Sun.COM 27610309SSriharsha.Basavapatna@Sun.COM /* max # of mac_open() retries */ 27710309SSriharsha.Basavapatna@Sun.COM uint32_t vnet_mac_open_retries = 100; 2786495Sspeer 2791991Sheppo /* 2801991Sheppo * Property names 2811991Sheppo */ 2821991Sheppo static char macaddr_propname[] = "local-mac-address"; 2831991Sheppo 2841991Sheppo /* 2851991Sheppo * This is the string displayed by modinfo(1m). 2861991Sheppo */ 2877529SSriharsha.Basavapatna@Sun.COM static char vnet_ident[] = "vnet driver"; 2881991Sheppo extern struct mod_ops mod_driverops; 2891991Sheppo static struct cb_ops cb_vnetops = { 2901991Sheppo nulldev, /* cb_open */ 2911991Sheppo nulldev, /* cb_close */ 2921991Sheppo nodev, /* cb_strategy */ 2931991Sheppo nodev, /* cb_print */ 2941991Sheppo nodev, /* cb_dump */ 2951991Sheppo nodev, /* cb_read */ 2961991Sheppo nodev, /* cb_write */ 2971991Sheppo nodev, /* cb_ioctl */ 2981991Sheppo nodev, /* cb_devmap */ 2991991Sheppo nodev, /* cb_mmap */ 3001991Sheppo nodev, /* cb_segmap */ 3011991Sheppo nochpoll, /* cb_chpoll */ 3021991Sheppo ddi_prop_op, /* cb_prop_op */ 3031991Sheppo NULL, /* cb_stream */ 3041991Sheppo (int)(D_MP) /* cb_flag */ 3051991Sheppo }; 3061991Sheppo 3071991Sheppo static struct dev_ops vnetops = { 3081991Sheppo DEVO_REV, /* devo_rev */ 3091991Sheppo 0, /* devo_refcnt */ 3101991Sheppo NULL, /* devo_getinfo */ 3111991Sheppo nulldev, /* devo_identify */ 3121991Sheppo nulldev, /* devo_probe */ 3131991Sheppo vnetattach, /* devo_attach */ 3141991Sheppo vnetdetach, /* devo_detach */ 3151991Sheppo nodev, /* devo_reset */ 3161991Sheppo &cb_vnetops, /* devo_cb_ops */ 3177656SSherry.Moore@Sun.COM (struct bus_ops *)NULL, /* devo_bus_ops */ 3187656SSherry.Moore@Sun.COM NULL, /* devo_power */ 3197656SSherry.Moore@Sun.COM ddi_quiesce_not_supported, /* devo_quiesce */ 3201991Sheppo }; 3211991Sheppo 3221991Sheppo static struct modldrv modldrv = { 3231991Sheppo &mod_driverops, /* Type of module. This one is a driver */ 3241991Sheppo vnet_ident, /* ID string */ 3251991Sheppo &vnetops /* driver specific ops */ 3261991Sheppo }; 3271991Sheppo 3281991Sheppo static struct modlinkage modlinkage = { 3291991Sheppo MODREV_1, (void *)&modldrv, NULL 3301991Sheppo }; 3311991Sheppo 3324647Sraghuram #ifdef DEBUG 3331991Sheppo 3341991Sheppo /* 3351991Sheppo * Print debug messages - set to 0xf to enable all msgs 3361991Sheppo */ 3374647Sraghuram int vnet_dbglevel = 0x8; 3381991Sheppo 3394647Sraghuram static void 3404647Sraghuram debug_printf(const char *fname, void *arg, const char *fmt, ...) 3411991Sheppo { 3421991Sheppo char buf[512]; 3431991Sheppo va_list ap; 3441991Sheppo vnet_t *vnetp = (vnet_t *)arg; 3454647Sraghuram char *bufp = buf; 3461991Sheppo 3474647Sraghuram if (vnetp == NULL) { 3484647Sraghuram (void) sprintf(bufp, "%s: ", fname); 3494647Sraghuram bufp += strlen(bufp); 3504647Sraghuram } else { 3514647Sraghuram (void) sprintf(bufp, "vnet%d:%s: ", vnetp->instance, fname); 3524647Sraghuram bufp += strlen(bufp); 3534647Sraghuram } 3544647Sraghuram va_start(ap, fmt); 3554647Sraghuram (void) vsprintf(bufp, fmt, ap); 3564647Sraghuram va_end(ap); 3574647Sraghuram cmn_err(CE_CONT, "%s\n", buf); 3584647Sraghuram } 3591991Sheppo 3601991Sheppo #endif 3611991Sheppo 3621991Sheppo /* _init(9E): initialize the loadable module */ 3631991Sheppo int 3641991Sheppo _init(void) 3651991Sheppo { 3661991Sheppo int status; 3671991Sheppo 3684647Sraghuram DBG1(NULL, "enter\n"); 3691991Sheppo 3701991Sheppo mac_init_ops(&vnetops, "vnet"); 3711991Sheppo status = mod_install(&modlinkage); 3721991Sheppo if (status != 0) { 3731991Sheppo mac_fini_ops(&vnetops); 3741991Sheppo } 3756495Sspeer vdds_mod_init(); 3769217SWentao.Yang@Sun.COM vgen_mod_init(); 3774647Sraghuram DBG1(NULL, "exit(%d)\n", status); 3781991Sheppo return (status); 3791991Sheppo } 3801991Sheppo 3811991Sheppo /* _fini(9E): prepare the module for unloading. */ 3821991Sheppo int 3831991Sheppo _fini(void) 3841991Sheppo { 3859217SWentao.Yang@Sun.COM int status; 3861991Sheppo 3874647Sraghuram DBG1(NULL, "enter\n"); 3881991Sheppo 3899217SWentao.Yang@Sun.COM status = vgen_mod_cleanup(); 3909217SWentao.Yang@Sun.COM if (status != 0) 3919217SWentao.Yang@Sun.COM return (status); 3929217SWentao.Yang@Sun.COM 3931991Sheppo status = mod_remove(&modlinkage); 3941991Sheppo if (status != 0) 3951991Sheppo return (status); 3961991Sheppo mac_fini_ops(&vnetops); 3979217SWentao.Yang@Sun.COM vgen_mod_fini(); 3986495Sspeer vdds_mod_fini(); 3991991Sheppo 4004647Sraghuram DBG1(NULL, "exit(%d)\n", status); 4011991Sheppo return (status); 4021991Sheppo } 4031991Sheppo 4041991Sheppo /* _info(9E): return information about the loadable module */ 4051991Sheppo int 4061991Sheppo _info(struct modinfo *modinfop) 4071991Sheppo { 4081991Sheppo return (mod_info(&modlinkage, modinfop)); 4091991Sheppo } 4101991Sheppo 4111991Sheppo /* 4121991Sheppo * attach(9E): attach a device to the system. 4131991Sheppo * called once for each instance of the device on the system. 4141991Sheppo */ 4151991Sheppo static int 4161991Sheppo vnetattach(dev_info_t *dip, ddi_attach_cmd_t cmd) 4171991Sheppo { 4189217SWentao.Yang@Sun.COM vnet_t *vnetp; 4199217SWentao.Yang@Sun.COM int status; 4209217SWentao.Yang@Sun.COM int instance; 4219217SWentao.Yang@Sun.COM uint64_t reg; 4229217SWentao.Yang@Sun.COM char qname[TASKQ_NAMELEN]; 4239217SWentao.Yang@Sun.COM vnet_attach_progress_t attach_progress; 4241991Sheppo 4259217SWentao.Yang@Sun.COM attach_progress = AST_init; 4261991Sheppo 4271991Sheppo switch (cmd) { 4281991Sheppo case DDI_ATTACH: 4291991Sheppo break; 4301991Sheppo case DDI_RESUME: 4311991Sheppo case DDI_PM_RESUME: 4321991Sheppo default: 4331991Sheppo goto vnet_attach_fail; 4341991Sheppo } 4351991Sheppo 4361991Sheppo instance = ddi_get_instance(dip); 4374647Sraghuram DBG1(NULL, "instance(%d) enter\n", instance); 4381991Sheppo 4391991Sheppo /* allocate vnet_t and mac_t structures */ 4401991Sheppo vnetp = kmem_zalloc(sizeof (vnet_t), KM_SLEEP); 4416495Sspeer vnetp->dip = dip; 4426495Sspeer vnetp->instance = instance; 4436495Sspeer rw_init(&vnetp->vrwlock, NULL, RW_DRIVER, NULL); 4446495Sspeer rw_init(&vnetp->vsw_fp_rw, NULL, RW_DRIVER, NULL); 4459217SWentao.Yang@Sun.COM attach_progress |= AST_vnet_alloc; 4461991Sheppo 44710309SSriharsha.Basavapatna@Sun.COM vnet_ring_grp_init(vnetp); 44810309SSriharsha.Basavapatna@Sun.COM attach_progress |= AST_ring_init; 44910309SSriharsha.Basavapatna@Sun.COM 4506495Sspeer status = vdds_init(vnetp); 4516495Sspeer if (status != 0) { 4526495Sspeer goto vnet_attach_fail; 4536495Sspeer } 4549217SWentao.Yang@Sun.COM attach_progress |= AST_vdds_init; 4556495Sspeer 4561991Sheppo /* setup links to vnet_t from both devinfo and mac_t */ 4571991Sheppo ddi_set_driver_private(dip, (caddr_t)vnetp); 4581991Sheppo 4591991Sheppo /* read the mac address */ 4601991Sheppo status = vnet_read_mac_address(vnetp); 4611991Sheppo if (status != DDI_SUCCESS) { 4621991Sheppo goto vnet_attach_fail; 4631991Sheppo } 4649217SWentao.Yang@Sun.COM attach_progress |= AST_read_macaddr; 4651991Sheppo 4666495Sspeer reg = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 4676495Sspeer DDI_PROP_DONTPASS, "reg", -1); 4686495Sspeer if (reg == -1) { 4696495Sspeer goto vnet_attach_fail; 4706495Sspeer } 4716495Sspeer vnetp->reg = reg; 4726495Sspeer 4736495Sspeer vnet_fdb_create(vnetp); 4749217SWentao.Yang@Sun.COM attach_progress |= AST_fdbh_alloc; 4756495Sspeer 4766495Sspeer (void) snprintf(qname, TASKQ_NAMELEN, "vnet_taskq%d", instance); 4776495Sspeer if ((vnetp->taskqp = ddi_taskq_create(dip, qname, 1, 4786495Sspeer TASKQ_DEFAULTPRI, 0)) == NULL) { 4796495Sspeer cmn_err(CE_WARN, "!vnet%d: Unable to create task queue", 4806495Sspeer instance); 4816495Sspeer goto vnet_attach_fail; 4826495Sspeer } 4839217SWentao.Yang@Sun.COM attach_progress |= AST_taskq_create; 4846495Sspeer 4856495Sspeer /* add to the list of vnet devices */ 4866495Sspeer WRITE_ENTER(&vnet_rw); 4876495Sspeer vnetp->nextp = vnet_headp; 4886495Sspeer vnet_headp = vnetp; 4896495Sspeer RW_EXIT(&vnet_rw); 4906495Sspeer 4919217SWentao.Yang@Sun.COM attach_progress |= AST_vnet_list; 4926495Sspeer 4931991Sheppo /* 49410309SSriharsha.Basavapatna@Sun.COM * Initialize the generic vnet plugin which provides communication via 49510309SSriharsha.Basavapatna@Sun.COM * sun4v LDC (logical domain channel) based resources. This involves 2 49610309SSriharsha.Basavapatna@Sun.COM * steps; first, vgen_init() is invoked to read the various properties 49710309SSriharsha.Basavapatna@Sun.COM * of the vnet device from its MD node (including its mtu which is 49810309SSriharsha.Basavapatna@Sun.COM * needed to mac_register()) and obtain a handle to the vgen layer. 49910309SSriharsha.Basavapatna@Sun.COM * After mac_register() is done and we have a mac handle, we then 50010309SSriharsha.Basavapatna@Sun.COM * invoke vgen_init_mdeg() which registers with the the MD event 50110309SSriharsha.Basavapatna@Sun.COM * generator (mdeg) framework to allow LDC resource notifications. 50210309SSriharsha.Basavapatna@Sun.COM * Note: this sequence also allows us to report the correct default # 50310309SSriharsha.Basavapatna@Sun.COM * of pseudo rings (2TX and 3RX) in vnet_m_capab() which gets invoked 50410309SSriharsha.Basavapatna@Sun.COM * in the context of mac_register(); and avoids conflicting with 50510309SSriharsha.Basavapatna@Sun.COM * dynamic pseudo rx rings which get added/removed as a result of mdeg 50610309SSriharsha.Basavapatna@Sun.COM * events in vgen. 5071991Sheppo */ 5086495Sspeer status = vgen_init(vnetp, reg, vnetp->dip, 5096495Sspeer (uint8_t *)vnetp->curr_macaddr, &vnetp->vgenhdl); 5101991Sheppo if (status != DDI_SUCCESS) { 5114647Sraghuram DERR(vnetp, "vgen_init() failed\n"); 5121991Sheppo goto vnet_attach_fail; 5131991Sheppo } 5149217SWentao.Yang@Sun.COM attach_progress |= AST_vgen_init; 5151991Sheppo 5161991Sheppo status = vnet_mac_register(vnetp); 5171991Sheppo if (status != DDI_SUCCESS) { 5181991Sheppo goto vnet_attach_fail; 5191991Sheppo } 5209336SSriharsha.Basavapatna@Sun.COM vnetp->link_state = LINK_STATE_UNKNOWN; 5219217SWentao.Yang@Sun.COM attach_progress |= AST_macreg; 5229217SWentao.Yang@Sun.COM 52310309SSriharsha.Basavapatna@Sun.COM status = vgen_init_mdeg(vnetp->vgenhdl); 52410309SSriharsha.Basavapatna@Sun.COM if (status != DDI_SUCCESS) { 52510309SSriharsha.Basavapatna@Sun.COM goto vnet_attach_fail; 52610309SSriharsha.Basavapatna@Sun.COM } 52710309SSriharsha.Basavapatna@Sun.COM attach_progress |= AST_init_mdeg; 52810309SSriharsha.Basavapatna@Sun.COM 5299217SWentao.Yang@Sun.COM vnetp->attach_progress = attach_progress; 5309217SWentao.Yang@Sun.COM 5314647Sraghuram DBG1(NULL, "instance(%d) exit\n", instance); 5321991Sheppo return (DDI_SUCCESS); 5331991Sheppo 5341991Sheppo vnet_attach_fail: 5359217SWentao.Yang@Sun.COM vnetp->attach_progress = attach_progress; 5369235SWentao.Yang@Sun.COM status = vnet_unattach(vnetp); 5379235SWentao.Yang@Sun.COM ASSERT(status == 0); 5381991Sheppo return (DDI_FAILURE); 5391991Sheppo } 5401991Sheppo 5411991Sheppo /* 5421991Sheppo * detach(9E): detach a device from the system. 5431991Sheppo */ 5441991Sheppo static int 5451991Sheppo vnetdetach(dev_info_t *dip, ddi_detach_cmd_t cmd) 5461991Sheppo { 5471991Sheppo vnet_t *vnetp; 5481991Sheppo int instance; 5491991Sheppo 5501991Sheppo instance = ddi_get_instance(dip); 5514647Sraghuram DBG1(NULL, "instance(%d) enter\n", instance); 5521991Sheppo 5531991Sheppo vnetp = ddi_get_driver_private(dip); 5541991Sheppo if (vnetp == NULL) { 5551991Sheppo goto vnet_detach_fail; 5561991Sheppo } 5571991Sheppo 5581991Sheppo switch (cmd) { 5591991Sheppo case DDI_DETACH: 5601991Sheppo break; 5611991Sheppo case DDI_SUSPEND: 5621991Sheppo case DDI_PM_SUSPEND: 5631991Sheppo default: 5641991Sheppo goto vnet_detach_fail; 5651991Sheppo } 5661991Sheppo 5679217SWentao.Yang@Sun.COM if (vnet_unattach(vnetp) != 0) { 5686495Sspeer goto vnet_detach_fail; 5692336Snarayan } 5702336Snarayan 5711991Sheppo return (DDI_SUCCESS); 5721991Sheppo 5731991Sheppo vnet_detach_fail: 5741991Sheppo return (DDI_FAILURE); 5751991Sheppo } 5761991Sheppo 5779217SWentao.Yang@Sun.COM /* 5789217SWentao.Yang@Sun.COM * Common routine to handle vnetattach() failure and vnetdetach(). Note that 5799217SWentao.Yang@Sun.COM * the only reason this function could fail is if mac_unregister() fails. 5809217SWentao.Yang@Sun.COM * Otherwise, this function must ensure that all resources are freed and return 5819217SWentao.Yang@Sun.COM * success. 5829217SWentao.Yang@Sun.COM */ 5839217SWentao.Yang@Sun.COM static int 5849217SWentao.Yang@Sun.COM vnet_unattach(vnet_t *vnetp) 5859217SWentao.Yang@Sun.COM { 5869217SWentao.Yang@Sun.COM vnet_attach_progress_t attach_progress; 5879217SWentao.Yang@Sun.COM 5889217SWentao.Yang@Sun.COM attach_progress = vnetp->attach_progress; 5899217SWentao.Yang@Sun.COM 5909217SWentao.Yang@Sun.COM /* 59110309SSriharsha.Basavapatna@Sun.COM * Disable the mac device in the gldv3 subsystem. This can fail, in 59210309SSriharsha.Basavapatna@Sun.COM * particular if there are still any open references to this mac 59310309SSriharsha.Basavapatna@Sun.COM * device; in which case we just return failure without continuing to 59410309SSriharsha.Basavapatna@Sun.COM * detach further. 59510309SSriharsha.Basavapatna@Sun.COM * If it succeeds, we then invoke vgen_uninit() which should unregister 59610309SSriharsha.Basavapatna@Sun.COM * any pseudo rings registered with the mac layer. Note we keep the 59710309SSriharsha.Basavapatna@Sun.COM * AST_macreg flag on, so we can unregister with the mac layer at 59810309SSriharsha.Basavapatna@Sun.COM * the end of this routine. 5999217SWentao.Yang@Sun.COM */ 6009217SWentao.Yang@Sun.COM if (attach_progress & AST_macreg) { 60110309SSriharsha.Basavapatna@Sun.COM if (mac_disable(vnetp->mh) != 0) { 6029217SWentao.Yang@Sun.COM return (1); 6039217SWentao.Yang@Sun.COM } 6049217SWentao.Yang@Sun.COM } 6059217SWentao.Yang@Sun.COM 6069217SWentao.Yang@Sun.COM /* 60710309SSriharsha.Basavapatna@Sun.COM * Now that we have disabled the device, we must finish all other steps 60810309SSriharsha.Basavapatna@Sun.COM * and successfully return from this function; otherwise we will end up 60910309SSriharsha.Basavapatna@Sun.COM * leaving the device in a broken/unusable state. 6109217SWentao.Yang@Sun.COM * 6119217SWentao.Yang@Sun.COM * First, release any hybrid resources assigned to this vnet device. 6129217SWentao.Yang@Sun.COM */ 6139217SWentao.Yang@Sun.COM if (attach_progress & AST_vdds_init) { 6149217SWentao.Yang@Sun.COM vdds_cleanup(vnetp); 6159217SWentao.Yang@Sun.COM attach_progress &= ~AST_vdds_init; 6169217SWentao.Yang@Sun.COM } 6179217SWentao.Yang@Sun.COM 6189217SWentao.Yang@Sun.COM /* 6199217SWentao.Yang@Sun.COM * Uninit vgen. This stops further mdeg callbacks to this vnet 6209217SWentao.Yang@Sun.COM * device and/or its ports; and detaches any existing ports. 6219217SWentao.Yang@Sun.COM */ 62210309SSriharsha.Basavapatna@Sun.COM if (attach_progress & (AST_vgen_init|AST_init_mdeg)) { 6239217SWentao.Yang@Sun.COM vgen_uninit(vnetp->vgenhdl); 6249217SWentao.Yang@Sun.COM attach_progress &= ~AST_vgen_init; 62510309SSriharsha.Basavapatna@Sun.COM attach_progress &= ~AST_init_mdeg; 6269217SWentao.Yang@Sun.COM } 6279217SWentao.Yang@Sun.COM 6289217SWentao.Yang@Sun.COM /* Destroy the taskq. */ 6299217SWentao.Yang@Sun.COM if (attach_progress & AST_taskq_create) { 6309217SWentao.Yang@Sun.COM ddi_taskq_destroy(vnetp->taskqp); 6319217SWentao.Yang@Sun.COM attach_progress &= ~AST_taskq_create; 6329217SWentao.Yang@Sun.COM } 6339217SWentao.Yang@Sun.COM 6349217SWentao.Yang@Sun.COM /* Destroy fdb. */ 6359217SWentao.Yang@Sun.COM if (attach_progress & AST_fdbh_alloc) { 6369217SWentao.Yang@Sun.COM vnet_fdb_destroy(vnetp); 6379217SWentao.Yang@Sun.COM attach_progress &= ~AST_fdbh_alloc; 6389217SWentao.Yang@Sun.COM } 6399217SWentao.Yang@Sun.COM 6409217SWentao.Yang@Sun.COM /* Remove from the device list */ 6419217SWentao.Yang@Sun.COM if (attach_progress & AST_vnet_list) { 6429217SWentao.Yang@Sun.COM vnet_t **vnetpp; 6439217SWentao.Yang@Sun.COM /* unlink from instance(vnet_t) list */ 6449217SWentao.Yang@Sun.COM WRITE_ENTER(&vnet_rw); 6459217SWentao.Yang@Sun.COM for (vnetpp = &vnet_headp; *vnetpp; 6469217SWentao.Yang@Sun.COM vnetpp = &(*vnetpp)->nextp) { 6479217SWentao.Yang@Sun.COM if (*vnetpp == vnetp) { 6489217SWentao.Yang@Sun.COM *vnetpp = vnetp->nextp; 6499217SWentao.Yang@Sun.COM break; 6509217SWentao.Yang@Sun.COM } 6519217SWentao.Yang@Sun.COM } 6529217SWentao.Yang@Sun.COM RW_EXIT(&vnet_rw); 6539217SWentao.Yang@Sun.COM attach_progress &= ~AST_vnet_list; 6549217SWentao.Yang@Sun.COM } 6559217SWentao.Yang@Sun.COM 65610309SSriharsha.Basavapatna@Sun.COM if (attach_progress & AST_ring_init) { 65710309SSriharsha.Basavapatna@Sun.COM vnet_ring_grp_uninit(vnetp); 65810309SSriharsha.Basavapatna@Sun.COM attach_progress &= ~AST_ring_init; 65910309SSriharsha.Basavapatna@Sun.COM } 66010309SSriharsha.Basavapatna@Sun.COM 66110309SSriharsha.Basavapatna@Sun.COM if (attach_progress & AST_macreg) { 66210309SSriharsha.Basavapatna@Sun.COM VERIFY(mac_unregister(vnetp->mh) == 0); 66310309SSriharsha.Basavapatna@Sun.COM vnetp->mh = NULL; 66410309SSriharsha.Basavapatna@Sun.COM attach_progress &= ~AST_macreg; 66510309SSriharsha.Basavapatna@Sun.COM } 66610309SSriharsha.Basavapatna@Sun.COM 6679217SWentao.Yang@Sun.COM if (attach_progress & AST_vnet_alloc) { 6689217SWentao.Yang@Sun.COM rw_destroy(&vnetp->vrwlock); 6699217SWentao.Yang@Sun.COM rw_destroy(&vnetp->vsw_fp_rw); 6709217SWentao.Yang@Sun.COM attach_progress &= ~AST_vnet_list; 6719217SWentao.Yang@Sun.COM KMEM_FREE(vnetp); 6729217SWentao.Yang@Sun.COM } 6739217SWentao.Yang@Sun.COM 6749217SWentao.Yang@Sun.COM return (0); 6759217SWentao.Yang@Sun.COM } 6769217SWentao.Yang@Sun.COM 6771991Sheppo /* enable the device for transmit/receive */ 6781991Sheppo static int 6791991Sheppo vnet_m_start(void *arg) 6801991Sheppo { 6811991Sheppo vnet_t *vnetp = arg; 6821991Sheppo 6834647Sraghuram DBG1(vnetp, "enter\n"); 6841991Sheppo 6856495Sspeer WRITE_ENTER(&vnetp->vrwlock); 6866495Sspeer vnetp->flags |= VNET_STARTED; 6876495Sspeer vnet_start_resources(vnetp); 6886495Sspeer RW_EXIT(&vnetp->vrwlock); 6891991Sheppo 6904647Sraghuram DBG1(vnetp, "exit\n"); 6911991Sheppo return (VNET_SUCCESS); 6921991Sheppo 6931991Sheppo } 6941991Sheppo 6951991Sheppo /* stop transmit/receive for the device */ 6961991Sheppo static void 6971991Sheppo vnet_m_stop(void *arg) 6981991Sheppo { 6991991Sheppo vnet_t *vnetp = arg; 7001991Sheppo 7014647Sraghuram DBG1(vnetp, "enter\n"); 7021991Sheppo 7036495Sspeer WRITE_ENTER(&vnetp->vrwlock); 7046495Sspeer if (vnetp->flags & VNET_STARTED) { 7059805SSriharsha.Basavapatna@Sun.COM /* 7069805SSriharsha.Basavapatna@Sun.COM * Set the flags appropriately; this should prevent starting of 7079805SSriharsha.Basavapatna@Sun.COM * any new resources that are added(see vnet_res_start_task()), 7089805SSriharsha.Basavapatna@Sun.COM * while we release the vrwlock in vnet_stop_resources() before 7099805SSriharsha.Basavapatna@Sun.COM * stopping each resource. 7109805SSriharsha.Basavapatna@Sun.COM */ 7119805SSriharsha.Basavapatna@Sun.COM vnetp->flags &= ~VNET_STARTED; 7129805SSriharsha.Basavapatna@Sun.COM vnetp->flags |= VNET_STOPPING; 7136495Sspeer vnet_stop_resources(vnetp); 7149805SSriharsha.Basavapatna@Sun.COM vnetp->flags &= ~VNET_STOPPING; 7151991Sheppo } 7166495Sspeer RW_EXIT(&vnetp->vrwlock); 7171991Sheppo 7184647Sraghuram DBG1(vnetp, "exit\n"); 7191991Sheppo } 7201991Sheppo 7211991Sheppo /* set the unicast mac address of the device */ 7221991Sheppo static int 7231991Sheppo vnet_m_unicst(void *arg, const uint8_t *macaddr) 7241991Sheppo { 7251991Sheppo _NOTE(ARGUNUSED(macaddr)) 7261991Sheppo 7271991Sheppo vnet_t *vnetp = arg; 7281991Sheppo 7294647Sraghuram DBG1(vnetp, "enter\n"); 7301991Sheppo /* 7312793Slm66018 * NOTE: setting mac address dynamically is not supported. 7321991Sheppo */ 7334647Sraghuram DBG1(vnetp, "exit\n"); 7341991Sheppo 7352109Slm66018 return (VNET_FAILURE); 7361991Sheppo } 7371991Sheppo 7381991Sheppo /* enable/disable a multicast address */ 7391991Sheppo static int 7401991Sheppo vnet_m_multicst(void *arg, boolean_t add, const uint8_t *mca) 7411991Sheppo { 7421991Sheppo _NOTE(ARGUNUSED(add, mca)) 7431991Sheppo 74411543SWentao.Yang@Sun.COM vnet_t *vnetp = arg; 7456495Sspeer vnet_res_t *vresp; 7466495Sspeer mac_register_t *macp; 7472311Sseb mac_callbacks_t *cbp; 74811543SWentao.Yang@Sun.COM int rv = VNET_SUCCESS; 7491991Sheppo 7504647Sraghuram DBG1(vnetp, "enter\n"); 7516495Sspeer 75211543SWentao.Yang@Sun.COM READ_ENTER(&vnetp->vsw_fp_rw); 75311543SWentao.Yang@Sun.COM if (vnetp->vsw_fp == NULL) { 75411543SWentao.Yang@Sun.COM RW_EXIT(&vnetp->vsw_fp_rw); 75511543SWentao.Yang@Sun.COM return (EAGAIN); 7561991Sheppo } 75711543SWentao.Yang@Sun.COM VNET_FDBE_REFHOLD(vnetp->vsw_fp); 75811543SWentao.Yang@Sun.COM RW_EXIT(&vnetp->vsw_fp_rw); 75911543SWentao.Yang@Sun.COM 76011543SWentao.Yang@Sun.COM vresp = vnetp->vsw_fp; 76111543SWentao.Yang@Sun.COM macp = &vresp->macreg; 76211543SWentao.Yang@Sun.COM cbp = macp->m_callbacks; 76311543SWentao.Yang@Sun.COM rv = cbp->mc_multicst(macp->m_driver, add, mca); 76411543SWentao.Yang@Sun.COM 76511543SWentao.Yang@Sun.COM VNET_FDBE_REFRELE(vnetp->vsw_fp); 7666495Sspeer 7674647Sraghuram DBG1(vnetp, "exit(%d)\n", rv); 7681991Sheppo return (rv); 7691991Sheppo } 7701991Sheppo 7711991Sheppo /* set or clear promiscuous mode on the device */ 7721991Sheppo static int 7731991Sheppo vnet_m_promisc(void *arg, boolean_t on) 7741991Sheppo { 7751991Sheppo _NOTE(ARGUNUSED(on)) 7761991Sheppo 7771991Sheppo vnet_t *vnetp = arg; 7784647Sraghuram DBG1(vnetp, "enter\n"); 7791991Sheppo /* 7802793Slm66018 * NOTE: setting promiscuous mode is not supported, just return success. 7811991Sheppo */ 7824647Sraghuram DBG1(vnetp, "exit\n"); 7831991Sheppo return (VNET_SUCCESS); 7841991Sheppo } 7851991Sheppo 7861991Sheppo /* 7871991Sheppo * Transmit a chain of packets. This function provides switching functionality 7881991Sheppo * based on the destination mac address to reach other guests (within ldoms) or 7891991Sheppo * external hosts. 7901991Sheppo */ 7911991Sheppo mblk_t * 79210309SSriharsha.Basavapatna@Sun.COM vnet_tx_ring_send(void *arg, mblk_t *mp) 7931991Sheppo { 79410309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_tx_ring_t *tx_ringp; 79511878SVenu.Iyer@Sun.COM vnet_tx_ring_stats_t *statsp; 7966419Ssb155480 vnet_t *vnetp; 7976495Sspeer vnet_res_t *vresp; 7986419Ssb155480 mblk_t *next; 7996495Sspeer mblk_t *resid_mp; 8006495Sspeer mac_register_t *macp; 8016495Sspeer struct ether_header *ehp; 8026495Sspeer boolean_t is_unicast; 8037896SSriharsha.Basavapatna@Sun.COM boolean_t is_pvid; /* non-default pvid ? */ 8047896SSriharsha.Basavapatna@Sun.COM boolean_t hres; /* Hybrid resource ? */ 80510309SSriharsha.Basavapatna@Sun.COM void *tx_arg; 80611878SVenu.Iyer@Sun.COM size_t size; 80710309SSriharsha.Basavapatna@Sun.COM 80810309SSriharsha.Basavapatna@Sun.COM tx_ringp = (vnet_pseudo_tx_ring_t *)arg; 80911878SVenu.Iyer@Sun.COM statsp = &tx_ringp->tx_ring_stats; 81010309SSriharsha.Basavapatna@Sun.COM vnetp = (vnet_t *)tx_ringp->vnetp; 8114647Sraghuram DBG1(vnetp, "enter\n"); 8121991Sheppo ASSERT(mp != NULL); 8131991Sheppo 8147896SSriharsha.Basavapatna@Sun.COM is_pvid = (vnetp->pvid != vnetp->default_vlan_id) ? B_TRUE : B_FALSE; 8157896SSriharsha.Basavapatna@Sun.COM 8161991Sheppo while (mp != NULL) { 8176419Ssb155480 8181991Sheppo next = mp->b_next; 8191991Sheppo mp->b_next = NULL; 8201991Sheppo 82111878SVenu.Iyer@Sun.COM /* update stats */ 82211878SVenu.Iyer@Sun.COM size = msgsize(mp); 82311878SVenu.Iyer@Sun.COM 8246419Ssb155480 /* 8256419Ssb155480 * Find fdb entry for the destination 8266419Ssb155480 * and hold a reference to it. 8276419Ssb155480 */ 8281991Sheppo ehp = (struct ether_header *)mp->b_rptr; 8296495Sspeer vresp = vnet_fdbe_find(vnetp, &ehp->ether_dhost); 8306495Sspeer if (vresp != NULL) { 8311991Sheppo 8321991Sheppo /* 8336419Ssb155480 * Destination found in FDB. 8346419Ssb155480 * The destination is a vnet device within ldoms 8356419Ssb155480 * and directly reachable, invoke the tx function 8366419Ssb155480 * in the fdb entry. 8371991Sheppo */ 8386495Sspeer macp = &vresp->macreg; 8396495Sspeer resid_mp = macp->m_callbacks->mc_tx(macp->m_driver, mp); 8406419Ssb155480 8416419Ssb155480 /* tx done; now release ref on fdb entry */ 8426495Sspeer VNET_FDBE_REFRELE(vresp); 8436419Ssb155480 8441991Sheppo if (resid_mp != NULL) { 8451991Sheppo /* m_tx failed */ 8461991Sheppo mp->b_next = next; 8471991Sheppo break; 8481991Sheppo } 8491991Sheppo } else { 8506495Sspeer is_unicast = !(IS_BROADCAST(ehp) || 8516495Sspeer (IS_MULTICAST(ehp))); 8521991Sheppo /* 8536419Ssb155480 * Destination is not in FDB. 8546495Sspeer * If the destination is broadcast or multicast, 8556495Sspeer * then forward the packet to vswitch. 8566495Sspeer * If a Hybrid resource avilable, then send the 8576495Sspeer * unicast packet via hybrid resource, otherwise 8586495Sspeer * forward it to vswitch. 8591991Sheppo */ 8606419Ssb155480 READ_ENTER(&vnetp->vsw_fp_rw); 8616419Ssb155480 8626495Sspeer if ((is_unicast) && (vnetp->hio_fp != NULL)) { 8636495Sspeer vresp = vnetp->hio_fp; 8647896SSriharsha.Basavapatna@Sun.COM hres = B_TRUE; 8656495Sspeer } else { 8666495Sspeer vresp = vnetp->vsw_fp; 8677896SSriharsha.Basavapatna@Sun.COM hres = B_FALSE; 8686495Sspeer } 8696495Sspeer if (vresp == NULL) { 8706419Ssb155480 /* 8716419Ssb155480 * no fdb entry to vsw? drop the packet. 8726419Ssb155480 */ 8736419Ssb155480 RW_EXIT(&vnetp->vsw_fp_rw); 8741991Sheppo freemsg(mp); 8756419Ssb155480 mp = next; 8766419Ssb155480 continue; 8771991Sheppo } 8786419Ssb155480 8796419Ssb155480 /* ref hold the fdb entry to vsw */ 8806495Sspeer VNET_FDBE_REFHOLD(vresp); 8816419Ssb155480 8826419Ssb155480 RW_EXIT(&vnetp->vsw_fp_rw); 8836419Ssb155480 8847896SSriharsha.Basavapatna@Sun.COM /* 8857896SSriharsha.Basavapatna@Sun.COM * In the case of a hybrid resource we need to insert 8867896SSriharsha.Basavapatna@Sun.COM * the tag for the pvid case here; unlike packets that 8877896SSriharsha.Basavapatna@Sun.COM * are destined to a vnet/vsw in which case the vgen 8887896SSriharsha.Basavapatna@Sun.COM * layer does the tagging before sending it over ldc. 8897896SSriharsha.Basavapatna@Sun.COM */ 8907896SSriharsha.Basavapatna@Sun.COM if (hres == B_TRUE) { 8917896SSriharsha.Basavapatna@Sun.COM /* 8927896SSriharsha.Basavapatna@Sun.COM * Determine if the frame being transmitted 8937896SSriharsha.Basavapatna@Sun.COM * over the hybrid resource is untagged. If so, 8947896SSriharsha.Basavapatna@Sun.COM * insert the tag before transmitting. 8957896SSriharsha.Basavapatna@Sun.COM */ 8967896SSriharsha.Basavapatna@Sun.COM if (is_pvid == B_TRUE && 8977896SSriharsha.Basavapatna@Sun.COM ehp->ether_type != htons(ETHERTYPE_VLAN)) { 8987896SSriharsha.Basavapatna@Sun.COM 8997896SSriharsha.Basavapatna@Sun.COM mp = vnet_vlan_insert_tag(mp, 9007896SSriharsha.Basavapatna@Sun.COM vnetp->pvid); 9017896SSriharsha.Basavapatna@Sun.COM if (mp == NULL) { 9027896SSriharsha.Basavapatna@Sun.COM VNET_FDBE_REFRELE(vresp); 9037896SSriharsha.Basavapatna@Sun.COM mp = next; 9047896SSriharsha.Basavapatna@Sun.COM continue; 9057896SSriharsha.Basavapatna@Sun.COM } 9067896SSriharsha.Basavapatna@Sun.COM 9077896SSriharsha.Basavapatna@Sun.COM } 90810309SSriharsha.Basavapatna@Sun.COM 90910309SSriharsha.Basavapatna@Sun.COM macp = &vresp->macreg; 91010309SSriharsha.Basavapatna@Sun.COM tx_arg = tx_ringp; 91110309SSriharsha.Basavapatna@Sun.COM } else { 91210309SSriharsha.Basavapatna@Sun.COM macp = &vresp->macreg; 91310309SSriharsha.Basavapatna@Sun.COM tx_arg = macp->m_driver; 9147896SSriharsha.Basavapatna@Sun.COM } 91510309SSriharsha.Basavapatna@Sun.COM resid_mp = macp->m_callbacks->mc_tx(tx_arg, mp); 9166419Ssb155480 9176419Ssb155480 /* tx done; now release ref on fdb entry */ 9186495Sspeer VNET_FDBE_REFRELE(vresp); 9196419Ssb155480 9206419Ssb155480 if (resid_mp != NULL) { 9216419Ssb155480 /* m_tx failed */ 9226419Ssb155480 mp->b_next = next; 9236419Ssb155480 break; 9246419Ssb155480 } 9251991Sheppo } 9261991Sheppo 92711878SVenu.Iyer@Sun.COM statsp->obytes += size; 92811878SVenu.Iyer@Sun.COM statsp->opackets++; 9291991Sheppo mp = next; 9301991Sheppo } 9311991Sheppo 9324647Sraghuram DBG1(vnetp, "exit\n"); 9331991Sheppo return (mp); 9341991Sheppo } 9351991Sheppo 9362311Sseb /* get statistics from the device */ 9372311Sseb int 9382311Sseb vnet_m_stat(void *arg, uint_t stat, uint64_t *val) 9391991Sheppo { 9401991Sheppo vnet_t *vnetp = arg; 9416495Sspeer vnet_res_t *vresp; 9426495Sspeer mac_register_t *macp; 9432311Sseb mac_callbacks_t *cbp; 9442311Sseb uint64_t val_total = 0; 9451991Sheppo 9464647Sraghuram DBG1(vnetp, "enter\n"); 9471991Sheppo 9481991Sheppo /* 9492311Sseb * get the specified statistic from each transport and return the 9502311Sseb * aggregate val. This obviously only works for counters. 9511991Sheppo */ 9522311Sseb if ((IS_MAC_STAT(stat) && !MAC_STAT_ISACOUNTER(stat)) || 9532311Sseb (IS_MACTYPE_STAT(stat) && !ETHER_STAT_ISACOUNTER(stat))) { 9542311Sseb return (ENOTSUP); 9552311Sseb } 9566495Sspeer 9576495Sspeer READ_ENTER(&vnetp->vrwlock); 9586495Sspeer for (vresp = vnetp->vres_list; vresp != NULL; vresp = vresp->nextp) { 9596495Sspeer macp = &vresp->macreg; 9606495Sspeer cbp = macp->m_callbacks; 9616495Sspeer if (cbp->mc_getstat(macp->m_driver, stat, val) == 0) 9622311Sseb val_total += *val; 9631991Sheppo } 9646495Sspeer RW_EXIT(&vnetp->vrwlock); 9651991Sheppo 9662311Sseb *val = val_total; 9672311Sseb 9684647Sraghuram DBG1(vnetp, "exit\n"); 9692311Sseb return (0); 9701991Sheppo } 9711991Sheppo 97210309SSriharsha.Basavapatna@Sun.COM static void 97310309SSriharsha.Basavapatna@Sun.COM vnet_ring_grp_init(vnet_t *vnetp) 97410309SSriharsha.Basavapatna@Sun.COM { 97510309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_rx_group_t *rx_grp; 97610309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_rx_ring_t *rx_ringp; 97710309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_tx_group_t *tx_grp; 97810309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_tx_ring_t *tx_ringp; 97910309SSriharsha.Basavapatna@Sun.COM int i; 98010309SSriharsha.Basavapatna@Sun.COM 98110309SSriharsha.Basavapatna@Sun.COM tx_grp = &vnetp->tx_grp[0]; 98210309SSriharsha.Basavapatna@Sun.COM tx_ringp = kmem_zalloc(sizeof (vnet_pseudo_tx_ring_t) * 98310309SSriharsha.Basavapatna@Sun.COM VNET_NUM_PSEUDO_TXRINGS, KM_SLEEP); 98410309SSriharsha.Basavapatna@Sun.COM for (i = 0; i < VNET_NUM_PSEUDO_TXRINGS; i++) { 98510309SSriharsha.Basavapatna@Sun.COM tx_ringp[i].state |= VNET_TXRING_SHARED; 98610309SSriharsha.Basavapatna@Sun.COM } 98710309SSriharsha.Basavapatna@Sun.COM tx_grp->rings = tx_ringp; 98810309SSriharsha.Basavapatna@Sun.COM tx_grp->ring_cnt = VNET_NUM_PSEUDO_TXRINGS; 98911878SVenu.Iyer@Sun.COM mutex_init(&tx_grp->flowctl_lock, NULL, MUTEX_DRIVER, NULL); 99011878SVenu.Iyer@Sun.COM cv_init(&tx_grp->flowctl_cv, NULL, CV_DRIVER, NULL); 99111878SVenu.Iyer@Sun.COM tx_grp->flowctl_thread = thread_create(NULL, 0, 99211878SVenu.Iyer@Sun.COM vnet_tx_notify_thread, tx_grp, 0, &p0, TS_RUN, minclsyspri); 99310309SSriharsha.Basavapatna@Sun.COM 99410309SSriharsha.Basavapatna@Sun.COM rx_grp = &vnetp->rx_grp[0]; 99510309SSriharsha.Basavapatna@Sun.COM rx_grp->max_ring_cnt = MAX_RINGS_PER_GROUP; 99610309SSriharsha.Basavapatna@Sun.COM rw_init(&rx_grp->lock, NULL, RW_DRIVER, NULL); 99710309SSriharsha.Basavapatna@Sun.COM rx_ringp = kmem_zalloc(sizeof (vnet_pseudo_rx_ring_t) * 99810309SSriharsha.Basavapatna@Sun.COM rx_grp->max_ring_cnt, KM_SLEEP); 99910309SSriharsha.Basavapatna@Sun.COM 100010309SSriharsha.Basavapatna@Sun.COM /* 100110309SSriharsha.Basavapatna@Sun.COM * Setup the first 3 Pseudo RX Rings that are reserved; 100210309SSriharsha.Basavapatna@Sun.COM * 1 for LDC resource to vswitch + 2 for RX rings of Hybrid resource. 100310309SSriharsha.Basavapatna@Sun.COM */ 100410309SSriharsha.Basavapatna@Sun.COM rx_ringp[0].state |= VNET_RXRING_INUSE|VNET_RXRING_LDC_SERVICE; 100510309SSriharsha.Basavapatna@Sun.COM rx_ringp[0].index = 0; 100610309SSriharsha.Basavapatna@Sun.COM rx_ringp[1].state |= VNET_RXRING_INUSE|VNET_RXRING_HYBRID; 100710309SSriharsha.Basavapatna@Sun.COM rx_ringp[1].index = 1; 100810309SSriharsha.Basavapatna@Sun.COM rx_ringp[2].state |= VNET_RXRING_INUSE|VNET_RXRING_HYBRID; 100910309SSriharsha.Basavapatna@Sun.COM rx_ringp[2].index = 2; 101010309SSriharsha.Basavapatna@Sun.COM 101110309SSriharsha.Basavapatna@Sun.COM rx_grp->ring_cnt = VNET_NUM_PSEUDO_RXRINGS_DEFAULT; 101210309SSriharsha.Basavapatna@Sun.COM rx_grp->rings = rx_ringp; 101310309SSriharsha.Basavapatna@Sun.COM 101410309SSriharsha.Basavapatna@Sun.COM for (i = VNET_NUM_PSEUDO_RXRINGS_DEFAULT; 101510309SSriharsha.Basavapatna@Sun.COM i < rx_grp->max_ring_cnt; i++) { 101610309SSriharsha.Basavapatna@Sun.COM rx_ringp = &rx_grp->rings[i]; 101710309SSriharsha.Basavapatna@Sun.COM rx_ringp->state = VNET_RXRING_FREE; 101810309SSriharsha.Basavapatna@Sun.COM rx_ringp->index = i; 101910309SSriharsha.Basavapatna@Sun.COM } 102010309SSriharsha.Basavapatna@Sun.COM } 102110309SSriharsha.Basavapatna@Sun.COM 102210309SSriharsha.Basavapatna@Sun.COM static void 102310309SSriharsha.Basavapatna@Sun.COM vnet_ring_grp_uninit(vnet_t *vnetp) 102410309SSriharsha.Basavapatna@Sun.COM { 102510309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_rx_group_t *rx_grp; 102610309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_tx_group_t *tx_grp; 102711878SVenu.Iyer@Sun.COM kt_did_t tid = 0; 102810309SSriharsha.Basavapatna@Sun.COM 102910309SSriharsha.Basavapatna@Sun.COM tx_grp = &vnetp->tx_grp[0]; 103011878SVenu.Iyer@Sun.COM 103111878SVenu.Iyer@Sun.COM /* Inform tx_notify_thread to exit */ 103211878SVenu.Iyer@Sun.COM mutex_enter(&tx_grp->flowctl_lock); 103311878SVenu.Iyer@Sun.COM if (tx_grp->flowctl_thread != NULL) { 103411878SVenu.Iyer@Sun.COM tid = tx_grp->flowctl_thread->t_did; 103511878SVenu.Iyer@Sun.COM tx_grp->flowctl_done = B_TRUE; 103611878SVenu.Iyer@Sun.COM cv_signal(&tx_grp->flowctl_cv); 103711878SVenu.Iyer@Sun.COM } 103811878SVenu.Iyer@Sun.COM mutex_exit(&tx_grp->flowctl_lock); 103911878SVenu.Iyer@Sun.COM if (tid != 0) 104011878SVenu.Iyer@Sun.COM thread_join(tid); 104111878SVenu.Iyer@Sun.COM 104210309SSriharsha.Basavapatna@Sun.COM if (tx_grp->rings != NULL) { 104310309SSriharsha.Basavapatna@Sun.COM ASSERT(tx_grp->ring_cnt == VNET_NUM_PSEUDO_TXRINGS); 104410309SSriharsha.Basavapatna@Sun.COM kmem_free(tx_grp->rings, sizeof (vnet_pseudo_tx_ring_t) * 104510309SSriharsha.Basavapatna@Sun.COM tx_grp->ring_cnt); 104610309SSriharsha.Basavapatna@Sun.COM tx_grp->rings = NULL; 104710309SSriharsha.Basavapatna@Sun.COM } 104810309SSriharsha.Basavapatna@Sun.COM 104910309SSriharsha.Basavapatna@Sun.COM rx_grp = &vnetp->rx_grp[0]; 105010309SSriharsha.Basavapatna@Sun.COM if (rx_grp->rings != NULL) { 105110309SSriharsha.Basavapatna@Sun.COM ASSERT(rx_grp->max_ring_cnt == MAX_RINGS_PER_GROUP); 105210309SSriharsha.Basavapatna@Sun.COM ASSERT(rx_grp->ring_cnt == VNET_NUM_PSEUDO_RXRINGS_DEFAULT); 105310309SSriharsha.Basavapatna@Sun.COM kmem_free(rx_grp->rings, sizeof (vnet_pseudo_rx_ring_t) * 105410309SSriharsha.Basavapatna@Sun.COM rx_grp->max_ring_cnt); 105510309SSriharsha.Basavapatna@Sun.COM rx_grp->rings = NULL; 105610309SSriharsha.Basavapatna@Sun.COM } 105710309SSriharsha.Basavapatna@Sun.COM } 105810309SSriharsha.Basavapatna@Sun.COM 105910309SSriharsha.Basavapatna@Sun.COM static vnet_pseudo_rx_ring_t * 106010309SSriharsha.Basavapatna@Sun.COM vnet_alloc_pseudo_rx_ring(vnet_t *vnetp) 106110309SSriharsha.Basavapatna@Sun.COM { 106210309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_rx_group_t *rx_grp; 106310309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_rx_ring_t *rx_ringp; 106410309SSriharsha.Basavapatna@Sun.COM int index; 106510309SSriharsha.Basavapatna@Sun.COM 106610309SSriharsha.Basavapatna@Sun.COM rx_grp = &vnetp->rx_grp[0]; 106710309SSriharsha.Basavapatna@Sun.COM WRITE_ENTER(&rx_grp->lock); 106810309SSriharsha.Basavapatna@Sun.COM 106910309SSriharsha.Basavapatna@Sun.COM if (rx_grp->ring_cnt == rx_grp->max_ring_cnt) { 107010309SSriharsha.Basavapatna@Sun.COM /* no rings available */ 107110309SSriharsha.Basavapatna@Sun.COM RW_EXIT(&rx_grp->lock); 107210309SSriharsha.Basavapatna@Sun.COM return (NULL); 107310309SSriharsha.Basavapatna@Sun.COM } 107410309SSriharsha.Basavapatna@Sun.COM 107510309SSriharsha.Basavapatna@Sun.COM for (index = VNET_NUM_PSEUDO_RXRINGS_DEFAULT; 107610309SSriharsha.Basavapatna@Sun.COM index < rx_grp->max_ring_cnt; index++) { 107710309SSriharsha.Basavapatna@Sun.COM rx_ringp = &rx_grp->rings[index]; 107810309SSriharsha.Basavapatna@Sun.COM if (rx_ringp->state == VNET_RXRING_FREE) { 107910309SSriharsha.Basavapatna@Sun.COM rx_ringp->state |= VNET_RXRING_INUSE; 108010309SSriharsha.Basavapatna@Sun.COM rx_grp->ring_cnt++; 108110309SSriharsha.Basavapatna@Sun.COM break; 108210309SSriharsha.Basavapatna@Sun.COM } 108310309SSriharsha.Basavapatna@Sun.COM } 108410309SSriharsha.Basavapatna@Sun.COM 108510309SSriharsha.Basavapatna@Sun.COM RW_EXIT(&rx_grp->lock); 108610309SSriharsha.Basavapatna@Sun.COM return (rx_ringp); 108710309SSriharsha.Basavapatna@Sun.COM } 108810309SSriharsha.Basavapatna@Sun.COM 108910309SSriharsha.Basavapatna@Sun.COM static void 109010309SSriharsha.Basavapatna@Sun.COM vnet_free_pseudo_rx_ring(vnet_t *vnetp, vnet_pseudo_rx_ring_t *ringp) 109110309SSriharsha.Basavapatna@Sun.COM { 109210309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_rx_group_t *rx_grp; 109310309SSriharsha.Basavapatna@Sun.COM 109410309SSriharsha.Basavapatna@Sun.COM ASSERT(ringp->index >= VNET_NUM_PSEUDO_RXRINGS_DEFAULT); 109510309SSriharsha.Basavapatna@Sun.COM rx_grp = &vnetp->rx_grp[0]; 109610309SSriharsha.Basavapatna@Sun.COM WRITE_ENTER(&rx_grp->lock); 109710309SSriharsha.Basavapatna@Sun.COM 109810309SSriharsha.Basavapatna@Sun.COM if (ringp->state != VNET_RXRING_FREE) { 109910309SSriharsha.Basavapatna@Sun.COM ringp->state = VNET_RXRING_FREE; 110010309SSriharsha.Basavapatna@Sun.COM ringp->handle = NULL; 110110309SSriharsha.Basavapatna@Sun.COM rx_grp->ring_cnt--; 110210309SSriharsha.Basavapatna@Sun.COM } 110310309SSriharsha.Basavapatna@Sun.COM 110410309SSriharsha.Basavapatna@Sun.COM RW_EXIT(&rx_grp->lock); 110510309SSriharsha.Basavapatna@Sun.COM } 110610309SSriharsha.Basavapatna@Sun.COM 11071991Sheppo /* wrapper function for mac_register() */ 11081991Sheppo static int 11091991Sheppo vnet_mac_register(vnet_t *vnetp) 11101991Sheppo { 11112311Sseb mac_register_t *macp; 11122311Sseb int err; 11131991Sheppo 11142311Sseb if ((macp = mac_alloc(MAC_VERSION)) == NULL) 11152311Sseb return (DDI_FAILURE); 11162311Sseb macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 11172311Sseb macp->m_driver = vnetp; 11181991Sheppo macp->m_dip = vnetp->dip; 11192311Sseb macp->m_src_addr = vnetp->curr_macaddr; 11202311Sseb macp->m_callbacks = &vnet_m_callbacks; 11212311Sseb macp->m_min_sdu = 0; 11227529SSriharsha.Basavapatna@Sun.COM macp->m_max_sdu = vnetp->mtu; 11236419Ssb155480 macp->m_margin = VLAN_TAGSZ; 11241991Sheppo 112510309SSriharsha.Basavapatna@Sun.COM macp->m_v12n = MAC_VIRT_LEVEL1; 112610309SSriharsha.Basavapatna@Sun.COM 112710309SSriharsha.Basavapatna@Sun.COM /* 11281991Sheppo * Finally, we're ready to register ourselves with the MAC layer 11291991Sheppo * interface; if this succeeds, we're all ready to start() 11301991Sheppo */ 11312311Sseb err = mac_register(macp, &vnetp->mh); 11322311Sseb mac_free(macp); 11332311Sseb return (err == 0 ? DDI_SUCCESS : DDI_FAILURE); 11341991Sheppo } 11351991Sheppo 11361991Sheppo /* read the mac address of the device */ 11371991Sheppo static int 11381991Sheppo vnet_read_mac_address(vnet_t *vnetp) 11391991Sheppo { 11401991Sheppo uchar_t *macaddr; 11411991Sheppo uint32_t size; 11421991Sheppo int rv; 11431991Sheppo 11441991Sheppo rv = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, vnetp->dip, 11454650Sraghuram DDI_PROP_DONTPASS, macaddr_propname, &macaddr, &size); 11461991Sheppo if ((rv != DDI_PROP_SUCCESS) || (size != ETHERADDRL)) { 11474647Sraghuram DWARN(vnetp, "prop_lookup failed(%s) err(%d)\n", 11484647Sraghuram macaddr_propname, rv); 11491991Sheppo return (DDI_FAILURE); 11501991Sheppo } 11511991Sheppo bcopy(macaddr, (caddr_t)vnetp->vendor_addr, ETHERADDRL); 11521991Sheppo bcopy(macaddr, (caddr_t)vnetp->curr_macaddr, ETHERADDRL); 11531991Sheppo ddi_prop_free(macaddr); 11541991Sheppo 11551991Sheppo return (DDI_SUCCESS); 11561991Sheppo } 11571991Sheppo 11586419Ssb155480 static void 11596419Ssb155480 vnet_fdb_create(vnet_t *vnetp) 11601991Sheppo { 11616419Ssb155480 char hashname[MAXNAMELEN]; 11621991Sheppo 11636419Ssb155480 (void) snprintf(hashname, MAXNAMELEN, "vnet%d-fdbhash", 11646419Ssb155480 vnetp->instance); 11656419Ssb155480 vnetp->fdb_nchains = vnet_fdb_nchains; 11666419Ssb155480 vnetp->fdb_hashp = mod_hash_create_ptrhash(hashname, vnetp->fdb_nchains, 11676419Ssb155480 mod_hash_null_valdtor, sizeof (void *)); 11686419Ssb155480 } 11691991Sheppo 11706419Ssb155480 static void 11716419Ssb155480 vnet_fdb_destroy(vnet_t *vnetp) 11726419Ssb155480 { 11736419Ssb155480 /* destroy fdb-hash-table */ 11746419Ssb155480 if (vnetp->fdb_hashp != NULL) { 11756419Ssb155480 mod_hash_destroy_hash(vnetp->fdb_hashp); 11766419Ssb155480 vnetp->fdb_hashp = NULL; 11776419Ssb155480 vnetp->fdb_nchains = 0; 11781991Sheppo } 11791991Sheppo } 11801991Sheppo 11816419Ssb155480 /* 11826419Ssb155480 * Add an entry into the fdb. 11836419Ssb155480 */ 11841991Sheppo void 11856495Sspeer vnet_fdbe_add(vnet_t *vnetp, vnet_res_t *vresp) 11861991Sheppo { 11876419Ssb155480 uint64_t addr = 0; 11886419Ssb155480 int rv; 11896419Ssb155480 11906495Sspeer KEY_HASH(addr, vresp->rem_macaddr); 11911991Sheppo 11926419Ssb155480 /* 11936495Sspeer * If the entry being added corresponds to LDC_SERVICE resource, 11946495Sspeer * that is, vswitch connection, it is added to the hash and also 11956495Sspeer * the entry is cached, an additional reference count reflects 11966495Sspeer * this. The HYBRID resource is not added to the hash, but only 11976495Sspeer * cached, as it is only used for sending out packets for unknown 11986495Sspeer * unicast destinations. 11996419Ssb155480 */ 12006495Sspeer (vresp->type == VIO_NET_RES_LDC_SERVICE) ? 12016495Sspeer (vresp->refcnt = 1) : (vresp->refcnt = 0); 12021991Sheppo 12036419Ssb155480 /* 12046419Ssb155480 * Note: duplicate keys will be rejected by mod_hash. 12056419Ssb155480 */ 12066495Sspeer if (vresp->type != VIO_NET_RES_HYBRID) { 12076495Sspeer rv = mod_hash_insert(vnetp->fdb_hashp, (mod_hash_key_t)addr, 12086495Sspeer (mod_hash_val_t)vresp); 12096495Sspeer if (rv != 0) { 12106495Sspeer DWARN(vnetp, "Duplicate macaddr key(%lx)\n", addr); 12116495Sspeer return; 12126495Sspeer } 12131991Sheppo } 12141991Sheppo 12156495Sspeer if (vresp->type == VIO_NET_RES_LDC_SERVICE) { 12166419Ssb155480 /* Cache the fdb entry to vsw-port */ 12176419Ssb155480 WRITE_ENTER(&vnetp->vsw_fp_rw); 12186419Ssb155480 if (vnetp->vsw_fp == NULL) 12196495Sspeer vnetp->vsw_fp = vresp; 12206495Sspeer RW_EXIT(&vnetp->vsw_fp_rw); 12216495Sspeer } else if (vresp->type == VIO_NET_RES_HYBRID) { 12226495Sspeer /* Cache the fdb entry to hybrid resource */ 12236495Sspeer WRITE_ENTER(&vnetp->vsw_fp_rw); 12246495Sspeer if (vnetp->hio_fp == NULL) 12256495Sspeer vnetp->hio_fp = vresp; 12266419Ssb155480 RW_EXIT(&vnetp->vsw_fp_rw); 12272793Slm66018 } 12281991Sheppo } 12291991Sheppo 12306419Ssb155480 /* 12316419Ssb155480 * Remove an entry from fdb. 12326419Ssb155480 */ 12336495Sspeer static void 12346495Sspeer vnet_fdbe_del(vnet_t *vnetp, vnet_res_t *vresp) 12355641Swentaoy { 12366419Ssb155480 uint64_t addr = 0; 12376419Ssb155480 int rv; 12386419Ssb155480 uint32_t refcnt; 12396495Sspeer vnet_res_t *tmp; 12405641Swentaoy 12416495Sspeer KEY_HASH(addr, vresp->rem_macaddr); 12425641Swentaoy 12436419Ssb155480 /* 12446419Ssb155480 * Remove the entry from fdb hash table. 12456419Ssb155480 * This prevents further references to this fdb entry. 12466419Ssb155480 */ 12476495Sspeer if (vresp->type != VIO_NET_RES_HYBRID) { 12486495Sspeer rv = mod_hash_remove(vnetp->fdb_hashp, (mod_hash_key_t)addr, 12496495Sspeer (mod_hash_val_t *)&tmp); 12506495Sspeer if (rv != 0) { 12516495Sspeer /* 12526495Sspeer * As the resources are added to the hash only 12536495Sspeer * after they are started, this can occur if 12546495Sspeer * a resource unregisters before it is ever started. 12556495Sspeer */ 12566495Sspeer return; 12576495Sspeer } 12586495Sspeer } 12595641Swentaoy 12606495Sspeer if (vresp->type == VIO_NET_RES_LDC_SERVICE) { 12616419Ssb155480 WRITE_ENTER(&vnetp->vsw_fp_rw); 12625641Swentaoy 12636495Sspeer ASSERT(tmp == vnetp->vsw_fp); 12646419Ssb155480 vnetp->vsw_fp = NULL; 12656419Ssb155480 12666419Ssb155480 RW_EXIT(&vnetp->vsw_fp_rw); 12676495Sspeer } else if (vresp->type == VIO_NET_RES_HYBRID) { 12686495Sspeer WRITE_ENTER(&vnetp->vsw_fp_rw); 12696495Sspeer 12706495Sspeer vnetp->hio_fp = NULL; 12716495Sspeer 12726495Sspeer RW_EXIT(&vnetp->vsw_fp_rw); 12735641Swentaoy } 12745641Swentaoy 12755641Swentaoy /* 12766419Ssb155480 * If there are threads already ref holding before the entry was 12776419Ssb155480 * removed from hash table, then wait for ref count to drop to zero. 12785641Swentaoy */ 12796495Sspeer (vresp->type == VIO_NET_RES_LDC_SERVICE) ? 12806495Sspeer (refcnt = 1) : (refcnt = 0); 12816495Sspeer while (vresp->refcnt > refcnt) { 12826419Ssb155480 delay(drv_usectohz(vnet_fdbe_refcnt_delay)); 12836419Ssb155480 } 12841991Sheppo } 12851991Sheppo 12866419Ssb155480 /* 12876419Ssb155480 * Search fdb for a given mac address. If an entry is found, hold 12886419Ssb155480 * a reference to it and return the entry; else returns NULL. 12896419Ssb155480 */ 12906495Sspeer static vnet_res_t * 12916419Ssb155480 vnet_fdbe_find(vnet_t *vnetp, struct ether_addr *addrp) 12921991Sheppo { 12936419Ssb155480 uint64_t key = 0; 12946495Sspeer vnet_res_t *vresp; 12956419Ssb155480 int rv; 12966419Ssb155480 12976495Sspeer KEY_HASH(key, addrp->ether_addr_octet); 12986419Ssb155480 12996419Ssb155480 rv = mod_hash_find_cb(vnetp->fdb_hashp, (mod_hash_key_t)key, 13006495Sspeer (mod_hash_val_t *)&vresp, vnet_fdbe_find_cb); 13011991Sheppo 13026419Ssb155480 if (rv != 0) 13036419Ssb155480 return (NULL); 13041991Sheppo 13056495Sspeer return (vresp); 13066419Ssb155480 } 13071991Sheppo 13086419Ssb155480 /* 13096419Ssb155480 * Callback function provided to mod_hash_find_cb(). After finding the fdb 13106419Ssb155480 * entry corresponding to the key (macaddr), this callback will be invoked by 13116419Ssb155480 * mod_hash_find_cb() to atomically increment the reference count on the fdb 13126419Ssb155480 * entry before returning the found entry. 13136419Ssb155480 */ 13146419Ssb155480 static void 13156419Ssb155480 vnet_fdbe_find_cb(mod_hash_key_t key, mod_hash_val_t val) 13166419Ssb155480 { 13176419Ssb155480 _NOTE(ARGUNUSED(key)) 13186495Sspeer VNET_FDBE_REFHOLD((vnet_res_t *)val); 13196495Sspeer } 13206495Sspeer 13217896SSriharsha.Basavapatna@Sun.COM /* 13227896SSriharsha.Basavapatna@Sun.COM * Frames received that are tagged with the pvid of the vnet device must be 13237896SSriharsha.Basavapatna@Sun.COM * untagged before sending up the stack. This function walks the chain of rx 13247896SSriharsha.Basavapatna@Sun.COM * frames, untags any such frames and returns the updated chain. 13257896SSriharsha.Basavapatna@Sun.COM * 13267896SSriharsha.Basavapatna@Sun.COM * Arguments: 13277896SSriharsha.Basavapatna@Sun.COM * pvid: pvid of the vnet device for which packets are being received 13287896SSriharsha.Basavapatna@Sun.COM * mp: head of pkt chain to be validated and untagged 13297896SSriharsha.Basavapatna@Sun.COM * 13307896SSriharsha.Basavapatna@Sun.COM * Returns: 13317896SSriharsha.Basavapatna@Sun.COM * mp: head of updated chain of packets 13327896SSriharsha.Basavapatna@Sun.COM */ 13337896SSriharsha.Basavapatna@Sun.COM static void 13347896SSriharsha.Basavapatna@Sun.COM vnet_rx_frames_untag(uint16_t pvid, mblk_t **mp) 13357896SSriharsha.Basavapatna@Sun.COM { 13367896SSriharsha.Basavapatna@Sun.COM struct ether_vlan_header *evhp; 13377896SSriharsha.Basavapatna@Sun.COM mblk_t *bp; 13387896SSriharsha.Basavapatna@Sun.COM mblk_t *bpt; 13397896SSriharsha.Basavapatna@Sun.COM mblk_t *bph; 13407896SSriharsha.Basavapatna@Sun.COM mblk_t *bpn; 13417896SSriharsha.Basavapatna@Sun.COM 13427896SSriharsha.Basavapatna@Sun.COM bpn = bph = bpt = NULL; 13437896SSriharsha.Basavapatna@Sun.COM 13447896SSriharsha.Basavapatna@Sun.COM for (bp = *mp; bp != NULL; bp = bpn) { 13457896SSriharsha.Basavapatna@Sun.COM 13467896SSriharsha.Basavapatna@Sun.COM bpn = bp->b_next; 13477896SSriharsha.Basavapatna@Sun.COM bp->b_next = bp->b_prev = NULL; 13487896SSriharsha.Basavapatna@Sun.COM 13497896SSriharsha.Basavapatna@Sun.COM evhp = (struct ether_vlan_header *)bp->b_rptr; 13507896SSriharsha.Basavapatna@Sun.COM 13517896SSriharsha.Basavapatna@Sun.COM if (ntohs(evhp->ether_tpid) == ETHERTYPE_VLAN && 13527896SSriharsha.Basavapatna@Sun.COM VLAN_ID(ntohs(evhp->ether_tci)) == pvid) { 13537896SSriharsha.Basavapatna@Sun.COM 13547896SSriharsha.Basavapatna@Sun.COM bp = vnet_vlan_remove_tag(bp); 13557896SSriharsha.Basavapatna@Sun.COM if (bp == NULL) { 13567896SSriharsha.Basavapatna@Sun.COM continue; 13577896SSriharsha.Basavapatna@Sun.COM } 13587896SSriharsha.Basavapatna@Sun.COM 13597896SSriharsha.Basavapatna@Sun.COM } 13607896SSriharsha.Basavapatna@Sun.COM 13617896SSriharsha.Basavapatna@Sun.COM /* build a chain of processed packets */ 13627896SSriharsha.Basavapatna@Sun.COM if (bph == NULL) { 13637896SSriharsha.Basavapatna@Sun.COM bph = bpt = bp; 13647896SSriharsha.Basavapatna@Sun.COM } else { 13657896SSriharsha.Basavapatna@Sun.COM bpt->b_next = bp; 13667896SSriharsha.Basavapatna@Sun.COM bpt = bp; 13677896SSriharsha.Basavapatna@Sun.COM } 13687896SSriharsha.Basavapatna@Sun.COM 13697896SSriharsha.Basavapatna@Sun.COM } 13707896SSriharsha.Basavapatna@Sun.COM 13717896SSriharsha.Basavapatna@Sun.COM *mp = bph; 13727896SSriharsha.Basavapatna@Sun.COM } 13737896SSriharsha.Basavapatna@Sun.COM 13746495Sspeer static void 13756495Sspeer vnet_rx(vio_net_handle_t vrh, mblk_t *mp) 13766495Sspeer { 137710309SSriharsha.Basavapatna@Sun.COM vnet_res_t *vresp = (vnet_res_t *)vrh; 137810309SSriharsha.Basavapatna@Sun.COM vnet_t *vnetp = vresp->vnetp; 137910309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_rx_ring_t *ringp; 13807896SSriharsha.Basavapatna@Sun.COM 13817896SSriharsha.Basavapatna@Sun.COM if ((vnetp == NULL) || (vnetp->mh == 0)) { 13827896SSriharsha.Basavapatna@Sun.COM freemsgchain(mp); 13837896SSriharsha.Basavapatna@Sun.COM return; 13847896SSriharsha.Basavapatna@Sun.COM } 13856495Sspeer 138610309SSriharsha.Basavapatna@Sun.COM ringp = vresp->rx_ringp; 138710309SSriharsha.Basavapatna@Sun.COM mac_rx_ring(vnetp->mh, ringp->handle, mp, ringp->gen_num); 13881991Sheppo } 13892311Sseb 13902311Sseb void 13916495Sspeer vnet_tx_update(vio_net_handle_t vrh) 13926495Sspeer { 139310309SSriharsha.Basavapatna@Sun.COM vnet_res_t *vresp = (vnet_res_t *)vrh; 139410309SSriharsha.Basavapatna@Sun.COM vnet_t *vnetp = vresp->vnetp; 139510309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_tx_ring_t *tx_ringp; 139610309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_tx_group_t *tx_grp; 139710309SSriharsha.Basavapatna@Sun.COM int i; 139810309SSriharsha.Basavapatna@Sun.COM 139910309SSriharsha.Basavapatna@Sun.COM if (vnetp == NULL || vnetp->mh == NULL) { 140010309SSriharsha.Basavapatna@Sun.COM return; 140110309SSriharsha.Basavapatna@Sun.COM } 140210309SSriharsha.Basavapatna@Sun.COM 140310309SSriharsha.Basavapatna@Sun.COM /* 140410309SSriharsha.Basavapatna@Sun.COM * Currently, the tx hwring API (used to access rings that belong to 140510309SSriharsha.Basavapatna@Sun.COM * a Hybrid IO resource) does not provide us a per ring flow ctrl 140610309SSriharsha.Basavapatna@Sun.COM * update; also the pseudo rings are shared by the ports/ldcs in the 140710309SSriharsha.Basavapatna@Sun.COM * vgen layer. Thus we can't figure out which pseudo ring is being 140810309SSriharsha.Basavapatna@Sun.COM * re-enabled for transmits. To work around this, when we get a tx 140910309SSriharsha.Basavapatna@Sun.COM * restart notification from below, we simply propagate that to all 141010309SSriharsha.Basavapatna@Sun.COM * the tx pseudo rings registered with the mac layer above. 141110309SSriharsha.Basavapatna@Sun.COM * 141210309SSriharsha.Basavapatna@Sun.COM * There are a couple of side effects with this approach, but they are 141310309SSriharsha.Basavapatna@Sun.COM * not harmful, as outlined below: 141410309SSriharsha.Basavapatna@Sun.COM * 141510309SSriharsha.Basavapatna@Sun.COM * A) We might send an invalid ring_update() for a ring that is not 141610309SSriharsha.Basavapatna@Sun.COM * really flow controlled. This will not have any effect in the mac 141710309SSriharsha.Basavapatna@Sun.COM * layer and packets will continue to be transmitted on that ring. 141810309SSriharsha.Basavapatna@Sun.COM * 141910309SSriharsha.Basavapatna@Sun.COM * B) We might end up clearing the flow control in the mac layer for 142010309SSriharsha.Basavapatna@Sun.COM * a ring that is still flow controlled in the underlying resource. 142110309SSriharsha.Basavapatna@Sun.COM * This will result in the mac layer restarting transmit, only to be 142210309SSriharsha.Basavapatna@Sun.COM * flow controlled again on that ring. 142310309SSriharsha.Basavapatna@Sun.COM */ 142410309SSriharsha.Basavapatna@Sun.COM tx_grp = &vnetp->tx_grp[0]; 142510309SSriharsha.Basavapatna@Sun.COM for (i = 0; i < tx_grp->ring_cnt; i++) { 142610309SSriharsha.Basavapatna@Sun.COM tx_ringp = &tx_grp->rings[i]; 142710309SSriharsha.Basavapatna@Sun.COM mac_tx_ring_update(vnetp->mh, tx_ringp->handle); 14286495Sspeer } 14296495Sspeer } 14306495Sspeer 14316495Sspeer /* 143211878SVenu.Iyer@Sun.COM * vnet_tx_notify_thread: 143311878SVenu.Iyer@Sun.COM * 143411878SVenu.Iyer@Sun.COM * vnet_tx_ring_update() callback function wakes up this thread when 143511878SVenu.Iyer@Sun.COM * it gets called. This thread will call mac_tx_ring_update() to 143611878SVenu.Iyer@Sun.COM * notify upper mac of flow control getting relieved. Note that 143711878SVenu.Iyer@Sun.COM * vnet_tx_ring_update() cannot call mac_tx_ring_update() directly 143811878SVenu.Iyer@Sun.COM * because vnet_tx_ring_update() is called from lower mac with 143911878SVenu.Iyer@Sun.COM * mi_rw_lock held and mac_tx_ring_update() would also try to grab 144011878SVenu.Iyer@Sun.COM * the same lock. 144111878SVenu.Iyer@Sun.COM */ 144211878SVenu.Iyer@Sun.COM static void 144311878SVenu.Iyer@Sun.COM vnet_tx_notify_thread(void *arg) 144411878SVenu.Iyer@Sun.COM { 144511878SVenu.Iyer@Sun.COM callb_cpr_t cprinfo; 144611878SVenu.Iyer@Sun.COM vnet_pseudo_tx_group_t *tx_grp = (vnet_pseudo_tx_group_t *)arg; 144711878SVenu.Iyer@Sun.COM vnet_pseudo_tx_ring_t *tx_ringp; 144811878SVenu.Iyer@Sun.COM vnet_t *vnetp; 144911878SVenu.Iyer@Sun.COM int i; 145011878SVenu.Iyer@Sun.COM 145111878SVenu.Iyer@Sun.COM CALLB_CPR_INIT(&cprinfo, &tx_grp->flowctl_lock, callb_generic_cpr, 145211878SVenu.Iyer@Sun.COM "vnet_tx_notify_thread"); 145311878SVenu.Iyer@Sun.COM 145411878SVenu.Iyer@Sun.COM mutex_enter(&tx_grp->flowctl_lock); 145511878SVenu.Iyer@Sun.COM while (!tx_grp->flowctl_done) { 145611878SVenu.Iyer@Sun.COM CALLB_CPR_SAFE_BEGIN(&cprinfo); 145711878SVenu.Iyer@Sun.COM cv_wait(&tx_grp->flowctl_cv, &tx_grp->flowctl_lock); 145811878SVenu.Iyer@Sun.COM CALLB_CPR_SAFE_END(&cprinfo, &tx_grp->flowctl_lock); 145911878SVenu.Iyer@Sun.COM 146011878SVenu.Iyer@Sun.COM for (i = 0; i < tx_grp->ring_cnt; i++) { 146111878SVenu.Iyer@Sun.COM tx_ringp = &tx_grp->rings[i]; 146211878SVenu.Iyer@Sun.COM if (tx_ringp->woken_up) { 146311878SVenu.Iyer@Sun.COM tx_ringp->woken_up = B_FALSE; 146411878SVenu.Iyer@Sun.COM vnetp = tx_ringp->vnetp; 146511878SVenu.Iyer@Sun.COM mac_tx_ring_update(vnetp->mh, tx_ringp->handle); 146611878SVenu.Iyer@Sun.COM } 146711878SVenu.Iyer@Sun.COM } 146811878SVenu.Iyer@Sun.COM } 146911878SVenu.Iyer@Sun.COM /* 147011878SVenu.Iyer@Sun.COM * The tx_grp is being destroyed, exit the thread. 147111878SVenu.Iyer@Sun.COM */ 147211878SVenu.Iyer@Sun.COM tx_grp->flowctl_thread = NULL; 147311878SVenu.Iyer@Sun.COM CALLB_CPR_EXIT(&cprinfo); 147411878SVenu.Iyer@Sun.COM thread_exit(); 147511878SVenu.Iyer@Sun.COM } 147611878SVenu.Iyer@Sun.COM 147711878SVenu.Iyer@Sun.COM void 147811878SVenu.Iyer@Sun.COM vnet_tx_ring_update(void *arg1, uintptr_t arg2) 147911878SVenu.Iyer@Sun.COM { 148011878SVenu.Iyer@Sun.COM vnet_t *vnetp = (vnet_t *)arg1; 148111878SVenu.Iyer@Sun.COM vnet_pseudo_tx_group_t *tx_grp; 148211878SVenu.Iyer@Sun.COM vnet_pseudo_tx_ring_t *tx_ringp; 148311878SVenu.Iyer@Sun.COM int i; 148411878SVenu.Iyer@Sun.COM 148511878SVenu.Iyer@Sun.COM tx_grp = &vnetp->tx_grp[0]; 148611878SVenu.Iyer@Sun.COM for (i = 0; i < tx_grp->ring_cnt; i++) { 148711878SVenu.Iyer@Sun.COM tx_ringp = &tx_grp->rings[i]; 148811878SVenu.Iyer@Sun.COM if (tx_ringp->hw_rh == (mac_ring_handle_t)arg2) { 148911878SVenu.Iyer@Sun.COM mutex_enter(&tx_grp->flowctl_lock); 149011878SVenu.Iyer@Sun.COM tx_ringp->woken_up = B_TRUE; 149111878SVenu.Iyer@Sun.COM cv_signal(&tx_grp->flowctl_cv); 149211878SVenu.Iyer@Sun.COM mutex_exit(&tx_grp->flowctl_lock); 149311878SVenu.Iyer@Sun.COM break; 149411878SVenu.Iyer@Sun.COM } 149511878SVenu.Iyer@Sun.COM } 149611878SVenu.Iyer@Sun.COM } 149711878SVenu.Iyer@Sun.COM 149811878SVenu.Iyer@Sun.COM /* 14997529SSriharsha.Basavapatna@Sun.COM * Update the new mtu of vnet into the mac layer. First check if the device has 15007529SSriharsha.Basavapatna@Sun.COM * been plumbed and if so fail the mtu update. Returns 0 on success. 15017529SSriharsha.Basavapatna@Sun.COM */ 15027529SSriharsha.Basavapatna@Sun.COM int 15037529SSriharsha.Basavapatna@Sun.COM vnet_mtu_update(vnet_t *vnetp, uint32_t mtu) 15047529SSriharsha.Basavapatna@Sun.COM { 15057529SSriharsha.Basavapatna@Sun.COM int rv; 15067529SSriharsha.Basavapatna@Sun.COM 15077529SSriharsha.Basavapatna@Sun.COM if (vnetp == NULL || vnetp->mh == NULL) { 15087529SSriharsha.Basavapatna@Sun.COM return (EINVAL); 15097529SSriharsha.Basavapatna@Sun.COM } 15107529SSriharsha.Basavapatna@Sun.COM 15117529SSriharsha.Basavapatna@Sun.COM WRITE_ENTER(&vnetp->vrwlock); 15127529SSriharsha.Basavapatna@Sun.COM 15137529SSriharsha.Basavapatna@Sun.COM if (vnetp->flags & VNET_STARTED) { 15147529SSriharsha.Basavapatna@Sun.COM RW_EXIT(&vnetp->vrwlock); 15157529SSriharsha.Basavapatna@Sun.COM cmn_err(CE_NOTE, "!vnet%d: Unable to process mtu " 15167529SSriharsha.Basavapatna@Sun.COM "update as the device is plumbed\n", 15177529SSriharsha.Basavapatna@Sun.COM vnetp->instance); 15187529SSriharsha.Basavapatna@Sun.COM return (EBUSY); 15197529SSriharsha.Basavapatna@Sun.COM } 15207529SSriharsha.Basavapatna@Sun.COM 15217529SSriharsha.Basavapatna@Sun.COM /* update mtu in the mac layer */ 15227529SSriharsha.Basavapatna@Sun.COM rv = mac_maxsdu_update(vnetp->mh, mtu); 15237529SSriharsha.Basavapatna@Sun.COM if (rv != 0) { 15247529SSriharsha.Basavapatna@Sun.COM RW_EXIT(&vnetp->vrwlock); 15257529SSriharsha.Basavapatna@Sun.COM cmn_err(CE_NOTE, 15267529SSriharsha.Basavapatna@Sun.COM "!vnet%d: Unable to update mtu with mac layer\n", 15277529SSriharsha.Basavapatna@Sun.COM vnetp->instance); 15287529SSriharsha.Basavapatna@Sun.COM return (EIO); 15297529SSriharsha.Basavapatna@Sun.COM } 15307529SSriharsha.Basavapatna@Sun.COM 15317529SSriharsha.Basavapatna@Sun.COM vnetp->mtu = mtu; 15327529SSriharsha.Basavapatna@Sun.COM 15337529SSriharsha.Basavapatna@Sun.COM RW_EXIT(&vnetp->vrwlock); 15347529SSriharsha.Basavapatna@Sun.COM 15357529SSriharsha.Basavapatna@Sun.COM return (0); 15367529SSriharsha.Basavapatna@Sun.COM } 15377529SSriharsha.Basavapatna@Sun.COM 15387529SSriharsha.Basavapatna@Sun.COM /* 15399336SSriharsha.Basavapatna@Sun.COM * Update the link state of vnet to the mac layer. 15409336SSriharsha.Basavapatna@Sun.COM */ 15419336SSriharsha.Basavapatna@Sun.COM void 15429336SSriharsha.Basavapatna@Sun.COM vnet_link_update(vnet_t *vnetp, link_state_t link_state) 15439336SSriharsha.Basavapatna@Sun.COM { 15449336SSriharsha.Basavapatna@Sun.COM if (vnetp == NULL || vnetp->mh == NULL) { 15459336SSriharsha.Basavapatna@Sun.COM return; 15469336SSriharsha.Basavapatna@Sun.COM } 15479336SSriharsha.Basavapatna@Sun.COM 15489336SSriharsha.Basavapatna@Sun.COM WRITE_ENTER(&vnetp->vrwlock); 15499336SSriharsha.Basavapatna@Sun.COM if (vnetp->link_state == link_state) { 15509336SSriharsha.Basavapatna@Sun.COM RW_EXIT(&vnetp->vrwlock); 15519336SSriharsha.Basavapatna@Sun.COM return; 15529336SSriharsha.Basavapatna@Sun.COM } 15539336SSriharsha.Basavapatna@Sun.COM vnetp->link_state = link_state; 15549336SSriharsha.Basavapatna@Sun.COM RW_EXIT(&vnetp->vrwlock); 15559336SSriharsha.Basavapatna@Sun.COM 15569336SSriharsha.Basavapatna@Sun.COM mac_link_update(vnetp->mh, link_state); 15579336SSriharsha.Basavapatna@Sun.COM } 15589336SSriharsha.Basavapatna@Sun.COM 15599336SSriharsha.Basavapatna@Sun.COM /* 15606495Sspeer * vio_net_resource_reg -- An interface called to register a resource 15616495Sspeer * with vnet. 15626495Sspeer * macp -- a GLDv3 mac_register that has all the details of 15636495Sspeer * a resource and its callbacks etc. 15646495Sspeer * type -- resource type. 15656495Sspeer * local_macaddr -- resource's MAC address. This is used to 15666495Sspeer * associate a resource with a corresponding vnet. 15676495Sspeer * remote_macaddr -- remote side MAC address. This is ignored for 15686495Sspeer * the Hybrid resources. 15696495Sspeer * vhp -- A handle returned to the caller. 15706495Sspeer * vcb -- A set of callbacks provided to the callers. 15716495Sspeer */ 15726495Sspeer int vio_net_resource_reg(mac_register_t *macp, vio_net_res_type_t type, 15736495Sspeer ether_addr_t local_macaddr, ether_addr_t rem_macaddr, vio_net_handle_t *vhp, 15746495Sspeer vio_net_callbacks_t *vcb) 15756495Sspeer { 157610309SSriharsha.Basavapatna@Sun.COM vnet_t *vnetp; 157710309SSriharsha.Basavapatna@Sun.COM vnet_res_t *vresp; 15786495Sspeer 15796495Sspeer vresp = kmem_zalloc(sizeof (vnet_res_t), KM_SLEEP); 15806495Sspeer ether_copy(local_macaddr, vresp->local_macaddr); 15816495Sspeer ether_copy(rem_macaddr, vresp->rem_macaddr); 15826495Sspeer vresp->type = type; 15836495Sspeer bcopy(macp, &vresp->macreg, sizeof (mac_register_t)); 15846495Sspeer 15856495Sspeer DBG1(NULL, "Resource Registerig type=0%X\n", type); 15866495Sspeer 15876495Sspeer READ_ENTER(&vnet_rw); 15886495Sspeer vnetp = vnet_headp; 15896495Sspeer while (vnetp != NULL) { 15906495Sspeer if (VNET_MATCH_RES(vresp, vnetp)) { 15918332SWentao.Yang@Sun.COM vresp->vnetp = vnetp; 15928332SWentao.Yang@Sun.COM 15938332SWentao.Yang@Sun.COM /* Setup kstats for hio resource */ 15948332SWentao.Yang@Sun.COM if (vresp->type == VIO_NET_RES_HYBRID) { 15958332SWentao.Yang@Sun.COM vresp->ksp = vnet_hio_setup_kstats(DRV_NAME, 15968332SWentao.Yang@Sun.COM "hio", vresp); 15978332SWentao.Yang@Sun.COM if (vresp->ksp == NULL) { 15988332SWentao.Yang@Sun.COM cmn_err(CE_NOTE, "!vnet%d: Cannot " 15998332SWentao.Yang@Sun.COM "create kstats for hio resource", 16008332SWentao.Yang@Sun.COM vnetp->instance); 16018332SWentao.Yang@Sun.COM } 16028332SWentao.Yang@Sun.COM } 160310309SSriharsha.Basavapatna@Sun.COM vnet_add_resource(vnetp, vresp); 16046495Sspeer break; 16056495Sspeer } 16066495Sspeer vnetp = vnetp->nextp; 16076495Sspeer } 16086495Sspeer RW_EXIT(&vnet_rw); 16096495Sspeer if (vresp->vnetp == NULL) { 16106495Sspeer DWARN(NULL, "No vnet instance"); 16116495Sspeer kmem_free(vresp, sizeof (vnet_res_t)); 16126495Sspeer return (ENXIO); 16136495Sspeer } 16146495Sspeer 16156495Sspeer *vhp = vresp; 16166495Sspeer vcb->vio_net_rx_cb = vnet_rx; 16176495Sspeer vcb->vio_net_tx_update = vnet_tx_update; 16186495Sspeer vcb->vio_net_report_err = vnet_handle_res_err; 16196495Sspeer 162010309SSriharsha.Basavapatna@Sun.COM /* Bind the resource to pseudo ring(s) */ 162110309SSriharsha.Basavapatna@Sun.COM if (vnet_bind_rings(vresp) != 0) { 162210309SSriharsha.Basavapatna@Sun.COM (void) vnet_rem_resource(vnetp, vresp); 162310309SSriharsha.Basavapatna@Sun.COM vnet_hio_destroy_kstats(vresp->ksp); 162410309SSriharsha.Basavapatna@Sun.COM KMEM_FREE(vresp); 162510309SSriharsha.Basavapatna@Sun.COM return (1); 162610309SSriharsha.Basavapatna@Sun.COM } 162710309SSriharsha.Basavapatna@Sun.COM 16286495Sspeer /* Dispatch a task to start resources */ 16296495Sspeer vnet_dispatch_res_task(vnetp); 16306495Sspeer return (0); 16316495Sspeer } 16326495Sspeer 16336495Sspeer /* 16346495Sspeer * vio_net_resource_unreg -- An interface to unregister a resource. 16356495Sspeer */ 16366495Sspeer void 16376495Sspeer vio_net_resource_unreg(vio_net_handle_t vhp) 16386495Sspeer { 16399805SSriharsha.Basavapatna@Sun.COM vnet_res_t *vresp = (vnet_res_t *)vhp; 16409805SSriharsha.Basavapatna@Sun.COM vnet_t *vnetp = vresp->vnetp; 16416495Sspeer 16426495Sspeer DBG1(NULL, "Resource Registerig hdl=0x%p", vhp); 16436495Sspeer 16446495Sspeer ASSERT(vnetp != NULL); 16459805SSriharsha.Basavapatna@Sun.COM /* 16469805SSriharsha.Basavapatna@Sun.COM * Remove the resource from fdb; this ensures 16479805SSriharsha.Basavapatna@Sun.COM * there are no references to the resource. 16489805SSriharsha.Basavapatna@Sun.COM */ 16496495Sspeer vnet_fdbe_del(vnetp, vresp); 16506495Sspeer 165110309SSriharsha.Basavapatna@Sun.COM vnet_unbind_rings(vresp); 165210309SSriharsha.Basavapatna@Sun.COM 16539805SSriharsha.Basavapatna@Sun.COM /* Now remove the resource from the list */ 165410309SSriharsha.Basavapatna@Sun.COM (void) vnet_rem_resource(vnetp, vresp); 165510309SSriharsha.Basavapatna@Sun.COM 165610309SSriharsha.Basavapatna@Sun.COM vnet_hio_destroy_kstats(vresp->ksp); 165710309SSriharsha.Basavapatna@Sun.COM KMEM_FREE(vresp); 165810309SSriharsha.Basavapatna@Sun.COM } 165910309SSriharsha.Basavapatna@Sun.COM 166010309SSriharsha.Basavapatna@Sun.COM static void 166110309SSriharsha.Basavapatna@Sun.COM vnet_add_resource(vnet_t *vnetp, vnet_res_t *vresp) 166210309SSriharsha.Basavapatna@Sun.COM { 166310309SSriharsha.Basavapatna@Sun.COM WRITE_ENTER(&vnetp->vrwlock); 166410309SSriharsha.Basavapatna@Sun.COM vresp->nextp = vnetp->vres_list; 166510309SSriharsha.Basavapatna@Sun.COM vnetp->vres_list = vresp; 166610309SSriharsha.Basavapatna@Sun.COM RW_EXIT(&vnetp->vrwlock); 166710309SSriharsha.Basavapatna@Sun.COM } 166810309SSriharsha.Basavapatna@Sun.COM 166910309SSriharsha.Basavapatna@Sun.COM static vnet_res_t * 167010309SSriharsha.Basavapatna@Sun.COM vnet_rem_resource(vnet_t *vnetp, vnet_res_t *vresp) 167110309SSriharsha.Basavapatna@Sun.COM { 167210309SSriharsha.Basavapatna@Sun.COM vnet_res_t *vrp; 167310309SSriharsha.Basavapatna@Sun.COM 16746495Sspeer WRITE_ENTER(&vnetp->vrwlock); 16756495Sspeer if (vresp == vnetp->vres_list) { 16766495Sspeer vnetp->vres_list = vresp->nextp; 16776495Sspeer } else { 16786495Sspeer vrp = vnetp->vres_list; 16796495Sspeer while (vrp->nextp != NULL) { 16806495Sspeer if (vrp->nextp == vresp) { 16816495Sspeer vrp->nextp = vresp->nextp; 16826495Sspeer break; 16836495Sspeer } 16846495Sspeer vrp = vrp->nextp; 16856495Sspeer } 16866495Sspeer } 16876495Sspeer vresp->vnetp = NULL; 16886495Sspeer vresp->nextp = NULL; 168910309SSriharsha.Basavapatna@Sun.COM 16906495Sspeer RW_EXIT(&vnetp->vrwlock); 169110309SSriharsha.Basavapatna@Sun.COM 169210309SSriharsha.Basavapatna@Sun.COM return (vresp); 16936495Sspeer } 16946495Sspeer 16956495Sspeer /* 16966495Sspeer * vnet_dds_rx -- an interface called by vgen to DDS messages. 16976495Sspeer */ 16986495Sspeer void 16996495Sspeer vnet_dds_rx(void *arg, void *dmsg) 17002311Sseb { 17012311Sseb vnet_t *vnetp = arg; 17026495Sspeer vdds_process_dds_msg(vnetp, dmsg); 17032311Sseb } 17042311Sseb 17056495Sspeer /* 17066495Sspeer * vnet_send_dds_msg -- An interface provided to DDS to send 17076495Sspeer * DDS messages. This simply sends meessages via vgen. 17086495Sspeer */ 17096495Sspeer int 17106495Sspeer vnet_send_dds_msg(vnet_t *vnetp, void *dmsg) 17116495Sspeer { 17126495Sspeer int rv; 17136495Sspeer 17146495Sspeer if (vnetp->vgenhdl != NULL) { 17156495Sspeer rv = vgen_dds_tx(vnetp->vgenhdl, dmsg); 17166495Sspeer } 17176495Sspeer return (rv); 17186495Sspeer } 17196495Sspeer 17206495Sspeer /* 17219647SWentao.Yang@Sun.COM * vnet_cleanup_hio -- an interface called by vgen to cleanup hio resources. 17229647SWentao.Yang@Sun.COM */ 17239647SWentao.Yang@Sun.COM void 17249647SWentao.Yang@Sun.COM vnet_dds_cleanup_hio(vnet_t *vnetp) 17259647SWentao.Yang@Sun.COM { 17269647SWentao.Yang@Sun.COM vdds_cleanup_hio(vnetp); 17279647SWentao.Yang@Sun.COM } 17289647SWentao.Yang@Sun.COM 17299647SWentao.Yang@Sun.COM /* 17306495Sspeer * vnet_handle_res_err -- A callback function called by a resource 17316495Sspeer * to report an error. For example, vgen can call to report 17326495Sspeer * an LDC down/reset event. This will trigger cleanup of associated 17336495Sspeer * Hybrid resource. 17346495Sspeer */ 17356495Sspeer /* ARGSUSED */ 17366495Sspeer static void 17376495Sspeer vnet_handle_res_err(vio_net_handle_t vrh, vio_net_err_val_t err) 17386495Sspeer { 17396495Sspeer vnet_res_t *vresp = (vnet_res_t *)vrh; 17406495Sspeer vnet_t *vnetp = vresp->vnetp; 17416495Sspeer 17426495Sspeer if (vnetp == NULL) { 17436495Sspeer return; 17446495Sspeer } 17456495Sspeer if ((vresp->type != VIO_NET_RES_LDC_SERVICE) && 17466495Sspeer (vresp->type != VIO_NET_RES_HYBRID)) { 17476495Sspeer return; 17486495Sspeer } 17499647SWentao.Yang@Sun.COM 17509647SWentao.Yang@Sun.COM vdds_cleanup_hio(vnetp); 17516495Sspeer } 17526495Sspeer 17536495Sspeer /* 17546495Sspeer * vnet_dispatch_res_task -- A function to dispatch tasks start resources. 17556495Sspeer */ 17566495Sspeer static void 17576495Sspeer vnet_dispatch_res_task(vnet_t *vnetp) 17586495Sspeer { 17596495Sspeer int rv; 17606495Sspeer 17619677SZachary.Kissel@Sun.COM /* 17629677SZachary.Kissel@Sun.COM * Dispatch the task. It could be the case that vnetp->flags does 17639677SZachary.Kissel@Sun.COM * not have VNET_STARTED set. This is ok as vnet_rest_start_task() 17649805SSriharsha.Basavapatna@Sun.COM * can abort the task when the task is started. See related comments 17659805SSriharsha.Basavapatna@Sun.COM * in vnet_m_stop() and vnet_stop_resources(). 17669677SZachary.Kissel@Sun.COM */ 17679677SZachary.Kissel@Sun.COM rv = ddi_taskq_dispatch(vnetp->taskqp, vnet_res_start_task, 17689677SZachary.Kissel@Sun.COM vnetp, DDI_NOSLEEP); 17699677SZachary.Kissel@Sun.COM if (rv != DDI_SUCCESS) { 17709677SZachary.Kissel@Sun.COM cmn_err(CE_WARN, 17719677SZachary.Kissel@Sun.COM "vnet%d:Can't dispatch start resource task", 17729677SZachary.Kissel@Sun.COM vnetp->instance); 17736495Sspeer } 17746495Sspeer } 17756495Sspeer 17766495Sspeer /* 17776495Sspeer * vnet_res_start_task -- A taskq callback function that starts a resource. 17786495Sspeer */ 17796495Sspeer static void 17806495Sspeer vnet_res_start_task(void *arg) 17812311Sseb { 17822311Sseb vnet_t *vnetp = arg; 17836495Sspeer 17846495Sspeer WRITE_ENTER(&vnetp->vrwlock); 17856495Sspeer if (vnetp->flags & VNET_STARTED) { 17866495Sspeer vnet_start_resources(vnetp); 17876495Sspeer } 17886495Sspeer RW_EXIT(&vnetp->vrwlock); 17892311Sseb } 17906495Sspeer 17916495Sspeer /* 17926495Sspeer * vnet_start_resources -- starts all resources associated with 17936495Sspeer * a vnet. 17946495Sspeer */ 17956495Sspeer static void 17966495Sspeer vnet_start_resources(vnet_t *vnetp) 17976495Sspeer { 17986495Sspeer mac_register_t *macp; 17996495Sspeer mac_callbacks_t *cbp; 18006495Sspeer vnet_res_t *vresp; 18016495Sspeer int rv; 18026495Sspeer 18036495Sspeer DBG1(vnetp, "enter\n"); 18046495Sspeer 18059805SSriharsha.Basavapatna@Sun.COM ASSERT(RW_WRITE_HELD(&vnetp->vrwlock)); 18069805SSriharsha.Basavapatna@Sun.COM 18076495Sspeer for (vresp = vnetp->vres_list; vresp != NULL; vresp = vresp->nextp) { 18086495Sspeer /* skip if it is already started */ 18096495Sspeer if (vresp->flags & VNET_STARTED) { 18106495Sspeer continue; 18116495Sspeer } 18126495Sspeer macp = &vresp->macreg; 18136495Sspeer cbp = macp->m_callbacks; 18146495Sspeer rv = cbp->mc_start(macp->m_driver); 18156495Sspeer if (rv == 0) { 18166495Sspeer /* 18176495Sspeer * Successfully started the resource, so now 18186495Sspeer * add it to the fdb. 18196495Sspeer */ 18206495Sspeer vresp->flags |= VNET_STARTED; 18216495Sspeer vnet_fdbe_add(vnetp, vresp); 18226495Sspeer } 18236495Sspeer } 18246495Sspeer 18256495Sspeer DBG1(vnetp, "exit\n"); 18266495Sspeer 18276495Sspeer } 18286495Sspeer 18296495Sspeer /* 18306495Sspeer * vnet_stop_resources -- stop all resources associated with a vnet. 18316495Sspeer */ 18326495Sspeer static void 18336495Sspeer vnet_stop_resources(vnet_t *vnetp) 18346495Sspeer { 18356495Sspeer vnet_res_t *vresp; 18366495Sspeer mac_register_t *macp; 18376495Sspeer mac_callbacks_t *cbp; 18386495Sspeer 18396495Sspeer DBG1(vnetp, "enter\n"); 18406495Sspeer 18419805SSriharsha.Basavapatna@Sun.COM ASSERT(RW_WRITE_HELD(&vnetp->vrwlock)); 18429805SSriharsha.Basavapatna@Sun.COM 18436495Sspeer for (vresp = vnetp->vres_list; vresp != NULL; ) { 18446495Sspeer if (vresp->flags & VNET_STARTED) { 18459805SSriharsha.Basavapatna@Sun.COM /* 18469805SSriharsha.Basavapatna@Sun.COM * Release the lock while invoking mc_stop() of the 18479805SSriharsha.Basavapatna@Sun.COM * underlying resource. We hold a reference to this 18489805SSriharsha.Basavapatna@Sun.COM * resource to prevent being removed from the list in 18499805SSriharsha.Basavapatna@Sun.COM * vio_net_resource_unreg(). Note that new resources 18509805SSriharsha.Basavapatna@Sun.COM * can be added to the head of the list while the lock 18519805SSriharsha.Basavapatna@Sun.COM * is released, but they won't be started, as 18529805SSriharsha.Basavapatna@Sun.COM * VNET_STARTED flag has been cleared for the vnet 18539805SSriharsha.Basavapatna@Sun.COM * device in vnet_m_stop(). Also, while the lock is 18549805SSriharsha.Basavapatna@Sun.COM * released a resource could be removed from the list 18559805SSriharsha.Basavapatna@Sun.COM * in vio_net_resource_unreg(); but that is ok, as we 18569805SSriharsha.Basavapatna@Sun.COM * re-acquire the lock and only then access the forward 18579805SSriharsha.Basavapatna@Sun.COM * link (vresp->nextp) to continue with the next 18589805SSriharsha.Basavapatna@Sun.COM * resource. 18599805SSriharsha.Basavapatna@Sun.COM */ 18609805SSriharsha.Basavapatna@Sun.COM vresp->flags &= ~VNET_STARTED; 18619805SSriharsha.Basavapatna@Sun.COM vresp->flags |= VNET_STOPPING; 18626495Sspeer macp = &vresp->macreg; 18636495Sspeer cbp = macp->m_callbacks; 18649805SSriharsha.Basavapatna@Sun.COM VNET_FDBE_REFHOLD(vresp); 18659805SSriharsha.Basavapatna@Sun.COM RW_EXIT(&vnetp->vrwlock); 18669805SSriharsha.Basavapatna@Sun.COM 18676495Sspeer cbp->mc_stop(macp->m_driver); 18689805SSriharsha.Basavapatna@Sun.COM 18699805SSriharsha.Basavapatna@Sun.COM WRITE_ENTER(&vnetp->vrwlock); 18709805SSriharsha.Basavapatna@Sun.COM vresp->flags &= ~VNET_STOPPING; 18719805SSriharsha.Basavapatna@Sun.COM VNET_FDBE_REFRELE(vresp); 18726495Sspeer } 18739805SSriharsha.Basavapatna@Sun.COM vresp = vresp->nextp; 18746495Sspeer } 18756495Sspeer DBG1(vnetp, "exit\n"); 18766495Sspeer } 18778160SWentao.Yang@Sun.COM 18788160SWentao.Yang@Sun.COM /* 18798160SWentao.Yang@Sun.COM * Setup kstats for the HIO statistics. 18808160SWentao.Yang@Sun.COM * NOTE: the synchronization for the statistics is the 18818160SWentao.Yang@Sun.COM * responsibility of the caller. 18828160SWentao.Yang@Sun.COM */ 18838160SWentao.Yang@Sun.COM kstat_t * 18848160SWentao.Yang@Sun.COM vnet_hio_setup_kstats(char *ks_mod, char *ks_name, vnet_res_t *vresp) 18858160SWentao.Yang@Sun.COM { 18868160SWentao.Yang@Sun.COM kstat_t *ksp; 18878160SWentao.Yang@Sun.COM vnet_t *vnetp = vresp->vnetp; 18888160SWentao.Yang@Sun.COM vnet_hio_kstats_t *hiokp; 18898160SWentao.Yang@Sun.COM size_t size; 18908160SWentao.Yang@Sun.COM 18918160SWentao.Yang@Sun.COM ASSERT(vnetp != NULL); 18928160SWentao.Yang@Sun.COM size = sizeof (vnet_hio_kstats_t) / sizeof (kstat_named_t); 18938160SWentao.Yang@Sun.COM ksp = kstat_create(ks_mod, vnetp->instance, ks_name, "net", 18948160SWentao.Yang@Sun.COM KSTAT_TYPE_NAMED, size, 0); 18958160SWentao.Yang@Sun.COM if (ksp == NULL) { 18968160SWentao.Yang@Sun.COM return (NULL); 18978160SWentao.Yang@Sun.COM } 18988160SWentao.Yang@Sun.COM 18998160SWentao.Yang@Sun.COM hiokp = (vnet_hio_kstats_t *)ksp->ks_data; 19008160SWentao.Yang@Sun.COM kstat_named_init(&hiokp->ipackets, "ipackets", 19018160SWentao.Yang@Sun.COM KSTAT_DATA_ULONG); 19028160SWentao.Yang@Sun.COM kstat_named_init(&hiokp->ierrors, "ierrors", 19038160SWentao.Yang@Sun.COM KSTAT_DATA_ULONG); 19048160SWentao.Yang@Sun.COM kstat_named_init(&hiokp->opackets, "opackets", 19058160SWentao.Yang@Sun.COM KSTAT_DATA_ULONG); 19068160SWentao.Yang@Sun.COM kstat_named_init(&hiokp->oerrors, "oerrors", 19078160SWentao.Yang@Sun.COM KSTAT_DATA_ULONG); 19088160SWentao.Yang@Sun.COM 19098160SWentao.Yang@Sun.COM 19108160SWentao.Yang@Sun.COM /* MIB II kstat variables */ 19118160SWentao.Yang@Sun.COM kstat_named_init(&hiokp->rbytes, "rbytes", 19128160SWentao.Yang@Sun.COM KSTAT_DATA_ULONG); 19138160SWentao.Yang@Sun.COM kstat_named_init(&hiokp->obytes, "obytes", 19148160SWentao.Yang@Sun.COM KSTAT_DATA_ULONG); 19158160SWentao.Yang@Sun.COM kstat_named_init(&hiokp->multircv, "multircv", 19168160SWentao.Yang@Sun.COM KSTAT_DATA_ULONG); 19178160SWentao.Yang@Sun.COM kstat_named_init(&hiokp->multixmt, "multixmt", 19188160SWentao.Yang@Sun.COM KSTAT_DATA_ULONG); 19198160SWentao.Yang@Sun.COM kstat_named_init(&hiokp->brdcstrcv, "brdcstrcv", 19208160SWentao.Yang@Sun.COM KSTAT_DATA_ULONG); 19218160SWentao.Yang@Sun.COM kstat_named_init(&hiokp->brdcstxmt, "brdcstxmt", 19228160SWentao.Yang@Sun.COM KSTAT_DATA_ULONG); 19238160SWentao.Yang@Sun.COM kstat_named_init(&hiokp->norcvbuf, "norcvbuf", 19248160SWentao.Yang@Sun.COM KSTAT_DATA_ULONG); 19258160SWentao.Yang@Sun.COM kstat_named_init(&hiokp->noxmtbuf, "noxmtbuf", 19268160SWentao.Yang@Sun.COM KSTAT_DATA_ULONG); 19278160SWentao.Yang@Sun.COM 19288160SWentao.Yang@Sun.COM ksp->ks_update = vnet_hio_update_kstats; 19298160SWentao.Yang@Sun.COM ksp->ks_private = (void *)vresp; 19308160SWentao.Yang@Sun.COM kstat_install(ksp); 19318160SWentao.Yang@Sun.COM return (ksp); 19328160SWentao.Yang@Sun.COM } 19338160SWentao.Yang@Sun.COM 19348160SWentao.Yang@Sun.COM /* 19358160SWentao.Yang@Sun.COM * Destroy kstats. 19368160SWentao.Yang@Sun.COM */ 19378160SWentao.Yang@Sun.COM static void 19388160SWentao.Yang@Sun.COM vnet_hio_destroy_kstats(kstat_t *ksp) 19398160SWentao.Yang@Sun.COM { 19408160SWentao.Yang@Sun.COM if (ksp != NULL) 19418160SWentao.Yang@Sun.COM kstat_delete(ksp); 19428160SWentao.Yang@Sun.COM } 19438160SWentao.Yang@Sun.COM 19448160SWentao.Yang@Sun.COM /* 19458160SWentao.Yang@Sun.COM * Update the kstats. 19468160SWentao.Yang@Sun.COM */ 19478160SWentao.Yang@Sun.COM static int 19488160SWentao.Yang@Sun.COM vnet_hio_update_kstats(kstat_t *ksp, int rw) 19498160SWentao.Yang@Sun.COM { 19508160SWentao.Yang@Sun.COM vnet_t *vnetp; 19518160SWentao.Yang@Sun.COM vnet_res_t *vresp; 19528160SWentao.Yang@Sun.COM vnet_hio_stats_t statsp; 19538160SWentao.Yang@Sun.COM vnet_hio_kstats_t *hiokp; 19548160SWentao.Yang@Sun.COM 19558160SWentao.Yang@Sun.COM vresp = (vnet_res_t *)ksp->ks_private; 19568160SWentao.Yang@Sun.COM vnetp = vresp->vnetp; 19578160SWentao.Yang@Sun.COM 19588160SWentao.Yang@Sun.COM bzero(&statsp, sizeof (vnet_hio_stats_t)); 19598160SWentao.Yang@Sun.COM 19608160SWentao.Yang@Sun.COM READ_ENTER(&vnetp->vsw_fp_rw); 19618160SWentao.Yang@Sun.COM if (vnetp->hio_fp == NULL) { 19628160SWentao.Yang@Sun.COM /* not using hio resources, just return */ 19638160SWentao.Yang@Sun.COM RW_EXIT(&vnetp->vsw_fp_rw); 19648160SWentao.Yang@Sun.COM return (0); 19658160SWentao.Yang@Sun.COM } 19668160SWentao.Yang@Sun.COM VNET_FDBE_REFHOLD(vnetp->hio_fp); 19678160SWentao.Yang@Sun.COM RW_EXIT(&vnetp->vsw_fp_rw); 19688160SWentao.Yang@Sun.COM vnet_hio_get_stats(vnetp->hio_fp, &statsp); 19698160SWentao.Yang@Sun.COM VNET_FDBE_REFRELE(vnetp->hio_fp); 19708160SWentao.Yang@Sun.COM 19718160SWentao.Yang@Sun.COM hiokp = (vnet_hio_kstats_t *)ksp->ks_data; 19728160SWentao.Yang@Sun.COM 19738160SWentao.Yang@Sun.COM if (rw == KSTAT_READ) { 19748160SWentao.Yang@Sun.COM /* Link Input/Output stats */ 19758160SWentao.Yang@Sun.COM hiokp->ipackets.value.ul = (uint32_t)statsp.ipackets; 19768160SWentao.Yang@Sun.COM hiokp->ipackets64.value.ull = statsp.ipackets; 19778160SWentao.Yang@Sun.COM hiokp->ierrors.value.ul = statsp.ierrors; 19788160SWentao.Yang@Sun.COM hiokp->opackets.value.ul = (uint32_t)statsp.opackets; 19798160SWentao.Yang@Sun.COM hiokp->opackets64.value.ull = statsp.opackets; 19808160SWentao.Yang@Sun.COM hiokp->oerrors.value.ul = statsp.oerrors; 19818160SWentao.Yang@Sun.COM 19828160SWentao.Yang@Sun.COM /* MIB II kstat variables */ 19838160SWentao.Yang@Sun.COM hiokp->rbytes.value.ul = (uint32_t)statsp.rbytes; 19848160SWentao.Yang@Sun.COM hiokp->rbytes64.value.ull = statsp.rbytes; 19858160SWentao.Yang@Sun.COM hiokp->obytes.value.ul = (uint32_t)statsp.obytes; 19868160SWentao.Yang@Sun.COM hiokp->obytes64.value.ull = statsp.obytes; 19878160SWentao.Yang@Sun.COM hiokp->multircv.value.ul = statsp.multircv; 19888160SWentao.Yang@Sun.COM hiokp->multixmt.value.ul = statsp.multixmt; 19898160SWentao.Yang@Sun.COM hiokp->brdcstrcv.value.ul = statsp.brdcstrcv; 19908160SWentao.Yang@Sun.COM hiokp->brdcstxmt.value.ul = statsp.brdcstxmt; 19918160SWentao.Yang@Sun.COM hiokp->norcvbuf.value.ul = statsp.norcvbuf; 19928160SWentao.Yang@Sun.COM hiokp->noxmtbuf.value.ul = statsp.noxmtbuf; 19938160SWentao.Yang@Sun.COM } else { 19948160SWentao.Yang@Sun.COM return (EACCES); 19958160SWentao.Yang@Sun.COM } 19968160SWentao.Yang@Sun.COM 19978160SWentao.Yang@Sun.COM return (0); 19988160SWentao.Yang@Sun.COM } 19998160SWentao.Yang@Sun.COM 20008160SWentao.Yang@Sun.COM static void 20018160SWentao.Yang@Sun.COM vnet_hio_get_stats(vnet_res_t *vresp, vnet_hio_stats_t *statsp) 20028160SWentao.Yang@Sun.COM { 20038160SWentao.Yang@Sun.COM mac_register_t *macp; 20048160SWentao.Yang@Sun.COM mac_callbacks_t *cbp; 20058160SWentao.Yang@Sun.COM uint64_t val; 20068160SWentao.Yang@Sun.COM int stat; 20078160SWentao.Yang@Sun.COM 20088160SWentao.Yang@Sun.COM /* 20098160SWentao.Yang@Sun.COM * get the specified statistics from the underlying nxge. 20108160SWentao.Yang@Sun.COM */ 20118160SWentao.Yang@Sun.COM macp = &vresp->macreg; 20128160SWentao.Yang@Sun.COM cbp = macp->m_callbacks; 20138160SWentao.Yang@Sun.COM for (stat = MAC_STAT_MIN; stat < MAC_STAT_OVERFLOWS; stat++) { 20148160SWentao.Yang@Sun.COM if (cbp->mc_getstat(macp->m_driver, stat, &val) == 0) { 20158160SWentao.Yang@Sun.COM switch (stat) { 20168160SWentao.Yang@Sun.COM case MAC_STAT_IPACKETS: 20178160SWentao.Yang@Sun.COM statsp->ipackets = val; 20188160SWentao.Yang@Sun.COM break; 20198160SWentao.Yang@Sun.COM 20208160SWentao.Yang@Sun.COM case MAC_STAT_IERRORS: 20218160SWentao.Yang@Sun.COM statsp->ierrors = val; 20228160SWentao.Yang@Sun.COM break; 20238160SWentao.Yang@Sun.COM 20248160SWentao.Yang@Sun.COM case MAC_STAT_OPACKETS: 20258160SWentao.Yang@Sun.COM statsp->opackets = val; 20268160SWentao.Yang@Sun.COM break; 20278160SWentao.Yang@Sun.COM 20288160SWentao.Yang@Sun.COM case MAC_STAT_OERRORS: 20298160SWentao.Yang@Sun.COM statsp->oerrors = val; 20308160SWentao.Yang@Sun.COM break; 20318160SWentao.Yang@Sun.COM 20328160SWentao.Yang@Sun.COM case MAC_STAT_RBYTES: 20338160SWentao.Yang@Sun.COM statsp->rbytes = val; 20348160SWentao.Yang@Sun.COM break; 20358160SWentao.Yang@Sun.COM 20368160SWentao.Yang@Sun.COM case MAC_STAT_OBYTES: 20378160SWentao.Yang@Sun.COM statsp->obytes = val; 20388160SWentao.Yang@Sun.COM break; 20398160SWentao.Yang@Sun.COM 20408160SWentao.Yang@Sun.COM case MAC_STAT_MULTIRCV: 20418160SWentao.Yang@Sun.COM statsp->multircv = val; 20428160SWentao.Yang@Sun.COM break; 20438160SWentao.Yang@Sun.COM 20448160SWentao.Yang@Sun.COM case MAC_STAT_MULTIXMT: 20458160SWentao.Yang@Sun.COM statsp->multixmt = val; 20468160SWentao.Yang@Sun.COM break; 20478160SWentao.Yang@Sun.COM 20488160SWentao.Yang@Sun.COM case MAC_STAT_BRDCSTRCV: 20498160SWentao.Yang@Sun.COM statsp->brdcstrcv = val; 20508160SWentao.Yang@Sun.COM break; 20518160SWentao.Yang@Sun.COM 20528160SWentao.Yang@Sun.COM case MAC_STAT_BRDCSTXMT: 20538160SWentao.Yang@Sun.COM statsp->brdcstxmt = val; 20548160SWentao.Yang@Sun.COM break; 20558160SWentao.Yang@Sun.COM 20568160SWentao.Yang@Sun.COM case MAC_STAT_NOXMTBUF: 20578160SWentao.Yang@Sun.COM statsp->noxmtbuf = val; 20588160SWentao.Yang@Sun.COM break; 20598160SWentao.Yang@Sun.COM 20608160SWentao.Yang@Sun.COM case MAC_STAT_NORCVBUF: 20618160SWentao.Yang@Sun.COM statsp->norcvbuf = val; 20628160SWentao.Yang@Sun.COM break; 20638160SWentao.Yang@Sun.COM 20648160SWentao.Yang@Sun.COM default: 20658160SWentao.Yang@Sun.COM /* 20668160SWentao.Yang@Sun.COM * parameters not interested. 20678160SWentao.Yang@Sun.COM */ 20688160SWentao.Yang@Sun.COM break; 20698160SWentao.Yang@Sun.COM } 20708160SWentao.Yang@Sun.COM } 20718160SWentao.Yang@Sun.COM } 20728160SWentao.Yang@Sun.COM } 20739336SSriharsha.Basavapatna@Sun.COM 207410309SSriharsha.Basavapatna@Sun.COM static boolean_t 207510309SSriharsha.Basavapatna@Sun.COM vnet_m_capab(void *arg, mac_capab_t cap, void *cap_data) 207610309SSriharsha.Basavapatna@Sun.COM { 207710309SSriharsha.Basavapatna@Sun.COM vnet_t *vnetp = (vnet_t *)arg; 207810309SSriharsha.Basavapatna@Sun.COM 207910309SSriharsha.Basavapatna@Sun.COM if (vnetp == NULL) { 208010309SSriharsha.Basavapatna@Sun.COM return (0); 208110309SSriharsha.Basavapatna@Sun.COM } 208210309SSriharsha.Basavapatna@Sun.COM 208310309SSriharsha.Basavapatna@Sun.COM switch (cap) { 208410309SSriharsha.Basavapatna@Sun.COM 208510309SSriharsha.Basavapatna@Sun.COM case MAC_CAPAB_RINGS: { 208610309SSriharsha.Basavapatna@Sun.COM 208710309SSriharsha.Basavapatna@Sun.COM mac_capab_rings_t *cap_rings = cap_data; 208810309SSriharsha.Basavapatna@Sun.COM /* 208910309SSriharsha.Basavapatna@Sun.COM * Rings Capability Notes: 209010309SSriharsha.Basavapatna@Sun.COM * We advertise rings to make use of the rings framework in 209110309SSriharsha.Basavapatna@Sun.COM * gldv3 mac layer, to improve the performance. This is 209210309SSriharsha.Basavapatna@Sun.COM * specifically needed when a Hybrid resource (with multiple 209310309SSriharsha.Basavapatna@Sun.COM * tx/rx hardware rings) is assigned to a vnet device. We also 209410309SSriharsha.Basavapatna@Sun.COM * leverage this for the normal case when no Hybrid resource is 209510309SSriharsha.Basavapatna@Sun.COM * assigned. 209610309SSriharsha.Basavapatna@Sun.COM * 209710309SSriharsha.Basavapatna@Sun.COM * Ring Allocation: 209810309SSriharsha.Basavapatna@Sun.COM * - TX path: 209910309SSriharsha.Basavapatna@Sun.COM * We expose a pseudo ring group with 2 pseudo tx rings (as 210010309SSriharsha.Basavapatna@Sun.COM * currently HybridIO exports only 2 rings) In the normal case, 210110309SSriharsha.Basavapatna@Sun.COM * transmit traffic that comes down to the driver through the 210210309SSriharsha.Basavapatna@Sun.COM * mri_tx (vnet_tx_ring_send()) entry point goes through the 210310309SSriharsha.Basavapatna@Sun.COM * distributed switching algorithm in vnet and gets transmitted 210410309SSriharsha.Basavapatna@Sun.COM * over a port/LDC in the vgen layer to either the vswitch or a 210510309SSriharsha.Basavapatna@Sun.COM * peer vnet. If and when a Hybrid resource is assigned to the 210610309SSriharsha.Basavapatna@Sun.COM * vnet, we obtain the tx ring information of the Hybrid device 210710309SSriharsha.Basavapatna@Sun.COM * (nxge) and map the pseudo rings 1:1 to the 2 hw tx rings. 210810309SSriharsha.Basavapatna@Sun.COM * Traffic being sent over the Hybrid resource by the mac layer 210910309SSriharsha.Basavapatna@Sun.COM * gets spread across both hw rings, as they are mapped to the 211010309SSriharsha.Basavapatna@Sun.COM * 2 pseudo tx rings in vnet. 211110309SSriharsha.Basavapatna@Sun.COM * 211210309SSriharsha.Basavapatna@Sun.COM * - RX path: 211310309SSriharsha.Basavapatna@Sun.COM * We expose a pseudo ring group with 3 pseudo rx rings (static 211410309SSriharsha.Basavapatna@Sun.COM * rings) initially. The first (default) pseudo rx ring is 211510309SSriharsha.Basavapatna@Sun.COM * reserved for the resource that connects to the vswitch 211610309SSriharsha.Basavapatna@Sun.COM * service. The next 2 rings are reserved for a Hybrid resource 211710309SSriharsha.Basavapatna@Sun.COM * that may be assigned to the vnet device. If and when a 211810309SSriharsha.Basavapatna@Sun.COM * Hybrid resource is assigned to the vnet, we obtain the rx 211910309SSriharsha.Basavapatna@Sun.COM * ring information of the Hybrid device (nxge) and map these 212010309SSriharsha.Basavapatna@Sun.COM * pseudo rings 1:1 to the 2 hw rx rings. For each additional 212110309SSriharsha.Basavapatna@Sun.COM * resource that connects to a peer vnet, we dynamically 212210309SSriharsha.Basavapatna@Sun.COM * allocate a pseudo rx ring and map it to that resource, when 212310309SSriharsha.Basavapatna@Sun.COM * the resource gets added; and the pseudo rx ring is 212410309SSriharsha.Basavapatna@Sun.COM * dynamically registered with the upper mac layer. We do the 212510309SSriharsha.Basavapatna@Sun.COM * reverse and unregister the ring with the mac layer when 212610309SSriharsha.Basavapatna@Sun.COM * the resource gets removed. 212710309SSriharsha.Basavapatna@Sun.COM * 212810309SSriharsha.Basavapatna@Sun.COM * Synchronization notes: 212910309SSriharsha.Basavapatna@Sun.COM * We don't need any lock to protect members of ring structure, 213010309SSriharsha.Basavapatna@Sun.COM * specifically ringp->hw_rh, in either the TX or the RX ring, 213110309SSriharsha.Basavapatna@Sun.COM * as explained below. 213210309SSriharsha.Basavapatna@Sun.COM * - TX ring: 213310309SSriharsha.Basavapatna@Sun.COM * ring->hw_rh is initialized only when a Hybrid resource is 213410309SSriharsha.Basavapatna@Sun.COM * associated; and gets referenced only in vnet_hio_tx(). The 213510309SSriharsha.Basavapatna@Sun.COM * Hybrid resource itself is available in fdb only after tx 213610309SSriharsha.Basavapatna@Sun.COM * hwrings are found and mapped; i.e, in vio_net_resource_reg() 213710309SSriharsha.Basavapatna@Sun.COM * we call vnet_bind_rings() first and then call 213810309SSriharsha.Basavapatna@Sun.COM * vnet_start_resources() which adds an entry to fdb. For 213910309SSriharsha.Basavapatna@Sun.COM * traffic going over LDC resources, we don't reference 214010309SSriharsha.Basavapatna@Sun.COM * ring->hw_rh at all. 214110309SSriharsha.Basavapatna@Sun.COM * - RX ring: 214210309SSriharsha.Basavapatna@Sun.COM * For rings mapped to Hybrid resource ring->hw_rh is 214310309SSriharsha.Basavapatna@Sun.COM * initialized and only then do we add the rx callback for 214410309SSriharsha.Basavapatna@Sun.COM * the underlying Hybrid resource; we disable callbacks before 214510309SSriharsha.Basavapatna@Sun.COM * we unmap ring->hw_rh. For rings mapped to LDC resources, we 214610309SSriharsha.Basavapatna@Sun.COM * stop the rx callbacks (in vgen) before we remove ring->hw_rh 214710309SSriharsha.Basavapatna@Sun.COM * (vio_net_resource_unreg()). 214811878SVenu.Iyer@Sun.COM * Also, we access ring->hw_rh in vnet_rx_ring_stat(). 214911878SVenu.Iyer@Sun.COM * Note that for rings mapped to Hybrid resource, though the 215011878SVenu.Iyer@Sun.COM * rings are statically registered with the mac layer, its 215111878SVenu.Iyer@Sun.COM * hardware ring mapping (ringp->hw_rh) can be torn down in 215211878SVenu.Iyer@Sun.COM * vnet_unbind_hwrings() while the kstat operation is in 215311878SVenu.Iyer@Sun.COM * progress. To protect against this, we hold a reference to 215411878SVenu.Iyer@Sun.COM * the resource in FDB; this ensures that the thread in 215511878SVenu.Iyer@Sun.COM * vio_net_resource_unreg() waits for the reference to be 215611878SVenu.Iyer@Sun.COM * dropped before unbinding the ring. 215711878SVenu.Iyer@Sun.COM * 215811878SVenu.Iyer@Sun.COM * We don't need to do this for rings mapped to LDC resources. 215911878SVenu.Iyer@Sun.COM * These rings are registered/unregistered dynamically with 216011878SVenu.Iyer@Sun.COM * the mac layer and so any attempt to unregister the ring 216111878SVenu.Iyer@Sun.COM * while kstat operation is in progress will block in 216211878SVenu.Iyer@Sun.COM * mac_group_rem_ring(). Thus implicitly protects the 216311878SVenu.Iyer@Sun.COM * resource (ringp->hw_rh) from disappearing. 216410309SSriharsha.Basavapatna@Sun.COM */ 216510309SSriharsha.Basavapatna@Sun.COM 216610309SSriharsha.Basavapatna@Sun.COM if (cap_rings->mr_type == MAC_RING_TYPE_RX) { 216710309SSriharsha.Basavapatna@Sun.COM cap_rings->mr_group_type = MAC_GROUP_TYPE_STATIC; 216810309SSriharsha.Basavapatna@Sun.COM 216910309SSriharsha.Basavapatna@Sun.COM /* 217010309SSriharsha.Basavapatna@Sun.COM * The ring_cnt for rx grp is initialized in 217110309SSriharsha.Basavapatna@Sun.COM * vnet_ring_grp_init(). Later, the ring_cnt gets 217210309SSriharsha.Basavapatna@Sun.COM * updated dynamically whenever LDC resources are added 217310309SSriharsha.Basavapatna@Sun.COM * or removed. 217410309SSriharsha.Basavapatna@Sun.COM */ 217510309SSriharsha.Basavapatna@Sun.COM cap_rings->mr_rnum = vnetp->rx_grp[0].ring_cnt; 217610309SSriharsha.Basavapatna@Sun.COM cap_rings->mr_rget = vnet_get_ring; 217710309SSriharsha.Basavapatna@Sun.COM 217810309SSriharsha.Basavapatna@Sun.COM cap_rings->mr_gnum = VNET_NUM_PSEUDO_GROUPS; 217910309SSriharsha.Basavapatna@Sun.COM cap_rings->mr_gget = vnet_get_group; 218010309SSriharsha.Basavapatna@Sun.COM cap_rings->mr_gaddring = NULL; 218110309SSriharsha.Basavapatna@Sun.COM cap_rings->mr_gremring = NULL; 218210309SSriharsha.Basavapatna@Sun.COM } else { 218310309SSriharsha.Basavapatna@Sun.COM cap_rings->mr_group_type = MAC_GROUP_TYPE_STATIC; 218410309SSriharsha.Basavapatna@Sun.COM 218510309SSriharsha.Basavapatna@Sun.COM /* 218610309SSriharsha.Basavapatna@Sun.COM * The ring_cnt for tx grp is initialized in 218710309SSriharsha.Basavapatna@Sun.COM * vnet_ring_grp_init() and remains constant, as we 218810309SSriharsha.Basavapatna@Sun.COM * do not support dymanic tx rings for now. 218910309SSriharsha.Basavapatna@Sun.COM */ 219010309SSriharsha.Basavapatna@Sun.COM cap_rings->mr_rnum = vnetp->tx_grp[0].ring_cnt; 219110309SSriharsha.Basavapatna@Sun.COM cap_rings->mr_rget = vnet_get_ring; 219210309SSriharsha.Basavapatna@Sun.COM 219310309SSriharsha.Basavapatna@Sun.COM /* 219410309SSriharsha.Basavapatna@Sun.COM * Transmit rings are not grouped; i.e, the number of 219510309SSriharsha.Basavapatna@Sun.COM * transmit ring groups advertised should be set to 0. 219610309SSriharsha.Basavapatna@Sun.COM */ 219710309SSriharsha.Basavapatna@Sun.COM cap_rings->mr_gnum = 0; 219810309SSriharsha.Basavapatna@Sun.COM 219910309SSriharsha.Basavapatna@Sun.COM cap_rings->mr_gget = vnet_get_group; 220010309SSriharsha.Basavapatna@Sun.COM cap_rings->mr_gaddring = NULL; 220110309SSriharsha.Basavapatna@Sun.COM cap_rings->mr_gremring = NULL; 220210309SSriharsha.Basavapatna@Sun.COM } 220310309SSriharsha.Basavapatna@Sun.COM return (B_TRUE); 220410309SSriharsha.Basavapatna@Sun.COM 220510309SSriharsha.Basavapatna@Sun.COM } 220610309SSriharsha.Basavapatna@Sun.COM 220710309SSriharsha.Basavapatna@Sun.COM default: 220810309SSriharsha.Basavapatna@Sun.COM break; 220910309SSriharsha.Basavapatna@Sun.COM 221010309SSriharsha.Basavapatna@Sun.COM } 221110309SSriharsha.Basavapatna@Sun.COM 221210309SSriharsha.Basavapatna@Sun.COM return (B_FALSE); 221310309SSriharsha.Basavapatna@Sun.COM } 221410309SSriharsha.Basavapatna@Sun.COM 221510309SSriharsha.Basavapatna@Sun.COM /* 221610309SSriharsha.Basavapatna@Sun.COM * Callback funtion for MAC layer to get ring information. 221710309SSriharsha.Basavapatna@Sun.COM */ 221810309SSriharsha.Basavapatna@Sun.COM static void 221910309SSriharsha.Basavapatna@Sun.COM vnet_get_ring(void *arg, mac_ring_type_t rtype, const int g_index, 222010309SSriharsha.Basavapatna@Sun.COM const int r_index, mac_ring_info_t *infop, mac_ring_handle_t r_handle) 222110309SSriharsha.Basavapatna@Sun.COM { 222210309SSriharsha.Basavapatna@Sun.COM vnet_t *vnetp = arg; 222310309SSriharsha.Basavapatna@Sun.COM 222410309SSriharsha.Basavapatna@Sun.COM switch (rtype) { 222510309SSriharsha.Basavapatna@Sun.COM 222610309SSriharsha.Basavapatna@Sun.COM case MAC_RING_TYPE_RX: { 222710309SSriharsha.Basavapatna@Sun.COM 222810309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_rx_group_t *rx_grp; 222910309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_rx_ring_t *rx_ringp; 223010309SSriharsha.Basavapatna@Sun.COM mac_intr_t *mintr; 223110309SSriharsha.Basavapatna@Sun.COM 223210309SSriharsha.Basavapatna@Sun.COM /* We advertised only one RX group */ 223310309SSriharsha.Basavapatna@Sun.COM ASSERT(g_index == 0); 223410309SSriharsha.Basavapatna@Sun.COM rx_grp = &vnetp->rx_grp[g_index]; 223510309SSriharsha.Basavapatna@Sun.COM 223610309SSriharsha.Basavapatna@Sun.COM /* Check the current # of rings in the rx group */ 223710309SSriharsha.Basavapatna@Sun.COM ASSERT((r_index >= 0) && (r_index < rx_grp->max_ring_cnt)); 223810309SSriharsha.Basavapatna@Sun.COM 223910309SSriharsha.Basavapatna@Sun.COM /* Get the ring based on the index */ 224010309SSriharsha.Basavapatna@Sun.COM rx_ringp = &rx_grp->rings[r_index]; 224110309SSriharsha.Basavapatna@Sun.COM 224210309SSriharsha.Basavapatna@Sun.COM rx_ringp->handle = r_handle; 224310309SSriharsha.Basavapatna@Sun.COM /* 224410309SSriharsha.Basavapatna@Sun.COM * Note: we don't need to save the incoming r_index in rx_ring, 224510309SSriharsha.Basavapatna@Sun.COM * as vnet_ring_grp_init() would have initialized the index for 224610309SSriharsha.Basavapatna@Sun.COM * each ring in the array. 224710309SSriharsha.Basavapatna@Sun.COM */ 224810309SSriharsha.Basavapatna@Sun.COM rx_ringp->grp = rx_grp; 224910309SSriharsha.Basavapatna@Sun.COM rx_ringp->vnetp = vnetp; 225010309SSriharsha.Basavapatna@Sun.COM 225110309SSriharsha.Basavapatna@Sun.COM mintr = &infop->mri_intr; 225210309SSriharsha.Basavapatna@Sun.COM mintr->mi_handle = (mac_intr_handle_t)rx_ringp; 225310309SSriharsha.Basavapatna@Sun.COM mintr->mi_enable = (mac_intr_enable_t)vnet_ring_enable_intr; 225410309SSriharsha.Basavapatna@Sun.COM mintr->mi_disable = (mac_intr_disable_t)vnet_ring_disable_intr; 225510309SSriharsha.Basavapatna@Sun.COM 225610309SSriharsha.Basavapatna@Sun.COM infop->mri_driver = (mac_ring_driver_t)rx_ringp; 225710309SSriharsha.Basavapatna@Sun.COM infop->mri_start = vnet_rx_ring_start; 225810309SSriharsha.Basavapatna@Sun.COM infop->mri_stop = vnet_rx_ring_stop; 225911878SVenu.Iyer@Sun.COM infop->mri_stat = vnet_rx_ring_stat; 226010309SSriharsha.Basavapatna@Sun.COM 226110309SSriharsha.Basavapatna@Sun.COM /* Set the poll function, as this is an rx ring */ 226210309SSriharsha.Basavapatna@Sun.COM infop->mri_poll = vnet_rx_poll; 226311878SVenu.Iyer@Sun.COM /* 226411878SVenu.Iyer@Sun.COM * MAC_RING_RX_ENQUEUE bit needed to be set for nxge 226511878SVenu.Iyer@Sun.COM * which was not sending packet chains in interrupt 226611878SVenu.Iyer@Sun.COM * context. For such drivers, packets are queued in 226711878SVenu.Iyer@Sun.COM * Rx soft rings so that we get a chance to switch 226811878SVenu.Iyer@Sun.COM * into a polling mode under backlog. This bug (not 226911878SVenu.Iyer@Sun.COM * sending packet chains) has now been fixed. Once 227011878SVenu.Iyer@Sun.COM * the performance impact is measured, this change 227111878SVenu.Iyer@Sun.COM * will be removed. 227211878SVenu.Iyer@Sun.COM */ 227311878SVenu.Iyer@Sun.COM infop->mri_flags = (vnet_mac_rx_queuing ? 227411878SVenu.Iyer@Sun.COM MAC_RING_RX_ENQUEUE : 0); 227510309SSriharsha.Basavapatna@Sun.COM break; 227610309SSriharsha.Basavapatna@Sun.COM } 227710309SSriharsha.Basavapatna@Sun.COM 227810309SSriharsha.Basavapatna@Sun.COM case MAC_RING_TYPE_TX: { 227910309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_tx_group_t *tx_grp; 228010309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_tx_ring_t *tx_ringp; 228110309SSriharsha.Basavapatna@Sun.COM 228210309SSriharsha.Basavapatna@Sun.COM /* 228310309SSriharsha.Basavapatna@Sun.COM * No need to check grp index; mac layer passes -1 for it. 228410309SSriharsha.Basavapatna@Sun.COM */ 228510309SSriharsha.Basavapatna@Sun.COM tx_grp = &vnetp->tx_grp[0]; 228610309SSriharsha.Basavapatna@Sun.COM 228710309SSriharsha.Basavapatna@Sun.COM /* Check the # of rings in the tx group */ 228810309SSriharsha.Basavapatna@Sun.COM ASSERT((r_index >= 0) && (r_index < tx_grp->ring_cnt)); 228910309SSriharsha.Basavapatna@Sun.COM 229010309SSriharsha.Basavapatna@Sun.COM /* Get the ring based on the index */ 229110309SSriharsha.Basavapatna@Sun.COM tx_ringp = &tx_grp->rings[r_index]; 229210309SSriharsha.Basavapatna@Sun.COM 229310309SSriharsha.Basavapatna@Sun.COM tx_ringp->handle = r_handle; 229410309SSriharsha.Basavapatna@Sun.COM tx_ringp->index = r_index; 229510309SSriharsha.Basavapatna@Sun.COM tx_ringp->grp = tx_grp; 229610309SSriharsha.Basavapatna@Sun.COM tx_ringp->vnetp = vnetp; 229710309SSriharsha.Basavapatna@Sun.COM 229810309SSriharsha.Basavapatna@Sun.COM infop->mri_driver = (mac_ring_driver_t)tx_ringp; 229910309SSriharsha.Basavapatna@Sun.COM infop->mri_start = vnet_tx_ring_start; 230010309SSriharsha.Basavapatna@Sun.COM infop->mri_stop = vnet_tx_ring_stop; 230111878SVenu.Iyer@Sun.COM infop->mri_stat = vnet_tx_ring_stat; 230210309SSriharsha.Basavapatna@Sun.COM 230310309SSriharsha.Basavapatna@Sun.COM /* Set the transmit function, as this is a tx ring */ 230410309SSriharsha.Basavapatna@Sun.COM infop->mri_tx = vnet_tx_ring_send; 230511878SVenu.Iyer@Sun.COM /* 230611878SVenu.Iyer@Sun.COM * MAC_RING_TX_SERIALIZE bit needs to be set while 230711878SVenu.Iyer@Sun.COM * hybridIO is enabled to workaround tx lock 230811878SVenu.Iyer@Sun.COM * contention issues in nxge. 230911878SVenu.Iyer@Sun.COM */ 231011878SVenu.Iyer@Sun.COM infop->mri_flags = (vnet_mac_tx_serialize ? 231111878SVenu.Iyer@Sun.COM MAC_RING_TX_SERIALIZE : 0); 231210309SSriharsha.Basavapatna@Sun.COM break; 231310309SSriharsha.Basavapatna@Sun.COM } 231410309SSriharsha.Basavapatna@Sun.COM 231510309SSriharsha.Basavapatna@Sun.COM default: 231610309SSriharsha.Basavapatna@Sun.COM break; 231710309SSriharsha.Basavapatna@Sun.COM } 231810309SSriharsha.Basavapatna@Sun.COM } 231910309SSriharsha.Basavapatna@Sun.COM 232010309SSriharsha.Basavapatna@Sun.COM /* 232110309SSriharsha.Basavapatna@Sun.COM * Callback funtion for MAC layer to get group information. 232210309SSriharsha.Basavapatna@Sun.COM */ 232310309SSriharsha.Basavapatna@Sun.COM static void 232410309SSriharsha.Basavapatna@Sun.COM vnet_get_group(void *arg, mac_ring_type_t type, const int index, 232510309SSriharsha.Basavapatna@Sun.COM mac_group_info_t *infop, mac_group_handle_t handle) 232610309SSriharsha.Basavapatna@Sun.COM { 232710309SSriharsha.Basavapatna@Sun.COM vnet_t *vnetp = (vnet_t *)arg; 232810309SSriharsha.Basavapatna@Sun.COM 232910309SSriharsha.Basavapatna@Sun.COM switch (type) { 233010309SSriharsha.Basavapatna@Sun.COM 233110309SSriharsha.Basavapatna@Sun.COM case MAC_RING_TYPE_RX: 233210309SSriharsha.Basavapatna@Sun.COM { 233310309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_rx_group_t *rx_grp; 233410309SSriharsha.Basavapatna@Sun.COM 233510309SSriharsha.Basavapatna@Sun.COM /* We advertised only one RX group */ 233610309SSriharsha.Basavapatna@Sun.COM ASSERT(index == 0); 233710309SSriharsha.Basavapatna@Sun.COM 233810309SSriharsha.Basavapatna@Sun.COM rx_grp = &vnetp->rx_grp[index]; 233910309SSriharsha.Basavapatna@Sun.COM rx_grp->handle = handle; 234010309SSriharsha.Basavapatna@Sun.COM rx_grp->index = index; 234110309SSriharsha.Basavapatna@Sun.COM rx_grp->vnetp = vnetp; 234210309SSriharsha.Basavapatna@Sun.COM 234310309SSriharsha.Basavapatna@Sun.COM infop->mgi_driver = (mac_group_driver_t)rx_grp; 234410309SSriharsha.Basavapatna@Sun.COM infop->mgi_start = NULL; 234510309SSriharsha.Basavapatna@Sun.COM infop->mgi_stop = NULL; 234610309SSriharsha.Basavapatna@Sun.COM infop->mgi_addmac = vnet_addmac; 234710309SSriharsha.Basavapatna@Sun.COM infop->mgi_remmac = vnet_remmac; 234810309SSriharsha.Basavapatna@Sun.COM infop->mgi_count = rx_grp->ring_cnt; 234910309SSriharsha.Basavapatna@Sun.COM 235010309SSriharsha.Basavapatna@Sun.COM break; 235110309SSriharsha.Basavapatna@Sun.COM } 235210309SSriharsha.Basavapatna@Sun.COM 235310309SSriharsha.Basavapatna@Sun.COM case MAC_RING_TYPE_TX: 235410309SSriharsha.Basavapatna@Sun.COM { 235510309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_tx_group_t *tx_grp; 235610309SSriharsha.Basavapatna@Sun.COM 235710309SSriharsha.Basavapatna@Sun.COM /* We advertised only one TX group */ 235810309SSriharsha.Basavapatna@Sun.COM ASSERT(index == 0); 235910309SSriharsha.Basavapatna@Sun.COM 236010309SSriharsha.Basavapatna@Sun.COM tx_grp = &vnetp->tx_grp[index]; 236110309SSriharsha.Basavapatna@Sun.COM tx_grp->handle = handle; 236210309SSriharsha.Basavapatna@Sun.COM tx_grp->index = index; 236310309SSriharsha.Basavapatna@Sun.COM tx_grp->vnetp = vnetp; 236410309SSriharsha.Basavapatna@Sun.COM 236510309SSriharsha.Basavapatna@Sun.COM infop->mgi_driver = (mac_group_driver_t)tx_grp; 236610309SSriharsha.Basavapatna@Sun.COM infop->mgi_start = NULL; 236710309SSriharsha.Basavapatna@Sun.COM infop->mgi_stop = NULL; 236810309SSriharsha.Basavapatna@Sun.COM infop->mgi_addmac = NULL; 236910309SSriharsha.Basavapatna@Sun.COM infop->mgi_remmac = NULL; 237010309SSriharsha.Basavapatna@Sun.COM infop->mgi_count = VNET_NUM_PSEUDO_TXRINGS; 237110309SSriharsha.Basavapatna@Sun.COM 237210309SSriharsha.Basavapatna@Sun.COM break; 237310309SSriharsha.Basavapatna@Sun.COM } 237410309SSriharsha.Basavapatna@Sun.COM 237510309SSriharsha.Basavapatna@Sun.COM default: 237610309SSriharsha.Basavapatna@Sun.COM break; 237710309SSriharsha.Basavapatna@Sun.COM 237810309SSriharsha.Basavapatna@Sun.COM } 237910309SSriharsha.Basavapatna@Sun.COM } 238010309SSriharsha.Basavapatna@Sun.COM 238110309SSriharsha.Basavapatna@Sun.COM static int 238210309SSriharsha.Basavapatna@Sun.COM vnet_rx_ring_start(mac_ring_driver_t arg, uint64_t mr_gen_num) 238310309SSriharsha.Basavapatna@Sun.COM { 238410309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_rx_ring_t *rx_ringp = (vnet_pseudo_rx_ring_t *)arg; 238510309SSriharsha.Basavapatna@Sun.COM int err; 238610309SSriharsha.Basavapatna@Sun.COM 238710309SSriharsha.Basavapatna@Sun.COM /* 238810309SSriharsha.Basavapatna@Sun.COM * If this ring is mapped to a LDC resource, simply mark the state to 238910309SSriharsha.Basavapatna@Sun.COM * indicate the ring is started and return. 239010309SSriharsha.Basavapatna@Sun.COM */ 239110309SSriharsha.Basavapatna@Sun.COM if ((rx_ringp->state & 239210309SSriharsha.Basavapatna@Sun.COM (VNET_RXRING_LDC_SERVICE|VNET_RXRING_LDC_GUEST)) != 0) { 239310309SSriharsha.Basavapatna@Sun.COM rx_ringp->gen_num = mr_gen_num; 239410309SSriharsha.Basavapatna@Sun.COM rx_ringp->state |= VNET_RXRING_STARTED; 239510309SSriharsha.Basavapatna@Sun.COM return (0); 239610309SSriharsha.Basavapatna@Sun.COM } 239710309SSriharsha.Basavapatna@Sun.COM 239810309SSriharsha.Basavapatna@Sun.COM ASSERT((rx_ringp->state & VNET_RXRING_HYBRID) != 0); 239910309SSriharsha.Basavapatna@Sun.COM 240010309SSriharsha.Basavapatna@Sun.COM /* 240110309SSriharsha.Basavapatna@Sun.COM * This must be a ring reserved for a hwring. If the hwring is not 240210309SSriharsha.Basavapatna@Sun.COM * bound yet, simply mark the state to indicate the ring is started and 240310309SSriharsha.Basavapatna@Sun.COM * return. If and when a hybrid resource is activated for this vnet 240410309SSriharsha.Basavapatna@Sun.COM * device, we will bind the hwring and start it then. If a hwring is 240510309SSriharsha.Basavapatna@Sun.COM * already bound, start it now. 240610309SSriharsha.Basavapatna@Sun.COM */ 240710309SSriharsha.Basavapatna@Sun.COM if (rx_ringp->hw_rh == NULL) { 240810309SSriharsha.Basavapatna@Sun.COM rx_ringp->gen_num = mr_gen_num; 240910309SSriharsha.Basavapatna@Sun.COM rx_ringp->state |= VNET_RXRING_STARTED; 241010309SSriharsha.Basavapatna@Sun.COM return (0); 241110309SSriharsha.Basavapatna@Sun.COM } 241210309SSriharsha.Basavapatna@Sun.COM 241310309SSriharsha.Basavapatna@Sun.COM err = mac_hwring_start(rx_ringp->hw_rh); 241410309SSriharsha.Basavapatna@Sun.COM if (err == 0) { 241510309SSriharsha.Basavapatna@Sun.COM rx_ringp->gen_num = mr_gen_num; 241610309SSriharsha.Basavapatna@Sun.COM rx_ringp->state |= VNET_RXRING_STARTED; 241710309SSriharsha.Basavapatna@Sun.COM } else { 241810309SSriharsha.Basavapatna@Sun.COM err = ENXIO; 241910309SSriharsha.Basavapatna@Sun.COM } 242010309SSriharsha.Basavapatna@Sun.COM 242110309SSriharsha.Basavapatna@Sun.COM return (err); 242210309SSriharsha.Basavapatna@Sun.COM } 242310309SSriharsha.Basavapatna@Sun.COM 242410309SSriharsha.Basavapatna@Sun.COM static void 242510309SSriharsha.Basavapatna@Sun.COM vnet_rx_ring_stop(mac_ring_driver_t arg) 242610309SSriharsha.Basavapatna@Sun.COM { 242710309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_rx_ring_t *rx_ringp = (vnet_pseudo_rx_ring_t *)arg; 242810309SSriharsha.Basavapatna@Sun.COM 242910309SSriharsha.Basavapatna@Sun.COM /* 243010309SSriharsha.Basavapatna@Sun.COM * If this ring is mapped to a LDC resource, simply mark the state to 243110309SSriharsha.Basavapatna@Sun.COM * indicate the ring is now stopped and return. 243210309SSriharsha.Basavapatna@Sun.COM */ 243310309SSriharsha.Basavapatna@Sun.COM if ((rx_ringp->state & 243410309SSriharsha.Basavapatna@Sun.COM (VNET_RXRING_LDC_SERVICE|VNET_RXRING_LDC_GUEST)) != 0) { 243510309SSriharsha.Basavapatna@Sun.COM rx_ringp->state &= ~VNET_RXRING_STARTED; 243610439SWentao.Yang@Sun.COM return; 243710309SSriharsha.Basavapatna@Sun.COM } 243810309SSriharsha.Basavapatna@Sun.COM 243910309SSriharsha.Basavapatna@Sun.COM ASSERT((rx_ringp->state & VNET_RXRING_HYBRID) != 0); 244010309SSriharsha.Basavapatna@Sun.COM 244110309SSriharsha.Basavapatna@Sun.COM /* 244210309SSriharsha.Basavapatna@Sun.COM * This must be a ring reserved for a hwring. If the hwring is not 244310309SSriharsha.Basavapatna@Sun.COM * bound yet, simply mark the state to indicate the ring is stopped and 244410309SSriharsha.Basavapatna@Sun.COM * return. If a hwring is already bound, stop it now. 244510309SSriharsha.Basavapatna@Sun.COM */ 244610309SSriharsha.Basavapatna@Sun.COM if (rx_ringp->hw_rh == NULL) { 244710309SSriharsha.Basavapatna@Sun.COM rx_ringp->state &= ~VNET_RXRING_STARTED; 244810309SSriharsha.Basavapatna@Sun.COM return; 244910309SSriharsha.Basavapatna@Sun.COM } 245010309SSriharsha.Basavapatna@Sun.COM 245110309SSriharsha.Basavapatna@Sun.COM mac_hwring_stop(rx_ringp->hw_rh); 245210309SSriharsha.Basavapatna@Sun.COM rx_ringp->state &= ~VNET_RXRING_STARTED; 245310309SSriharsha.Basavapatna@Sun.COM } 245410309SSriharsha.Basavapatna@Sun.COM 245511878SVenu.Iyer@Sun.COM static int 245611878SVenu.Iyer@Sun.COM vnet_rx_ring_stat(mac_ring_driver_t rdriver, uint_t stat, uint64_t *val) 245711878SVenu.Iyer@Sun.COM { 245811878SVenu.Iyer@Sun.COM vnet_pseudo_rx_ring_t *rx_ringp = (vnet_pseudo_rx_ring_t *)rdriver; 245911878SVenu.Iyer@Sun.COM vnet_t *vnetp = (vnet_t *)rx_ringp->vnetp; 246011878SVenu.Iyer@Sun.COM vnet_res_t *vresp; 246111878SVenu.Iyer@Sun.COM mac_register_t *macp; 246211878SVenu.Iyer@Sun.COM mac_callbacks_t *cbp; 246311878SVenu.Iyer@Sun.COM 246411878SVenu.Iyer@Sun.COM /* 246511878SVenu.Iyer@Sun.COM * Refer to vnet_m_capab() function for detailed comments on ring 246611878SVenu.Iyer@Sun.COM * synchronization. 246711878SVenu.Iyer@Sun.COM */ 246811878SVenu.Iyer@Sun.COM if ((rx_ringp->state & VNET_RXRING_HYBRID) != 0) { 246911878SVenu.Iyer@Sun.COM READ_ENTER(&vnetp->vsw_fp_rw); 247011878SVenu.Iyer@Sun.COM if (vnetp->hio_fp == NULL) { 247111878SVenu.Iyer@Sun.COM RW_EXIT(&vnetp->vsw_fp_rw); 247211878SVenu.Iyer@Sun.COM return (0); 247311878SVenu.Iyer@Sun.COM } 247411878SVenu.Iyer@Sun.COM 247511878SVenu.Iyer@Sun.COM VNET_FDBE_REFHOLD(vnetp->hio_fp); 247611878SVenu.Iyer@Sun.COM RW_EXIT(&vnetp->vsw_fp_rw); 2477*11881SVenu.Iyer@Sun.COM (void) mac_hwring_getstat(rx_ringp->hw_rh, stat, val); 247811878SVenu.Iyer@Sun.COM VNET_FDBE_REFRELE(vnetp->hio_fp); 247911878SVenu.Iyer@Sun.COM return (0); 248011878SVenu.Iyer@Sun.COM } 248111878SVenu.Iyer@Sun.COM 248211878SVenu.Iyer@Sun.COM ASSERT((rx_ringp->state & 248311878SVenu.Iyer@Sun.COM (VNET_RXRING_LDC_SERVICE|VNET_RXRING_LDC_GUEST)) != 0); 248411878SVenu.Iyer@Sun.COM vresp = (vnet_res_t *)rx_ringp->hw_rh; 248511878SVenu.Iyer@Sun.COM macp = &vresp->macreg; 248611878SVenu.Iyer@Sun.COM cbp = macp->m_callbacks; 248711878SVenu.Iyer@Sun.COM 248811878SVenu.Iyer@Sun.COM cbp->mc_getstat(macp->m_driver, stat, val); 248911878SVenu.Iyer@Sun.COM 249011878SVenu.Iyer@Sun.COM return (0); 249111878SVenu.Iyer@Sun.COM } 249211878SVenu.Iyer@Sun.COM 249310309SSriharsha.Basavapatna@Sun.COM /* ARGSUSED */ 249410309SSriharsha.Basavapatna@Sun.COM static int 249510309SSriharsha.Basavapatna@Sun.COM vnet_tx_ring_start(mac_ring_driver_t arg, uint64_t mr_gen_num) 249610309SSriharsha.Basavapatna@Sun.COM { 249710309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_tx_ring_t *tx_ringp = (vnet_pseudo_tx_ring_t *)arg; 249810309SSriharsha.Basavapatna@Sun.COM 249910309SSriharsha.Basavapatna@Sun.COM tx_ringp->state |= VNET_TXRING_STARTED; 250010309SSriharsha.Basavapatna@Sun.COM return (0); 250110309SSriharsha.Basavapatna@Sun.COM } 250210309SSriharsha.Basavapatna@Sun.COM 250310309SSriharsha.Basavapatna@Sun.COM static void 250410309SSriharsha.Basavapatna@Sun.COM vnet_tx_ring_stop(mac_ring_driver_t arg) 250510309SSriharsha.Basavapatna@Sun.COM { 250610309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_tx_ring_t *tx_ringp = (vnet_pseudo_tx_ring_t *)arg; 250710309SSriharsha.Basavapatna@Sun.COM 250810309SSriharsha.Basavapatna@Sun.COM tx_ringp->state &= ~VNET_TXRING_STARTED; 250910309SSriharsha.Basavapatna@Sun.COM } 251010309SSriharsha.Basavapatna@Sun.COM 251111878SVenu.Iyer@Sun.COM static int 251211878SVenu.Iyer@Sun.COM vnet_tx_ring_stat(mac_ring_driver_t rdriver, uint_t stat, uint64_t *val) 251311878SVenu.Iyer@Sun.COM { 251411878SVenu.Iyer@Sun.COM vnet_pseudo_tx_ring_t *tx_ringp = (vnet_pseudo_tx_ring_t *)rdriver; 251511878SVenu.Iyer@Sun.COM vnet_tx_ring_stats_t *statsp; 251611878SVenu.Iyer@Sun.COM 251711878SVenu.Iyer@Sun.COM statsp = &tx_ringp->tx_ring_stats; 251811878SVenu.Iyer@Sun.COM 251911878SVenu.Iyer@Sun.COM switch (stat) { 252011878SVenu.Iyer@Sun.COM case MAC_STAT_OPACKETS: 252111878SVenu.Iyer@Sun.COM *val = statsp->opackets; 252211878SVenu.Iyer@Sun.COM break; 252311878SVenu.Iyer@Sun.COM 252411878SVenu.Iyer@Sun.COM case MAC_STAT_OBYTES: 252511878SVenu.Iyer@Sun.COM *val = statsp->obytes; 252611878SVenu.Iyer@Sun.COM break; 252711878SVenu.Iyer@Sun.COM 252811878SVenu.Iyer@Sun.COM default: 252911878SVenu.Iyer@Sun.COM *val = 0; 253011878SVenu.Iyer@Sun.COM return (ENOTSUP); 253111878SVenu.Iyer@Sun.COM } 253211878SVenu.Iyer@Sun.COM 253311878SVenu.Iyer@Sun.COM return (0); 253411878SVenu.Iyer@Sun.COM } 253511878SVenu.Iyer@Sun.COM 253610309SSriharsha.Basavapatna@Sun.COM /* 253710309SSriharsha.Basavapatna@Sun.COM * Disable polling for a ring and enable its interrupt. 253810309SSriharsha.Basavapatna@Sun.COM */ 253910309SSriharsha.Basavapatna@Sun.COM static int 254010309SSriharsha.Basavapatna@Sun.COM vnet_ring_enable_intr(void *arg) 254110309SSriharsha.Basavapatna@Sun.COM { 254210309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_rx_ring_t *rx_ringp = (vnet_pseudo_rx_ring_t *)arg; 254310309SSriharsha.Basavapatna@Sun.COM vnet_res_t *vresp; 254410309SSriharsha.Basavapatna@Sun.COM 254510309SSriharsha.Basavapatna@Sun.COM if (rx_ringp->hw_rh == NULL) { 254610309SSriharsha.Basavapatna@Sun.COM /* 254710309SSriharsha.Basavapatna@Sun.COM * Ring enable intr func is being invoked, but the ring is 254810309SSriharsha.Basavapatna@Sun.COM * not bound to any underlying resource ? This must be a ring 254910309SSriharsha.Basavapatna@Sun.COM * reserved for Hybrid resource and no such resource has been 255010309SSriharsha.Basavapatna@Sun.COM * assigned to this vnet device yet. We simply return success. 255110309SSriharsha.Basavapatna@Sun.COM */ 255210309SSriharsha.Basavapatna@Sun.COM ASSERT((rx_ringp->state & VNET_RXRING_HYBRID) != 0); 255310309SSriharsha.Basavapatna@Sun.COM return (0); 255410309SSriharsha.Basavapatna@Sun.COM } 255510309SSriharsha.Basavapatna@Sun.COM 255610309SSriharsha.Basavapatna@Sun.COM /* 255710309SSriharsha.Basavapatna@Sun.COM * The rx ring has been bound to either a LDC or a Hybrid resource. 255810309SSriharsha.Basavapatna@Sun.COM * Call the appropriate function to enable interrupts for the ring. 255910309SSriharsha.Basavapatna@Sun.COM */ 256010309SSriharsha.Basavapatna@Sun.COM if (rx_ringp->state & VNET_RXRING_HYBRID) { 256110309SSriharsha.Basavapatna@Sun.COM return (mac_hwring_enable_intr(rx_ringp->hw_rh)); 256210309SSriharsha.Basavapatna@Sun.COM } else { 256310309SSriharsha.Basavapatna@Sun.COM vresp = (vnet_res_t *)rx_ringp->hw_rh; 256410309SSriharsha.Basavapatna@Sun.COM return (vgen_enable_intr(vresp->macreg.m_driver)); 256510309SSriharsha.Basavapatna@Sun.COM } 256610309SSriharsha.Basavapatna@Sun.COM } 256710309SSriharsha.Basavapatna@Sun.COM 256810309SSriharsha.Basavapatna@Sun.COM /* 256910309SSriharsha.Basavapatna@Sun.COM * Enable polling for a ring and disable its interrupt. 257010309SSriharsha.Basavapatna@Sun.COM */ 257110309SSriharsha.Basavapatna@Sun.COM static int 257210309SSriharsha.Basavapatna@Sun.COM vnet_ring_disable_intr(void *arg) 257310309SSriharsha.Basavapatna@Sun.COM { 257410309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_rx_ring_t *rx_ringp = (vnet_pseudo_rx_ring_t *)arg; 257510309SSriharsha.Basavapatna@Sun.COM vnet_res_t *vresp; 257610309SSriharsha.Basavapatna@Sun.COM 257710309SSriharsha.Basavapatna@Sun.COM if (rx_ringp->hw_rh == NULL) { 257810309SSriharsha.Basavapatna@Sun.COM /* 257910309SSriharsha.Basavapatna@Sun.COM * Ring disable intr func is being invoked, but the ring is 258010309SSriharsha.Basavapatna@Sun.COM * not bound to any underlying resource ? This must be a ring 258110309SSriharsha.Basavapatna@Sun.COM * reserved for Hybrid resource and no such resource has been 258210309SSriharsha.Basavapatna@Sun.COM * assigned to this vnet device yet. We simply return success. 258310309SSriharsha.Basavapatna@Sun.COM */ 258410309SSriharsha.Basavapatna@Sun.COM ASSERT((rx_ringp->state & VNET_RXRING_HYBRID) != 0); 258510309SSriharsha.Basavapatna@Sun.COM return (0); 258610309SSriharsha.Basavapatna@Sun.COM } 258710309SSriharsha.Basavapatna@Sun.COM 258810309SSriharsha.Basavapatna@Sun.COM /* 258910309SSriharsha.Basavapatna@Sun.COM * The rx ring has been bound to either a LDC or a Hybrid resource. 259010309SSriharsha.Basavapatna@Sun.COM * Call the appropriate function to disable interrupts for the ring. 259110309SSriharsha.Basavapatna@Sun.COM */ 259210309SSriharsha.Basavapatna@Sun.COM if (rx_ringp->state & VNET_RXRING_HYBRID) { 259310309SSriharsha.Basavapatna@Sun.COM return (mac_hwring_disable_intr(rx_ringp->hw_rh)); 259410309SSriharsha.Basavapatna@Sun.COM } else { 259510309SSriharsha.Basavapatna@Sun.COM vresp = (vnet_res_t *)rx_ringp->hw_rh; 259610309SSriharsha.Basavapatna@Sun.COM return (vgen_disable_intr(vresp->macreg.m_driver)); 259710309SSriharsha.Basavapatna@Sun.COM } 259810309SSriharsha.Basavapatna@Sun.COM } 259910309SSriharsha.Basavapatna@Sun.COM 260010309SSriharsha.Basavapatna@Sun.COM /* 260110309SSriharsha.Basavapatna@Sun.COM * Poll 'bytes_to_pickup' bytes of message from the rx ring. 260210309SSriharsha.Basavapatna@Sun.COM */ 260310309SSriharsha.Basavapatna@Sun.COM static mblk_t * 260410309SSriharsha.Basavapatna@Sun.COM vnet_rx_poll(void *arg, int bytes_to_pickup) 260510309SSriharsha.Basavapatna@Sun.COM { 260610309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_rx_ring_t *rx_ringp = (vnet_pseudo_rx_ring_t *)arg; 260710309SSriharsha.Basavapatna@Sun.COM mblk_t *mp = NULL; 260810309SSriharsha.Basavapatna@Sun.COM vnet_res_t *vresp; 260910309SSriharsha.Basavapatna@Sun.COM vnet_t *vnetp = rx_ringp->vnetp; 261010309SSriharsha.Basavapatna@Sun.COM 261110309SSriharsha.Basavapatna@Sun.COM if (rx_ringp->hw_rh == NULL) { 261210309SSriharsha.Basavapatna@Sun.COM return (NULL); 261310309SSriharsha.Basavapatna@Sun.COM } 261410309SSriharsha.Basavapatna@Sun.COM 261510309SSriharsha.Basavapatna@Sun.COM if (rx_ringp->state & VNET_RXRING_HYBRID) { 261610309SSriharsha.Basavapatna@Sun.COM mp = mac_hwring_poll(rx_ringp->hw_rh, bytes_to_pickup); 261710309SSriharsha.Basavapatna@Sun.COM /* 261810309SSriharsha.Basavapatna@Sun.COM * Packets received over a hybrid resource need additional 261910309SSriharsha.Basavapatna@Sun.COM * processing to remove the tag, for the pvid case. The 262010309SSriharsha.Basavapatna@Sun.COM * underlying resource is not aware of the vnet's pvid and thus 262110309SSriharsha.Basavapatna@Sun.COM * packets are received with the vlan tag in the header; unlike 262210309SSriharsha.Basavapatna@Sun.COM * packets that are received over a ldc channel in which case 262310309SSriharsha.Basavapatna@Sun.COM * the peer vnet/vsw would have already removed the tag. 262410309SSriharsha.Basavapatna@Sun.COM */ 262510309SSriharsha.Basavapatna@Sun.COM if (vnetp->pvid != vnetp->default_vlan_id) { 262610309SSriharsha.Basavapatna@Sun.COM vnet_rx_frames_untag(vnetp->pvid, &mp); 262710309SSriharsha.Basavapatna@Sun.COM } 262810309SSriharsha.Basavapatna@Sun.COM } else { 262910309SSriharsha.Basavapatna@Sun.COM vresp = (vnet_res_t *)rx_ringp->hw_rh; 263010309SSriharsha.Basavapatna@Sun.COM mp = vgen_poll(vresp->macreg.m_driver, bytes_to_pickup); 263110309SSriharsha.Basavapatna@Sun.COM } 263210309SSriharsha.Basavapatna@Sun.COM return (mp); 263310309SSriharsha.Basavapatna@Sun.COM } 263410309SSriharsha.Basavapatna@Sun.COM 263510309SSriharsha.Basavapatna@Sun.COM /* ARGSUSED */ 263610309SSriharsha.Basavapatna@Sun.COM void 263710309SSriharsha.Basavapatna@Sun.COM vnet_hio_rx_cb(void *arg, mac_resource_handle_t mrh, mblk_t *mp, 263810309SSriharsha.Basavapatna@Sun.COM boolean_t loopback) 263910309SSriharsha.Basavapatna@Sun.COM { 264010309SSriharsha.Basavapatna@Sun.COM vnet_t *vnetp = (vnet_t *)arg; 264110309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_rx_ring_t *ringp = (vnet_pseudo_rx_ring_t *)mrh; 264210309SSriharsha.Basavapatna@Sun.COM 264310309SSriharsha.Basavapatna@Sun.COM /* 264410309SSriharsha.Basavapatna@Sun.COM * Packets received over a hybrid resource need additional processing 264510309SSriharsha.Basavapatna@Sun.COM * to remove the tag, for the pvid case. The underlying resource is 264610309SSriharsha.Basavapatna@Sun.COM * not aware of the vnet's pvid and thus packets are received with the 264710309SSriharsha.Basavapatna@Sun.COM * vlan tag in the header; unlike packets that are received over a ldc 264810309SSriharsha.Basavapatna@Sun.COM * channel in which case the peer vnet/vsw would have already removed 264910309SSriharsha.Basavapatna@Sun.COM * the tag. 265010309SSriharsha.Basavapatna@Sun.COM */ 265110309SSriharsha.Basavapatna@Sun.COM if (vnetp->pvid != vnetp->default_vlan_id) { 265210309SSriharsha.Basavapatna@Sun.COM vnet_rx_frames_untag(vnetp->pvid, &mp); 265310309SSriharsha.Basavapatna@Sun.COM if (mp == NULL) { 265410309SSriharsha.Basavapatna@Sun.COM return; 265510309SSriharsha.Basavapatna@Sun.COM } 265610309SSriharsha.Basavapatna@Sun.COM } 265710309SSriharsha.Basavapatna@Sun.COM mac_rx_ring(vnetp->mh, ringp->handle, mp, ringp->gen_num); 265810309SSriharsha.Basavapatna@Sun.COM } 265910309SSriharsha.Basavapatna@Sun.COM 266010309SSriharsha.Basavapatna@Sun.COM static int 266110309SSriharsha.Basavapatna@Sun.COM vnet_addmac(void *arg, const uint8_t *mac_addr) 266210309SSriharsha.Basavapatna@Sun.COM { 266310309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_rx_group_t *rx_grp = (vnet_pseudo_rx_group_t *)arg; 266410309SSriharsha.Basavapatna@Sun.COM vnet_t *vnetp; 266510309SSriharsha.Basavapatna@Sun.COM 266610309SSriharsha.Basavapatna@Sun.COM vnetp = rx_grp->vnetp; 266710309SSriharsha.Basavapatna@Sun.COM 266810309SSriharsha.Basavapatna@Sun.COM if (bcmp(mac_addr, vnetp->curr_macaddr, ETHERADDRL) == 0) { 266910309SSriharsha.Basavapatna@Sun.COM return (0); 267010309SSriharsha.Basavapatna@Sun.COM } 267110309SSriharsha.Basavapatna@Sun.COM 267210309SSriharsha.Basavapatna@Sun.COM cmn_err(CE_CONT, "!vnet%d: %s: Multiple macaddr unsupported\n", 267310309SSriharsha.Basavapatna@Sun.COM vnetp->instance, __func__); 267410309SSriharsha.Basavapatna@Sun.COM return (EINVAL); 267510309SSriharsha.Basavapatna@Sun.COM } 267610309SSriharsha.Basavapatna@Sun.COM 267710309SSriharsha.Basavapatna@Sun.COM static int 267810309SSriharsha.Basavapatna@Sun.COM vnet_remmac(void *arg, const uint8_t *mac_addr) 267910309SSriharsha.Basavapatna@Sun.COM { 268010309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_rx_group_t *rx_grp = (vnet_pseudo_rx_group_t *)arg; 268110309SSriharsha.Basavapatna@Sun.COM vnet_t *vnetp; 268210309SSriharsha.Basavapatna@Sun.COM 268310309SSriharsha.Basavapatna@Sun.COM vnetp = rx_grp->vnetp; 268410309SSriharsha.Basavapatna@Sun.COM 268510309SSriharsha.Basavapatna@Sun.COM if (bcmp(mac_addr, vnetp->curr_macaddr, ETHERADDRL) == 0) { 268610309SSriharsha.Basavapatna@Sun.COM return (0); 268710309SSriharsha.Basavapatna@Sun.COM } 268810309SSriharsha.Basavapatna@Sun.COM 268910309SSriharsha.Basavapatna@Sun.COM cmn_err(CE_CONT, "!vnet%d: %s: Invalid macaddr: %s\n", 269010309SSriharsha.Basavapatna@Sun.COM vnetp->instance, __func__, ether_sprintf((void *)mac_addr)); 269110309SSriharsha.Basavapatna@Sun.COM return (EINVAL); 269210309SSriharsha.Basavapatna@Sun.COM } 269310309SSriharsha.Basavapatna@Sun.COM 269410309SSriharsha.Basavapatna@Sun.COM int 269510309SSriharsha.Basavapatna@Sun.COM vnet_hio_mac_init(vnet_t *vnetp, char *ifname) 269610309SSriharsha.Basavapatna@Sun.COM { 269710309SSriharsha.Basavapatna@Sun.COM mac_handle_t mh; 269810309SSriharsha.Basavapatna@Sun.COM mac_client_handle_t mch = NULL; 269910309SSriharsha.Basavapatna@Sun.COM mac_unicast_handle_t muh = NULL; 270010309SSriharsha.Basavapatna@Sun.COM mac_diag_t diag; 270110309SSriharsha.Basavapatna@Sun.COM mac_register_t *macp; 270210309SSriharsha.Basavapatna@Sun.COM char client_name[MAXNAMELEN]; 270310309SSriharsha.Basavapatna@Sun.COM int rv; 270410309SSriharsha.Basavapatna@Sun.COM uint16_t mac_flags = MAC_UNICAST_TAG_DISABLE | 270510309SSriharsha.Basavapatna@Sun.COM MAC_UNICAST_STRIP_DISABLE | MAC_UNICAST_PRIMARY; 270610309SSriharsha.Basavapatna@Sun.COM vio_net_callbacks_t vcb; 270710309SSriharsha.Basavapatna@Sun.COM ether_addr_t rem_addr = 270810309SSriharsha.Basavapatna@Sun.COM { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 270910309SSriharsha.Basavapatna@Sun.COM uint32_t retries = 0; 271010309SSriharsha.Basavapatna@Sun.COM 271110309SSriharsha.Basavapatna@Sun.COM if ((macp = mac_alloc(MAC_VERSION)) == NULL) { 271210309SSriharsha.Basavapatna@Sun.COM return (EAGAIN); 271310309SSriharsha.Basavapatna@Sun.COM } 271410309SSriharsha.Basavapatna@Sun.COM 271510309SSriharsha.Basavapatna@Sun.COM do { 271610309SSriharsha.Basavapatna@Sun.COM rv = mac_open_by_linkname(ifname, &mh); 271710309SSriharsha.Basavapatna@Sun.COM if (rv == 0) { 271810309SSriharsha.Basavapatna@Sun.COM break; 271910309SSriharsha.Basavapatna@Sun.COM } 272010309SSriharsha.Basavapatna@Sun.COM if (rv != ENOENT || (retries++ >= vnet_mac_open_retries)) { 272110309SSriharsha.Basavapatna@Sun.COM mac_free(macp); 272210309SSriharsha.Basavapatna@Sun.COM return (rv); 272310309SSriharsha.Basavapatna@Sun.COM } 272410309SSriharsha.Basavapatna@Sun.COM drv_usecwait(vnet_mac_open_delay); 272510309SSriharsha.Basavapatna@Sun.COM } while (rv == ENOENT); 272610309SSriharsha.Basavapatna@Sun.COM 272710309SSriharsha.Basavapatna@Sun.COM vnetp->hio_mh = mh; 272810309SSriharsha.Basavapatna@Sun.COM 272910309SSriharsha.Basavapatna@Sun.COM (void) snprintf(client_name, MAXNAMELEN, "vnet%d-%s", vnetp->instance, 273010309SSriharsha.Basavapatna@Sun.COM ifname); 273110309SSriharsha.Basavapatna@Sun.COM rv = mac_client_open(mh, &mch, client_name, MAC_OPEN_FLAGS_EXCLUSIVE); 273210309SSriharsha.Basavapatna@Sun.COM if (rv != 0) { 273310309SSriharsha.Basavapatna@Sun.COM goto fail; 273410309SSriharsha.Basavapatna@Sun.COM } 273510309SSriharsha.Basavapatna@Sun.COM vnetp->hio_mch = mch; 273610309SSriharsha.Basavapatna@Sun.COM 273710309SSriharsha.Basavapatna@Sun.COM rv = mac_unicast_add(mch, vnetp->curr_macaddr, mac_flags, &muh, 0, 273810309SSriharsha.Basavapatna@Sun.COM &diag); 273910309SSriharsha.Basavapatna@Sun.COM if (rv != 0) { 274010309SSriharsha.Basavapatna@Sun.COM goto fail; 274110309SSriharsha.Basavapatna@Sun.COM } 274210309SSriharsha.Basavapatna@Sun.COM vnetp->hio_muh = muh; 274310309SSriharsha.Basavapatna@Sun.COM 274410309SSriharsha.Basavapatna@Sun.COM macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 274510309SSriharsha.Basavapatna@Sun.COM macp->m_driver = vnetp; 274610309SSriharsha.Basavapatna@Sun.COM macp->m_dip = NULL; 274710309SSriharsha.Basavapatna@Sun.COM macp->m_src_addr = NULL; 274810309SSriharsha.Basavapatna@Sun.COM macp->m_callbacks = &vnet_hio_res_callbacks; 274910309SSriharsha.Basavapatna@Sun.COM macp->m_min_sdu = 0; 275010309SSriharsha.Basavapatna@Sun.COM macp->m_max_sdu = ETHERMTU; 275110309SSriharsha.Basavapatna@Sun.COM 275210309SSriharsha.Basavapatna@Sun.COM rv = vio_net_resource_reg(macp, VIO_NET_RES_HYBRID, 275310309SSriharsha.Basavapatna@Sun.COM vnetp->curr_macaddr, rem_addr, &vnetp->hio_vhp, &vcb); 275410309SSriharsha.Basavapatna@Sun.COM if (rv != 0) { 275510309SSriharsha.Basavapatna@Sun.COM goto fail; 275610309SSriharsha.Basavapatna@Sun.COM } 275710309SSriharsha.Basavapatna@Sun.COM mac_free(macp); 275810309SSriharsha.Basavapatna@Sun.COM 275910309SSriharsha.Basavapatna@Sun.COM /* add the recv callback */ 276010309SSriharsha.Basavapatna@Sun.COM mac_rx_set(vnetp->hio_mch, vnet_hio_rx_cb, vnetp); 276110309SSriharsha.Basavapatna@Sun.COM 276210309SSriharsha.Basavapatna@Sun.COM return (0); 276310309SSriharsha.Basavapatna@Sun.COM 276410309SSriharsha.Basavapatna@Sun.COM fail: 276510309SSriharsha.Basavapatna@Sun.COM mac_free(macp); 276610309SSriharsha.Basavapatna@Sun.COM vnet_hio_mac_cleanup(vnetp); 276710309SSriharsha.Basavapatna@Sun.COM return (1); 276810309SSriharsha.Basavapatna@Sun.COM } 276910309SSriharsha.Basavapatna@Sun.COM 277010309SSriharsha.Basavapatna@Sun.COM void 277110309SSriharsha.Basavapatna@Sun.COM vnet_hio_mac_cleanup(vnet_t *vnetp) 277210309SSriharsha.Basavapatna@Sun.COM { 277310309SSriharsha.Basavapatna@Sun.COM if (vnetp->hio_vhp != NULL) { 277410309SSriharsha.Basavapatna@Sun.COM vio_net_resource_unreg(vnetp->hio_vhp); 277510309SSriharsha.Basavapatna@Sun.COM vnetp->hio_vhp = NULL; 277610309SSriharsha.Basavapatna@Sun.COM } 277710309SSriharsha.Basavapatna@Sun.COM 277810309SSriharsha.Basavapatna@Sun.COM if (vnetp->hio_muh != NULL) { 277911311SSurya.Prakki@Sun.COM (void) mac_unicast_remove(vnetp->hio_mch, vnetp->hio_muh); 278010309SSriharsha.Basavapatna@Sun.COM vnetp->hio_muh = NULL; 278110309SSriharsha.Basavapatna@Sun.COM } 278210309SSriharsha.Basavapatna@Sun.COM 278310309SSriharsha.Basavapatna@Sun.COM if (vnetp->hio_mch != NULL) { 278410309SSriharsha.Basavapatna@Sun.COM mac_client_close(vnetp->hio_mch, 0); 278510309SSriharsha.Basavapatna@Sun.COM vnetp->hio_mch = NULL; 278610309SSriharsha.Basavapatna@Sun.COM } 278710309SSriharsha.Basavapatna@Sun.COM 278810309SSriharsha.Basavapatna@Sun.COM if (vnetp->hio_mh != NULL) { 278910309SSriharsha.Basavapatna@Sun.COM mac_close(vnetp->hio_mh); 279010309SSriharsha.Basavapatna@Sun.COM vnetp->hio_mh = NULL; 279110309SSriharsha.Basavapatna@Sun.COM } 279210309SSriharsha.Basavapatna@Sun.COM } 279310309SSriharsha.Basavapatna@Sun.COM 279410309SSriharsha.Basavapatna@Sun.COM /* Bind pseudo rings to hwrings */ 279510309SSriharsha.Basavapatna@Sun.COM static int 279610309SSriharsha.Basavapatna@Sun.COM vnet_bind_hwrings(vnet_t *vnetp) 279710309SSriharsha.Basavapatna@Sun.COM { 279810309SSriharsha.Basavapatna@Sun.COM mac_ring_handle_t hw_rh[VNET_NUM_HYBRID_RINGS]; 279910309SSriharsha.Basavapatna@Sun.COM mac_perim_handle_t mph1; 280010309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_rx_group_t *rx_grp; 280110309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_rx_ring_t *rx_ringp; 280210309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_tx_group_t *tx_grp; 280310309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_tx_ring_t *tx_ringp; 280410309SSriharsha.Basavapatna@Sun.COM int hw_ring_cnt; 280510309SSriharsha.Basavapatna@Sun.COM int i; 280610309SSriharsha.Basavapatna@Sun.COM int rv; 280710309SSriharsha.Basavapatna@Sun.COM 280810309SSriharsha.Basavapatna@Sun.COM mac_perim_enter_by_mh(vnetp->hio_mh, &mph1); 280910309SSriharsha.Basavapatna@Sun.COM 281010309SSriharsha.Basavapatna@Sun.COM /* Get the list of the underlying RX rings. */ 281110309SSriharsha.Basavapatna@Sun.COM hw_ring_cnt = mac_hwrings_get(vnetp->hio_mch, &vnetp->rx_hwgh, hw_rh, 281210309SSriharsha.Basavapatna@Sun.COM MAC_RING_TYPE_RX); 281310309SSriharsha.Basavapatna@Sun.COM 281410309SSriharsha.Basavapatna@Sun.COM /* We expect the the # of hw rx rings to match VNET_NUM_HYBRID_RINGS */ 281510309SSriharsha.Basavapatna@Sun.COM if (hw_ring_cnt != VNET_NUM_HYBRID_RINGS) { 281610309SSriharsha.Basavapatna@Sun.COM cmn_err(CE_WARN, 281710309SSriharsha.Basavapatna@Sun.COM "!vnet%d: vnet_bind_hwrings: bad rx hw_ring_cnt(%d)\n", 281810309SSriharsha.Basavapatna@Sun.COM vnetp->instance, hw_ring_cnt); 281910309SSriharsha.Basavapatna@Sun.COM goto fail; 282010309SSriharsha.Basavapatna@Sun.COM } 282110309SSriharsha.Basavapatna@Sun.COM 282210309SSriharsha.Basavapatna@Sun.COM if (vnetp->rx_hwgh != NULL) { 282310309SSriharsha.Basavapatna@Sun.COM /* 282410309SSriharsha.Basavapatna@Sun.COM * Quiesce the HW ring and the mac srs on the ring. Note 282510309SSriharsha.Basavapatna@Sun.COM * that the HW ring will be restarted when the pseudo ring 282610309SSriharsha.Basavapatna@Sun.COM * is started. At that time all the packets will be 282710309SSriharsha.Basavapatna@Sun.COM * directly passed up to the pseudo RX ring and handled 282810309SSriharsha.Basavapatna@Sun.COM * by mac srs created over the pseudo RX ring. 282910309SSriharsha.Basavapatna@Sun.COM */ 283010309SSriharsha.Basavapatna@Sun.COM mac_rx_client_quiesce(vnetp->hio_mch); 283110309SSriharsha.Basavapatna@Sun.COM mac_srs_perm_quiesce(vnetp->hio_mch, B_TRUE); 283210309SSriharsha.Basavapatna@Sun.COM } 283310309SSriharsha.Basavapatna@Sun.COM 283410309SSriharsha.Basavapatna@Sun.COM /* 283510309SSriharsha.Basavapatna@Sun.COM * Bind the pseudo rings to the hwrings and start the hwrings. 283610309SSriharsha.Basavapatna@Sun.COM * Note we don't need to register these with the upper mac, as we have 283710309SSriharsha.Basavapatna@Sun.COM * statically exported these pseudo rxrings which are reserved for 283810309SSriharsha.Basavapatna@Sun.COM * rxrings of Hybrid resource. 283910309SSriharsha.Basavapatna@Sun.COM */ 284010309SSriharsha.Basavapatna@Sun.COM rx_grp = &vnetp->rx_grp[0]; 284110309SSriharsha.Basavapatna@Sun.COM for (i = 0; i < VNET_NUM_HYBRID_RINGS; i++) { 284210309SSriharsha.Basavapatna@Sun.COM /* Pick the rxrings reserved for Hybrid resource */ 284310309SSriharsha.Basavapatna@Sun.COM rx_ringp = &rx_grp->rings[i + VNET_HYBRID_RXRING_INDEX]; 284410309SSriharsha.Basavapatna@Sun.COM 284510309SSriharsha.Basavapatna@Sun.COM /* Store the hw ring handle */ 284610309SSriharsha.Basavapatna@Sun.COM rx_ringp->hw_rh = hw_rh[i]; 284710309SSriharsha.Basavapatna@Sun.COM 284810309SSriharsha.Basavapatna@Sun.COM /* Bind the pseudo ring to the underlying hwring */ 284910309SSriharsha.Basavapatna@Sun.COM mac_hwring_setup(rx_ringp->hw_rh, 285011878SVenu.Iyer@Sun.COM (mac_resource_handle_t)rx_ringp, NULL); 285110309SSriharsha.Basavapatna@Sun.COM 285210309SSriharsha.Basavapatna@Sun.COM /* Start the hwring if needed */ 285310309SSriharsha.Basavapatna@Sun.COM if (rx_ringp->state & VNET_RXRING_STARTED) { 285410309SSriharsha.Basavapatna@Sun.COM rv = mac_hwring_start(rx_ringp->hw_rh); 285510309SSriharsha.Basavapatna@Sun.COM if (rv != 0) { 285610309SSriharsha.Basavapatna@Sun.COM mac_hwring_teardown(rx_ringp->hw_rh); 285710309SSriharsha.Basavapatna@Sun.COM rx_ringp->hw_rh = NULL; 285810309SSriharsha.Basavapatna@Sun.COM goto fail; 285910309SSriharsha.Basavapatna@Sun.COM } 286010309SSriharsha.Basavapatna@Sun.COM } 286110309SSriharsha.Basavapatna@Sun.COM } 286210309SSriharsha.Basavapatna@Sun.COM 286310309SSriharsha.Basavapatna@Sun.COM /* Get the list of the underlying TX rings. */ 286410309SSriharsha.Basavapatna@Sun.COM hw_ring_cnt = mac_hwrings_get(vnetp->hio_mch, &vnetp->tx_hwgh, hw_rh, 286510309SSriharsha.Basavapatna@Sun.COM MAC_RING_TYPE_TX); 286610309SSriharsha.Basavapatna@Sun.COM 286710309SSriharsha.Basavapatna@Sun.COM /* We expect the # of hw tx rings to match VNET_NUM_HYBRID_RINGS */ 286810309SSriharsha.Basavapatna@Sun.COM if (hw_ring_cnt != VNET_NUM_HYBRID_RINGS) { 286910309SSriharsha.Basavapatna@Sun.COM cmn_err(CE_WARN, 287010309SSriharsha.Basavapatna@Sun.COM "!vnet%d: vnet_bind_hwrings: bad tx hw_ring_cnt(%d)\n", 287110309SSriharsha.Basavapatna@Sun.COM vnetp->instance, hw_ring_cnt); 287210309SSriharsha.Basavapatna@Sun.COM goto fail; 287310309SSriharsha.Basavapatna@Sun.COM } 287410309SSriharsha.Basavapatna@Sun.COM 287510309SSriharsha.Basavapatna@Sun.COM /* 287610309SSriharsha.Basavapatna@Sun.COM * Now map the pseudo txrings to the hw txrings. Note we don't need 287710309SSriharsha.Basavapatna@Sun.COM * to register these with the upper mac, as we have statically exported 287810309SSriharsha.Basavapatna@Sun.COM * these rings. Note that these rings will continue to be used for LDC 287910309SSriharsha.Basavapatna@Sun.COM * resources to peer vnets and vswitch (shared ring). 288010309SSriharsha.Basavapatna@Sun.COM */ 288110309SSriharsha.Basavapatna@Sun.COM tx_grp = &vnetp->tx_grp[0]; 288210309SSriharsha.Basavapatna@Sun.COM for (i = 0; i < tx_grp->ring_cnt; i++) { 288310309SSriharsha.Basavapatna@Sun.COM tx_ringp = &tx_grp->rings[i]; 288410309SSriharsha.Basavapatna@Sun.COM tx_ringp->hw_rh = hw_rh[i]; 288510309SSriharsha.Basavapatna@Sun.COM tx_ringp->state |= VNET_TXRING_HYBRID; 288610309SSriharsha.Basavapatna@Sun.COM } 288711878SVenu.Iyer@Sun.COM tx_grp->tx_notify_handle = 288811878SVenu.Iyer@Sun.COM mac_client_tx_notify(vnetp->hio_mch, vnet_tx_ring_update, vnetp); 288910309SSriharsha.Basavapatna@Sun.COM 289010309SSriharsha.Basavapatna@Sun.COM mac_perim_exit(mph1); 289110309SSriharsha.Basavapatna@Sun.COM return (0); 289210309SSriharsha.Basavapatna@Sun.COM 289310309SSriharsha.Basavapatna@Sun.COM fail: 289410309SSriharsha.Basavapatna@Sun.COM mac_perim_exit(mph1); 289510309SSriharsha.Basavapatna@Sun.COM vnet_unbind_hwrings(vnetp); 289610309SSriharsha.Basavapatna@Sun.COM return (1); 289710309SSriharsha.Basavapatna@Sun.COM } 289810309SSriharsha.Basavapatna@Sun.COM 289910309SSriharsha.Basavapatna@Sun.COM /* Unbind pseudo rings from hwrings */ 290010309SSriharsha.Basavapatna@Sun.COM static void 290110309SSriharsha.Basavapatna@Sun.COM vnet_unbind_hwrings(vnet_t *vnetp) 290210309SSriharsha.Basavapatna@Sun.COM { 290310309SSriharsha.Basavapatna@Sun.COM mac_perim_handle_t mph1; 290410309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_rx_ring_t *rx_ringp; 290510309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_rx_group_t *rx_grp; 290610309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_tx_group_t *tx_grp; 290710309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_tx_ring_t *tx_ringp; 290810309SSriharsha.Basavapatna@Sun.COM int i; 290910309SSriharsha.Basavapatna@Sun.COM 291010309SSriharsha.Basavapatna@Sun.COM mac_perim_enter_by_mh(vnetp->hio_mh, &mph1); 291110309SSriharsha.Basavapatna@Sun.COM 291210309SSriharsha.Basavapatna@Sun.COM tx_grp = &vnetp->tx_grp[0]; 291310309SSriharsha.Basavapatna@Sun.COM for (i = 0; i < VNET_NUM_HYBRID_RINGS; i++) { 291410309SSriharsha.Basavapatna@Sun.COM tx_ringp = &tx_grp->rings[i]; 291510309SSriharsha.Basavapatna@Sun.COM if (tx_ringp->state & VNET_TXRING_HYBRID) { 291610309SSriharsha.Basavapatna@Sun.COM tx_ringp->state &= ~VNET_TXRING_HYBRID; 291710309SSriharsha.Basavapatna@Sun.COM tx_ringp->hw_rh = NULL; 291810309SSriharsha.Basavapatna@Sun.COM } 291910309SSriharsha.Basavapatna@Sun.COM } 292011878SVenu.Iyer@Sun.COM (void) mac_client_tx_notify(vnetp->hio_mch, NULL, 292111878SVenu.Iyer@Sun.COM tx_grp->tx_notify_handle); 292210309SSriharsha.Basavapatna@Sun.COM 292310309SSriharsha.Basavapatna@Sun.COM rx_grp = &vnetp->rx_grp[0]; 292410309SSriharsha.Basavapatna@Sun.COM for (i = 0; i < VNET_NUM_HYBRID_RINGS; i++) { 292510309SSriharsha.Basavapatna@Sun.COM rx_ringp = &rx_grp->rings[i + VNET_HYBRID_RXRING_INDEX]; 292610309SSriharsha.Basavapatna@Sun.COM if (rx_ringp->hw_rh != NULL) { 292710309SSriharsha.Basavapatna@Sun.COM /* Stop the hwring */ 292810309SSriharsha.Basavapatna@Sun.COM mac_hwring_stop(rx_ringp->hw_rh); 292910309SSriharsha.Basavapatna@Sun.COM 293010309SSriharsha.Basavapatna@Sun.COM /* Teardown the hwring */ 293110309SSriharsha.Basavapatna@Sun.COM mac_hwring_teardown(rx_ringp->hw_rh); 293210309SSriharsha.Basavapatna@Sun.COM rx_ringp->hw_rh = NULL; 293310309SSriharsha.Basavapatna@Sun.COM } 293410309SSriharsha.Basavapatna@Sun.COM } 293510309SSriharsha.Basavapatna@Sun.COM 293610309SSriharsha.Basavapatna@Sun.COM if (vnetp->rx_hwgh != NULL) { 293710309SSriharsha.Basavapatna@Sun.COM vnetp->rx_hwgh = NULL; 293810309SSriharsha.Basavapatna@Sun.COM /* 293910309SSriharsha.Basavapatna@Sun.COM * First clear the permanent-quiesced flag of the RX srs then 294010309SSriharsha.Basavapatna@Sun.COM * restart the HW ring and the mac srs on the ring. 294110309SSriharsha.Basavapatna@Sun.COM */ 294210309SSriharsha.Basavapatna@Sun.COM mac_srs_perm_quiesce(vnetp->hio_mch, B_FALSE); 294310309SSriharsha.Basavapatna@Sun.COM mac_rx_client_restart(vnetp->hio_mch); 294410309SSriharsha.Basavapatna@Sun.COM } 294510309SSriharsha.Basavapatna@Sun.COM 294610309SSriharsha.Basavapatna@Sun.COM mac_perim_exit(mph1); 294710309SSriharsha.Basavapatna@Sun.COM } 294810309SSriharsha.Basavapatna@Sun.COM 294910309SSriharsha.Basavapatna@Sun.COM /* Bind pseudo ring to a LDC resource */ 295010309SSriharsha.Basavapatna@Sun.COM static int 295110309SSriharsha.Basavapatna@Sun.COM vnet_bind_vgenring(vnet_res_t *vresp) 295210309SSriharsha.Basavapatna@Sun.COM { 295310309SSriharsha.Basavapatna@Sun.COM vnet_t *vnetp; 295410309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_rx_group_t *rx_grp; 295510309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_rx_ring_t *rx_ringp; 295610309SSriharsha.Basavapatna@Sun.COM mac_perim_handle_t mph1; 295710309SSriharsha.Basavapatna@Sun.COM int rv; 295810309SSriharsha.Basavapatna@Sun.COM int type; 295910309SSriharsha.Basavapatna@Sun.COM 296010309SSriharsha.Basavapatna@Sun.COM vnetp = vresp->vnetp; 296110309SSriharsha.Basavapatna@Sun.COM type = vresp->type; 296210309SSriharsha.Basavapatna@Sun.COM rx_grp = &vnetp->rx_grp[0]; 296310309SSriharsha.Basavapatna@Sun.COM 296410309SSriharsha.Basavapatna@Sun.COM if (type == VIO_NET_RES_LDC_SERVICE) { 296510309SSriharsha.Basavapatna@Sun.COM /* 296610309SSriharsha.Basavapatna@Sun.COM * Ring Index 0 is the default ring in the group and is 296710309SSriharsha.Basavapatna@Sun.COM * reserved for LDC_SERVICE in vnet_ring_grp_init(). This ring 296810309SSriharsha.Basavapatna@Sun.COM * is allocated statically and is reported to the mac layer 296910309SSriharsha.Basavapatna@Sun.COM * in vnet_m_capab(). So, all we need to do here, is save a 297010309SSriharsha.Basavapatna@Sun.COM * reference to the associated vresp. 297110309SSriharsha.Basavapatna@Sun.COM */ 297210309SSriharsha.Basavapatna@Sun.COM rx_ringp = &rx_grp->rings[0]; 297310309SSriharsha.Basavapatna@Sun.COM rx_ringp->hw_rh = (mac_ring_handle_t)vresp; 297410309SSriharsha.Basavapatna@Sun.COM vresp->rx_ringp = (void *)rx_ringp; 297510309SSriharsha.Basavapatna@Sun.COM return (0); 297610309SSriharsha.Basavapatna@Sun.COM } 297710309SSriharsha.Basavapatna@Sun.COM ASSERT(type == VIO_NET_RES_LDC_GUEST); 297810309SSriharsha.Basavapatna@Sun.COM 297910309SSriharsha.Basavapatna@Sun.COM mac_perim_enter_by_mh(vnetp->mh, &mph1); 298010309SSriharsha.Basavapatna@Sun.COM 298110309SSriharsha.Basavapatna@Sun.COM rx_ringp = vnet_alloc_pseudo_rx_ring(vnetp); 298210309SSriharsha.Basavapatna@Sun.COM if (rx_ringp == NULL) { 298310309SSriharsha.Basavapatna@Sun.COM cmn_err(CE_WARN, "!vnet%d: Failed to allocate pseudo rx ring", 298410309SSriharsha.Basavapatna@Sun.COM vnetp->instance); 298510309SSriharsha.Basavapatna@Sun.COM goto fail; 298610309SSriharsha.Basavapatna@Sun.COM } 298710309SSriharsha.Basavapatna@Sun.COM 298810309SSriharsha.Basavapatna@Sun.COM /* Store the LDC resource itself as the ring handle */ 298910309SSriharsha.Basavapatna@Sun.COM rx_ringp->hw_rh = (mac_ring_handle_t)vresp; 299010309SSriharsha.Basavapatna@Sun.COM 299110309SSriharsha.Basavapatna@Sun.COM /* 299210309SSriharsha.Basavapatna@Sun.COM * Save a reference to the ring in the resource for lookup during 299310309SSriharsha.Basavapatna@Sun.COM * unbind. Note this is only done for LDC resources. We don't need this 299410309SSriharsha.Basavapatna@Sun.COM * in the case of a Hybrid resource (see vnet_bind_hwrings()), as its 299510309SSriharsha.Basavapatna@Sun.COM * rx rings are mapped to reserved pseudo rx rings (index 1 and 2). 299610309SSriharsha.Basavapatna@Sun.COM */ 299710309SSriharsha.Basavapatna@Sun.COM vresp->rx_ringp = (void *)rx_ringp; 299810309SSriharsha.Basavapatna@Sun.COM rx_ringp->state |= VNET_RXRING_LDC_GUEST; 299910309SSriharsha.Basavapatna@Sun.COM 300010309SSriharsha.Basavapatna@Sun.COM /* Register the pseudo ring with upper-mac */ 300110309SSriharsha.Basavapatna@Sun.COM rv = mac_group_add_ring(rx_grp->handle, rx_ringp->index); 300210309SSriharsha.Basavapatna@Sun.COM if (rv != 0) { 300310309SSriharsha.Basavapatna@Sun.COM rx_ringp->state &= ~VNET_RXRING_LDC_GUEST; 300410309SSriharsha.Basavapatna@Sun.COM rx_ringp->hw_rh = NULL; 300510309SSriharsha.Basavapatna@Sun.COM vnet_free_pseudo_rx_ring(vnetp, rx_ringp); 300610309SSriharsha.Basavapatna@Sun.COM goto fail; 300710309SSriharsha.Basavapatna@Sun.COM } 300810309SSriharsha.Basavapatna@Sun.COM 300910309SSriharsha.Basavapatna@Sun.COM mac_perim_exit(mph1); 301010309SSriharsha.Basavapatna@Sun.COM return (0); 301110309SSriharsha.Basavapatna@Sun.COM fail: 301210309SSriharsha.Basavapatna@Sun.COM mac_perim_exit(mph1); 301310309SSriharsha.Basavapatna@Sun.COM return (1); 301410309SSriharsha.Basavapatna@Sun.COM } 301510309SSriharsha.Basavapatna@Sun.COM 301610309SSriharsha.Basavapatna@Sun.COM /* Unbind pseudo ring from a LDC resource */ 301710309SSriharsha.Basavapatna@Sun.COM static void 301810309SSriharsha.Basavapatna@Sun.COM vnet_unbind_vgenring(vnet_res_t *vresp) 301910309SSriharsha.Basavapatna@Sun.COM { 302010309SSriharsha.Basavapatna@Sun.COM vnet_t *vnetp; 302110309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_rx_group_t *rx_grp; 302210309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_rx_ring_t *rx_ringp; 302310309SSriharsha.Basavapatna@Sun.COM mac_perim_handle_t mph1; 302410309SSriharsha.Basavapatna@Sun.COM int type; 302510309SSriharsha.Basavapatna@Sun.COM 302610309SSriharsha.Basavapatna@Sun.COM vnetp = vresp->vnetp; 302710309SSriharsha.Basavapatna@Sun.COM type = vresp->type; 302810309SSriharsha.Basavapatna@Sun.COM rx_grp = &vnetp->rx_grp[0]; 302910309SSriharsha.Basavapatna@Sun.COM 303010309SSriharsha.Basavapatna@Sun.COM if (vresp->rx_ringp == NULL) { 303110309SSriharsha.Basavapatna@Sun.COM return; 303210309SSriharsha.Basavapatna@Sun.COM } 303310309SSriharsha.Basavapatna@Sun.COM 303410309SSriharsha.Basavapatna@Sun.COM if (type == VIO_NET_RES_LDC_SERVICE) { 303510309SSriharsha.Basavapatna@Sun.COM /* 303610309SSriharsha.Basavapatna@Sun.COM * Ring Index 0 is the default ring in the group and is 303710309SSriharsha.Basavapatna@Sun.COM * reserved for LDC_SERVICE in vnet_ring_grp_init(). This ring 303810309SSriharsha.Basavapatna@Sun.COM * is allocated statically and is reported to the mac layer 303910309SSriharsha.Basavapatna@Sun.COM * in vnet_m_capab(). So, all we need to do here, is remove its 304010309SSriharsha.Basavapatna@Sun.COM * reference to the associated vresp. 304110309SSriharsha.Basavapatna@Sun.COM */ 304210309SSriharsha.Basavapatna@Sun.COM rx_ringp = &rx_grp->rings[0]; 304310309SSriharsha.Basavapatna@Sun.COM rx_ringp->hw_rh = NULL; 304410309SSriharsha.Basavapatna@Sun.COM vresp->rx_ringp = NULL; 304510309SSriharsha.Basavapatna@Sun.COM return; 304610309SSriharsha.Basavapatna@Sun.COM } 304710309SSriharsha.Basavapatna@Sun.COM ASSERT(type == VIO_NET_RES_LDC_GUEST); 304810309SSriharsha.Basavapatna@Sun.COM 304910309SSriharsha.Basavapatna@Sun.COM mac_perim_enter_by_mh(vnetp->mh, &mph1); 305010309SSriharsha.Basavapatna@Sun.COM 305110309SSriharsha.Basavapatna@Sun.COM rx_ringp = (vnet_pseudo_rx_ring_t *)vresp->rx_ringp; 305210309SSriharsha.Basavapatna@Sun.COM vresp->rx_ringp = NULL; 305310309SSriharsha.Basavapatna@Sun.COM 305410309SSriharsha.Basavapatna@Sun.COM if (rx_ringp != NULL && (rx_ringp->state & VNET_RXRING_LDC_GUEST)) { 305510309SSriharsha.Basavapatna@Sun.COM /* Unregister the pseudo ring with upper-mac */ 305610309SSriharsha.Basavapatna@Sun.COM mac_group_rem_ring(rx_grp->handle, rx_ringp->handle); 305710309SSriharsha.Basavapatna@Sun.COM 305810309SSriharsha.Basavapatna@Sun.COM rx_ringp->hw_rh = NULL; 305910309SSriharsha.Basavapatna@Sun.COM rx_ringp->state &= ~VNET_RXRING_LDC_GUEST; 306010309SSriharsha.Basavapatna@Sun.COM 306110309SSriharsha.Basavapatna@Sun.COM /* Free the pseudo rx ring */ 306210309SSriharsha.Basavapatna@Sun.COM vnet_free_pseudo_rx_ring(vnetp, rx_ringp); 306310309SSriharsha.Basavapatna@Sun.COM } 306410309SSriharsha.Basavapatna@Sun.COM 306510309SSriharsha.Basavapatna@Sun.COM mac_perim_exit(mph1); 306610309SSriharsha.Basavapatna@Sun.COM } 306710309SSriharsha.Basavapatna@Sun.COM 306810309SSriharsha.Basavapatna@Sun.COM static void 306910309SSriharsha.Basavapatna@Sun.COM vnet_unbind_rings(vnet_res_t *vresp) 307010309SSriharsha.Basavapatna@Sun.COM { 307110309SSriharsha.Basavapatna@Sun.COM switch (vresp->type) { 307210309SSriharsha.Basavapatna@Sun.COM 307310309SSriharsha.Basavapatna@Sun.COM case VIO_NET_RES_LDC_SERVICE: 307410309SSriharsha.Basavapatna@Sun.COM case VIO_NET_RES_LDC_GUEST: 307510309SSriharsha.Basavapatna@Sun.COM vnet_unbind_vgenring(vresp); 307610309SSriharsha.Basavapatna@Sun.COM break; 307710309SSriharsha.Basavapatna@Sun.COM 307810309SSriharsha.Basavapatna@Sun.COM case VIO_NET_RES_HYBRID: 307910309SSriharsha.Basavapatna@Sun.COM vnet_unbind_hwrings(vresp->vnetp); 308010309SSriharsha.Basavapatna@Sun.COM break; 308110309SSriharsha.Basavapatna@Sun.COM 308210309SSriharsha.Basavapatna@Sun.COM default: 308310309SSriharsha.Basavapatna@Sun.COM break; 308410309SSriharsha.Basavapatna@Sun.COM 308510309SSriharsha.Basavapatna@Sun.COM } 308610309SSriharsha.Basavapatna@Sun.COM } 308710309SSriharsha.Basavapatna@Sun.COM 308810309SSriharsha.Basavapatna@Sun.COM static int 308910309SSriharsha.Basavapatna@Sun.COM vnet_bind_rings(vnet_res_t *vresp) 309010309SSriharsha.Basavapatna@Sun.COM { 309110309SSriharsha.Basavapatna@Sun.COM int rv; 309210309SSriharsha.Basavapatna@Sun.COM 309310309SSriharsha.Basavapatna@Sun.COM switch (vresp->type) { 309410309SSriharsha.Basavapatna@Sun.COM 309510309SSriharsha.Basavapatna@Sun.COM case VIO_NET_RES_LDC_SERVICE: 309610309SSriharsha.Basavapatna@Sun.COM case VIO_NET_RES_LDC_GUEST: 309710309SSriharsha.Basavapatna@Sun.COM rv = vnet_bind_vgenring(vresp); 309810309SSriharsha.Basavapatna@Sun.COM break; 309910309SSriharsha.Basavapatna@Sun.COM 310010309SSriharsha.Basavapatna@Sun.COM case VIO_NET_RES_HYBRID: 310110309SSriharsha.Basavapatna@Sun.COM rv = vnet_bind_hwrings(vresp->vnetp); 310210309SSriharsha.Basavapatna@Sun.COM break; 310310309SSriharsha.Basavapatna@Sun.COM 310410309SSriharsha.Basavapatna@Sun.COM default: 310510309SSriharsha.Basavapatna@Sun.COM rv = 1; 310610309SSriharsha.Basavapatna@Sun.COM break; 310710309SSriharsha.Basavapatna@Sun.COM 310810309SSriharsha.Basavapatna@Sun.COM } 310910309SSriharsha.Basavapatna@Sun.COM 311010309SSriharsha.Basavapatna@Sun.COM return (rv); 311110309SSriharsha.Basavapatna@Sun.COM } 311210309SSriharsha.Basavapatna@Sun.COM 311310309SSriharsha.Basavapatna@Sun.COM /* ARGSUSED */ 311410309SSriharsha.Basavapatna@Sun.COM int 311510309SSriharsha.Basavapatna@Sun.COM vnet_hio_stat(void *arg, uint_t stat, uint64_t *val) 311610309SSriharsha.Basavapatna@Sun.COM { 311710309SSriharsha.Basavapatna@Sun.COM vnet_t *vnetp = (vnet_t *)arg; 311810309SSriharsha.Basavapatna@Sun.COM 311910309SSriharsha.Basavapatna@Sun.COM *val = mac_stat_get(vnetp->hio_mh, stat); 312010309SSriharsha.Basavapatna@Sun.COM return (0); 312110309SSriharsha.Basavapatna@Sun.COM } 312210309SSriharsha.Basavapatna@Sun.COM 312310309SSriharsha.Basavapatna@Sun.COM /* 312410309SSriharsha.Basavapatna@Sun.COM * The start() and stop() routines for the Hybrid resource below, are just 312510309SSriharsha.Basavapatna@Sun.COM * dummy functions. This is provided to avoid resource type specific code in 312610309SSriharsha.Basavapatna@Sun.COM * vnet_start_resources() and vnet_stop_resources(). The starting and stopping 312710309SSriharsha.Basavapatna@Sun.COM * of the Hybrid resource happens in the context of the mac_client interfaces 312810309SSriharsha.Basavapatna@Sun.COM * that are invoked in vnet_hio_mac_init() and vnet_hio_mac_cleanup(). 312910309SSriharsha.Basavapatna@Sun.COM */ 313010309SSriharsha.Basavapatna@Sun.COM /* ARGSUSED */ 313110309SSriharsha.Basavapatna@Sun.COM static int 313210309SSriharsha.Basavapatna@Sun.COM vnet_hio_start(void *arg) 313310309SSriharsha.Basavapatna@Sun.COM { 313410309SSriharsha.Basavapatna@Sun.COM return (0); 313510309SSriharsha.Basavapatna@Sun.COM } 313610309SSriharsha.Basavapatna@Sun.COM 313710309SSriharsha.Basavapatna@Sun.COM /* ARGSUSED */ 313810309SSriharsha.Basavapatna@Sun.COM static void 313910309SSriharsha.Basavapatna@Sun.COM vnet_hio_stop(void *arg) 314010309SSriharsha.Basavapatna@Sun.COM { 314110309SSriharsha.Basavapatna@Sun.COM } 314210309SSriharsha.Basavapatna@Sun.COM 314310309SSriharsha.Basavapatna@Sun.COM mblk_t * 314410309SSriharsha.Basavapatna@Sun.COM vnet_hio_tx(void *arg, mblk_t *mp) 314510309SSriharsha.Basavapatna@Sun.COM { 314610309SSriharsha.Basavapatna@Sun.COM vnet_pseudo_tx_ring_t *tx_ringp; 314710309SSriharsha.Basavapatna@Sun.COM mblk_t *nextp; 314810309SSriharsha.Basavapatna@Sun.COM mblk_t *ret_mp; 314910309SSriharsha.Basavapatna@Sun.COM 315010309SSriharsha.Basavapatna@Sun.COM tx_ringp = (vnet_pseudo_tx_ring_t *)arg; 315110309SSriharsha.Basavapatna@Sun.COM for (;;) { 315210309SSriharsha.Basavapatna@Sun.COM nextp = mp->b_next; 315310309SSriharsha.Basavapatna@Sun.COM mp->b_next = NULL; 315410309SSriharsha.Basavapatna@Sun.COM 315510309SSriharsha.Basavapatna@Sun.COM ret_mp = mac_hwring_tx(tx_ringp->hw_rh, mp); 315610309SSriharsha.Basavapatna@Sun.COM if (ret_mp != NULL) { 315710309SSriharsha.Basavapatna@Sun.COM ret_mp->b_next = nextp; 315810309SSriharsha.Basavapatna@Sun.COM mp = ret_mp; 315910309SSriharsha.Basavapatna@Sun.COM break; 316010309SSriharsha.Basavapatna@Sun.COM } 316110309SSriharsha.Basavapatna@Sun.COM 316210309SSriharsha.Basavapatna@Sun.COM if ((mp = nextp) == NULL) 316310309SSriharsha.Basavapatna@Sun.COM break; 316410309SSriharsha.Basavapatna@Sun.COM } 316510309SSriharsha.Basavapatna@Sun.COM return (mp); 316610309SSriharsha.Basavapatna@Sun.COM } 316710309SSriharsha.Basavapatna@Sun.COM 31689336SSriharsha.Basavapatna@Sun.COM #ifdef VNET_IOC_DEBUG 31699336SSriharsha.Basavapatna@Sun.COM 31709336SSriharsha.Basavapatna@Sun.COM /* 31719336SSriharsha.Basavapatna@Sun.COM * The ioctl entry point is used only for debugging for now. The ioctl commands 31729336SSriharsha.Basavapatna@Sun.COM * can be used to force the link state of the channel connected to vsw. 31739336SSriharsha.Basavapatna@Sun.COM */ 31749336SSriharsha.Basavapatna@Sun.COM static void 31759336SSriharsha.Basavapatna@Sun.COM vnet_m_ioctl(void *arg, queue_t *q, mblk_t *mp) 31769336SSriharsha.Basavapatna@Sun.COM { 31779336SSriharsha.Basavapatna@Sun.COM struct iocblk *iocp; 31789336SSriharsha.Basavapatna@Sun.COM vnet_t *vnetp; 31799336SSriharsha.Basavapatna@Sun.COM 31809336SSriharsha.Basavapatna@Sun.COM iocp = (struct iocblk *)(uintptr_t)mp->b_rptr; 31819336SSriharsha.Basavapatna@Sun.COM iocp->ioc_error = 0; 31829336SSriharsha.Basavapatna@Sun.COM vnetp = (vnet_t *)arg; 31839336SSriharsha.Basavapatna@Sun.COM 31849336SSriharsha.Basavapatna@Sun.COM if (vnetp == NULL) { 31859336SSriharsha.Basavapatna@Sun.COM miocnak(q, mp, 0, EINVAL); 31869336SSriharsha.Basavapatna@Sun.COM return; 31879336SSriharsha.Basavapatna@Sun.COM } 31889336SSriharsha.Basavapatna@Sun.COM 31899336SSriharsha.Basavapatna@Sun.COM switch (iocp->ioc_cmd) { 31909336SSriharsha.Basavapatna@Sun.COM 31919336SSriharsha.Basavapatna@Sun.COM case VNET_FORCE_LINK_DOWN: 31929336SSriharsha.Basavapatna@Sun.COM case VNET_FORCE_LINK_UP: 31939336SSriharsha.Basavapatna@Sun.COM vnet_force_link_state(vnetp, q, mp); 31949336SSriharsha.Basavapatna@Sun.COM break; 31959336SSriharsha.Basavapatna@Sun.COM 31969336SSriharsha.Basavapatna@Sun.COM default: 31979336SSriharsha.Basavapatna@Sun.COM iocp->ioc_error = EINVAL; 31989336SSriharsha.Basavapatna@Sun.COM miocnak(q, mp, 0, iocp->ioc_error); 31999336SSriharsha.Basavapatna@Sun.COM break; 32009336SSriharsha.Basavapatna@Sun.COM 32019336SSriharsha.Basavapatna@Sun.COM } 32029336SSriharsha.Basavapatna@Sun.COM } 32039336SSriharsha.Basavapatna@Sun.COM 32049336SSriharsha.Basavapatna@Sun.COM static void 32059336SSriharsha.Basavapatna@Sun.COM vnet_force_link_state(vnet_t *vnetp, queue_t *q, mblk_t *mp) 32069336SSriharsha.Basavapatna@Sun.COM { 32079336SSriharsha.Basavapatna@Sun.COM mac_register_t *macp; 32089336SSriharsha.Basavapatna@Sun.COM mac_callbacks_t *cbp; 32099336SSriharsha.Basavapatna@Sun.COM vnet_res_t *vresp; 32109336SSriharsha.Basavapatna@Sun.COM 32119336SSriharsha.Basavapatna@Sun.COM READ_ENTER(&vnetp->vsw_fp_rw); 32129336SSriharsha.Basavapatna@Sun.COM 32139336SSriharsha.Basavapatna@Sun.COM vresp = vnetp->vsw_fp; 32149336SSriharsha.Basavapatna@Sun.COM if (vresp == NULL) { 32159336SSriharsha.Basavapatna@Sun.COM RW_EXIT(&vnetp->vsw_fp_rw); 32169336SSriharsha.Basavapatna@Sun.COM return; 32179336SSriharsha.Basavapatna@Sun.COM } 32189336SSriharsha.Basavapatna@Sun.COM 32199336SSriharsha.Basavapatna@Sun.COM macp = &vresp->macreg; 32209336SSriharsha.Basavapatna@Sun.COM cbp = macp->m_callbacks; 32219336SSriharsha.Basavapatna@Sun.COM cbp->mc_ioctl(macp->m_driver, q, mp); 32229336SSriharsha.Basavapatna@Sun.COM 32239336SSriharsha.Basavapatna@Sun.COM RW_EXIT(&vnetp->vsw_fp_rw); 32249336SSriharsha.Basavapatna@Sun.COM } 32259336SSriharsha.Basavapatna@Sun.COM 32269336SSriharsha.Basavapatna@Sun.COM #else 32279336SSriharsha.Basavapatna@Sun.COM 32289336SSriharsha.Basavapatna@Sun.COM static void 32299336SSriharsha.Basavapatna@Sun.COM vnet_m_ioctl(void *arg, queue_t *q, mblk_t *mp) 32309336SSriharsha.Basavapatna@Sun.COM { 32319336SSriharsha.Basavapatna@Sun.COM vnet_t *vnetp; 32329336SSriharsha.Basavapatna@Sun.COM 32339336SSriharsha.Basavapatna@Sun.COM vnetp = (vnet_t *)arg; 32349336SSriharsha.Basavapatna@Sun.COM 32359336SSriharsha.Basavapatna@Sun.COM if (vnetp == NULL) { 32369336SSriharsha.Basavapatna@Sun.COM miocnak(q, mp, 0, EINVAL); 32379336SSriharsha.Basavapatna@Sun.COM return; 32389336SSriharsha.Basavapatna@Sun.COM } 32399336SSriharsha.Basavapatna@Sun.COM 32409336SSriharsha.Basavapatna@Sun.COM /* ioctl support only for debugging */ 32419336SSriharsha.Basavapatna@Sun.COM miocnak(q, mp, 0, ENOTSUP); 32429336SSriharsha.Basavapatna@Sun.COM } 32439336SSriharsha.Basavapatna@Sun.COM 32449336SSriharsha.Basavapatna@Sun.COM #endif 3245