summaryrefslogtreecommitdiff
path: root/usr/src/uts/common/io/mac/mac_client.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/uts/common/io/mac/mac_client.c')
-rw-r--r--usr/src/uts/common/io/mac/mac_client.c1345
1 files changed, 1163 insertions, 182 deletions
diff --git a/usr/src/uts/common/io/mac/mac_client.c b/usr/src/uts/common/io/mac/mac_client.c
index 78c7eae9f2..2f8962f67a 100644
--- a/usr/src/uts/common/io/mac/mac_client.c
+++ b/usr/src/uts/common/io/mac/mac_client.c
@@ -108,6 +108,7 @@
#include <sys/mac_impl.h>
#include <sys/mac_client_impl.h>
#include <sys/mac_soft_ring.h>
+#include <sys/mac_stat.h>
#include <sys/dls.h>
#include <sys/dld.h>
#include <sys/modctl.h>
@@ -144,6 +145,10 @@ static void mac_client_remove_flow_from_list(mac_client_impl_t *,
static void mac_client_add_to_flow_list(mac_client_impl_t *, flow_entry_t *);
static void mac_rename_flow_names(mac_client_impl_t *, const char *);
static void mac_virtual_link_update(mac_impl_t *);
+static int mac_client_datapath_setup(mac_client_impl_t *, uint16_t,
+ uint8_t *, mac_resource_props_t *, boolean_t, mac_unicast_impl_t *);
+static void mac_client_datapath_teardown(mac_client_handle_t,
+ mac_unicast_impl_t *, flow_entry_t *);
/* ARGSUSED */
static int
@@ -560,6 +565,14 @@ mac_client_link_state(mac_client_impl_t *mcip)
}
/*
+ * These statistics are consumed by dladm show-link -s <vnic>,
+ * dladm show-vnic -s and netstat. With the introduction of dlstat,
+ * dladm show-link -s and dladm show-vnic -s witll be EOL'ed while
+ * netstat will consume from kstats introduced for dlstat. This code
+ * will be removed at that time.
+ */
+
+/*
* Return the statistics of a MAC client. These statistics are different
* then the statistics of the underlying MAC which are returned by
* mac_stat_get().
@@ -567,9 +580,17 @@ mac_client_link_state(mac_client_impl_t *mcip)
uint64_t
mac_client_stat_get(mac_client_handle_t mch, uint_t stat)
{
- mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
- mac_impl_t *mip = mcip->mci_mip;
- uint64_t val;
+ mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
+ mac_impl_t *mip = mcip->mci_mip;
+ flow_entry_t *flent = mcip->mci_flent;
+ mac_soft_ring_set_t *mac_srs;
+ mac_rx_stats_t *mac_rx_stat;
+ mac_tx_stats_t *mac_tx_stat;
+ int i;
+ uint64_t val = 0;
+
+ mac_srs = (mac_soft_ring_set_t *)(flent->fe_tx_srs);
+ mac_tx_stat = &mac_srs->srs_tx.st_stat;
switch (stat) {
case MAC_STAT_LINK_STATE:
@@ -588,37 +609,52 @@ mac_client_stat_get(mac_client_handle_t mch, uint_t stat)
val = mac_client_ifspeed(mcip);
break;
case MAC_STAT_MULTIRCV:
- val = mcip->mci_stat_multircv;
+ val = mcip->mci_misc_stat.mms_multircv;
break;
case MAC_STAT_BRDCSTRCV:
- val = mcip->mci_stat_brdcstrcv;
+ val = mcip->mci_misc_stat.mms_brdcstrcv;
break;
case MAC_STAT_MULTIXMT:
- val = mcip->mci_stat_multixmt;
+ val = mcip->mci_misc_stat.mms_multixmt;
break;
case MAC_STAT_BRDCSTXMT:
- val = mcip->mci_stat_brdcstxmt;
+ val = mcip->mci_misc_stat.mms_brdcstxmt;
break;
case MAC_STAT_OBYTES:
- val = mcip->mci_stat_obytes;
+ val = mac_tx_stat->mts_obytes;
break;
case MAC_STAT_OPACKETS:
- val = mcip->mci_stat_opackets;
+ val = mac_tx_stat->mts_opackets;
break;
case MAC_STAT_OERRORS:
- val = mcip->mci_stat_oerrors;
+ val = mac_tx_stat->mts_oerrors;
break;
case MAC_STAT_IPACKETS:
- val = mcip->mci_stat_ipackets;
+ for (i = 0; i < flent->fe_rx_srs_cnt; i++) {
+ mac_srs = (mac_soft_ring_set_t *)flent->fe_rx_srs[i];
+ mac_rx_stat = &mac_srs->srs_rx.sr_stat;
+ val += mac_rx_stat->mrs_intrcnt +
+ mac_rx_stat->mrs_pollcnt + mac_rx_stat->mrs_lclcnt;
+ }
break;
case MAC_STAT_RBYTES:
- val = mcip->mci_stat_ibytes;
+ for (i = 0; i < flent->fe_rx_srs_cnt; i++) {
+ mac_srs = (mac_soft_ring_set_t *)flent->fe_rx_srs[i];
+ mac_rx_stat = &mac_srs->srs_rx.sr_stat;
+ val += mac_rx_stat->mrs_intrbytes +
+ mac_rx_stat->mrs_pollbytes +
+ mac_rx_stat->mrs_lclbytes;
+ }
break;
case MAC_STAT_IERRORS:
- val = mcip->mci_stat_ierrors;
+ for (i = 0; i < flent->fe_rx_srs_cnt; i++) {
+ mac_srs = (mac_soft_ring_set_t *)flent->fe_rx_srs[i];
+ mac_rx_stat = &mac_srs->srs_rx.sr_stat;
+ val += mac_rx_stat->mrs_ierrors;
+ }
break;
default:
- val = mac_stat_default(mip, stat);
+ val = mac_driver_stat_default(mip, stat);
break;
}
@@ -676,12 +712,30 @@ mac_stat_get(mac_handle_t mh, uint_t stat)
* The driver doesn't support this statistic. Get the
* statistic's default value.
*/
- val = mac_stat_default(mip, stat);
+ val = mac_driver_stat_default(mip, stat);
}
return (val);
}
/*
+ * Query hardware rx ring corresponding to the pseudo ring.
+ */
+uint64_t
+mac_pseudo_rx_ring_stat_get(mac_ring_handle_t handle, uint_t stat)
+{
+ return (mac_rx_ring_stat_get(handle, stat));
+}
+
+/*
+ * Query hardware tx ring corresponding to the pseudo ring.
+ */
+uint64_t
+mac_pseudo_tx_ring_stat_get(mac_ring_handle_t handle, uint_t stat)
+{
+ return (mac_tx_ring_stat_get(handle, stat));
+}
+
+/*
* Utility function which returns the VID associated with a flow entry.
*/
uint16_t
@@ -752,6 +806,12 @@ mac_unicast_update_client_flow(mac_client_impl_t *mcip)
mac_flow_set_desc(flent, &flow_desc);
/*
+ * The v6 local addr (used by mac protection) needs to be
+ * regenerated because our mac address has changed.
+ */
+ mac_protect_update_v6_local_addr(mcip);
+
+ /*
* A MAC client could have one MAC address but multiple
* VLANs. In that case update the flow entries corresponding
* to all VLANs of the MAC client.
@@ -1184,20 +1244,14 @@ int
mac_client_open(mac_handle_t mh, mac_client_handle_t *mchp, char *name,
uint16_t flags)
{
- mac_impl_t *mip = (mac_impl_t *)mh;
- mac_client_impl_t *mcip;
- int err = 0;
- boolean_t share_desired =
- ((flags & MAC_OPEN_FLAGS_SHARES_DESIRED) != 0);
- boolean_t no_hwrings = ((flags & MAC_OPEN_FLAGS_NO_HWRINGS) != 0);
- boolean_t req_hwrings = ((flags & MAC_OPEN_FLAGS_REQ_HWRINGS) != 0);
- flow_entry_t *flent = NULL;
+ mac_impl_t *mip = (mac_impl_t *)mh;
+ mac_client_impl_t *mcip;
+ int err = 0;
+ boolean_t share_desired;
+ flow_entry_t *flent = NULL;
+ share_desired = (flags & MAC_OPEN_FLAGS_SHARES_DESIRED) != 0;
*mchp = NULL;
- if (share_desired && no_hwrings) {
- /* can't have shares but no hardware rings */
- return (EINVAL);
- }
i_mac_perim_enter(mip);
@@ -1249,6 +1303,9 @@ mac_client_open(mac_handle_t mh, mac_client_handle_t *mchp, char *name,
if ((flags & MAC_OPEN_FLAGS_IS_AGGR_PORT) != 0)
mcip->mci_state_flags |= MCIS_IS_AGGR_PORT;
+ if (mip->mi_state_flags & MIS_IS_AGGR)
+ mcip->mci_state_flags |= MCIS_IS_AGGR;
+
if ((flags & MAC_OPEN_FLAGS_USE_DATALINK_NAME) != 0) {
datalink_id_t linkid;
@@ -1283,19 +1340,18 @@ mac_client_open(mac_handle_t mh, mac_client_handle_t *mchp, char *name,
if (flags & MAC_OPEN_FLAGS_MULTI_PRIMARY)
mcip->mci_flags |= MAC_CLIENT_FLAGS_MULTI_PRIMARY;
+ if (flags & MAC_OPEN_FLAGS_NO_UNICAST_ADDR)
+ mcip->mci_state_flags |= MCIS_NO_UNICAST_ADDR;
+
+ mac_protect_init(mcip);
+
/* the subflow table will be created dynamically */
mcip->mci_subflow_tab = NULL;
- mcip->mci_stat_multircv = 0;
- mcip->mci_stat_brdcstrcv = 0;
- mcip->mci_stat_multixmt = 0;
- mcip->mci_stat_brdcstxmt = 0;
-
- mcip->mci_stat_obytes = 0;
- mcip->mci_stat_opackets = 0;
- mcip->mci_stat_oerrors = 0;
- mcip->mci_stat_ibytes = 0;
- mcip->mci_stat_ipackets = 0;
- mcip->mci_stat_ierrors = 0;
+
+ mcip->mci_misc_stat.mms_multircv = 0;
+ mcip->mci_misc_stat.mms_brdcstrcv = 0;
+ mcip->mci_misc_stat.mms_multixmt = 0;
+ mcip->mci_misc_stat.mms_brdcstxmt = 0;
/* Create an initial flow */
@@ -1321,20 +1377,25 @@ mac_client_open(mac_handle_t mh, mac_client_handle_t *mchp, char *name,
*/
mac_client_add(mcip);
- if (no_hwrings)
- mcip->mci_state_flags |= MCIS_NO_HWRINGS;
- if (req_hwrings)
- mcip->mci_state_flags |= MCIS_REQ_HWRINGS;
mcip->mci_share = NULL;
- if (share_desired) {
- ASSERT(!no_hwrings);
+ if (share_desired)
i_mac_share_alloc(mcip);
- }
DTRACE_PROBE2(mac__client__open__allocated, mac_impl_t *,
mcip->mci_mip, mac_client_impl_t *, mcip);
*mchp = (mac_client_handle_t)mcip;
+ /*
+ * We will do mimimal datapath setup to allow a MAC client to
+ * transmit or receive non-unicast packets without waiting
+ * for mac_unicast_add.
+ */
+ if (mcip->mci_state_flags & MCIS_NO_UNICAST_ADDR) {
+ if ((err = mac_client_datapath_setup(mcip, VLAN_ID_NONE,
+ NULL, NULL, B_TRUE, NULL)) != 0) {
+ goto done;
+ }
+ }
i_mac_perim_exit(mip);
return (0);
@@ -1373,6 +1434,13 @@ mac_client_close(mac_client_handle_t mch, uint16_t flags)
return;
}
+ /* If we have only setup up minimal datapth setup, tear it down */
+ if (mcip->mci_state_flags & MCIS_NO_UNICAST_ADDR) {
+ mac_client_datapath_teardown((mac_client_handle_t)mcip, NULL,
+ mcip->mci_flent);
+ mcip->mci_state_flags &= ~MCIS_NO_UNICAST_ADDR;
+ }
+
/*
* Remove the flent associated with the MAC client
*/
@@ -1389,7 +1457,7 @@ mac_client_close(mac_client_handle_t mch, uint16_t flags)
ASSERT(mcip->mci_tx_notify_cb_list == NULL);
i_mac_share_free(mcip);
-
+ mac_protect_fini(mcip);
mac_client_remove(mcip);
i_mac_perim_exit(mip);
@@ -1495,6 +1563,335 @@ mac_update_subflow_priority(mac_client_impl_t *mcip)
}
/*
+ * Modify the TX or RX ring properties. We could either just move around
+ * rings, i.e add/remove rings given to a client. Or this might cause the
+ * client to move from hardware based to software or the other way around.
+ * If we want to reset this property, then we clear the mask, additionally
+ * if the client was given a non-default group we remove all rings except
+ * for 1 and give it back to the default group.
+ */
+int
+mac_client_set_rings_prop(mac_client_impl_t *mcip, mac_resource_props_t *mrp,
+ mac_resource_props_t *tmrp)
+{
+ mac_impl_t *mip = mcip->mci_mip;
+ flow_entry_t *flent = mcip->mci_flent;
+ uint8_t *mac_addr;
+ int err = 0;
+ mac_group_t *defgrp;
+ mac_group_t *group;
+ mac_group_t *ngrp;
+ mac_resource_props_t *cmrp = MCIP_RESOURCE_PROPS(mcip);
+ uint_t ringcnt;
+ boolean_t unspec;
+
+ if (mcip->mci_share != NULL)
+ return (EINVAL);
+
+ if (mrp->mrp_mask & MRP_RX_RINGS) {
+ unspec = mrp->mrp_mask & MRP_RXRINGS_UNSPEC;
+ group = flent->fe_rx_ring_group;
+ defgrp = MAC_DEFAULT_RX_GROUP(mip);
+ mac_addr = flent->fe_flow_desc.fd_dst_mac;
+
+ /*
+ * No resulting change. If we are resetting on a client on
+ * which there was no rx rings property. For dynamic group
+ * if we are setting the same number of rings already set.
+ * For static group if we are requesting a group again.
+ */
+ if (mrp->mrp_mask & MRP_RINGS_RESET) {
+ if (!(tmrp->mrp_mask & MRP_RX_RINGS))
+ return (0);
+ } else {
+ if (unspec) {
+ if (tmrp->mrp_mask & MRP_RXRINGS_UNSPEC)
+ return (0);
+ } else if (mip->mi_rx_group_type ==
+ MAC_GROUP_TYPE_DYNAMIC) {
+ if ((tmrp->mrp_mask & MRP_RX_RINGS) &&
+ !(tmrp->mrp_mask & MRP_RXRINGS_UNSPEC) &&
+ mrp->mrp_nrxrings == tmrp->mrp_nrxrings) {
+ return (0);
+ }
+ }
+ }
+ /* Resetting the prop */
+ if (mrp->mrp_mask & MRP_RINGS_RESET) {
+ /*
+ * We will just keep one ring and give others back if
+ * we are not the primary. For the primary we give
+ * all the rings in the default group except the
+ * default ring. If it is a static group, then
+ * we don't do anything, but clear the MRP_RX_RINGS
+ * flag.
+ */
+ if (group != defgrp) {
+ if (mip->mi_rx_group_type ==
+ MAC_GROUP_TYPE_DYNAMIC) {
+ /*
+ * This group has reserved rings
+ * that need to be released now,
+ * so does the group.
+ */
+ MAC_RX_RING_RELEASED(mip,
+ group->mrg_cur_count);
+ MAC_RX_GRP_RELEASED(mip);
+ if ((flent->fe_type &
+ FLOW_PRIMARY_MAC) != 0) {
+ if (mip->mi_nactiveclients ==
+ 1) {
+ (void)
+ mac_rx_switch_group(
+ mcip, group,
+ defgrp);
+ return (0);
+ } else {
+ cmrp->mrp_nrxrings =
+ group->
+ mrg_cur_count +
+ defgrp->
+ mrg_cur_count - 1;
+ }
+ } else {
+ cmrp->mrp_nrxrings = 1;
+ }
+ (void) mac_group_ring_modify(mcip,
+ group, defgrp);
+ } else {
+ /*
+ * If this is a static group, we
+ * need to release the group. The
+ * client will remain in the same
+ * group till some other client
+ * needs this group.
+ */
+ MAC_RX_GRP_RELEASED(mip);
+ }
+ /* Let check if we can give this an excl group */
+ } else if (group == defgrp) {
+ ngrp = mac_reserve_rx_group(mcip, mac_addr,
+ B_TRUE);
+ /* Couldn't give it a group, that's fine */
+ if (ngrp == NULL)
+ return (0);
+ /* Switch to H/W */
+ if (mac_rx_switch_group(mcip, defgrp, ngrp) !=
+ 0) {
+ mac_stop_group(ngrp);
+ return (0);
+ }
+ }
+ /*
+ * If the client is in the default group, we will
+ * just clear the MRP_RX_RINGS and leave it as
+ * it rather than look for an exclusive group
+ * for it.
+ */
+ return (0);
+ }
+
+ if (group == defgrp && ((mrp->mrp_nrxrings > 0) || unspec)) {
+ ngrp = mac_reserve_rx_group(mcip, mac_addr, B_TRUE);
+ if (ngrp == NULL)
+ return (ENOSPC);
+
+ /* Switch to H/W */
+ if (mac_rx_switch_group(mcip, defgrp, ngrp) != 0) {
+ mac_release_rx_group(mcip, ngrp);
+ return (ENOSPC);
+ }
+ MAC_RX_GRP_RESERVED(mip);
+ if (mip->mi_rx_group_type == MAC_GROUP_TYPE_DYNAMIC)
+ MAC_RX_RING_RESERVED(mip, ngrp->mrg_cur_count);
+ } else if (group != defgrp && !unspec &&
+ mrp->mrp_nrxrings == 0) {
+ /* Switch to S/W */
+ ringcnt = group->mrg_cur_count;
+ if (mac_rx_switch_group(mcip, group, defgrp) != 0)
+ return (ENOSPC);
+ if (tmrp->mrp_mask & MRP_RX_RINGS) {
+ MAC_RX_GRP_RELEASED(mip);
+ if (mip->mi_rx_group_type ==
+ MAC_GROUP_TYPE_DYNAMIC) {
+ MAC_RX_RING_RELEASED(mip, ringcnt);
+ }
+ }
+ } else if (group != defgrp && mip->mi_rx_group_type ==
+ MAC_GROUP_TYPE_DYNAMIC) {
+ ringcnt = group->mrg_cur_count;
+ err = mac_group_ring_modify(mcip, group, defgrp);
+ if (err != 0)
+ return (err);
+ /*
+ * Update the accounting. If this group
+ * already had explicitly reserved rings,
+ * we need to update the rings based on
+ * the new ring count. If this group
+ * had not explicitly reserved rings,
+ * then we just reserve the rings asked for
+ * and reserve the group.
+ */
+ if (tmrp->mrp_mask & MRP_RX_RINGS) {
+ if (ringcnt > group->mrg_cur_count) {
+ MAC_RX_RING_RELEASED(mip,
+ ringcnt - group->mrg_cur_count);
+ } else {
+ MAC_RX_RING_RESERVED(mip,
+ group->mrg_cur_count - ringcnt);
+ }
+ } else {
+ MAC_RX_RING_RESERVED(mip, group->mrg_cur_count);
+ MAC_RX_GRP_RESERVED(mip);
+ }
+ }
+ }
+ if (mrp->mrp_mask & MRP_TX_RINGS) {
+ unspec = mrp->mrp_mask & MRP_TXRINGS_UNSPEC;
+ group = flent->fe_tx_ring_group;
+ defgrp = MAC_DEFAULT_TX_GROUP(mip);
+
+ /*
+ * For static groups we only allow rings=0 or resetting the
+ * rings property.
+ */
+ if (mrp->mrp_ntxrings > 0 &&
+ mip->mi_tx_group_type != MAC_GROUP_TYPE_DYNAMIC) {
+ return (ENOTSUP);
+ }
+ if (mrp->mrp_mask & MRP_RINGS_RESET) {
+ if (!(tmrp->mrp_mask & MRP_TX_RINGS))
+ return (0);
+ } else {
+ if (unspec) {
+ if (tmrp->mrp_mask & MRP_TXRINGS_UNSPEC)
+ return (0);
+ } else if (mip->mi_tx_group_type ==
+ MAC_GROUP_TYPE_DYNAMIC) {
+ if ((tmrp->mrp_mask & MRP_TX_RINGS) &&
+ !(tmrp->mrp_mask & MRP_TXRINGS_UNSPEC) &&
+ mrp->mrp_ntxrings == tmrp->mrp_ntxrings) {
+ return (0);
+ }
+ }
+ }
+ /* Resetting the prop */
+ if (mrp->mrp_mask & MRP_RINGS_RESET) {
+ if (group != defgrp) {
+ if (mip->mi_tx_group_type ==
+ MAC_GROUP_TYPE_DYNAMIC) {
+ ringcnt = group->mrg_cur_count;
+ if ((flent->fe_type &
+ FLOW_PRIMARY_MAC) != 0) {
+ mac_tx_client_quiesce(
+ (mac_client_handle_t)
+ mcip);
+ mac_tx_switch_group(mcip,
+ group, defgrp);
+ mac_tx_client_restart(
+ (mac_client_handle_t)
+ mcip);
+ MAC_TX_GRP_RELEASED(mip);
+ MAC_TX_RING_RELEASED(mip,
+ ringcnt);
+ return (0);
+ }
+ cmrp->mrp_ntxrings = 1;
+ (void) mac_group_ring_modify(mcip,
+ group, defgrp);
+ /*
+ * This group has reserved rings
+ * that need to be released now.
+ */
+ MAC_TX_RING_RELEASED(mip, ringcnt);
+ }
+ /*
+ * If this is a static group, we
+ * need to release the group. The
+ * client will remain in the same
+ * group till some other client
+ * needs this group.
+ */
+ MAC_TX_GRP_RELEASED(mip);
+ } else if (group == defgrp &&
+ (flent->fe_type & FLOW_PRIMARY_MAC) == 0) {
+ ngrp = mac_reserve_tx_group(mcip, B_TRUE);
+ if (ngrp == NULL)
+ return (0);
+ mac_tx_client_quiesce(
+ (mac_client_handle_t)mcip);
+ mac_tx_switch_group(mcip, defgrp, ngrp);
+ mac_tx_client_restart(
+ (mac_client_handle_t)mcip);
+ }
+ /*
+ * If the client is in the default group, we will
+ * just clear the MRP_TX_RINGS and leave it as
+ * it rather than look for an exclusive group
+ * for it.
+ */
+ return (0);
+ }
+
+ /* Switch to H/W */
+ if (group == defgrp && ((mrp->mrp_ntxrings > 0) || unspec)) {
+ ngrp = mac_reserve_tx_group(mcip, B_TRUE);
+ if (ngrp == NULL)
+ return (ENOSPC);
+ mac_tx_client_quiesce((mac_client_handle_t)mcip);
+ mac_tx_switch_group(mcip, defgrp, ngrp);
+ mac_tx_client_restart((mac_client_handle_t)mcip);
+ MAC_TX_GRP_RESERVED(mip);
+ if (mip->mi_tx_group_type == MAC_GROUP_TYPE_DYNAMIC)
+ MAC_TX_RING_RESERVED(mip, ngrp->mrg_cur_count);
+ /* Switch to S/W */
+ } else if (group != defgrp && !unspec &&
+ mrp->mrp_ntxrings == 0) {
+ /* Switch to S/W */
+ ringcnt = group->mrg_cur_count;
+ mac_tx_client_quiesce((mac_client_handle_t)mcip);
+ mac_tx_switch_group(mcip, group, defgrp);
+ mac_tx_client_restart((mac_client_handle_t)mcip);
+ if (tmrp->mrp_mask & MRP_TX_RINGS) {
+ MAC_TX_GRP_RELEASED(mip);
+ if (mip->mi_tx_group_type ==
+ MAC_GROUP_TYPE_DYNAMIC) {
+ MAC_TX_RING_RELEASED(mip, ringcnt);
+ }
+ }
+ } else if (group != defgrp && mip->mi_tx_group_type ==
+ MAC_GROUP_TYPE_DYNAMIC) {
+ ringcnt = group->mrg_cur_count;
+ err = mac_group_ring_modify(mcip, group, defgrp);
+ if (err != 0)
+ return (err);
+ /*
+ * Update the accounting. If this group
+ * already had explicitly reserved rings,
+ * we need to update the rings based on
+ * the new ring count. If this group
+ * had not explicitly reserved rings,
+ * then we just reserve the rings asked for
+ * and reserve the group.
+ */
+ if (tmrp->mrp_mask & MRP_TX_RINGS) {
+ if (ringcnt > group->mrg_cur_count) {
+ MAC_TX_RING_RELEASED(mip,
+ ringcnt - group->mrg_cur_count);
+ } else {
+ MAC_TX_RING_RESERVED(mip,
+ group->mrg_cur_count - ringcnt);
+ }
+ } else {
+ MAC_TX_RING_RESERVED(mip, group->mrg_cur_count);
+ MAC_TX_GRP_RESERVED(mip);
+ }
+ }
+ }
+ return (0);
+}
+
+/*
* When the MAC client is being brought up (i.e. we do a unicast_add) we need
* to initialize the cpu and resource control structure in the
* mac_client_impl_t from the mac_impl_t (i.e if there are any cached
@@ -1506,16 +1903,73 @@ mac_resource_ctl_set(mac_client_handle_t mch, mac_resource_props_t *mrp)
mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
mac_impl_t *mip = (mac_impl_t *)mcip->mci_mip;
int err = 0;
+ flow_entry_t *flent = mcip->mci_flent;
+ mac_resource_props_t *omrp, *nmrp = MCIP_RESOURCE_PROPS(mcip);
ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
- err = mac_validate_props(mrp);
+ err = mac_validate_props(mcip->mci_state_flags & MCIS_IS_VNIC ?
+ mcip->mci_upper_mip : mip, mrp);
if (err != 0)
return (err);
+ /*
+ * Copy over the existing properties since mac_update_resources
+ * will modify the client's mrp. Currently, the saved property
+ * is used to determine the difference between existing and
+ * modified rings property.
+ */
+ omrp = kmem_zalloc(sizeof (*omrp), KM_SLEEP);
+ bcopy(nmrp, omrp, sizeof (*omrp));
mac_update_resources(mrp, MCIP_RESOURCE_PROPS(mcip), B_FALSE);
if (MCIP_DATAPATH_SETUP(mcip)) {
/*
+ * We support rings only for primary client when there are
+ * multiple clients sharing the same MAC address (e.g. VLAN).
+ */
+ if (mrp->mrp_mask & MRP_RX_RINGS ||
+ mrp->mrp_mask & MRP_TX_RINGS) {
+
+ if ((err = mac_client_set_rings_prop(mcip, mrp,
+ omrp)) != 0) {
+ if (omrp->mrp_mask & MRP_RX_RINGS) {
+ nmrp->mrp_mask |= MRP_RX_RINGS;
+ nmrp->mrp_nrxrings = omrp->mrp_nrxrings;
+ } else {
+ nmrp->mrp_mask &= ~MRP_RX_RINGS;
+ nmrp->mrp_nrxrings = 0;
+ }
+ if (omrp->mrp_mask & MRP_TX_RINGS) {
+ nmrp->mrp_mask |= MRP_TX_RINGS;
+ nmrp->mrp_ntxrings = omrp->mrp_ntxrings;
+ } else {
+ nmrp->mrp_mask &= ~MRP_TX_RINGS;
+ nmrp->mrp_ntxrings = 0;
+ }
+ if (omrp->mrp_mask & MRP_RXRINGS_UNSPEC)
+ omrp->mrp_mask |= MRP_RXRINGS_UNSPEC;
+ else
+ omrp->mrp_mask &= ~MRP_RXRINGS_UNSPEC;
+
+ if (omrp->mrp_mask & MRP_TXRINGS_UNSPEC)
+ omrp->mrp_mask |= MRP_TXRINGS_UNSPEC;
+ else
+ omrp->mrp_mask &= ~MRP_TXRINGS_UNSPEC;
+ kmem_free(omrp, sizeof (*omrp));
+ return (err);
+ }
+
+ /*
+ * If we modified the rings property of the primary
+ * we need to update the property fields of its
+ * VLANs as they inherit the primary's properites.
+ */
+ if (mac_is_primary_client(mcip)) {
+ mac_set_prim_vlan_rings(mip,
+ MCIP_RESOURCE_PROPS(mcip));
+ }
+ }
+ /*
* We have to set this prior to calling mac_flow_modify.
*/
if (mrp->mrp_mask & MRP_PRIORITY) {
@@ -1528,11 +1982,11 @@ mac_resource_ctl_set(mac_client_handle_t mch, mac_resource_props_t *mrp)
}
}
- mac_flow_modify(mip->mi_flow_tab, mcip->mci_flent, mrp);
+ mac_flow_modify(mip->mi_flow_tab, flent, mrp);
if (mrp->mrp_mask & MRP_PRIORITY)
mac_update_subflow_priority(mcip);
- return (0);
}
+ kmem_free(omrp, sizeof (*omrp));
return (0);
}
@@ -1562,8 +2016,12 @@ mac_unicast_flow_create(mac_client_impl_t *mcip, uint8_t *mac_addr,
*/
bzero(&flow_desc, sizeof (flow_desc));
- flow_desc.fd_mac_len = mip->mi_type->mt_addr_length;
- bcopy(mac_addr, flow_desc.fd_dst_mac, flow_desc.fd_mac_len);
+ ASSERT(mac_addr != NULL ||
+ (mcip->mci_state_flags & MCIS_NO_UNICAST_ADDR));
+ if (mac_addr != NULL) {
+ flow_desc.fd_mac_len = mip->mi_type->mt_addr_length;
+ bcopy(mac_addr, flow_desc.fd_dst_mac, flow_desc.fd_mac_len);
+ }
flow_desc.fd_mask = FLOW_LINK_DST;
if (vid != 0) {
flow_desc.fd_vid = vid;
@@ -1612,6 +2070,7 @@ mac_unicast_flow_create(mac_client_impl_t *mcip, uint8_t *mac_addr,
flent_flags, flent)) != 0)
return (err);
+ mac_misc_stat_create(*flent);
FLOW_MARK(*flent, FE_INCIPIENT);
(*flent)->fe_mcip = mcip;
@@ -1700,6 +2159,9 @@ mac_client_datapath_setup(mac_client_impl_t *mcip, uint16_t vid,
boolean_t nactiveclients_added = B_FALSE;
flow_entry_t *flent;
int err = 0;
+ boolean_t no_unicast;
+
+ no_unicast = mcip->mci_state_flags & MCIS_NO_UNICAST_ADDR;
if ((err = mac_start((mac_handle_t)mip)) != 0)
goto bail;
@@ -1725,10 +2187,11 @@ mac_client_datapath_setup(mac_client_impl_t *mcip, uint16_t vid,
/* We are configuring the unicast flow now */
if (!MCIP_DATAPATH_SETUP(mcip)) {
- MAC_CLIENT_SET_PRIORITY_RANGE(mcip,
- (mrp->mrp_mask & MRP_PRIORITY) ? mrp->mrp_priority :
- MPL_LINK_DEFAULT);
-
+ if (mrp != NULL) {
+ MAC_CLIENT_SET_PRIORITY_RANGE(mcip,
+ (mrp->mrp_mask & MRP_PRIORITY) ? mrp->mrp_priority :
+ MPL_LINK_DEFAULT);
+ }
if ((err = mac_unicast_flow_create(mcip, mac_addr, vid,
isprimary, B_TRUE, &flent, mrp)) != 0)
goto bail;
@@ -1743,6 +2206,8 @@ mac_client_datapath_setup(mac_client_impl_t *mcip, uint16_t vid,
if ((err = mac_datapath_setup(mcip, flent, SRST_LINK)) != 0)
goto bail;
+ if (no_unicast)
+ goto done_setup;
/*
* The unicast MAC address must have been added successfully.
*/
@@ -1756,6 +2221,7 @@ mac_client_datapath_setup(mac_client_impl_t *mcip, uint16_t vid,
} else {
mac_address_t *map = mcip->mci_unicast;
+ ASSERT(!no_unicast);
/*
* A unicast flow already exists for that MAC client,
* this flow must be the same mac address but with
@@ -1794,7 +2260,7 @@ mac_client_datapath_setup(mac_client_impl_t *mcip, uint16_t vid,
mcip->mci_unicast_list = muip;
rw_exit(&mcip->mci_rw_lock);
-
+done_setup:
/*
* First add the flent to the flow list of this mcip. Then set
* the mip's mi_single_active_client if needed. The Rx path assumes
@@ -1802,7 +2268,6 @@ mac_client_datapath_setup(mac_client_impl_t *mcip, uint16_t vid,
* flent.
*/
mac_client_add_to_flow_list(mcip, flent);
-
if (nactiveclients_added)
mac_update_single_active_client(mip);
/*
@@ -1889,7 +2354,7 @@ i_mac_unicast_add(mac_client_handle_t mch, uint8_t *mac_addr, uint16_t flags,
boolean_t fastpath_disabled = B_FALSE;
boolean_t is_primary = (flags & MAC_UNICAST_PRIMARY);
boolean_t is_unicast_hw = (flags & MAC_UNICAST_HW);
- mac_resource_props_t mrp;
+ mac_resource_props_t *mrp;
boolean_t passive_client = B_FALSE;
mac_unicast_impl_t *muip;
boolean_t is_vnic_primary =
@@ -1899,6 +2364,13 @@ i_mac_unicast_add(mac_client_handle_t mch, uint8_t *mac_addr, uint16_t flags,
ASSERT(!((mip->mi_state_flags & MIS_IS_VNIC) && (vid != 0)));
/*
+ * Can't unicast add if the client asked only for minimal datapath
+ * setup.
+ */
+ if (mcip->mci_state_flags & MCIS_NO_UNICAST_ADDR)
+ return (ENOTSUP);
+
+ /*
* Check for an attempted use of the current Port VLAN ID, if enabled.
* No client may use it.
*/
@@ -2020,7 +2492,7 @@ i_mac_unicast_add(mac_client_handle_t mch, uint8_t *mac_addr, uint16_t flags,
mip->mi_state_flags |= MIS_EXCLUSIVE;
}
- bzero(&mrp, sizeof (mac_resource_props_t));
+ mrp = kmem_zalloc(sizeof (*mrp), KM_SLEEP);
if (is_primary && !(mcip->mci_state_flags & (MCIS_IS_VNIC |
MCIS_IS_AGGR_PORT))) {
/*
@@ -2029,11 +2501,40 @@ i_mac_unicast_add(mac_client_handle_t mch, uint8_t *mac_addr, uint16_t flags,
* port, its property should be set in the mcip when the
* VNIC/aggr was created.
*/
- mac_get_resources((mac_handle_t)mip, &mrp);
- (void) mac_client_set_resources(mch, &mrp);
+ mac_get_resources((mac_handle_t)mip, mrp);
+ (void) mac_client_set_resources(mch, mrp);
} else if (mcip->mci_state_flags & MCIS_IS_VNIC) {
- bcopy(MCIP_RESOURCE_PROPS(mcip), &mrp,
- sizeof (mac_resource_props_t));
+ /*
+ * This is a primary VLAN client, we don't support
+ * specifying rings property for this as it inherits the
+ * rings property from its MAC.
+ */
+ if (is_vnic_primary) {
+ mac_resource_props_t *vmrp;
+
+ vmrp = MCIP_RESOURCE_PROPS(mcip);
+ if (vmrp->mrp_mask & MRP_RX_RINGS ||
+ vmrp->mrp_mask & MRP_TX_RINGS) {
+ if (fastpath_disabled)
+ mac_fastpath_enable((mac_handle_t)mip);
+ kmem_free(mrp, sizeof (*mrp));
+ return (ENOTSUP);
+ }
+ /*
+ * Additionally we also need to inherit any
+ * rings property from the MAC.
+ */
+ mac_get_resources((mac_handle_t)mip, mrp);
+ if (mrp->mrp_mask & MRP_RX_RINGS) {
+ vmrp->mrp_mask |= MRP_RX_RINGS;
+ vmrp->mrp_nrxrings = mrp->mrp_nrxrings;
+ }
+ if (mrp->mrp_mask & MRP_TX_RINGS) {
+ vmrp->mrp_mask |= MRP_TX_RINGS;
+ vmrp->mrp_ntxrings = mrp->mrp_ntxrings;
+ }
+ }
+ bcopy(MCIP_RESOURCE_PROPS(mcip), mrp, sizeof (*mrp));
}
muip = kmem_zalloc(sizeof (mac_unicast_impl_t), KM_SLEEP);
@@ -2151,6 +2652,7 @@ i_mac_unicast_add(mac_client_handle_t mch, uint8_t *mac_addr, uint16_t flags,
ASSERT((mcip->mci_flags &
MAC_CLIENT_FLAGS_PASSIVE_PRIMARY) == 0);
mcip->mci_flags |= MAC_CLIENT_FLAGS_PASSIVE_PRIMARY;
+ kmem_free(mrp, sizeof (*mrp));
/*
* Stash the unicast address handle, we will use it when
@@ -2161,10 +2663,12 @@ i_mac_unicast_add(mac_client_handle_t mch, uint8_t *mac_addr, uint16_t flags,
return (0);
}
- err = mac_client_datapath_setup(mcip, vid, mac_addr, &mrp,
+ err = mac_client_datapath_setup(mcip, vid, mac_addr, mrp,
is_primary || is_vnic_primary, muip);
if (err != 0)
goto bail_out;
+
+ kmem_free(mrp, sizeof (*mrp));
*mah = (mac_unicast_handle_t)muip;
return (0);
@@ -2178,6 +2682,7 @@ bail_out:
mip->mi_driver);
}
}
+ kmem_free(mrp, sizeof (*mrp));
kmem_free(muip, sizeof (mac_unicast_impl_t));
return (err);
}
@@ -2227,25 +2732,33 @@ mac_unicast_add(mac_client_handle_t mch, uint8_t *mac_addr, uint16_t flags,
return (err);
}
-void
+static void
mac_client_datapath_teardown(mac_client_handle_t mch, mac_unicast_impl_t *muip,
flow_entry_t *flent)
{
mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
mac_impl_t *mip = mcip->mci_mip;
+ boolean_t no_unicast;
/*
- * We would have initialized subflows etc. only if we brought up
- * the primary client and set the unicast unicast address etc.
- * Deactivate the flows. The flow entry will be removed from the
- * active flow tables, and the associated SRS, softrings etc will
- * be deleted. But the flow entry itself won't be destroyed, instead
- * it will continue to be archived off the the global flow hash
- * list, for a possible future activation when say IP is plumbed
- * again.
+ * If we have not added a unicast address for this MAC client, just
+ * teardown the datapath.
*/
- mac_link_release_flows(mch);
+ no_unicast = mcip->mci_state_flags & MCIS_NO_UNICAST_ADDR;
+ if (!no_unicast) {
+ /*
+ * We would have initialized subflows etc. only if we brought
+ * up the primary client and set the unicast unicast address
+ * etc. Deactivate the flows. The flow entry will be removed
+ * from the active flow tables, and the associated SRS,
+ * softrings etc will be deleted. But the flow entry itself
+ * won't be destroyed, instead it will continue to be archived
+ * off the the global flow hash list, for a possible future
+ * activation when say IP is plumbed again.
+ */
+ mac_link_release_flows(mch);
+ }
mip->mi_nactiveclients--;
mac_update_single_active_client(mip);
@@ -2287,6 +2800,7 @@ mac_client_datapath_teardown(mac_client_handle_t mch, mac_unicast_impl_t *muip,
flent->fe_tx_srs == NULL && flent->fe_rx_srs_cnt == 0);
flent->fe_flags = FE_MC_NO_DATAPATH;
flow_stat_destroy(flent);
+ mac_misc_stat_delete(flent);
/* Initialize the receiver function to a safe routine */
flent->fe_cb_fn = (flow_fn_t)mac_pkt_drop;
@@ -2297,8 +2811,9 @@ mac_client_datapath_teardown(mac_client_handle_t mch, mac_unicast_impl_t *muip,
mutex_exit(&flent->fe_lock);
if (mip->mi_type->mt_brdcst_addr != NULL) {
+ ASSERT(muip != NULL || no_unicast);
mac_bcast_delete(mcip, mip->mi_type->mt_brdcst_addr,
- muip->mui_vid);
+ muip != NULL ? muip->mui_vid : VLAN_ID_NONE);
}
if (mip->mi_nactiveclients == 1) {
@@ -2324,8 +2839,12 @@ mac_client_datapath_teardown(mac_client_handle_t mch, mac_unicast_impl_t *muip,
if (mcip->mci_state_flags & MCIS_DISABLE_TX_VID_CHECK)
mcip->mci_state_flags &= ~MCIS_DISABLE_TX_VID_CHECK;
- kmem_free(muip, sizeof (mac_unicast_impl_t));
+ if (muip != NULL)
+ kmem_free(muip, sizeof (mac_unicast_impl_t));
+ mac_protect_cancel_timer(mcip);
+ mac_protect_flush_dhcp(mcip);
+ bzero(&mcip->mci_misc_stat, sizeof (mcip->mci_misc_stat));
/*
* Disable fastpath if this is a VNIC or a VLAN.
*/
@@ -2345,7 +2864,7 @@ mac_unicast_remove(mac_client_handle_t mch, mac_unicast_handle_t mah)
mac_unicast_impl_t *pre;
mac_impl_t *mip = mcip->mci_mip;
flow_entry_t *flent;
- boolean_t isprimary = B_FALSE;
+ uint16_t mui_vid;
i_mac_perim_enter(mip);
if (mcip->mci_flags & MAC_CLIENT_FLAGS_VNIC_PRIMARY) {
@@ -2436,11 +2955,6 @@ mac_unicast_remove(mac_client_handle_t mch, mac_unicast_handle_t mah)
rw_exit(&mcip->mci_rw_lock);
}
- if ((mcip->mci_flags & MAC_CLIENT_FLAGS_PRIMARY) &&
- muip->mui_vid == 0) {
- mcip->mci_flags &= ~MAC_CLIENT_FLAGS_PRIMARY;
- isprimary = B_TRUE;
- }
if (!mac_client_single_rcvr(mcip)) {
/*
* This MAC client is shared by more than one unicast
@@ -2490,34 +3004,39 @@ mac_unicast_remove(mac_client_handle_t mch, mac_unicast_handle_t mah)
return (0);
}
+ mui_vid = muip->mui_vid;
mac_client_datapath_teardown(mch, muip, flent);
+ if ((mcip->mci_flags & MAC_CLIENT_FLAGS_PRIMARY) && mui_vid == 0) {
+ mcip->mci_flags &= ~MAC_CLIENT_FLAGS_PRIMARY;
+ } else {
+ i_mac_perim_exit(mip);
+ return (0);
+ }
+
/*
* If we are removing the primary, check if we have a passive primary
* client that we need to activate now.
*/
- if (!isprimary) {
- i_mac_perim_exit(mip);
- return (0);
- }
mcip = mac_get_passive_primary_client(mip);
if (mcip != NULL) {
- mac_resource_props_t mrp;
+ mac_resource_props_t *mrp;
mac_unicast_impl_t *muip;
mcip->mci_flags &= ~MAC_CLIENT_FLAGS_PASSIVE_PRIMARY;
- bzero(&mrp, sizeof (mac_resource_props_t));
+ mrp = kmem_zalloc(sizeof (*mrp), KM_SLEEP);
+
/*
* Apply the property cached in the mac_impl_t to the
* primary mac client.
*/
- mac_get_resources((mac_handle_t)mip, &mrp);
- (void) mac_client_set_resources(mch, &mrp);
+ mac_get_resources((mac_handle_t)mip, mrp);
+ (void) mac_client_set_resources(mch, mrp);
ASSERT(mcip->mci_p_unicast_list != NULL);
muip = mcip->mci_p_unicast_list;
mcip->mci_p_unicast_list = NULL;
if (mac_client_datapath_setup(mcip, VLAN_ID_NONE,
- mip->mi_addr, &mrp, B_TRUE, muip) == 0) {
+ mip->mi_addr, mrp, B_TRUE, muip) == 0) {
if (mcip->mci_rx_p_fn != NULL) {
mac_rx_set(mch, mcip->mci_rx_p_fn,
mcip->mci_rx_p_arg);
@@ -2527,6 +3046,7 @@ mac_unicast_remove(mac_client_handle_t mch, mac_unicast_handle_t mah)
} else {
kmem_free(muip, sizeof (mac_unicast_impl_t));
}
+ kmem_free(mrp, sizeof (*mrp));
}
i_mac_perim_exit(mip);
return (0);
@@ -2775,36 +3295,6 @@ mac_promisc_remove(mac_promisc_handle_t mph)
}
/*
- * Bump the count of the number of active Tx threads. This is maintained as
- * a per CPU counter. On (CMT kind of) machines with large number of CPUs,
- * a single mci_tx_lock may become contended. However a count of the total
- * number of Tx threads per client is needed in order to quiesce the Tx side
- * prior to reassigning a Tx ring dynamically to another client. The thread
- * that needs to quiesce the Tx traffic grabs all the percpu locks and checks
- * the sum of the individual percpu refcnts. Each Tx data thread only grabs
- * its own percpu lock and increments its own refcnt.
- */
-void *
-mac_tx_hold(mac_client_handle_t mch)
-{
- mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
- mac_tx_percpu_t *mytx;
- int error;
-
- MAC_TX_TRY_HOLD(mcip, mytx, error);
- return (error == 0 ? (void *)mytx : NULL);
-}
-
-void
-mac_tx_rele(mac_client_handle_t mch, void *mytx_handle)
-{
- mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
- mac_tx_percpu_t *mytx = mytx_handle;
-
- MAC_TX_RELE(mcip, mytx)
-}
-
-/*
* Send function invoked by MAC clients.
*/
mac_tx_cookie_t
@@ -2872,8 +3362,7 @@ mac_tx(mac_client_handle_t mch, mblk_t *mp_chain, uintptr_t hint,
srs_tx = &srs->srs_tx;
if (srs_tx->st_mode == SRS_TX_DEFAULT &&
(srs->srs_state & SRS_ENQUEUED) == 0 &&
- mip->mi_nactiveclients == 1 && mip->mi_promisc_list == NULL &&
- mp_chain->b_next == NULL) {
+ mip->mi_nactiveclients == 1 && mp_chain->b_next == NULL) {
uint64_t obytes;
/*
@@ -2891,7 +3380,7 @@ mac_tx(mac_client_handle_t mch, mblk_t *mp_chain, uintptr_t hint,
MAC_VID_CHECK(mcip, mp_chain, err);
if (err != 0) {
freemsg(mp_chain);
- mcip->mci_stat_oerrors++;
+ mcip->mci_misc_stat.mms_txerrors++;
goto done;
}
}
@@ -2899,7 +3388,7 @@ mac_tx(mac_client_handle_t mch, mblk_t *mp_chain, uintptr_t hint,
mp_chain = mac_add_vlan_tag(mp_chain, 0,
mac_client_vid(mch));
if (mp_chain == NULL) {
- mcip->mci_stat_oerrors++;
+ mcip->mci_misc_stat.mms_txerrors++;
goto done;
}
}
@@ -2908,17 +3397,11 @@ mac_tx(mac_client_handle_t mch, mblk_t *mp_chain, uintptr_t hint,
obytes = (mp_chain->b_cont == NULL ? MBLKL(mp_chain) :
msgdsize(mp_chain));
- MAC_TX(mip, srs_tx->st_arg2, mp_chain,
- ((mcip->mci_state_flags & MCIS_SHARE_BOUND) != 0));
-
+ MAC_TX(mip, srs_tx->st_arg2, mp_chain, mcip);
if (mp_chain == NULL) {
cookie = NULL;
- mcip->mci_stat_obytes += obytes;
- mcip->mci_stat_opackets += 1;
- if ((srs->srs_type & SRST_FLOW) != 0) {
- FLOW_STAT_UPDATE(flent, obytes, obytes);
- FLOW_STAT_UPDATE(flent, opackets, 1);
- }
+ SRS_TX_STAT_UPDATE(srs, opackets, 1);
+ SRS_TX_STAT_UPDATE(srs, obytes, obytes);
} else {
mutex_enter(&srs->srs_lock);
cookie = mac_tx_srs_no_desc(srs, mp_chain,
@@ -2978,7 +3461,14 @@ mac_tx_is_flow_blocked(mac_client_handle_t mch, mac_tx_cookie_t cookie)
}
mutex_enter(&mac_srs->srs_lock);
- if (mac_srs->srs_tx.st_mode == SRS_TX_FANOUT) {
+ /*
+ * Only in the case of TX_FANOUT and TX_AGGR, the underlying
+ * softring (s_ring_state) will have the HIWAT set. This is
+ * the multiple Tx ring flow control case. For all other
+ * case, SRS (srs_state) will store the condition.
+ */
+ if (mac_srs->srs_tx.st_mode == SRS_TX_FANOUT ||
+ mac_srs->srs_tx.st_mode == SRS_TX_AGGR) {
if (cookie != NULL) {
sringp = (mac_soft_ring_t *)cookie;
mutex_enter(&sringp->s_ring_lock);
@@ -2986,8 +3476,8 @@ mac_tx_is_flow_blocked(mac_client_handle_t mch, mac_tx_cookie_t cookie)
blocked = B_TRUE;
mutex_exit(&sringp->s_ring_lock);
} else {
- for (i = 0; i < mac_srs->srs_oth_ring_count; i++) {
- sringp = mac_srs->srs_oth_soft_rings[i];
+ for (i = 0; i < mac_srs->srs_tx_ring_count; i++) {
+ sringp = mac_srs->srs_tx_soft_rings[i];
mutex_enter(&sringp->s_ring_lock);
if (sringp->s_ring_state & S_RING_TX_HIWAT) {
blocked = B_TRUE;
@@ -3228,9 +3718,10 @@ mac_cpu_set(mac_client_handle_t mch, mac_resource_props_t *mrp)
ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
- if ((err = mac_validate_props(mrp)) != 0)
+ if ((err = mac_validate_props(mcip->mci_state_flags & MCIS_IS_VNIC ?
+ mcip->mci_upper_mip : mip, mrp)) != 0) {
return (err);
-
+ }
if (MCIP_DATAPATH_SETUP(mcip))
mac_flow_modify(mip->mi_flow_tab, mcip->mci_flent, mrp);
@@ -3256,14 +3747,20 @@ mac_client_set_resources(mac_client_handle_t mch, mac_resource_props_t *mrp)
goto done;
}
- if (mrp->mrp_mask & MRP_CPUS) {
+ if (mrp->mrp_mask & (MRP_CPUS|MRP_POOL)) {
err = mac_cpu_set(mch, mrp);
if (err != 0)
goto done;
}
- if (mrp->mrp_mask & MRP_PROTECT)
+ if (mrp->mrp_mask & MRP_PROTECT) {
err = mac_protect_set(mch, mrp);
+ if (err != 0)
+ goto done;
+ }
+
+ if ((mrp->mrp_mask & MRP_RX_RINGS) || (mrp->mrp_mask & MRP_TX_RINGS))
+ err = mac_resource_ctl_set(mch, mrp);
done:
i_mac_perim_exit(mip);
@@ -3283,6 +3780,20 @@ mac_client_get_resources(mac_client_handle_t mch, mac_resource_props_t *mrp)
}
/*
+ * Return the effective properties currently associated with the specified
+ * MAC client.
+ */
+void
+mac_client_get_effective_resources(mac_client_handle_t mch,
+ mac_resource_props_t *mrp)
+{
+ mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
+ mac_resource_props_t *mcip_mrp = MCIP_EFFECTIVE_PROPS(mcip);
+
+ bcopy(mcip_mrp, mrp, sizeof (mac_resource_props_t));
+}
+
+/*
* Pass a copy of the specified packet to the promiscuous callbacks
* of the specified MAC.
*
@@ -3708,6 +4219,16 @@ mac_get_lower_mac_handle(mac_handle_t mh)
return (((vnic_t *)mip->mi_driver)->vn_lower_mh);
}
+boolean_t
+mac_is_vnic_primary(mac_handle_t mh)
+{
+ mac_impl_t *mip = (mac_impl_t *)mh;
+
+ ASSERT(mac_is_vnic(mh));
+ return (((vnic_t *)mip->mi_driver)->vn_addr_type ==
+ VNIC_MAC_ADDR_TYPE_PRIMARY);
+}
+
void
mac_update_resources(mac_resource_props_t *nmrp, mac_resource_props_t *cmrp,
boolean_t is_user_flow)
@@ -3728,17 +4249,66 @@ mac_update_resources(mac_resource_props_t *nmrp, mac_resource_props_t *cmrp,
}
}
if (nmrp->mrp_mask & MRP_MAXBW) {
- cmrp->mrp_maxbw = nmrp->mrp_maxbw;
- if (nmrp->mrp_maxbw == MRP_MAXBW_RESETVAL)
+ if (nmrp->mrp_maxbw == MRP_MAXBW_RESETVAL) {
cmrp->mrp_mask &= ~MRP_MAXBW;
- else
+ cmrp->mrp_maxbw = 0;
+ } else {
cmrp->mrp_mask |= MRP_MAXBW;
+ cmrp->mrp_maxbw = nmrp->mrp_maxbw;
+ }
}
if (nmrp->mrp_mask & MRP_CPUS)
MAC_COPY_CPUS(nmrp, cmrp);
+ if (nmrp->mrp_mask & MRP_POOL) {
+ if (strlen(nmrp->mrp_pool) == 0) {
+ cmrp->mrp_mask &= ~MRP_POOL;
+ bzero(cmrp->mrp_pool, sizeof (cmrp->mrp_pool));
+ } else {
+ cmrp->mrp_mask |= MRP_POOL;
+ (void) strncpy(cmrp->mrp_pool, nmrp->mrp_pool,
+ sizeof (cmrp->mrp_pool));
+ }
+
+ }
+
if (nmrp->mrp_mask & MRP_PROTECT)
mac_protect_update(nmrp, cmrp);
+
+ /*
+ * Update the rings specified.
+ */
+ if (nmrp->mrp_mask & MRP_RX_RINGS) {
+ if (nmrp->mrp_mask & MRP_RINGS_RESET) {
+ cmrp->mrp_mask &= ~MRP_RX_RINGS;
+ if (cmrp->mrp_mask & MRP_RXRINGS_UNSPEC)
+ cmrp->mrp_mask &= ~MRP_RXRINGS_UNSPEC;
+ cmrp->mrp_nrxrings = 0;
+ } else {
+ cmrp->mrp_mask |= MRP_RX_RINGS;
+ cmrp->mrp_nrxrings = nmrp->mrp_nrxrings;
+ }
+ }
+ if (nmrp->mrp_mask & MRP_TX_RINGS) {
+ if (nmrp->mrp_mask & MRP_RINGS_RESET) {
+ cmrp->mrp_mask &= ~MRP_TX_RINGS;
+ if (cmrp->mrp_mask & MRP_TXRINGS_UNSPEC)
+ cmrp->mrp_mask &= ~MRP_TXRINGS_UNSPEC;
+ cmrp->mrp_ntxrings = 0;
+ } else {
+ cmrp->mrp_mask |= MRP_TX_RINGS;
+ cmrp->mrp_ntxrings = nmrp->mrp_ntxrings;
+ }
+ }
+ if (nmrp->mrp_mask & MRP_RXRINGS_UNSPEC)
+ cmrp->mrp_mask |= MRP_RXRINGS_UNSPEC;
+ else if (cmrp->mrp_mask & MRP_RXRINGS_UNSPEC)
+ cmrp->mrp_mask &= ~MRP_RXRINGS_UNSPEC;
+
+ if (nmrp->mrp_mask & MRP_TXRINGS_UNSPEC)
+ cmrp->mrp_mask |= MRP_TXRINGS_UNSPEC;
+ else if (cmrp->mrp_mask & MRP_TXRINGS_UNSPEC)
+ cmrp->mrp_mask &= ~MRP_TXRINGS_UNSPEC;
}
}
@@ -3757,26 +4327,29 @@ i_mac_set_resources(mac_handle_t mh, mac_resource_props_t *mrp)
mac_client_impl_t *mcip;
int err = 0;
uint32_t resmask, newresmask;
- mac_resource_props_t tmrp, umrp;
+ mac_resource_props_t *tmrp, *umrp;
ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
- err = mac_validate_props(mrp);
+ err = mac_validate_props(mip, mrp);
if (err != 0)
return (err);
- bcopy(&mip->mi_resource_props, &umrp, sizeof (mac_resource_props_t));
- resmask = umrp.mrp_mask;
- mac_update_resources(mrp, &umrp, B_FALSE);
- newresmask = umrp.mrp_mask;
+ umrp = kmem_zalloc(sizeof (*umrp), KM_SLEEP);
+ bcopy(&mip->mi_resource_props, umrp, sizeof (*umrp));
+ resmask = umrp->mrp_mask;
+ mac_update_resources(mrp, umrp, B_FALSE);
+ newresmask = umrp->mrp_mask;
if (resmask == 0 && newresmask != 0) {
/*
- * Bandwidth, priority or cpu link properties configured,
+ * Bandwidth, priority, cpu or pool link properties configured,
* must disable fastpath.
*/
- if ((err = mac_fastpath_disable((mac_handle_t)mip)) != 0)
+ if ((err = mac_fastpath_disable((mac_handle_t)mip)) != 0) {
+ kmem_free(umrp, sizeof (*umrp));
return (err);
+ }
}
/*
@@ -3784,19 +4357,93 @@ i_mac_set_resources(mac_handle_t mh, mac_resource_props_t *mrp)
* we use a copy of bind_cpu and finally cache bind_cpu in mip.
* This allows us to cache only user edits in mip.
*/
- bcopy(mrp, &tmrp, sizeof (mac_resource_props_t));
+ tmrp = kmem_zalloc(sizeof (*tmrp), KM_SLEEP);
+ bcopy(mrp, tmrp, sizeof (*tmrp));
mcip = mac_primary_client_handle(mip);
if (mcip != NULL && (mcip->mci_state_flags & MCIS_IS_AGGR_PORT) == 0) {
- err =
- mac_client_set_resources((mac_client_handle_t)mcip, &tmrp);
+ err = mac_client_set_resources((mac_client_handle_t)mcip, tmrp);
+ } else if ((mrp->mrp_mask & MRP_RX_RINGS ||
+ mrp->mrp_mask & MRP_TX_RINGS)) {
+ mac_client_impl_t *vmcip;
+
+ /*
+ * If the primary is not up, we need to check if there
+ * are any VLANs on this primary. If there are then
+ * we need to set this property on the VLANs since
+ * VLANs follow the primary they are based on. Just
+ * look for the first VLAN and change its properties,
+ * all the other VLANs should be in the same group.
+ */
+ for (vmcip = mip->mi_clients_list; vmcip != NULL;
+ vmcip = vmcip->mci_client_next) {
+ if ((vmcip->mci_flent->fe_type & FLOW_PRIMARY_MAC) &&
+ mac_client_vid((mac_client_handle_t)vmcip) !=
+ VLAN_ID_NONE) {
+ break;
+ }
+ }
+ if (vmcip != NULL) {
+ mac_resource_props_t *omrp;
+ mac_resource_props_t *vmrp;
+
+ omrp = kmem_zalloc(sizeof (*omrp), KM_SLEEP);
+ bcopy(MCIP_RESOURCE_PROPS(vmcip), omrp, sizeof (*omrp));
+ /*
+ * We dont' call mac_update_resources since we
+ * want to take only the ring properties and
+ * not all the properties that may have changed.
+ */
+ vmrp = MCIP_RESOURCE_PROPS(vmcip);
+ if (mrp->mrp_mask & MRP_RX_RINGS) {
+ if (mrp->mrp_mask & MRP_RINGS_RESET) {
+ vmrp->mrp_mask &= ~MRP_RX_RINGS;
+ if (vmrp->mrp_mask &
+ MRP_RXRINGS_UNSPEC) {
+ vmrp->mrp_mask &=
+ ~MRP_RXRINGS_UNSPEC;
+ }
+ vmrp->mrp_nrxrings = 0;
+ } else {
+ vmrp->mrp_mask |= MRP_RX_RINGS;
+ vmrp->mrp_nrxrings = mrp->mrp_nrxrings;
+ }
+ }
+ if (mrp->mrp_mask & MRP_TX_RINGS) {
+ if (mrp->mrp_mask & MRP_RINGS_RESET) {
+ vmrp->mrp_mask &= ~MRP_TX_RINGS;
+ if (vmrp->mrp_mask &
+ MRP_TXRINGS_UNSPEC) {
+ vmrp->mrp_mask &=
+ ~MRP_TXRINGS_UNSPEC;
+ }
+ vmrp->mrp_ntxrings = 0;
+ } else {
+ vmrp->mrp_mask |= MRP_TX_RINGS;
+ vmrp->mrp_ntxrings = mrp->mrp_ntxrings;
+ }
+ }
+ if (mrp->mrp_mask & MRP_RXRINGS_UNSPEC)
+ vmrp->mrp_mask |= MRP_RXRINGS_UNSPEC;
+
+ if (mrp->mrp_mask & MRP_TXRINGS_UNSPEC)
+ vmrp->mrp_mask |= MRP_TXRINGS_UNSPEC;
+
+ if ((err = mac_client_set_rings_prop(vmcip, mrp,
+ omrp)) != 0) {
+ bcopy(omrp, MCIP_RESOURCE_PROPS(vmcip),
+ sizeof (*omrp));
+ } else {
+ mac_set_prim_vlan_rings(mip, vmrp);
+ }
+ kmem_free(omrp, sizeof (*omrp));
+ }
}
/* Only update the values if mac_client_set_resources succeeded */
if (err == 0) {
- bcopy(&umrp, &mip->mi_resource_props,
- sizeof (mac_resource_props_t));
+ bcopy(umrp, &mip->mi_resource_props, sizeof (*umrp));
/*
- * If bankwidth, priority or cpu link properties cleared,
+ * If bandwidth, priority or cpu link properties cleared,
* renable fastpath.
*/
if (resmask != 0 && newresmask == 0)
@@ -3804,6 +4451,8 @@ i_mac_set_resources(mac_handle_t mh, mac_resource_props_t *mrp)
} else if (resmask == 0 && newresmask != 0) {
mac_fastpath_enable((mac_handle_t)mip);
}
+ kmem_free(tmrp, sizeof (*tmrp));
+ kmem_free(umrp, sizeof (*umrp));
return (err);
}
@@ -3827,17 +4476,33 @@ mac_get_resources(mac_handle_t mh, mac_resource_props_t *mrp)
mac_impl_t *mip = (mac_impl_t *)mh;
mac_client_impl_t *mcip;
- if (mip->mi_state_flags & MIS_IS_VNIC) {
- mcip = mac_primary_client_handle(mip);
- if (mcip != NULL) {
- mac_client_get_resources((mac_client_handle_t)mcip,
- mrp);
- return;
- }
+ mcip = mac_primary_client_handle(mip);
+ if (mcip != NULL) {
+ mac_client_get_resources((mac_client_handle_t)mcip, mrp);
+ return;
}
bcopy(&mip->mi_resource_props, mrp, sizeof (mac_resource_props_t));
}
+/*
+ * Get the effective properties from the primary client of the
+ * specified MAC instance.
+ */
+void
+mac_get_effective_resources(mac_handle_t mh, mac_resource_props_t *mrp)
+{
+ mac_impl_t *mip = (mac_impl_t *)mh;
+ mac_client_impl_t *mcip;
+
+ mcip = mac_primary_client_handle(mip);
+ if (mcip != NULL) {
+ mac_client_get_effective_resources((mac_client_handle_t)mcip,
+ mrp);
+ return;
+ }
+ bzero(mrp, sizeof (mac_resource_props_t));
+}
+
int
mac_set_pvid(mac_handle_t mh, uint16_t pvid)
{
@@ -3904,8 +4569,10 @@ mac_rename_primary(mac_handle_t mh, const char *new_name)
* the associated flow kstat.
*/
if (mip->mi_state_flags & MIS_IS_VNIC) {
+ mac_client_impl_t *mcip = mac_vnic_lower(mip);
ASSERT(new_name != NULL);
- mac_rename_flow_names(mac_vnic_lower(mip), new_name);
+ mac_rename_flow_names(mcip, new_name);
+ mac_stat_rename(mcip);
goto done;
}
/*
@@ -3954,6 +4621,10 @@ mac_rename_primary(mac_handle_t mh, const char *new_name)
}
}
+ /* Recreate kstats associated with aggr pseudo rings */
+ if (mip->mi_state_flags & MIS_IS_AGGR)
+ mac_pseudo_ring_stat_rename(mip);
+
done:
i_mac_perim_exit(mip);
return (0);
@@ -4187,8 +4858,14 @@ mac_client_single_rcvr(mac_client_impl_t *mcip)
}
int
-mac_validate_props(mac_resource_props_t *mrp)
+mac_validate_props(mac_impl_t *mip, mac_resource_props_t *mrp)
{
+ boolean_t reset;
+ uint32_t rings_needed;
+ uint32_t rings_avail;
+ mac_group_type_t gtype;
+ mac_resource_props_t *mip_mrp;
+
if (mrp == NULL)
return (0);
@@ -4246,6 +4923,100 @@ mac_validate_props(mac_resource_props_t *mrp)
if (err != 0)
return (err);
}
+
+ if (!(mrp->mrp_mask & MRP_RX_RINGS) &&
+ !(mrp->mrp_mask & MRP_TX_RINGS)) {
+ return (0);
+ }
+
+ /*
+ * mip will be null when we come from mac_flow_create or
+ * mac_link_flow_modify. In the latter case it is a user flow,
+ * for which we don't support rings. In the former we would
+ * have validated the props beforehand (i_mac_unicast_add ->
+ * mac_client_set_resources -> validate for the primary and
+ * vnic_dev_create -> mac_client_set_resources -> validate for
+ * a vnic.
+ */
+ if (mip == NULL)
+ return (0);
+
+ /*
+ * We don't support setting rings property for a VNIC that is using a
+ * primary address (VLAN)
+ */
+ if ((mip->mi_state_flags & MIS_IS_VNIC) &&
+ mac_is_vnic_primary((mac_handle_t)mip)) {
+ return (ENOTSUP);
+ }
+
+ mip_mrp = &mip->mi_resource_props;
+ /*
+ * The rings property should be validated against the NICs
+ * resources
+ */
+ if (mip->mi_state_flags & MIS_IS_VNIC)
+ mip = (mac_impl_t *)mac_get_lower_mac_handle((mac_handle_t)mip);
+
+ reset = mrp->mrp_mask & MRP_RINGS_RESET;
+ /*
+ * If groups are not supported, return error.
+ */
+ if (((mrp->mrp_mask & MRP_RX_RINGS) && mip->mi_rx_groups == NULL) ||
+ ((mrp->mrp_mask & MRP_TX_RINGS) && mip->mi_tx_groups == NULL)) {
+ return (EINVAL);
+ }
+ /*
+ * If we are just resetting, there is no validation needed.
+ */
+ if (reset)
+ return (0);
+
+ if (mrp->mrp_mask & MRP_RX_RINGS) {
+ rings_needed = mrp->mrp_nrxrings;
+ /*
+ * We just want to check if the number of additional
+ * rings requested is available.
+ */
+ if (mip_mrp->mrp_mask & MRP_RX_RINGS) {
+ if (mrp->mrp_nrxrings > mip_mrp->mrp_nrxrings)
+ /* Just check for the additional rings */
+ rings_needed -= mip_mrp->mrp_nrxrings;
+ else
+ /* We are not asking for additional rings */
+ rings_needed = 0;
+ }
+ rings_avail = mip->mi_rxrings_avail;
+ gtype = mip->mi_rx_group_type;
+ } else {
+ rings_needed = mrp->mrp_ntxrings;
+ /* Similarly for the TX rings */
+ if (mip_mrp->mrp_mask & MRP_TX_RINGS) {
+ if (mrp->mrp_ntxrings > mip_mrp->mrp_ntxrings)
+ /* Just check for the additional rings */
+ rings_needed -= mip_mrp->mrp_ntxrings;
+ else
+ /* We are not asking for additional rings */
+ rings_needed = 0;
+ }
+ rings_avail = mip->mi_txrings_avail;
+ gtype = mip->mi_tx_group_type;
+ }
+
+ /* Error if the group is dynamic .. */
+ if (gtype == MAC_GROUP_TYPE_DYNAMIC) {
+ /*
+ * .. and rings specified are more than available.
+ */
+ if (rings_needed > rings_avail)
+ return (EINVAL);
+ } else {
+ /*
+ * OR group is static and we have specified some rings.
+ */
+ if (rings_needed > 0)
+ return (EINVAL);
+ }
return (0);
}
@@ -4266,11 +5037,18 @@ mac_virtual_link_update(mac_impl_t *mip)
* mac handle in the client.
*/
void
-mac_set_upper_mac(mac_client_handle_t mch, mac_handle_t mh)
+mac_set_upper_mac(mac_client_handle_t mch, mac_handle_t mh,
+ mac_resource_props_t *mrp)
{
mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
+ mac_impl_t *mip = (mac_impl_t *)mh;
- mcip->mci_upper_mip = (mac_impl_t *)mh;
+ mcip->mci_upper_mip = mip;
+ /* If there are any properties, copy it over too */
+ if (mrp != NULL) {
+ bcopy(mrp, &mip->mi_resource_props,
+ sizeof (mac_resource_props_t));
+ }
}
/*
@@ -4326,15 +5104,7 @@ mac_unmark_exclusive(mac_handle_t mh)
}
/*
- * Set the MTU for the specified MAC. Note that this mechanism depends on
- * the driver calling mac_maxsdu_update() to update the link MTU if it was
- * successful in setting its MTU.
- *
- * Note that there is potential for improvement here. A better model might be
- * to not require drivers to call mac_maxsdu_update(), but rather have this
- * function update mi_sdu_max and send notifications if the driver setprop
- * callback succeeds. This would remove the burden and complexity from
- * drivers.
+ * Set the MTU for the specified MAC.
*/
int
mac_set_mtu(mac_handle_t mh, uint_t new_mtu, uint_t *old_mtu_arg)
@@ -4352,9 +5122,18 @@ mac_set_mtu(mac_handle_t mh, uint_t new_mtu, uint_t *old_mtu_arg)
old_mtu = mip->mi_sdu_max;
+ if (new_mtu == 0 || new_mtu < mip->mi_sdu_min) {
+ rv = EINVAL;
+ goto bail;
+ }
+
if (old_mtu != new_mtu) {
rv = mip->mi_callbacks->mc_setprop(mip->mi_driver,
"mtu", MAC_PROP_MTU, sizeof (uint_t), &new_mtu);
+ if (rv != 0)
+ goto bail;
+ rv = mac_maxsdu_update(mh, new_mtu);
+ ASSERT(rv == 0);
}
bail:
@@ -4365,13 +5144,18 @@ bail:
return (rv);
}
+/*
+ * Return the RX h/w information for the group indexed by grp_num.
+ */
void
-mac_get_hwgrp_info(mac_handle_t mh, int grp_index, uint_t *grp_num,
- uint_t *n_rings, uint_t *type, uint_t *n_clnts, char *clnts_name)
+mac_get_hwrxgrp_info(mac_handle_t mh, int grp_index, uint_t *grp_num,
+ uint_t *n_rings, uint_t *rings, uint_t *type, uint_t *n_clnts,
+ char *clnts_name)
{
mac_impl_t *mip = (mac_impl_t *)mh;
mac_grp_client_t *mcip;
uint_t i = 0, index = 0;
+ mac_ring_t *ring;
/* Revisit when we implement fully dynamic group allocation */
ASSERT(grp_index >= 0 && grp_index < mip->mi_rx_group_count);
@@ -4380,6 +5164,19 @@ mac_get_hwgrp_info(mac_handle_t mh, int grp_index, uint_t *grp_num,
*grp_num = mip->mi_rx_groups[grp_index].mrg_index;
*type = mip->mi_rx_groups[grp_index].mrg_type;
*n_rings = mip->mi_rx_groups[grp_index].mrg_cur_count;
+ ring = mip->mi_rx_groups[grp_index].mrg_rings;
+ for (index = 0; index < mip->mi_rx_groups[grp_index].mrg_cur_count;
+ index++) {
+ rings[index] = ring->mr_index;
+ ring = ring->mr_next;
+ }
+ /* Assuming the 1st is the default group */
+ index = 0;
+ if (grp_index == 0) {
+ (void) strlcpy(clnts_name, "<default,mcast>,",
+ MAXCLIENTNAMELEN);
+ index += strlen("<default,mcast>,");
+ }
for (mcip = mip->mi_rx_groups[grp_index].mrg_clients; mcip != NULL;
mcip = mcip->mgc_next) {
int name_len = strlen(mcip->mgc_client->mci_name);
@@ -4410,10 +5207,194 @@ mac_get_hwgrp_info(mac_handle_t mh, int grp_index, uint_t *grp_num,
rw_exit(&mip->mi_rw_lock);
}
+/*
+ * Return the TX h/w information for the group indexed by grp_num.
+ */
+void
+mac_get_hwtxgrp_info(mac_handle_t mh, int grp_index, uint_t *grp_num,
+ uint_t *n_rings, uint_t *rings, uint_t *type, uint_t *n_clnts,
+ char *clnts_name)
+{
+ mac_impl_t *mip = (mac_impl_t *)mh;
+ mac_grp_client_t *mcip;
+ uint_t i = 0, index = 0;
+ mac_ring_t *ring;
+
+ /* Revisit when we implement fully dynamic group allocation */
+ ASSERT(grp_index >= 0 && grp_index <= mip->mi_tx_group_count);
+
+ rw_enter(&mip->mi_rw_lock, RW_READER);
+ *grp_num = mip->mi_tx_groups[grp_index].mrg_index > 0 ?
+ mip->mi_tx_groups[grp_index].mrg_index : grp_index;
+ *type = mip->mi_tx_groups[grp_index].mrg_type;
+ *n_rings = mip->mi_tx_groups[grp_index].mrg_cur_count;
+ ring = mip->mi_tx_groups[grp_index].mrg_rings;
+ for (index = 0; index < mip->mi_tx_groups[grp_index].mrg_cur_count;
+ index++) {
+ rings[index] = ring->mr_index;
+ ring = ring->mr_next;
+ }
+ index = 0;
+ /* Default group has an index of -1 */
+ if (mip->mi_tx_groups[grp_index].mrg_index < 0) {
+ (void) strlcpy(clnts_name, "<default>,",
+ MAXCLIENTNAMELEN);
+ index += strlen("<default>,");
+ }
+ for (mcip = mip->mi_tx_groups[grp_index].mrg_clients; mcip != NULL;
+ mcip = mcip->mgc_next) {
+ int name_len = strlen(mcip->mgc_client->mci_name);
+
+ /*
+ * MAXCLIENTNAMELEN is the buffer size reserved for client
+ * names.
+ * XXXX Formating the client name string needs to be moved
+ * to user land when fixing the size of dhi_clnts in
+ * dld_hwgrpinfo_t. We should use n_clients * client_name for
+ * dhi_clntsin instead of MAXCLIENTNAMELEN
+ */
+ if (index + name_len >= MAXCLIENTNAMELEN) {
+ index = MAXCLIENTNAMELEN;
+ break;
+ }
+ bcopy(mcip->mgc_client->mci_name, &(clnts_name[index]),
+ name_len);
+ index += name_len;
+ clnts_name[index++] = ',';
+ i++;
+ }
+
+ /* Get rid of the last , */
+ if (index > 0)
+ clnts_name[index - 1] = '\0';
+ *n_clnts = i;
+ rw_exit(&mip->mi_rw_lock);
+}
+
+/*
+ * Return the group count for RX or TX.
+ */
uint_t
-mac_hwgrp_num(mac_handle_t mh)
+mac_hwgrp_num(mac_handle_t mh, int type)
{
mac_impl_t *mip = (mac_impl_t *)mh;
- return (mip->mi_rx_group_count);
+ /*
+ * Return the Rx and Tx group count; for the Tx we need to
+ * include the default too.
+ */
+ return (type == MAC_RING_TYPE_RX ? mip->mi_rx_group_count :
+ mip->mi_tx_groups != NULL ? mip->mi_tx_group_count + 1 : 0);
+}
+
+/*
+ * The total number of free TX rings for this MAC.
+ */
+uint_t
+mac_txavail_get(mac_handle_t mh)
+{
+ mac_impl_t *mip = (mac_impl_t *)mh;
+
+ return (mip->mi_txrings_avail);
+}
+
+/*
+ * The total number of free RX rings for this MAC.
+ */
+uint_t
+mac_rxavail_get(mac_handle_t mh)
+{
+ mac_impl_t *mip = (mac_impl_t *)mh;
+
+ return (mip->mi_rxrings_avail);
+}
+
+/*
+ * The total number of reserved RX rings on this MAC.
+ */
+uint_t
+mac_rxrsvd_get(mac_handle_t mh)
+{
+ mac_impl_t *mip = (mac_impl_t *)mh;
+
+ return (mip->mi_rxrings_rsvd);
+}
+
+/*
+ * The total number of reserved TX rings on this MAC.
+ */
+uint_t
+mac_txrsvd_get(mac_handle_t mh)
+{
+ mac_impl_t *mip = (mac_impl_t *)mh;
+
+ return (mip->mi_txrings_rsvd);
+}
+
+/*
+ * Total number of free RX groups on this MAC.
+ */
+uint_t
+mac_rxhwlnksavail_get(mac_handle_t mh)
+{
+ mac_impl_t *mip = (mac_impl_t *)mh;
+
+ return (mip->mi_rxhwclnt_avail);
+}
+
+/*
+ * Total number of RX groups reserved on this MAC.
+ */
+uint_t
+mac_rxhwlnksrsvd_get(mac_handle_t mh)
+{
+ mac_impl_t *mip = (mac_impl_t *)mh;
+
+ return (mip->mi_rxhwclnt_used);
+}
+
+/*
+ * Total number of free TX groups on this MAC.
+ */
+uint_t
+mac_txhwlnksavail_get(mac_handle_t mh)
+{
+ mac_impl_t *mip = (mac_impl_t *)mh;
+
+ return (mip->mi_txhwclnt_avail);
+}
+
+/*
+ * Total number of TX groups reserved on this MAC.
+ */
+uint_t
+mac_txhwlnksrsvd_get(mac_handle_t mh)
+{
+ mac_impl_t *mip = (mac_impl_t *)mh;
+
+ return (mip->mi_txhwclnt_used);
+}
+
+/*
+ * Initialize the rings property for a mac client. A non-0 value for
+ * rxring or txring specifies the number of rings required, a value
+ * of MAC_RXRINGS_NONE/MAC_TXRINGS_NONE specifies that it doesn't need
+ * any RX/TX rings and a value of MAC_RXRINGS_DONTCARE/MAC_TXRINGS_DONTCARE
+ * means the system can decide whether it can give any rings or not.
+ */
+void
+mac_client_set_rings(mac_client_handle_t mch, int rxrings, int txrings)
+{
+ mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
+ mac_resource_props_t *mrp = MCIP_RESOURCE_PROPS(mcip);
+
+ if (rxrings != MAC_RXRINGS_DONTCARE) {
+ mrp->mrp_mask |= MRP_RX_RINGS;
+ mrp->mrp_nrxrings = rxrings;
+ }
+
+ if (txrings != MAC_TXRINGS_DONTCARE) {
+ mrp->mrp_mask |= MRP_TX_RINGS;
+ mrp->mrp_ntxrings = txrings;
+ }
}