Print this page
11493 aggr needs support for multiple pseudo rx groups
Portions contributed by: Dan McDonald <danmcd@joyent.com>
Reviewed by: Patrick Mooney <patrick.mooney@joyent.com>
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Reviewed by: Robert Mustacchi <rm@joyent.com>
*** 1455,1465 ****
/*
* The following mac_hwrings_xxx() functions are private mac client functions
* used by the aggr driver to access and control the underlying HW Rx group
* and rings. In this case, the aggr driver has exclusive control of the
* underlying HW Rx group/rings, it calls the following functions to
! * start/stop the HW Rx rings, disable/enable polling, add/remove mac'
* addresses, or set up the Rx callback.
*/
/* ARGSUSED */
static void
mac_hwrings_rx_process(void *arg, mac_resource_handle_t srs,
--- 1455,1465 ----
/*
* The following mac_hwrings_xxx() functions are private mac client functions
* used by the aggr driver to access and control the underlying HW Rx group
* and rings. In this case, the aggr driver has exclusive control of the
* underlying HW Rx group/rings, it calls the following functions to
! * start/stop the HW Rx rings, disable/enable polling, add/remove MAC
* addresses, or set up the Rx callback.
*/
/* ARGSUSED */
static void
mac_hwrings_rx_process(void *arg, mac_resource_handle_t srs,
*** 1500,1520 ****
grp = flent->fe_tx_ring_group;
} else {
ASSERT(B_FALSE);
return (-1);
}
/*
! * The mac client did not reserve any RX group, return directly.
* This is probably because the underlying MAC does not support
* any groups.
*/
if (hwgh != NULL)
*hwgh = NULL;
if (grp == NULL)
return (0);
/*
! * This group must be reserved by this mac client.
*/
ASSERT((grp->mrg_state == MAC_GROUP_STATE_RESERVED) &&
(mcip == MAC_GROUP_ONLY_CLIENT(grp)));
for (ring = grp->mrg_rings; ring != NULL; ring = ring->mr_next, cnt++) {
--- 1500,1521 ----
grp = flent->fe_tx_ring_group;
} else {
ASSERT(B_FALSE);
return (-1);
}
+
/*
! * The MAC client did not reserve an Rx group, return directly.
* This is probably because the underlying MAC does not support
* any groups.
*/
if (hwgh != NULL)
*hwgh = NULL;
if (grp == NULL)
return (0);
/*
! * This group must be reserved by this MAC client.
*/
ASSERT((grp->mrg_state == MAC_GROUP_STATE_RESERVED) &&
(mcip == MAC_GROUP_ONLY_CLIENT(grp)));
for (ring = grp->mrg_rings; ring != NULL; ring = ring->mr_next, cnt++) {
*** 1526,1535 ****
--- 1527,1607 ----
return (cnt);
}
/*
+ * Get the HW ring handles of the given group index. If the MAC
+ * doesn't have a group at this index, or any groups at all, then 0 is
+ * returned and hwgh is set to NULL. This is a private client API. The
+ * MAC perimeter must be held when calling this function.
+ *
+ * mh: A handle to the MAC that owns the group.
+ *
+ * idx: The index of the HW group to be read.
+ *
+ * hwgh: If non-NULL, contains a handle to the HW group on return.
+ *
+ * hwrh: An array of ring handles pointing to the HW rings in the
+ * group. The array must be large enough to hold a handle to each ring
+ * in the group. To be safe, this array should be of size MAX_RINGS_PER_GROUP.
+ *
+ * rtype: Used to determine if we are fetching Rx or Tx rings.
+ *
+ * Returns the number of rings in the group.
+ */
+ uint_t
+ mac_hwrings_idx_get(mac_handle_t mh, uint_t idx, mac_group_handle_t *hwgh,
+ mac_ring_handle_t *hwrh, mac_ring_type_t rtype)
+ {
+ mac_impl_t *mip = (mac_impl_t *)mh;
+ mac_group_t *grp;
+ mac_ring_t *ring;
+ uint_t cnt = 0;
+
+ /*
+ * The MAC perimeter must be held when accessing the
+ * mi_{rx,tx}_groups fields.
+ */
+ ASSERT(MAC_PERIM_HELD(mh));
+ ASSERT(rtype == MAC_RING_TYPE_RX || rtype == MAC_RING_TYPE_TX);
+
+ if (rtype == MAC_RING_TYPE_RX) {
+ grp = mip->mi_rx_groups;
+ } else if (rtype == MAC_RING_TYPE_TX) {
+ grp = mip->mi_tx_groups;
+ }
+
+ while (grp != NULL && grp->mrg_index != idx)
+ grp = grp->mrg_next;
+
+ /*
+ * If the MAC doesn't have a group at this index or doesn't
+ * impelement RINGS capab, then set hwgh to NULL and return 0.
+ */
+ if (hwgh != NULL)
+ *hwgh = NULL;
+
+ if (grp == NULL)
+ return (0);
+
+ ASSERT3U(idx, ==, grp->mrg_index);
+
+ for (ring = grp->mrg_rings; ring != NULL; ring = ring->mr_next, cnt++) {
+ ASSERT3U(cnt, <, MAX_RINGS_PER_GROUP);
+ hwrh[cnt] = (mac_ring_handle_t)ring;
+ }
+
+ /* A group should always have at least one ring. */
+ ASSERT3U(cnt, >, 0);
+
+ if (hwgh != NULL)
+ *hwgh = (mac_group_handle_t)grp;
+
+ return (cnt);
+ }
+
+ /*
* This function is called to get info about Tx/Rx rings.
*
* Return value: returns uint_t which will have various bits set
* that indicates different properties of the ring.
*/
*** 1541,1550 ****
--- 1613,1685 ----
return (info->mri_flags);
}
/*
+ * Set the passthru callback on the hardware ring.
+ */
+ void
+ mac_hwring_set_passthru(mac_ring_handle_t hwrh, mac_rx_t fn, void *arg1,
+ mac_resource_handle_t arg2)
+ {
+ mac_ring_t *hwring = (mac_ring_t *)hwrh;
+
+ ASSERT3S(hwring->mr_type, ==, MAC_RING_TYPE_RX);
+
+ hwring->mr_classify_type = MAC_PASSTHRU_CLASSIFIER;
+
+ hwring->mr_pt_fn = fn;
+ hwring->mr_pt_arg1 = arg1;
+ hwring->mr_pt_arg2 = arg2;
+ }
+
+ /*
+ * Clear the passthru callback on the hardware ring.
+ */
+ void
+ mac_hwring_clear_passthru(mac_ring_handle_t hwrh)
+ {
+ mac_ring_t *hwring = (mac_ring_t *)hwrh;
+
+ ASSERT3S(hwring->mr_type, ==, MAC_RING_TYPE_RX);
+
+ hwring->mr_classify_type = MAC_NO_CLASSIFIER;
+
+ hwring->mr_pt_fn = NULL;
+ hwring->mr_pt_arg1 = NULL;
+ hwring->mr_pt_arg2 = NULL;
+ }
+
+ void
+ mac_client_set_flow_cb(mac_client_handle_t mch, mac_rx_t func, void *arg1)
+ {
+ mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
+ flow_entry_t *flent = mcip->mci_flent;
+
+ mutex_enter(&flent->fe_lock);
+ flent->fe_cb_fn = (flow_fn_t)func;
+ flent->fe_cb_arg1 = arg1;
+ flent->fe_cb_arg2 = NULL;
+ flent->fe_flags &= ~FE_MC_NO_DATAPATH;
+ mutex_exit(&flent->fe_lock);
+ }
+
+ void
+ mac_client_clear_flow_cb(mac_client_handle_t mch)
+ {
+ mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
+ flow_entry_t *flent = mcip->mci_flent;
+
+ mutex_enter(&flent->fe_lock);
+ flent->fe_cb_fn = (flow_fn_t)mac_pkt_drop;
+ flent->fe_cb_arg1 = NULL;
+ flent->fe_cb_arg2 = NULL;
+ flent->fe_flags |= FE_MC_NO_DATAPATH;
+ mutex_exit(&flent->fe_lock);
+ }
+
+ /*
* Export ddi interrupt handles from the HW ring to the pseudo ring and
* setup the RX callback of the mac client which exclusively controls
* HW ring.
*/
void
*** 1612,1632 ****
mac_intr_t *intr = &rr_ring->mr_info.mri_intr;
return (intr->mi_enable(intr->mi_handle));
}
int
mac_hwring_start(mac_ring_handle_t rh)
{
mac_ring_t *rr_ring = (mac_ring_t *)rh;
MAC_RING_UNMARK(rr_ring, MR_QUIESCE);
return (0);
}
void
! mac_hwring_stop(mac_ring_handle_t rh)
{
mac_ring_t *rr_ring = (mac_ring_t *)rh;
mac_rx_ring_quiesce(rr_ring, MR_QUIESCE);
}
--- 1747,1806 ----
mac_intr_t *intr = &rr_ring->mr_info.mri_intr;
return (intr->mi_enable(intr->mi_handle));
}
+ /*
+ * Start the HW ring pointed to by rh.
+ *
+ * This is used by special MAC clients that are MAC themselves and
+ * need to exert control over the underlying HW rings of the NIC.
+ */
int
mac_hwring_start(mac_ring_handle_t rh)
{
mac_ring_t *rr_ring = (mac_ring_t *)rh;
+ int rv = 0;
+ if (rr_ring->mr_state != MR_INUSE)
+ rv = mac_start_ring(rr_ring);
+
+ return (rv);
+ }
+
+ /*
+ * Stop the HW ring pointed to by rh. Also see mac_hwring_start().
+ */
+ void
+ mac_hwring_stop(mac_ring_handle_t rh)
+ {
+ mac_ring_t *rr_ring = (mac_ring_t *)rh;
+
+ if (rr_ring->mr_state != MR_FREE)
+ mac_stop_ring(rr_ring);
+ }
+
+ /*
+ * Remove the quiesced flag from the HW ring pointed to by rh.
+ *
+ * This is used by special MAC clients that are MAC themselves and
+ * need to exert control over the underlying HW rings of the NIC.
+ */
+ int
+ mac_hwring_activate(mac_ring_handle_t rh)
+ {
+ mac_ring_t *rr_ring = (mac_ring_t *)rh;
+
MAC_RING_UNMARK(rr_ring, MR_QUIESCE);
return (0);
}
+ /*
+ * Quiesce the HW ring pointed to by rh. Also see mac_hwring_activate().
+ */
void
! mac_hwring_quiesce(mac_ring_handle_t rh)
{
mac_ring_t *rr_ring = (mac_ring_t *)rh;
mac_rx_ring_quiesce(rr_ring, MR_QUIESCE);
}
*** 1770,1779 ****
--- 1944,1974 ----
return (MAC_GROUP_HW_VLAN(mip->mi_rx_groups));
}
/*
+ * Get the number of Rx HW groups on this MAC.
+ */
+ uint_t
+ mac_get_num_rx_groups(mac_handle_t mh)
+ {
+ mac_impl_t *mip = (mac_impl_t *)mh;
+
+ ASSERT(MAC_PERIM_HELD(mh));
+ return (mip->mi_rx_group_count);
+ }
+
+ int
+ mac_set_promisc(mac_handle_t mh, boolean_t value)
+ {
+ mac_impl_t *mip = (mac_impl_t *)mh;
+
+ ASSERT(MAC_PERIM_HELD(mh));
+ return (i_mac_promisc_set(mip, value));
+ }
+
+ /*
* Set the RX group to be shared/reserved. Note that the group must be
* started/stopped outside of this function.
*/
void
mac_set_group_state(mac_group_t *grp, mac_group_state_t state)
*** 2463,2485 ****
{
flow_entry_t *flent = NULL;
uint_t flags = FLOW_INBOUND;
int err;
- /*
- * If the MAC is a port of an aggregation, pass FLOW_IGNORE_VLAN
- * to mac_flow_lookup() so that the VLAN packets can be successfully
- * passed to the non-VLAN aggregation flows.
- *
- * Note that there is possibly a race between this and
- * mac_unicast_remove/add() and VLAN packets could be incorrectly
- * classified to non-VLAN flows of non-aggregation MAC clients. These
- * VLAN packets will be then filtered out by the MAC module.
- */
- if ((mip->mi_state_flags & MIS_EXCLUSIVE) != 0)
- flags |= FLOW_IGNORE_VLAN;
-
err = mac_flow_lookup(mip->mi_flow_tab, mp, flags, &flent);
if (err != 0) {
/* no registered receive function */
return (mp);
} else {
--- 2658,2667 ----
*** 3809,3821 ****
if ((rv = mac_start_group(group)) != 0)
return (rv);
for (ring = group->mrg_rings; ring != NULL; ring = ring->mr_next) {
ASSERT(ring->mr_state == MR_FREE);
if ((rv = mac_start_ring(ring)) != 0)
goto error;
! ring->mr_classify_type = MAC_SW_CLASSIFIER;
}
return (0);
error:
mac_stop_group_and_rings(group);
--- 3991,4021 ----
if ((rv = mac_start_group(group)) != 0)
return (rv);
for (ring = group->mrg_rings; ring != NULL; ring = ring->mr_next) {
ASSERT(ring->mr_state == MR_FREE);
+
if ((rv = mac_start_ring(ring)) != 0)
goto error;
!
! /*
! * When aggr_set_port_sdu() is called, it will remove
! * the port client's unicast address. This will cause
! * MAC to stop the default group's rings on the port
! * MAC. After it modifies the SDU, it will then re-add
! * the unicast address. At which time, this function is
! * called to start the default group's rings. Normally
! * this function would set the classify type to
! * MAC_SW_CLASSIFIER; but that will break aggr which
! * relies on the passthru classify mode being set for
! * correct delivery (see mac_rx_common()). To avoid
! * that, we check for a passthru callback and set the
! * classify type to MAC_PASSTHRU_CLASSIFIER; as it was
! * before the rings were stopped.
! */
! ring->mr_classify_type = (ring->mr_pt_fn != NULL) ?
! MAC_PASSTHRU_CLASSIFIER : MAC_SW_CLASSIFIER;
}
return (0);
error:
mac_stop_group_and_rings(group);