diff options
author | Yinjun Zhang <yinjun.zhang@corigine.com> | 2023-11-17 10:11:14 +0300 |
---|---|---|
committer | Jakub Kicinski <kuba@kernel.org> | 2023-11-21 05:04:30 +0300 |
commit | c38fb3dcd53dbfc68eb429e8ecb0ec795f0d6ba1 (patch) | |
tree | 987243937ae0c5a86baf537c05851fa45967fc99 /drivers/net/ethernet/netronome | |
parent | 9eb03bb1c035ff6e2c3a34046419446588253dda (diff) | |
download | linux-c38fb3dcd53dbfc68eb429e8ecb0ec795f0d6ba1.tar.xz |
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: Yinjun Zhang <yinjun.zhang@corigine.com>
Signed-off-by: Louis Peens <louis.peens@corigine.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://lore.kernel.org/r/20231117071114.10667-3-louis.peens@corigine.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Diffstat (limited to 'drivers/net/ethernet/netronome')
-rw-r--r-- | drivers/net/ethernet/netronome/nfp/nfp_net_common.c | 163 | ||||
-rw-r--r-- | drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h | 14 |
2 files changed, 175 insertions, 2 deletions
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c index 12eda2c2ac23..ac1f4514b1d0 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c @@ -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) diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h b/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h index 515472924a5d..eaf4d3c499d1 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h @@ -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 |