Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /****************************************************************************
0003  * Driver for Solarflare network controllers and boards
0004  * Copyright 2019 Solarflare Communications Inc.
0005  * Copyright 2020-2022 Xilinx Inc.
0006  *
0007  * This program is free software; you can redistribute it and/or modify it
0008  * under the terms of the GNU General Public License version 2 as published
0009  * by the Free Software Foundation, incorporated herein by reference.
0010  */
0011 
0012 #include "mae.h"
0013 #include "mcdi.h"
0014 #include "mcdi_pcol_mae.h"
0015 
0016 int efx_mae_allocate_mport(struct efx_nic *efx, u32 *id, u32 *label)
0017 {
0018     MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_MPORT_ALLOC_ALIAS_OUT_LEN);
0019     MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_MPORT_ALLOC_ALIAS_IN_LEN);
0020     size_t outlen;
0021     int rc;
0022 
0023     if (WARN_ON_ONCE(!id))
0024         return -EINVAL;
0025     if (WARN_ON_ONCE(!label))
0026         return -EINVAL;
0027 
0028     MCDI_SET_DWORD(inbuf, MAE_MPORT_ALLOC_ALIAS_IN_TYPE,
0029                MC_CMD_MAE_MPORT_ALLOC_ALIAS_IN_MPORT_TYPE_ALIAS);
0030     MCDI_SET_DWORD(inbuf, MAE_MPORT_ALLOC_ALIAS_IN_DELIVER_MPORT,
0031                MAE_MPORT_SELECTOR_ASSIGNED);
0032     rc = efx_mcdi_rpc(efx, MC_CMD_MAE_MPORT_ALLOC, inbuf, sizeof(inbuf),
0033               outbuf, sizeof(outbuf), &outlen);
0034     if (rc)
0035         return rc;
0036     if (outlen < sizeof(outbuf))
0037         return -EIO;
0038     *id = MCDI_DWORD(outbuf, MAE_MPORT_ALLOC_ALIAS_OUT_MPORT_ID);
0039     *label = MCDI_DWORD(outbuf, MAE_MPORT_ALLOC_ALIAS_OUT_LABEL);
0040     return 0;
0041 }
0042 
0043 int efx_mae_free_mport(struct efx_nic *efx, u32 id)
0044 {
0045     MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_MPORT_FREE_IN_LEN);
0046 
0047     BUILD_BUG_ON(MC_CMD_MAE_MPORT_FREE_OUT_LEN);
0048     MCDI_SET_DWORD(inbuf, MAE_MPORT_FREE_IN_MPORT_ID, id);
0049     return efx_mcdi_rpc(efx, MC_CMD_MAE_MPORT_FREE, inbuf, sizeof(inbuf),
0050                 NULL, 0, NULL);
0051 }
0052 
0053 void efx_mae_mport_wire(struct efx_nic *efx, u32 *out)
0054 {
0055     efx_dword_t mport;
0056 
0057     EFX_POPULATE_DWORD_2(mport,
0058                  MAE_MPORT_SELECTOR_TYPE, MAE_MPORT_SELECTOR_TYPE_PPORT,
0059                  MAE_MPORT_SELECTOR_PPORT_ID, efx->port_num);
0060     *out = EFX_DWORD_VAL(mport);
0061 }
0062 
0063 void efx_mae_mport_uplink(struct efx_nic *efx __always_unused, u32 *out)
0064 {
0065     efx_dword_t mport;
0066 
0067     EFX_POPULATE_DWORD_3(mport,
0068                  MAE_MPORT_SELECTOR_TYPE, MAE_MPORT_SELECTOR_TYPE_FUNC,
0069                  MAE_MPORT_SELECTOR_FUNC_PF_ID, MAE_MPORT_SELECTOR_FUNC_PF_ID_CALLER,
0070                  MAE_MPORT_SELECTOR_FUNC_VF_ID, MAE_MPORT_SELECTOR_FUNC_VF_ID_NULL);
0071     *out = EFX_DWORD_VAL(mport);
0072 }
0073 
0074 void efx_mae_mport_vf(struct efx_nic *efx __always_unused, u32 vf_id, u32 *out)
0075 {
0076     efx_dword_t mport;
0077 
0078     EFX_POPULATE_DWORD_3(mport,
0079                  MAE_MPORT_SELECTOR_TYPE, MAE_MPORT_SELECTOR_TYPE_FUNC,
0080                  MAE_MPORT_SELECTOR_FUNC_PF_ID, MAE_MPORT_SELECTOR_FUNC_PF_ID_CALLER,
0081                  MAE_MPORT_SELECTOR_FUNC_VF_ID, vf_id);
0082     *out = EFX_DWORD_VAL(mport);
0083 }
0084 
0085 /* Constructs an mport selector from an mport ID, because they're not the same */
0086 void efx_mae_mport_mport(struct efx_nic *efx __always_unused, u32 mport_id, u32 *out)
0087 {
0088     efx_dword_t mport;
0089 
0090     EFX_POPULATE_DWORD_2(mport,
0091                  MAE_MPORT_SELECTOR_TYPE, MAE_MPORT_SELECTOR_TYPE_MPORT_ID,
0092                  MAE_MPORT_SELECTOR_MPORT_ID, mport_id);
0093     *out = EFX_DWORD_VAL(mport);
0094 }
0095 
0096 /* id is really only 24 bits wide */
0097 int efx_mae_lookup_mport(struct efx_nic *efx, u32 selector, u32 *id)
0098 {
0099     MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_MPORT_LOOKUP_OUT_LEN);
0100     MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_MPORT_LOOKUP_IN_LEN);
0101     size_t outlen;
0102     int rc;
0103 
0104     MCDI_SET_DWORD(inbuf, MAE_MPORT_LOOKUP_IN_MPORT_SELECTOR, selector);
0105     rc = efx_mcdi_rpc(efx, MC_CMD_MAE_MPORT_LOOKUP, inbuf, sizeof(inbuf),
0106               outbuf, sizeof(outbuf), &outlen);
0107     if (rc)
0108         return rc;
0109     if (outlen < sizeof(outbuf))
0110         return -EIO;
0111     *id = MCDI_DWORD(outbuf, MAE_MPORT_LOOKUP_OUT_MPORT_ID);
0112     return 0;
0113 }
0114 
0115 static bool efx_mae_asl_id(u32 id)
0116 {
0117     return !!(id & BIT(31));
0118 }
0119 
0120 int efx_mae_alloc_action_set(struct efx_nic *efx, struct efx_tc_action_set *act)
0121 {
0122     MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN);
0123     MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_ACTION_SET_ALLOC_IN_LEN);
0124     size_t outlen;
0125     int rc;
0126 
0127     MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_SRC_MAC_ID,
0128                MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL);
0129     MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_DST_MAC_ID,
0130                MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL);
0131     MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_COUNTER_ID,
0132                MC_CMD_MAE_COUNTER_ALLOC_OUT_COUNTER_ID_NULL);
0133     MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_COUNTER_LIST_ID,
0134                MC_CMD_MAE_COUNTER_LIST_ALLOC_OUT_COUNTER_LIST_ID_NULL);
0135     MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_ENCAP_HEADER_ID,
0136                MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID_NULL);
0137     if (act->deliver)
0138         MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_DELIVER,
0139                    act->dest_mport);
0140     BUILD_BUG_ON(MAE_MPORT_SELECTOR_NULL);
0141     rc = efx_mcdi_rpc(efx, MC_CMD_MAE_ACTION_SET_ALLOC, inbuf, sizeof(inbuf),
0142               outbuf, sizeof(outbuf), &outlen);
0143     if (rc)
0144         return rc;
0145     if (outlen < sizeof(outbuf))
0146         return -EIO;
0147     act->fw_id = MCDI_DWORD(outbuf, MAE_ACTION_SET_ALLOC_OUT_AS_ID);
0148     /* We rely on the high bit of AS IDs always being clear.
0149      * The firmware API guarantees this, but let's check it ourselves.
0150      */
0151     if (WARN_ON_ONCE(efx_mae_asl_id(act->fw_id))) {
0152         efx_mae_free_action_set(efx, act->fw_id);
0153         return -EIO;
0154     }
0155     return 0;
0156 }
0157 
0158 int efx_mae_free_action_set(struct efx_nic *efx, u32 fw_id)
0159 {
0160     MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ACTION_SET_FREE_OUT_LEN(1));
0161     MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_ACTION_SET_FREE_IN_LEN(1));
0162     size_t outlen;
0163     int rc;
0164 
0165     MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_FREE_IN_AS_ID, fw_id);
0166     rc = efx_mcdi_rpc(efx, MC_CMD_MAE_ACTION_SET_FREE, inbuf, sizeof(inbuf),
0167               outbuf, sizeof(outbuf), &outlen);
0168     if (rc)
0169         return rc;
0170     if (outlen < sizeof(outbuf))
0171         return -EIO;
0172     /* FW freed a different ID than we asked for, should never happen.
0173      * Warn because it means we've now got a different idea to the FW of
0174      * what action-sets exist, which could cause mayhem later.
0175      */
0176     if (WARN_ON(MCDI_DWORD(outbuf, MAE_ACTION_SET_FREE_OUT_FREED_AS_ID) != fw_id))
0177         return -EIO;
0178     return 0;
0179 }
0180 
0181 int efx_mae_alloc_action_set_list(struct efx_nic *efx,
0182                   struct efx_tc_action_set_list *acts)
0183 {
0184     MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ACTION_SET_LIST_ALLOC_OUT_LEN);
0185     struct efx_tc_action_set *act;
0186     size_t inlen, outlen, i = 0;
0187     efx_dword_t *inbuf;
0188     int rc;
0189 
0190     list_for_each_entry(act, &acts->list, list)
0191         i++;
0192     if (i == 0)
0193         return -EINVAL;
0194     if (i == 1) {
0195         /* Don't wrap an ASL around a single AS, just use the AS_ID
0196          * directly.  ASLs are a more limited resource.
0197          */
0198         act = list_first_entry(&acts->list, struct efx_tc_action_set, list);
0199         acts->fw_id = act->fw_id;
0200         return 0;
0201     }
0202     if (i > MC_CMD_MAE_ACTION_SET_LIST_ALLOC_IN_AS_IDS_MAXNUM_MCDI2)
0203         return -EOPNOTSUPP; /* Too many actions */
0204     inlen = MC_CMD_MAE_ACTION_SET_LIST_ALLOC_IN_LEN(i);
0205     inbuf = kzalloc(inlen, GFP_KERNEL);
0206     if (!inbuf)
0207         return -ENOMEM;
0208     i = 0;
0209     list_for_each_entry(act, &acts->list, list) {
0210         MCDI_SET_ARRAY_DWORD(inbuf, MAE_ACTION_SET_LIST_ALLOC_IN_AS_IDS,
0211                      i, act->fw_id);
0212         i++;
0213     }
0214     MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_LIST_ALLOC_IN_COUNT, i);
0215     rc = efx_mcdi_rpc(efx, MC_CMD_MAE_ACTION_SET_LIST_ALLOC, inbuf, inlen,
0216               outbuf, sizeof(outbuf), &outlen);
0217     if (rc)
0218         goto out_free;
0219     if (outlen < sizeof(outbuf)) {
0220         rc = -EIO;
0221         goto out_free;
0222     }
0223     acts->fw_id = MCDI_DWORD(outbuf, MAE_ACTION_SET_LIST_ALLOC_OUT_ASL_ID);
0224     /* We rely on the high bit of ASL IDs always being set.
0225      * The firmware API guarantees this, but let's check it ourselves.
0226      */
0227     if (WARN_ON_ONCE(!efx_mae_asl_id(acts->fw_id))) {
0228         efx_mae_free_action_set_list(efx, acts);
0229         rc = -EIO;
0230     }
0231 out_free:
0232     kfree(inbuf);
0233     return rc;
0234 }
0235 
0236 int efx_mae_free_action_set_list(struct efx_nic *efx,
0237                  struct efx_tc_action_set_list *acts)
0238 {
0239     MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ACTION_SET_LIST_FREE_OUT_LEN(1));
0240     MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_ACTION_SET_LIST_FREE_IN_LEN(1));
0241     size_t outlen;
0242     int rc;
0243 
0244     /* If this is just an AS_ID with no ASL wrapper, then there is
0245      * nothing for us to free.  (The AS will be freed later.)
0246      */
0247     if (efx_mae_asl_id(acts->fw_id)) {
0248         MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_LIST_FREE_IN_ASL_ID,
0249                    acts->fw_id);
0250         rc = efx_mcdi_rpc(efx, MC_CMD_MAE_ACTION_SET_LIST_FREE, inbuf,
0251                   sizeof(inbuf), outbuf, sizeof(outbuf), &outlen);
0252         if (rc)
0253             return rc;
0254         if (outlen < sizeof(outbuf))
0255             return -EIO;
0256         /* FW freed a different ID than we asked for, should never happen.
0257          * Warn because it means we've now got a different idea to the FW of
0258          * what action-set-lists exist, which could cause mayhem later.
0259          */
0260         if (WARN_ON(MCDI_DWORD(outbuf, MAE_ACTION_SET_LIST_FREE_OUT_FREED_ASL_ID) != acts->fw_id))
0261             return -EIO;
0262     }
0263     /* We're probably about to free @acts, but let's just make sure its
0264      * fw_id is blatted so that it won't look valid if it leaks out.
0265      */
0266     acts->fw_id = MC_CMD_MAE_ACTION_SET_LIST_ALLOC_OUT_ACTION_SET_LIST_ID_NULL;
0267     return 0;
0268 }
0269 
0270 static int efx_mae_populate_match_criteria(MCDI_DECLARE_STRUCT_PTR(match_crit),
0271                        const struct efx_tc_match *match)
0272 {
0273     if (match->mask.ingress_port) {
0274         if (~match->mask.ingress_port)
0275             return -EOPNOTSUPP;
0276         MCDI_STRUCT_SET_DWORD(match_crit,
0277                       MAE_FIELD_MASK_VALUE_PAIRS_V2_INGRESS_MPORT_SELECTOR,
0278                       match->value.ingress_port);
0279     }
0280     MCDI_STRUCT_SET_DWORD(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_INGRESS_MPORT_SELECTOR_MASK,
0281                   match->mask.ingress_port);
0282     return 0;
0283 }
0284 
0285 int efx_mae_insert_rule(struct efx_nic *efx, const struct efx_tc_match *match,
0286             u32 prio, u32 acts_id, u32 *id)
0287 {
0288     MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_ACTION_RULE_INSERT_IN_LEN(MAE_FIELD_MASK_VALUE_PAIRS_V2_LEN));
0289     MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN);
0290     MCDI_DECLARE_STRUCT_PTR(match_crit);
0291     MCDI_DECLARE_STRUCT_PTR(response);
0292     size_t outlen;
0293     int rc;
0294 
0295     if (!id)
0296         return -EINVAL;
0297 
0298     match_crit = _MCDI_DWORD(inbuf, MAE_ACTION_RULE_INSERT_IN_MATCH_CRITERIA);
0299     response = _MCDI_DWORD(inbuf, MAE_ACTION_RULE_INSERT_IN_RESPONSE);
0300     if (efx_mae_asl_id(acts_id)) {
0301         MCDI_STRUCT_SET_DWORD(response, MAE_ACTION_RULE_RESPONSE_ASL_ID, acts_id);
0302         MCDI_STRUCT_SET_DWORD(response, MAE_ACTION_RULE_RESPONSE_AS_ID,
0303                       MC_CMD_MAE_ACTION_SET_ALLOC_OUT_ACTION_SET_ID_NULL);
0304     } else {
0305         /* We only had one AS, so we didn't wrap it in an ASL */
0306         MCDI_STRUCT_SET_DWORD(response, MAE_ACTION_RULE_RESPONSE_ASL_ID,
0307                       MC_CMD_MAE_ACTION_SET_LIST_ALLOC_OUT_ACTION_SET_LIST_ID_NULL);
0308         MCDI_STRUCT_SET_DWORD(response, MAE_ACTION_RULE_RESPONSE_AS_ID, acts_id);
0309     }
0310     MCDI_SET_DWORD(inbuf, MAE_ACTION_RULE_INSERT_IN_PRIO, prio);
0311     rc = efx_mae_populate_match_criteria(match_crit, match);
0312     if (rc)
0313         return rc;
0314 
0315     rc = efx_mcdi_rpc(efx, MC_CMD_MAE_ACTION_RULE_INSERT, inbuf, sizeof(inbuf),
0316               outbuf, sizeof(outbuf), &outlen);
0317     if (rc)
0318         return rc;
0319     if (outlen < sizeof(outbuf))
0320         return -EIO;
0321     *id = MCDI_DWORD(outbuf, MAE_ACTION_RULE_INSERT_OUT_AR_ID);
0322     return 0;
0323 }
0324 
0325 int efx_mae_delete_rule(struct efx_nic *efx, u32 id)
0326 {
0327     MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ACTION_RULE_DELETE_OUT_LEN(1));
0328     MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_ACTION_RULE_DELETE_IN_LEN(1));
0329     size_t outlen;
0330     int rc;
0331 
0332     MCDI_SET_DWORD(inbuf, MAE_ACTION_RULE_DELETE_IN_AR_ID, id);
0333     rc = efx_mcdi_rpc(efx, MC_CMD_MAE_ACTION_RULE_DELETE, inbuf, sizeof(inbuf),
0334               outbuf, sizeof(outbuf), &outlen);
0335     if (rc)
0336         return rc;
0337     if (outlen < sizeof(outbuf))
0338         return -EIO;
0339     /* FW freed a different ID than we asked for, should also never happen.
0340      * Warn because it means we've now got a different idea to the FW of
0341      * what rules exist, which could cause mayhem later.
0342      */
0343     if (WARN_ON(MCDI_DWORD(outbuf, MAE_ACTION_RULE_DELETE_OUT_DELETED_AR_ID) != id))
0344         return -EIO;
0345     return 0;
0346 }