enic: fix UDP rss bits
authorGovindarajulu Varadarajan <gvaradar@cisco.com>
Tue, 5 Jun 2018 17:14:57 +0000 (10:14 -0700)
committerDavid S. Miller <davem@davemloft.net>
Wed, 6 Jun 2018 13:09:09 +0000 (09:09 -0400)
In commit 48398b6e7065 ("enic: set UDP rss flag") driver needed to set a
single bit to enable UDP rss. This is changed to two bit. One for UDP
IPv4 and other bit for UDP IPv6. The hardware which supports this is not
released yet. When released, driver should set 2 bit to enable UDP rss for
both IPv4 and IPv6.

Also add spinlock around vnic_dev_capable_rss_hash_type().

Signed-off-by: Govindarajulu Varadarajan <gvaradar@cisco.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/cisco/enic/enic_ethtool.c
drivers/net/ethernet/cisco/enic/enic_main.c
drivers/net/ethernet/cisco/enic/enic_res.c
drivers/net/ethernet/cisco/enic/vnic_dev.c
drivers/net/ethernet/cisco/enic/vnic_dev.h
drivers/net/ethernet/cisco/enic/vnic_devcmd.h
drivers/net/ethernet/cisco/enic/vnic_nic.h

index 869006c2002d3be453f2443fd69cb6d07fbee4b2..f42f7a6e1559134cabb1a4b568406e803aa31b1f 100644 (file)
@@ -476,18 +476,28 @@ static int enic_grxclsrule(struct enic *enic, struct ethtool_rxnfc *cmd)
 
 static int enic_get_rx_flow_hash(struct enic *enic, struct ethtool_rxnfc *cmd)
 {
+       u8 rss_hash_type = 0;
        cmd->data = 0;
 
+       spin_lock_bh(&enic->devcmd_lock);
+       (void)vnic_dev_capable_rss_hash_type(enic->vdev, &rss_hash_type);
+       spin_unlock_bh(&enic->devcmd_lock);
        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 */
+               cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3 |
+                            RXH_IP_SRC | RXH_IP_DST;
+               break;
        case UDP_V6_FLOW:
+               cmd->data |= RXH_IP_SRC | RXH_IP_DST;
+               if (rss_hash_type & NIC_CFG_RSS_HASH_TYPE_UDP_IPV6)
+                       cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
+               break;
        case UDP_V4_FLOW:
-               if (vnic_dev_capable_udp_rss(enic->vdev))
+               cmd->data |= RXH_IP_SRC | RXH_IP_DST;
+               if (rss_hash_type & NIC_CFG_RSS_HASH_TYPE_UDP_IPV4)
                        cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
-               /* Fall through */
+               break;
        case SCTP_V4_FLOW:
        case AH_ESP_V4_FLOW:
        case AH_V4_FLOW:
index 8a8b12b720ef99bb923a3a441c933ee36e596e80..30d2eaa18c0479adcd75315db194d3785b8007bc 100644 (file)
@@ -2320,16 +2320,24 @@ static int enic_set_rss_nic_cfg(struct enic *enic)
 {
        struct device *dev = enic_get_dev(enic);
        const u8 rss_default_cpu = 0;
-       u8 rss_hash_type = NIC_CFG_RSS_HASH_TYPE_IPV4 |
-               NIC_CFG_RSS_HASH_TYPE_TCP_IPV4 |
-               NIC_CFG_RSS_HASH_TYPE_IPV6 |
-               NIC_CFG_RSS_HASH_TYPE_TCP_IPV6;
        const u8 rss_hash_bits = 7;
        const u8 rss_base_cpu = 0;
+       u8 rss_hash_type;
+       int res;
        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;
+       spin_lock_bh(&enic->devcmd_lock);
+       res = vnic_dev_capable_rss_hash_type(enic->vdev, &rss_hash_type);
+       spin_unlock_bh(&enic->devcmd_lock);
+       if (res) {
+               /* defaults for old adapters
+                */
+               rss_hash_type = NIC_CFG_RSS_HASH_TYPE_IPV4      |
+                               NIC_CFG_RSS_HASH_TYPE_TCP_IPV4  |
+                               NIC_CFG_RSS_HASH_TYPE_IPV6      |
+                               NIC_CFG_RSS_HASH_TYPE_TCP_IPV6;
+       }
+
        if (rss_enable) {
                if (!enic_set_rsskey(enic)) {
                        if (enic_set_rsscpu(enic, rss_hash_bits)) {
index 9c96911fb2c8a7dc0bfb2df8e2c9398c15aa4132..40b20817ddd569caf8cea4130d11b9eeb2c559dd 100644 (file)
@@ -149,6 +149,7 @@ int enic_set_nic_cfg(struct enic *enic, u8 rss_default_cpu, u8 rss_hash_type,
        u8 rss_hash_bits, u8 rss_base_cpu, u8 rss_enable, u8 tso_ipid_split_en,
        u8 ig_vlan_strip_en)
 {
+       enum vnic_devcmd_cmd cmd = CMD_NIC_CFG;
        u64 a0, a1;
        u32 nic_cfg;
        int wait = 1000;
@@ -160,7 +161,11 @@ int enic_set_nic_cfg(struct enic *enic, u8 rss_default_cpu, u8 rss_hash_type,
        a0 = nic_cfg;
        a1 = 0;
 
-       return vnic_dev_cmd(enic->vdev, CMD_NIC_CFG, &a0, &a1, wait);
+       if (rss_hash_type & (NIC_CFG_RSS_HASH_TYPE_UDP_IPV4 |
+                            NIC_CFG_RSS_HASH_TYPE_UDP_IPV6))
+               cmd = CMD_NIC_CFG_CHK;
+
+       return vnic_dev_cmd(enic->vdev, cmd, &a0, &a1, wait);
 }
 
 int enic_set_rss_key(struct enic *enic, dma_addr_t key_pa, u64 len)
index 76cdd4c9d11f3e64c33102d3e1b145f45c57762a..e9db811df59c01f0c0dc96827039936273159401 100644 (file)
@@ -1282,19 +1282,23 @@ int vnic_dev_get_supported_feature_ver(struct vnic_dev *vdev, u8 feature,
        return ret;
 }
 
-bool vnic_dev_capable_udp_rss(struct vnic_dev *vdev)
+int vnic_dev_capable_rss_hash_type(struct vnic_dev *vdev, u8 *rss_hash_type)
 {
        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 false;
+       /* rss_hash_type is valid only when a0 is 1. Adapter which does not
+        * support CMD_CAPABILITY for rss_hash_type has a0 = 0
+        */
+       if (err || (a0 != 1))
+               return -EOPNOTSUPP;
+
+       a1 = (a1 >> NIC_CFG_RSS_HASH_TYPE_SHIFT) &
+            NIC_CFG_RSS_HASH_TYPE_MASK_FIELD;
 
-       rss_hash_type = (a1 >> NIC_CFG_RSS_HASH_TYPE_SHIFT) &
-                       NIC_CFG_RSS_HASH_TYPE_MASK_FIELD;
+       *rss_hash_type = (u8)a1;
 
-       return (rss_hash_type & NIC_CFG_RSS_HASH_TYPE_UDP);
+       return 0;
 }
index 59d4cc8fbb85b21f4ce37e39a64066112db68844..714fc1ed79e32a881e3666cd9e3f8bc6789d6d85 100644 (file)
@@ -184,6 +184,6 @@ int vnic_dev_overlay_offload_cfg(struct vnic_dev *vdev, u8 overlay,
                                 u16 vxlan_udp_port_number);
 int vnic_dev_get_supported_feature_ver(struct vnic_dev *vdev, u8 feature,
                                       u64 *supported_versions, u64 *a1);
-bool vnic_dev_capable_udp_rss(struct vnic_dev *vdev);
+int vnic_dev_capable_rss_hash_type(struct vnic_dev *vdev, u8 *rss_hash_type);
 
 #endif /* _VNIC_DEV_H_ */
index 41de4ba622a1605db7d4d35e1c5f6f105f5db1aa..fef5a0a0663d8cf5a79683a8173e11433ac8d1ec 100644 (file)
@@ -148,8 +148,26 @@ enum vnic_devcmd_cmd {
        /* del VLAN id in (u16)a0 */
        CMD_VLAN_DEL            = _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 15),
 
-       /* nic_cfg in (u32)a0 */
+       /* nic_cfg (no wait, always succeeds)
+        * in: (u32)a0
+        *
+        * Capability query:
+        * out: (u64) a0 = 1 if a1 is valid
+        *      (u64) a1 = (NIC_CFG bits supported) | (flags << 32)
+        *
+        * flags are CMD_NIC_CFG_CAPF_xxx
+        */
        CMD_NIC_CFG             = _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ALL, 16),
+       /* nic_cfg_chk (will return error if flags are invalid)
+        * in: (u32)a0
+        *
+        * Capability query:
+        * out: (u64) a0 = 1 if a1 is valid
+        *      (u64) a1 = (NIC_CFG bits supported) | (flags << 32)
+        *
+        * flags are CMD_NIC_CFG_CAPF_xxx
+        */
+       CMD_NIC_CFG_CHK         = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ALL, 16),
 
        /* union vnic_rss_key in mem: (u64)a0=paddr, (u16)a1=len */
        CMD_RSS_KEY             = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 17),
index 5a93db0d7afcaee53e6f5cd47a9c00d1e6672845..84ff8ca17fcb13e1410a7ec0459e279904221f88 100644 (file)
 #define NIC_CFG_IG_VLAN_STRIP_EN_MASK_FIELD    1UL
 #define NIC_CFG_IG_VLAN_STRIP_EN_SHIFT         24
 
+#define NIC_CFG_RSS_HASH_TYPE_UDP_IPV4         (1 << 0)
 #define NIC_CFG_RSS_HASH_TYPE_IPV4             (1 << 1)
 #define NIC_CFG_RSS_HASH_TYPE_TCP_IPV4         (1 << 2)
 #define NIC_CFG_RSS_HASH_TYPE_IPV6             (1 << 3)
 #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_TCP_IPV6_EX      (1 << 6)
-#define NIC_CFG_RSS_HASH_TYPE_UDP              (1 << 7)
+#define NIC_CFG_RSS_HASH_TYPE_UDP_IPV6         (1 << 7)
 
 static inline void vnic_set_nic_cfg(u32 *nic_cfg,
        u8 rss_default_cpu, u8 rss_hash_type,