Commit e431e712 authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

Merge branch 'sfc-tc-encap-actions-offload'

Edward Cree says:

====================
sfc: TC encap actions offload

This series adds support for offloading TC tunnel_key set actions to the
 EF100 driver, supporting VxLAN and GENEVE tunnels over IPv4 or IPv6.
====================

Link: https://lore.kernel.org/r/cover.1686240142.git.ecree.xilinx@gmail.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents d457a0e3 a1e82162
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -10,7 +10,8 @@ sfc-y += efx.o efx_common.o efx_channels.o nic.o \
			   efx_devlink.o
sfc-$(CONFIG_SFC_MTD)	+= mtd.o
sfc-$(CONFIG_SFC_SRIOV)	+= sriov.o ef10_sriov.o ef100_sriov.o ef100_rep.o \
                           mae.o tc.o tc_bindings.o tc_counters.o
                           mae.o tc.o tc_bindings.o tc_counters.o \
                           tc_encap_actions.o

obj-$(CONFIG_SFC)	+= sfc.o

+34 −0
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@
#include "rx_common.h"
#include "ef100_sriov.h"
#include "tc_bindings.h"
#include "tc_encap_actions.h"
#include "efx_devlink.h"

static void ef100_update_name(struct efx_nic *efx)
@@ -300,14 +301,38 @@ int ef100_netdev_event(struct notifier_block *this,
{
	struct efx_nic *efx = container_of(this, struct efx_nic, netdev_notifier);
	struct net_device *net_dev = netdev_notifier_info_to_dev(ptr);
	struct ef100_nic_data *nic_data = efx->nic_data;
	int err;

	if (efx->net_dev == net_dev &&
	    (event == NETDEV_CHANGENAME || event == NETDEV_REGISTER))
		ef100_update_name(efx);

	if (!nic_data->grp_mae)
		return NOTIFY_DONE;
	err = efx_tc_netdev_event(efx, event, net_dev);
	if (err & NOTIFY_STOP_MASK)
		return err;

	return NOTIFY_DONE;
}

static int ef100_netevent_event(struct notifier_block *this,
				unsigned long event, void *ptr)
{
	struct efx_nic *efx = container_of(this, struct efx_nic, netevent_notifier);
	struct ef100_nic_data *nic_data = efx->nic_data;
	int err;

	if (!nic_data->grp_mae)
		return NOTIFY_DONE;
	err = efx_tc_netevent_event(efx, event, ptr);
	if (err & NOTIFY_STOP_MASK)
		return err;

	return NOTIFY_DONE;
};

static int ef100_register_netdev(struct efx_nic *efx)
{
	struct net_device *net_dev = efx->net_dev;
@@ -367,6 +392,7 @@ void ef100_remove_netdev(struct efx_probe_data *probe_data)
	rtnl_unlock();

	unregister_netdevice_notifier(&efx->netdev_notifier);
	unregister_netevent_notifier(&efx->netevent_notifier);
#if defined(CONFIG_SFC_SRIOV)
	if (!efx->type->is_vf)
		efx_ef100_pci_sriov_disable(efx, true);
@@ -487,6 +513,14 @@ int ef100_probe_netdev(struct efx_probe_data *probe_data)
		goto fail;
	}

	efx->netevent_notifier.notifier_call = ef100_netevent_event;
	rc = register_netevent_notifier(&efx->netevent_notifier);
	if (rc) {
		netif_err(efx, probe, efx->net_dev,
			  "Failed to register netevent notifier, rc=%d\n", rc);
		goto fail;
	}

	efx_probe_devlink_unlock(efx);
	return rc;
fail:
+111 −2
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
#include "mcdi.h"
#include "mcdi_pcol.h"
#include "mcdi_pcol_mae.h"
#include "tc_encap_actions.h"

int efx_mae_allocate_mport(struct efx_nic *efx, u32 *id, u32 *label)
{
@@ -610,6 +611,87 @@ static int efx_mae_encap_type_to_mae_type(enum efx_encap_type type)
	}
}

int efx_mae_allocate_encap_md(struct efx_nic *efx,
			      struct efx_tc_encap_action *encap)
{
	MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_LEN(EFX_TC_MAX_ENCAP_HDR));
	MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_LEN);
	size_t inlen, outlen;
	int rc;

	rc = efx_mae_encap_type_to_mae_type(encap->type);
	if (rc < 0)
		return rc;
	MCDI_SET_DWORD(inbuf, MAE_ENCAP_HEADER_ALLOC_IN_ENCAP_TYPE, rc);
	inlen = MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_LEN(encap->encap_hdr_len);
	if (WARN_ON(inlen > sizeof(inbuf))) /* can't happen */
		return -EINVAL;
	memcpy(MCDI_PTR(inbuf, MAE_ENCAP_HEADER_ALLOC_IN_HDR_DATA),
	       encap->encap_hdr,
	       encap->encap_hdr_len);
	rc = efx_mcdi_rpc(efx, MC_CMD_MAE_ENCAP_HEADER_ALLOC, inbuf,
			  inlen, outbuf, sizeof(outbuf), &outlen);
	if (rc)
		return rc;
	if (outlen < sizeof(outbuf))
		return -EIO;
	encap->fw_id = MCDI_DWORD(outbuf, MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID);
	return 0;
}

int efx_mae_update_encap_md(struct efx_nic *efx,
			    struct efx_tc_encap_action *encap)
{
	MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_ENCAP_HEADER_UPDATE_IN_LEN(EFX_TC_MAX_ENCAP_HDR));
	size_t inlen;
	int rc;

	rc = efx_mae_encap_type_to_mae_type(encap->type);
	if (rc < 0)
		return rc;
	MCDI_SET_DWORD(inbuf, MAE_ENCAP_HEADER_UPDATE_IN_ENCAP_TYPE, rc);
	MCDI_SET_DWORD(inbuf, MAE_ENCAP_HEADER_UPDATE_IN_EH_ID,
		       encap->fw_id);
	inlen = MC_CMD_MAE_ENCAP_HEADER_UPDATE_IN_LEN(encap->encap_hdr_len);
	if (WARN_ON(inlen > sizeof(inbuf))) /* can't happen */
		return -EINVAL;
	memcpy(MCDI_PTR(inbuf, MAE_ENCAP_HEADER_UPDATE_IN_HDR_DATA),
	       encap->encap_hdr,
	       encap->encap_hdr_len);

	BUILD_BUG_ON(MC_CMD_MAE_ENCAP_HEADER_UPDATE_OUT_LEN != 0);
	return efx_mcdi_rpc(efx, MC_CMD_MAE_ENCAP_HEADER_UPDATE, inbuf,
			    inlen, NULL, 0, NULL);
}

int efx_mae_free_encap_md(struct efx_nic *efx,
			  struct efx_tc_encap_action *encap)
{
	MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ENCAP_HEADER_FREE_OUT_LEN(1));
	MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_ENCAP_HEADER_FREE_IN_LEN(1));
	size_t outlen;
	int rc;

	MCDI_SET_DWORD(inbuf, MAE_ENCAP_HEADER_FREE_IN_EH_ID, encap->fw_id);
	rc = efx_mcdi_rpc(efx, MC_CMD_MAE_ENCAP_HEADER_FREE, inbuf,
			  sizeof(inbuf), outbuf, sizeof(outbuf), &outlen);
	if (rc)
		return rc;
	if (outlen < sizeof(outbuf))
		return -EIO;
	/* 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 encap_mds exist, which could cause mayhem later.
	 */
	if (WARN_ON(MCDI_DWORD(outbuf, MAE_ENCAP_HEADER_FREE_OUT_FREED_EH_ID) != encap->fw_id))
		return -EIO;
	/* We're probably about to free @encap, but let's just make sure its
	 * fw_id is blatted so that it won't look valid if it leaks out.
	 */
	encap->fw_id = MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID_NULL;
	return 0;
}

int efx_mae_lookup_mport(struct efx_nic *efx, u32 vf_idx, u32 *id)
{
	struct ef100_nic_data *nic_data = efx->nic_data;
@@ -833,6 +915,10 @@ int efx_mae_alloc_action_set(struct efx_nic *efx, struct efx_tc_action_set *act)
		MCDI_SET_WORD_BE(inbuf, MAE_ACTION_SET_ALLOC_IN_VLAN1_PROTO_BE,
				 act->vlan_proto[1]);
	}
	if (act->encap_md)
		MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_ENCAP_HEADER_ID,
			       act->encap_md->fw_id);
	else
		MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_ENCAP_HEADER_ID,
			       MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID_NULL);
	if (act->deliver)
@@ -1229,6 +1315,29 @@ int efx_mae_insert_rule(struct efx_nic *efx, const struct efx_tc_match *match,
	return 0;
}

int efx_mae_update_rule(struct efx_nic *efx, u32 acts_id, u32 id)
{
	MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_ACTION_RULE_UPDATE_IN_LEN);
	MCDI_DECLARE_STRUCT_PTR(response);

	BUILD_BUG_ON(MC_CMD_MAE_ACTION_RULE_UPDATE_OUT_LEN);
	response = _MCDI_DWORD(inbuf, MAE_ACTION_RULE_UPDATE_IN_RESPONSE);

	MCDI_SET_DWORD(inbuf, MAE_ACTION_RULE_UPDATE_IN_AR_ID, id);
	if (efx_mae_asl_id(acts_id)) {
		MCDI_STRUCT_SET_DWORD(response, MAE_ACTION_RULE_RESPONSE_ASL_ID, acts_id);
		MCDI_STRUCT_SET_DWORD(response, MAE_ACTION_RULE_RESPONSE_AS_ID,
				      MC_CMD_MAE_ACTION_SET_ALLOC_OUT_ACTION_SET_ID_NULL);
	} else {
		/* We only had one AS, so we didn't wrap it in an ASL */
		MCDI_STRUCT_SET_DWORD(response, MAE_ACTION_RULE_RESPONSE_ASL_ID,
				      MC_CMD_MAE_ACTION_SET_LIST_ALLOC_OUT_ACTION_SET_LIST_ID_NULL);
		MCDI_STRUCT_SET_DWORD(response, MAE_ACTION_RULE_RESPONSE_AS_ID, acts_id);
	}
	return efx_mcdi_rpc(efx, MC_CMD_MAE_ACTION_RULE_UPDATE, inbuf, sizeof(inbuf),
			    NULL, 0, NULL);
}

int efx_mae_delete_rule(struct efx_nic *efx, u32 id)
{
	MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ACTION_RULE_DELETE_OUT_LEN(1));
+8 −0
Original line number Diff line number Diff line
@@ -90,6 +90,13 @@ int efx_mae_check_encap_type_supported(struct efx_nic *efx,
int efx_mae_allocate_counter(struct efx_nic *efx, struct efx_tc_counter *cnt);
int efx_mae_free_counter(struct efx_nic *efx, struct efx_tc_counter *cnt);

int efx_mae_allocate_encap_md(struct efx_nic *efx,
			      struct efx_tc_encap_action *encap);
int efx_mae_update_encap_md(struct efx_nic *efx,
			    struct efx_tc_encap_action *encap);
int efx_mae_free_encap_md(struct efx_nic *efx,
			  struct efx_tc_encap_action *encap);

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);

@@ -105,6 +112,7 @@ int efx_mae_unregister_encap_match(struct efx_nic *efx,

int efx_mae_insert_rule(struct efx_nic *efx, const struct efx_tc_match *match,
			u32 prio, u32 acts_id, u32 *id);
int efx_mae_update_rule(struct efx_nic *efx, u32 acts_id, u32 id);
int efx_mae_delete_rule(struct efx_nic *efx, u32 id);

int efx_init_mae(struct efx_nic *efx);
+3 −0
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@
#include <linux/mtd/mtd.h>
#include <net/busy_poll.h>
#include <net/xdp.h>
#include <net/netevent.h>

#include "enum.h"
#include "bitfield.h"
@@ -996,6 +997,7 @@ struct efx_mae;
 * @xdp_rxq_info_failed: Have any of the rx queues failed to initialise their
 *      xdp_rxq_info structures?
 * @netdev_notifier: Netdevice notifier.
 * @netevent_notifier: Netevent notifier (for neighbour updates).
 * @tc: state for TC offload (EF100).
 * @devlink: reference to devlink structure owned by this device
 * @dl_port: devlink port associated with the PF
@@ -1183,6 +1185,7 @@ struct efx_nic {
	bool xdp_rxq_info_failed;

	struct notifier_block netdev_notifier;
	struct notifier_block netevent_notifier;
	struct efx_tc_state *tc;

	struct devlink *devlink;
Loading