EFX_MAE_FIELD_ID_HAS_IVLAN = MAE_FIELD_HAS_IVLAN,
EFX_MAE_FIELD_ID_ENC_HAS_OVLAN = MAE_FIELD_ENC_HAS_OVLAN,
EFX_MAE_FIELD_ID_ENC_HAS_IVLAN = MAE_FIELD_ENC_HAS_IVLAN,
+ EFX_MAE_FIELD_ID_RECIRC_ID = MAE_FIELD_RECIRC_ID,
EFX_MAE_FIELD_CAP_NIDS
} efx_mae_field_cap_id_t;
[EFX_MAE_FIELD_##_name] = \
{ \
EFX_MAE_FIELD_ID_##_name, \
- MAE_FIELD_MASK_VALUE_PAIRS_##_name##_LEN, \
- MAE_FIELD_MASK_VALUE_PAIRS_##_name##_OFST, \
- MAE_FIELD_MASK_VALUE_PAIRS_##_name##_MASK_LEN, \
- MAE_FIELD_MASK_VALUE_PAIRS_##_name##_MASK_OFST, \
+ MAE_FIELD_MASK_VALUE_PAIRS_V2_##_name##_LEN, \
+ MAE_FIELD_MASK_VALUE_PAIRS_V2_##_name##_OFST, \
+ MAE_FIELD_MASK_VALUE_PAIRS_V2_##_name##_MASK_LEN, \
+ MAE_FIELD_MASK_VALUE_PAIRS_V2_##_name##_MASK_OFST, \
0, 0 /* no alternative field */, \
_endianness \
}
EFX_MAE_MV_DESC(TCP_FLAGS_BE, EFX_MAE_FIELD_BE),
EFX_MAE_MV_DESC(ENC_VNET_ID_BE, EFX_MAE_FIELD_BE),
EFX_MAE_MV_DESC(OUTER_RULE_ID, EFX_MAE_FIELD_LE),
+ EFX_MAE_MV_DESC(RECIRC_ID, EFX_MAE_FIELD_LE),
#undef EFX_MAE_MV_DESC
};
#undef EFX_MAE_MV_BIT_DESC
};
+ __checkReturn efx_rc_t
+efx_mae_mport_invalid(
+ __out efx_mport_sel_t *mportp)
+{
+ efx_dword_t dword;
+ efx_rc_t rc;
+
+ if (mportp == NULL) {
+ rc = EINVAL;
+ goto fail1;
+ }
+
+ EFX_POPULATE_DWORD_1(dword,
+ MAE_MPORT_SELECTOR_TYPE, MAE_MPORT_SELECTOR_TYPE_INVALID);
+
+ memset(mportp, 0, sizeof (*mportp));
+ mportp->sel = dword.ed_u32[0];
+
+ return (0);
+
+fail1:
+ EFSYS_PROBE1(fail1, efx_rc_t, rc);
+ return (rc);
+}
+
__checkReturn efx_rc_t
efx_mae_mport_by_phy_port(
__in uint32_t phy_port,
efx_dword_t dword;
efx_rc_t rc;
+ rc = efx_mae_mport_by_pcie_mh_function(EFX_PCIE_INTERFACE_CALLER,
+ pf, vf, mportp);
+ if (rc != 0)
+ goto fail1;
+
+ return (0);
+
+fail1:
+ EFSYS_PROBE1(fail1, efx_rc_t, rc);
+ return (rc);
+}
+
+static __checkReturn efx_rc_t
+efx_mae_intf_to_selector(
+ __in efx_pcie_interface_t intf,
+ __out uint32_t *selector_intfp)
+{
+ efx_rc_t rc;
+
+ switch (intf) {
+ case EFX_PCIE_INTERFACE_HOST_PRIMARY:
+ EFX_STATIC_ASSERT(MAE_MPORT_SELECTOR_HOST_PRIMARY <=
+ EFX_MASK32(MAE_MPORT_SELECTOR_FUNC_INTF_ID));
+ *selector_intfp = MAE_MPORT_SELECTOR_HOST_PRIMARY;
+ break;
+ case EFX_PCIE_INTERFACE_NIC_EMBEDDED:
+ EFX_STATIC_ASSERT(MAE_MPORT_SELECTOR_NIC_EMBEDDED <=
+ EFX_MASK32(MAE_MPORT_SELECTOR_FUNC_INTF_ID));
+ *selector_intfp = MAE_MPORT_SELECTOR_NIC_EMBEDDED;
+ break;
+ case EFX_PCIE_INTERFACE_CALLER:
+ EFX_STATIC_ASSERT(MAE_MPORT_SELECTOR_CALLER_INTF <=
+ EFX_MASK32(MAE_MPORT_SELECTOR_FUNC_INTF_ID));
+ *selector_intfp = MAE_MPORT_SELECTOR_CALLER_INTF;
+ break;
+ default:
+ rc = EINVAL;
+ goto fail1;
+ }
+
+ return (0);
+
+fail1:
+ EFSYS_PROBE1(fail1, efx_rc_t, rc);
+ return (rc);
+}
+
+ __checkReturn efx_rc_t
+efx_mae_mport_by_pcie_mh_function(
+ __in efx_pcie_interface_t intf,
+ __in uint32_t pf,
+ __in uint32_t vf,
+ __out efx_mport_sel_t *mportp)
+{
+ uint32_t selector_intf;
+ efx_dword_t dword;
+ efx_rc_t rc;
+
EFX_STATIC_ASSERT(EFX_PCI_VF_INVALID ==
MAE_MPORT_SELECTOR_FUNC_VF_ID_NULL);
- if (pf > EFX_MASK32(MAE_MPORT_SELECTOR_FUNC_PF_ID)) {
- rc = EINVAL;
+ rc = efx_mae_intf_to_selector(intf, &selector_intf);
+ if (rc != 0)
goto fail1;
+
+ if (pf > EFX_MASK32(MAE_MPORT_SELECTOR_FUNC_MH_PF_ID)) {
+ rc = EINVAL;
+ goto fail2;
}
if (vf > EFX_MASK32(MAE_MPORT_SELECTOR_FUNC_VF_ID)) {
rc = EINVAL;
- goto fail2;
+ goto fail3;
}
- EFX_POPULATE_DWORD_3(dword,
- MAE_MPORT_SELECTOR_TYPE, MAE_MPORT_SELECTOR_TYPE_FUNC,
- MAE_MPORT_SELECTOR_FUNC_PF_ID, pf,
+
+ EFX_POPULATE_DWORD_4(dword,
+ MAE_MPORT_SELECTOR_TYPE, MAE_MPORT_SELECTOR_TYPE_MH_FUNC,
+ MAE_MPORT_SELECTOR_FUNC_INTF_ID, selector_intf,
+ MAE_MPORT_SELECTOR_FUNC_MH_PF_ID, pf,
MAE_MPORT_SELECTOR_FUNC_VF_ID, vf);
memset(mportp, 0, sizeof (*mportp));
- /*
- * The constructed DWORD is little-endian,
- * but the resulting value is meant to be
- * passed to MCDIs, where it will undergo
- * host-order to little endian conversion.
- */
- mportp->sel = EFX_DWORD_FIELD(dword, EFX_DWORD_0);
+ mportp->sel = dword.ed_u32[0];
return (0);
+fail3:
+ EFSYS_PROBE(fail3);
fail2:
EFSYS_PROBE(fail2);
fail1:
return (rc);
}
+static __checkReturn efx_rc_t
+efx_mcdi_mae_mport_lookup(
+ __in efx_nic_t *enp,
+ __in const efx_mport_sel_t *mport_selectorp,
+ __out efx_mport_id_t *mport_idp)
+{
+ efx_mcdi_req_t req;
+ EFX_MCDI_DECLARE_BUF(payload,
+ MC_CMD_MAE_MPORT_LOOKUP_IN_LEN,
+ MC_CMD_MAE_MPORT_LOOKUP_OUT_LEN);
+ efx_rc_t rc;
+
+ req.emr_cmd = MC_CMD_MAE_MPORT_LOOKUP;
+ req.emr_in_buf = payload;
+ req.emr_in_length = MC_CMD_MAE_MPORT_LOOKUP_IN_LEN;
+ req.emr_out_buf = payload;
+ req.emr_out_length = MC_CMD_MAE_MPORT_LOOKUP_OUT_LEN;
+
+ MCDI_IN_SET_DWORD(req, MAE_MPORT_LOOKUP_IN_MPORT_SELECTOR,
+ mport_selectorp->sel);
+
+ efx_mcdi_execute(enp, &req);
+
+ if (req.emr_rc != 0) {
+ rc = req.emr_rc;
+ goto fail1;
+ }
+
+ mport_idp->id = MCDI_OUT_DWORD(req, MAE_MPORT_LOOKUP_OUT_MPORT_ID);
+
+ return (0);
+
+fail1:
+ EFSYS_PROBE1(fail1, efx_rc_t, rc);
+ return (rc);
+}
+
+ __checkReturn efx_rc_t
+efx_mae_mport_id_by_selector(
+ __in efx_nic_t *enp,
+ __in const efx_mport_sel_t *mport_selectorp,
+ __out efx_mport_id_t *mport_idp)
+{
+ const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
+ efx_rc_t rc;
+
+ if (encp->enc_mae_supported == B_FALSE) {
+ rc = ENOTSUP;
+ goto fail1;
+ }
+
+ rc = efx_mcdi_mae_mport_lookup(enp, mport_selectorp, mport_idp);
+ if (rc != 0)
+ goto fail2;
+
+ return (0);
+
+fail2:
+ EFSYS_PROBE(fail2);
+fail1:
+ EFSYS_PROBE1(fail1, efx_rc_t, rc);
+ return (rc);
+}
+
+ __checkReturn efx_rc_t
+efx_mae_match_spec_recirc_id_set(
+ __in efx_mae_match_spec_t *spec,
+ __in uint8_t recirc_id)
+{
+ uint8_t full_mask = UINT8_MAX;
+ const uint8_t *vp;
+ const uint8_t *mp;
+ efx_rc_t rc;
+
+ vp = (const uint8_t *)&recirc_id;
+ mp = (const uint8_t *)&full_mask;
+
+ rc = efx_mae_match_spec_field_set(spec, EFX_MAE_FIELD_RECIRC_ID,
+ sizeof (recirc_id), vp,
+ sizeof (full_mask), mp);
+ if (rc != 0)
+ goto fail1;
+
+ return (0);
+
+fail1:
+ EFSYS_PROBE1(fail1, efx_rc_t, rc);
+ return (rc);
+}
+
+ __checkReturn efx_rc_t
+efx_mae_mport_by_id(
+ __in const efx_mport_id_t *mport_idp,
+ __out efx_mport_sel_t *mportp)
+{
+ efx_dword_t dword;
+
+ EFX_POPULATE_DWORD_2(dword,
+ MAE_MPORT_SELECTOR_TYPE, MAE_MPORT_SELECTOR_TYPE_MPORT_ID,
+ MAE_MPORT_SELECTOR_MPORT_ID, mport_idp->id);
+
+ memset(mportp, 0, sizeof (*mportp));
+ mportp->sel = __LE_TO_CPU_32(dword.ed_u32[0]);
+
+ return (0);
+}
+
__checkReturn efx_rc_t
efx_mae_match_spec_field_set(
__in efx_mae_match_spec_t *spec,
__in efx_nic_t *enp,
__out efx_mae_actions_t **specp)
{
+ const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
efx_mae_actions_t *spec;
efx_rc_t rc;
goto fail1;
}
+ spec->ema_rsrc.emar_dst_mac_id.id = EFX_MAE_RSRC_ID_INVALID;
+ spec->ema_rsrc.emar_src_mac_id.id = EFX_MAE_RSRC_ID_INVALID;
spec->ema_rsrc.emar_eh_id.id = EFX_MAE_RSRC_ID_INVALID;
spec->ema_rsrc.emar_counter_id.id = EFX_MAE_RSRC_ID_INVALID;
+ /*
+ * Helpers which populate v2 actions must reject them when v2 is not
+ * supported. As they have no EFX NIC argument, save v2 status here.
+ */
+ spec->ema_v2_is_supported = encp->enc_mae_aset_v2_supported;
+
*specp = spec;
return (0);
}
static __checkReturn efx_rc_t
-efx_mae_action_set_add_decap(
+efx_mae_action_set_no_op(
__in efx_mae_actions_t *spec,
__in size_t arg_size,
__in_bcount(arg_size) const uint8_t *arg)
return (rc);
}
-static __checkReturn efx_rc_t
-efx_mae_action_set_add_encap(
- __in efx_mae_actions_t *spec,
- __in size_t arg_size,
- __in_bcount(arg_size) const uint8_t *arg)
-{
- efx_rc_t rc;
-
- /*
- * Adding this specific action to an action set spec and setting encap.
- * header ID in the spec are two individual steps. This design allows
- * the client driver to avoid encap. header allocation when it simply
- * needs to check the order of actions submitted by user ("validate"),
- * without actually allocating an action set and inserting a rule.
- *
- * For now, mark encap. header ID as invalid; the caller will invoke
- * efx_mae_action_set_fill_in_eh_id() to override the field prior
- * to action set allocation; otherwise, the allocation will fail.
- */
- spec->ema_rsrc.emar_eh_id.id = EFX_MAE_RSRC_ID_INVALID;
-
- /*
- * As explained above, there are no arguments to handle here.
- * efx_mae_action_set_fill_in_eh_id() will take care of them.
- */
- if (arg_size != 0) {
- rc = EINVAL;
- goto fail1;
- }
-
- if (arg != NULL) {
- rc = EINVAL;
- goto fail2;
- }
-
- return (0);
-
-fail2:
- EFSYS_PROBE(fail2);
-fail1:
- EFSYS_PROBE1(fail1, efx_rc_t, rc);
- return (rc);
-}
-
static __checkReturn efx_rc_t
efx_mae_action_set_add_count(
__in efx_mae_actions_t *spec,
* two steps: first add this action to the action spec, and then
* add the counter ID to the spec. This allows validity checking
* and resource allocation to be done separately.
- * Mark the counter ID as invalid in the spec to ensure that the
- * caller must also invoke efx_mae_action_set_fill_in_counter_id()
- * before action set allocation.
+ *
+ * In order to fill in the counter ID, the caller is supposed to invoke
+ * efx_mae_action_set_fill_in_counter_id(). If they do not do that,
+ * efx_mae_action_set_alloc() invocation will throw an error.
+ *
+ * For now, no arguments are supposed to be handled.
*/
- spec->ema_rsrc.emar_counter_id.id = EFX_MAE_RSRC_ID_INVALID;
- /* Nothing else is supposed to take place over here. */
if (arg_size != 0) {
rc = EINVAL;
goto fail1;
return (rc);
}
-static __checkReturn efx_rc_t
-efx_mae_action_set_add_flag(
- __in efx_mae_actions_t *spec,
- __in size_t arg_size,
- __in_bcount(arg_size) const uint8_t *arg)
-{
- efx_rc_t rc;
-
- _NOTE(ARGUNUSED(spec))
-
- if (arg_size != 0) {
- rc = EINVAL;
- goto fail1;
- }
-
- if (arg != NULL) {
- rc = EINVAL;
- goto fail2;
- }
-
- /* This action does not have any arguments, so do nothing here. */
-
- return (0);
-
-fail2:
- EFSYS_PROBE(fail2);
-fail1:
- EFSYS_PROBE1(fail1, efx_rc_t, rc);
- return (rc);
-}
-
static __checkReturn efx_rc_t
efx_mae_action_set_add_mark(
__in efx_mae_actions_t *spec,
static const efx_mae_action_desc_t efx_mae_actions[EFX_MAE_NACTIONS] = {
[EFX_MAE_ACTION_DECAP] = {
- .emad_add = efx_mae_action_set_add_decap
+ .emad_add = efx_mae_action_set_no_op
},
[EFX_MAE_ACTION_VLAN_POP] = {
.emad_add = efx_mae_action_set_add_vlan_pop
},
+ [EFX_MAE_ACTION_SET_DST_MAC] = {
+ .emad_add = efx_mae_action_set_no_op
+ },
+ [EFX_MAE_ACTION_SET_SRC_MAC] = {
+ .emad_add = efx_mae_action_set_no_op
+ },
+ [EFX_MAE_ACTION_DECR_IP_TTL] = {
+ .emad_add = efx_mae_action_set_no_op
+ },
[EFX_MAE_ACTION_VLAN_PUSH] = {
.emad_add = efx_mae_action_set_add_vlan_push
},
[EFX_MAE_ACTION_ENCAP] = {
- .emad_add = efx_mae_action_set_add_encap
+ .emad_add = efx_mae_action_set_no_op
},
[EFX_MAE_ACTION_COUNT] = {
.emad_add = efx_mae_action_set_add_count
},
[EFX_MAE_ACTION_FLAG] = {
- .emad_add = efx_mae_action_set_add_flag
+ .emad_add = efx_mae_action_set_no_op
},
[EFX_MAE_ACTION_MARK] = {
.emad_add = efx_mae_action_set_add_mark
static const uint32_t efx_mae_action_ordered_map =
(1U << EFX_MAE_ACTION_DECAP) |
(1U << EFX_MAE_ACTION_VLAN_POP) |
+ (1U << EFX_MAE_ACTION_SET_DST_MAC) |
+ (1U << EFX_MAE_ACTION_SET_SRC_MAC) |
+ (1U << EFX_MAE_ACTION_DECR_IP_TTL) |
(1U << EFX_MAE_ACTION_VLAN_PUSH) |
/*
* HW will conduct action COUNT after
EFX_MAE_ACTION_VLAN_POP, 0, NULL));
}
+ __checkReturn efx_rc_t
+efx_mae_action_set_populate_set_dst_mac(
+ __in efx_mae_actions_t *spec)
+{
+ efx_rc_t rc;
+
+ if (spec->ema_v2_is_supported == B_FALSE) {
+ rc = ENOTSUP;
+ goto fail1;
+ }
+
+ return (efx_mae_action_set_spec_populate(spec,
+ EFX_MAE_ACTION_SET_DST_MAC, 0, NULL));
+
+fail1:
+ EFSYS_PROBE1(fail1, efx_rc_t, rc);
+ return (rc);
+}
+
+ __checkReturn efx_rc_t
+efx_mae_action_set_populate_set_src_mac(
+ __in efx_mae_actions_t *spec)
+{
+ efx_rc_t rc;
+
+ if (spec->ema_v2_is_supported == B_FALSE) {
+ rc = ENOTSUP;
+ goto fail1;
+ }
+
+ return (efx_mae_action_set_spec_populate(spec,
+ EFX_MAE_ACTION_SET_SRC_MAC, 0, NULL));
+
+fail1:
+ EFSYS_PROBE1(fail1, efx_rc_t, rc);
+ return (rc);
+}
+
+ __checkReturn efx_rc_t
+efx_mae_action_set_populate_decr_ip_ttl(
+ __in efx_mae_actions_t *spec)
+{
+ efx_rc_t rc;
+
+ if (spec->ema_v2_is_supported == B_FALSE) {
+ rc = ENOTSUP;
+ goto fail1;
+ }
+
+ return (efx_mae_action_set_spec_populate(spec,
+ EFX_MAE_ACTION_DECR_IP_TTL, 0, NULL));
+
+fail1:
+ EFSYS_PROBE1(fail1, efx_rc_t, rc);
+ return (rc);
+}
+
__checkReturn efx_rc_t
efx_mae_action_set_populate_vlan_push(
__in efx_mae_actions_t *spec,
fail2:
EFSYS_PROBE(fail2);
+fail1:
+ EFSYS_PROBE1(fail1, efx_rc_t, rc);
+ return (rc);
+}
+
+ __checkReturn efx_rc_t
+efx_mae_outer_rule_recirc_id_set(
+ __in efx_mae_match_spec_t *spec,
+ __in uint8_t recirc_id)
+{
+ efx_rc_t rc;
+
+ if (spec->emms_type != EFX_MAE_RULE_OUTER) {
+ rc = EINVAL;
+ goto fail1;
+ }
+
+ spec->emms_outer_rule_recirc_id = recirc_id;
+
+ return (0);
+
fail1:
EFSYS_PROBE1(fail1, efx_rc_t, rc);
return (rc);
memcpy(payload + offset, spec->emms_mask_value_pairs.outer,
MAE_ENC_FIELD_PAIRS_LEN);
+ MCDI_IN_SET_BYTE(req, MAE_OUTER_RULE_INSERT_IN_RECIRC_ID,
+ spec->emms_outer_rule_recirc_id);
+
efx_mcdi_execute(enp, &req);
if (req.emr_rc != 0) {
efx_mcdi_execute(enp, &req);
- if (req.emr_rc != 0) {
- rc = req.emr_rc;
+ if (req.emr_rc != 0) {
+ rc = req.emr_rc;
+ goto fail2;
+ }
+
+ if (req.emr_out_length_used < MC_CMD_MAE_OUTER_RULE_REMOVE_OUT_LENMIN) {
+ rc = EMSGSIZE;
+ goto fail3;
+ }
+
+ if (MCDI_OUT_DWORD(req, MAE_OUTER_RULE_REMOVE_OUT_REMOVED_OR_ID) !=
+ or_idp->id) {
+ /* Firmware failed to remove the outer rule. */
+ rc = EAGAIN;
+ goto fail4;
+ }
+
+ return (0);
+
+fail4:
+ EFSYS_PROBE(fail4);
+fail3:
+ EFSYS_PROBE(fail3);
+fail2:
+ EFSYS_PROBE(fail2);
+fail1:
+ EFSYS_PROBE1(fail1, efx_rc_t, rc);
+ return (rc);
+}
+
+ __checkReturn efx_rc_t
+efx_mae_match_spec_outer_rule_id_set(
+ __in efx_mae_match_spec_t *spec,
+ __in const efx_mae_rule_id_t *or_idp)
+{
+ uint32_t full_mask = UINT32_MAX;
+ efx_rc_t rc;
+
+ if (spec->emms_type != EFX_MAE_RULE_ACTION) {
+ rc = EINVAL;
+ goto fail1;
+ }
+
+ if (or_idp == NULL) {
+ rc = EINVAL;
+ goto fail2;
+ }
+
+ rc = efx_mae_match_spec_field_set(spec, EFX_MAE_FIELD_OUTER_RULE_ID,
+ sizeof (or_idp->id), (const uint8_t *)&or_idp->id,
+ sizeof (full_mask), (const uint8_t *)&full_mask);
+ if (rc != 0)
+ goto fail3;
+
+ return (0);
+
+fail3:
+ EFSYS_PROBE(fail3);
+fail2:
+ EFSYS_PROBE(fail2);
+fail1:
+ EFSYS_PROBE1(fail1, efx_rc_t, rc);
+ return (rc);
+}
+
+ __checkReturn efx_rc_t
+efx_mae_mac_addr_alloc(
+ __in efx_nic_t *enp,
+ __in uint8_t addr_bytes[EFX_MAC_ADDR_LEN],
+ __out efx_mae_mac_id_t *mac_idp)
+{
+ const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
+ efx_mcdi_req_t req;
+ EFX_MCDI_DECLARE_BUF(payload,
+ MC_CMD_MAE_MAC_ADDR_ALLOC_IN_LEN,
+ MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_LEN);
+ efx_mae_mac_id_t mac_id;
+ efx_rc_t rc;
+
+ EFX_STATIC_ASSERT(sizeof (mac_idp->id) ==
+ MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_LEN);
+
+ EFX_STATIC_ASSERT(EFX_MAE_RSRC_ID_INVALID ==
+ MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL);
+
+ if (encp->enc_mae_supported == B_FALSE) {
+ rc = ENOTSUP;
+ goto fail1;
+ }
+
+ if (encp->enc_mae_aset_v2_supported == B_FALSE) {
+ rc = ENOTSUP;
+ goto fail2;
+ }
+
+ req.emr_cmd = MC_CMD_MAE_MAC_ADDR_ALLOC;
+ req.emr_in_buf = payload;
+ req.emr_in_length = MC_CMD_MAE_MAC_ADDR_ALLOC_IN_LEN;
+ req.emr_out_buf = payload;
+ req.emr_out_length = MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_LEN;
+
+ memcpy(payload + MC_CMD_MAE_MAC_ADDR_ALLOC_IN_MAC_ADDR_OFST,
+ addr_bytes, EFX_MAC_ADDR_LEN);
+
+ efx_mcdi_execute(enp, &req);
+
+ if (req.emr_rc != 0) {
+ rc = req.emr_rc;
+ goto fail3;
+ }
+
+ if (req.emr_out_length_used < MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_LEN) {
+ rc = EMSGSIZE;
+ goto fail4;
+ }
+
+ mac_id.id = MCDI_OUT_DWORD(req, MAE_MAC_ADDR_ALLOC_OUT_MAC_ID);
+ if (mac_id.id == EFX_MAE_RSRC_ID_INVALID) {
+ rc = ENOENT;
+ goto fail5;
+ }
+
+ mac_idp->id = mac_id.id;
+
+ return (0);
+
+fail5:
+ EFSYS_PROBE(fail5);
+fail4:
+ EFSYS_PROBE(fail4);
+fail3:
+ EFSYS_PROBE(fail3);
+fail2:
+ EFSYS_PROBE(fail2);
+fail1:
+ EFSYS_PROBE1(fail1, efx_rc_t, rc);
+ return (rc);
+}
+
+ __checkReturn efx_rc_t
+efx_mae_mac_addr_free(
+ __in efx_nic_t *enp,
+ __in const efx_mae_mac_id_t *mac_idp)
+{
+ const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
+ efx_mcdi_req_t req;
+ EFX_MCDI_DECLARE_BUF(payload,
+ MC_CMD_MAE_MAC_ADDR_FREE_IN_LEN(1),
+ MC_CMD_MAE_MAC_ADDR_FREE_OUT_LEN(1));
+ efx_rc_t rc;
+
+ if (encp->enc_mae_supported == B_FALSE) {
+ rc = ENOTSUP;
+ goto fail1;
+ }
+
+ if (encp->enc_mae_aset_v2_supported == B_FALSE) {
+ rc = ENOTSUP;
+ goto fail2;
+ }
+
+ req.emr_cmd = MC_CMD_MAE_MAC_ADDR_FREE;
+ req.emr_in_buf = payload;
+ req.emr_in_length = MC_CMD_MAE_MAC_ADDR_FREE_IN_LEN(1);
+ req.emr_out_buf = payload;
+ req.emr_out_length = MC_CMD_MAE_MAC_ADDR_FREE_OUT_LEN(1);
+
+ MCDI_IN_SET_DWORD(req, MAE_MAC_ADDR_FREE_IN_MAC_ID, mac_idp->id);
+
+ efx_mcdi_execute(enp, &req);
+
+ if (req.emr_rc != 0) {
+ rc = req.emr_rc;
+ goto fail3;
+ }
+
+ if (req.emr_out_length_used < MC_CMD_MAE_MAC_ADDR_FREE_OUT_LEN(1)) {
+ rc = EMSGSIZE;
+ goto fail4;
+ }
+
+ if (MCDI_OUT_DWORD(req, MAE_MAC_ADDR_FREE_OUT_FREED_MAC_ID) !=
+ mac_idp->id) {
+ /* Firmware failed to remove the MAC address entry. */
+ rc = EAGAIN;
+ goto fail5;
+ }
+
+ return (0);
+
+fail5:
+ EFSYS_PROBE(fail5);
+fail4:
+ EFSYS_PROBE(fail4);
+fail3:
+ EFSYS_PROBE(fail3);
+fail2:
+ EFSYS_PROBE(fail2);
+fail1:
+ EFSYS_PROBE1(fail1, efx_rc_t, rc);
+ return (rc);
+}
+
+ __checkReturn efx_rc_t
+efx_mae_action_set_fill_in_dst_mac_id(
+ __in efx_mae_actions_t *spec,
+ __in const efx_mae_mac_id_t *mac_idp)
+{
+ efx_rc_t rc;
+
+ if ((spec->ema_actions & (1U << EFX_MAE_ACTION_SET_DST_MAC)) == 0) {
+ /*
+ * The caller has not intended to have this action originally,
+ * hence, they cannot indicate the MAC address entry ID.
+ */
+ rc = EINVAL;
+ goto fail1;
+ }
+
+ if (spec->ema_rsrc.emar_dst_mac_id.id != EFX_MAE_RSRC_ID_INVALID) {
+ /* An attempt to indicate the MAC address entry ID twice. */
+ rc = EINVAL;
goto fail2;
}
- if (req.emr_out_length_used < MC_CMD_MAE_OUTER_RULE_REMOVE_OUT_LENMIN) {
- rc = EMSGSIZE;
+ if (mac_idp->id == EFX_MAE_RSRC_ID_INVALID) {
+ rc = EINVAL;
goto fail3;
}
- if (MCDI_OUT_DWORD(req, MAE_OUTER_RULE_REMOVE_OUT_REMOVED_OR_ID) !=
- or_idp->id) {
- /* Firmware failed to remove the outer rule. */
- rc = EAGAIN;
- goto fail4;
- }
+ spec->ema_rsrc.emar_dst_mac_id.id = mac_idp->id;
return (0);
-fail4:
- EFSYS_PROBE(fail4);
fail3:
EFSYS_PROBE(fail3);
fail2:
}
__checkReturn efx_rc_t
-efx_mae_match_spec_outer_rule_id_set(
- __in efx_mae_match_spec_t *spec,
- __in const efx_mae_rule_id_t *or_idp)
+efx_mae_action_set_fill_in_src_mac_id(
+ __in efx_mae_actions_t *spec,
+ __in const efx_mae_mac_id_t *mac_idp)
{
- uint32_t full_mask = UINT32_MAX;
efx_rc_t rc;
- if (spec->emms_type != EFX_MAE_RULE_ACTION) {
+ if ((spec->ema_actions & (1U << EFX_MAE_ACTION_SET_SRC_MAC)) == 0) {
+ /*
+ * The caller has not intended to have this action originally,
+ * hence, they cannot indicate the MAC address entry ID.
+ */
rc = EINVAL;
goto fail1;
}
- if (or_idp == NULL) {
+ if (spec->ema_rsrc.emar_src_mac_id.id != EFX_MAE_RSRC_ID_INVALID) {
+ /* An attempt to indicate the MAC address entry ID twice. */
rc = EINVAL;
goto fail2;
}
- rc = efx_mae_match_spec_field_set(spec, EFX_MAE_FIELD_OUTER_RULE_ID,
- sizeof (or_idp->id), (const uint8_t *)&or_idp->id,
- sizeof (full_mask), (const uint8_t *)&full_mask);
- if (rc != 0)
+ if (mac_idp->id == EFX_MAE_RSRC_ID_INVALID) {
+ rc = EINVAL;
goto fail3;
+ }
+
+ spec->ema_rsrc.emar_src_mac_id.id = mac_idp->id;
return (0);
goto fail1;
}
+ if ((spec->ema_actions & (1U << EFX_MAE_ACTION_SET_DST_MAC)) != 0 &&
+ spec->ema_rsrc.emar_dst_mac_id.id == EFX_MAE_RSRC_ID_INVALID) {
+ rc = EINVAL;
+ goto fail2;
+ }
+
+ if ((spec->ema_actions & (1U << EFX_MAE_ACTION_SET_SRC_MAC)) != 0 &&
+ spec->ema_rsrc.emar_src_mac_id.id == EFX_MAE_RSRC_ID_INVALID) {
+ rc = EINVAL;
+ goto fail3;
+ }
+
+ if ((spec->ema_actions & (1U << EFX_MAE_ACTION_ENCAP)) != 0 &&
+ spec->ema_rsrc.emar_eh_id.id == EFX_MAE_RSRC_ID_INVALID) {
+ rc = EINVAL;
+ goto fail4;
+ }
+
+ if (spec->ema_n_count_actions == 1 &&
+ spec->ema_rsrc.emar_counter_id.id == EFX_MAE_RSRC_ID_INVALID) {
+ rc = EINVAL;
+ goto fail5;
+ }
+
req.emr_cmd = MC_CMD_MAE_ACTION_SET_ALLOC;
req.emr_in_buf = payload;
req.emr_in_length = MC_CMD_MAE_ACTION_SET_ALLOC_IN_LEN;
MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
MAE_ACTION_SET_ALLOC_IN_VLAN_POP, spec->ema_n_vlan_tags_to_pop);
+ MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_ALLOC_IN_DST_MAC_ID,
+ spec->ema_rsrc.emar_dst_mac_id.id);
+
+ MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_ALLOC_IN_SRC_MAC_ID,
+ spec->ema_rsrc.emar_src_mac_id.id);
+
+ if ((spec->ema_actions & (1U << EFX_MAE_ACTION_DECR_IP_TTL)) != 0) {
+ MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
+ MAE_ACTION_SET_ALLOC_IN_DO_DECR_IP_TTL, 1);
+ }
+
if (spec->ema_n_vlan_tags_to_push > 0) {
unsigned int outer_tag_idx;
MCDI_IN_SET_DWORD(req,
MAE_ACTION_SET_ALLOC_IN_DELIVER, spec->ema_deliver_mport.sel);
- MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_ALLOC_IN_SRC_MAC_ID,
- MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL);
- MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_ALLOC_IN_DST_MAC_ID,
- MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL);
-
efx_mcdi_execute(enp, &req);
if (req.emr_rc != 0) {
rc = req.emr_rc;
- goto fail2;
+ goto fail6;
}
if (req.emr_out_length_used < MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN) {
rc = EMSGSIZE;
- goto fail3;
+ goto fail7;
}
aset_id.id = MCDI_OUT_DWORD(req, MAE_ACTION_SET_ALLOC_OUT_AS_ID);
if (aset_id.id == EFX_MAE_RSRC_ID_INVALID) {
rc = ENOENT;
- goto fail4;
+ goto fail8;
}
aset_idp->id = aset_id.id;
return (0);
+fail8:
+ EFSYS_PROBE(fail8);
+fail7:
+ EFSYS_PROBE(fail7);
+fail6:
+ EFSYS_PROBE(fail6);
+fail5:
+ EFSYS_PROBE(fail5);
fail4:
EFSYS_PROBE(fail4);
fail3:
return (rc);
}
+ __checkReturn efx_rc_t
+efx_mcdi_mport_alloc_alias(
+ __in efx_nic_t *enp,
+ __out efx_mport_id_t *mportp,
+ __out_opt uint32_t *labelp)
+{
+ const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
+ efx_mcdi_req_t req;
+ EFX_MCDI_DECLARE_BUF(payload,
+ MC_CMD_MAE_MPORT_ALLOC_ALIAS_IN_LEN,
+ MC_CMD_MAE_MPORT_ALLOC_ALIAS_OUT_LEN);
+ efx_rc_t rc;
+
+ if (encp->enc_mae_supported == B_FALSE) {
+ rc = ENOTSUP;
+ goto fail1;
+ }
+
+ req.emr_cmd = MC_CMD_MAE_MPORT_ALLOC;
+ req.emr_in_buf = payload;
+ req.emr_in_length = MC_CMD_MAE_MPORT_ALLOC_ALIAS_IN_LEN;
+ req.emr_out_buf = payload;
+ req.emr_out_length = MC_CMD_MAE_MPORT_ALLOC_ALIAS_OUT_LEN;
+
+ MCDI_IN_SET_DWORD(req, MAE_MPORT_ALLOC_IN_TYPE,
+ MC_CMD_MAE_MPORT_ALLOC_IN_MPORT_TYPE_ALIAS);
+ MCDI_IN_SET_DWORD(req, MAE_MPORT_ALLOC_ALIAS_IN_DELIVER_MPORT,
+ MAE_MPORT_SELECTOR_ASSIGNED);
+
+ efx_mcdi_execute(enp, &req);
+
+ if (req.emr_rc != 0) {
+ rc = req.emr_rc;
+ goto fail2;
+ }
+
+ mportp->id = MCDI_OUT_DWORD(req, MAE_MPORT_ALLOC_OUT_MPORT_ID);
+ if (labelp != NULL)
+ *labelp = MCDI_OUT_DWORD(req, MAE_MPORT_ALLOC_ALIAS_OUT_LABEL);
+
+ return (0);
+
+fail2:
+ EFSYS_PROBE(fail2);
+fail1:
+ EFSYS_PROBE1(fail1, efx_rc_t, rc);
+ return (rc);
+}
+
+ __checkReturn efx_rc_t
+efx_mae_mport_free(
+ __in efx_nic_t *enp,
+ __in const efx_mport_id_t *mportp)
+{
+ const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
+ efx_mcdi_req_t req;
+ EFX_MCDI_DECLARE_BUF(payload,
+ MC_CMD_MAE_MPORT_FREE_IN_LEN,
+ MC_CMD_MAE_MPORT_FREE_OUT_LEN);
+ efx_rc_t rc;
+
+ if (encp->enc_mae_supported == B_FALSE) {
+ rc = ENOTSUP;
+ goto fail1;
+ }
+
+ req.emr_cmd = MC_CMD_MAE_MPORT_FREE;
+ req.emr_in_buf = payload;
+ req.emr_in_length = MC_CMD_MAE_MPORT_FREE_IN_LEN;
+ req.emr_out_buf = payload;
+ req.emr_out_length = MC_CMD_MAE_MPORT_FREE_OUT_LEN;
+
+ MCDI_IN_SET_DWORD(req, MAE_MPORT_FREE_IN_MPORT_ID, mportp->id);
+
+ efx_mcdi_execute(enp, &req);
+
+ if (req.emr_rc != 0) {
+ rc = req.emr_rc;
+ goto fail2;
+ }
+
+ return (0);
+
+fail2:
+ EFSYS_PROBE(fail2);
+fail1:
+ EFSYS_PROBE1(fail1, efx_rc_t, rc);
+ return (rc);
+}
+
+static __checkReturn efx_rc_t
+efx_mae_read_mport_journal_single(
+ __in uint8_t *entry_buf,
+ __out efx_mport_desc_t *desc)
+{
+ uint32_t pcie_intf;
+ efx_rc_t rc;
+
+ memset(desc, 0, sizeof (*desc));
+
+ desc->emd_id.id = MCDI_STRUCT_DWORD(entry_buf,
+ MAE_MPORT_DESC_V2_MPORT_ID);
+
+ desc->emd_can_receive_on = MCDI_STRUCT_DWORD_FIELD(entry_buf,
+ MAE_MPORT_DESC_V2_FLAGS,
+ MAE_MPORT_DESC_V2_CAN_RECEIVE_ON);
+
+ desc->emd_can_deliver_to = MCDI_STRUCT_DWORD_FIELD(entry_buf,
+ MAE_MPORT_DESC_V2_FLAGS,
+ MAE_MPORT_DESC_V2_CAN_DELIVER_TO);
+
+ desc->emd_can_delete = MCDI_STRUCT_DWORD_FIELD(entry_buf,
+ MAE_MPORT_DESC_V2_FLAGS,
+ MAE_MPORT_DESC_V2_CAN_DELETE);
+
+ desc->emd_zombie = MCDI_STRUCT_DWORD_FIELD(entry_buf,
+ MAE_MPORT_DESC_V2_FLAGS,
+ MAE_MPORT_DESC_V2_IS_ZOMBIE);
+
+ desc->emd_type = MCDI_STRUCT_DWORD(entry_buf,
+ MAE_MPORT_DESC_V2_MPORT_TYPE);
+
+ /*
+ * We can't check everything here. If some additional checks are
+ * required, they should be performed by the callback function.
+ */
+ switch (desc->emd_type) {
+ case EFX_MPORT_TYPE_NET_PORT:
+ desc->emd_net_port.ep_index =
+ MCDI_STRUCT_DWORD(entry_buf,
+ MAE_MPORT_DESC_V2_NET_PORT_IDX);
+ break;
+ case EFX_MPORT_TYPE_ALIAS:
+ desc->emd_alias.ea_target_mport_id.id =
+ MCDI_STRUCT_DWORD(entry_buf,
+ MAE_MPORT_DESC_V2_ALIAS_DELIVER_MPORT_ID);
+ break;
+ case EFX_MPORT_TYPE_VNIC:
+ desc->emd_vnic.ev_client_type =
+ MCDI_STRUCT_DWORD(entry_buf,
+ MAE_MPORT_DESC_V2_VNIC_CLIENT_TYPE);
+ if (desc->emd_vnic.ev_client_type !=
+ EFX_MPORT_VNIC_CLIENT_FUNCTION)
+ break;
+
+ pcie_intf = MCDI_STRUCT_DWORD(entry_buf,
+ MAE_MPORT_DESC_V2_VNIC_FUNCTION_INTERFACE);
+ rc = efx_mcdi_intf_from_pcie(pcie_intf,
+ &desc->emd_vnic.ev_intf);
+ if (rc != 0)
+ goto fail1;
+
+ desc->emd_vnic.ev_pf = MCDI_STRUCT_WORD(entry_buf,
+ MAE_MPORT_DESC_V2_VNIC_FUNCTION_PF_IDX);
+ desc->emd_vnic.ev_vf = MCDI_STRUCT_WORD(entry_buf,
+ MAE_MPORT_DESC_V2_VNIC_FUNCTION_VF_IDX);
+ desc->emd_vnic.ev_handle = MCDI_STRUCT_DWORD(entry_buf,
+ MAE_MPORT_DESC_V2_VNIC_CLIENT_HANDLE);
+ break;
+ default:
+ rc = EINVAL;
+ goto fail2;
+ }
+
+ return (0);
+
+fail2:
+ EFSYS_PROBE(fail2);
+fail1:
+ EFSYS_PROBE1(fail1, efx_rc_t, rc);
+ return (rc);
+}
+
+static __checkReturn efx_rc_t
+efx_mae_read_mport_journal_batch(
+ __in efx_nic_t *enp,
+ __in efx_mae_read_mport_journal_cb *cbp,
+ __in void *cb_datap,
+ __out uint32_t *morep)
+{
+ efx_mcdi_req_t req;
+ EFX_MCDI_DECLARE_BUF(payload,
+ MC_CMD_MAE_MPORT_READ_JOURNAL_IN_LEN,
+ MC_CMD_MAE_MPORT_READ_JOURNAL_OUT_LENMAX_MCDI2);
+ uint32_t n_entries;
+ uint32_t entry_sz;
+ uint8_t *entry_buf;
+ unsigned int i;
+ efx_rc_t rc;
+
+ EFX_STATIC_ASSERT(EFX_MPORT_TYPE_NET_PORT ==
+ MAE_MPORT_DESC_V2_MPORT_TYPE_NET_PORT);
+ EFX_STATIC_ASSERT(EFX_MPORT_TYPE_ALIAS ==
+ MAE_MPORT_DESC_V2_MPORT_TYPE_ALIAS);
+ EFX_STATIC_ASSERT(EFX_MPORT_TYPE_VNIC ==
+ MAE_MPORT_DESC_V2_MPORT_TYPE_VNIC);
+
+ EFX_STATIC_ASSERT(EFX_MPORT_VNIC_CLIENT_FUNCTION ==
+ MAE_MPORT_DESC_V2_VNIC_CLIENT_TYPE_FUNCTION);
+ EFX_STATIC_ASSERT(EFX_MPORT_VNIC_CLIENT_PLUGIN ==
+ MAE_MPORT_DESC_V2_VNIC_CLIENT_TYPE_PLUGIN);
+
+ if (cbp == NULL) {
+ rc = EINVAL;
+ goto fail1;
+ }
+
+ req.emr_cmd = MC_CMD_MAE_MPORT_READ_JOURNAL;
+ req.emr_in_buf = payload;
+ req.emr_in_length = MC_CMD_MAE_MPORT_READ_JOURNAL_IN_LEN;
+ req.emr_out_buf = payload;
+ req.emr_out_length = MC_CMD_MAE_MPORT_READ_JOURNAL_OUT_LENMAX_MCDI2;
+
+ MCDI_IN_SET_DWORD(req, MAE_MPORT_READ_JOURNAL_IN_FLAGS, 0);
+
+ efx_mcdi_execute(enp, &req);
+
+ if (req.emr_rc != 0) {
+ rc = req.emr_rc;
+ goto fail2;
+ }
+
+ if (req.emr_out_length_used <
+ MC_CMD_MAE_MPORT_READ_JOURNAL_OUT_LENMIN) {
+ rc = EMSGSIZE;
+ goto fail3;
+ }
+
+ if (morep != NULL) {
+ *morep = MCDI_OUT_DWORD_FIELD(req,
+ MAE_MPORT_READ_JOURNAL_OUT_FLAGS,
+ MAE_MPORT_READ_JOURNAL_OUT_MORE);
+ }
+ n_entries = MCDI_OUT_DWORD(req,
+ MAE_MPORT_READ_JOURNAL_OUT_MPORT_DESC_COUNT);
+ entry_sz = MCDI_OUT_DWORD(req,
+ MAE_MPORT_READ_JOURNAL_OUT_SIZEOF_MPORT_DESC);
+ entry_buf = MCDI_OUT2(req, uint8_t,
+ MAE_MPORT_READ_JOURNAL_OUT_MPORT_DESC_DATA);
+
+ if (entry_sz < MAE_MPORT_DESC_V2_VNIC_CLIENT_HANDLE_OFST +
+ MAE_MPORT_DESC_V2_VNIC_CLIENT_HANDLE_LEN) {
+ rc = EINVAL;
+ goto fail4;
+ }
+ if (n_entries * entry_sz / entry_sz != n_entries) {
+ rc = EINVAL;
+ goto fail5;
+ }
+ if (req.emr_out_length_used !=
+ MC_CMD_MAE_MPORT_READ_JOURNAL_OUT_LENMIN + n_entries * entry_sz) {
+ rc = EINVAL;
+ goto fail6;
+ }
+
+ for (i = 0; i < n_entries; i++) {
+ efx_mport_desc_t desc;
+
+ rc = efx_mae_read_mport_journal_single(entry_buf, &desc);
+ if (rc != 0)
+ continue;
+
+ (*cbp)(cb_datap, &desc, sizeof (desc));
+ entry_buf += entry_sz;
+ }
+
+ return (0);
+
+fail6:
+ EFSYS_PROBE(fail6);
+fail5:
+ EFSYS_PROBE(fail5);
+fail4:
+ EFSYS_PROBE(fail4);
+fail3:
+ EFSYS_PROBE(fail3);
+fail2:
+ EFSYS_PROBE(fail2);
+fail1:
+ EFSYS_PROBE1(fail1, efx_rc_t, rc);
+ return (rc);
+}
+
+ __checkReturn efx_rc_t
+efx_mae_read_mport_journal(
+ __in efx_nic_t *enp,
+ __in efx_mae_read_mport_journal_cb *cbp,
+ __in void *cb_datap)
+{
+ const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
+ uint32_t more = 0;
+ efx_rc_t rc;
+
+ if (encp->enc_mae_supported == B_FALSE) {
+ rc = ENOTSUP;
+ goto fail1;
+ }
+
+ do {
+ rc = efx_mae_read_mport_journal_batch(enp, cbp, cb_datap,
+ &more);
+ if (rc != 0)
+ goto fail2;
+ } while (more != 0);
+
+ return (0);
+
+fail2:
+ EFSYS_PROBE(fail2);
+fail1:
+ EFSYS_PROBE1(fail1, efx_rc_t, rc);
+ return (rc);
+}
+
#endif /* EFSYS_OPT_MAE */