bnxt_en: Add ethtool -n|-N rx-flow-hash support.

To display and modify the RSS hash.

Signed-off-by: Michael Chan <michael.chan@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Michael Chan 2016-11-16 21:13:10 -05:00 committed by David S. Miller
parent 87da7f796d
commit a011952a1a

View File

@ -542,6 +542,146 @@ fltr_err:
return rc; return rc;
} }
#endif
static u64 get_ethtool_ipv4_rss(struct bnxt *bp)
{
if (bp->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_IPV4)
return RXH_IP_SRC | RXH_IP_DST;
return 0;
}
static u64 get_ethtool_ipv6_rss(struct bnxt *bp)
{
if (bp->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_IPV6)
return RXH_IP_SRC | RXH_IP_DST;
return 0;
}
static int bnxt_grxfh(struct bnxt *bp, struct ethtool_rxnfc *cmd)
{
cmd->data = 0;
switch (cmd->flow_type) {
case TCP_V4_FLOW:
if (bp->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV4)
cmd->data |= RXH_IP_SRC | RXH_IP_DST |
RXH_L4_B_0_1 | RXH_L4_B_2_3;
cmd->data |= get_ethtool_ipv4_rss(bp);
break;
case UDP_V4_FLOW:
if (bp->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV4)
cmd->data |= RXH_IP_SRC | RXH_IP_DST |
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 IPV4_FLOW:
cmd->data |= get_ethtool_ipv4_rss(bp);
break;
case TCP_V6_FLOW:
if (bp->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV6)
cmd->data |= RXH_IP_SRC | RXH_IP_DST |
RXH_L4_B_0_1 | RXH_L4_B_2_3;
cmd->data |= get_ethtool_ipv6_rss(bp);
break;
case UDP_V6_FLOW:
if (bp->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV6)
cmd->data |= RXH_IP_SRC | RXH_IP_DST |
RXH_L4_B_0_1 | RXH_L4_B_2_3;
/* fall through */
case SCTP_V6_FLOW:
case AH_ESP_V6_FLOW:
case AH_V6_FLOW:
case ESP_V6_FLOW:
case IPV6_FLOW:
cmd->data |= get_ethtool_ipv6_rss(bp);
break;
}
return 0;
}
#define RXH_4TUPLE (RXH_IP_SRC | RXH_IP_DST | RXH_L4_B_0_1 | RXH_L4_B_2_3)
#define RXH_2TUPLE (RXH_IP_SRC | RXH_IP_DST)
static int bnxt_srxfh(struct bnxt *bp, struct ethtool_rxnfc *cmd)
{
u32 rss_hash_cfg = bp->rss_hash_cfg;
int tuple, rc = 0;
if (cmd->data == RXH_4TUPLE)
tuple = 4;
else if (cmd->data == RXH_2TUPLE)
tuple = 2;
else if (!cmd->data)
tuple = 0;
else
return -EINVAL;
if (cmd->flow_type == TCP_V4_FLOW) {
rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV4;
if (tuple == 4)
rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV4;
} else if (cmd->flow_type == UDP_V4_FLOW) {
if (tuple == 4 && !(bp->flags & BNXT_FLAG_UDP_RSS_CAP))
return -EINVAL;
rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV4;
if (tuple == 4)
rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV4;
} else if (cmd->flow_type == TCP_V6_FLOW) {
rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV6;
if (tuple == 4)
rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV6;
} else if (cmd->flow_type == UDP_V6_FLOW) {
if (tuple == 4 && !(bp->flags & BNXT_FLAG_UDP_RSS_CAP))
return -EINVAL;
rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV6;
if (tuple == 4)
rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV6;
} else if (tuple == 4) {
return -EINVAL;
}
switch (cmd->flow_type) {
case TCP_V4_FLOW:
case UDP_V4_FLOW:
case SCTP_V4_FLOW:
case AH_ESP_V4_FLOW:
case AH_V4_FLOW:
case ESP_V4_FLOW:
case IPV4_FLOW:
if (tuple == 2)
rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_IPV4;
else if (!tuple)
rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_IPV4;
break;
case TCP_V6_FLOW:
case UDP_V6_FLOW:
case SCTP_V6_FLOW:
case AH_ESP_V6_FLOW:
case AH_V6_FLOW:
case ESP_V6_FLOW:
case IPV6_FLOW:
if (tuple == 2)
rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_IPV6;
else if (!tuple)
rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_IPV6;
break;
}
if (bp->rss_hash_cfg == rss_hash_cfg)
return 0;
bp->rss_hash_cfg = rss_hash_cfg;
if (netif_running(bp->dev)) {
bnxt_close_nic(bp, false, false);
rc = bnxt_open_nic(bp, false, false);
}
return rc;
}
static int bnxt_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd, static int bnxt_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
u32 *rule_locs) u32 *rule_locs)
@ -550,6 +690,7 @@ static int bnxt_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
int rc = 0; int rc = 0;
switch (cmd->cmd) { switch (cmd->cmd) {
#ifdef CONFIG_RFS_ACCEL
case ETHTOOL_GRXRINGS: case ETHTOOL_GRXRINGS:
cmd->data = bp->rx_nr_rings; cmd->data = bp->rx_nr_rings;
break; break;
@ -566,6 +707,11 @@ static int bnxt_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
case ETHTOOL_GRXCLSRULE: case ETHTOOL_GRXCLSRULE:
rc = bnxt_grxclsrule(bp, cmd); rc = bnxt_grxclsrule(bp, cmd);
break; break;
#endif
case ETHTOOL_GRXFH:
rc = bnxt_grxfh(bp, cmd);
break;
default: default:
rc = -EOPNOTSUPP; rc = -EOPNOTSUPP;
@ -574,7 +720,23 @@ static int bnxt_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
return rc; return rc;
} }
#endif
static int bnxt_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd)
{
struct bnxt *bp = netdev_priv(dev);
int rc;
switch (cmd->cmd) {
case ETHTOOL_SRXFH:
rc = bnxt_srxfh(bp, cmd);
break;
default:
rc = -EOPNOTSUPP;
break;
}
return rc;
}
static u32 bnxt_get_rxfh_indir_size(struct net_device *dev) static u32 bnxt_get_rxfh_indir_size(struct net_device *dev)
{ {
@ -1885,9 +2047,8 @@ const struct ethtool_ops bnxt_ethtool_ops = {
.get_ringparam = bnxt_get_ringparam, .get_ringparam = bnxt_get_ringparam,
.get_channels = bnxt_get_channels, .get_channels = bnxt_get_channels,
.set_channels = bnxt_set_channels, .set_channels = bnxt_set_channels,
#ifdef CONFIG_RFS_ACCEL
.get_rxnfc = bnxt_get_rxnfc, .get_rxnfc = bnxt_get_rxnfc,
#endif .set_rxnfc = bnxt_set_rxnfc,
.get_rxfh_indir_size = bnxt_get_rxfh_indir_size, .get_rxfh_indir_size = bnxt_get_rxfh_indir_size,
.get_rxfh_key_size = bnxt_get_rxfh_key_size, .get_rxfh_key_size = bnxt_get_rxfh_key_size,
.get_rxfh = bnxt_get_rxfh, .get_rxfh = bnxt_get_rxfh,