sfc: interrogate MAE capabilities at probe time
Different versions of EF100 firmware and FPGA bitstreams support different matching capabilities in the Match-Action Engine. Probe for these at start of day; subsequent patches will validate TC offload requests against the reported capabilities. Signed-off-by: Edward Cree <ecree.xilinx@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
committed by
David S. Miller
parent
f54a28a211
commit
7ce3e235f2
@@ -112,6 +112,62 @@ int efx_mae_lookup_mport(struct efx_nic *efx, u32 selector, u32 *id)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int efx_mae_get_basic_caps(struct efx_nic *efx, struct mae_caps *caps)
|
||||
{
|
||||
MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_GET_CAPS_OUT_LEN);
|
||||
size_t outlen;
|
||||
int rc;
|
||||
|
||||
BUILD_BUG_ON(MC_CMD_MAE_GET_CAPS_IN_LEN);
|
||||
|
||||
rc = efx_mcdi_rpc(efx, MC_CMD_MAE_GET_CAPS, NULL, 0, outbuf,
|
||||
sizeof(outbuf), &outlen);
|
||||
if (rc)
|
||||
return rc;
|
||||
if (outlen < sizeof(outbuf))
|
||||
return -EIO;
|
||||
caps->match_field_count = MCDI_DWORD(outbuf, MAE_GET_CAPS_OUT_MATCH_FIELD_COUNT);
|
||||
caps->action_prios = MCDI_DWORD(outbuf, MAE_GET_CAPS_OUT_ACTION_PRIOS);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int efx_mae_get_rule_fields(struct efx_nic *efx, u32 cmd,
|
||||
u8 *field_support)
|
||||
{
|
||||
MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_GET_AR_CAPS_OUT_LEN(MAE_NUM_FIELDS));
|
||||
MCDI_DECLARE_STRUCT_PTR(caps);
|
||||
unsigned int count;
|
||||
size_t outlen;
|
||||
int rc, i;
|
||||
|
||||
BUILD_BUG_ON(MC_CMD_MAE_GET_AR_CAPS_IN_LEN);
|
||||
|
||||
rc = efx_mcdi_rpc(efx, cmd, NULL, 0, outbuf, sizeof(outbuf), &outlen);
|
||||
if (rc)
|
||||
return rc;
|
||||
count = MCDI_DWORD(outbuf, MAE_GET_AR_CAPS_OUT_COUNT);
|
||||
memset(field_support, MAE_FIELD_UNSUPPORTED, MAE_NUM_FIELDS);
|
||||
caps = _MCDI_DWORD(outbuf, MAE_GET_AR_CAPS_OUT_FIELD_FLAGS);
|
||||
/* We're only interested in the support status enum, not any other
|
||||
* flags, so just extract that from each entry.
|
||||
*/
|
||||
for (i = 0; i < count; i++)
|
||||
if (i * sizeof(*outbuf) + MC_CMD_MAE_GET_AR_CAPS_OUT_FIELD_FLAGS_OFST < outlen)
|
||||
field_support[i] = EFX_DWORD_FIELD(caps[i], MAE_FIELD_FLAGS_SUPPORT_STATUS);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int efx_mae_get_caps(struct efx_nic *efx, struct mae_caps *caps)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = efx_mae_get_basic_caps(efx, caps);
|
||||
if (rc)
|
||||
return rc;
|
||||
return efx_mae_get_rule_fields(efx, MC_CMD_MAE_GET_AR_CAPS,
|
||||
caps->action_rule_fields);
|
||||
}
|
||||
|
||||
static bool efx_mae_asl_id(u32 id)
|
||||
{
|
||||
return !!(id & BIT(31));
|
||||
|
||||
@@ -27,6 +27,16 @@ void efx_mae_mport_mport(struct efx_nic *efx, u32 mport_id, u32 *out);
|
||||
|
||||
int efx_mae_lookup_mport(struct efx_nic *efx, u32 selector, u32 *id);
|
||||
|
||||
#define MAE_NUM_FIELDS (MAE_FIELD_ENC_VNET_ID + 1)
|
||||
|
||||
struct mae_caps {
|
||||
u32 match_field_count;
|
||||
u32 action_prios;
|
||||
u8 action_rule_fields[MAE_NUM_FIELDS];
|
||||
};
|
||||
|
||||
int efx_mae_get_caps(struct efx_nic *efx, struct mae_caps *caps);
|
||||
|
||||
int efx_mae_alloc_action_set(struct efx_nic *efx, struct efx_tc_action_set *act);
|
||||
int efx_mae_free_action_set(struct efx_nic *efx, u32 fw_id);
|
||||
|
||||
|
||||
@@ -305,6 +305,23 @@ int efx_init_tc(struct efx_nic *efx)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = efx_mae_get_caps(efx, efx->tc->caps);
|
||||
if (rc)
|
||||
return rc;
|
||||
if (efx->tc->caps->match_field_count > MAE_NUM_FIELDS)
|
||||
/* Firmware supports some match fields the driver doesn't know
|
||||
* about. Not fatal, unless any of those fields are required
|
||||
* (MAE_FIELD_SUPPORTED_MATCH_ALWAYS) but if so we don't know.
|
||||
*/
|
||||
netif_warn(efx, probe, efx->net_dev,
|
||||
"FW reports additional match fields %u\n",
|
||||
efx->tc->caps->match_field_count);
|
||||
if (efx->tc->caps->action_prios < EFX_TC_PRIO__NUM) {
|
||||
netif_err(efx, probe, efx->net_dev,
|
||||
"Too few action prios supported (have %u, need %u)\n",
|
||||
efx->tc->caps->action_prios, EFX_TC_PRIO__NUM);
|
||||
return -EIO;
|
||||
}
|
||||
rc = efx_tc_configure_default_rule_pf(efx);
|
||||
if (rc)
|
||||
return rc;
|
||||
@@ -344,6 +361,11 @@ int efx_init_struct_tc(struct efx_nic *efx)
|
||||
efx->tc = kzalloc(sizeof(*efx->tc), GFP_KERNEL);
|
||||
if (!efx->tc)
|
||||
return -ENOMEM;
|
||||
efx->tc->caps = kzalloc(sizeof(struct mae_caps), GFP_KERNEL);
|
||||
if (!efx->tc->caps) {
|
||||
rc = -ENOMEM;
|
||||
goto fail_alloc_caps;
|
||||
}
|
||||
INIT_LIST_HEAD(&efx->tc->block_list);
|
||||
|
||||
mutex_init(&efx->tc->mutex);
|
||||
@@ -359,6 +381,8 @@ int efx_init_struct_tc(struct efx_nic *efx)
|
||||
return 0;
|
||||
fail_match_action_ht:
|
||||
mutex_destroy(&efx->tc->mutex);
|
||||
kfree(efx->tc->caps);
|
||||
fail_alloc_caps:
|
||||
kfree(efx->tc);
|
||||
efx->tc = NULL;
|
||||
return rc;
|
||||
@@ -378,6 +402,7 @@ void efx_fini_struct_tc(struct efx_nic *efx)
|
||||
efx);
|
||||
mutex_unlock(&efx->tc->mutex);
|
||||
mutex_destroy(&efx->tc->mutex);
|
||||
kfree(efx->tc->caps);
|
||||
kfree(efx->tc);
|
||||
efx->tc = NULL;
|
||||
}
|
||||
|
||||
@@ -71,6 +71,7 @@ enum efx_tc_rule_prios {
|
||||
/**
|
||||
* struct efx_tc_state - control plane data for TC offload
|
||||
*
|
||||
* @caps: MAE capabilities reported by MCDI
|
||||
* @block_list: List of &struct efx_tc_block_binding
|
||||
* @mutex: Used to serialise operations on TC hashtables
|
||||
* @match_action_ht: Hashtable of TC match-action rules
|
||||
@@ -85,6 +86,7 @@ enum efx_tc_rule_prios {
|
||||
* @up: have TC datastructures been set up?
|
||||
*/
|
||||
struct efx_tc_state {
|
||||
struct mae_caps *caps;
|
||||
struct list_head block_list;
|
||||
struct mutex mutex;
|
||||
struct rhashtable match_action_ht;
|
||||
|
||||
Reference in New Issue
Block a user