qede: Add getter APIs support for RX flow classification
authorChopra, Manish <Manish.Chopra@cavium.com>
Wed, 26 Jul 2017 13:07:09 +0000 (06:07 -0700)
committerDavid S. Miller <davem@davemloft.net>
Thu, 27 Jul 2017 07:05:22 +0000 (00:05 -0700)
This patch adds support for ethtool getter APIs to query
RX flow classification rules.

Signed-off-by: Manish Chopra <manish.chopra@cavium.com>
Signed-off-by: Yuval Mintz <yuval.mintz@cavium.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/qlogic/qede/qede.h
drivers/net/ethernet/qlogic/qede/qede_ethtool.c
drivers/net/ethernet/qlogic/qede/qede_filter.c

index 4dfb238..0a2475b 100644 (file)
@@ -160,6 +160,8 @@ struct qede_rdma_dev {
 
 struct qede_ptp;
 
+#define QEDE_RFS_MAX_FLTR      256
+
 struct qede_dev {
        struct qed_dev                  *cdev;
        struct net_device               *ndev;
@@ -241,9 +243,7 @@ struct qede_dev {
        u16                             vxlan_dst_port;
        u16                             geneve_dst_port;
 
-#ifdef CONFIG_RFS_ACCEL
        struct qede_arfs                *arfs;
-#endif
        bool                            wol_enabled;
 
        struct qede_rdma_dev            rdma_info;
@@ -455,9 +455,13 @@ int qede_alloc_arfs(struct qede_dev *edev);
 
 #define QEDE_SP_ARFS_CONFIG    4
 #define QEDE_SP_TASK_POLL_DELAY        (5 * HZ)
-#define QEDE_RFS_MAX_FLTR      256
 #endif
 
+int qede_get_cls_rule_entry(struct qede_dev *edev, struct ethtool_rxnfc *cmd);
+int qede_get_cls_rule_all(struct qede_dev *edev, struct ethtool_rxnfc *info,
+                         u32 *rule_locs);
+int qede_get_arfs_filter_count(struct qede_dev *edev);
+
 struct qede_reload_args {
        void (*func)(struct qede_dev *edev, struct qede_reload_args *args);
        union {
index 6a03d3e..dd39dec 100644 (file)
@@ -1045,20 +1045,34 @@ static int qede_get_rss_flags(struct qede_dev *edev, struct ethtool_rxnfc *info)
 }
 
 static int qede_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info,
-                         u32 *rules __always_unused)
+                         u32 *rule_locs)
 {
        struct qede_dev *edev = netdev_priv(dev);
+       int rc = 0;
 
        switch (info->cmd) {
        case ETHTOOL_GRXRINGS:
                info->data = QEDE_RSS_COUNT(edev);
-               return 0;
+               break;
        case ETHTOOL_GRXFH:
-               return qede_get_rss_flags(edev, info);
+               rc = qede_get_rss_flags(edev, info);
+               break;
+       case ETHTOOL_GRXCLSRLCNT:
+               info->rule_cnt = qede_get_arfs_filter_count(edev);
+               info->data = QEDE_RFS_MAX_FLTR;
+               break;
+       case ETHTOOL_GRXCLSRULE:
+               rc = qede_get_cls_rule_entry(edev, info);
+               break;
+       case ETHTOOL_GRXCLSRLALL:
+               rc = qede_get_cls_rule_all(edev, info, rule_locs);
+               break;
        default:
                DP_ERR(edev, "Command parameters not supported\n");
-               return -EOPNOTSUPP;
+               rc = -EOPNOTSUPP;
        }
+
+       return rc;
 }
 
 static int qede_set_rss_flags(struct qede_dev *edev, struct ethtool_rxnfc *info)
index f939db5..a5e5d32 100644 (file)
@@ -38,7 +38,6 @@
 #include <linux/qed/qed_if.h>
 #include "qede.h"
 
-#ifdef CONFIG_RFS_ACCEL
 struct qede_arfs_tuple {
        union {
                __be32 src_ipv4;
@@ -80,6 +79,7 @@ struct qede_arfs_fltr_node {
 };
 
 struct qede_arfs {
+#define QEDE_ARFS_BUCKET_HEAD(edev, idx) (&(edev)->arfs->arfs_hl_head[idx])
 #define QEDE_ARFS_POLL_COUNT   100
 #define QEDE_RFS_FLW_BITSHIFT  (4)
 #define QEDE_RFS_FLW_MASK      ((1 << QEDE_RFS_FLW_BITSHIFT) - 1)
@@ -92,6 +92,7 @@ struct qede_arfs {
        bool                    enable;
 };
 
+#ifdef CONFIG_RFS_ACCEL
 static void qede_configure_arfs_fltr(struct qede_dev *edev,
                                     struct qede_arfs_fltr_node *n,
                                     u16 rxq_id, bool add_fltr)
@@ -1263,3 +1264,120 @@ void qede_config_rx_mode(struct net_device *ndev)
 out:
        kfree(uc_macs);
 }
+
+static struct qede_arfs_fltr_node *
+qede_get_arfs_fltr_by_loc(struct hlist_head *head, u32 location)
+{
+       struct qede_arfs_fltr_node *fltr;
+
+       hlist_for_each_entry(fltr, head, node)
+               if (location == fltr->sw_id)
+                       return fltr;
+
+       return NULL;
+}
+
+int qede_get_cls_rule_all(struct qede_dev *edev, struct ethtool_rxnfc *info,
+                         u32 *rule_locs)
+{
+       struct qede_arfs_fltr_node *fltr;
+       struct hlist_head *head;
+       int cnt = 0, rc = 0;
+
+       info->data = QEDE_RFS_MAX_FLTR;
+
+       __qede_lock(edev);
+
+       if (!edev->arfs) {
+               rc = -EPERM;
+               goto unlock;
+       }
+
+       head = QEDE_ARFS_BUCKET_HEAD(edev, 0);
+
+       hlist_for_each_entry(fltr, head, node) {
+               if (cnt == info->rule_cnt) {
+                       rc = -EMSGSIZE;
+                       goto unlock;
+               }
+
+               rule_locs[cnt] = fltr->sw_id;
+               cnt++;
+       }
+
+       info->rule_cnt = cnt;
+
+unlock:
+       __qede_unlock(edev);
+       return rc;
+}
+
+int qede_get_cls_rule_entry(struct qede_dev *edev, struct ethtool_rxnfc *cmd)
+{
+       struct ethtool_rx_flow_spec *fsp = &cmd->fs;
+       struct qede_arfs_fltr_node *fltr = NULL;
+       int rc = 0;
+
+       cmd->data = QEDE_RFS_MAX_FLTR;
+
+       __qede_lock(edev);
+
+       if (!edev->arfs) {
+               rc = -EPERM;
+               goto unlock;
+       }
+
+       fltr = qede_get_arfs_fltr_by_loc(QEDE_ARFS_BUCKET_HEAD(edev, 0),
+                                        fsp->location);
+       if (!fltr) {
+               DP_NOTICE(edev, "Rule not found - location=0x%x\n",
+                         fsp->location);
+               rc = -EINVAL;
+               goto unlock;
+       }
+
+       if (fltr->tuple.eth_proto == htons(ETH_P_IP)) {
+               if (fltr->tuple.ip_proto == IPPROTO_TCP)
+                       fsp->flow_type = TCP_V4_FLOW;
+               else
+                       fsp->flow_type = UDP_V4_FLOW;
+
+               fsp->h_u.tcp_ip4_spec.psrc = fltr->tuple.src_port;
+               fsp->h_u.tcp_ip4_spec.pdst = fltr->tuple.dst_port;
+               fsp->h_u.tcp_ip4_spec.ip4src = fltr->tuple.src_ipv4;
+               fsp->h_u.tcp_ip4_spec.ip4dst = fltr->tuple.dst_ipv4;
+       } else {
+               if (fltr->tuple.ip_proto == IPPROTO_TCP)
+                       fsp->flow_type = TCP_V6_FLOW;
+               else
+                       fsp->flow_type = UDP_V6_FLOW;
+               fsp->h_u.tcp_ip6_spec.psrc = fltr->tuple.src_port;
+               fsp->h_u.tcp_ip6_spec.pdst = fltr->tuple.dst_port;
+               memcpy(&fsp->h_u.tcp_ip6_spec.ip6src,
+                      &fltr->tuple.src_ipv6, sizeof(struct in6_addr));
+               memcpy(&fsp->h_u.tcp_ip6_spec.ip6dst,
+                      &fltr->tuple.dst_ipv6, sizeof(struct in6_addr));
+       }
+
+       fsp->ring_cookie = fltr->rxq_id;
+
+unlock:
+       __qede_unlock(edev);
+       return rc;
+}
+
+int qede_get_arfs_filter_count(struct qede_dev *edev)
+{
+       int count = 0;
+
+       __qede_lock(edev);
+
+       if (!edev->arfs)
+               goto unlock;
+
+       count = edev->arfs->filter_count;
+
+unlock:
+       __qede_unlock(edev);
+       return count;
+}