Commit c38fb3dc authored by Yinjun Zhang's avatar Yinjun Zhang Committed by Jakub Kicinski
Browse files

nfp: offload flow steering to the nfp



This is the second part to implement flow steering. Mailbox is used
for the communication between driver and HW.

Signed-off-by: default avatarYinjun Zhang <yinjun.zhang@corigine.com>
Signed-off-by: default avatarLouis Peens <louis.peens@corigine.com>
Reviewed-by: default avatarSimon Horman <horms@kernel.org>
Link: https://lore.kernel.org/r/20231117071114.10667-3-louis.peens@corigine.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 9eb03bb1
Loading
Loading
Loading
Loading
+161 −2
Original line number Diff line number Diff line
@@ -1763,14 +1763,173 @@ nfp_net_vlan_rx_kill_vid(struct net_device *netdev, __be16 proto, u16 vid)
	return nfp_net_mbox_reconfig_and_unlock(nn, cmd);
}

static void
nfp_net_fs_fill_v4(struct nfp_net *nn, struct nfp_fs_entry *entry, u32 op, u32 *addr)
{
	unsigned int i;

	union {
		struct {
			__be16 loc;
			u8 k_proto, m_proto;
			__be32 k_sip, m_sip, k_dip, m_dip;
			__be16 k_sport, m_sport, k_dport, m_dport;
		};
		__be32 val[7];
	} v4_rule;

	nn_writel(nn, *addr, op);
	*addr += sizeof(u32);

	v4_rule.loc     = cpu_to_be16(entry->loc);
	v4_rule.k_proto = entry->key.l4_proto;
	v4_rule.m_proto = entry->msk.l4_proto;
	v4_rule.k_sip   = entry->key.sip4;
	v4_rule.m_sip   = entry->msk.sip4;
	v4_rule.k_dip   = entry->key.dip4;
	v4_rule.m_dip   = entry->msk.dip4;
	v4_rule.k_sport = entry->key.sport;
	v4_rule.m_sport = entry->msk.sport;
	v4_rule.k_dport = entry->key.dport;
	v4_rule.m_dport = entry->msk.dport;

	for (i = 0; i < ARRAY_SIZE(v4_rule.val); i++, *addr += sizeof(__be32))
		nn_writel(nn, *addr, be32_to_cpu(v4_rule.val[i]));
}

static void
nfp_net_fs_fill_v6(struct nfp_net *nn, struct nfp_fs_entry *entry, u32 op, u32 *addr)
{
	unsigned int i;

	union {
		struct {
			__be16 loc;
			u8 k_proto, m_proto;
			__be32 k_sip[4], m_sip[4], k_dip[4], m_dip[4];
			__be16 k_sport, m_sport, k_dport, m_dport;
		};
		__be32 val[19];
	} v6_rule;

	nn_writel(nn, *addr, op);
	*addr += sizeof(u32);

	v6_rule.loc     = cpu_to_be16(entry->loc);
	v6_rule.k_proto = entry->key.l4_proto;
	v6_rule.m_proto = entry->msk.l4_proto;
	for (i = 0; i < 4; i++) {
		v6_rule.k_sip[i] = entry->key.sip6[i];
		v6_rule.m_sip[i] = entry->msk.sip6[i];
		v6_rule.k_dip[i] = entry->key.dip6[i];
		v6_rule.m_dip[i] = entry->msk.dip6[i];
	}
	v6_rule.k_sport = entry->key.sport;
	v6_rule.m_sport = entry->msk.sport;
	v6_rule.k_dport = entry->key.dport;
	v6_rule.m_dport = entry->msk.dport;

	for (i = 0; i < ARRAY_SIZE(v6_rule.val); i++, *addr += sizeof(__be32))
		nn_writel(nn, *addr, be32_to_cpu(v6_rule.val[i]));
}

#define NFP_FS_QUEUE_ID	GENMASK(22, 16)
#define NFP_FS_ACT	GENMASK(15, 0)
#define NFP_FS_ACT_DROP	BIT(0)
#define NFP_FS_ACT_Q	BIT(1)
static void
nfp_net_fs_fill_act(struct nfp_net *nn, struct nfp_fs_entry *entry, u32 addr)
{
	u32 action = 0; /* 0 means default passthrough */

	if (entry->action == RX_CLS_FLOW_DISC)
		action = NFP_FS_ACT_DROP;
	else if (!(entry->flow_type & FLOW_RSS))
		action = FIELD_PREP(NFP_FS_QUEUE_ID, entry->action) | NFP_FS_ACT_Q;

	nn_writel(nn, addr, action);
}

int nfp_net_fs_add_hw(struct nfp_net *nn, struct nfp_fs_entry *entry)
{
	return -EOPNOTSUPP;
	u32 addr = nn->tlv_caps.mbox_off + NFP_NET_CFG_MBOX_SIMPLE_VAL;
	int err;

	err = nfp_net_mbox_lock(nn, NFP_NET_CFG_FS_SZ);
	if (err)
		return err;

	switch (entry->flow_type & ~FLOW_RSS) {
	case TCP_V4_FLOW:
	case UDP_V4_FLOW:
	case SCTP_V4_FLOW:
	case IPV4_USER_FLOW:
		nfp_net_fs_fill_v4(nn, entry, NFP_NET_CFG_MBOX_CMD_FS_ADD_V4, &addr);
		break;
	case TCP_V6_FLOW:
	case UDP_V6_FLOW:
	case SCTP_V6_FLOW:
	case IPV6_USER_FLOW:
		nfp_net_fs_fill_v6(nn, entry, NFP_NET_CFG_MBOX_CMD_FS_ADD_V6, &addr);
		break;
	case ETHER_FLOW:
		nn_writel(nn, addr, NFP_NET_CFG_MBOX_CMD_FS_ADD_ETHTYPE);
		addr += sizeof(u32);
		nn_writew(nn, addr, be16_to_cpu(entry->key.l3_proto));
		addr += sizeof(u32);
		break;
	}

	nfp_net_fs_fill_act(nn, entry, addr);

	err = nfp_net_mbox_reconfig_and_unlock(nn, NFP_NET_CFG_MBOX_CMD_FLOW_STEER);
	if (err) {
		nn_err(nn, "Add new fs rule failed with %d\n", err);
		return -EIO;
	}

	return 0;
}

int nfp_net_fs_del_hw(struct nfp_net *nn, struct nfp_fs_entry *entry)
{
	return -EOPNOTSUPP;
	u32 addr = nn->tlv_caps.mbox_off + NFP_NET_CFG_MBOX_SIMPLE_VAL;
	int err;

	err = nfp_net_mbox_lock(nn, NFP_NET_CFG_FS_SZ);
	if (err)
		return err;

	switch (entry->flow_type & ~FLOW_RSS) {
	case TCP_V4_FLOW:
	case UDP_V4_FLOW:
	case SCTP_V4_FLOW:
	case IPV4_USER_FLOW:
		nfp_net_fs_fill_v4(nn, entry, NFP_NET_CFG_MBOX_CMD_FS_DEL_V4, &addr);
		break;
	case TCP_V6_FLOW:
	case UDP_V6_FLOW:
	case SCTP_V6_FLOW:
	case IPV6_USER_FLOW:
		nfp_net_fs_fill_v6(nn, entry, NFP_NET_CFG_MBOX_CMD_FS_DEL_V6, &addr);
		break;
	case ETHER_FLOW:
		nn_writel(nn, addr, NFP_NET_CFG_MBOX_CMD_FS_DEL_ETHTYPE);
		addr += sizeof(u32);
		nn_writew(nn, addr, be16_to_cpu(entry->key.l3_proto));
		addr += sizeof(u32);
		break;
	}

	nfp_net_fs_fill_act(nn, entry, addr);

	err = nfp_net_mbox_reconfig_and_unlock(nn, NFP_NET_CFG_MBOX_CMD_FLOW_STEER);
	if (err) {
		nn_err(nn, "Delete fs rule failed with %d\n", err);
		return -EIO;
	}

	return 0;
}

static void nfp_net_fs_clean(struct nfp_net *nn)
+14 −0
Original line number Diff line number Diff line
@@ -419,6 +419,8 @@
#define NFP_NET_CFG_MBOX_CMD_MULTICAST_ADD		8
#define NFP_NET_CFG_MBOX_CMD_MULTICAST_DEL		9

#define NFP_NET_CFG_MBOX_CMD_FLOW_STEER			10

/* VLAN filtering using general use mailbox
 * %NFP_NET_CFG_VLAN_FILTER:		Base address of VLAN filter mailbox
 * %NFP_NET_CFG_VLAN_FILTER_VID:	VLAN ID to filter
@@ -441,6 +443,18 @@
#define NFP_NET_CFG_MULTICAST_MAC_LO	(NFP_NET_CFG_MULTICAST + 6)
#define NFP_NET_CFG_MULTICAST_SZ	0x0006

/* Max size of FS rules in bytes */
#define NFP_NET_CFG_FS_SZ		0x0054
/* Sub commands for FS */
enum {
	NFP_NET_CFG_MBOX_CMD_FS_ADD_V4,
	NFP_NET_CFG_MBOX_CMD_FS_DEL_V4,
	NFP_NET_CFG_MBOX_CMD_FS_ADD_V6,
	NFP_NET_CFG_MBOX_CMD_FS_DEL_V6,
	NFP_NET_CFG_MBOX_CMD_FS_ADD_ETHTYPE,
	NFP_NET_CFG_MBOX_CMD_FS_DEL_ETHTYPE,
};

/* TLV capabilities
 * %NFP_NET_CFG_TLV_TYPE:	Offset of type within the TLV
 * %NFP_NET_CFG_TLV_TYPE_REQUIRED: Driver must be able to parse the TLV