Merge branch 'enic-update'

Govindarajulu Varadarajan says:

====================
enic update

This series adds support for IPv6 vxlan offload and UDP rss along with a
bug fix in filling the rq ring.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2018-03-04 18:19:26 -05:00
commit a56cd508e7
7 changed files with 131 additions and 20 deletions

View File

@ -33,7 +33,7 @@
#define DRV_NAME "enic" #define DRV_NAME "enic"
#define DRV_DESCRIPTION "Cisco VIC Ethernet NIC Driver" #define DRV_DESCRIPTION "Cisco VIC Ethernet NIC Driver"
#define DRV_VERSION "2.3.0.45" #define DRV_VERSION "2.3.0.53"
#define DRV_COPYRIGHT "Copyright 2008-2013 Cisco Systems, Inc" #define DRV_COPYRIGHT "Copyright 2008-2013 Cisco Systems, Inc"
#define ENIC_BARS_MAX 6 #define ENIC_BARS_MAX 6
@ -140,6 +140,7 @@ struct enic_rfs_flw_tbl {
struct vxlan_offload { struct vxlan_offload {
u16 vxlan_udp_port_number; u16 vxlan_udp_port_number;
u8 patch_level; u8 patch_level;
u8 flags;
}; };
/* Per-instance private data structure */ /* Per-instance private data structure */

View File

@ -474,6 +474,39 @@ static int enic_grxclsrule(struct enic *enic, struct ethtool_rxnfc *cmd)
return 0; return 0;
} }
static int enic_get_rx_flow_hash(struct enic *enic, struct ethtool_rxnfc *cmd)
{
cmd->data = 0;
switch (cmd->flow_type) {
case TCP_V6_FLOW:
case TCP_V4_FLOW:
cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
/* Fall through */
case UDP_V6_FLOW:
case UDP_V4_FLOW:
if (vnic_dev_capable_udp_rss(enic->vdev))
cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
/* Fall through */
case SCTP_V4_FLOW:
case AH_ESP_V4_FLOW:
case AH_V4_FLOW:
case ESP_V4_FLOW:
case SCTP_V6_FLOW:
case AH_ESP_V6_FLOW:
case AH_V6_FLOW:
case ESP_V6_FLOW:
case IPV4_FLOW:
case IPV6_FLOW:
cmd->data |= RXH_IP_SRC | RXH_IP_DST;
break;
default:
return -EINVAL;
}
return 0;
}
static int enic_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd, static int enic_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
u32 *rule_locs) u32 *rule_locs)
{ {
@ -500,6 +533,9 @@ static int enic_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
ret = enic_grxclsrule(enic, cmd); ret = enic_grxclsrule(enic, cmd);
spin_unlock_bh(&enic->rfs_h.lock); spin_unlock_bh(&enic->rfs_h.lock);
break; break;
case ETHTOOL_GRXFH:
ret = enic_get_rx_flow_hash(enic, cmd);
break;
default: default:
ret = -EOPNOTSUPP; ret = -EOPNOTSUPP;
break; break;

View File

@ -191,10 +191,18 @@ static void enic_udp_tunnel_add(struct net_device *netdev,
goto error; goto error;
} }
if (ti->sa_family != AF_INET) { switch (ti->sa_family) {
case AF_INET6:
if (!(enic->vxlan.flags & ENIC_VXLAN_OUTER_IPV6)) {
netdev_info(netdev, "vxlan: only IPv4 offload supported"); netdev_info(netdev, "vxlan: only IPv4 offload supported");
goto error; goto error;
} }
/* Fall through */
case AF_INET:
break;
default:
goto error;
}
if (enic->vxlan.vxlan_udp_port_number) { if (enic->vxlan.vxlan_udp_port_number) {
if (ntohs(port) == enic->vxlan.vxlan_udp_port_number) if (ntohs(port) == enic->vxlan.vxlan_udp_port_number)
@ -204,6 +212,11 @@ static void enic_udp_tunnel_add(struct net_device *netdev,
goto error; goto error;
} }
if ((vnic_dev_get_res_count(enic->vdev, RES_TYPE_WQ) != 1) &&
!(enic->vxlan.flags & ENIC_VXLAN_MULTI_WQ)) {
netdev_info(netdev, "vxlan: vxlan offload with multi wq not supported on this adapter");
goto error;
}
err = vnic_dev_overlay_offload_cfg(enic->vdev, err = vnic_dev_overlay_offload_cfg(enic->vdev,
OVERLAY_CFG_VXLAN_PORT_UPDATE, OVERLAY_CFG_VXLAN_PORT_UPDATE,
@ -271,22 +284,37 @@ static netdev_features_t enic_features_check(struct sk_buff *skb,
struct enic *enic = netdev_priv(dev); struct enic *enic = netdev_priv(dev);
struct udphdr *udph; struct udphdr *udph;
u16 port = 0; u16 port = 0;
u16 proto; u8 proto;
if (!skb->encapsulation) if (!skb->encapsulation)
return features; return features;
features = vxlan_features_check(skb, features); features = vxlan_features_check(skb, features);
/* hardware only supports IPv4 vxlan tunnel */ switch (vlan_get_protocol(skb)) {
if (vlan_get_protocol(skb) != htons(ETH_P_IP)) case htons(ETH_P_IPV6):
if (!(enic->vxlan.flags & ENIC_VXLAN_OUTER_IPV6))
goto out; goto out;
proto = ipv6_hdr(skb)->nexthdr;
/* hardware does not support offload of ipv6 inner pkt */ break;
if (eth->h_proto != ntohs(ETH_P_IP)) case htons(ETH_P_IP):
goto out;
proto = ip_hdr(skb)->protocol; proto = ip_hdr(skb)->protocol;
break;
default:
goto out;
}
switch (eth->h_proto) {
case ntohs(ETH_P_IPV6):
if (!(enic->vxlan.flags & ENIC_VXLAN_INNER_IPV6))
goto out;
/* Fall through */
case ntohs(ETH_P_IP):
break;
default:
goto out;
}
if (proto == IPPROTO_UDP) { if (proto == IPPROTO_UDP) {
udph = udp_hdr(skb); udph = udp_hdr(skb);
@ -635,12 +663,25 @@ static int enic_queue_wq_skb_csum_l4(struct enic *enic, struct vnic_wq *wq,
static void enic_preload_tcp_csum_encap(struct sk_buff *skb) static void enic_preload_tcp_csum_encap(struct sk_buff *skb)
{ {
if (skb->protocol == cpu_to_be16(ETH_P_IP)) { const struct ethhdr *eth = (struct ethhdr *)skb_inner_mac_header(skb);
switch (eth->h_proto) {
case ntohs(ETH_P_IP):
inner_ip_hdr(skb)->check = 0; inner_ip_hdr(skb)->check = 0;
inner_tcp_hdr(skb)->check = inner_tcp_hdr(skb)->check =
~csum_tcpudp_magic(inner_ip_hdr(skb)->saddr, ~csum_tcpudp_magic(inner_ip_hdr(skb)->saddr,
inner_ip_hdr(skb)->daddr, 0, inner_ip_hdr(skb)->daddr, 0,
IPPROTO_TCP, 0); IPPROTO_TCP, 0);
break;
case ntohs(ETH_P_IPV6):
inner_tcp_hdr(skb)->check =
~csum_ipv6_magic(&inner_ipv6_hdr(skb)->saddr,
&inner_ipv6_hdr(skb)->daddr, 0,
IPPROTO_TCP, 0);
break;
default:
WARN_ONCE(1, "Non ipv4/ipv6 inner pkt for encap offload");
break;
} }
} }
@ -1898,6 +1939,8 @@ static int enic_open(struct net_device *netdev)
} }
for (i = 0; i < enic->rq_count; i++) { for (i = 0; i < enic->rq_count; i++) {
/* enable rq before updating rq desc */
vnic_rq_enable(&enic->rq[i]);
vnic_rq_fill(&enic->rq[i], enic_rq_alloc_buf); vnic_rq_fill(&enic->rq[i], enic_rq_alloc_buf);
/* Need at least one buffer on ring to get going */ /* Need at least one buffer on ring to get going */
if (vnic_rq_desc_used(&enic->rq[i]) == 0) { if (vnic_rq_desc_used(&enic->rq[i]) == 0) {
@ -1909,8 +1952,6 @@ static int enic_open(struct net_device *netdev)
for (i = 0; i < enic->wq_count; i++) for (i = 0; i < enic->wq_count; i++)
vnic_wq_enable(&enic->wq[i]); vnic_wq_enable(&enic->wq[i]);
for (i = 0; i < enic->rq_count; i++)
vnic_rq_enable(&enic->rq[i]);
if (!enic_is_dynamic(enic) && !enic_is_sriov_vf(enic)) if (!enic_is_dynamic(enic) && !enic_is_sriov_vf(enic))
enic_dev_add_station_addr(enic); enic_dev_add_station_addr(enic);
@ -1936,8 +1977,12 @@ static int enic_open(struct net_device *netdev)
return 0; return 0;
err_out_free_rq: err_out_free_rq:
for (i = 0; i < enic->rq_count; i++) for (i = 0; i < enic->rq_count; i++) {
err = vnic_rq_disable(&enic->rq[i]);
if (err)
return err;
vnic_rq_clean(&enic->rq[i], enic_free_rq_buf); vnic_rq_clean(&enic->rq[i], enic_free_rq_buf);
}
enic_dev_notify_unset(enic); enic_dev_notify_unset(enic);
err_out_free_intr: err_out_free_intr:
enic_unset_affinity_hint(enic); enic_unset_affinity_hint(enic);
@ -2151,9 +2196,10 @@ static int enic_dev_wait(struct vnic_dev *vdev,
static int enic_dev_open(struct enic *enic) static int enic_dev_open(struct enic *enic)
{ {
int err; int err;
u32 flags = CMD_OPENF_IG_DESCCACHE;
err = enic_dev_wait(enic->vdev, vnic_dev_open, err = enic_dev_wait(enic->vdev, vnic_dev_open,
vnic_dev_open_done, 0); vnic_dev_open_done, flags);
if (err) if (err)
dev_err(enic_get_dev(enic), "vNIC device open failed, err %d\n", dev_err(enic_get_dev(enic), "vNIC device open failed, err %d\n",
err); err);
@ -2275,7 +2321,7 @@ static int enic_set_rss_nic_cfg(struct enic *enic)
{ {
struct device *dev = enic_get_dev(enic); struct device *dev = enic_get_dev(enic);
const u8 rss_default_cpu = 0; const u8 rss_default_cpu = 0;
const u8 rss_hash_type = NIC_CFG_RSS_HASH_TYPE_IPV4 | u8 rss_hash_type = NIC_CFG_RSS_HASH_TYPE_IPV4 |
NIC_CFG_RSS_HASH_TYPE_TCP_IPV4 | NIC_CFG_RSS_HASH_TYPE_TCP_IPV4 |
NIC_CFG_RSS_HASH_TYPE_IPV6 | NIC_CFG_RSS_HASH_TYPE_IPV6 |
NIC_CFG_RSS_HASH_TYPE_TCP_IPV6; NIC_CFG_RSS_HASH_TYPE_TCP_IPV6;
@ -2283,6 +2329,8 @@ static int enic_set_rss_nic_cfg(struct enic *enic)
const u8 rss_base_cpu = 0; const u8 rss_base_cpu = 0;
u8 rss_enable = ENIC_SETTING(enic, RSS) && (enic->rq_count > 1); u8 rss_enable = ENIC_SETTING(enic, RSS) && (enic->rq_count > 1);
if (vnic_dev_capable_udp_rss(enic->vdev))
rss_hash_type |= NIC_CFG_RSS_HASH_TYPE_UDP;
if (rss_enable) { if (rss_enable) {
if (!enic_set_rsskey(enic)) { if (!enic_set_rsskey(enic)) {
if (enic_set_rsscpu(enic, rss_hash_bits)) { if (enic_set_rsscpu(enic, rss_hash_bits)) {
@ -2901,9 +2949,11 @@ static int enic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
netdev->hw_features |= NETIF_F_RXCSUM; netdev->hw_features |= NETIF_F_RXCSUM;
if (ENIC_SETTING(enic, VXLAN)) { if (ENIC_SETTING(enic, VXLAN)) {
u64 patch_level; u64 patch_level;
u64 a1 = 0;
netdev->hw_enc_features |= NETIF_F_RXCSUM | netdev->hw_enc_features |= NETIF_F_RXCSUM |
NETIF_F_TSO | NETIF_F_TSO |
NETIF_F_TSO6 |
NETIF_F_TSO_ECN | NETIF_F_TSO_ECN |
NETIF_F_GSO_UDP_TUNNEL | NETIF_F_GSO_UDP_TUNNEL |
NETIF_F_HW_CSUM | NETIF_F_HW_CSUM |
@ -2922,9 +2972,10 @@ static int enic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
*/ */
err = vnic_dev_get_supported_feature_ver(enic->vdev, err = vnic_dev_get_supported_feature_ver(enic->vdev,
VIC_FEATURE_VXLAN, VIC_FEATURE_VXLAN,
&patch_level); &patch_level, &a1);
if (err) if (err)
patch_level = 0; patch_level = 0;
enic->vxlan.flags = (u8)a1;
/* mask bits that are supported by driver /* mask bits that are supported by driver
*/ */
patch_level &= BIT_ULL(0) | BIT_ULL(2); patch_level &= BIT_ULL(0) | BIT_ULL(2);

View File

@ -1269,16 +1269,32 @@ int vnic_dev_overlay_offload_cfg(struct vnic_dev *vdev, u8 overlay,
} }
int vnic_dev_get_supported_feature_ver(struct vnic_dev *vdev, u8 feature, int vnic_dev_get_supported_feature_ver(struct vnic_dev *vdev, u8 feature,
u64 *supported_versions) u64 *supported_versions, u64 *a1)
{ {
u64 a0 = feature; u64 a0 = feature;
int wait = 1000; int wait = 1000;
u64 a1 = 0;
int ret; int ret;
ret = vnic_dev_cmd(vdev, CMD_GET_SUPP_FEATURE_VER, &a0, &a1, wait); ret = vnic_dev_cmd(vdev, CMD_GET_SUPP_FEATURE_VER, &a0, a1, wait);
if (!ret) if (!ret)
*supported_versions = a0; *supported_versions = a0;
return ret; return ret;
} }
bool vnic_dev_capable_udp_rss(struct vnic_dev *vdev)
{
u64 a0 = CMD_NIC_CFG, a1 = 0;
u64 rss_hash_type;
int wait = 1000;
int err;
err = vnic_dev_cmd(vdev, CMD_CAPABILITY, &a0, &a1, wait);
if (err || !a0)
return 0;
rss_hash_type = (a1 >> NIC_CFG_RSS_HASH_TYPE_SHIFT) &
NIC_CFG_RSS_HASH_TYPE_MASK_FIELD;
return (rss_hash_type & NIC_CFG_RSS_HASH_TYPE_UDP);
}

View File

@ -183,6 +183,7 @@ int vnic_dev_overlay_offload_ctrl(struct vnic_dev *vdev, u8 overlay, u8 config);
int vnic_dev_overlay_offload_cfg(struct vnic_dev *vdev, u8 overlay, int vnic_dev_overlay_offload_cfg(struct vnic_dev *vdev, u8 overlay,
u16 vxlan_udp_port_number); u16 vxlan_udp_port_number);
int vnic_dev_get_supported_feature_ver(struct vnic_dev *vdev, u8 feature, int vnic_dev_get_supported_feature_ver(struct vnic_dev *vdev, u8 feature,
u64 *supported_versions); u64 *supported_versions, u64 *a1);
bool vnic_dev_capable_udp_rss(struct vnic_dev *vdev);
#endif /* _VNIC_DEV_H_ */ #endif /* _VNIC_DEV_H_ */

View File

@ -439,6 +439,7 @@ enum vnic_devcmd_cmd {
/* flags for CMD_OPEN */ /* flags for CMD_OPEN */
#define CMD_OPENF_OPROM 0x1 /* open coming from option rom */ #define CMD_OPENF_OPROM 0x1 /* open coming from option rom */
#define CMD_OPENF_IG_DESCCACHE 0x2 /* Do not flush IG DESC cache */
/* flags for CMD_INIT */ /* flags for CMD_INIT */
#define CMD_INITF_DEFAULT_MAC 0x1 /* init with default mac addr */ #define CMD_INITF_DEFAULT_MAC 0x1 /* init with default mac addr */
@ -697,6 +698,10 @@ enum overlay_ofld_cmd {
#define OVERLAY_CFG_VXLAN_PORT_UPDATE 0 #define OVERLAY_CFG_VXLAN_PORT_UPDATE 0
#define ENIC_VXLAN_INNER_IPV6 BIT(0)
#define ENIC_VXLAN_OUTER_IPV6 BIT(1)
#define ENIC_VXLAN_MULTI_WQ BIT(2)
/* Use this enum to get the supported versions for each of these features /* Use this enum to get the supported versions for each of these features
* If you need to use the devcmd_get_supported_feature_version(), add * If you need to use the devcmd_get_supported_feature_version(), add
* the new feature into this enum and install function handler in devcmd.c * the new feature into this enum and install function handler in devcmd.c

View File

@ -47,6 +47,7 @@
#define NIC_CFG_RSS_HASH_TYPE_TCP_IPV6 (1 << 4) #define NIC_CFG_RSS_HASH_TYPE_TCP_IPV6 (1 << 4)
#define NIC_CFG_RSS_HASH_TYPE_IPV6_EX (1 << 5) #define NIC_CFG_RSS_HASH_TYPE_IPV6_EX (1 << 5)
#define NIC_CFG_RSS_HASH_TYPE_TCP_IPV6_EX (1 << 6) #define NIC_CFG_RSS_HASH_TYPE_TCP_IPV6_EX (1 << 6)
#define NIC_CFG_RSS_HASH_TYPE_UDP (1 << 7)
static inline void vnic_set_nic_cfg(u32 *nic_cfg, static inline void vnic_set_nic_cfg(u32 *nic_cfg,
u8 rss_default_cpu, u8 rss_hash_type, u8 rss_default_cpu, u8 rss_hash_type,