Commit 439c4be9 authored by Pieter Jansen van Vuuren's avatar Pieter Jansen van Vuuren Committed by David S. Miller

sfc: introduce ethernet pedit set action infrastructure

Introduce the initial ethernet pedit set action infrastructure in
preparation for adding mac src and dst pedit action offloads.
Co-developed-by: default avatarEdward Cree <ecree.xilinx@gmail.com>
Signed-off-by: default avatarEdward Cree <ecree.xilinx@gmail.com>
Signed-off-by: default avatarPieter Jansen van Vuuren <pieter.jansen-van-vuuren@amd.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent b32add2d
...@@ -1219,6 +1219,71 @@ int efx_mae_enumerate_mports(struct efx_nic *efx) ...@@ -1219,6 +1219,71 @@ int efx_mae_enumerate_mports(struct efx_nic *efx)
return rc; return rc;
} }
/**
* efx_mae_allocate_pedit_mac() - allocate pedit MAC address in HW.
* @efx: NIC we're installing a pedit MAC address on
* @ped: pedit MAC action to be installed
*
* Attempts to install @ped in HW and populates its id with an index of this
* entry in the firmware MAC address table on success.
*
* Return: negative value on error, 0 in success.
*/
int efx_mae_allocate_pedit_mac(struct efx_nic *efx,
struct efx_tc_mac_pedit_action *ped)
{
MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_LEN);
MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_MAC_ADDR_ALLOC_IN_LEN);
size_t outlen;
int rc;
BUILD_BUG_ON(MC_CMD_MAE_MAC_ADDR_ALLOC_IN_MAC_ADDR_LEN !=
sizeof(ped->h_addr));
memcpy(MCDI_PTR(inbuf, MAE_MAC_ADDR_ALLOC_IN_MAC_ADDR), ped->h_addr,
sizeof(ped->h_addr));
rc = efx_mcdi_rpc(efx, MC_CMD_MAE_MAC_ADDR_ALLOC, inbuf, sizeof(inbuf),
outbuf, sizeof(outbuf), &outlen);
if (rc)
return rc;
if (outlen < sizeof(outbuf))
return -EIO;
ped->fw_id = MCDI_DWORD(outbuf, MAE_MAC_ADDR_ALLOC_OUT_MAC_ID);
return 0;
}
/**
* efx_mae_free_pedit_mac() - free pedit MAC address in HW.
* @efx: NIC we're installing a pedit MAC address on
* @ped: pedit MAC action that needs to be freed
*
* Frees @ped in HW, check that firmware did not free a different one and clears
* the id (which denotes the index of the entry in the MAC address table).
*/
void efx_mae_free_pedit_mac(struct efx_nic *efx,
struct efx_tc_mac_pedit_action *ped)
{
MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_MAC_ADDR_FREE_OUT_LEN(1));
MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_MAC_ADDR_FREE_IN_LEN(1));
size_t outlen;
int rc;
MCDI_SET_DWORD(inbuf, MAE_MAC_ADDR_FREE_IN_MAC_ID, ped->fw_id);
rc = efx_mcdi_rpc(efx, MC_CMD_MAE_MAC_ADDR_FREE, inbuf,
sizeof(inbuf), outbuf, sizeof(outbuf), &outlen);
if (rc || outlen < sizeof(outbuf))
return;
/* FW freed a different ID than we asked for, should also never happen.
* Warn because it means we've now got a different idea to the FW of
* what MAC addresses exist, which could cause mayhem later.
*/
if (WARN_ON(MCDI_DWORD(outbuf, MAE_MAC_ADDR_FREE_OUT_FREED_MAC_ID) != ped->fw_id))
return;
/* We're probably about to free @ped, but let's just make sure its
* fw_id is blatted so that it won't look valid if it leaks out.
*/
ped->fw_id = MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL;
}
int efx_mae_alloc_action_set(struct efx_nic *efx, struct efx_tc_action_set *act) int efx_mae_alloc_action_set(struct efx_nic *efx, struct efx_tc_action_set *act)
{ {
MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN); MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN);
...@@ -1231,10 +1296,20 @@ int efx_mae_alloc_action_set(struct efx_nic *efx, struct efx_tc_action_set *act) ...@@ -1231,10 +1296,20 @@ int efx_mae_alloc_action_set(struct efx_nic *efx, struct efx_tc_action_set *act)
MAE_ACTION_SET_ALLOC_IN_VLAN_POP, act->vlan_pop, MAE_ACTION_SET_ALLOC_IN_VLAN_POP, act->vlan_pop,
MAE_ACTION_SET_ALLOC_IN_DECAP, act->decap); MAE_ACTION_SET_ALLOC_IN_DECAP, act->decap);
MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_SRC_MAC_ID, if (act->src_mac)
MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL); MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_SRC_MAC_ID,
MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_DST_MAC_ID, act->src_mac->fw_id);
MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL); else
MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_SRC_MAC_ID,
MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL);
if (act->dst_mac)
MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_DST_MAC_ID,
act->dst_mac->fw_id);
else
MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_DST_MAC_ID,
MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL);
if (act->count && !WARN_ON(!act->count->cnt)) if (act->count && !WARN_ON(!act->count->cnt))
MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_COUNTER_ID, MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_COUNTER_ID,
act->count->cnt->fw_id); act->count->cnt->fw_id);
......
...@@ -103,6 +103,10 @@ int efx_mae_update_encap_md(struct efx_nic *efx, ...@@ -103,6 +103,10 @@ int efx_mae_update_encap_md(struct efx_nic *efx,
int efx_mae_free_encap_md(struct efx_nic *efx, int efx_mae_free_encap_md(struct efx_nic *efx,
struct efx_tc_encap_action *encap); struct efx_tc_encap_action *encap);
int efx_mae_allocate_pedit_mac(struct efx_nic *efx,
struct efx_tc_mac_pedit_action *ped);
void efx_mae_free_pedit_mac(struct efx_nic *efx,
struct efx_tc_mac_pedit_action *ped);
int efx_mae_alloc_action_set(struct efx_nic *efx, struct efx_tc_action_set *act); 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); int efx_mae_free_action_set(struct efx_nic *efx, u32 fw_id);
......
...@@ -86,6 +86,12 @@ s64 efx_tc_flower_external_mport(struct efx_nic *efx, struct efx_rep *efv) ...@@ -86,6 +86,12 @@ s64 efx_tc_flower_external_mport(struct efx_nic *efx, struct efx_rep *efv)
return mport; return mport;
} }
static const struct rhashtable_params efx_tc_mac_ht_params = {
.key_len = offsetofend(struct efx_tc_mac_pedit_action, h_addr),
.key_offset = 0,
.head_offset = offsetof(struct efx_tc_mac_pedit_action, linkage),
};
static const struct rhashtable_params efx_tc_encap_match_ht_params = { static const struct rhashtable_params efx_tc_encap_match_ht_params = {
.key_len = offsetof(struct efx_tc_encap_match, linkage), .key_len = offsetof(struct efx_tc_encap_match, linkage),
.key_offset = 0, .key_offset = 0,
...@@ -110,6 +116,56 @@ static const struct rhashtable_params efx_tc_recirc_ht_params = { ...@@ -110,6 +116,56 @@ static const struct rhashtable_params efx_tc_recirc_ht_params = {
.head_offset = offsetof(struct efx_tc_recirc_id, linkage), .head_offset = offsetof(struct efx_tc_recirc_id, linkage),
}; };
static struct efx_tc_mac_pedit_action __maybe_unused *efx_tc_flower_get_mac(struct efx_nic *efx,
unsigned char h_addr[ETH_ALEN],
struct netlink_ext_ack *extack)
{
struct efx_tc_mac_pedit_action *ped, *old;
int rc;
ped = kzalloc(sizeof(*ped), GFP_USER);
if (!ped)
return ERR_PTR(-ENOMEM);
memcpy(ped->h_addr, h_addr, ETH_ALEN);
old = rhashtable_lookup_get_insert_fast(&efx->tc->mac_ht,
&ped->linkage,
efx_tc_mac_ht_params);
if (old) {
/* don't need our new entry */
kfree(ped);
if (!refcount_inc_not_zero(&old->ref))
return ERR_PTR(-EAGAIN);
/* existing entry found, ref taken */
return old;
}
rc = efx_mae_allocate_pedit_mac(efx, ped);
if (rc < 0) {
NL_SET_ERR_MSG_MOD(extack, "Failed to store pedit MAC address in hw");
goto out_remove;
}
/* ref and return */
refcount_set(&ped->ref, 1);
return ped;
out_remove:
rhashtable_remove_fast(&efx->tc->mac_ht, &ped->linkage,
efx_tc_mac_ht_params);
kfree(ped);
return ERR_PTR(rc);
}
static void __maybe_unused efx_tc_flower_put_mac(struct efx_nic *efx,
struct efx_tc_mac_pedit_action *ped)
{
if (!refcount_dec_and_test(&ped->ref))
return; /* still in use */
rhashtable_remove_fast(&efx->tc->mac_ht, &ped->linkage,
efx_tc_mac_ht_params);
efx_mae_free_pedit_mac(efx, ped);
kfree(ped);
}
static void efx_tc_free_action_set(struct efx_nic *efx, static void efx_tc_free_action_set(struct efx_nic *efx,
struct efx_tc_action_set *act, bool in_hw) struct efx_tc_action_set *act, bool in_hw)
{ {
...@@ -2156,6 +2212,14 @@ static void efx_tc_lhs_free(void *ptr, void *arg) ...@@ -2156,6 +2212,14 @@ static void efx_tc_lhs_free(void *ptr, void *arg)
kfree(rule); kfree(rule);
} }
static void efx_tc_mac_free(void *ptr, void *__unused)
{
struct efx_tc_mac_pedit_action *ped = ptr;
WARN_ON(refcount_read(&ped->ref));
kfree(ped);
}
static void efx_tc_flow_free(void *ptr, void *arg) static void efx_tc_flow_free(void *ptr, void *arg)
{ {
struct efx_tc_flow_rule *rule = ptr; struct efx_tc_flow_rule *rule = ptr;
...@@ -2196,6 +2260,9 @@ int efx_init_struct_tc(struct efx_nic *efx) ...@@ -2196,6 +2260,9 @@ int efx_init_struct_tc(struct efx_nic *efx)
rc = efx_tc_init_counters(efx); rc = efx_tc_init_counters(efx);
if (rc < 0) if (rc < 0)
goto fail_counters; goto fail_counters;
rc = rhashtable_init(&efx->tc->mac_ht, &efx_tc_mac_ht_params);
if (rc < 0)
goto fail_mac_ht;
rc = rhashtable_init(&efx->tc->encap_match_ht, &efx_tc_encap_match_ht_params); rc = rhashtable_init(&efx->tc->encap_match_ht, &efx_tc_encap_match_ht_params);
if (rc < 0) if (rc < 0)
goto fail_encap_match_ht; goto fail_encap_match_ht;
...@@ -2233,6 +2300,8 @@ int efx_init_struct_tc(struct efx_nic *efx) ...@@ -2233,6 +2300,8 @@ int efx_init_struct_tc(struct efx_nic *efx)
fail_match_action_ht: fail_match_action_ht:
rhashtable_destroy(&efx->tc->encap_match_ht); rhashtable_destroy(&efx->tc->encap_match_ht);
fail_encap_match_ht: fail_encap_match_ht:
rhashtable_destroy(&efx->tc->mac_ht);
fail_mac_ht:
efx_tc_destroy_counters(efx); efx_tc_destroy_counters(efx);
fail_counters: fail_counters:
efx_tc_destroy_encap_actions(efx); efx_tc_destroy_encap_actions(efx);
...@@ -2268,6 +2337,7 @@ void efx_fini_struct_tc(struct efx_nic *efx) ...@@ -2268,6 +2337,7 @@ void efx_fini_struct_tc(struct efx_nic *efx)
rhashtable_free_and_destroy(&efx->tc->recirc_ht, efx_tc_recirc_free, efx); rhashtable_free_and_destroy(&efx->tc->recirc_ht, efx_tc_recirc_free, efx);
WARN_ON(!ida_is_empty(&efx->tc->recirc_ida)); WARN_ON(!ida_is_empty(&efx->tc->recirc_ida));
ida_destroy(&efx->tc->recirc_ida); ida_destroy(&efx->tc->recirc_ida);
rhashtable_free_and_destroy(&efx->tc->mac_ht, efx_tc_mac_free, NULL);
efx_tc_fini_counters(efx); efx_tc_fini_counters(efx);
efx_tc_fini_encap_actions(efx); efx_tc_fini_encap_actions(efx);
mutex_unlock(&efx->tc->mutex); mutex_unlock(&efx->tc->mutex);
......
...@@ -18,6 +18,23 @@ ...@@ -18,6 +18,23 @@
#define IS_ALL_ONES(v) (!(typeof (v))~(v)) #define IS_ALL_ONES(v) (!(typeof (v))~(v))
/**
* struct efx_tc_mac_pedit_action - mac pedit action fields
*
* @h_addr: mac address field of ethernet header
* @linkage: rhashtable reference
* @ref: reference count
* @fw_id: index of this entry in firmware MAC address table
*
* MAC address edits are indirected through a table in the hardware
*/
struct efx_tc_mac_pedit_action {
u8 h_addr[ETH_ALEN];
struct rhash_head linkage;
refcount_t ref;
u32 fw_id; /* index of this entry in firmware MAC address table */
};
static inline bool efx_ipv6_addr_all_ones(struct in6_addr *addr) static inline bool efx_ipv6_addr_all_ones(struct in6_addr *addr)
{ {
return !memchr_inv(addr, 0xff, sizeof(*addr)); return !memchr_inv(addr, 0xff, sizeof(*addr));
...@@ -25,20 +42,43 @@ static inline bool efx_ipv6_addr_all_ones(struct in6_addr *addr) ...@@ -25,20 +42,43 @@ static inline bool efx_ipv6_addr_all_ones(struct in6_addr *addr)
struct efx_tc_encap_action; /* see tc_encap_actions.h */ struct efx_tc_encap_action; /* see tc_encap_actions.h */
/**
* struct efx_tc_action_set - collection of tc action fields
*
* @vlan_push: the number of vlan headers to push
* @vlan_pop: the number of vlan headers to pop
* @decap: used to indicate a tunnel header decapsulation should take place
* @deliver: used to indicate a deliver action should take place
* @vlan_tci: tci fields for vlan push actions
* @vlan_proto: ethernet types for vlan push actions
* @count: counter mapping
* @encap_md: encap entry in tc_encap_ht table
* @encap_user: linked list of encap users (encap_md->users)
* @user: owning action-set-list. Only populated if @encap_md is; used by efx_tc_update_encap() fallback handling
* @count_user: linked list of counter users (counter->users)
* @dest_mport: destination mport
* @src_mac: source mac entry in tc_mac_ht table
* @dst_mac: destination mac entry in tc_mac_ht table
* @fw_id: index of this entry in firmware actions table
* @list: linked list of tc actions
*
*/
struct efx_tc_action_set { struct efx_tc_action_set {
u16 vlan_push:2; u16 vlan_push:2;
u16 vlan_pop:2; u16 vlan_pop:2;
u16 decap:1; u16 decap:1;
u16 deliver:1; u16 deliver:1;
__be16 vlan_tci[2]; /* TCIs for vlan_push */ __be16 vlan_tci[2];
__be16 vlan_proto[2]; /* Ethertypes for vlan_push */ __be16 vlan_proto[2];
struct efx_tc_counter_index *count; struct efx_tc_counter_index *count;
struct efx_tc_encap_action *encap_md; /* entry in tc_encap_ht table */ struct efx_tc_encap_action *encap_md;
struct list_head encap_user; /* entry on encap_md->users list */ struct list_head encap_user;
struct efx_tc_action_set_list *user; /* Only populated if encap_md */ struct efx_tc_action_set_list *user;
struct list_head count_user; /* entry on counter->users list, if encap */ struct list_head count_user;
u32 dest_mport; u32 dest_mport;
u32 fw_id; /* index of this entry in firmware actions table */ struct efx_tc_mac_pedit_action *src_mac;
struct efx_tc_mac_pedit_action *dst_mac;
u32 fw_id;
struct list_head list; struct list_head list;
}; };
...@@ -220,6 +260,7 @@ struct efx_tc_table_ct { /* TABLE_ID_CONNTRACK_TABLE */ ...@@ -220,6 +260,7 @@ struct efx_tc_table_ct { /* TABLE_ID_CONNTRACK_TABLE */
* @counter_ht: Hashtable of TC counters (FW IDs and counter values) * @counter_ht: Hashtable of TC counters (FW IDs and counter values)
* @counter_id_ht: Hashtable mapping TC counter cookies to counters * @counter_id_ht: Hashtable mapping TC counter cookies to counters
* @encap_ht: Hashtable of TC encap actions * @encap_ht: Hashtable of TC encap actions
* @mac_ht: Hashtable of MAC address entries (for pedits)
* @encap_match_ht: Hashtable of TC encap matches * @encap_match_ht: Hashtable of TC encap matches
* @match_action_ht: Hashtable of TC match-action rules * @match_action_ht: Hashtable of TC match-action rules
* @lhs_rule_ht: Hashtable of TC left-hand (act ct & goto chain) rules * @lhs_rule_ht: Hashtable of TC left-hand (act ct & goto chain) rules
...@@ -257,6 +298,7 @@ struct efx_tc_state { ...@@ -257,6 +298,7 @@ struct efx_tc_state {
struct rhashtable counter_ht; struct rhashtable counter_ht;
struct rhashtable counter_id_ht; struct rhashtable counter_id_ht;
struct rhashtable encap_ht; struct rhashtable encap_ht;
struct rhashtable mac_ht;
struct rhashtable encap_match_ht; struct rhashtable encap_match_ht;
struct rhashtable match_action_ht; struct rhashtable match_action_ht;
struct rhashtable lhs_rule_ht; struct rhashtable lhs_rule_ht;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment