Commit ec9b8dbd authored by Chopra, Manish's avatar Chopra, Manish Committed by David S. Miller

qede: Add getter APIs support for RX flow classification

This patch adds support for ethtool getter APIs to query
RX flow classification rules.
Signed-off-by: default avatarManish Chopra <manish.chopra@cavium.com>
Signed-off-by: default avatarYuval Mintz <yuval.mintz@cavium.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent e27a8792
...@@ -160,6 +160,8 @@ struct qede_rdma_dev { ...@@ -160,6 +160,8 @@ struct qede_rdma_dev {
struct qede_ptp; struct qede_ptp;
#define QEDE_RFS_MAX_FLTR 256
struct qede_dev { struct qede_dev {
struct qed_dev *cdev; struct qed_dev *cdev;
struct net_device *ndev; struct net_device *ndev;
...@@ -241,9 +243,7 @@ struct qede_dev { ...@@ -241,9 +243,7 @@ struct qede_dev {
u16 vxlan_dst_port; u16 vxlan_dst_port;
u16 geneve_dst_port; u16 geneve_dst_port;
#ifdef CONFIG_RFS_ACCEL
struct qede_arfs *arfs; struct qede_arfs *arfs;
#endif
bool wol_enabled; bool wol_enabled;
struct qede_rdma_dev rdma_info; struct qede_rdma_dev rdma_info;
...@@ -455,9 +455,13 @@ int qede_alloc_arfs(struct qede_dev *edev); ...@@ -455,9 +455,13 @@ int qede_alloc_arfs(struct qede_dev *edev);
#define QEDE_SP_ARFS_CONFIG 4 #define QEDE_SP_ARFS_CONFIG 4
#define QEDE_SP_TASK_POLL_DELAY (5 * HZ) #define QEDE_SP_TASK_POLL_DELAY (5 * HZ)
#define QEDE_RFS_MAX_FLTR 256
#endif #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 { struct qede_reload_args {
void (*func)(struct qede_dev *edev, struct qede_reload_args *args); void (*func)(struct qede_dev *edev, struct qede_reload_args *args);
union { union {
......
...@@ -1045,20 +1045,34 @@ static int qede_get_rss_flags(struct qede_dev *edev, struct ethtool_rxnfc *info) ...@@ -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, 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); struct qede_dev *edev = netdev_priv(dev);
int rc = 0;
switch (info->cmd) { switch (info->cmd) {
case ETHTOOL_GRXRINGS: case ETHTOOL_GRXRINGS:
info->data = QEDE_RSS_COUNT(edev); info->data = QEDE_RSS_COUNT(edev);
return 0; break;
case ETHTOOL_GRXFH: 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: default:
DP_ERR(edev, "Command parameters not supported\n"); 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) static int qede_set_rss_flags(struct qede_dev *edev, struct ethtool_rxnfc *info)
......
...@@ -38,7 +38,6 @@ ...@@ -38,7 +38,6 @@
#include <linux/qed/qed_if.h> #include <linux/qed/qed_if.h>
#include "qede.h" #include "qede.h"
#ifdef CONFIG_RFS_ACCEL
struct qede_arfs_tuple { struct qede_arfs_tuple {
union { union {
__be32 src_ipv4; __be32 src_ipv4;
...@@ -80,6 +79,7 @@ struct qede_arfs_fltr_node { ...@@ -80,6 +79,7 @@ struct qede_arfs_fltr_node {
}; };
struct qede_arfs { struct qede_arfs {
#define QEDE_ARFS_BUCKET_HEAD(edev, idx) (&(edev)->arfs->arfs_hl_head[idx])
#define QEDE_ARFS_POLL_COUNT 100 #define QEDE_ARFS_POLL_COUNT 100
#define QEDE_RFS_FLW_BITSHIFT (4) #define QEDE_RFS_FLW_BITSHIFT (4)
#define QEDE_RFS_FLW_MASK ((1 << QEDE_RFS_FLW_BITSHIFT) - 1) #define QEDE_RFS_FLW_MASK ((1 << QEDE_RFS_FLW_BITSHIFT) - 1)
...@@ -92,6 +92,7 @@ struct qede_arfs { ...@@ -92,6 +92,7 @@ struct qede_arfs {
bool enable; bool enable;
}; };
#ifdef CONFIG_RFS_ACCEL
static void qede_configure_arfs_fltr(struct qede_dev *edev, static void qede_configure_arfs_fltr(struct qede_dev *edev,
struct qede_arfs_fltr_node *n, struct qede_arfs_fltr_node *n,
u16 rxq_id, bool add_fltr) u16 rxq_id, bool add_fltr)
...@@ -1263,3 +1264,120 @@ void qede_config_rx_mode(struct net_device *ndev) ...@@ -1263,3 +1264,120 @@ void qede_config_rx_mode(struct net_device *ndev)
out: out:
kfree(uc_macs); 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;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment