+ req.emr_in_length = MC_CMD_MAE_OUTER_RULE_REMOVE_IN_LEN(1);
+ req.emr_out_buf = payload;
+ req.emr_out_length = MC_CMD_MAE_OUTER_RULE_REMOVE_OUT_LEN(1);
+
+ MCDI_IN_SET_DWORD(req, MAE_OUTER_RULE_REMOVE_IN_OR_ID, or_idp->id);
+
+ 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_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_encap_header_alloc(
+ __in efx_nic_t *enp,
+ __in efx_tunnel_protocol_t encap_type,
+ __in_bcount(header_size) uint8_t *header_data,
+ __in size_t header_size,
+ __out efx_mae_eh_id_t *eh_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_ENCAP_HEADER_ALLOC_IN_LENMAX_MCDI2,
+ MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_LEN);
+ uint32_t encap_type_mcdi;
+ efx_mae_eh_id_t eh_id;
+ efx_rc_t rc;
+
+ EFX_STATIC_ASSERT(sizeof (eh_idp->id) ==
+ MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID_LEN);
+
+ EFX_STATIC_ASSERT(EFX_MAE_RSRC_ID_INVALID ==
+ MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID_NULL);
+
+ if (encp->enc_mae_supported == B_FALSE) {
+ rc = ENOTSUP;
+ goto fail1;
+ }
+
+ switch (encap_type) {
+ case EFX_TUNNEL_PROTOCOL_NONE:
+ encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_NONE;
+ break;
+ case EFX_TUNNEL_PROTOCOL_VXLAN:
+ encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_VXLAN;
+ break;
+ case EFX_TUNNEL_PROTOCOL_GENEVE:
+ encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_GENEVE;
+ break;
+ case EFX_TUNNEL_PROTOCOL_NVGRE:
+ encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_NVGRE;
+ break;
+ default:
+ rc = ENOTSUP;
+ goto fail2;
+ }
+
+ if (header_size >
+ MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_HDR_DATA_MAXNUM_MCDI2) {
+ rc = EINVAL;
+ goto fail3;
+ }
+
+ req.emr_cmd = MC_CMD_MAE_ENCAP_HEADER_ALLOC;
+ req.emr_in_buf = payload;
+ req.emr_in_length = MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_LEN(header_size);
+ req.emr_out_buf = payload;
+ req.emr_out_length = MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_LEN;
+
+ MCDI_IN_SET_DWORD(req,
+ MAE_ENCAP_HEADER_ALLOC_IN_ENCAP_TYPE, encap_type_mcdi);
+
+ memcpy(payload + MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_HDR_DATA_OFST,
+ header_data, header_size);
+
+ efx_mcdi_execute(enp, &req);
+
+ if (req.emr_rc != 0) {
+ rc = req.emr_rc;
+ goto fail4;
+ }
+
+ if (req.emr_out_length_used < MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_LEN) {
+ rc = EMSGSIZE;
+ goto fail5;
+ }
+
+ eh_id.id = MCDI_OUT_DWORD(req,
+ MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID);
+
+ if (eh_id.id == EFX_MAE_RSRC_ID_INVALID) {
+ rc = ENOENT;
+ goto fail6;
+ }
+
+ eh_idp->id = eh_id.id;
+
+ 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_encap_header_free(
+ __in efx_nic_t *enp,
+ __in const efx_mae_eh_id_t *eh_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_ENCAP_HEADER_FREE_IN_LEN(1),
+ MC_CMD_MAE_ENCAP_HEADER_FREE_OUT_LEN(1));
+ efx_rc_t rc;
+
+ if (encp->enc_mae_supported == B_FALSE) {
+ rc = ENOTSUP;
+ goto fail1;
+ }
+
+ req.emr_cmd = MC_CMD_MAE_ENCAP_HEADER_FREE;
+ req.emr_in_buf = payload;
+ req.emr_in_length = MC_CMD_MAE_ENCAP_HEADER_FREE_IN_LEN(1);
+ req.emr_out_buf = payload;
+ req.emr_out_length = MC_CMD_MAE_ENCAP_HEADER_FREE_OUT_LEN(1);
+
+ MCDI_IN_SET_DWORD(req, MAE_ENCAP_HEADER_FREE_IN_EH_ID, eh_idp->id);
+
+ efx_mcdi_execute(enp, &req);
+
+ if (req.emr_rc != 0) {
+ rc = req.emr_rc;
+ goto fail2;
+ }
+
+ if (MCDI_OUT_DWORD(req, MAE_ENCAP_HEADER_FREE_OUT_FREED_EH_ID) !=
+ eh_idp->id) {
+ /* Firmware failed to remove the encap. header. */
+ rc = EAGAIN;
+ 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_action_set_fill_in_eh_id(
+ __in efx_mae_actions_t *spec,
+ __in const efx_mae_eh_id_t *eh_idp)
+{
+ efx_rc_t rc;
+
+ if ((spec->ema_actions & (1U << EFX_MAE_ACTION_ENCAP)) == 0) {
+ /*
+ * The caller has not intended to have action ENCAP originally,
+ * hence, this attempt to indicate encap. header ID is invalid.
+ */
+ rc = EINVAL;
+ goto fail1;
+ }
+
+ if (spec->ema_rsrc.emar_eh_id.id != EFX_MAE_RSRC_ID_INVALID) {
+ /* The caller attempts to indicate encap. header ID twice. */
+ rc = EINVAL;
+ goto fail2;
+ }
+
+ if (eh_idp->id == EFX_MAE_RSRC_ID_INVALID) {
+ rc = EINVAL;
+ goto fail3;
+ }
+
+ spec->ema_rsrc.emar_eh_id.id = eh_idp->id;
+
+ 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_action_set_alloc(
+ __in efx_nic_t *enp,
+ __in const efx_mae_actions_t *spec,
+ __out efx_mae_aset_id_t *aset_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_ACTION_SET_ALLOC_IN_LEN,
+ MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN);
+ efx_mae_aset_id_t aset_id;
+ efx_rc_t rc;
+
+ if (encp->enc_mae_supported == B_FALSE) {
+ rc = ENOTSUP;
+ goto fail1;
+ }
+
+ 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;
+ req.emr_out_buf = payload;
+ req.emr_out_length = MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN;
+
+ /*
+ * TODO: Remove these EFX_MAE_RSRC_ID_INVALID assignments once the
+ * corresponding resource types are supported by the implementation.
+ * Use proper resource ID assignments instead.
+ */
+ MCDI_IN_SET_DWORD(req,
+ MAE_ACTION_SET_ALLOC_IN_COUNTER_LIST_ID, EFX_MAE_RSRC_ID_INVALID);
+
+ if ((spec->ema_actions & (1U << EFX_MAE_ACTION_DECAP)) != 0) {
+ MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
+ MAE_ACTION_SET_ALLOC_IN_DECAP, 1);
+ }
+
+ 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);
+
+ if (spec->ema_n_vlan_tags_to_push > 0) {
+ unsigned int outer_tag_idx;
+
+ MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
+ MAE_ACTION_SET_ALLOC_IN_VLAN_PUSH,
+ spec->ema_n_vlan_tags_to_push);
+
+ if (spec->ema_n_vlan_tags_to_push ==
+ EFX_MAE_VLAN_PUSH_MAX_NTAGS) {
+ MCDI_IN_SET_WORD(req,
+ MAE_ACTION_SET_ALLOC_IN_VLAN1_PROTO_BE,
+ spec->ema_vlan_push_descs[0].emavp_tpid_be);
+ MCDI_IN_SET_WORD(req,
+ MAE_ACTION_SET_ALLOC_IN_VLAN1_TCI_BE,
+ spec->ema_vlan_push_descs[0].emavp_tci_be);
+ }
+
+ outer_tag_idx = spec->ema_n_vlan_tags_to_push - 1;
+
+ MCDI_IN_SET_WORD(req, MAE_ACTION_SET_ALLOC_IN_VLAN0_PROTO_BE,
+ spec->ema_vlan_push_descs[outer_tag_idx].emavp_tpid_be);
+ MCDI_IN_SET_WORD(req, MAE_ACTION_SET_ALLOC_IN_VLAN0_TCI_BE,
+ spec->ema_vlan_push_descs[outer_tag_idx].emavp_tci_be);
+ }
+
+ MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_ALLOC_IN_ENCAP_HEADER_ID,
+ spec->ema_rsrc.emar_eh_id.id);
+ MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_ALLOC_IN_COUNTER_ID,
+ spec->ema_rsrc.emar_counter_id.id);
+
+ if ((spec->ema_actions & (1U << EFX_MAE_ACTION_FLAG)) != 0) {
+ MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
+ MAE_ACTION_SET_ALLOC_IN_FLAG, 1);
+ }
+
+ if ((spec->ema_actions & (1U << EFX_MAE_ACTION_MARK)) != 0) {
+ MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
+ MAE_ACTION_SET_ALLOC_IN_MARK, 1);
+
+ MCDI_IN_SET_DWORD(req,
+ MAE_ACTION_SET_ALLOC_IN_MARK_VALUE, spec->ema_mark_value);
+ }
+
+ 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;
+ }
+
+ if (req.emr_out_length_used < MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN) {
+ rc = EMSGSIZE;
+ goto fail3;
+ }
+
+ 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;
+ }
+
+ aset_idp->id = aset_id.id;
+
+ 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 unsigned int
+efx_mae_action_set_get_nb_count(
+ __in const efx_mae_actions_t *spec)
+{
+ return (spec->ema_n_count_actions);
+}
+
+ __checkReturn efx_rc_t
+efx_mae_action_set_fill_in_counter_id(
+ __in efx_mae_actions_t *spec,
+ __in const efx_counter_t *counter_idp)
+{
+ efx_rc_t rc;
+
+ if ((spec->ema_actions & (1U << EFX_MAE_ACTION_COUNT)) == 0) {
+ /*
+ * Invalid to add counter ID if spec does not have COUNT action.
+ */
+ rc = EINVAL;
+ goto fail1;
+ }
+
+ if (spec->ema_n_count_actions != 1) {
+ /*
+ * Having multiple COUNT actions in the spec requires a counter
+ * list to be used. This API must only be used for a single
+ * counter per spec. Turn down the request as inappropriate.
+ */
+ rc = EINVAL;
+ goto fail2;
+ }
+
+ if (spec->ema_rsrc.emar_counter_id.id != EFX_MAE_RSRC_ID_INVALID) {
+ /* The caller attempts to indicate counter ID twice. */
+ rc = EALREADY;
+ goto fail3;
+ }
+
+ if (counter_idp->id == EFX_MAE_RSRC_ID_INVALID) {
+ rc = EINVAL;
+ goto fail4;
+ }
+
+ spec->ema_rsrc.emar_counter_id.id = counter_idp->id;
+
+ 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_counters_alloc(
+ __in efx_nic_t *enp,
+ __in uint32_t n_counters,
+ __out uint32_t *n_allocatedp,
+ __out_ecount(n_counters) efx_counter_t *countersp,
+ __out_opt uint32_t *gen_countp)
+{
+ EFX_MCDI_DECLARE_BUF(payload,
+ MC_CMD_MAE_COUNTER_ALLOC_IN_LEN,
+ MC_CMD_MAE_COUNTER_ALLOC_OUT_LENMAX_MCDI2);
+ efx_mae_t *maep = enp->en_maep;
+ uint32_t n_allocated;
+ efx_mcdi_req_t req;
+ unsigned int i;
+ efx_rc_t rc;
+
+ if (n_counters > maep->em_max_ncounters ||
+ n_counters < MC_CMD_MAE_COUNTER_ALLOC_OUT_COUNTER_ID_MINNUM ||
+ n_counters > MC_CMD_MAE_COUNTER_ALLOC_OUT_COUNTER_ID_MAXNUM_MCDI2) {
+ rc = EINVAL;
+ goto fail1;
+ }
+
+ req.emr_cmd = MC_CMD_MAE_COUNTER_ALLOC;
+ req.emr_in_buf = payload;
+ req.emr_in_length = MC_CMD_MAE_COUNTER_ALLOC_IN_LEN;
+ req.emr_out_buf = payload;
+ req.emr_out_length = MC_CMD_MAE_COUNTER_ALLOC_OUT_LEN(n_counters);
+
+ MCDI_IN_SET_DWORD(req, MAE_COUNTER_ALLOC_IN_REQUESTED_COUNT,
+ n_counters);
+
+ 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_COUNTER_ALLOC_OUT_LENMIN) {
+ rc = EMSGSIZE;
+ goto fail3;
+ }
+
+ n_allocated = MCDI_OUT_DWORD(req,
+ MAE_COUNTER_ALLOC_OUT_COUNTER_ID_COUNT);
+ if (n_allocated < MC_CMD_MAE_COUNTER_ALLOC_OUT_COUNTER_ID_MINNUM) {
+ rc = EFAULT;
+ goto fail4;
+ }
+
+ for (i = 0; i < n_allocated; i++) {
+ countersp[i].id = MCDI_OUT_INDEXED_DWORD(req,
+ MAE_COUNTER_ALLOC_OUT_COUNTER_ID, i);
+ }
+
+ if (gen_countp != NULL) {
+ *gen_countp = MCDI_OUT_DWORD(req,
+ MAE_COUNTER_ALLOC_OUT_GENERATION_COUNT);
+ }
+
+ *n_allocatedp = n_allocated;
+
+ 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_counters_free(
+ __in efx_nic_t *enp,
+ __in uint32_t n_counters,
+ __out uint32_t *n_freedp,
+ __in_ecount(n_counters) const efx_counter_t *countersp,
+ __out_opt uint32_t *gen_countp)
+{
+ EFX_MCDI_DECLARE_BUF(payload,
+ MC_CMD_MAE_COUNTER_FREE_IN_LENMAX_MCDI2,
+ MC_CMD_MAE_COUNTER_FREE_OUT_LENMAX_MCDI2);
+ efx_mae_t *maep = enp->en_maep;
+ efx_mcdi_req_t req;
+ uint32_t n_freed;
+ unsigned int i;
+ efx_rc_t rc;
+
+ if (n_counters > maep->em_max_ncounters ||
+ n_counters < MC_CMD_MAE_COUNTER_FREE_IN_FREE_COUNTER_ID_MINNUM ||
+ n_counters >
+ MC_CMD_MAE_COUNTER_FREE_IN_FREE_COUNTER_ID_MAXNUM_MCDI2) {
+ rc = EINVAL;
+ goto fail1;
+ }
+
+ req.emr_cmd = MC_CMD_MAE_COUNTER_FREE;
+ req.emr_in_buf = payload;
+ req.emr_in_length = MC_CMD_MAE_COUNTER_FREE_IN_LEN(n_counters);
+ req.emr_out_buf = payload;
+ req.emr_out_length = MC_CMD_MAE_COUNTER_FREE_OUT_LEN(n_counters);
+
+ for (i = 0; i < n_counters; i++) {
+ MCDI_IN_SET_INDEXED_DWORD(req,
+ MAE_COUNTER_FREE_IN_FREE_COUNTER_ID, i, countersp[i].id);
+ }
+ MCDI_IN_SET_DWORD(req, MAE_COUNTER_FREE_IN_COUNTER_ID_COUNT,
+ n_counters);
+
+ 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_COUNTER_FREE_OUT_LENMIN) {
+ rc = EMSGSIZE;
+ goto fail3;
+ }
+
+ n_freed = MCDI_OUT_DWORD(req, MAE_COUNTER_FREE_OUT_COUNTER_ID_COUNT);
+
+ if (n_freed < MC_CMD_MAE_COUNTER_FREE_OUT_FREED_COUNTER_ID_MINNUM) {
+ rc = EFAULT;
+ goto fail4;
+ }
+
+ if (gen_countp != NULL) {
+ *gen_countp = MCDI_OUT_DWORD(req,
+ MAE_COUNTER_FREE_OUT_GENERATION_COUNT);
+ }
+
+ *n_freedp = n_freed;
+
+ 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_counters_stream_start(
+ __in efx_nic_t *enp,
+ __in uint16_t rxq_id,
+ __in uint16_t packet_size,
+ __in uint32_t flags_in,
+ __out uint32_t *flags_out)
+{
+ efx_mcdi_req_t req;
+ EFX_MCDI_DECLARE_BUF(payload, MC_CMD_MAE_COUNTERS_STREAM_START_IN_LEN,
+ MC_CMD_MAE_COUNTERS_STREAM_START_OUT_LEN);
+ efx_rc_t rc;
+
+ EFX_STATIC_ASSERT(EFX_MAE_COUNTERS_STREAM_IN_ZERO_SQUASH_DISABLE ==
+ 1U << MC_CMD_MAE_COUNTERS_STREAM_START_IN_ZERO_SQUASH_DISABLE_LBN);
+
+ EFX_STATIC_ASSERT(EFX_MAE_COUNTERS_STREAM_OUT_USES_CREDITS ==
+ 1U << MC_CMD_MAE_COUNTERS_STREAM_START_OUT_USES_CREDITS_LBN);
+
+ req.emr_cmd = MC_CMD_MAE_COUNTERS_STREAM_START;
+ req.emr_in_buf = payload;
+ req.emr_in_length = MC_CMD_MAE_COUNTERS_STREAM_START_IN_LEN;
+ req.emr_out_buf = payload;
+ req.emr_out_length = MC_CMD_MAE_COUNTERS_STREAM_START_OUT_LEN;
+
+ MCDI_IN_SET_WORD(req, MAE_COUNTERS_STREAM_START_IN_QID, rxq_id);
+ MCDI_IN_SET_WORD(req, MAE_COUNTERS_STREAM_START_IN_PACKET_SIZE,
+ packet_size);
+ MCDI_IN_SET_DWORD(req, MAE_COUNTERS_STREAM_START_IN_FLAGS, flags_in);
+
+ efx_mcdi_execute(enp, &req);
+
+ if (req.emr_rc != 0) {
+ rc = req.emr_rc;
+ goto fail1;
+ }
+
+ if (req.emr_out_length_used <
+ MC_CMD_MAE_COUNTERS_STREAM_START_OUT_LEN) {
+ rc = EMSGSIZE;
+ goto fail2;
+ }
+
+ *flags_out = MCDI_OUT_DWORD(req, MAE_COUNTERS_STREAM_START_OUT_FLAGS);
+
+ return (0);
+
+fail2:
+ EFSYS_PROBE(fail2);
+fail1:
+ EFSYS_PROBE1(fail1, efx_rc_t, rc);
+
+ return (rc);
+}
+
+ __checkReturn efx_rc_t
+efx_mae_counters_stream_stop(
+ __in efx_nic_t *enp,
+ __in uint16_t rxq_id,
+ __out_opt uint32_t *gen_countp)
+{
+ efx_mcdi_req_t req;
+ EFX_MCDI_DECLARE_BUF(payload, MC_CMD_MAE_COUNTERS_STREAM_STOP_IN_LEN,
+ MC_CMD_MAE_COUNTERS_STREAM_STOP_OUT_LEN);
+ efx_rc_t rc;
+
+ req.emr_cmd = MC_CMD_MAE_COUNTERS_STREAM_STOP;
+ req.emr_in_buf = payload;
+ req.emr_in_length = MC_CMD_MAE_COUNTERS_STREAM_STOP_IN_LEN;
+ req.emr_out_buf = payload;
+ req.emr_out_length = MC_CMD_MAE_COUNTERS_STREAM_STOP_OUT_LEN;
+
+ MCDI_IN_SET_WORD(req, MAE_COUNTERS_STREAM_STOP_IN_QID, rxq_id);
+
+ efx_mcdi_execute(enp, &req);
+
+ if (req.emr_rc != 0) {
+ rc = req.emr_rc;
+ goto fail1;
+ }
+
+ if (req.emr_out_length_used <
+ MC_CMD_MAE_COUNTERS_STREAM_STOP_OUT_LEN) {
+ rc = EMSGSIZE;
+ goto fail2;
+ }
+
+ if (gen_countp != NULL) {
+ *gen_countp = MCDI_OUT_DWORD(req,
+ MAE_COUNTERS_STREAM_STOP_OUT_GENERATION_COUNT);
+ }
+
+ return (0);
+
+fail2:
+ EFSYS_PROBE(fail2);
+fail1:
+ EFSYS_PROBE1(fail1, efx_rc_t, rc);
+
+ return (rc);
+}
+
+ __checkReturn efx_rc_t
+efx_mae_counters_stream_give_credits(
+ __in efx_nic_t *enp,
+ __in uint32_t n_credits)
+{
+ efx_mcdi_req_t req;
+ EFX_MCDI_DECLARE_BUF(payload,
+ MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS_IN_LEN,
+ MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS_OUT_LEN);
+ efx_rc_t rc;
+
+ req.emr_cmd = MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS;
+ req.emr_in_buf = payload;
+ req.emr_in_length = MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS_IN_LEN;
+ req.emr_out_buf = payload;
+ req.emr_out_length = MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS_OUT_LEN;
+
+ MCDI_IN_SET_DWORD(req, MAE_COUNTERS_STREAM_GIVE_CREDITS_IN_NUM_CREDITS,
+ n_credits);
+
+ efx_mcdi_execute(enp, &req);
+
+ if (req.emr_rc != 0) {
+ rc = req.emr_rc;
+ goto fail1;
+ }
+
+ return (0);
+
+fail1:
+ EFSYS_PROBE1(fail1, efx_rc_t, rc);
+
+ return (rc);
+}
+
+ __checkReturn efx_rc_t
+efx_mae_action_set_free(
+ __in efx_nic_t *enp,
+ __in const efx_mae_aset_id_t *aset_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_ACTION_SET_FREE_IN_LEN(1),
+ MC_CMD_MAE_ACTION_SET_FREE_OUT_LEN(1));
+ efx_rc_t rc;
+
+ if (encp->enc_mae_supported == B_FALSE) {
+ rc = ENOTSUP;
+ goto fail1;
+ }
+
+ req.emr_cmd = MC_CMD_MAE_ACTION_SET_FREE;
+ req.emr_in_buf = payload;
+ req.emr_in_length = MC_CMD_MAE_ACTION_SET_FREE_IN_LEN(1);