Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5d317c6a authored by Merav Sicron's avatar Merav Sicron Committed by David S. Miller
Browse files

bnx2x: Add support for 4-tupple UDP RSS



This change enables to control via ethtool whether to do UDP RSS on 2-tupple
(IP source / destination only) or on 4-tupple (include UDP source / destination
port). It also enables to read back the RSS configuration.

Signed-off-by: default avatarMerav Sicron <meravs@broadcom.com>
Signed-off-by: default avatarEilon Greenstein <eilong@broadcom.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent cf2c1df6
Loading
Loading
Loading
Loading
+9 −7
Original line number Diff line number Diff line
@@ -1666,14 +1666,13 @@ static void bnx2x_set_rx_buf_size(struct bnx2x *bp)
static int bnx2x_init_rss_pf(struct bnx2x *bp)
{
	int i;
	u8 ind_table[T_ETH_INDIRECTION_TABLE_SIZE] = {0};
	u8 num_eth_queues = BNX2X_NUM_ETH_QUEUES(bp);

	/* Prepare the initial contents fo the indirection table if RSS is
	 * enabled
	 */
	for (i = 0; i < sizeof(ind_table); i++)
		ind_table[i] =
	for (i = 0; i < sizeof(bp->rss_conf_obj.ind_table); i++)
		bp->rss_conf_obj.ind_table[i] =
			bp->fp->cl_id +
			ethtool_rxfh_indir_default(i, num_eth_queues);

@@ -1685,12 +1684,11 @@ static int bnx2x_init_rss_pf(struct bnx2x *bp)
	 * For 57712 and newer on the other hand it's a per-function
	 * configuration.
	 */
	return bnx2x_config_rss_eth(bp, ind_table,
				    bp->port.pmf || !CHIP_IS_E1x(bp));
	return bnx2x_config_rss_eth(bp, bp->port.pmf || !CHIP_IS_E1x(bp));
}

int bnx2x_config_rss_pf(struct bnx2x *bp, struct bnx2x_rss_config_obj *rss_obj,
			u8 *ind_table, bool config_hash)
			bool config_hash)
{
	struct bnx2x_config_rss_params params = {NULL};
	int i;
@@ -1713,11 +1711,15 @@ int bnx2x_config_rss_pf(struct bnx2x *bp, struct bnx2x_rss_config_obj *rss_obj,
	__set_bit(BNX2X_RSS_IPV4_TCP, &params.rss_flags);
	__set_bit(BNX2X_RSS_IPV6, &params.rss_flags);
	__set_bit(BNX2X_RSS_IPV6_TCP, &params.rss_flags);
	if (rss_obj->udp_rss_v4)
		__set_bit(BNX2X_RSS_IPV4_UDP, &params.rss_flags);
	if (rss_obj->udp_rss_v6)
		__set_bit(BNX2X_RSS_IPV6_UDP, &params.rss_flags);

	/* Hash bits */
	params.rss_result_mask = MULTI_MASK;

	memcpy(params.ind_table, ind_table, sizeof(params.ind_table));
	memcpy(params.ind_table, rss_obj->ind_table, sizeof(params.ind_table));

	if (config_hash) {
		/* RSS keys */
+3 −5
Original line number Diff line number Diff line
@@ -94,7 +94,7 @@ void bnx2x_send_unload_done(struct bnx2x *bp);
 * @config_hash:	re-configure RSS hash keys configuration
 */
int bnx2x_config_rss_pf(struct bnx2x *bp, struct bnx2x_rss_config_obj *rss_obj,
			u8 *ind_table, bool config_hash);
			bool config_hash);

/**
 * bnx2x__init_func_obj - init function object
@@ -865,11 +865,9 @@ static inline int func_by_vn(struct bnx2x *bp, int vn)
	return 2 * vn + BP_PORT(bp);
}

static inline int bnx2x_config_rss_eth(struct bnx2x *bp, u8 *ind_table,
				       bool config_hash)
static inline int bnx2x_config_rss_eth(struct bnx2x *bp, bool config_hash)
{
	return bnx2x_config_rss_pf(bp, &bp->rss_conf_obj, ind_table,
				   config_hash);
	return bnx2x_config_rss_pf(bp, &bp->rss_conf_obj, config_hash);
}

/**
+133 −3
Original line number Diff line number Diff line
@@ -2600,6 +2600,41 @@ static int bnx2x_set_phys_id(struct net_device *dev,
	return 0;
}

static int bnx2x_get_rss_flags(struct bnx2x *bp, struct ethtool_rxnfc *info)
{

	switch (info->flow_type) {
	case TCP_V4_FLOW:
	case TCP_V6_FLOW:
		info->data = RXH_IP_SRC | RXH_IP_DST |
			     RXH_L4_B_0_1 | RXH_L4_B_2_3;
		break;
	case UDP_V4_FLOW:
		if (bp->rss_conf_obj.udp_rss_v4)
			info->data = RXH_IP_SRC | RXH_IP_DST |
				     RXH_L4_B_0_1 | RXH_L4_B_2_3;
		else
			info->data = RXH_IP_SRC | RXH_IP_DST;
		break;
	case UDP_V6_FLOW:
		if (bp->rss_conf_obj.udp_rss_v6)
			info->data = RXH_IP_SRC | RXH_IP_DST |
				     RXH_L4_B_0_1 | RXH_L4_B_2_3;
		else
			info->data = RXH_IP_SRC | RXH_IP_DST;
		break;
	case IPV4_FLOW:
	case IPV6_FLOW:
		info->data = RXH_IP_SRC | RXH_IP_DST;
		break;
	default:
		info->data = 0;
		break;
	}

	return 0;
}

static int bnx2x_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info,
			   u32 *rules __always_unused)
{
@@ -2609,7 +2644,102 @@ static int bnx2x_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info,
	case ETHTOOL_GRXRINGS:
		info->data = BNX2X_NUM_ETH_QUEUES(bp);
		return 0;
	case ETHTOOL_GRXFH:
		return bnx2x_get_rss_flags(bp, info);
	default:
		DP(BNX2X_MSG_ETHTOOL, "Command parameters not supported\n");
		return -EOPNOTSUPP;
	}
}

static int bnx2x_set_rss_flags(struct bnx2x *bp, struct ethtool_rxnfc *info)
{
	int udp_rss_requested;

	DP(BNX2X_MSG_ETHTOOL,
	   "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-tupple hash is supported */
		if (info->data ^ (RXH_IP_SRC | RXH_IP_DST |
				  RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
			DP(BNX2X_MSG_ETHTOOL,
			   "Command parameters not supported\n");
			return -EINVAL;
		} else {
			return 0;
		}

	case UDP_V4_FLOW:
	case UDP_V6_FLOW:
		/* For UDP either 2-tupple hash or 4-tupple hash is supported */
		if (info->data == (RXH_IP_SRC | RXH_IP_DST |
				 RXH_L4_B_0_1 | RXH_L4_B_2_3))
			udp_rss_requested = 1;
		else if (info->data == (RXH_IP_SRC | RXH_IP_DST))
			udp_rss_requested = 0;
		else
			return -EINVAL;
		if ((info->flow_type == UDP_V4_FLOW) &&
		    (bp->rss_conf_obj.udp_rss_v4 != udp_rss_requested)) {
			bp->rss_conf_obj.udp_rss_v4 = udp_rss_requested;
			DP(BNX2X_MSG_ETHTOOL,
			   "rss re-configured, UDP 4-tupple %s\n",
			   udp_rss_requested ? "enabled" : "disabled");
			return bnx2x_config_rss_pf(bp, &bp->rss_conf_obj, 0);
		} else if ((info->flow_type == UDP_V6_FLOW) &&
			   (bp->rss_conf_obj.udp_rss_v6 != udp_rss_requested)) {
			bp->rss_conf_obj.udp_rss_v6 = udp_rss_requested;
			return bnx2x_config_rss_pf(bp, &bp->rss_conf_obj, 0);
			DP(BNX2X_MSG_ETHTOOL,
			   "rss re-configured, UDP 4-tupple %s\n",
			   udp_rss_requested ? "enabled" : "disabled");
		} else {
			return 0;
		}
	case IPV4_FLOW:
	case IPV6_FLOW:
		/* For IP only 2-tupple hash is supported */
		if (info->data ^ (RXH_IP_SRC | RXH_IP_DST)) {
			DP(BNX2X_MSG_ETHTOOL,
			   "Command parameters not supported\n");
			return -EINVAL;
		} else {
			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(BNX2X_MSG_ETHTOOL,
			   "Command parameters not supported\n");
			return -EINVAL;
		} else {
			return 0;
		}
	default:
		return -EINVAL;
	}
}

static int bnx2x_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info)
{
	struct bnx2x *bp = netdev_priv(dev);

	switch (info->cmd) {
	case ETHTOOL_SRXFH:
		return bnx2x_set_rss_flags(bp, info);
	default:
		DP(BNX2X_MSG_ETHTOOL, "Command parameters not supported\n");
		return -EOPNOTSUPP;
@@ -2649,7 +2779,6 @@ static int bnx2x_set_rxfh_indir(struct net_device *dev, const u32 *indir)
{
	struct bnx2x *bp = netdev_priv(dev);
	size_t i;
	u8 ind_table[T_ETH_INDIRECTION_TABLE_SIZE] = {0};

	for (i = 0; i < T_ETH_INDIRECTION_TABLE_SIZE; i++) {
		/*
@@ -2661,10 +2790,10 @@ static int bnx2x_set_rxfh_indir(struct net_device *dev, const u32 *indir)
		 * align the received table to the Client ID of the leading RSS
		 * queue
		 */
		ind_table[i] = indir[i] + bp->fp->cl_id;
		bp->rss_conf_obj.ind_table[i] = indir[i] + bp->fp->cl_id;
	}

	return bnx2x_config_rss_eth(bp, ind_table, false);
	return bnx2x_config_rss_eth(bp, false);
}

static const struct ethtool_ops bnx2x_ethtool_ops = {
@@ -2694,6 +2823,7 @@ static const struct ethtool_ops bnx2x_ethtool_ops = {
	.set_phys_id		= bnx2x_set_phys_id,
	.get_ethtool_stats	= bnx2x_get_ethtool_stats,
	.get_rxnfc		= bnx2x_get_rxnfc,
	.set_rxnfc		= bnx2x_set_rxnfc,
	.get_rxfh_indir_size	= bnx2x_get_rxfh_indir_size,
	.get_rxfh_indir		= bnx2x_get_rxfh_indir,
	.set_rxfh_indir		= bnx2x_set_rxfh_indir,
+8 −0
Original line number Diff line number Diff line
@@ -4107,6 +4107,10 @@ static int bnx2x_setup_rss(struct bnx2x *bp,
		data->capabilities |=
			ETH_RSS_UPDATE_RAMROD_DATA_IPV4_TCP_CAPABILITY;

	if (test_bit(BNX2X_RSS_IPV4_UDP, &p->rss_flags))
		data->capabilities |=
			ETH_RSS_UPDATE_RAMROD_DATA_IPV4_UDP_CAPABILITY;

	if (test_bit(BNX2X_RSS_IPV6, &p->rss_flags))
		data->capabilities |=
			ETH_RSS_UPDATE_RAMROD_DATA_IPV6_CAPABILITY;
@@ -4115,6 +4119,10 @@ static int bnx2x_setup_rss(struct bnx2x *bp,
		data->capabilities |=
			ETH_RSS_UPDATE_RAMROD_DATA_IPV6_TCP_CAPABILITY;

	if (test_bit(BNX2X_RSS_IPV6_UDP, &p->rss_flags))
		data->capabilities |=
			ETH_RSS_UPDATE_RAMROD_DATA_IPV6_UDP_CAPABILITY;

	/* Hashing mask */
	data->rss_result_mask = p->rss_result_mask;

+6 −0
Original line number Diff line number Diff line
@@ -694,8 +694,10 @@ enum {

	BNX2X_RSS_IPV4,
	BNX2X_RSS_IPV4_TCP,
	BNX2X_RSS_IPV4_UDP,
	BNX2X_RSS_IPV6,
	BNX2X_RSS_IPV6_TCP,
	BNX2X_RSS_IPV6_UDP,
};

struct bnx2x_config_rss_params {
@@ -729,6 +731,10 @@ struct bnx2x_rss_config_obj {
	/* Last configured indirection table */
	u8			ind_table[T_ETH_INDIRECTION_TABLE_SIZE];

	/* flags for enabling 4-tupple hash on UDP */
	u8			udp_rss_v4;
	u8			udp_rss_v6;

	int (*config_rss)(struct bnx2x *bp,
			  struct bnx2x_config_rss_params *p);
};