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