18275SEric Cheng /*
28275SEric Cheng * CDDL HEADER START
38275SEric Cheng *
48275SEric Cheng * The contents of this file are subject to the terms of the
58275SEric Cheng * Common Development and Distribution License (the "License").
68275SEric Cheng * You may not use this file except in compliance with the License.
78275SEric Cheng *
88275SEric Cheng * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
98275SEric Cheng * or http://www.opensolaris.org/os/licensing.
108275SEric Cheng * See the License for the specific language governing permissions
118275SEric Cheng * and limitations under the License.
128275SEric Cheng *
138275SEric Cheng * When distributing Covered Code, include this CDDL HEADER in each
148275SEric Cheng * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
158275SEric Cheng * If applicable, add the following below this CDDL HEADER, with the
168275SEric Cheng * fields enclosed by brackets "[]" replaced with your own identifying
178275SEric Cheng * information: Portions Copyright [yyyy] [name of copyright owner]
188275SEric Cheng *
198275SEric Cheng * CDDL HEADER END
208275SEric Cheng */
218275SEric Cheng
228275SEric Cheng /*
2312850SPrakash.Jalan@Sun.COM * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
248275SEric Cheng */
258275SEric Cheng
268275SEric Cheng #include <sys/types.h>
278275SEric Cheng #include <sys/conf.h>
288275SEric Cheng #include <sys/id_space.h>
298275SEric Cheng #include <sys/esunddi.h>
308275SEric Cheng #include <sys/stat.h>
318275SEric Cheng #include <sys/mkdev.h>
328275SEric Cheng #include <sys/stream.h>
338275SEric Cheng #include <sys/strsubr.h>
348275SEric Cheng #include <sys/dlpi.h>
358275SEric Cheng #include <sys/modhash.h>
368275SEric Cheng #include <sys/mac.h>
378275SEric Cheng #include <sys/mac_provider.h>
388275SEric Cheng #include <sys/mac_impl.h>
398275SEric Cheng #include <sys/mac_client_impl.h>
408275SEric Cheng #include <sys/mac_client_priv.h>
418275SEric Cheng #include <sys/mac_soft_ring.h>
4211878SVenu.Iyer@Sun.COM #include <sys/mac_stat.h>
4310654SGarrett.Damore@Sun.COM #include <sys/dld.h>
448275SEric Cheng #include <sys/modctl.h>
458275SEric Cheng #include <sys/fs/dv_node.h>
468275SEric Cheng #include <sys/thread.h>
478275SEric Cheng #include <sys/proc.h>
488275SEric Cheng #include <sys/callb.h>
498275SEric Cheng #include <sys/cpuvar.h>
508275SEric Cheng #include <sys/atomic.h>
518275SEric Cheng #include <sys/sdt.h>
528275SEric Cheng #include <sys/mac_flow.h>
538275SEric Cheng #include <sys/ddi_intr_impl.h>
548275SEric Cheng #include <sys/disp.h>
558275SEric Cheng #include <sys/sdt.h>
5611878SVenu.Iyer@Sun.COM #include <sys/pattr.h>
5711878SVenu.Iyer@Sun.COM #include <sys/strsun.h>
588275SEric Cheng
598275SEric Cheng /*
608275SEric Cheng * MAC Provider Interface.
618275SEric Cheng *
628275SEric Cheng * Interface for GLDv3 compatible NIC drivers.
638275SEric Cheng */
648275SEric Cheng
658275SEric Cheng static void i_mac_notify_thread(void *);
668275SEric Cheng
678275SEric Cheng typedef void (*mac_notify_default_cb_fn_t)(mac_impl_t *);
688275SEric Cheng
6910491SRishi.Srivatsavai@Sun.COM static const mac_notify_default_cb_fn_t mac_notify_cb_list[MAC_NNOTE] = {
7010491SRishi.Srivatsavai@Sun.COM mac_fanout_recompute, /* MAC_NOTE_LINK */
7110491SRishi.Srivatsavai@Sun.COM NULL, /* MAC_NOTE_UNICST */
7210491SRishi.Srivatsavai@Sun.COM NULL, /* MAC_NOTE_TX */
7310491SRishi.Srivatsavai@Sun.COM NULL, /* MAC_NOTE_DEVPROMISC */
7410491SRishi.Srivatsavai@Sun.COM NULL, /* MAC_NOTE_FASTPATH_FLUSH */
7510491SRishi.Srivatsavai@Sun.COM NULL, /* MAC_NOTE_SDU_SIZE */
7610491SRishi.Srivatsavai@Sun.COM NULL, /* MAC_NOTE_MARGIN */
7710491SRishi.Srivatsavai@Sun.COM NULL, /* MAC_NOTE_CAPAB_CHG */
7810491SRishi.Srivatsavai@Sun.COM NULL /* MAC_NOTE_LOWLINK */
798275SEric Cheng };
808275SEric Cheng
818275SEric Cheng /*
828275SEric Cheng * Driver support functions.
838275SEric Cheng */
848275SEric Cheng
858275SEric Cheng /* REGISTRATION */
868275SEric Cheng
878275SEric Cheng mac_register_t *
mac_alloc(uint_t mac_version)888275SEric Cheng mac_alloc(uint_t mac_version)
898275SEric Cheng {
908275SEric Cheng mac_register_t *mregp;
918275SEric Cheng
928275SEric Cheng /*
938275SEric Cheng * Make sure there isn't a version mismatch between the driver and
948275SEric Cheng * the framework. In the future, if multiple versions are
958275SEric Cheng * supported, this check could become more sophisticated.
968275SEric Cheng */
978275SEric Cheng if (mac_version != MAC_VERSION)
988275SEric Cheng return (NULL);
998275SEric Cheng
1008275SEric Cheng mregp = kmem_zalloc(sizeof (mac_register_t), KM_SLEEP);
1018275SEric Cheng mregp->m_version = mac_version;
1028275SEric Cheng return (mregp);
1038275SEric Cheng }
1048275SEric Cheng
1058275SEric Cheng void
mac_free(mac_register_t * mregp)1068275SEric Cheng mac_free(mac_register_t *mregp)
1078275SEric Cheng {
1088275SEric Cheng kmem_free(mregp, sizeof (mac_register_t));
1098275SEric Cheng }
1108275SEric Cheng
1118275SEric Cheng /*
1128275SEric Cheng * mac_register() is how drivers register new MACs with the GLDv3
1138275SEric Cheng * framework. The mregp argument is allocated by drivers using the
1148275SEric Cheng * mac_alloc() function, and can be freed using mac_free() immediately upon
1158275SEric Cheng * return from mac_register(). Upon success (0 return value), the mhp
1168275SEric Cheng * opaque pointer becomes the driver's handle to its MAC interface, and is
1178275SEric Cheng * the argument to all other mac module entry points.
1188275SEric Cheng */
1198275SEric Cheng /* ARGSUSED */
1208275SEric Cheng int
mac_register(mac_register_t * mregp,mac_handle_t * mhp)1218275SEric Cheng mac_register(mac_register_t *mregp, mac_handle_t *mhp)
1228275SEric Cheng {
1238275SEric Cheng mac_impl_t *mip;
1248275SEric Cheng mactype_t *mtype;
1258275SEric Cheng int err = EINVAL;
1268275SEric Cheng struct devnames *dnp = NULL;
1278275SEric Cheng uint_t instance;
1288275SEric Cheng boolean_t style1_created = B_FALSE;
1298275SEric Cheng boolean_t style2_created = B_FALSE;
1308275SEric Cheng char *driver;
1318275SEric Cheng minor_t minor = 0;
1328275SEric Cheng
13310986SSebastien.Roy@Sun.COM /* A successful call to mac_init_ops() sets the DN_GLDV3_DRIVER flag. */
13410986SSebastien.Roy@Sun.COM if (!GLDV3_DRV(ddi_driver_major(mregp->m_dip)))
13510986SSebastien.Roy@Sun.COM return (EINVAL);
13610986SSebastien.Roy@Sun.COM
1378275SEric Cheng /* Find the required MAC-Type plugin. */
1388275SEric Cheng if ((mtype = mactype_getplugin(mregp->m_type_ident)) == NULL)
1398275SEric Cheng return (EINVAL);
1408275SEric Cheng
1418275SEric Cheng /* Create a mac_impl_t to represent this MAC. */
1428275SEric Cheng mip = kmem_cache_alloc(i_mac_impl_cachep, KM_SLEEP);
1438275SEric Cheng
1448275SEric Cheng /*
1458275SEric Cheng * The mac is not ready for open yet.
1468275SEric Cheng */
1478275SEric Cheng mip->mi_state_flags |= MIS_DISABLED;
1488275SEric Cheng
1498275SEric Cheng /*
1508275SEric Cheng * When a mac is registered, the m_instance field can be set to:
1518275SEric Cheng *
1528275SEric Cheng * 0: Get the mac's instance number from m_dip.
1538275SEric Cheng * This is usually used for physical device dips.
1548275SEric Cheng *
1558275SEric Cheng * [1 .. MAC_MAX_MINOR-1]: Use the value as the mac's instance number.
1568275SEric Cheng * For example, when an aggregation is created with the key option,
1578275SEric Cheng * "key" will be used as the instance number.
1588275SEric Cheng *
1598275SEric Cheng * -1: Assign an instance number from [MAC_MAX_MINOR .. MAXMIN-1].
1608275SEric Cheng * This is often used when a MAC of a virtual link is registered
1618275SEric Cheng * (e.g., aggregation when "key" is not specified, or vnic).
1628275SEric Cheng *
1638275SEric Cheng * Note that the instance number is used to derive the mi_minor field
1648275SEric Cheng * of mac_impl_t, which will then be used to derive the name of kstats
1658275SEric Cheng * and the devfs nodes. The first 2 cases are needed to preserve
1668275SEric Cheng * backward compatibility.
1678275SEric Cheng */
1688275SEric Cheng switch (mregp->m_instance) {
1698275SEric Cheng case 0:
1708275SEric Cheng instance = ddi_get_instance(mregp->m_dip);
1718275SEric Cheng break;
1728275SEric Cheng case ((uint_t)-1):
1738275SEric Cheng minor = mac_minor_hold(B_TRUE);
1748275SEric Cheng if (minor == 0) {
1758275SEric Cheng err = ENOSPC;
1768275SEric Cheng goto fail;
1778275SEric Cheng }
1788275SEric Cheng instance = minor - 1;
1798275SEric Cheng break;
1808275SEric Cheng default:
1818275SEric Cheng instance = mregp->m_instance;
1828275SEric Cheng if (instance >= MAC_MAX_MINOR) {
1838275SEric Cheng err = EINVAL;
1848275SEric Cheng goto fail;
1858275SEric Cheng }
1868275SEric Cheng break;
1878275SEric Cheng }
1888275SEric Cheng
1898275SEric Cheng mip->mi_minor = (minor_t)(instance + 1);
1908275SEric Cheng mip->mi_dip = mregp->m_dip;
1918275SEric Cheng mip->mi_clients_list = NULL;
1928275SEric Cheng mip->mi_nclients = 0;
1938275SEric Cheng
19410491SRishi.Srivatsavai@Sun.COM /* Set the default IEEE Port VLAN Identifier */
19510491SRishi.Srivatsavai@Sun.COM mip->mi_pvid = 1;
19610491SRishi.Srivatsavai@Sun.COM
19710491SRishi.Srivatsavai@Sun.COM /* Default bridge link learning protection values */
19810491SRishi.Srivatsavai@Sun.COM mip->mi_llimit = 1000;
19910491SRishi.Srivatsavai@Sun.COM mip->mi_ldecay = 200;
20010491SRishi.Srivatsavai@Sun.COM
2018275SEric Cheng driver = (char *)ddi_driver_name(mip->mi_dip);
2028275SEric Cheng
2038275SEric Cheng /* Construct the MAC name as <drvname><instance> */
2048275SEric Cheng (void) snprintf(mip->mi_name, sizeof (mip->mi_name), "%s%d",
2058275SEric Cheng driver, instance);
2068275SEric Cheng
2078275SEric Cheng mip->mi_driver = mregp->m_driver;
2088275SEric Cheng
2098275SEric Cheng mip->mi_type = mtype;
2108275SEric Cheng mip->mi_margin = mregp->m_margin;
2118275SEric Cheng mip->mi_info.mi_media = mtype->mt_type;
2128275SEric Cheng mip->mi_info.mi_nativemedia = mtype->mt_nativetype;
2138275SEric Cheng if (mregp->m_max_sdu <= mregp->m_min_sdu)
2148275SEric Cheng goto fail;
215*13123SErik.Nordmark@Sun.COM if (mregp->m_multicast_sdu == 0)
216*13123SErik.Nordmark@Sun.COM mregp->m_multicast_sdu = mregp->m_max_sdu;
217*13123SErik.Nordmark@Sun.COM if (mregp->m_multicast_sdu < mregp->m_min_sdu ||
218*13123SErik.Nordmark@Sun.COM mregp->m_multicast_sdu > mregp->m_max_sdu)
219*13123SErik.Nordmark@Sun.COM goto fail;
2208275SEric Cheng mip->mi_sdu_min = mregp->m_min_sdu;
2218275SEric Cheng mip->mi_sdu_max = mregp->m_max_sdu;
222*13123SErik.Nordmark@Sun.COM mip->mi_sdu_multicast = mregp->m_multicast_sdu;
2238275SEric Cheng mip->mi_info.mi_addr_length = mip->mi_type->mt_addr_length;
2248275SEric Cheng /*
2258275SEric Cheng * If the media supports a broadcast address, cache a pointer to it
2268275SEric Cheng * in the mac_info_t so that upper layers can use it.
2278275SEric Cheng */
2288275SEric Cheng mip->mi_info.mi_brdcst_addr = mip->mi_type->mt_brdcst_addr;
2298275SEric Cheng
2308275SEric Cheng mip->mi_v12n_level = mregp->m_v12n;
2318275SEric Cheng
2328275SEric Cheng /*
2338275SEric Cheng * Copy the unicast source address into the mac_info_t, but only if
2348275SEric Cheng * the MAC-Type defines a non-zero address length. We need to
2358275SEric Cheng * handle MAC-Types that have an address length of 0
2368275SEric Cheng * (point-to-point protocol MACs for example).
2378275SEric Cheng */
2388275SEric Cheng if (mip->mi_type->mt_addr_length > 0) {
2398275SEric Cheng if (mregp->m_src_addr == NULL)
2408275SEric Cheng goto fail;
2418275SEric Cheng mip->mi_info.mi_unicst_addr =
2428275SEric Cheng kmem_alloc(mip->mi_type->mt_addr_length, KM_SLEEP);
2438275SEric Cheng bcopy(mregp->m_src_addr, mip->mi_info.mi_unicst_addr,
2448275SEric Cheng mip->mi_type->mt_addr_length);
2458275SEric Cheng
2468275SEric Cheng /*
2478275SEric Cheng * Copy the fixed 'factory' MAC address from the immutable
2488275SEric Cheng * info. This is taken to be the MAC address currently in
2498275SEric Cheng * use.
2508275SEric Cheng */
2518275SEric Cheng bcopy(mip->mi_info.mi_unicst_addr, mip->mi_addr,
2528275SEric Cheng mip->mi_type->mt_addr_length);
2538275SEric Cheng
2548275SEric Cheng /*
2558275SEric Cheng * At this point, we should set up the classification
2568275SEric Cheng * rules etc but we delay it till mac_open() so that
2578275SEric Cheng * the resource discovery has taken place and we
2588275SEric Cheng * know someone wants to use the device. Otherwise
2598275SEric Cheng * memory gets allocated for Rx ring structures even
2608275SEric Cheng * during probe.
2618275SEric Cheng */
2628275SEric Cheng
2638275SEric Cheng /* Copy the destination address if one is provided. */
2648275SEric Cheng if (mregp->m_dst_addr != NULL) {
2658275SEric Cheng bcopy(mregp->m_dst_addr, mip->mi_dstaddr,
2668275SEric Cheng mip->mi_type->mt_addr_length);
26710616SSebastien.Roy@Sun.COM mip->mi_dstaddr_set = B_TRUE;
2688275SEric Cheng }
2698275SEric Cheng } else if (mregp->m_src_addr != NULL) {
2708275SEric Cheng goto fail;
2718275SEric Cheng }
2728275SEric Cheng
2738275SEric Cheng /*
2748275SEric Cheng * The format of the m_pdata is specific to the plugin. It is
2758275SEric Cheng * passed in as an argument to all of the plugin callbacks. The
2768275SEric Cheng * driver can update this information by calling
2778275SEric Cheng * mac_pdata_update().
2788275SEric Cheng */
27910616SSebastien.Roy@Sun.COM if (mip->mi_type->mt_ops.mtops_ops & MTOPS_PDATA_VERIFY) {
2808275SEric Cheng /*
28110616SSebastien.Roy@Sun.COM * Verify if the supplied plugin data is valid. Note that
28210616SSebastien.Roy@Sun.COM * even if the caller passed in a NULL pointer as plugin data,
28310616SSebastien.Roy@Sun.COM * we still need to verify if that's valid as the plugin may
28410616SSebastien.Roy@Sun.COM * require plugin data to function.
2858275SEric Cheng */
2868275SEric Cheng if (!mip->mi_type->mt_ops.mtops_pdata_verify(mregp->m_pdata,
2878275SEric Cheng mregp->m_pdata_size)) {
2888275SEric Cheng goto fail;
2898275SEric Cheng }
29010616SSebastien.Roy@Sun.COM if (mregp->m_pdata != NULL) {
29110616SSebastien.Roy@Sun.COM mip->mi_pdata =
29210616SSebastien.Roy@Sun.COM kmem_alloc(mregp->m_pdata_size, KM_SLEEP);
29310616SSebastien.Roy@Sun.COM bcopy(mregp->m_pdata, mip->mi_pdata,
29410616SSebastien.Roy@Sun.COM mregp->m_pdata_size);
29510616SSebastien.Roy@Sun.COM mip->mi_pdata_size = mregp->m_pdata_size;
29610616SSebastien.Roy@Sun.COM }
29710616SSebastien.Roy@Sun.COM } else if (mregp->m_pdata != NULL) {
29810616SSebastien.Roy@Sun.COM /*
29910616SSebastien.Roy@Sun.COM * The caller supplied non-NULL plugin data, but the plugin
30010616SSebastien.Roy@Sun.COM * does not recognize plugin data.
30110616SSebastien.Roy@Sun.COM */
30210616SSebastien.Roy@Sun.COM err = EINVAL;
30310616SSebastien.Roy@Sun.COM goto fail;
3048275SEric Cheng }
3058275SEric Cheng
3068275SEric Cheng /*
3078275SEric Cheng * Register the private properties.
3088275SEric Cheng */
30911878SVenu.Iyer@Sun.COM mac_register_priv_prop(mip, mregp->m_priv_props);
3108275SEric Cheng
3118275SEric Cheng /*
3128275SEric Cheng * Stash the driver callbacks into the mac_impl_t, but first sanity
3138275SEric Cheng * check to make sure all mandatory callbacks are set.
3148275SEric Cheng */
3158275SEric Cheng if (mregp->m_callbacks->mc_getstat == NULL ||
3168275SEric Cheng mregp->m_callbacks->mc_start == NULL ||
3178275SEric Cheng mregp->m_callbacks->mc_stop == NULL ||
3188275SEric Cheng mregp->m_callbacks->mc_setpromisc == NULL ||
3198275SEric Cheng mregp->m_callbacks->mc_multicst == NULL) {
3208275SEric Cheng goto fail;
3218275SEric Cheng }
3228275SEric Cheng mip->mi_callbacks = mregp->m_callbacks;
3238275SEric Cheng
3249073SCathy.Zhou@Sun.COM if (mac_capab_get((mac_handle_t)mip, MAC_CAPAB_LEGACY,
3259073SCathy.Zhou@Sun.COM &mip->mi_capab_legacy)) {
3268275SEric Cheng mip->mi_state_flags |= MIS_LEGACY;
3279073SCathy.Zhou@Sun.COM mip->mi_phy_dev = mip->mi_capab_legacy.ml_dev;
3288275SEric Cheng } else {
3298275SEric Cheng mip->mi_phy_dev = makedevice(ddi_driver_major(mip->mi_dip),
33010654SGarrett.Damore@Sun.COM mip->mi_minor);
3318275SEric Cheng }
3328275SEric Cheng
3338275SEric Cheng /*
3348275SEric Cheng * Allocate a notification thread. thread_create blocks for memory
3358275SEric Cheng * if needed, it never fails.
3368275SEric Cheng */
3378275SEric Cheng mip->mi_notify_thread = thread_create(NULL, 0, i_mac_notify_thread,
3388275SEric Cheng mip, 0, &p0, TS_RUN, minclsyspri);
3398275SEric Cheng
3408275SEric Cheng /*
3418275SEric Cheng * Initialize the capabilities
3428275SEric Cheng */
3438275SEric Cheng
34411878SVenu.Iyer@Sun.COM bzero(&mip->mi_rx_rings_cap, sizeof (mac_capab_rings_t));
34511878SVenu.Iyer@Sun.COM bzero(&mip->mi_tx_rings_cap, sizeof (mac_capab_rings_t));
34611878SVenu.Iyer@Sun.COM
3478275SEric Cheng if (i_mac_capab_get((mac_handle_t)mip, MAC_CAPAB_VNIC, NULL))
3488275SEric Cheng mip->mi_state_flags |= MIS_IS_VNIC;
3498275SEric Cheng
3508275SEric Cheng if (i_mac_capab_get((mac_handle_t)mip, MAC_CAPAB_AGGR, NULL))
3518275SEric Cheng mip->mi_state_flags |= MIS_IS_AGGR;
3528275SEric Cheng
3538275SEric Cheng mac_addr_factory_init(mip);
3548275SEric Cheng
3558275SEric Cheng /*
3568275SEric Cheng * Enforce the virtrualization level registered.
3578275SEric Cheng */
3588275SEric Cheng if (mip->mi_v12n_level & MAC_VIRT_LEVEL1) {
3598275SEric Cheng if (mac_init_rings(mip, MAC_RING_TYPE_RX) != 0 ||
3608275SEric Cheng mac_init_rings(mip, MAC_RING_TYPE_TX) != 0)
3618275SEric Cheng goto fail;
3628275SEric Cheng
3638275SEric Cheng /*
3648275SEric Cheng * The driver needs to register at least rx rings for this
3658275SEric Cheng * virtualization level.
3668275SEric Cheng */
3678275SEric Cheng if (mip->mi_rx_groups == NULL)
3688275SEric Cheng goto fail;
3698275SEric Cheng }
3708275SEric Cheng
3718275SEric Cheng /*
3728275SEric Cheng * The driver must set mc_unicst entry point to NULL when it advertises
3738275SEric Cheng * CAP_RINGS for rx groups.
3748275SEric Cheng */
3758275SEric Cheng if (mip->mi_rx_groups != NULL) {
3768275SEric Cheng if (mregp->m_callbacks->mc_unicst != NULL)
3778275SEric Cheng goto fail;
3788275SEric Cheng } else {
3798275SEric Cheng if (mregp->m_callbacks->mc_unicst == NULL)
3808275SEric Cheng goto fail;
3818275SEric Cheng }
3828275SEric Cheng
3838275SEric Cheng /*
3848275SEric Cheng * Initialize MAC addresses. Must be called after mac_init_rings().
3858275SEric Cheng */
3868275SEric Cheng mac_init_macaddr(mip);
3878275SEric Cheng
3888275SEric Cheng mip->mi_share_capab.ms_snum = 0;
3898275SEric Cheng if (mip->mi_v12n_level & MAC_VIRT_HIO) {
3908275SEric Cheng (void) mac_capab_get((mac_handle_t)mip, MAC_CAPAB_SHARES,
3918275SEric Cheng &mip->mi_share_capab);
3928275SEric Cheng }
3938275SEric Cheng
3948275SEric Cheng /*
3958275SEric Cheng * Initialize the kstats for this device.
3968275SEric Cheng */
39711878SVenu.Iyer@Sun.COM mac_driver_stat_create(mip);
3988275SEric Cheng
3998275SEric Cheng /* Zero out any properties. */
4008275SEric Cheng bzero(&mip->mi_resource_props, sizeof (mac_resource_props_t));
4018275SEric Cheng
40210727Sgdamore@opensolaris.org if (mip->mi_minor <= MAC_MAX_MINOR) {
4038275SEric Cheng /* Create a style-2 DLPI device */
4048275SEric Cheng if (ddi_create_minor_node(mip->mi_dip, driver, S_IFCHR, 0,
4058275SEric Cheng DDI_NT_NET, CLONE_DEV) != DDI_SUCCESS)
4068275SEric Cheng goto fail;
4078275SEric Cheng style2_created = B_TRUE;
4088275SEric Cheng
4098275SEric Cheng /* Create a style-1 DLPI device */
4108275SEric Cheng if (ddi_create_minor_node(mip->mi_dip, mip->mi_name, S_IFCHR,
4118275SEric Cheng mip->mi_minor, DDI_NT_NET, 0) != DDI_SUCCESS)
4128275SEric Cheng goto fail;
4138275SEric Cheng style1_created = B_TRUE;
4148275SEric Cheng }
4158275SEric Cheng
4168275SEric Cheng mac_flow_l2tab_create(mip, &mip->mi_flow_tab);
4178275SEric Cheng
4188275SEric Cheng rw_enter(&i_mac_impl_lock, RW_WRITER);
4198275SEric Cheng if (mod_hash_insert(i_mac_impl_hash,
4208275SEric Cheng (mod_hash_key_t)mip->mi_name, (mod_hash_val_t)mip) != 0) {
4218275SEric Cheng rw_exit(&i_mac_impl_lock);
4228275SEric Cheng err = EEXIST;
4238275SEric Cheng goto fail;
4248275SEric Cheng }
4258275SEric Cheng
4268275SEric Cheng DTRACE_PROBE2(mac__register, struct devnames *, dnp,
4278275SEric Cheng (mac_impl_t *), mip);
4288275SEric Cheng
4298275SEric Cheng /*
4308275SEric Cheng * Mark the MAC to be ready for open.
4318275SEric Cheng */
4328275SEric Cheng mip->mi_state_flags &= ~MIS_DISABLED;
4338275SEric Cheng rw_exit(&i_mac_impl_lock);
4348275SEric Cheng
4358275SEric Cheng atomic_inc_32(&i_mac_impl_count);
4368275SEric Cheng
4378275SEric Cheng cmn_err(CE_NOTE, "!%s registered", mip->mi_name);
4388275SEric Cheng *mhp = (mac_handle_t)mip;
4398275SEric Cheng return (0);
4408275SEric Cheng
4418275SEric Cheng fail:
4428275SEric Cheng if (style1_created)
4438275SEric Cheng ddi_remove_minor_node(mip->mi_dip, mip->mi_name);
4448275SEric Cheng
4458275SEric Cheng if (style2_created)
4468275SEric Cheng ddi_remove_minor_node(mip->mi_dip, driver);
4478275SEric Cheng
4488275SEric Cheng mac_addr_factory_fini(mip);
4498275SEric Cheng
4508275SEric Cheng /* Clean up registered MAC addresses */
4518275SEric Cheng mac_fini_macaddr(mip);
4528275SEric Cheng
4538275SEric Cheng /* Clean up registered rings */
4548275SEric Cheng mac_free_rings(mip, MAC_RING_TYPE_RX);
4558275SEric Cheng mac_free_rings(mip, MAC_RING_TYPE_TX);
4568275SEric Cheng
4578275SEric Cheng /* Clean up notification thread */
4588275SEric Cheng if (mip->mi_notify_thread != NULL)
4598275SEric Cheng i_mac_notify_exit(mip);
4608275SEric Cheng
4618275SEric Cheng if (mip->mi_info.mi_unicst_addr != NULL) {
4628275SEric Cheng kmem_free(mip->mi_info.mi_unicst_addr,
4638275SEric Cheng mip->mi_type->mt_addr_length);
4648275SEric Cheng mip->mi_info.mi_unicst_addr = NULL;
4658275SEric Cheng }
4668275SEric Cheng
46711878SVenu.Iyer@Sun.COM mac_driver_stat_delete(mip);
4688275SEric Cheng
4698275SEric Cheng if (mip->mi_type != NULL) {
4708275SEric Cheng atomic_dec_32(&mip->mi_type->mt_ref);
4718275SEric Cheng mip->mi_type = NULL;
4728275SEric Cheng }
4738275SEric Cheng
4748275SEric Cheng if (mip->mi_pdata != NULL) {
4758275SEric Cheng kmem_free(mip->mi_pdata, mip->mi_pdata_size);
4768275SEric Cheng mip->mi_pdata = NULL;
4778275SEric Cheng mip->mi_pdata_size = 0;
4788275SEric Cheng }
4798275SEric Cheng
4808275SEric Cheng if (minor != 0) {
4818275SEric Cheng ASSERT(minor > MAC_MAX_MINOR);
4828275SEric Cheng mac_minor_rele(minor);
4838275SEric Cheng }
4848275SEric Cheng
48511878SVenu.Iyer@Sun.COM mip->mi_state_flags = 0;
4868275SEric Cheng mac_unregister_priv_prop(mip);
4878275SEric Cheng
48811544SMichael.Speer@Sun.COM /*
48911544SMichael.Speer@Sun.COM * Clear the state before destroying the mac_impl_t
49011544SMichael.Speer@Sun.COM */
49111544SMichael.Speer@Sun.COM mip->mi_state_flags = 0;
49211544SMichael.Speer@Sun.COM
4938275SEric Cheng kmem_cache_free(i_mac_impl_cachep, mip);
4948275SEric Cheng return (err);
4958275SEric Cheng }
4968275SEric Cheng
4978275SEric Cheng /*
4988275SEric Cheng * Unregister from the GLDv3 framework
4998275SEric Cheng */
5008275SEric Cheng int
mac_unregister(mac_handle_t mh)5018275SEric Cheng mac_unregister(mac_handle_t mh)
5028275SEric Cheng {
5038275SEric Cheng int err;
5048275SEric Cheng mac_impl_t *mip = (mac_impl_t *)mh;
5058275SEric Cheng mod_hash_val_t val;
5068275SEric Cheng mac_margin_req_t *mmr, *nextmmr;
5078275SEric Cheng
5088275SEric Cheng /* Fail the unregister if there are any open references to this mac. */
5098275SEric Cheng if ((err = mac_disable_nowait(mh)) != 0)
5108275SEric Cheng return (err);
5118275SEric Cheng
5128275SEric Cheng /*
5138275SEric Cheng * Clean up notification thread and wait for it to exit.
5148275SEric Cheng */
5158275SEric Cheng i_mac_notify_exit(mip);
5168275SEric Cheng
5178275SEric Cheng i_mac_perim_enter(mip);
5188275SEric Cheng
5199073SCathy.Zhou@Sun.COM /*
5209073SCathy.Zhou@Sun.COM * There is still resource properties configured over this mac.
5219073SCathy.Zhou@Sun.COM */
5229073SCathy.Zhou@Sun.COM if (mip->mi_resource_props.mrp_mask != 0)
5239073SCathy.Zhou@Sun.COM mac_fastpath_enable((mac_handle_t)mip);
5249073SCathy.Zhou@Sun.COM
5258275SEric Cheng if (mip->mi_minor < MAC_MAX_MINOR + 1) {
5268275SEric Cheng ddi_remove_minor_node(mip->mi_dip, mip->mi_name);
5278275SEric Cheng ddi_remove_minor_node(mip->mi_dip,
5288275SEric Cheng (char *)ddi_driver_name(mip->mi_dip));
5298275SEric Cheng }
5308275SEric Cheng
5318275SEric Cheng ASSERT(mip->mi_nactiveclients == 0 && !(mip->mi_state_flags &
5328275SEric Cheng MIS_EXCLUSIVE));
5338275SEric Cheng
53411878SVenu.Iyer@Sun.COM mac_driver_stat_delete(mip);
5358275SEric Cheng
5368275SEric Cheng (void) mod_hash_remove(i_mac_impl_hash,
5378275SEric Cheng (mod_hash_key_t)mip->mi_name, &val);
5388275SEric Cheng ASSERT(mip == (mac_impl_t *)val);
5398275SEric Cheng
5408275SEric Cheng ASSERT(i_mac_impl_count > 0);
5418275SEric Cheng atomic_dec_32(&i_mac_impl_count);
5428275SEric Cheng
5438275SEric Cheng if (mip->mi_pdata != NULL)
5448275SEric Cheng kmem_free(mip->mi_pdata, mip->mi_pdata_size);
5458275SEric Cheng mip->mi_pdata = NULL;
5468275SEric Cheng mip->mi_pdata_size = 0;
5478275SEric Cheng
5488275SEric Cheng /*
5498275SEric Cheng * Free the list of margin request.
5508275SEric Cheng */
5518275SEric Cheng for (mmr = mip->mi_mmrp; mmr != NULL; mmr = nextmmr) {
5528275SEric Cheng nextmmr = mmr->mmr_nextp;
5538275SEric Cheng kmem_free(mmr, sizeof (mac_margin_req_t));
5548275SEric Cheng }
5558275SEric Cheng mip->mi_mmrp = NULL;
5568275SEric Cheng
55710491SRishi.Srivatsavai@Sun.COM mip->mi_linkstate = mip->mi_lowlinkstate = LINK_STATE_UNKNOWN;
5588275SEric Cheng kmem_free(mip->mi_info.mi_unicst_addr, mip->mi_type->mt_addr_length);
5598275SEric Cheng mip->mi_info.mi_unicst_addr = NULL;
5608275SEric Cheng
5618275SEric Cheng atomic_dec_32(&mip->mi_type->mt_ref);
5628275SEric Cheng mip->mi_type = NULL;
5638275SEric Cheng
5648275SEric Cheng /*
5658275SEric Cheng * Free the primary MAC address.
5668275SEric Cheng */
5678275SEric Cheng mac_fini_macaddr(mip);
5688275SEric Cheng
5698275SEric Cheng /*
5708275SEric Cheng * free all rings
5718275SEric Cheng */
5728275SEric Cheng mac_free_rings(mip, MAC_RING_TYPE_RX);
5738275SEric Cheng mac_free_rings(mip, MAC_RING_TYPE_TX);
5748275SEric Cheng
5758275SEric Cheng mac_addr_factory_fini(mip);
5768275SEric Cheng
5778275SEric Cheng bzero(mip->mi_addr, MAXMACADDRLEN);
5788275SEric Cheng bzero(mip->mi_dstaddr, MAXMACADDRLEN);
5798275SEric Cheng
5808275SEric Cheng /* and the flows */
5818275SEric Cheng mac_flow_tab_destroy(mip->mi_flow_tab);
5828275SEric Cheng mip->mi_flow_tab = NULL;
5838275SEric Cheng
5848275SEric Cheng if (mip->mi_minor > MAC_MAX_MINOR)
5858275SEric Cheng mac_minor_rele(mip->mi_minor);
5868275SEric Cheng
5878275SEric Cheng cmn_err(CE_NOTE, "!%s unregistered", mip->mi_name);
5888275SEric Cheng
5898275SEric Cheng /*
5908275SEric Cheng * Reset the perim related fields to default values before
5918275SEric Cheng * kmem_cache_free
5928275SEric Cheng */
5938275SEric Cheng i_mac_perim_exit(mip);
5948275SEric Cheng mip->mi_state_flags = 0;
5958275SEric Cheng
5968275SEric Cheng mac_unregister_priv_prop(mip);
59710491SRishi.Srivatsavai@Sun.COM
59810491SRishi.Srivatsavai@Sun.COM ASSERT(mip->mi_bridge_link == NULL);
5998275SEric Cheng kmem_cache_free(i_mac_impl_cachep, mip);
6008275SEric Cheng
6018275SEric Cheng return (0);
6028275SEric Cheng }
6038275SEric Cheng
6048275SEric Cheng /* DATA RECEPTION */
6058275SEric Cheng
6068275SEric Cheng /*
6078275SEric Cheng * This function is invoked for packets received by the MAC driver in
6088275SEric Cheng * interrupt context. The ring generation number provided by the driver
6098275SEric Cheng * is matched with the ring generation number held in MAC. If they do not
6108275SEric Cheng * match, received packets are considered stale packets coming from an older
6118275SEric Cheng * assignment of the ring. Drop them.
6128275SEric Cheng */
6138275SEric Cheng void
mac_rx_ring(mac_handle_t mh,mac_ring_handle_t mrh,mblk_t * mp_chain,uint64_t mr_gen_num)6148275SEric Cheng mac_rx_ring(mac_handle_t mh, mac_ring_handle_t mrh, mblk_t *mp_chain,
6158275SEric Cheng uint64_t mr_gen_num)
6168275SEric Cheng {
6178275SEric Cheng mac_ring_t *mr = (mac_ring_t *)mrh;
6188275SEric Cheng
6198275SEric Cheng if ((mr != NULL) && (mr->mr_gen_num != mr_gen_num)) {
6208275SEric Cheng DTRACE_PROBE2(mac__rx__rings__stale__packet, uint64_t,
6218275SEric Cheng mr->mr_gen_num, uint64_t, mr_gen_num);
6228275SEric Cheng freemsgchain(mp_chain);
6238275SEric Cheng return;
6248275SEric Cheng }
6258275SEric Cheng mac_rx(mh, (mac_resource_handle_t)mrh, mp_chain);
6268275SEric Cheng }
6278275SEric Cheng
6288275SEric Cheng /*
62910491SRishi.Srivatsavai@Sun.COM * This function is invoked for each packet received by the underlying driver.
6308275SEric Cheng */
6318275SEric Cheng void
mac_rx(mac_handle_t mh,mac_resource_handle_t mrh,mblk_t * mp_chain)6328275SEric Cheng mac_rx(mac_handle_t mh, mac_resource_handle_t mrh, mblk_t *mp_chain)
6338275SEric Cheng {
63410491SRishi.Srivatsavai@Sun.COM mac_impl_t *mip = (mac_impl_t *)mh;
63510491SRishi.Srivatsavai@Sun.COM
63610491SRishi.Srivatsavai@Sun.COM /*
63710491SRishi.Srivatsavai@Sun.COM * Check if the link is part of a bridge. If not, then we don't need
63810491SRishi.Srivatsavai@Sun.COM * to take the lock to remain consistent. Make this common case
63910491SRishi.Srivatsavai@Sun.COM * lock-free and tail-call optimized.
64010491SRishi.Srivatsavai@Sun.COM */
64110491SRishi.Srivatsavai@Sun.COM if (mip->mi_bridge_link == NULL) {
64210491SRishi.Srivatsavai@Sun.COM mac_rx_common(mh, mrh, mp_chain);
64310491SRishi.Srivatsavai@Sun.COM } else {
64410491SRishi.Srivatsavai@Sun.COM /*
64510491SRishi.Srivatsavai@Sun.COM * Once we take a reference on the bridge link, the bridge
64610491SRishi.Srivatsavai@Sun.COM * module itself can't unload, so the callback pointers are
64710491SRishi.Srivatsavai@Sun.COM * stable.
64810491SRishi.Srivatsavai@Sun.COM */
64910491SRishi.Srivatsavai@Sun.COM mutex_enter(&mip->mi_bridge_lock);
65010491SRishi.Srivatsavai@Sun.COM if ((mh = mip->mi_bridge_link) != NULL)
65110491SRishi.Srivatsavai@Sun.COM mac_bridge_ref_cb(mh, B_TRUE);
65210491SRishi.Srivatsavai@Sun.COM mutex_exit(&mip->mi_bridge_lock);
65310491SRishi.Srivatsavai@Sun.COM if (mh == NULL) {
65410491SRishi.Srivatsavai@Sun.COM mac_rx_common((mac_handle_t)mip, mrh, mp_chain);
65510491SRishi.Srivatsavai@Sun.COM } else {
65610491SRishi.Srivatsavai@Sun.COM mac_bridge_rx_cb(mh, mrh, mp_chain);
65710491SRishi.Srivatsavai@Sun.COM mac_bridge_ref_cb(mh, B_FALSE);
65810491SRishi.Srivatsavai@Sun.COM }
65910491SRishi.Srivatsavai@Sun.COM }
66010491SRishi.Srivatsavai@Sun.COM }
66110491SRishi.Srivatsavai@Sun.COM
66210491SRishi.Srivatsavai@Sun.COM /*
66310491SRishi.Srivatsavai@Sun.COM * Special case function: this allows snooping of packets transmitted and
66410491SRishi.Srivatsavai@Sun.COM * received by TRILL. By design, they go directly into the TRILL module.
66510491SRishi.Srivatsavai@Sun.COM */
66610491SRishi.Srivatsavai@Sun.COM void
mac_trill_snoop(mac_handle_t mh,mblk_t * mp)66710491SRishi.Srivatsavai@Sun.COM mac_trill_snoop(mac_handle_t mh, mblk_t *mp)
66810491SRishi.Srivatsavai@Sun.COM {
66910491SRishi.Srivatsavai@Sun.COM mac_impl_t *mip = (mac_impl_t *)mh;
67010491SRishi.Srivatsavai@Sun.COM
67110491SRishi.Srivatsavai@Sun.COM if (mip->mi_promisc_list != NULL)
67210491SRishi.Srivatsavai@Sun.COM mac_promisc_dispatch(mip, mp, NULL);
67310491SRishi.Srivatsavai@Sun.COM }
67410491SRishi.Srivatsavai@Sun.COM
67510491SRishi.Srivatsavai@Sun.COM /*
67610491SRishi.Srivatsavai@Sun.COM * This is the upward reentry point for packets arriving from the bridging
67710491SRishi.Srivatsavai@Sun.COM * module and from mac_rx for links not part of a bridge.
67810491SRishi.Srivatsavai@Sun.COM */
67910491SRishi.Srivatsavai@Sun.COM void
mac_rx_common(mac_handle_t mh,mac_resource_handle_t mrh,mblk_t * mp_chain)68010491SRishi.Srivatsavai@Sun.COM mac_rx_common(mac_handle_t mh, mac_resource_handle_t mrh, mblk_t *mp_chain)
68110491SRishi.Srivatsavai@Sun.COM {
6828275SEric Cheng mac_impl_t *mip = (mac_impl_t *)mh;
6838275SEric Cheng mac_ring_t *mr = (mac_ring_t *)mrh;
6848275SEric Cheng mac_soft_ring_set_t *mac_srs;
6858275SEric Cheng mblk_t *bp = mp_chain;
6868275SEric Cheng boolean_t hw_classified = B_FALSE;
6878275SEric Cheng
6888275SEric Cheng /*
6898275SEric Cheng * If there are any promiscuous mode callbacks defined for
6908275SEric Cheng * this MAC, pass them a copy if appropriate.
6918275SEric Cheng */
6928275SEric Cheng if (mip->mi_promisc_list != NULL)
6938275SEric Cheng mac_promisc_dispatch(mip, mp_chain, NULL);
6948275SEric Cheng
6958275SEric Cheng if (mr != NULL) {
6968275SEric Cheng /*
6978275SEric Cheng * If the SRS teardown has started, just return. The 'mr'
6988275SEric Cheng * continues to be valid until the driver unregisters the mac.
6998275SEric Cheng * Hardware classified packets will not make their way up
7008275SEric Cheng * beyond this point once the teardown has started. The driver
7018275SEric Cheng * is never passed a pointer to a flow entry or SRS or any
7028275SEric Cheng * structure that can be freed much before mac_unregister.
7038275SEric Cheng */
7048275SEric Cheng mutex_enter(&mr->mr_lock);
7058275SEric Cheng if ((mr->mr_state != MR_INUSE) || (mr->mr_flag &
7068275SEric Cheng (MR_INCIPIENT | MR_CONDEMNED | MR_QUIESCE))) {
7078275SEric Cheng mutex_exit(&mr->mr_lock);
7088275SEric Cheng freemsgchain(mp_chain);
7098275SEric Cheng return;
7108275SEric Cheng }
7118275SEric Cheng if (mr->mr_classify_type == MAC_HW_CLASSIFIER) {
7128275SEric Cheng hw_classified = B_TRUE;
7138275SEric Cheng MR_REFHOLD_LOCKED(mr);
7148275SEric Cheng }
7158275SEric Cheng mutex_exit(&mr->mr_lock);
7168275SEric Cheng
7178275SEric Cheng /*
7188275SEric Cheng * We check if an SRS is controlling this ring.
7198275SEric Cheng * If so, we can directly call the srs_lower_proc
7208275SEric Cheng * routine otherwise we need to go through mac_rx_classify
7218275SEric Cheng * to reach the right place.
7228275SEric Cheng */
7238275SEric Cheng if (hw_classified) {
7248275SEric Cheng mac_srs = mr->mr_srs;
7258275SEric Cheng /*
7268275SEric Cheng * This is supposed to be the fast path.
7278275SEric Cheng * All packets received though here were steered by
7288275SEric Cheng * the hardware classifier, and share the same
7298275SEric Cheng * MAC header info.
7308275SEric Cheng */
7318275SEric Cheng mac_srs->srs_rx.sr_lower_proc(mh,
7328275SEric Cheng (mac_resource_handle_t)mac_srs, mp_chain, B_FALSE);
7338275SEric Cheng MR_REFRELE(mr);
7348275SEric Cheng return;
7358275SEric Cheng }
7368275SEric Cheng /* We'll fall through to software classification */
7378833SVenu.Iyer@Sun.COM } else {
7388833SVenu.Iyer@Sun.COM flow_entry_t *flent;
7398833SVenu.Iyer@Sun.COM int err;
7408833SVenu.Iyer@Sun.COM
7418833SVenu.Iyer@Sun.COM rw_enter(&mip->mi_rw_lock, RW_READER);
7428833SVenu.Iyer@Sun.COM if (mip->mi_single_active_client != NULL) {
7438833SVenu.Iyer@Sun.COM flent = mip->mi_single_active_client->mci_flent_list;
7448833SVenu.Iyer@Sun.COM FLOW_TRY_REFHOLD(flent, err);
7458833SVenu.Iyer@Sun.COM rw_exit(&mip->mi_rw_lock);
7468833SVenu.Iyer@Sun.COM if (err == 0) {
7478833SVenu.Iyer@Sun.COM (flent->fe_cb_fn)(flent->fe_cb_arg1,
7488833SVenu.Iyer@Sun.COM flent->fe_cb_arg2, mp_chain, B_FALSE);
7498833SVenu.Iyer@Sun.COM FLOW_REFRELE(flent);
7508833SVenu.Iyer@Sun.COM return;
7518833SVenu.Iyer@Sun.COM }
7528833SVenu.Iyer@Sun.COM } else {
7538833SVenu.Iyer@Sun.COM rw_exit(&mip->mi_rw_lock);
7548833SVenu.Iyer@Sun.COM }
7558275SEric Cheng }
7568275SEric Cheng
7578275SEric Cheng if (!FLOW_TAB_EMPTY(mip->mi_flow_tab)) {
7588275SEric Cheng if ((bp = mac_rx_flow(mh, mrh, bp)) == NULL)
7598275SEric Cheng return;
7608275SEric Cheng }
7618275SEric Cheng
7628275SEric Cheng freemsgchain(bp);
7638275SEric Cheng }
7648275SEric Cheng
7658275SEric Cheng /* DATA TRANSMISSION */
7668275SEric Cheng
7678275SEric Cheng /*
7688275SEric Cheng * A driver's notification to resume transmission, in case of a provider
7698275SEric Cheng * without TX rings.
7708275SEric Cheng */
7718275SEric Cheng void
mac_tx_update(mac_handle_t mh)7728275SEric Cheng mac_tx_update(mac_handle_t mh)
7738275SEric Cheng {
77411878SVenu.Iyer@Sun.COM mac_tx_ring_update(mh, NULL);
7758275SEric Cheng }
7768275SEric Cheng
7778275SEric Cheng /*
7788275SEric Cheng * A driver's notification to resume transmission on the specified TX ring.
7798275SEric Cheng */
7808275SEric Cheng void
mac_tx_ring_update(mac_handle_t mh,mac_ring_handle_t rh)7818275SEric Cheng mac_tx_ring_update(mac_handle_t mh, mac_ring_handle_t rh)
7828275SEric Cheng {
7838275SEric Cheng i_mac_tx_srs_notify((mac_impl_t *)mh, rh);
7848275SEric Cheng }
7858275SEric Cheng
7868275SEric Cheng /* LINK STATE */
7878275SEric Cheng /*
7888275SEric Cheng * Notify the MAC layer about a link state change
7898275SEric Cheng */
7908275SEric Cheng void
mac_link_update(mac_handle_t mh,link_state_t link)7918275SEric Cheng mac_link_update(mac_handle_t mh, link_state_t link)
7928275SEric Cheng {
7938275SEric Cheng mac_impl_t *mip = (mac_impl_t *)mh;
7948275SEric Cheng
7958275SEric Cheng /*
7968275SEric Cheng * Save the link state.
7978275SEric Cheng */
79810491SRishi.Srivatsavai@Sun.COM mip->mi_lowlinkstate = link;
79910491SRishi.Srivatsavai@Sun.COM
80010491SRishi.Srivatsavai@Sun.COM /*
80110491SRishi.Srivatsavai@Sun.COM * Send a MAC_NOTE_LOWLINK notification. This tells the notification
80210491SRishi.Srivatsavai@Sun.COM * thread to deliver both lower and upper notifications.
80310491SRishi.Srivatsavai@Sun.COM */
80410491SRishi.Srivatsavai@Sun.COM i_mac_notify(mip, MAC_NOTE_LOWLINK);
80510491SRishi.Srivatsavai@Sun.COM }
80610491SRishi.Srivatsavai@Sun.COM
80710491SRishi.Srivatsavai@Sun.COM /*
80810491SRishi.Srivatsavai@Sun.COM * Notify the MAC layer about a link state change due to bridging.
80910491SRishi.Srivatsavai@Sun.COM */
81010491SRishi.Srivatsavai@Sun.COM void
mac_link_redo(mac_handle_t mh,link_state_t link)81110491SRishi.Srivatsavai@Sun.COM mac_link_redo(mac_handle_t mh, link_state_t link)
81210491SRishi.Srivatsavai@Sun.COM {
81310491SRishi.Srivatsavai@Sun.COM mac_impl_t *mip = (mac_impl_t *)mh;
81410491SRishi.Srivatsavai@Sun.COM
81510491SRishi.Srivatsavai@Sun.COM /*
81610491SRishi.Srivatsavai@Sun.COM * Save the link state.
81710491SRishi.Srivatsavai@Sun.COM */
8188275SEric Cheng mip->mi_linkstate = link;
8198275SEric Cheng
8208275SEric Cheng /*
82110491SRishi.Srivatsavai@Sun.COM * Send a MAC_NOTE_LINK notification. Only upper notifications are
82210491SRishi.Srivatsavai@Sun.COM * made.
8238275SEric Cheng */
8248275SEric Cheng i_mac_notify(mip, MAC_NOTE_LINK);
8258275SEric Cheng }
8268275SEric Cheng
82710654SGarrett.Damore@Sun.COM /* MINOR NODE HANDLING */
82810654SGarrett.Damore@Sun.COM
82910654SGarrett.Damore@Sun.COM /*
83010654SGarrett.Damore@Sun.COM * Given a dev_t, return the instance number (PPA) associated with it.
83110654SGarrett.Damore@Sun.COM * Drivers can use this in their getinfo(9e) implementation to lookup
83210654SGarrett.Damore@Sun.COM * the instance number (i.e. PPA) of the device, to use as an index to
83310654SGarrett.Damore@Sun.COM * their own array of soft state structures.
83410654SGarrett.Damore@Sun.COM *
83510654SGarrett.Damore@Sun.COM * Returns -1 on error.
83610654SGarrett.Damore@Sun.COM */
83710654SGarrett.Damore@Sun.COM int
mac_devt_to_instance(dev_t devt)83810654SGarrett.Damore@Sun.COM mac_devt_to_instance(dev_t devt)
83910654SGarrett.Damore@Sun.COM {
84010654SGarrett.Damore@Sun.COM return (dld_devt_to_instance(devt));
84110654SGarrett.Damore@Sun.COM }
84210654SGarrett.Damore@Sun.COM
84310654SGarrett.Damore@Sun.COM /*
84410654SGarrett.Damore@Sun.COM * This function returns the first minor number that is available for
84510654SGarrett.Damore@Sun.COM * driver private use. All minor numbers smaller than this are
84610654SGarrett.Damore@Sun.COM * reserved for GLDv3 use.
84710654SGarrett.Damore@Sun.COM */
84810654SGarrett.Damore@Sun.COM minor_t
mac_private_minor(void)84910654SGarrett.Damore@Sun.COM mac_private_minor(void)
85010654SGarrett.Damore@Sun.COM {
85110654SGarrett.Damore@Sun.COM return (MAC_PRIVATE_MINOR);
85210654SGarrett.Damore@Sun.COM }
85310654SGarrett.Damore@Sun.COM
8548275SEric Cheng /* OTHER CONTROL INFORMATION */
8558275SEric Cheng
8568275SEric Cheng /*
8578275SEric Cheng * A driver notified us that its primary MAC address has changed.
8588275SEric Cheng */
8598275SEric Cheng void
mac_unicst_update(mac_handle_t mh,const uint8_t * addr)8608275SEric Cheng mac_unicst_update(mac_handle_t mh, const uint8_t *addr)
8618275SEric Cheng {
8628275SEric Cheng mac_impl_t *mip = (mac_impl_t *)mh;
8638275SEric Cheng
8648275SEric Cheng if (mip->mi_type->mt_addr_length == 0)
8658275SEric Cheng return;
8668275SEric Cheng
8678275SEric Cheng i_mac_perim_enter(mip);
8688275SEric Cheng
8698275SEric Cheng /*
87011588Sdavid.edmondson@sun.com * If address changes, freshen the MAC address value and update
87111588Sdavid.edmondson@sun.com * all MAC clients that share this MAC address.
8728275SEric Cheng */
87311588Sdavid.edmondson@sun.com if (bcmp(addr, mip->mi_addr, mip->mi_type->mt_addr_length) != 0) {
87411588Sdavid.edmondson@sun.com mac_freshen_macaddr(mac_find_macaddr(mip, mip->mi_addr),
87511588Sdavid.edmondson@sun.com (uint8_t *)addr);
87611588Sdavid.edmondson@sun.com }
8778275SEric Cheng
8788275SEric Cheng i_mac_perim_exit(mip);
8798275SEric Cheng
8808275SEric Cheng /*
8818275SEric Cheng * Send a MAC_NOTE_UNICST notification.
8828275SEric Cheng */
8838275SEric Cheng i_mac_notify(mip, MAC_NOTE_UNICST);
8848275SEric Cheng }
8858275SEric Cheng
88610616SSebastien.Roy@Sun.COM void
mac_dst_update(mac_handle_t mh,const uint8_t * addr)88710616SSebastien.Roy@Sun.COM mac_dst_update(mac_handle_t mh, const uint8_t *addr)
88810616SSebastien.Roy@Sun.COM {
88910616SSebastien.Roy@Sun.COM mac_impl_t *mip = (mac_impl_t *)mh;
89010616SSebastien.Roy@Sun.COM
89110616SSebastien.Roy@Sun.COM if (mip->mi_type->mt_addr_length == 0)
89210616SSebastien.Roy@Sun.COM return;
89310616SSebastien.Roy@Sun.COM
89410616SSebastien.Roy@Sun.COM i_mac_perim_enter(mip);
89510616SSebastien.Roy@Sun.COM bcopy(addr, mip->mi_dstaddr, mip->mi_type->mt_addr_length);
89610616SSebastien.Roy@Sun.COM i_mac_perim_exit(mip);
89710616SSebastien.Roy@Sun.COM i_mac_notify(mip, MAC_NOTE_DEST);
89810616SSebastien.Roy@Sun.COM }
89910616SSebastien.Roy@Sun.COM
9008275SEric Cheng /*
9018275SEric Cheng * MAC plugin information changed.
9028275SEric Cheng */
9038275SEric Cheng int
mac_pdata_update(mac_handle_t mh,void * mac_pdata,size_t dsize)9048275SEric Cheng mac_pdata_update(mac_handle_t mh, void *mac_pdata, size_t dsize)
9058275SEric Cheng {
9068275SEric Cheng mac_impl_t *mip = (mac_impl_t *)mh;
9078275SEric Cheng
9088275SEric Cheng /*
9098275SEric Cheng * Verify that the plugin supports MAC plugin data and that the
9108275SEric Cheng * supplied data is valid.
9118275SEric Cheng */
9128275SEric Cheng if (!(mip->mi_type->mt_ops.mtops_ops & MTOPS_PDATA_VERIFY))
9138275SEric Cheng return (EINVAL);
9148275SEric Cheng if (!mip->mi_type->mt_ops.mtops_pdata_verify(mac_pdata, dsize))
9158275SEric Cheng return (EINVAL);
9168275SEric Cheng
9178275SEric Cheng if (mip->mi_pdata != NULL)
9188275SEric Cheng kmem_free(mip->mi_pdata, mip->mi_pdata_size);
9198275SEric Cheng
9208275SEric Cheng mip->mi_pdata = kmem_alloc(dsize, KM_SLEEP);
9218275SEric Cheng bcopy(mac_pdata, mip->mi_pdata, dsize);
9228275SEric Cheng mip->mi_pdata_size = dsize;
9238275SEric Cheng
9248275SEric Cheng /*
9258275SEric Cheng * Since the MAC plugin data is used to construct MAC headers that
9268275SEric Cheng * were cached in fast-path headers, we need to flush fast-path
9278275SEric Cheng * information for links associated with this mac.
9288275SEric Cheng */
9298275SEric Cheng i_mac_notify(mip, MAC_NOTE_FASTPATH_FLUSH);
9308275SEric Cheng return (0);
9318275SEric Cheng }
9328275SEric Cheng
9338275SEric Cheng /*
9348275SEric Cheng * Invoked by driver as well as the framework to notify its capability change.
9358275SEric Cheng */
9368275SEric Cheng void
mac_capab_update(mac_handle_t mh)9378275SEric Cheng mac_capab_update(mac_handle_t mh)
9388275SEric Cheng {
9398275SEric Cheng /* Send MAC_NOTE_CAPAB_CHG notification */
9408275SEric Cheng i_mac_notify((mac_impl_t *)mh, MAC_NOTE_CAPAB_CHG);
9418275SEric Cheng }
9428275SEric Cheng
943*13123SErik.Nordmark@Sun.COM /*
944*13123SErik.Nordmark@Sun.COM * Used by normal drivers to update the max sdu size.
945*13123SErik.Nordmark@Sun.COM * We need to handle the case of a smaller mi_sdu_multicast
946*13123SErik.Nordmark@Sun.COM * since this is called by mac_set_mtu() even for drivers that
947*13123SErik.Nordmark@Sun.COM * have differing unicast and multicast mtu and we don't want to
948*13123SErik.Nordmark@Sun.COM * increase the multicast mtu by accident in that case.
949*13123SErik.Nordmark@Sun.COM */
9508275SEric Cheng int
mac_maxsdu_update(mac_handle_t mh,uint_t sdu_max)9518275SEric Cheng mac_maxsdu_update(mac_handle_t mh, uint_t sdu_max)
9528275SEric Cheng {
9538275SEric Cheng mac_impl_t *mip = (mac_impl_t *)mh;
9548275SEric Cheng
9559514SGirish.Moodalbail@Sun.COM if (sdu_max == 0 || sdu_max < mip->mi_sdu_min)
9568275SEric Cheng return (EINVAL);
9578275SEric Cheng mip->mi_sdu_max = sdu_max;
958*13123SErik.Nordmark@Sun.COM if (mip->mi_sdu_multicast > mip->mi_sdu_max)
959*13123SErik.Nordmark@Sun.COM mip->mi_sdu_multicast = mip->mi_sdu_max;
960*13123SErik.Nordmark@Sun.COM
961*13123SErik.Nordmark@Sun.COM /* Send a MAC_NOTE_SDU_SIZE notification. */
962*13123SErik.Nordmark@Sun.COM i_mac_notify(mip, MAC_NOTE_SDU_SIZE);
963*13123SErik.Nordmark@Sun.COM return (0);
964*13123SErik.Nordmark@Sun.COM }
965*13123SErik.Nordmark@Sun.COM
966*13123SErik.Nordmark@Sun.COM /*
967*13123SErik.Nordmark@Sun.COM * Version of the above function that is used by drivers that have a different
968*13123SErik.Nordmark@Sun.COM * max sdu size for multicast/broadcast vs. unicast.
969*13123SErik.Nordmark@Sun.COM */
970*13123SErik.Nordmark@Sun.COM int
mac_maxsdu_update2(mac_handle_t mh,uint_t sdu_max,uint_t sdu_multicast)971*13123SErik.Nordmark@Sun.COM mac_maxsdu_update2(mac_handle_t mh, uint_t sdu_max, uint_t sdu_multicast)
972*13123SErik.Nordmark@Sun.COM {
973*13123SErik.Nordmark@Sun.COM mac_impl_t *mip = (mac_impl_t *)mh;
974*13123SErik.Nordmark@Sun.COM
975*13123SErik.Nordmark@Sun.COM if (sdu_max == 0 || sdu_max < mip->mi_sdu_min)
976*13123SErik.Nordmark@Sun.COM return (EINVAL);
977*13123SErik.Nordmark@Sun.COM if (sdu_multicast == 0)
978*13123SErik.Nordmark@Sun.COM sdu_multicast = sdu_max;
979*13123SErik.Nordmark@Sun.COM if (sdu_multicast > sdu_max || sdu_multicast < mip->mi_sdu_min)
980*13123SErik.Nordmark@Sun.COM return (EINVAL);
981*13123SErik.Nordmark@Sun.COM mip->mi_sdu_max = sdu_max;
982*13123SErik.Nordmark@Sun.COM mip->mi_sdu_multicast = sdu_multicast;
9838275SEric Cheng
9848275SEric Cheng /* Send a MAC_NOTE_SDU_SIZE notification. */
9858275SEric Cheng i_mac_notify(mip, MAC_NOTE_SDU_SIZE);
9868275SEric Cheng return (0);
9878275SEric Cheng }
9888275SEric Cheng
98911878SVenu.Iyer@Sun.COM static void
mac_ring_intr_retarget(mac_group_t * group,mac_ring_t * ring)99011878SVenu.Iyer@Sun.COM mac_ring_intr_retarget(mac_group_t *group, mac_ring_t *ring)
99111878SVenu.Iyer@Sun.COM {
99211878SVenu.Iyer@Sun.COM mac_client_impl_t *mcip;
99311878SVenu.Iyer@Sun.COM flow_entry_t *flent;
99411878SVenu.Iyer@Sun.COM mac_soft_ring_set_t *mac_rx_srs;
99511878SVenu.Iyer@Sun.COM mac_cpus_t *srs_cpu;
99611878SVenu.Iyer@Sun.COM int i;
99711878SVenu.Iyer@Sun.COM
99811878SVenu.Iyer@Sun.COM if (((mcip = MAC_GROUP_ONLY_CLIENT(group)) != NULL) &&
99911878SVenu.Iyer@Sun.COM (!ring->mr_info.mri_intr.mi_ddi_shared)) {
100011878SVenu.Iyer@Sun.COM /* interrupt can be re-targeted */
100111878SVenu.Iyer@Sun.COM ASSERT(group->mrg_state == MAC_GROUP_STATE_RESERVED);
100211878SVenu.Iyer@Sun.COM flent = mcip->mci_flent;
100311878SVenu.Iyer@Sun.COM if (ring->mr_type == MAC_RING_TYPE_RX) {
100411878SVenu.Iyer@Sun.COM for (i = 0; i < flent->fe_rx_srs_cnt; i++) {
100511878SVenu.Iyer@Sun.COM mac_rx_srs = flent->fe_rx_srs[i];
100611878SVenu.Iyer@Sun.COM if (mac_rx_srs->srs_ring != ring)
100711878SVenu.Iyer@Sun.COM continue;
100811878SVenu.Iyer@Sun.COM srs_cpu = &mac_rx_srs->srs_cpu;
100911878SVenu.Iyer@Sun.COM mutex_enter(&cpu_lock);
101011878SVenu.Iyer@Sun.COM mac_rx_srs_retarget_intr(mac_rx_srs,
101111878SVenu.Iyer@Sun.COM srs_cpu->mc_rx_intr_cpu);
101211878SVenu.Iyer@Sun.COM mutex_exit(&cpu_lock);
101311878SVenu.Iyer@Sun.COM break;
101411878SVenu.Iyer@Sun.COM }
101511878SVenu.Iyer@Sun.COM } else {
101611878SVenu.Iyer@Sun.COM if (flent->fe_tx_srs != NULL) {
101711878SVenu.Iyer@Sun.COM mutex_enter(&cpu_lock);
101811878SVenu.Iyer@Sun.COM mac_tx_srs_retarget_intr(
101911878SVenu.Iyer@Sun.COM flent->fe_tx_srs);
102011878SVenu.Iyer@Sun.COM mutex_exit(&cpu_lock);
102111878SVenu.Iyer@Sun.COM }
102211878SVenu.Iyer@Sun.COM }
102311878SVenu.Iyer@Sun.COM }
102411878SVenu.Iyer@Sun.COM }
102511878SVenu.Iyer@Sun.COM
102611878SVenu.Iyer@Sun.COM /*
102711878SVenu.Iyer@Sun.COM * Clients like aggr create pseudo rings (mac_ring_t) and expose them to
102811878SVenu.Iyer@Sun.COM * their clients. There is a 1-1 mapping pseudo ring and the hardware
102911878SVenu.Iyer@Sun.COM * ring. ddi interrupt handles are exported from the hardware ring to
103011878SVenu.Iyer@Sun.COM * the pseudo ring. Thus when the interrupt handle changes, clients of
103111878SVenu.Iyer@Sun.COM * aggr that are using the handle need to use the new handle and
103211878SVenu.Iyer@Sun.COM * re-target their interrupts.
103311878SVenu.Iyer@Sun.COM */
103411878SVenu.Iyer@Sun.COM static void
mac_pseudo_ring_intr_retarget(mac_impl_t * mip,mac_ring_t * ring,ddi_intr_handle_t ddh)103511878SVenu.Iyer@Sun.COM mac_pseudo_ring_intr_retarget(mac_impl_t *mip, mac_ring_t *ring,
103611878SVenu.Iyer@Sun.COM ddi_intr_handle_t ddh)
103711878SVenu.Iyer@Sun.COM {
103811878SVenu.Iyer@Sun.COM mac_ring_t *pring;
103911878SVenu.Iyer@Sun.COM mac_group_t *pgroup;
104011878SVenu.Iyer@Sun.COM mac_impl_t *pmip;
104111878SVenu.Iyer@Sun.COM char macname[MAXNAMELEN];
104211878SVenu.Iyer@Sun.COM mac_perim_handle_t p_mph;
104311878SVenu.Iyer@Sun.COM uint64_t saved_gen_num;
104411878SVenu.Iyer@Sun.COM
104511878SVenu.Iyer@Sun.COM again:
104611878SVenu.Iyer@Sun.COM pring = (mac_ring_t *)ring->mr_prh;
104711878SVenu.Iyer@Sun.COM pgroup = (mac_group_t *)pring->mr_gh;
104811878SVenu.Iyer@Sun.COM pmip = (mac_impl_t *)pgroup->mrg_mh;
104911878SVenu.Iyer@Sun.COM saved_gen_num = ring->mr_gen_num;
105011878SVenu.Iyer@Sun.COM (void) strlcpy(macname, pmip->mi_name, MAXNAMELEN);
105111878SVenu.Iyer@Sun.COM /*
105211878SVenu.Iyer@Sun.COM * We need to enter aggr's perimeter. The locking hierarchy
105311878SVenu.Iyer@Sun.COM * dictates that aggr's perimeter should be entered first
105411878SVenu.Iyer@Sun.COM * and then the port's perimeter. So drop the port's
105511878SVenu.Iyer@Sun.COM * perimeter, enter aggr's and then re-enter port's
105611878SVenu.Iyer@Sun.COM * perimeter.
105711878SVenu.Iyer@Sun.COM */
105811878SVenu.Iyer@Sun.COM i_mac_perim_exit(mip);
105911878SVenu.Iyer@Sun.COM /*
106011878SVenu.Iyer@Sun.COM * While we know pmip is the aggr's mip, there is a
106111878SVenu.Iyer@Sun.COM * possibility that aggr could have unregistered by
106211878SVenu.Iyer@Sun.COM * the time we exit port's perimeter (mip) and
106311878SVenu.Iyer@Sun.COM * enter aggr's perimeter (pmip). To avoid that
106411878SVenu.Iyer@Sun.COM * scenario, enter aggr's perimeter using its name.
106511878SVenu.Iyer@Sun.COM */
106611878SVenu.Iyer@Sun.COM if (mac_perim_enter_by_macname(macname, &p_mph) != 0)
106711878SVenu.Iyer@Sun.COM return;
106811878SVenu.Iyer@Sun.COM i_mac_perim_enter(mip);
106911878SVenu.Iyer@Sun.COM /*
107011878SVenu.Iyer@Sun.COM * Check if the ring got assigned to another aggregation before
107111878SVenu.Iyer@Sun.COM * be could enter aggr's and the port's perimeter. When a ring
107211878SVenu.Iyer@Sun.COM * gets deleted from an aggregation, it calls mac_stop_ring()
107311878SVenu.Iyer@Sun.COM * which increments the generation number. So checking
107411878SVenu.Iyer@Sun.COM * generation number will be enough.
107511878SVenu.Iyer@Sun.COM */
107611878SVenu.Iyer@Sun.COM if (ring->mr_gen_num != saved_gen_num && ring->mr_prh != NULL) {
107711878SVenu.Iyer@Sun.COM i_mac_perim_exit(mip);
107811878SVenu.Iyer@Sun.COM mac_perim_exit(p_mph);
107911878SVenu.Iyer@Sun.COM i_mac_perim_enter(mip);
108011878SVenu.Iyer@Sun.COM goto again;
108111878SVenu.Iyer@Sun.COM }
108211878SVenu.Iyer@Sun.COM
108311878SVenu.Iyer@Sun.COM /* Check if pseudo ring is still present */
108411878SVenu.Iyer@Sun.COM if (ring->mr_prh != NULL) {
108511878SVenu.Iyer@Sun.COM pring->mr_info.mri_intr.mi_ddi_handle = ddh;
108611878SVenu.Iyer@Sun.COM pring->mr_info.mri_intr.mi_ddi_shared =
108711878SVenu.Iyer@Sun.COM ring->mr_info.mri_intr.mi_ddi_shared;
108811878SVenu.Iyer@Sun.COM if (ddh != NULL)
108911878SVenu.Iyer@Sun.COM mac_ring_intr_retarget(pgroup, pring);
109011878SVenu.Iyer@Sun.COM }
109111878SVenu.Iyer@Sun.COM i_mac_perim_exit(mip);
109211878SVenu.Iyer@Sun.COM mac_perim_exit(p_mph);
109311878SVenu.Iyer@Sun.COM }
109411878SVenu.Iyer@Sun.COM /*
109511878SVenu.Iyer@Sun.COM * API called by driver to provide new interrupt handle for TX/RX rings.
109611878SVenu.Iyer@Sun.COM * This usually happens when IRM (Interrupt Resource Manangement)
109711878SVenu.Iyer@Sun.COM * framework either gives the driver more MSI-x interrupts or takes
109811878SVenu.Iyer@Sun.COM * away MSI-x interrupts from the driver.
109911878SVenu.Iyer@Sun.COM */
110011878SVenu.Iyer@Sun.COM void
mac_ring_intr_set(mac_ring_handle_t mrh,ddi_intr_handle_t ddh)110111878SVenu.Iyer@Sun.COM mac_ring_intr_set(mac_ring_handle_t mrh, ddi_intr_handle_t ddh)
110211878SVenu.Iyer@Sun.COM {
110311878SVenu.Iyer@Sun.COM mac_ring_t *ring = (mac_ring_t *)mrh;
110411878SVenu.Iyer@Sun.COM mac_group_t *group = (mac_group_t *)ring->mr_gh;
110511878SVenu.Iyer@Sun.COM mac_impl_t *mip = (mac_impl_t *)group->mrg_mh;
110611878SVenu.Iyer@Sun.COM
110711878SVenu.Iyer@Sun.COM i_mac_perim_enter(mip);
110811878SVenu.Iyer@Sun.COM ring->mr_info.mri_intr.mi_ddi_handle = ddh;
110911878SVenu.Iyer@Sun.COM if (ddh == NULL) {
111011878SVenu.Iyer@Sun.COM /* Interrupts being reset */
111111878SVenu.Iyer@Sun.COM ring->mr_info.mri_intr.mi_ddi_shared = B_FALSE;
111211878SVenu.Iyer@Sun.COM if (ring->mr_prh != NULL) {
111311878SVenu.Iyer@Sun.COM mac_pseudo_ring_intr_retarget(mip, ring, ddh);
111411878SVenu.Iyer@Sun.COM return;
111511878SVenu.Iyer@Sun.COM }
111611878SVenu.Iyer@Sun.COM } else {
111711878SVenu.Iyer@Sun.COM /* New interrupt handle */
111811878SVenu.Iyer@Sun.COM mac_compare_ddi_handle(mip->mi_rx_groups,
111911878SVenu.Iyer@Sun.COM mip->mi_rx_group_count, ring);
112011878SVenu.Iyer@Sun.COM if (!ring->mr_info.mri_intr.mi_ddi_shared) {
112111878SVenu.Iyer@Sun.COM mac_compare_ddi_handle(mip->mi_tx_groups,
112211878SVenu.Iyer@Sun.COM mip->mi_tx_group_count, ring);
112311878SVenu.Iyer@Sun.COM }
112411878SVenu.Iyer@Sun.COM if (ring->mr_prh != NULL) {
112511878SVenu.Iyer@Sun.COM mac_pseudo_ring_intr_retarget(mip, ring, ddh);
112611878SVenu.Iyer@Sun.COM return;
112711878SVenu.Iyer@Sun.COM } else {
112811878SVenu.Iyer@Sun.COM mac_ring_intr_retarget(group, ring);
112911878SVenu.Iyer@Sun.COM }
113011878SVenu.Iyer@Sun.COM }
113111878SVenu.Iyer@Sun.COM i_mac_perim_exit(mip);
113211878SVenu.Iyer@Sun.COM }
113311878SVenu.Iyer@Sun.COM
11348275SEric Cheng /* PRIVATE FUNCTIONS, FOR INTERNAL USE ONLY */
11358275SEric Cheng
11368275SEric Cheng /*
11378275SEric Cheng * Updates the mac_impl structure with the current state of the link
11388275SEric Cheng */
11398275SEric Cheng static void
i_mac_log_link_state(mac_impl_t * mip)11408275SEric Cheng i_mac_log_link_state(mac_impl_t *mip)
11418275SEric Cheng {
11428275SEric Cheng /*
11438275SEric Cheng * If no change, then it is not interesting.
11448275SEric Cheng */
114510491SRishi.Srivatsavai@Sun.COM if (mip->mi_lastlowlinkstate == mip->mi_lowlinkstate)
11468275SEric Cheng return;
11478275SEric Cheng
114810491SRishi.Srivatsavai@Sun.COM switch (mip->mi_lowlinkstate) {
11498275SEric Cheng case LINK_STATE_UP:
11508275SEric Cheng if (mip->mi_type->mt_ops.mtops_ops & MTOPS_LINK_DETAILS) {
11518275SEric Cheng char det[200];
11528275SEric Cheng
11538275SEric Cheng mip->mi_type->mt_ops.mtops_link_details(det,
11548275SEric Cheng sizeof (det), (mac_handle_t)mip, mip->mi_pdata);
11558275SEric Cheng
11568275SEric Cheng cmn_err(CE_NOTE, "!%s link up, %s", mip->mi_name, det);
11578275SEric Cheng } else {
11588275SEric Cheng cmn_err(CE_NOTE, "!%s link up", mip->mi_name);
11598275SEric Cheng }
11608275SEric Cheng break;
11618275SEric Cheng
11628275SEric Cheng case LINK_STATE_DOWN:
11638275SEric Cheng /*
11648275SEric Cheng * Only transitions from UP to DOWN are interesting
11658275SEric Cheng */
116610491SRishi.Srivatsavai@Sun.COM if (mip->mi_lastlowlinkstate != LINK_STATE_UNKNOWN)
11678275SEric Cheng cmn_err(CE_NOTE, "!%s link down", mip->mi_name);
11688275SEric Cheng break;
11698275SEric Cheng
11708275SEric Cheng case LINK_STATE_UNKNOWN:
11718275SEric Cheng /*
11728275SEric Cheng * This case is normally not interesting.
11738275SEric Cheng */
11748275SEric Cheng break;
11758275SEric Cheng }
117610491SRishi.Srivatsavai@Sun.COM mip->mi_lastlowlinkstate = mip->mi_lowlinkstate;
11778275SEric Cheng }
11788275SEric Cheng
11798275SEric Cheng /*
11808275SEric Cheng * Main routine for the callbacks notifications thread
11818275SEric Cheng */
11828275SEric Cheng static void
i_mac_notify_thread(void * arg)11838275SEric Cheng i_mac_notify_thread(void *arg)
11848275SEric Cheng {
11858275SEric Cheng mac_impl_t *mip = arg;
11868275SEric Cheng callb_cpr_t cprinfo;
11878275SEric Cheng mac_cb_t *mcb;
11888275SEric Cheng mac_cb_info_t *mcbi;
11898275SEric Cheng mac_notify_cb_t *mncb;
11908275SEric Cheng
11918275SEric Cheng mcbi = &mip->mi_notify_cb_info;
11928275SEric Cheng CALLB_CPR_INIT(&cprinfo, mcbi->mcbi_lockp, callb_generic_cpr,
11938275SEric Cheng "i_mac_notify_thread");
11948275SEric Cheng
11958275SEric Cheng mutex_enter(mcbi->mcbi_lockp);
11968275SEric Cheng
11978275SEric Cheng for (;;) {
11988275SEric Cheng uint32_t bits;
11998275SEric Cheng uint32_t type;
12008275SEric Cheng
12018275SEric Cheng bits = mip->mi_notify_bits;
12028275SEric Cheng if (bits == 0) {
12038275SEric Cheng CALLB_CPR_SAFE_BEGIN(&cprinfo);
12048275SEric Cheng cv_wait(&mcbi->mcbi_cv, mcbi->mcbi_lockp);
12058275SEric Cheng CALLB_CPR_SAFE_END(&cprinfo, mcbi->mcbi_lockp);
12068275SEric Cheng continue;
12078275SEric Cheng }
12088275SEric Cheng mip->mi_notify_bits = 0;
12098275SEric Cheng if ((bits & (1 << MAC_NNOTE)) != 0) {
12108275SEric Cheng /* request to quit */
12118275SEric Cheng ASSERT(mip->mi_state_flags & MIS_DISABLED);
12128275SEric Cheng break;
12138275SEric Cheng }
12148275SEric Cheng
12158275SEric Cheng mutex_exit(mcbi->mcbi_lockp);
12168275SEric Cheng
12178275SEric Cheng /*
121810491SRishi.Srivatsavai@Sun.COM * Log link changes on the actual link, but then do reports on
121910491SRishi.Srivatsavai@Sun.COM * synthetic state (if part of a bridge).
12208275SEric Cheng */
122110491SRishi.Srivatsavai@Sun.COM if ((bits & (1 << MAC_NOTE_LOWLINK)) != 0) {
122210491SRishi.Srivatsavai@Sun.COM link_state_t newstate;
122310491SRishi.Srivatsavai@Sun.COM mac_handle_t mh;
122410491SRishi.Srivatsavai@Sun.COM
12258275SEric Cheng i_mac_log_link_state(mip);
122610491SRishi.Srivatsavai@Sun.COM newstate = mip->mi_lowlinkstate;
122710491SRishi.Srivatsavai@Sun.COM if (mip->mi_bridge_link != NULL) {
122810491SRishi.Srivatsavai@Sun.COM mutex_enter(&mip->mi_bridge_lock);
122910491SRishi.Srivatsavai@Sun.COM if ((mh = mip->mi_bridge_link) != NULL) {
123010491SRishi.Srivatsavai@Sun.COM newstate = mac_bridge_ls_cb(mh,
123110491SRishi.Srivatsavai@Sun.COM newstate);
123210491SRishi.Srivatsavai@Sun.COM }
123310491SRishi.Srivatsavai@Sun.COM mutex_exit(&mip->mi_bridge_lock);
123410491SRishi.Srivatsavai@Sun.COM }
123510491SRishi.Srivatsavai@Sun.COM if (newstate != mip->mi_linkstate) {
123610491SRishi.Srivatsavai@Sun.COM mip->mi_linkstate = newstate;
123710491SRishi.Srivatsavai@Sun.COM bits |= 1 << MAC_NOTE_LINK;
123810491SRishi.Srivatsavai@Sun.COM }
123910491SRishi.Srivatsavai@Sun.COM }
12408275SEric Cheng
12418275SEric Cheng /*
12428275SEric Cheng * Do notification callbacks for each notification type.
12438275SEric Cheng */
12448275SEric Cheng for (type = 0; type < MAC_NNOTE; type++) {
12458275SEric Cheng if ((bits & (1 << type)) == 0) {
12468275SEric Cheng continue;
12478275SEric Cheng }
12488275SEric Cheng
124910491SRishi.Srivatsavai@Sun.COM if (mac_notify_cb_list[type] != NULL)
125010491SRishi.Srivatsavai@Sun.COM (*mac_notify_cb_list[type])(mip);
12518275SEric Cheng
12528275SEric Cheng /*
12538275SEric Cheng * Walk the list of notifications.
12548275SEric Cheng */
12558275SEric Cheng MAC_CALLBACK_WALKER_INC(&mip->mi_notify_cb_info);
12568275SEric Cheng for (mcb = mip->mi_notify_cb_list; mcb != NULL;
12578275SEric Cheng mcb = mcb->mcb_nextp) {
12588275SEric Cheng mncb = (mac_notify_cb_t *)mcb->mcb_objp;
12598275SEric Cheng mncb->mncb_fn(mncb->mncb_arg, type);
12608275SEric Cheng }
12618275SEric Cheng MAC_CALLBACK_WALKER_DCR(&mip->mi_notify_cb_info,
12628275SEric Cheng &mip->mi_notify_cb_list);
12638275SEric Cheng }
12648275SEric Cheng
12658275SEric Cheng mutex_enter(mcbi->mcbi_lockp);
12668275SEric Cheng }
12678275SEric Cheng
12688275SEric Cheng mip->mi_state_flags |= MIS_NOTIFY_DONE;
12698275SEric Cheng cv_broadcast(&mcbi->mcbi_cv);
12708275SEric Cheng
12718275SEric Cheng /* CALLB_CPR_EXIT drops the lock */
12728275SEric Cheng CALLB_CPR_EXIT(&cprinfo);
12738275SEric Cheng thread_exit();
12748275SEric Cheng }
12758275SEric Cheng
12768275SEric Cheng /*
12778275SEric Cheng * Signal the i_mac_notify_thread asking it to quit.
12788275SEric Cheng * Then wait till it is done.
12798275SEric Cheng */
12808275SEric Cheng void
i_mac_notify_exit(mac_impl_t * mip)12818275SEric Cheng i_mac_notify_exit(mac_impl_t *mip)
12828275SEric Cheng {
12838275SEric Cheng mac_cb_info_t *mcbi;
12848275SEric Cheng
12858275SEric Cheng mcbi = &mip->mi_notify_cb_info;
12868275SEric Cheng
12878275SEric Cheng mutex_enter(mcbi->mcbi_lockp);
12888275SEric Cheng mip->mi_notify_bits = (1 << MAC_NNOTE);
12898275SEric Cheng cv_broadcast(&mcbi->mcbi_cv);
12908275SEric Cheng
12918275SEric Cheng
12928275SEric Cheng while ((mip->mi_notify_thread != NULL) &&
12938275SEric Cheng !(mip->mi_state_flags & MIS_NOTIFY_DONE)) {
12948275SEric Cheng cv_wait(&mcbi->mcbi_cv, mcbi->mcbi_lockp);
12958275SEric Cheng }
12968275SEric Cheng
12978275SEric Cheng /* Necessary clean up before doing kmem_cache_free */
12988275SEric Cheng mip->mi_state_flags &= ~MIS_NOTIFY_DONE;
12998275SEric Cheng mip->mi_notify_bits = 0;
13008275SEric Cheng mip->mi_notify_thread = NULL;
13018275SEric Cheng mutex_exit(mcbi->mcbi_lockp);
13028275SEric Cheng }
13038275SEric Cheng
13048275SEric Cheng /*
13058275SEric Cheng * Entry point invoked by drivers to dynamically add a ring to an
13068275SEric Cheng * existing group.
13078275SEric Cheng */
13088275SEric Cheng int
mac_group_add_ring(mac_group_handle_t gh,int index)13098275SEric Cheng mac_group_add_ring(mac_group_handle_t gh, int index)
13108275SEric Cheng {
13118275SEric Cheng mac_group_t *group = (mac_group_t *)gh;
13128275SEric Cheng mac_impl_t *mip = (mac_impl_t *)group->mrg_mh;
13138275SEric Cheng int ret;
13148275SEric Cheng
13158275SEric Cheng i_mac_perim_enter(mip);
13168275SEric Cheng ret = i_mac_group_add_ring(group, NULL, index);
13178275SEric Cheng i_mac_perim_exit(mip);
13188275SEric Cheng return (ret);
13198275SEric Cheng }
13208275SEric Cheng
13218275SEric Cheng /*
13228275SEric Cheng * Entry point invoked by drivers to dynamically remove a ring
13238275SEric Cheng * from an existing group. The specified ring handle must no longer
13248275SEric Cheng * be used by the driver after a call to this function.
13258275SEric Cheng */
13268275SEric Cheng void
mac_group_rem_ring(mac_group_handle_t gh,mac_ring_handle_t rh)13278275SEric Cheng mac_group_rem_ring(mac_group_handle_t gh, mac_ring_handle_t rh)
13288275SEric Cheng {
13298275SEric Cheng mac_group_t *group = (mac_group_t *)gh;
13308275SEric Cheng mac_impl_t *mip = (mac_impl_t *)group->mrg_mh;
13318275SEric Cheng
13328275SEric Cheng i_mac_perim_enter(mip);
13338275SEric Cheng i_mac_group_rem_ring(group, (mac_ring_t *)rh, B_TRUE);
13348275SEric Cheng i_mac_perim_exit(mip);
13358275SEric Cheng }
133611878SVenu.Iyer@Sun.COM
133711878SVenu.Iyer@Sun.COM /*
133811878SVenu.Iyer@Sun.COM * mac_prop_info_*() callbacks called from the driver's prefix_propinfo()
133911878SVenu.Iyer@Sun.COM * entry points.
134011878SVenu.Iyer@Sun.COM */
134111878SVenu.Iyer@Sun.COM
134211878SVenu.Iyer@Sun.COM void
mac_prop_info_set_default_uint8(mac_prop_info_handle_t ph,uint8_t val)134311878SVenu.Iyer@Sun.COM mac_prop_info_set_default_uint8(mac_prop_info_handle_t ph, uint8_t val)
134411878SVenu.Iyer@Sun.COM {
134511878SVenu.Iyer@Sun.COM mac_prop_info_state_t *pr = (mac_prop_info_state_t *)ph;
134611878SVenu.Iyer@Sun.COM
134711878SVenu.Iyer@Sun.COM /* nothing to do if the caller doesn't want the default value */
134811878SVenu.Iyer@Sun.COM if (pr->pr_default == NULL)
134911878SVenu.Iyer@Sun.COM return;
135011878SVenu.Iyer@Sun.COM
135111878SVenu.Iyer@Sun.COM ASSERT(pr->pr_default_size >= sizeof (uint8_t));
135211878SVenu.Iyer@Sun.COM
135311878SVenu.Iyer@Sun.COM *(uint8_t *)(pr->pr_default) = val;
135411878SVenu.Iyer@Sun.COM pr->pr_flags |= MAC_PROP_INFO_DEFAULT;
135511878SVenu.Iyer@Sun.COM }
135611878SVenu.Iyer@Sun.COM
135711878SVenu.Iyer@Sun.COM void
mac_prop_info_set_default_uint64(mac_prop_info_handle_t ph,uint64_t val)135811878SVenu.Iyer@Sun.COM mac_prop_info_set_default_uint64(mac_prop_info_handle_t ph, uint64_t val)
135911878SVenu.Iyer@Sun.COM {
136011878SVenu.Iyer@Sun.COM mac_prop_info_state_t *pr = (mac_prop_info_state_t *)ph;
136111878SVenu.Iyer@Sun.COM
136211878SVenu.Iyer@Sun.COM /* nothing to do if the caller doesn't want the default value */
136311878SVenu.Iyer@Sun.COM if (pr->pr_default == NULL)
136411878SVenu.Iyer@Sun.COM return;
136511878SVenu.Iyer@Sun.COM
136611878SVenu.Iyer@Sun.COM ASSERT(pr->pr_default_size >= sizeof (uint64_t));
136711878SVenu.Iyer@Sun.COM
136811878SVenu.Iyer@Sun.COM bcopy(&val, pr->pr_default, sizeof (val));
136911878SVenu.Iyer@Sun.COM
137011878SVenu.Iyer@Sun.COM pr->pr_flags |= MAC_PROP_INFO_DEFAULT;
137111878SVenu.Iyer@Sun.COM }
137211878SVenu.Iyer@Sun.COM
137311878SVenu.Iyer@Sun.COM void
mac_prop_info_set_default_uint32(mac_prop_info_handle_t ph,uint32_t val)137411878SVenu.Iyer@Sun.COM mac_prop_info_set_default_uint32(mac_prop_info_handle_t ph, uint32_t val)
137511878SVenu.Iyer@Sun.COM {
137611878SVenu.Iyer@Sun.COM mac_prop_info_state_t *pr = (mac_prop_info_state_t *)ph;
137711878SVenu.Iyer@Sun.COM
137811878SVenu.Iyer@Sun.COM /* nothing to do if the caller doesn't want the default value */
137911878SVenu.Iyer@Sun.COM if (pr->pr_default == NULL)
138011878SVenu.Iyer@Sun.COM return;
138111878SVenu.Iyer@Sun.COM
138211878SVenu.Iyer@Sun.COM ASSERT(pr->pr_default_size >= sizeof (uint32_t));
138311878SVenu.Iyer@Sun.COM
138411878SVenu.Iyer@Sun.COM bcopy(&val, pr->pr_default, sizeof (val));
138511878SVenu.Iyer@Sun.COM
138611878SVenu.Iyer@Sun.COM pr->pr_flags |= MAC_PROP_INFO_DEFAULT;
138711878SVenu.Iyer@Sun.COM }
138811878SVenu.Iyer@Sun.COM
138911878SVenu.Iyer@Sun.COM void
mac_prop_info_set_default_str(mac_prop_info_handle_t ph,const char * str)139011878SVenu.Iyer@Sun.COM mac_prop_info_set_default_str(mac_prop_info_handle_t ph, const char *str)
139111878SVenu.Iyer@Sun.COM {
139211878SVenu.Iyer@Sun.COM mac_prop_info_state_t *pr = (mac_prop_info_state_t *)ph;
139311878SVenu.Iyer@Sun.COM
139411878SVenu.Iyer@Sun.COM /* nothing to do if the caller doesn't want the default value */
139511878SVenu.Iyer@Sun.COM if (pr->pr_default == NULL)
139611878SVenu.Iyer@Sun.COM return;
139711878SVenu.Iyer@Sun.COM
139812953SRishi.Srivatsavai@Sun.COM if (strlen(str) >= pr->pr_default_size)
139912850SPrakash.Jalan@Sun.COM pr->pr_errno = ENOBUFS;
140011878SVenu.Iyer@Sun.COM else
140112953SRishi.Srivatsavai@Sun.COM (void) strlcpy(pr->pr_default, str, pr->pr_default_size);
140211878SVenu.Iyer@Sun.COM pr->pr_flags |= MAC_PROP_INFO_DEFAULT;
140311878SVenu.Iyer@Sun.COM }
140411878SVenu.Iyer@Sun.COM
140511878SVenu.Iyer@Sun.COM void
mac_prop_info_set_default_link_flowctrl(mac_prop_info_handle_t ph,link_flowctrl_t val)140611878SVenu.Iyer@Sun.COM mac_prop_info_set_default_link_flowctrl(mac_prop_info_handle_t ph,
140711878SVenu.Iyer@Sun.COM link_flowctrl_t val)
140811878SVenu.Iyer@Sun.COM {
140911878SVenu.Iyer@Sun.COM mac_prop_info_state_t *pr = (mac_prop_info_state_t *)ph;
141011878SVenu.Iyer@Sun.COM
141111878SVenu.Iyer@Sun.COM /* nothing to do if the caller doesn't want the default value */
141211878SVenu.Iyer@Sun.COM if (pr->pr_default == NULL)
141311878SVenu.Iyer@Sun.COM return;
141411878SVenu.Iyer@Sun.COM
141511878SVenu.Iyer@Sun.COM ASSERT(pr->pr_default_size >= sizeof (link_flowctrl_t));
141611878SVenu.Iyer@Sun.COM
141711878SVenu.Iyer@Sun.COM bcopy(&val, pr->pr_default, sizeof (val));
141811878SVenu.Iyer@Sun.COM
141911878SVenu.Iyer@Sun.COM pr->pr_flags |= MAC_PROP_INFO_DEFAULT;
142011878SVenu.Iyer@Sun.COM }
142111878SVenu.Iyer@Sun.COM
142211878SVenu.Iyer@Sun.COM void
mac_prop_info_set_range_uint32(mac_prop_info_handle_t ph,uint32_t min,uint32_t max)142311878SVenu.Iyer@Sun.COM mac_prop_info_set_range_uint32(mac_prop_info_handle_t ph, uint32_t min,
142411878SVenu.Iyer@Sun.COM uint32_t max)
142511878SVenu.Iyer@Sun.COM {
142611878SVenu.Iyer@Sun.COM mac_prop_info_state_t *pr = (mac_prop_info_state_t *)ph;
142711878SVenu.Iyer@Sun.COM mac_propval_range_t *range = pr->pr_range;
142812850SPrakash.Jalan@Sun.COM mac_propval_uint32_range_t *range32;
142911878SVenu.Iyer@Sun.COM
143011878SVenu.Iyer@Sun.COM /* nothing to do if the caller doesn't want the range info */
143111878SVenu.Iyer@Sun.COM if (range == NULL)
143211878SVenu.Iyer@Sun.COM return;
143311878SVenu.Iyer@Sun.COM
143412850SPrakash.Jalan@Sun.COM if (pr->pr_range_cur_count++ == 0) {
143512850SPrakash.Jalan@Sun.COM /* first range */
143612850SPrakash.Jalan@Sun.COM pr->pr_flags |= MAC_PROP_INFO_RANGE;
143712850SPrakash.Jalan@Sun.COM range->mpr_type = MAC_PROPVAL_UINT32;
143812850SPrakash.Jalan@Sun.COM } else {
143912850SPrakash.Jalan@Sun.COM /* all ranges of a property should be of the same type */
144012850SPrakash.Jalan@Sun.COM ASSERT(range->mpr_type == MAC_PROPVAL_UINT32);
144112850SPrakash.Jalan@Sun.COM if (pr->pr_range_cur_count > range->mpr_count) {
144212850SPrakash.Jalan@Sun.COM pr->pr_errno = ENOSPC;
144312850SPrakash.Jalan@Sun.COM return;
144412850SPrakash.Jalan@Sun.COM }
144512850SPrakash.Jalan@Sun.COM }
144612850SPrakash.Jalan@Sun.COM
144712850SPrakash.Jalan@Sun.COM range32 = range->mpr_range_uint32;
144812850SPrakash.Jalan@Sun.COM range32[pr->pr_range_cur_count - 1].mpur_min = min;
144912850SPrakash.Jalan@Sun.COM range32[pr->pr_range_cur_count - 1].mpur_max = max;
145011878SVenu.Iyer@Sun.COM }
145111878SVenu.Iyer@Sun.COM
145211878SVenu.Iyer@Sun.COM void
mac_prop_info_set_perm(mac_prop_info_handle_t ph,uint8_t perm)145311878SVenu.Iyer@Sun.COM mac_prop_info_set_perm(mac_prop_info_handle_t ph, uint8_t perm)
145411878SVenu.Iyer@Sun.COM {
145511878SVenu.Iyer@Sun.COM mac_prop_info_state_t *pr = (mac_prop_info_state_t *)ph;
145611878SVenu.Iyer@Sun.COM
145711878SVenu.Iyer@Sun.COM pr->pr_perm = perm;
145811878SVenu.Iyer@Sun.COM pr->pr_flags |= MAC_PROP_INFO_PERM;
145911878SVenu.Iyer@Sun.COM }
146011878SVenu.Iyer@Sun.COM
mac_hcksum_get(mblk_t * mp,uint32_t * start,uint32_t * stuff,uint32_t * end,uint32_t * value,uint32_t * flags_ptr)146111878SVenu.Iyer@Sun.COM void mac_hcksum_get(mblk_t *mp, uint32_t *start, uint32_t *stuff,
146211878SVenu.Iyer@Sun.COM uint32_t *end, uint32_t *value, uint32_t *flags_ptr)
146311878SVenu.Iyer@Sun.COM {
146411878SVenu.Iyer@Sun.COM uint32_t flags;
146511878SVenu.Iyer@Sun.COM
146611878SVenu.Iyer@Sun.COM ASSERT(DB_TYPE(mp) == M_DATA);
146711878SVenu.Iyer@Sun.COM
146811878SVenu.Iyer@Sun.COM flags = DB_CKSUMFLAGS(mp) & HCK_FLAGS;
146911878SVenu.Iyer@Sun.COM if ((flags & (HCK_PARTIALCKSUM | HCK_FULLCKSUM)) != 0) {
147011878SVenu.Iyer@Sun.COM if (value != NULL)
147111878SVenu.Iyer@Sun.COM *value = (uint32_t)DB_CKSUM16(mp);
147211878SVenu.Iyer@Sun.COM if ((flags & HCK_PARTIALCKSUM) != 0) {
147311878SVenu.Iyer@Sun.COM if (start != NULL)
147411878SVenu.Iyer@Sun.COM *start = (uint32_t)DB_CKSUMSTART(mp);
147511878SVenu.Iyer@Sun.COM if (stuff != NULL)
147611878SVenu.Iyer@Sun.COM *stuff = (uint32_t)DB_CKSUMSTUFF(mp);
147711878SVenu.Iyer@Sun.COM if (end != NULL)
147811878SVenu.Iyer@Sun.COM *end = (uint32_t)DB_CKSUMEND(mp);
147911878SVenu.Iyer@Sun.COM }
148011878SVenu.Iyer@Sun.COM }
148111878SVenu.Iyer@Sun.COM
148211878SVenu.Iyer@Sun.COM if (flags_ptr != NULL)
148311878SVenu.Iyer@Sun.COM *flags_ptr = flags;
148411878SVenu.Iyer@Sun.COM }
148511878SVenu.Iyer@Sun.COM
mac_hcksum_set(mblk_t * mp,uint32_t start,uint32_t stuff,uint32_t end,uint32_t value,uint32_t flags)148611878SVenu.Iyer@Sun.COM void mac_hcksum_set(mblk_t *mp, uint32_t start, uint32_t stuff,
148711878SVenu.Iyer@Sun.COM uint32_t end, uint32_t value, uint32_t flags)
148811878SVenu.Iyer@Sun.COM {
148911878SVenu.Iyer@Sun.COM ASSERT(DB_TYPE(mp) == M_DATA);
149011878SVenu.Iyer@Sun.COM
149111878SVenu.Iyer@Sun.COM DB_CKSUMSTART(mp) = (intptr_t)start;
149211878SVenu.Iyer@Sun.COM DB_CKSUMSTUFF(mp) = (intptr_t)stuff;
149311878SVenu.Iyer@Sun.COM DB_CKSUMEND(mp) = (intptr_t)end;
149411878SVenu.Iyer@Sun.COM DB_CKSUMFLAGS(mp) = (uint16_t)flags;
149511878SVenu.Iyer@Sun.COM DB_CKSUM16(mp) = (uint16_t)value;
149611878SVenu.Iyer@Sun.COM }
149711878SVenu.Iyer@Sun.COM
149811878SVenu.Iyer@Sun.COM void
mac_lso_get(mblk_t * mp,uint32_t * mss,uint32_t * flags)149911878SVenu.Iyer@Sun.COM mac_lso_get(mblk_t *mp, uint32_t *mss, uint32_t *flags)
150011878SVenu.Iyer@Sun.COM {
150111878SVenu.Iyer@Sun.COM ASSERT(DB_TYPE(mp) == M_DATA);
150211878SVenu.Iyer@Sun.COM
150311878SVenu.Iyer@Sun.COM if (flags != NULL) {
150411878SVenu.Iyer@Sun.COM *flags = DB_CKSUMFLAGS(mp) & HW_LSO;
150511878SVenu.Iyer@Sun.COM if ((*flags != 0) && (mss != NULL))
150611878SVenu.Iyer@Sun.COM *mss = (uint32_t)DB_LSOMSS(mp);
150711878SVenu.Iyer@Sun.COM }
150811878SVenu.Iyer@Sun.COM }
1509