Merge branch 'qed-ethtool-rss'
authorDavid S. Miller <davem@davemloft.net>
Thu, 14 Apr 2016 04:43:21 +0000 (00:43 -0400)
committerDavid S. Miller <davem@davemloft.net>
Thu, 14 Apr 2016 04:43:21 +0000 (00:43 -0400)
Yuval Mintz says:

====================
qed*: [mostly] Ethtool RSS configuration

Most of the content [code-wise] in this series is for allowing various
RSS-related configuration via ethtool.

In addition, this also removed an unnecessary versioning scheme between
the drivers and bump the driver version.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/qlogic/qed/qed.h
drivers/net/ethernet/qlogic/qed/qed_l2.c
drivers/net/ethernet/qlogic/qed/qed_main.c
drivers/net/ethernet/qlogic/qede/qede.h
drivers/net/ethernet/qlogic/qede/qede_ethtool.c
drivers/net/ethernet/qlogic/qede/qede_main.c
include/linux/qed/qed_eth_if.h
include/linux/qed/qed_if.h

index fcb8e9b..0f0d2d1 100644 (file)
@@ -26,7 +26,7 @@
 #include "qed_hsi.h"
 
 extern const struct qed_common_ops qed_common_ops_pass;
-#define DRV_MODULE_VERSION "8.7.0.0"
+#define DRV_MODULE_VERSION "8.7.1.20"
 
 #define MAX_HWFNS_PER_DEVICE    (4)
 #define NAME_SIZE 16
@@ -507,6 +507,4 @@ u32 qed_unzip_data(struct qed_hwfn *p_hwfn,
 
 int qed_slowpath_irq_req(struct qed_hwfn *hwfn);
 
-#define QED_ETH_INTERFACE_VERSION       300
-
 #endif /* _QED_H */
index 3f35c6c..5005497 100644 (file)
 #include "qed_reg_addr.h"
 #include "qed_sp.h"
 
-enum qed_rss_caps {
-       QED_RSS_IPV4            = 0x1,
-       QED_RSS_IPV6            = 0x2,
-       QED_RSS_IPV4_TCP        = 0x4,
-       QED_RSS_IPV6_TCP        = 0x8,
-       QED_RSS_IPV4_UDP        = 0x10,
-       QED_RSS_IPV6_UDP        = 0x20,
-};
-
-/* Should be the same as ETH_RSS_IND_TABLE_ENTRIES_NUM */
-#define QED_RSS_IND_TABLE_SIZE 128
-#define QED_RSS_KEY_SIZE 10 /* size in 32b chunks */
-
 struct qed_rss_params {
        u8      update_rss_config;
        u8      rss_enable;
@@ -1744,9 +1731,7 @@ static int qed_update_vport(struct qed_dev *cdev,
                sp_rss_params.update_rss_capabilities = 1;
                sp_rss_params.update_rss_ind_table = 1;
                sp_rss_params.update_rss_key = 1;
-               sp_rss_params.rss_caps = QED_RSS_IPV4 |
-                                        QED_RSS_IPV6 |
-                                        QED_RSS_IPV4_TCP | QED_RSS_IPV6_TCP;
+               sp_rss_params.rss_caps = params->rss_params.rss_caps;
                sp_rss_params.rss_table_size_log = 7; /* 2^7 = 128 */
                memcpy(sp_rss_params.rss_ind_table,
                       params->rss_params.rss_ind_table,
@@ -2043,14 +2028,8 @@ static const struct qed_eth_ops qed_eth_ops_pass = {
        .get_vport_stats = &qed_get_vport_stats,
 };
 
-const struct qed_eth_ops *qed_get_eth_ops(u32 version)
+const struct qed_eth_ops *qed_get_eth_ops(void)
 {
-       if (version != QED_ETH_INTERFACE_VERSION) {
-               pr_notice("Cannot supply ethtool operations [%08x != %08x]\n",
-                         version, QED_ETH_INTERFACE_VERSION);
-               return NULL;
-       }
-
        return &qed_eth_ops_pass;
 }
 EXPORT_SYMBOL(qed_get_eth_ops);
index 26d40db..c31d485 100644 (file)
@@ -1172,14 +1172,3 @@ const struct qed_common_ops qed_common_ops_pass = {
        .chain_free = &qed_chain_free,
        .set_led = &qed_set_led,
 };
-
-u32 qed_get_protocol_version(enum qed_protocol protocol)
-{
-       switch (protocol) {
-       case QED_PROTOCOL_ETH:
-               return QED_ETH_INTERFACE_VERSION;
-       default:
-               return 0;
-       }
-}
-EXPORT_SYMBOL(qed_get_protocol_version);
index d023251..41c4189 100644 (file)
 
 #define QEDE_MAJOR_VERSION             8
 #define QEDE_MINOR_VERSION             7
-#define QEDE_REVISION_VERSION          0
-#define QEDE_ENGINEERING_VERSION       0
+#define QEDE_REVISION_VERSION          1
+#define QEDE_ENGINEERING_VERSION       20
 #define DRV_MODULE_VERSION __stringify(QEDE_MAJOR_VERSION) "." \
                __stringify(QEDE_MINOR_VERSION) "."             \
                __stringify(QEDE_REVISION_VERSION) "."          \
                __stringify(QEDE_ENGINEERING_VERSION)
 
-#define QEDE_ETH_INTERFACE_VERSION     300
-
 #define DRV_MODULE_SYM         qede
 
 struct qede_stats {
@@ -156,6 +154,10 @@ struct qede_dev {
              SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))
 
        struct qede_stats               stats;
+#define QEDE_RSS_INDIR_INITED  BIT(0)
+#define QEDE_RSS_KEY_INITED    BIT(1)
+#define QEDE_RSS_CAPS_INITED   BIT(2)
+       u32 rss_params_inited; /* bit-field to track initialized rss params */
        struct qed_update_vport_rss_params      rss_params;
        u16                     q_num_rx_buffers; /* Must be a power of two */
        u16                     q_num_tx_buffers; /* Must be a power of two */
index c49dc10..f0982f1 100644 (file)
@@ -569,6 +569,236 @@ static int qede_set_phys_id(struct net_device *dev,
        return 0;
 }
 
+static int qede_get_rss_flags(struct qede_dev *edev, struct ethtool_rxnfc *info)
+{
+       info->data = RXH_IP_SRC | RXH_IP_DST;
+
+       switch (info->flow_type) {
+       case TCP_V4_FLOW:
+       case TCP_V6_FLOW:
+               info->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
+               break;
+       case UDP_V4_FLOW:
+               if (edev->rss_params.rss_caps & QED_RSS_IPV4_UDP)
+                       info->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
+               break;
+       case UDP_V6_FLOW:
+               if (edev->rss_params.rss_caps & QED_RSS_IPV6_UDP)
+                       info->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
+               break;
+       case IPV4_FLOW:
+       case IPV6_FLOW:
+               break;
+       default:
+               info->data = 0;
+               break;
+       }
+
+       return 0;
+}
+
+static int qede_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info,
+                         u32 *rules __always_unused)
+{
+       struct qede_dev *edev = netdev_priv(dev);
+
+       switch (info->cmd) {
+       case ETHTOOL_GRXRINGS:
+               info->data = edev->num_rss;
+               return 0;
+       case ETHTOOL_GRXFH:
+               return qede_get_rss_flags(edev, info);
+       default:
+               DP_ERR(edev, "Command parameters not supported\n");
+               return -EOPNOTSUPP;
+       }
+}
+
+static int qede_set_rss_flags(struct qede_dev *edev, struct ethtool_rxnfc *info)
+{
+       struct qed_update_vport_params vport_update_params;
+       u8 set_caps = 0, clr_caps = 0;
+
+       DP_VERBOSE(edev, QED_MSG_DEBUG,
+                  "Set rss flags command parameters: flow type = %d, data = %llu\n",
+                  info->flow_type, info->data);
+
+       switch (info->flow_type) {
+       case TCP_V4_FLOW:
+       case TCP_V6_FLOW:
+               /* For TCP only 4-tuple hash is supported */
+               if (info->data ^ (RXH_IP_SRC | RXH_IP_DST |
+                                 RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
+                       DP_INFO(edev, "Command parameters not supported\n");
+                       return -EINVAL;
+               }
+               return 0;
+       case UDP_V4_FLOW:
+               /* For UDP either 2-tuple hash or 4-tuple hash is supported */
+               if (info->data == (RXH_IP_SRC | RXH_IP_DST |
+                                  RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
+                       set_caps = QED_RSS_IPV4_UDP;
+                       DP_VERBOSE(edev, QED_MSG_DEBUG,
+                                  "UDP 4-tuple enabled\n");
+               } else if (info->data == (RXH_IP_SRC | RXH_IP_DST)) {
+                       clr_caps = QED_RSS_IPV4_UDP;
+                       DP_VERBOSE(edev, QED_MSG_DEBUG,
+                                  "UDP 4-tuple disabled\n");
+               } else {
+                       return -EINVAL;
+               }
+               break;
+       case UDP_V6_FLOW:
+               /* For UDP either 2-tuple hash or 4-tuple hash is supported */
+               if (info->data == (RXH_IP_SRC | RXH_IP_DST |
+                                  RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
+                       set_caps = QED_RSS_IPV6_UDP;
+                       DP_VERBOSE(edev, QED_MSG_DEBUG,
+                                  "UDP 4-tuple enabled\n");
+               } else if (info->data == (RXH_IP_SRC | RXH_IP_DST)) {
+                       clr_caps = QED_RSS_IPV6_UDP;
+                       DP_VERBOSE(edev, QED_MSG_DEBUG,
+                                  "UDP 4-tuple disabled\n");
+               } else {
+                       return -EINVAL;
+               }
+               break;
+       case IPV4_FLOW:
+       case IPV6_FLOW:
+               /* For IP only 2-tuple hash is supported */
+               if (info->data ^ (RXH_IP_SRC | RXH_IP_DST)) {
+                       DP_INFO(edev, "Command parameters not supported\n");
+                       return -EINVAL;
+               }
+               return 0;
+       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 IP_USER_FLOW:
+       case ETHER_FLOW:
+               /* RSS is not supported for these protocols */
+               if (info->data) {
+                       DP_INFO(edev, "Command parameters not supported\n");
+                       return -EINVAL;
+               }
+               return 0;
+       default:
+               return -EINVAL;
+       }
+
+       /* No action is needed if there is no change in the rss capability */
+       if (edev->rss_params.rss_caps == ((edev->rss_params.rss_caps &
+                                          ~clr_caps) | set_caps))
+               return 0;
+
+       /* Update internal configuration */
+       edev->rss_params.rss_caps = (edev->rss_params.rss_caps & ~clr_caps) |
+                                   set_caps;
+       edev->rss_params_inited |= QEDE_RSS_CAPS_INITED;
+
+       /* Re-configure if possible */
+       if (netif_running(edev->ndev)) {
+               memset(&vport_update_params, 0, sizeof(vport_update_params));
+               vport_update_params.update_rss_flg = 1;
+               vport_update_params.vport_id = 0;
+               memcpy(&vport_update_params.rss_params, &edev->rss_params,
+                      sizeof(vport_update_params.rss_params));
+               return edev->ops->vport_update(edev->cdev,
+                                              &vport_update_params);
+       }
+
+       return 0;
+}
+
+static int qede_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info)
+{
+       struct qede_dev *edev = netdev_priv(dev);
+
+       switch (info->cmd) {
+       case ETHTOOL_SRXFH:
+               return qede_set_rss_flags(edev, info);
+       default:
+               DP_INFO(edev, "Command parameters not supported\n");
+               return -EOPNOTSUPP;
+       }
+}
+
+static u32 qede_get_rxfh_indir_size(struct net_device *dev)
+{
+       return QED_RSS_IND_TABLE_SIZE;
+}
+
+static u32 qede_get_rxfh_key_size(struct net_device *dev)
+{
+       struct qede_dev *edev = netdev_priv(dev);
+
+       return sizeof(edev->rss_params.rss_key);
+}
+
+static int qede_get_rxfh(struct net_device *dev, u32 *indir, u8 *key, u8 *hfunc)
+{
+       struct qede_dev *edev = netdev_priv(dev);
+       int i;
+
+       if (hfunc)
+               *hfunc = ETH_RSS_HASH_TOP;
+
+       if (!indir)
+               return 0;
+
+       for (i = 0; i < QED_RSS_IND_TABLE_SIZE; i++)
+               indir[i] = edev->rss_params.rss_ind_table[i];
+
+       if (key)
+               memcpy(key, edev->rss_params.rss_key,
+                      qede_get_rxfh_key_size(dev));
+
+       return 0;
+}
+
+static int qede_set_rxfh(struct net_device *dev, const u32 *indir,
+                        const u8 *key, const u8 hfunc)
+{
+       struct qed_update_vport_params vport_update_params;
+       struct qede_dev *edev = netdev_priv(dev);
+       int i;
+
+       if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)
+               return -EOPNOTSUPP;
+
+       if (!indir && !key)
+               return 0;
+
+       if (indir) {
+               for (i = 0; i < QED_RSS_IND_TABLE_SIZE; i++)
+                       edev->rss_params.rss_ind_table[i] = indir[i];
+               edev->rss_params_inited |= QEDE_RSS_INDIR_INITED;
+       }
+
+       if (key) {
+               memcpy(&edev->rss_params.rss_key, key,
+                      qede_get_rxfh_key_size(dev));
+               edev->rss_params_inited |= QEDE_RSS_KEY_INITED;
+       }
+
+       if (netif_running(edev->ndev)) {
+               memset(&vport_update_params, 0, sizeof(vport_update_params));
+               vport_update_params.update_rss_flg = 1;
+               vport_update_params.vport_id = 0;
+               memcpy(&vport_update_params.rss_params, &edev->rss_params,
+                      sizeof(vport_update_params.rss_params));
+               return edev->ops->vport_update(edev->cdev,
+                                              &vport_update_params);
+       }
+
+       return 0;
+}
+
 static const struct ethtool_ops qede_ethtool_ops = {
        .get_settings = qede_get_settings,
        .set_settings = qede_set_settings,
@@ -585,7 +815,12 @@ static const struct ethtool_ops qede_ethtool_ops = {
        .set_phys_id = qede_set_phys_id,
        .get_ethtool_stats = qede_get_ethtool_stats,
        .get_sset_count = qede_get_sset_count,
-
+       .get_rxnfc = qede_get_rxnfc,
+       .set_rxnfc = qede_set_rxnfc,
+       .get_rxfh_indir_size = qede_get_rxfh_indir_size,
+       .get_rxfh_key_size = qede_get_rxfh_key_size,
+       .get_rxfh = qede_get_rxfh,
+       .set_rxfh = qede_set_rxfh,
        .get_channels = qede_get_channels,
        .set_channels = qede_set_channels,
 };
index 518af32..457caad 100644 (file)
@@ -141,19 +141,10 @@ static
 int __init qede_init(void)
 {
        int ret;
-       u32 qed_ver;
 
        pr_notice("qede_init: %s\n", version);
 
-       qed_ver = qed_get_protocol_version(QED_PROTOCOL_ETH);
-       if (qed_ver !=  QEDE_ETH_INTERFACE_VERSION) {
-               pr_notice("Version mismatch [%08x != %08x]\n",
-                         qed_ver,
-                         QEDE_ETH_INTERFACE_VERSION);
-               return -EINVAL;
-       }
-
-       qed_ops = qed_get_eth_ops(QEDE_ETH_INTERFACE_VERSION);
+       qed_ops = qed_get_eth_ops();
        if (!qed_ops) {
                pr_notice("Failed to get qed ethtool operations\n");
                return -EINVAL;
@@ -2835,10 +2826,10 @@ static int qede_start_queues(struct qede_dev *edev)
        int rc, tc, i;
        int vlan_removal_en = 1;
        struct qed_dev *cdev = edev->cdev;
-       struct qed_update_vport_rss_params *rss_params = &edev->rss_params;
        struct qed_update_vport_params vport_update_params;
        struct qed_queue_start_common_params q_params;
        struct qed_start_vport_params start = {0};
+       bool reset_rss_indir = false;
 
        if (!edev->num_rss) {
                DP_ERR(edev,
@@ -2933,16 +2924,50 @@ static int qede_start_queues(struct qede_dev *edev)
        /* Fill struct with RSS params */
        if (QEDE_RSS_CNT(edev) > 1) {
                vport_update_params.update_rss_flg = 1;
-               for (i = 0; i < 128; i++)
-                       rss_params->rss_ind_table[i] =
-                       ethtool_rxfh_indir_default(i, QEDE_RSS_CNT(edev));
-               netdev_rss_key_fill(rss_params->rss_key,
-                                   sizeof(rss_params->rss_key));
+
+               /* Need to validate current RSS config uses valid entries */
+               for (i = 0; i < QED_RSS_IND_TABLE_SIZE; i++) {
+                       if (edev->rss_params.rss_ind_table[i] >=
+                           edev->num_rss) {
+                               reset_rss_indir = true;
+                               break;
+                       }
+               }
+
+               if (!(edev->rss_params_inited & QEDE_RSS_INDIR_INITED) ||
+                   reset_rss_indir) {
+                       u16 val;
+
+                       for (i = 0; i < QED_RSS_IND_TABLE_SIZE; i++) {
+                               u16 indir_val;
+
+                               val = QEDE_RSS_CNT(edev);
+                               indir_val = ethtool_rxfh_indir_default(i, val);
+                               edev->rss_params.rss_ind_table[i] = indir_val;
+                       }
+                       edev->rss_params_inited |= QEDE_RSS_INDIR_INITED;
+               }
+
+               if (!(edev->rss_params_inited & QEDE_RSS_KEY_INITED)) {
+                       netdev_rss_key_fill(edev->rss_params.rss_key,
+                                           sizeof(edev->rss_params.rss_key));
+                       edev->rss_params_inited |= QEDE_RSS_KEY_INITED;
+               }
+
+               if (!(edev->rss_params_inited & QEDE_RSS_CAPS_INITED)) {
+                       edev->rss_params.rss_caps = QED_RSS_IPV4 |
+                                                   QED_RSS_IPV6 |
+                                                   QED_RSS_IPV4_TCP |
+                                                   QED_RSS_IPV6_TCP;
+                       edev->rss_params_inited |= QEDE_RSS_CAPS_INITED;
+               }
+
+               memcpy(&vport_update_params.rss_params, &edev->rss_params,
+                      sizeof(vport_update_params.rss_params));
        } else {
-               memset(rss_params, 0, sizeof(*rss_params));
+               memset(&vport_update_params.rss_params, 0,
+                      sizeof(vport_update_params.rss_params));
        }
-       memcpy(&vport_update_params.rss_params, rss_params,
-              sizeof(*rss_params));
 
        rc = edev->ops->vport_update(cdev, &vport_update_params);
        if (rc) {
index e1d6983..795c990 100644 (file)
@@ -27,6 +27,7 @@ struct qed_dev_eth_info {
 struct qed_update_vport_rss_params {
        u16     rss_ind_table[128];
        u32     rss_key[10];
+       u8      rss_caps;
 };
 
 struct qed_update_vport_params {
@@ -167,7 +168,7 @@ struct qed_eth_ops {
                                struct qed_eth_stats *stats);
 };
 
-const struct qed_eth_ops *qed_get_eth_ops(u32 version);
+const struct qed_eth_ops *qed_get_eth_ops(void);
 void qed_put_eth_ops(void);
 
 #endif
index 1f7599c..67e8c20 100644 (file)
@@ -271,15 +271,6 @@ struct qed_common_ops {
                       enum qed_led_mode mode);
 };
 
-/**
- * @brief qed_get_protocol_version
- *
- * @param protocol
- *
- * @return version supported by qed for given protocol driver
- */
-u32 qed_get_protocol_version(enum qed_protocol protocol);
-
 #define MASK_FIELD(_name, _value) \
        ((_value) &= (_name ## _MASK))
 
@@ -524,4 +515,15 @@ static inline void internal_ram_wr(void __iomem *addr,
        __internal_ram_wr(NULL, addr, size, data);
 }
 
+enum qed_rss_caps {
+       QED_RSS_IPV4            = 0x1,
+       QED_RSS_IPV6            = 0x2,
+       QED_RSS_IPV4_TCP        = 0x4,
+       QED_RSS_IPV6_TCP        = 0x8,
+       QED_RSS_IPV4_UDP        = 0x10,
+       QED_RSS_IPV6_UDP        = 0x20,
+};
+
+#define QED_RSS_IND_TABLE_SIZE 128
+#define QED_RSS_KEY_SIZE 10 /* size in 32b chunks */
 #endif