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